summaryrefslogtreecommitdiff
path: root/src/widgets/control-center/control-details.c
diff options
context:
space:
mode:
authorHannes Schulze <haschu0103@outlook.de>2024-05-06 13:42:55 +0200
committerHannes Schulze <haschu0103@outlook.de>2024-05-06 14:33:54 +0200
commit37d5ef75306c45ca95550f4af40d9750c5b9cb88 (patch)
tree7125c8e8445eeecb86097bc99bb2d1febfb7e2a5 /src/widgets/control-center/control-details.c
initial commit
yup, i definitely wrote all of this in a single commit
Diffstat (limited to 'src/widgets/control-center/control-details.c')
-rw-r--r--src/widgets/control-center/control-details.c289
1 files changed, 289 insertions, 0 deletions
diff --git a/src/widgets/control-center/control-details.c b/src/widgets/control-center/control-details.c
new file mode 100644
index 0000000..4f0d422
--- /dev/null
+++ b/src/widgets/control-center/control-details.c
@@ -0,0 +1,289 @@
+#include "widgets/control-center/control-details.h"
+
+//
+// FoobarControlDetails:
+//
+// A revealer for details in the "controls" section of the control center. This widget is usually used to embed a list
+// view. It takes care of scrolling by embedding the child in a GtkScrolledWindow.
+//
+
+struct _FoobarControlDetails
+{
+ GtkWidget parent_instance;
+ GtkWidget* child;
+ gboolean is_expanded;
+ gint inset_top;
+};
+
+enum
+{
+ PROP_CHILD = 1,
+ PROP_IS_EXPANDED,
+ PROP_INSET_TOP,
+ N_PROPS,
+};
+
+static GParamSpec* props[N_PROPS] = { 0 };
+
+static void foobar_control_details_class_init ( FoobarControlDetailsClass* klass );
+static void foobar_control_details_init ( FoobarControlDetails* self );
+static void foobar_control_details_get_property( GObject* object,
+ guint prop_id,
+ GValue* value,
+ GParamSpec* pspec );
+static void foobar_control_details_set_property( GObject* object,
+ guint prop_id,
+ GValue const* value,
+ GParamSpec* pspec );
+static void foobar_control_details_dispose ( GObject* object );
+
+G_DEFINE_FINAL_TYPE( FoobarControlDetails, foobar_control_details, GTK_TYPE_WIDGET )
+
+// ---------------------------------------------------------------------------------------------------------------------
+// Widget Implementation
+// ---------------------------------------------------------------------------------------------------------------------
+
+//
+// Static initialization for control details.
+//
+void foobar_control_details_class_init( FoobarControlDetailsClass* klass )
+{
+ GtkWidgetClass* widget_klass = GTK_WIDGET_CLASS( klass );
+ gtk_widget_class_set_css_name( widget_klass, "control-details" );
+ gtk_widget_class_set_layout_manager_type( widget_klass, GTK_TYPE_BIN_LAYOUT );
+
+ GObjectClass* object_klass = G_OBJECT_CLASS( klass );
+ object_klass->get_property = foobar_control_details_get_property;
+ object_klass->set_property = foobar_control_details_set_property;
+ object_klass->dispose = foobar_control_details_dispose;
+
+ props[PROP_CHILD] = g_param_spec_object(
+ "child",
+ "Child",
+ "Child widget for the details revealer.",
+ GTK_TYPE_WIDGET,
+ G_PARAM_READWRITE );
+ props[PROP_IS_EXPANDED] = g_param_spec_boolean(
+ "is-expanded",
+ "Is Expanded",
+ "Current state of the details revealer.",
+ FALSE,
+ G_PARAM_READWRITE );
+ props[PROP_INSET_TOP] = g_param_spec_int(
+ "inset-top",
+ "Inset Top",
+ "Inset from the top edge (only visible when expanded).",
+ 0,
+ INT_MAX,
+ 0,
+ G_PARAM_READWRITE );
+ g_object_class_install_properties( object_klass, N_PROPS, props );
+}
+
+//
+// Instance initialization for control details.
+//
+void foobar_control_details_init( FoobarControlDetails* self )
+{
+ GtkWidget* scrolled_window = gtk_scrolled_window_new( );
+ gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( scrolled_window ), GTK_POLICY_NEVER, GTK_POLICY_EXTERNAL );
+ gtk_scrolled_window_set_propagate_natural_height( GTK_SCROLLED_WINDOW( scrolled_window ), TRUE );
+ g_object_bind_property(
+ self,
+ "child",
+ scrolled_window,
+ "child",
+ G_BINDING_SYNC_CREATE );
+ g_object_bind_property(
+ self,
+ "inset-top",
+ scrolled_window,
+ "margin-top",
+ G_BINDING_SYNC_CREATE );
+
+ GtkWidget* revealer = gtk_revealer_new( );
+ gtk_revealer_set_transition_type( GTK_REVEALER( revealer ), GTK_REVEALER_TRANSITION_TYPE_SLIDE_DOWN );
+ gtk_revealer_set_transition_duration( GTK_REVEALER( revealer ), 100 );
+ gtk_revealer_set_child( GTK_REVEALER( revealer ), scrolled_window );
+ g_object_bind_property(
+ self,
+ "is-expanded",
+ revealer,
+ "reveal-child",
+ G_BINDING_SYNC_CREATE );
+
+ gtk_widget_set_parent( revealer, GTK_WIDGET( self ) );
+}
+
+//
+// Property getter implementation, mapping a property id to a method.
+//
+void foobar_control_details_get_property(
+ GObject* object,
+ guint prop_id,
+ GValue* value,
+ GParamSpec* pspec )
+{
+ FoobarControlDetails* self = (FoobarControlDetails*)object;
+
+ switch ( prop_id )
+ {
+ case PROP_CHILD:
+ g_value_set_object( value, foobar_control_details_get_child( self ) );
+ break;
+ case PROP_IS_EXPANDED:
+ g_value_set_boolean( value, foobar_control_details_is_expanded( self ) );
+ break;
+ case PROP_INSET_TOP:
+ g_value_set_int( value, foobar_control_details_get_inset_top( 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_set_property(
+ GObject* object,
+ guint prop_id,
+ GValue const* value,
+ GParamSpec* pspec )
+{
+ FoobarControlDetails* self = (FoobarControlDetails*)object;
+
+ switch ( prop_id )
+ {
+ case PROP_CHILD:
+ foobar_control_details_set_child( self, g_value_get_object( value ) );
+ break;
+ case PROP_IS_EXPANDED:
+ foobar_control_details_set_expanded( self, g_value_get_boolean( value ) );
+ break;
+ case PROP_INSET_TOP:
+ foobar_control_details_set_inset_top( self, g_value_get_int( value ) );
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID( object, prop_id, pspec );
+ break;
+ }
+}
+
+//
+// Instance de-initialization for control details.
+//
+void foobar_control_details_dispose( GObject* object )
+{
+ FoobarControlDetails* self = (FoobarControlDetails*)object;
+
+ GtkWidget* child;
+ while ( ( child = gtk_widget_get_first_child( GTK_WIDGET( self ) ) ) )
+ {
+ gtk_widget_unparent( child );
+ }
+
+ g_clear_object( &self->child );
+
+ G_OBJECT_CLASS( foobar_control_details_parent_class )->dispose( object );
+}
+
+// ---------------------------------------------------------------------------------------------------------------------
+// Public API
+// ---------------------------------------------------------------------------------------------------------------------
+
+//
+// Create a new control details instance.
+//
+GtkWidget* foobar_control_details_new( void )
+{
+ return g_object_new( FOOBAR_TYPE_CONTROL_DETAILS, NULL );
+}
+
+//
+// Get the child widget for the details revealer.
+//
+GtkWidget* foobar_control_details_get_child( FoobarControlDetails* self )
+{
+ g_return_val_if_fail( FOOBAR_IS_CONTROL_DETAILS( self ), NULL );
+ return self->child;
+}
+
+//
+// Get the current state of the details revealer.
+//
+gboolean foobar_control_details_is_expanded( FoobarControlDetails* self )
+{
+ g_return_val_if_fail( FOOBAR_IS_CONTROL_DETAILS( self ), FALSE );
+ return self->is_expanded;
+}
+
+//
+// Get the inset from the top edge (only visible when expanded).
+//
+gint foobar_control_details_get_inset_top( FoobarControlDetails* self )
+{
+ g_return_val_if_fail( FOOBAR_IS_CONTROL_DETAILS( self ), FALSE );
+ return self->inset_top;
+}
+
+//
+// Update the child widget for the details revealer.
+//
+void foobar_control_details_set_child(
+ FoobarControlDetails* self,
+ GtkWidget* value )
+{
+ g_return_if_fail( FOOBAR_IS_CONTROL_DETAILS( self ) );
+
+ if ( self->child != value )
+ {
+ g_clear_object( &self->child );
+ if ( value ) { self->child = g_object_ref( value ); }
+ g_object_notify_by_pspec( G_OBJECT( self ), props[PROP_CHILD] );
+ }
+}
+
+//
+// Update the current state of the details revealer.
+//
+void foobar_control_details_set_expanded(
+ FoobarControlDetails* self,
+ gboolean value )
+{
+ g_return_if_fail( FOOBAR_IS_CONTROL_DETAILS( self ) );
+
+ value = !!value;
+ if ( self->is_expanded != value )
+ {
+ self->is_expanded = value;
+ g_object_notify_by_pspec( G_OBJECT( self ), props[PROP_IS_EXPANDED] );
+
+ if ( self->is_expanded )
+ {
+ gtk_widget_add_css_class( GTK_WIDGET( self ), "expanded" );
+ }
+ else
+ {
+ gtk_widget_remove_css_class( GTK_WIDGET( self ), "expanded" );
+ }
+ }
+}
+
+//
+// Update the inset from the top edge (only visible when expanded).
+//
+void foobar_control_details_set_inset_top(
+ FoobarControlDetails* self,
+ gint value )
+{
+ g_return_if_fail( FOOBAR_IS_CONTROL_DETAILS( self ) );
+
+ value = MAX( value, 0 );
+ if ( self->inset_top != value )
+ {
+ self->inset_top = value;
+ g_object_notify_by_pspec( G_OBJECT( self ), props[PROP_INSET_TOP] );
+ }
+} \ No newline at end of file