*
* Copyright 2025 Hari Rana <theevilskeleton@riseup.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 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/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "bz-list-tile.h"
typedef struct
{
GtkWidget *child;
} BzListTilePrivate;
G_DEFINE_TYPE_WITH_PRIVATE (BzListTile, bz_list_tile, GTK_TYPE_WIDGET)
enum
{
PROP_0,
PROP_CHILD,
LAST_PROP
};
static GParamSpec *props[LAST_PROP];
enum
{
ACTIVATED,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = {
0,
};
static void
on_gesture_click_released (BzListTile *self,
gint n_press,
gdouble x,
gdouble y,
GtkGestureClick *gesture);
static void
bz_list_tile_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
BzListTile *self = BZ_LIST_TILE (object);
switch (prop_id)
{
case PROP_CHILD:
g_value_set_object (value, bz_list_tile_get_child (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
bz_list_tile_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
BzListTile *self = BZ_LIST_TILE (object);
switch (prop_id)
{
case PROP_CHILD:
bz_list_tile_set_child (self, g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
bz_list_tile_dispose (GObject *object)
{
BzListTile *self = BZ_LIST_TILE (object);
BzListTilePrivate *priv = bz_list_tile_get_instance_private (self);
g_clear_pointer (&priv->child, gtk_widget_unparent);
G_OBJECT_CLASS (bz_list_tile_parent_class)->dispose (object);
}
static void
bz_list_tile_class_init (BzListTileClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->get_property = bz_list_tile_get_property;
object_class->set_property = bz_list_tile_set_property;
object_class->dispose = bz_list_tile_dispose;
* BzListTile:child:
*
* The child widget.
*/
props[PROP_CHILD] =
g_param_spec_object ("child", NULL, NULL,
GTK_TYPE_WIDGET,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, LAST_PROP, props);
* BzListTile::activated:
*
* This signal is emitted after the tile has been activated.
*/
signals[ACTIVATED] =
g_signal_new ("activated",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
0, NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE,
0);
{
g_autoptr (GtkShortcutAction) activate_action = NULL;
const guint activate_keyvals[] = {
GDK_KEY_space,
GDK_KEY_KP_Space,
GDK_KEY_Return,
GDK_KEY_ISO_Enter,
GDK_KEY_KP_Enter,
};
activate_action = gtk_signal_action_new ("activated");
for (size_t i = 0; i < G_N_ELEMENTS (activate_keyvals); i++)
{
g_autoptr (GtkShortcut) activate_shortcut = NULL;
activate_shortcut = gtk_shortcut_new (gtk_keyval_trigger_new (activate_keyvals[i], 0),
g_object_ref (activate_action));
gtk_widget_class_add_shortcut (widget_class, activate_shortcut);
}
}
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
}
static void
bz_list_tile_init (BzListTile *self)
{
GtkGesture *gesture_click;
gtk_widget_add_css_class (GTK_WIDGET (self), "card");
gtk_widget_add_css_class (GTK_WIDGET (self), "activatable");
gesture_click = gtk_gesture_click_new ();
g_signal_connect_swapped (gesture_click, "released", G_CALLBACK (on_gesture_click_released), self);
gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (gesture_click));
gtk_widget_set_focusable (GTK_WIDGET (self), TRUE);
gtk_widget_set_receives_default (GTK_WIDGET (self), TRUE);
}
* bz_list_tile_new:
*
* Create a new #BzListTile.
*
* Returns: (transfer full): a newly created #BzListTile
*/
BzListTile *
bz_list_tile_new (void)
{
return g_object_new (BZ_TYPE_LIST_TILE, NULL);
}
* bz_list_tile_get_child:
* @self: a #BzListTile
*
* Get the child associated with @self.
*
* Returns: (transfer none) (nullable): the child
*/
GtkWidget *
bz_list_tile_get_child (BzListTile *self)
{
BzListTilePrivate *priv;
g_assert (BZ_IS_LIST_TILE (self));
priv = bz_list_tile_get_instance_private (self);
return priv->child;
}
* bz_list_tile_set_child:
* @self: a #BzListTile
* @child: (transfer none): the child
*
* Set the child to associate with @self.
*/
void
bz_list_tile_set_child (BzListTile *self,
GtkWidget *child)
{
BzListTilePrivate *priv;
g_assert (BZ_IS_LIST_TILE (self));
priv = bz_list_tile_get_instance_private (self);
priv->child = child;
gtk_widget_set_parent (child, GTK_WIDGET (self));
}
static void
on_gesture_click_released (BzListTile *self,
gint n_press,
gdouble x,
gdouble y,
GtkGestureClick *gesture)
{
if (gtk_widget_contains (GTK_WIDGET (self), x, y))
{
gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
g_signal_emit (self, signals[ACTIVATED], 0);
}
else
{
gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_DENIED);
}
}