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 793 additions and 607 deletions
<?xml version="1.0" encoding="UTF-8"?>
<!--
SPDX-FileCopyrightText: 2012-2023 Bruce Cowan <bruce@bcowan.me.uk>
SPDX-License-Identifier: CC0-1.0
-->
<gresources>
<gresource prefix="/uk/me/bcowan/Rugby">
<file compressed="true" preprocess="xml-stripblanks">gtk/help-overlay.ui</file>
<file compressed="true" preprocess="xml-stripblanks">gtk/prefs.ui</file>
<file compressed="true" preprocess="xml-stripblanks">gtk/window.ui</file>
<file compressed="true">style.css</file>
<file compressed="true" preprocess="xml-stripblanks">uk.me.bcowan.Rugby.metainfo.xml</file>
</gresource>
<gresource prefix="/uk/me/bcowan/Rugby/icons/scalable/actions/">
<file compressed="true" preprocess="xml-stripblanks" alias="football-american-symbolic.svg">icons/football-american-symbolic.svg</file>
<file compressed="true" preprocess="xml-stripblanks" alias="funnel-symbolic.svg">icons/funnel-symbolic.svg</file>
<file compressed="true" preprocess="xml-stripblanks" alias="list-symbolic.svg">icons/list-symbolic.svg</file>
</gresource>
</gresources>
<?xml version="1.0" encoding="UTF-8"?>
<!--
SPDX-FileCopyrightText: 2020-2023 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>
<schema id="uk.me.bcowan.Rugby.window" path="/uk/me/bcowan/Rugby/window/">
<key name="height" type="i">
<default>600</default>
<summary>Window height</summary>
<description>The height of the window</description>
</key>
<key name="width" type="i">
<default>400</default>
<summary>Window width</summary>
<description>The width of the window</description>
</key>
</schema>
</schemalist>
<?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>
project('rugby', 'c', license:'LGPL') # SPDX-FileCopyrightText: 2016-2024 Bruce Cowan <bruce@bcowan.me.uk>
#
# SPDX-License-Identifier: GPL-3.0-or-later
add_project_arguments('-Wdeprecated-declarations', language: 'c') project('rugby', 'c',
add_project_arguments('-DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_46', language: 'c') version: '0.4.alpha',
add_project_arguments('-DGLIB_VERSION_MAX_ALLOWED=GLIB_VERSION_2_46', language: 'c') license:'GPLv3+',
add_project_arguments('-DGDK_VERSION_MIN_REQUIRED=GDK_VERSION_3_16', language: 'c') meson_version: '>= 1.1.0',
add_project_arguments('-DGDK_VERSION_MAX_ALLOWED=GDK_VERSION_3_16', language: 'c') default_options: [
'buildtype=debugoptimized',
'c_std=gnu11',
'warning_level=3'
],
)
gio_dep = dependency('gio-2.0', version: '>=2.46') datadir = get_option('datadir')
gtk_dep = dependency('gtk+-3.0', version: '>=3.16') desktopdir = datadir / 'applications'
gnome = import('gnome')
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()
profile = get_option('profile')
conf.set_quoted('PROFILE', profile)
if profile == 'development'
conf.set_quoted('VERSION', '@0@-@VCS_TAG@'.format(meson.project_version()))
else
conf.set_quoted('VERSION', meson.project_version())
endif
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('data')
subdir('src') 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?'
)
# These should be integers for Meson >= 0.45
option('try_points', type: 'string', value: '7')
option('utry_points', type: 'string', value: '5')
option('kick_points', type: 'string', value: '3')
\ No newline at end of file
/*
* SPDX-FileCopyrightText: 2012-2024 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-dialog.h"
static void
on_activate ( GApplication *app,
G_GNUC_UNUSED void *user_data)
{
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 (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);
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);
}
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,
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);
gtk_application_set_accels_for_action (GTK_APPLICATION (app),
"app.prefs",
(const char*[]) { "<Ctrl>comma", NULL });
}
int
main (int argc,
char **argv)
{
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);
g_signal_connect (app, "activate",
G_CALLBACK (on_activate), NULL);
return g_application_run (G_APPLICATION (app), argc, argv);
}
gnome = import('gnome') # SPDX-FileCopyrightText: 2016-2024 Bruce Cowan <bruce@bcowan.me.uk>
#
conf = configuration_data() # SPDX-License-Identifier: GPL-3.0-or-later
conf.set('TRY_POINTS', get_option('try_points')) sources = [
conf.set('UTRY_POINTS', get_option('utry_points')) 'main.c',
conf.set('KICK_POINTS', get_option('kick_points'))
config_h = configure_file(configuration: conf, output: 'config.h')
sources = files(
'rugby.c',
'rugby-application.c',
'rugby-app-window.c', 'rugby-app-window.c',
'rugby-list-store.c', 'rugby-list-store.c',
'rugby-possibility.c', 'rugby-possibility.c',
'rugby-possibility-widget.c' 'rugby-possibility-widget.c',
) 'rugby-pref-dialog.c',
]
sources += config_h
sources += resources
deps = [gio_dep, gtk_dep] 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', executable('rugby',
sources, sources, config_h, resources,
dependencies: deps, dependencies: [gio_dep, gtk_dep, libadwaita_dep],
install_dir: get_option('bindir'),
install: true) install: true)
/* rugby-app-window.c /*
* SPDX-FileCopyrightText: 2017-2024 Bruce Cowan <bruce@bcowan.me.uk>
* *
* Copyright © 2017-2018 Bruce Cowan <bruce@bcowan.eu> * SPDX-License-Identifier: GPL-3.0-or-later
*
* This file is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <gtk/gtk.h>
#include "config.h" #include "config.h"
#include "rugby-application.h"
#include "rugby-app-window.h" #include "rugby-app-window.h"
#include "rugby-list-store.h" #include "rugby-list-store.h"
#include "rugby-possibility.h" #include "rugby-possibility.h"
#include "rugby-possibility-widget.h" #include "rugby-possibility-widget.h"
#include <glib/gi18n.h>
struct _RugbyAppWindow struct _RugbyAppWindow
{ {
GtkApplicationWindow parent; AdwApplicationWindow parent;
RugbyListStore *store; GtkWidget *scorespin;
GtkWidget *stack;
GtkWidget *tryfilter; GSettings *win_settings;
GtkWidget *kickfilter;
GtkWidget *tryscale;
GtkWidget *kickscale;
GtkWidget *listbox;
}; };
G_DEFINE_TYPE (RugbyAppWindow, rugby_app_window, GTK_TYPE_APPLICATION_WINDOW) G_DEFINE_FINAL_TYPE (RugbyAppWindow, rugby_app_window, ADW_TYPE_APPLICATION_WINDOW)
static inline guint static void
get_max_tries (guint score) list_store_items_changed_cb ( GListModel *model,
G_GNUC_UNUSED unsigned position,
G_GNUC_UNUSED unsigned removed,
G_GNUC_UNUSED unsigned added,
RugbyAppWindow *self)
{ {
return (score % 5 == 1) ? score / UTRY_POINTS - 1 : score / UTRY_POINTS; 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");
} }
static inline guint static char *
get_max_kicks (guint score) item_tooltip_cb (GtkListItem *item)
{ {
return (score % 3 == 1) ? score / KICK_POINTS : score / KICK_POINTS - 1; 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 void static char *
scorespin_value_changed_cb (GtkSpinButton *spin, header_label_cb (GtkListItem *item)
RugbyAppWindow *self)
{ {
gint score = gtk_spin_button_get_value_as_int (spin); RugbyPossibility *possibility = gtk_list_header_get_item (GTK_LIST_HEADER (item));
if (!possibility)
rugby_list_store_set_score (self->store, score); return NULL;
gint max_tries = MAX (get_max_tries (score), 1.0); int total_tries = rugby_possibility_total_tries (possibility);
gtk_range_set_range (GTK_RANGE (self->tryscale), 0.0, max_tries);
gint max_kicks = MAX (get_max_kicks (score), 1.0); return g_strdup_printf (ngettext ("%d try", "%d tries", total_tries), total_tries);
gtk_range_set_range (GTK_RANGE (self->kickscale), 0.0, max_kicks);
} }
static void static void
scale_value_changed_cb (GtkRange *range, activate_score_changed (G_GNUC_UNUSED GSimpleAction *action,
RugbyAppWindow *self) GVariant *parameter,
void *user_data)
{ {
// pass RugbyAppWindow *self = RUGBY_APP_WINDOW (user_data);
}
static GtkWidget * double current_value = gtk_spin_button_get_value (GTK_SPIN_BUTTON (self->scorespin));
listbox_widget_func (gpointer item, const char *direction = g_variant_get_string (parameter, NULL);
gpointer user_data)
{
RugbyPossibility *possibility = RUGBY_POSSIBILITY (item);
return rugby_possibility_widget_new (possibility); 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 static void
rugby_app_window_init (RugbyAppWindow *self) rugby_app_window_dispose (GObject *object)
{ {
gtk_widget_init_template (GTK_WIDGET (self)); gtk_widget_dispose_template (GTK_WIDGET (object), RUGBY_TYPE_APP_WINDOW);
g_clear_object (&RUGBY_APP_WINDOW (object)->win_settings);
self->store = rugby_list_store_new (); G_OBJECT_CLASS (rugby_app_window_parent_class)->dispose (object);
gtk_list_box_bind_model (GTK_LIST_BOX (self->listbox),
G_LIST_MODEL (self->store),
listbox_widget_func,
NULL,
NULL);
g_object_bind_property (self->tryfilter, "active",
self->tryscale, "sensitive",
G_BINDING_DEFAULT);
g_object_bind_property (self->kickfilter, "active",
self->kickscale, "sensitive",
G_BINDING_DEFAULT);
} }
static void static void
rugby_app_window_dispose (GObject *object) rugby_app_window_init (RugbyAppWindow *self)
{ {
RugbyAppWindow *self = RUGBY_APP_WINDOW (object); gtk_widget_init_template (GTK_WIDGET (self));
g_clear_object (&self->store);
G_OBJECT_CLASS (rugby_app_window_parent_class)->dispose (object); 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 static void
rugby_app_window_class_init (RugbyAppWindowClass *klass) 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); 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, gtk_widget_class_set_template_from_resource (widget_class,
"/uk/me/bcowan/rugby/interface.ui"); "/uk/me/bcowan/Rugby/gtk/window.ui");
gtk_widget_class_bind_template_child (widget_class, RugbyAppWindow, tryfilter);
gtk_widget_class_bind_template_child (widget_class, RugbyAppWindow, kickfilter); gtk_widget_class_bind_template_child (widget_class, RugbyAppWindow, scorespin);
gtk_widget_class_bind_template_child (widget_class, RugbyAppWindow, tryscale); gtk_widget_class_bind_template_child (widget_class, RugbyAppWindow, stack);
gtk_widget_class_bind_template_child (widget_class, RugbyAppWindow, kickscale);
gtk_widget_class_bind_template_child (widget_class, RugbyAppWindow, listbox); 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, scorespin_value_changed_cb); gtk_widget_class_bind_template_callback (widget_class, list_store_items_changed_cb);
gtk_widget_class_bind_template_callback (widget_class, scale_value_changed_cb);
} }
RugbyAppWindow * RugbyAppWindow *
rugby_app_window_new (RugbyApplication *app) rugby_app_window_new (GtkApplication *app)
{ {
return g_object_new (RUGBY_TYPE_APP_WINDOW, "application", app, NULL); return g_object_new (RUGBY_TYPE_APP_WINDOW,
"application", app,
NULL);
} }
/* rugby-app-window.h /*
* SPDX-FileCopyrightText: 2017-2022 Bruce Cowan <bruce@bcowan.me.uk>
* *
* Copyright © 2017 Bruce Cowan <bruce@bcowan.eu> * SPDX-License-Identifier: GPL-3.0-or-later
*
* This file is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include <gtk/gtk.h> #include <adwaita.h>
G_BEGIN_DECLS G_BEGIN_DECLS
#define RUGBY_TYPE_APP_WINDOW (rugby_app_window_get_type()) #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 (RugbyApplication *app); RugbyAppWindow *rugby_app_window_new (GtkApplication *app);
G_END_DECLS G_END_DECLS
/* rugby-application.c
*
* Copyright © 2012, 2016, 2017 Bruce Cowan <bruce@bcowan.eu>
*
* This file is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <gtk/gtk.h>
#include "rugby-application.h"
#include "rugby-app-window.h"
struct _RugbyApplication
{
GtkApplication parent;
};
G_DEFINE_TYPE (RugbyApplication, rugby_application, GTK_TYPE_APPLICATION)
static void
rugby_application_activate (GApplication *app)
{
RugbyAppWindow *win = rugby_app_window_new (RUGBY_APPLICATION (app));
gtk_window_present (GTK_WINDOW (win));
}
static void
about_activated (GSimpleAction *simple,
GVariant *parameter,
gpointer user_data)
{
GtkApplication *app = GTK_APPLICATION (user_data);
GtkWindow *window = gtk_application_get_active_window (app);
const gchar *authors[] = { "Bruce Cowan", NULL };
g_autoptr (GDateTime) date = g_date_time_new_now_local ();
gint year = g_date_time_get_year (date);
g_autofree gchar *copyright = g_strdup_printf ("Copyright © 2012–%d Bruce Cowan",
year);
gtk_show_about_dialog (window,
"logo-icon-name", "face-wink",
"program-name", "Rugby",
"copyright", copyright,
"license-type", GTK_LICENSE_LGPL_3_0,
"authors", authors,
"comments", "Rugby scores possiblities program",
NULL);
}
static void
quit_activated (GSimpleAction *simple,
GVariant *parameter,
gpointer user_data)
{
g_application_quit (G_APPLICATION (user_data));
}
static void
rugby_application_startup (GApplication *app)
{
const GActionEntry app_entries[] =
{
{ "about", about_activated },
{ "quit", quit_activated }
};
G_APPLICATION_CLASS (rugby_application_parent_class)->startup (app);
g_action_map_add_action_entries (G_ACTION_MAP (app),
app_entries,
G_N_ELEMENTS (app_entries),
app);
g_autoptr (GtkBuilder) builder = gtk_builder_new_from_resource ("/uk/me/bcowan/rugby/menu.ui");
GMenuModel *app_menu = G_MENU_MODEL (gtk_builder_get_object (builder, "appmenu"));
gtk_application_set_app_menu (GTK_APPLICATION (app), app_menu);
// 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);
}
static void
rugby_application_class_init (RugbyApplicationClass *klass)
{
GApplicationClass *app_class = G_APPLICATION_CLASS (klass);
app_class->activate = rugby_application_activate;
app_class->startup = rugby_application_startup;
}
static void
rugby_application_init (RugbyApplication *self)
{
}
RugbyApplication *
rugby_application_new (void)
{
return g_object_new (RUGBY_TYPE_APPLICATION,
"application-id", "uk.me.bcowan.rugby",
NULL);
}
/* rugby-application.h
*
* Copyright © 2012, 2016 Bruce Cowan <bruce@bcowan.eu>
*
* This file is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define RUGBY_TYPE_APPLICATION rugby_application_get_type ()
G_DECLARE_FINAL_TYPE (RugbyApplication, rugby_application, RUGBY, APPLICATION, GtkApplication)
RugbyApplication * rugby_application_new (void);
G_END_DECLS
/* rugby-list-store.c /*
* SPDX-FileCopyrightText: 2018-2024 Bruce Cowan <bruce@bcowan.me.uk>
* *
* Copyright 2018 Bruce Cowan <bruce@bcowan.eu> * SPDX-License-Identifier: GPL-3.0-or-later
*
* This file is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/ */
#include "config.h"
#include "rugby-list-store.h" #include "rugby-list-store.h"
#include "rugby-possibility.h" #include "rugby-possibility.h"
#include <gio/gio.h> #include <gio/gio.h>
#include <gtk/gtk.h>
struct _RugbyListStore struct _RugbyListStore
{ {
GObject parent_instance; GObject parent_instance;
guint score; int score;
GPtrArray *items;
GListStore *items;
GSettings *settings;
}; };
static void rugby_list_store_iface_init (GListModelInterface *iface); 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_iface_init))
enum enum
{ {
PROP_0, PROP_SCORE = 1,
PROP_SCORE,
N_PROPS N_PROPS
}; };
static GParamSpec *properties [N_PROPS]; static GParamSpec *properties[N_PROPS];
// Helper functions // Helper functions
static gint static int
sort_func (gconstpointer a, sort_func ( gconstpointer a,
gconstpointer b) gconstpointer b,
G_GNUC_UNUSED void *user_data)
{ {
gint atries, autries; int atries = rugby_possibility_get_tries ((void *) a);
gint btries, butries; int autries = rugby_possibility_get_utries ((void *) a);
int btries = rugby_possibility_get_tries ((void *) b);
int butries = rugby_possibility_get_utries ((void *) b);
g_object_get ((gpointer) a, int trydiff = (btries + butries) - (atries + autries);
"tries", &atries,
"utries", &autries,
NULL);
g_object_get ((gpointer) b,
"tries", &btries,
"utries", &butries,
NULL);
gint trydiff = (btries + butries) - (atries + autries);
// Sort by total tries first, then converted // Sort by total tries first, then converted
if (trydiff != 0) if (trydiff != 0)
return trydiff; return trydiff;
else else
return atries - btries; return btries - atries;
} }
// Callbacks
static void static void
notify_score_cb (GObject *gobject, process_data (RugbyListStore *self)
GParamSpec *pspec,
gpointer user_data)
{ {
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");
gint max_tries = self->score / TRY_POINTS; unsigned old_length = g_list_model_get_n_items (G_LIST_MODEL (self->items));
gint max_utries = self->score / UTRY_POINTS; g_list_store_remove_all (self->items);
guint old_length = self->items->len; if (self->score == 0)
g_ptr_array_remove_range (self->items, 0, self->items->len); {
g_list_model_items_changed (G_LIST_MODEL (self), 0, old_length, 0);
return;
}
for (gint tries = 0; tries <= max_tries; tries++) int max_tries = self->score / try_points;
int max_utries = self->score / utry_points;
for (int tries = 0; tries <= max_tries; tries++)
{ {
for (gint utries = 0; utries <= max_utries; utries++) for (int utries = 0; utries <= max_utries; utries++)
{ {
gint left = self->score - (tries * TRY_POINTS) - (utries * UTRY_POINTS); int left = self->score - (tries * try_points) - (utries * utry_points);
if (left < 0) if (left < 0)
break; break;
if (left % KICK_POINTS == 0) if (left % kick_points == 0)
{ {
gint kicks = left / KICK_POINTS; int kicks = left / kick_points;
RugbyPossibility *possibility = rugby_possibility_new (tries, RugbyPossibility *possibility = rugby_possibility_new (tries,
utries, utries,
kicks); 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_store_sort (self->items, sort_func, NULL);
g_list_model_items_changed (G_LIST_MODEL (self), 0, old_length, self->items->len); 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 // GListModel implementation
static GType 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; return RUGBY_TYPE_POSSIBILITY;
} }
static guint static unsigned
rugby_list_store_get_n_items (GListModel *list) rugby_list_store_get_n_items (GListModel *list)
{ {
RugbyListStore *self = RUGBY_LIST_STORE (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, rugby_list_store_get_item (GListModel *list,
guint position) unsigned position)
{ {
RugbyListStore *self = RUGBY_LIST_STORE (list); RugbyListStore *self = RUGBY_LIST_STORE (list);
g_return_val_if_fail (position < self->items->len, NULL); 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;
}
// 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;
}
}
return g_object_ref (g_ptr_array_index (self->items, position)); *out_end = n_items;
} }
static void static void
rugby_list_store_iface_init (GListModelInterface *iface) rugby_list_store_section_model_iface_init (GtkSectionModelInterface *iface)
{ {
iface->get_item_type = rugby_list_store_get_item_type; iface->get_section = rugby_list_store_get_section;
iface->get_n_items = rugby_list_store_get_n_items;
iface->get_item = rugby_list_store_get_item;
} }
// Class functions // Class functions
static void static void
rugby_list_store_finalize (GObject *object) rugby_list_store_dispose (GObject *object)
{ {
RugbyListStore *self = RUGBY_LIST_STORE (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 static void
rugby_list_store_get_property (GObject *object, rugby_list_store_get_property (GObject *object,
guint prop_id, unsigned prop_id,
GValue *value, GValue *value,
GParamSpec *pspec) GParamSpec *pspec)
{ {
...@@ -171,7 +220,7 @@ rugby_list_store_get_property (GObject *object, ...@@ -171,7 +220,7 @@ rugby_list_store_get_property (GObject *object,
switch (prop_id) switch (prop_id)
{ {
case PROP_SCORE: case PROP_SCORE:
g_value_set_uint (value, rugby_list_store_get_score (self)); g_value_set_int (value, self->score);
break; break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
...@@ -180,7 +229,7 @@ rugby_list_store_get_property (GObject *object, ...@@ -180,7 +229,7 @@ rugby_list_store_get_property (GObject *object,
static void static void
rugby_list_store_set_property (GObject *object, rugby_list_store_set_property (GObject *object,
guint prop_id, unsigned prop_id,
const GValue *value, const GValue *value,
GParamSpec *pspec) GParamSpec *pspec)
{ {
...@@ -188,8 +237,15 @@ rugby_list_store_set_property (GObject *object, ...@@ -188,8 +237,15 @@ rugby_list_store_set_property (GObject *object,
switch (prop_id) switch (prop_id)
{ {
int score;
case PROP_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; break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
...@@ -201,15 +257,13 @@ rugby_list_store_class_init (RugbyListStoreClass *klass) ...@@ -201,15 +257,13 @@ rugby_list_store_class_init (RugbyListStoreClass *klass)
{ {
GObjectClass *object_class = G_OBJECT_CLASS (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->get_property = rugby_list_store_get_property;
object_class->set_property = rugby_list_store_set_property; object_class->set_property = rugby_list_store_set_property;
properties[PROP_SCORE] = g_param_spec_uint ("score", properties[PROP_SCORE] = g_param_spec_int ("score", "", "",
"Score", 0, 200, 0,
"Score of the match", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
0, 200, 0,
G_PARAM_READWRITE);
g_object_class_install_properties (object_class, g_object_class_install_properties (object_class,
N_PROPS, N_PROPS,
...@@ -219,38 +273,16 @@ rugby_list_store_class_init (RugbyListStoreClass *klass) ...@@ -219,38 +273,16 @@ rugby_list_store_class_init (RugbyListStoreClass *klass)
static void static void
rugby_list_store_init (RugbyListStore *self) rugby_list_store_init (RugbyListStore *self)
{ {
self->score = 0; self->settings = g_settings_new ("uk.me.bcowan.Rugby");
self->items = g_ptr_array_new_with_free_func (g_object_unref);
g_signal_connect (self, "notify::score", g_signal_connect_swapped (self->settings, "changed::try-points",
G_CALLBACK (notify_score_cb), self); G_CALLBACK (process_data), self);
} g_signal_connect_swapped (self->settings, "changed::utry-points",
G_CALLBACK (process_data), self);
// Public functions g_signal_connect_swapped (self->settings, "changed::kick-points",
G_CALLBACK (process_data), self);
guint
rugby_list_store_get_score (RugbyListStore *self)
{
g_return_val_if_fail (RUGBY_IS_LIST_STORE (self), 0);
return self->score; self->score = 0;
} self->items = g_list_store_new (RUGBY_TYPE_POSSIBILITY);
void
rugby_list_store_set_score (RugbyListStore *self,
guint 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]);
}
} }
RugbyListStore *
rugby_list_store_new (void)
{
return g_object_new (RUGBY_TYPE_LIST_STORE, NULL);
}
/* rugby-list-store.h /*
* SPDX-FileCopyrightText: 2018-2022 Bruce Cowan <bruce@bcowan.me.uk>
* *
* Copyright 2018 Bruce Cowan <bruce@bcowan.eu> * SPDX-License-Identifier: GPL-3.0-or-later
*
* This file is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/ */
#pragma once #pragma once
...@@ -25,12 +11,7 @@ ...@@ -25,12 +11,7 @@
G_BEGIN_DECLS G_BEGIN_DECLS
#define RUGBY_TYPE_LIST_STORE (rugby_list_store_get_type()) #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);
guint rugby_list_store_get_score (RugbyListStore *self); G_DECLARE_FINAL_TYPE (RugbyListStore, rugby_list_store, RUGBY, LIST_STORE, GObject)
void rugby_list_store_set_score (RugbyListStore *self,
guint score);
G_END_DECLS G_END_DECLS
/*
* 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-widget.h"
#include "rugby-possibility.h"
#include <adwaita.h>
struct _RugbyPossibilityWidget struct _RugbyPossibilityWidget
{ {
GtkDrawingArea parent_instance; GtkWidget parent_instance;
GSettings *settings;
RugbyPossibility *possibility; 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 enum
{ {
PROP_0, PROP_POSSIBILITY = 1,
PROP_POSSIBILITY,
N_PROPS N_PROPS
}; };
static GParamSpec *properties[N_PROPS]; static GParamSpec *properties[N_PROPS];
#define FIXED_HEIGHT 20
static void static void
rugby_possibility_widget_dispose (GObject *object) rugby_possibility_widget_dispose (GObject *object)
{ {
RugbyPossibilityWidget *self = RUGBY_POSSIBILITY_WIDGET (object); RugbyPossibilityWidget *self = RUGBY_POSSIBILITY_WIDGET (object);
g_clear_object (&self->settings);
g_clear_object (&self->possibility); g_clear_object (&self->possibility);
G_OBJECT_CLASS (rugby_possibility_widget_parent_class)->dispose (object); G_OBJECT_CLASS (rugby_possibility_widget_parent_class)->dispose (object);
...@@ -32,7 +42,7 @@ rugby_possibility_widget_dispose (GObject *object) ...@@ -32,7 +42,7 @@ rugby_possibility_widget_dispose (GObject *object)
static void static void
rugby_possibility_widget_get_property (GObject *object, rugby_possibility_widget_get_property (GObject *object,
guint prop_id, unsigned prop_id,
GValue *value, GValue *value,
GParamSpec *pspec) GParamSpec *pspec)
{ {
...@@ -50,7 +60,7 @@ rugby_possibility_widget_get_property (GObject *object, ...@@ -50,7 +60,7 @@ rugby_possibility_widget_get_property (GObject *object,
static void static void
rugby_possibility_widget_set_property (GObject *object, rugby_possibility_widget_set_property (GObject *object,
guint prop_id, unsigned prop_id,
const GValue *value, const GValue *value,
GParamSpec *pspec) GParamSpec *pspec)
{ {
...@@ -67,116 +77,91 @@ rugby_possibility_widget_set_property (GObject *object, ...@@ -67,116 +77,91 @@ rugby_possibility_widget_set_property (GObject *object,
} }
static void static void
rugby_possibility_widget_get_preferred_height (GtkWidget *widget, render_bar (GtkSnapshot *snapshot,
gint *minimum_height, float x,
gint *natural_height) float w,
float h,
const GdkRGBA fill,
const GdkRGBA border)
{ {
if (minimum_height) graphene_rect_t area = GRAPHENE_RECT_INIT (x, 0.0, w, h);
*minimum_height = FIXED_HEIGHT;
if (natural_height) GskRoundedRect rounded;
*natural_height = FIXED_HEIGHT; 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 static void
render_bar (cairo_t *cr, rugby_possibility_widget_snapshot (GtkWidget *widget,
GtkStyleContext *context, GtkSnapshot *snapshot)
gdouble x,
gdouble y,
gdouble w,
gdouble h,
const gchar *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)
{ {
RugbyPossibilityWidget *self = RUGBY_POSSIBILITY_WIDGET (widget); RugbyPossibilityWidget *self = RUGBY_POSSIBILITY_WIDGET (widget);
gdouble width = gtk_widget_get_allocated_width (widget); int try_points = g_settings_get_int (self->settings, "try-points");
gdouble height = gtk_widget_get_allocated_height (widget); int utry_points = g_settings_get_int (self->settings, "utry-points");
gdouble x = 0.0, y = 0.0; int kick_points = g_settings_get_int (self->settings, "kick-points");
GtkStyleContext *context = gtk_widget_get_style_context (widget); int width = gtk_widget_get_width (widget);
gtk_style_context_save (context); int height = gtk_widget_get_height (widget);
gtk_style_context_add_class (context, "level-cell"); float x = 0.0;
gtk_render_background (context, cr, x, y, width, height); int tries = rugby_possibility_get_tries (self->possibility);
gtk_render_frame (context, cr, x, y, width, height); int utries = rugby_possibility_get_utries (self->possibility);
int kicks = rugby_possibility_get_kicks (self->possibility);
gint 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);
gint 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 // Tries
gdouble 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++) 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; x += w;
} }
// Unconverted tries // 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++) 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; x += w;
} }
// Unconverted kicks // Kicks
w = width / (score / 3.0); w = width / (score / (float) kick_points);
gdk_rgba_parse (&fill, "#e01b24"); // Red 3
for (int i = 0; i < kicks; i++) 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; x += w;
} }
gtk_style_context_restore (context);
return TRUE;
}
static void
rugby_possibility_widget_constructed (GObject *obj)
{
RugbyPossibilityWidget *self = RUGBY_POSSIBILITY_WIDGET (obj);
gint 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 static void
...@@ -185,20 +170,16 @@ rugby_possibility_widget_class_init (RugbyPossibilityWidgetClass *klass) ...@@ -185,20 +170,16 @@ rugby_possibility_widget_class_init (RugbyPossibilityWidgetClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass); GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_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->dispose = rugby_possibility_widget_dispose;
object_class->get_property = rugby_possibility_widget_get_property; object_class->get_property = rugby_possibility_widget_get_property;
object_class->set_property = rugby_possibility_widget_set_property; object_class->set_property = rugby_possibility_widget_set_property;
widget_class->draw = rugby_possibility_widget_draw; widget_class->snapshot = rugby_possibility_widget_snapshot;
widget_class->get_preferred_height = rugby_possibility_widget_get_preferred_height;
properties[PROP_POSSIBILITY] = g_param_spec_object ("possibility", properties[PROP_POSSIBILITY] =
"Possibility", g_param_spec_object ("possibility", "", "",
"Possibility to be represented", RUGBY_TYPE_POSSIBILITY,
RUGBY_TYPE_POSSIBILITY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_properties (object_class, g_object_class_install_properties (object_class,
N_PROPS, N_PROPS,
...@@ -208,12 +189,5 @@ rugby_possibility_widget_class_init (RugbyPossibilityWidgetClass *klass) ...@@ -208,12 +189,5 @@ rugby_possibility_widget_class_init (RugbyPossibilityWidgetClass *klass)
static void static void
rugby_possibility_widget_init (RugbyPossibilityWidget *self) rugby_possibility_widget_init (RugbyPossibilityWidget *self)
{ {
} self->settings = g_settings_new ("uk.me.bcowan.Rugby");
GtkWidget *
rugby_possibility_widget_new (RugbyPossibility *possibility)
{
return g_object_new (RUGBY_TYPE_POSSIBILITY_WIDGET,
"possibility", possibility,
NULL);
} }
/* rugby-possibility-widget.h /*
* SPDX-FileCopyrightText: 2018-2022 Bruce Cowan <bruce@bcowan.me.uk>
* *
* Copyright © 2018 Bruce Cowan <bruce@bcowan.eu> * SPDX-License-Identifier: GPL-3.0-or-later
*
* This file is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include <gtk/gtk.h> #include <gtk/gtk.h>
#include "rugby-possibility.h"
G_BEGIN_DECLS G_BEGIN_DECLS
#define RUGBY_TYPE_POSSIBILITY_WIDGET (rugby_possibility_widget_get_type()) #define RUGBY_TYPE_POSSIBILITY_WIDGET (rugby_possibility_widget_get_type())
G_DECLARE_FINAL_TYPE (RugbyPossibilityWidget, rugby_possibility_widget, RUGBY, POSSIBILITY_WIDGET, GtkDrawingArea) G_DECLARE_FINAL_TYPE (RugbyPossibilityWidget, rugby_possibility_widget, RUGBY, POSSIBILITY_WIDGET, GtkWidget)
GtkWidget * rugby_possibility_widget_new (RugbyPossibility *possibility);
G_END_DECLS G_END_DECLS
/* rugby-possibility.c /*
* SPDX-FileCopyrightText: 2018-2024 Bruce Cowan <bruce@bcowan.me.uk>
* *
* Copyright © 2018 Bruce Cowan <bruce@bcowan.eu> * SPDX-License-Identifier: GPL-3.0-or-later
*
* This file is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <config.h>
#include "rugby-possibility.h" #include "rugby-possibility.h"
struct _RugbyPossibility struct _RugbyPossibility
{ {
GObject parent_instance; GObject parent_instance;
gint tries; int tries;
gint utries; int utries;
gint kicks; int kicks;
}; };
G_DEFINE_TYPE (RugbyPossibility, rugby_possibility, G_TYPE_OBJECT) G_DEFINE_FINAL_TYPE (RugbyPossibility, rugby_possibility, G_TYPE_OBJECT)
enum enum
{ {
PROP_0, PROP_TRIES = 1,
PROP_TRIES,
PROP_UTRIES, PROP_UTRIES,
PROP_KICKS, PROP_KICKS,
N_PROPS N_PROPS
}; };
static GParamSpec *properties [N_PROPS]; static GParamSpec *properties[N_PROPS];
static void static void
rugby_possibility_get_property (GObject *object, rugby_possibility_get_property (GObject *object,
guint prop_id, unsigned prop_id,
GValue *value, GValue *value,
GParamSpec *pspec) GParamSpec *pspec)
{ {
...@@ -51,13 +39,13 @@ rugby_possibility_get_property (GObject *object, ...@@ -51,13 +39,13 @@ rugby_possibility_get_property (GObject *object,
switch (prop_id) switch (prop_id)
{ {
case PROP_TRIES: case PROP_TRIES:
g_value_set_int (value, self->tries); g_value_set_int (value, rugby_possibility_get_tries (self));
break; break;
case PROP_UTRIES: case PROP_UTRIES:
g_value_set_int (value, self->utries); g_value_set_int (value, rugby_possibility_get_utries (self));
break; break;
case PROP_KICKS: case PROP_KICKS:
g_value_set_int (value, self->kicks); g_value_set_int (value, rugby_possibility_get_kicks (self));
break; break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
...@@ -66,7 +54,7 @@ rugby_possibility_get_property (GObject *object, ...@@ -66,7 +54,7 @@ rugby_possibility_get_property (GObject *object,
static void static void
rugby_possibility_set_property (GObject *object, rugby_possibility_set_property (GObject *object,
guint prop_id, unsigned prop_id,
const GValue *value, const GValue *value,
GParamSpec *pspec) GParamSpec *pspec)
{ {
...@@ -97,17 +85,17 @@ rugby_possibility_class_init (RugbyPossibilityClass *klass) ...@@ -97,17 +85,17 @@ rugby_possibility_class_init (RugbyPossibilityClass *klass)
object_class->set_property = rugby_possibility_set_property; object_class->set_property = rugby_possibility_set_property;
properties[PROP_TRIES] = properties[PROP_TRIES] =
g_param_spec_int ("tries", "Tries", "Converted tries", g_param_spec_int ("tries", "", "",
0, 20, 0, 0, 200, 0,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
properties[PROP_UTRIES] = properties[PROP_UTRIES] =
g_param_spec_int ("utries", "Utries", "Unconverted tries", g_param_spec_int ("utries", "", "",
0, 20, 0, 0, 200, 0,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
properties[PROP_KICKS] = properties[PROP_KICKS] =
g_param_spec_int ("kicks", "Kicks", "Penalties and drop goals", g_param_spec_int ("kicks", "", "",
0, 20, 0, 0, 200, 0,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, g_object_class_install_properties (object_class,
N_PROPS, N_PROPS,
...@@ -116,14 +104,14 @@ rugby_possibility_class_init (RugbyPossibilityClass *klass) ...@@ -116,14 +104,14 @@ rugby_possibility_class_init (RugbyPossibilityClass *klass)
} }
static void static void
rugby_possibility_init (RugbyPossibility *self) rugby_possibility_init (G_GNUC_UNUSED RugbyPossibility *self)
{ {
} }
RugbyPossibility * RugbyPossibility *
rugby_possibility_new (gint tries, rugby_possibility_new (int tries,
gint utries, int utries,
gint kicks) int kicks)
{ {
return g_object_new (RUGBY_TYPE_POSSIBILITY, return g_object_new (RUGBY_TYPE_POSSIBILITY,
"tries", tries, "tries", tries,
...@@ -132,3 +120,34 @@ rugby_possibility_new (gint tries, ...@@ -132,3 +120,34 @@ rugby_possibility_new (gint tries,
NULL); 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;
}
/* rugby-possibility.h /*
* SPDX-FileCopyrightText: 2018-2024 Bruce Cowan <bruce@bcowan.me.uk>
* *
* Copyright © 2018 Bruce Cowan <bruce@bcowan.eu> * SPDX-License-Identifier: GPL-3.0-or-later
*
* This file is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
...@@ -26,8 +14,14 @@ G_BEGIN_DECLS ...@@ -26,8 +14,14 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE (RugbyPossibility, rugby_possibility, RUGBY, POSSIBILITY, GObject) G_DECLARE_FINAL_TYPE (RugbyPossibility, rugby_possibility, RUGBY, POSSIBILITY, GObject)
RugbyPossibility * rugby_possibility_new (gint tries, RugbyPossibility *rugby_possibility_new (int tries,
gint utries, int utries,
gint kicks); 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 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