Files
federated-calendar/src/gui/gcal-gizmo.c
T
Hari Rana 89ff82924b gui/gizmo: Introduce GcalGizmo
This is a utility widget akin to GtkGizmo[1] and AdwGizmo[2].
It is designed for use in complex widgets which require additional
features such as snapshotting, measuring/allocating, and
focusing capabilities.

We want to implement an entry row widget that allows multi-line content.
The first implementation had two widgets: GcalNotesRow for the widget
itself, and GcalNotesTitle to contain and animate the title by overriding
the measure() and size_allocate() class methods. The GcalNotesTitle
widget ended up becoming a basic widget that could easily be handled
by GcalGizmo. The new implementation simply uses GcalGizmo.[3]

Another potential user of GcalGizmo is GcalDateChooser, where the
date grid contains complicated logic for handling focus to a child widget.
Since GcalGizmo is designed to give full reign over focusability, we can
also use it to simplify focus. The layout manager can quickly be swapped to
GtkBinLayout since we don't want to handle custom measure/allocation logic.[4]

[1]: <https://gitlab.gnome.org/GNOME/gtk/-/blob/main/gtk/gtkgizmo.c>
[2]: <https://gitlab.gnome.org/GNOME/libadwaita/-/blob/main/src/adw-gizmo.c>
[3]: <https://gitlab.gnome.org/GNOME/gnome-calendar/-/merge_requests/737>
[4]: <https://gitlab.gnome.org/GNOME/gnome-calendar/-/merge_requests/760>

Part-of: <https://gitlab.gnome.org/GNOME/gnome-calendar/-/merge_requests/790>
2026-09-09 14:57:14 -04:00

258 lines
6.5 KiB
C

/* gcal-gizmo.c
*
* Copyright (C) 2020 Purism SPC
* Copyright 2025 Hari Rana <theevilskeleton@riseup.net>
*
* 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 "gcal-gizmo.h"
/**
* GcalGizmo:
*
* A very basic widget for setting virtual functions affecting layout.
*
* This is only meant to be used for custom widgets that need child widgets with custom
* functions that contribute to layout.
*/
struct _GcalGizmo
{
GtkWidget parent_instance;
GcalGizmoMeasureFunc measure_func;
gpointer measure_user_data;
GcalGizmoSizeAllocateFunc size_allocate_func;
gpointer size_allocate_user_data;
GcalGizmoSnapshotFunc snapshot_func;
gpointer snapshot_user_data;
GcalGizmoFocusFunc focus_func;
gpointer focus_user_data;
};
G_DEFINE_FINAL_TYPE (GcalGizmo, gcal_gizmo, GTK_TYPE_WIDGET)
/*
* GtkWidget overrides
*/
static void
gcal_gizmo_real_measure (GtkWidget *widget,
GtkOrientation orientation,
int for_size,
int *minimum,
int *natural,
int *minimum_baseline,
int *natural_baseline)
{
GcalGizmo *self = (GcalGizmo *) widget;
g_assert (GCAL_IS_GIZMO (self));
if (self->measure_func)
{
self->measure_func (self,
orientation,
for_size,
minimum, natural,
minimum_baseline, natural_baseline,
self->measure_user_data);
}
}
static void
gcal_gizmo_real_size_allocate (GtkWidget *widget,
int width,
int height,
int baseline)
{
GcalGizmo *self = (GcalGizmo *) widget;
g_assert (GCAL_IS_GIZMO (self));
if (self->size_allocate_func)
self->size_allocate_func (self, width, height, baseline, self->size_allocate_user_data);
}
static void
gcal_gizmo_real_snapshot (GtkWidget *widget,
GtkSnapshot *snapshot)
{
GcalGizmo *self = (GcalGizmo *) widget;
g_assert (GCAL_IS_GIZMO (self));
if (self->snapshot_func)
self->snapshot_func (self, snapshot, self->snapshot_user_data);
else
GTK_WIDGET_CLASS (gcal_gizmo_parent_class)->snapshot (widget, snapshot);
}
static gboolean
gcal_gizmo_real_focus (GtkWidget *widget,
GtkDirectionType direction)
{
GcalGizmo *self = (GcalGizmo *) widget;
g_assert (GCAL_IS_GIZMO (self));
if (self->focus_func)
return self->focus_func (self, direction, self->focus_user_data);
return FALSE;
}
/*
* GObject overrides
*/
static void
gcal_gizmo_dispose (GObject *object)
{
GtkWidget *widget = GTK_WIDGET (object);
GtkWidget *child;
while ((child = gtk_widget_get_first_child (widget)))
gtk_widget_unparent (child);
G_OBJECT_CLASS (gcal_gizmo_parent_class)->dispose (object);
}
/*
* Initialization
*/
static void
gcal_gizmo_class_init (GcalGizmoClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->dispose = gcal_gizmo_dispose;
widget_class->measure = gcal_gizmo_real_measure;
widget_class->size_allocate = gcal_gizmo_real_size_allocate;
widget_class->snapshot = gcal_gizmo_real_snapshot;
widget_class->focus = gcal_gizmo_real_focus;
}
static void
gcal_gizmo_init (GcalGizmo *self)
{
}
/**
* gcal_gizmo_new:
*
* Create a new #GcalGizmo.
*
* Returns: (transfer full): a newly created #GcalGizmo
*/
GcalGizmo *
gcal_gizmo_new (void)
{
return g_object_new (GCAL_TYPE_GIZMO, NULL);
}
/**
* gcal_gizmo_set_measure_func:
* @self: a #GcalGizmo
* @measure_func: (scope call): the function to set
*
* Set the function overriding [vfunc@Gtk.Widget.measure].
*/
void
gcal_gizmo_set_measure_func (GcalGizmo *self,
GcalGizmoMeasureFunc measure_func,
gpointer user_data)
{
g_assert (GCAL_IS_GIZMO (self));
self->measure_func = measure_func;
self->measure_user_data = user_data;
gtk_widget_queue_resize (GTK_WIDGET (self));
}
/**
* gcal_gizmo_set_size_allocate_func:
* @self: a #GcalGizmo
* @size_allocate_func: (scope call): the function to set
*
* Set the function overriding [vfunc@Gtk.Widget.size_allocate].
*/
void
gcal_gizmo_set_size_allocate_func (GcalGizmo *self,
GcalGizmoSizeAllocateFunc size_allocate_func,
gpointer user_data)
{
g_assert (GCAL_IS_GIZMO (self));
self->size_allocate_func = size_allocate_func;
self->size_allocate_user_data = user_data;
gtk_widget_queue_allocate (GTK_WIDGET (self));
}
/**
* gcal_gizmo_set_snapshot_func:
* @self: a #GcalGizmo
* @snapshot_func: (scope call): the function to set
*
* Set the function overriding [vfunc@Gtk.Widget.snapshot].
*/
void
gcal_gizmo_set_snapshot_func (GcalGizmo *self,
GcalGizmoSnapshotFunc snapshot_func,
gpointer user_data)
{
g_assert (GCAL_IS_GIZMO (self));
self->snapshot_func = snapshot_func;
self->snapshot_user_data = user_data;
gtk_widget_queue_draw (GTK_WIDGET (self));
}
/**
* gcal_gizmo_set_focus_func:
* @self: a #GcalGizmo
* @focus_func: (scope call): the function to set
*
* Set the function overriding [vfunc@Gtk.Widget.focus].
*/
void
gcal_gizmo_set_focus_func (GcalGizmo *self,
GcalGizmoFocusFunc focus_func,
gpointer user_data)
{
g_assert (GCAL_IS_GIZMO (self));
self->focus_func = focus_func;
self->focus_user_data = user_data;
}