summaryrefslogtreecommitdiff
path: root/csrc/widgets/control-center/control-details-item.c
diff options
context:
space:
mode:
Diffstat (limited to 'csrc/widgets/control-center/control-details-item.c')
-rw-r--r--csrc/widgets/control-center/control-details-item.c307
1 files changed, 307 insertions, 0 deletions
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 );
+}