From 1af3d14f3f995645a0de08a54b244c19840709e9 Mon Sep 17 00:00:00 2001 From: Hannes Schulze Date: Thu, 19 Jun 2025 23:17:58 +0200 Subject: init hs project --- csrc/widgets/control-center/control-details-item.c | 307 +++++++++++++++++++++ 1 file changed, 307 insertions(+) create mode 100644 csrc/widgets/control-center/control-details-item.c (limited to 'csrc/widgets/control-center/control-details-item.c') diff --git a/csrc/widgets/control-center/control-details-item.c b/csrc/widgets/control-center/control-details-item.c new file mode 100644 index 0000000..cb54dd3 --- /dev/null +++ b/csrc/widgets/control-center/control-details-item.c @@ -0,0 +1,307 @@ +#include "widgets/control-center/control-details-item.h" + +// +// FoobarControlDetailsAccessory: +// +// The accessory shown next to an item in the control center details list (if any). +// + +G_DEFINE_ENUM_TYPE( + FoobarControlDetailsAccessory, + foobar_control_details_accessory, + G_DEFINE_ENUM_VALUE( FOOBAR_CONTROL_DETAILS_ACCESSORY_NONE, "none" ), + G_DEFINE_ENUM_VALUE( FOOBAR_CONTROL_DETAILS_ACCESSORY_PROGRESS, "progress" ), + G_DEFINE_ENUM_VALUE( FOOBAR_CONTROL_DETAILS_ACCESSORY_CHECKED, "checked" ) ) + +// +// FoobarControlDetailsItem: +// +// Standard row layout for items in a FoobarControlDetails list. The rows are made up of a label and an accessory that +// is shown or hidden depending on the item's state. +// + +struct _FoobarControlDetailsItem +{ + GtkWidget parent_instance; + GtkWidget* spinner; + GtkWidget* checkmark; + gchar* label; + FoobarControlDetailsAccessory accessory; +}; + +enum +{ + PROP_LABEL = 1, + PROP_ACCESSORY, + PROP_IS_CHECKED, + N_PROPS, +}; + +static GParamSpec* props[N_PROPS] = { 0 }; + +static void foobar_control_details_item_class_init ( FoobarControlDetailsItemClass* klass ); +static void foobar_control_details_item_init ( FoobarControlDetailsItem* self ); +static void foobar_control_details_item_get_property( GObject* object, + guint prop_id, + GValue* value, + GParamSpec* pspec ); +static void foobar_control_details_item_set_property( GObject* object, + guint prop_id, + GValue const* value, + GParamSpec* pspec ); +static void foobar_control_details_item_dispose ( GObject* object ); +static void foobar_control_details_item_finalize ( GObject* object ); + +G_DEFINE_FINAL_TYPE( FoobarControlDetailsItem, foobar_control_details_item, GTK_TYPE_WIDGET ) + +// --------------------------------------------------------------------------------------------------------------------- +// Widget Implementation +// --------------------------------------------------------------------------------------------------------------------- + +// +// Static initialization for control details items. +// +void foobar_control_details_item_class_init( FoobarControlDetailsItemClass* klass ) +{ + GtkWidgetClass* widget_klass = GTK_WIDGET_CLASS( klass ); + gtk_widget_class_set_css_name( widget_klass, "control-details-item" ); + gtk_widget_class_set_layout_manager_type( widget_klass, GTK_TYPE_BOX_LAYOUT ); + + GObjectClass* object_klass = G_OBJECT_CLASS( klass ); + object_klass->get_property = foobar_control_details_item_get_property; + object_klass->set_property = foobar_control_details_item_set_property; + object_klass->dispose = foobar_control_details_item_dispose; + object_klass->finalize = foobar_control_details_item_finalize; + + props[PROP_LABEL] = g_param_spec_string( + "label", + "Label", + "Label shown for the item.", + NULL, + G_PARAM_READWRITE ); + props[PROP_ACCESSORY] = g_param_spec_enum( + "accessory", + "Accessory", + "Accessory shown for the item.", + FOOBAR_TYPE_CONTROL_DETAILS_ACCESSORY, + 0, + G_PARAM_READWRITE ); + props[PROP_IS_CHECKED] = g_param_spec_boolean( + "is-checked", + "Is Checked", + "Current checked-state for the item.", + FALSE, + G_PARAM_READWRITE ); + g_object_class_install_properties( object_klass, N_PROPS, props ); +} + +// +// Instance initialization for control details items. +// +void foobar_control_details_item_init( FoobarControlDetailsItem* self ) +{ + GtkWidget* label = gtk_label_new( NULL ); + gtk_widget_set_hexpand( label, TRUE ); + gtk_widget_set_valign( label, GTK_ALIGN_CENTER ); + gtk_label_set_ellipsize( GTK_LABEL( label ), PANGO_ELLIPSIZE_END ); + gtk_label_set_justify( GTK_LABEL( label ), GTK_JUSTIFY_LEFT ); + gtk_label_set_xalign( GTK_LABEL( label ), 0 ); + gtk_label_set_wrap( GTK_LABEL( label ), FALSE ); + g_object_bind_property( + self, + "label", + label, + "label", + G_BINDING_SYNC_CREATE ); + + self->spinner = gtk_spinner_new( ); + gtk_spinner_set_spinning( GTK_SPINNER( self->spinner ), TRUE ); + gtk_widget_add_css_class( self->spinner, "accessory" ); + gtk_widget_set_valign( self->spinner, GTK_ALIGN_CENTER ); + gtk_widget_set_visible( self->spinner, FALSE ); + + self->checkmark = gtk_image_new_from_icon_name( "fluent-checkmark-symbolic" ); + gtk_widget_add_css_class( self->checkmark, "checkmark" ); + gtk_widget_add_css_class( self->checkmark, "accessory" ); + gtk_widget_set_valign( self->checkmark, GTK_ALIGN_CENTER ); + gtk_widget_set_visible( self->checkmark, FALSE ); + + gtk_widget_insert_before( label, GTK_WIDGET( self ), NULL ); + gtk_widget_insert_before( self->spinner, GTK_WIDGET( self ), NULL ); + gtk_widget_insert_before( self->checkmark, GTK_WIDGET( self ), NULL ); +} + +// +// Property getter implementation, mapping a property id to a method. +// +void foobar_control_details_item_get_property( + GObject* object, + guint prop_id, + GValue* value, + GParamSpec* pspec ) +{ + FoobarControlDetailsItem* self = (FoobarControlDetailsItem*)object; + + switch ( prop_id ) + { + case PROP_LABEL: + g_value_set_string( value, foobar_control_details_item_get_label( self ) ); + break; + case PROP_ACCESSORY: + g_value_set_enum( value, foobar_control_details_item_get_accessory( self ) ); + break; + case PROP_IS_CHECKED: + g_value_set_boolean( value, foobar_control_details_item_is_checked( self ) ); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID( object, prop_id, pspec ); + break; + } +} + +// +// Property setter implementation, mapping a property id to a method. +// +void foobar_control_details_item_set_property( + GObject* object, + guint prop_id, + GValue const* value, + GParamSpec* pspec ) +{ + FoobarControlDetailsItem* self = (FoobarControlDetailsItem*)object; + + switch ( prop_id ) + { + case PROP_LABEL: + foobar_control_details_item_set_label( self, g_value_get_string( value ) ); + break; + case PROP_ACCESSORY: + foobar_control_details_item_set_accessory( self, g_value_get_enum( value ) ); + break; + case PROP_IS_CHECKED: + foobar_control_details_item_set_checked( self, g_value_get_boolean( value ) ); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID( object, prop_id, pspec ); + break; + } +} + +// +// Instance de-initialization for control details items. +// +void foobar_control_details_item_dispose( GObject* object ) +{ + FoobarControlDetailsItem* self = (FoobarControlDetailsItem*)object; + + GtkWidget* child; + while ( ( child = gtk_widget_get_first_child( GTK_WIDGET( self ) ) ) ) + { + gtk_widget_unparent( child ); + } + + G_OBJECT_CLASS( foobar_control_details_item_parent_class )->dispose( object ); +} + +// +// Instance cleanup for control details items. +// +void foobar_control_details_item_finalize( GObject* object ) +{ + FoobarControlDetailsItem* self = (FoobarControlDetailsItem*)object; + + g_clear_pointer( &self->label, g_free ); + + G_OBJECT_CLASS( foobar_control_details_item_parent_class )->finalize( object ); +} + +// --------------------------------------------------------------------------------------------------------------------- +// Public API +// --------------------------------------------------------------------------------------------------------------------- + +// +// Create a new control details item instance. +// +GtkWidget* foobar_control_details_item_new( void ) +{ + return g_object_new( FOOBAR_TYPE_CONTROL_DETAILS_ITEM, NULL ); +} + +// +// Get the label shown for the item. +// +gchar const* foobar_control_details_item_get_label( FoobarControlDetailsItem* self ) +{ + g_return_val_if_fail( FOOBAR_IS_CONTROL_DETAILS_ITEM( self ), NULL ); + return self->label; +} + +// +// Get the accessory shown for the item. +// +FoobarControlDetailsAccessory foobar_control_details_item_get_accessory( FoobarControlDetailsItem* self ) +{ + g_return_val_if_fail( FOOBAR_IS_CONTROL_DETAILS_ITEM( self ), 0 ); + return self->accessory; +} + +// +// Get the current checked-state for the item. +// +gboolean foobar_control_details_item_is_checked( FoobarControlDetailsItem* self ) +{ + g_return_val_if_fail( FOOBAR_IS_CONTROL_DETAILS_ITEM( self ), FALSE ); + return self->accessory == FOOBAR_CONTROL_DETAILS_ACCESSORY_CHECKED; +} + +// +// Update the label shown for the item. +// +void foobar_control_details_item_set_label( + FoobarControlDetailsItem* self, + gchar const* value ) +{ + g_return_if_fail( FOOBAR_IS_CONTROL_DETAILS_ITEM( self ) ); + + if ( g_strcmp0( self->label, value ) ) + { + g_clear_pointer( &self->label, g_free ); + self->label = g_strdup( value ); + g_object_notify_by_pspec( G_OBJECT( self ), props[PROP_LABEL] ); + } +} + +// +// Update the current accessory shown for the item. +// +void foobar_control_details_item_set_accessory( + FoobarControlDetailsItem* self, + FoobarControlDetailsAccessory value ) +{ + g_return_if_fail( FOOBAR_IS_CONTROL_DETAILS_ITEM( self ) ); + + if ( self->accessory != value ) + { + self->accessory = value; + g_object_notify_by_pspec( G_OBJECT( self ), props[PROP_ACCESSORY] ); + g_object_notify_by_pspec( G_OBJECT( self ), props[PROP_IS_CHECKED] ); + + gtk_widget_set_visible( self->spinner, self->accessory == FOOBAR_CONTROL_DETAILS_ACCESSORY_PROGRESS ); + gtk_widget_set_visible( self->checkmark, self->accessory == FOOBAR_CONTROL_DETAILS_ACCESSORY_CHECKED ); + } +} + +// +// Update the current checked-state for the item. +// +void foobar_control_details_item_set_checked( + FoobarControlDetailsItem* self, + gboolean value ) +{ + g_return_if_fail( FOOBAR_IS_CONTROL_DETAILS_ITEM( self ) ); + + FoobarControlDetailsAccessory accessory = value + ? FOOBAR_CONTROL_DETAILS_ACCESSORY_CHECKED + : FOOBAR_CONTROL_DETAILS_ACCESSORY_NONE; + foobar_control_details_item_set_accessory( self, accessory ); +} -- cgit v1.3.1