1
1
mirror of https://gitlab.gnome.org/GNOME/gimp.git synced 2025-10-06 01:12:40 +02:00

Compare commits

...

5 Commits

Author SHA1 Message Date
Jehan
aa05004985 gimp-ux#176: align expander arrow to the right.
The GimpCheckExpander now takes the max possible amount as allocated to
the full frame. It means that if several GimpCheckExpander objects are
added on a same container and are all made to take as much space as
possible, their arrow should also align.

As a secondary update in this commit, the full space after the label is
clickable and would expand the frame (not just the arrow), hence making
expanding/collapsing easier without having to be extra accurate in
pointing the small arrow.
2025-09-22 21:54:54 +02:00
Jehan
9daf021a7f app: port more setting to GimpCheckExpander. 2025-09-22 21:54:54 +02:00
Jehan
200cb75260 gimp-ux#176: gray-out the triangle when collapsed.
I was trying to convey the difference of the collapsed frame by making
the triangle empty. But graying it out instead (while keeping it filled)
may be a more common UI styling.
2025-09-22 21:54:54 +02:00
Jehan
5f596e3ded app: use the new GimpCheckExpander widget for Dynamics settings.
This is a first usage mostly for testing.

This new widget doesn't use bold text to show it will expand
sub-settings, unlike the previous expanding frame (issue gimp-ux#176).
Instead it shows a small triangle on the side, as is customary for
expanders.

Furthermore the expansion state is stored as a separate property, which
means you can enable dynamics while still hiding all sub-options, hence
saving space in the tool options (issue gimp-ux#311).
2025-09-22 21:54:54 +02:00
Jehan
7ef2e80f69 Issue gimp-ux#176: new GimpCheckExpander widget.
Core-only widget for now. The idea is a widget which has both an
enabled/checked state and an expanded/collapse state which will show a
child widget.

When enabling or disabling the main boolean value, it also triggers the
expansion of the child widget, but the opposite is not true.
2025-09-22 21:54:54 +02:00
9 changed files with 590 additions and 8 deletions

View File

@@ -62,6 +62,7 @@
#define DEFAULT_USE_JITTER FALSE
#define DEFAULT_JITTER_AMOUNT 0.2
#define DEFAULT_JITTER_ENABLED TRUE
#define DEFAULT_DYNAMICS_ENABLED TRUE
#define DEFAULT_FADE_LENGTH 100.0
@@ -111,9 +112,11 @@ enum
PROP_HARD,
PROP_USE_JITTER,
PROP_JITTER_SETTINGS_SHOWN,
PROP_JITTER_AMOUNT,
PROP_DYNAMICS_ENABLED,
PROP_DYNAMICS_SETTINGS_SHOWN,
PROP_FADE_LENGTH,
PROP_FADE_REVERSE,
@@ -134,10 +137,12 @@ enum
PROP_GRADIENT_VIEW_SIZE,
PROP_USE_SMOOTHING,
PROP_SMOOTHING_SETTINGS_SHOWN,
PROP_SMOOTHING_QUALITY,
PROP_SMOOTHING_FACTOR,
PROP_EXPAND_USE,
PROP_EXPAND_LAYERS_SETTINGS_SHOWN,
PROP_EXPAND_AMOUNT,
PROP_EXPAND_FILL_TYPE,
PROP_EXPAND_MASK_FILL_TYPE
@@ -313,6 +318,12 @@ gimp_paint_options_class_init (GimpPaintOptionsClass *klass)
_("Scatter brush as you paint"),
DEFAULT_USE_JITTER,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_JITTER_SETTINGS_SHOWN,
"jitter-settings-shown",
_("Showing Jitter settings"),
_("Showing sub-settings for the jitter"),
DEFAULT_USE_JITTER,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_EXPAND_USE,
"expand-use",
@@ -320,6 +331,12 @@ gimp_paint_options_class_init (GimpPaintOptionsClass *klass)
_("Expand active layer as you paint"),
DEFAULT_EXPAND_USE,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_EXPAND_LAYERS_SETTINGS_SHOWN,
"expand-layers-settings-shown",
_("Showing Expand Layers settings"),
_("Showing sub-settings for the Expand Layers feature"),
DEFAULT_EXPAND_USE,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_EXPAND_AMOUNT,
"expand-amount",
@@ -350,6 +367,12 @@ gimp_paint_options_class_init (GimpPaintOptionsClass *klass)
_("Apply dynamics curves to paint settings"),
DEFAULT_DYNAMICS_ENABLED,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_DYNAMICS_SETTINGS_SHOWN,
"dynamics-settings-shown",
_("Showing dynamics settings"),
_("Showing sub-settings for the dynamics"),
DEFAULT_DYNAMICS_ENABLED,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_JITTER_AMOUNT,
"jitter-amount",
@@ -465,6 +488,12 @@ gimp_paint_options_class_init (GimpPaintOptionsClass *klass)
_("Paint smoother strokes"),
FALSE,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_SMOOTHING_SETTINGS_SHOWN,
"smoothing-settings-shown",
_("Showing Smoothing settings"),
_("Showing sub-settings for Smoothing"),
FALSE,
GIMP_PARAM_STATIC_STRINGS);
GIMP_CONFIG_PROP_INT (object_class, PROP_SMOOTHING_QUALITY,
"smoothing-quality",
_("Quality"),
@@ -609,6 +638,9 @@ gimp_paint_options_set_property (GObject *object,
case PROP_USE_JITTER:
jitter_options->use_jitter = g_value_get_boolean (value);
break;
case PROP_JITTER_SETTINGS_SHOWN:
options->jitter_settings_shown = g_value_get_boolean (value);
break;
case PROP_JITTER_AMOUNT:
jitter_options->jitter_amount = g_value_get_double (value);
break;
@@ -616,6 +648,9 @@ gimp_paint_options_set_property (GObject *object,
case PROP_DYNAMICS_ENABLED:
options->dynamics_enabled = g_value_get_boolean (value);
break;
case PROP_DYNAMICS_SETTINGS_SHOWN:
options->dynamics_settings_shown = g_value_get_boolean (value);
break;
case PROP_FADE_LENGTH:
fade_options->fade_length = g_value_get_double (value);
@@ -671,6 +706,9 @@ gimp_paint_options_set_property (GObject *object,
case PROP_USE_SMOOTHING:
smoothing_options->use_smoothing = g_value_get_boolean (value);
break;
case PROP_SMOOTHING_SETTINGS_SHOWN:
options->smoothing_settings_shown = g_value_get_boolean (value);
break;
case PROP_SMOOTHING_QUALITY:
smoothing_options->smoothing_quality = g_value_get_int (value);
break;
@@ -681,6 +719,9 @@ gimp_paint_options_set_property (GObject *object,
case PROP_EXPAND_USE:
options->expand_use = g_value_get_boolean (value);
break;
case PROP_EXPAND_LAYERS_SETTINGS_SHOWN:
options->expand_use_shown = g_value_get_boolean (value);
break;
case PROP_EXPAND_AMOUNT:
options->expand_amount = g_value_get_double (value);
break;
@@ -768,6 +809,9 @@ gimp_paint_options_get_property (GObject *object,
case PROP_USE_JITTER:
g_value_set_boolean (value, jitter_options->use_jitter);
break;
case PROP_JITTER_SETTINGS_SHOWN:
g_value_set_boolean (value, options->jitter_settings_shown);
break;
case PROP_JITTER_AMOUNT:
g_value_set_double (value, jitter_options->jitter_amount);
break;
@@ -775,6 +819,9 @@ gimp_paint_options_get_property (GObject *object,
case PROP_DYNAMICS_ENABLED:
g_value_set_boolean (value, options->dynamics_enabled);
break;
case PROP_DYNAMICS_SETTINGS_SHOWN:
g_value_set_boolean (value, options->dynamics_settings_shown);
break;
case PROP_FADE_LENGTH:
g_value_set_double (value, fade_options->fade_length);
@@ -830,6 +877,9 @@ gimp_paint_options_get_property (GObject *object,
case PROP_USE_SMOOTHING:
g_value_set_boolean (value, smoothing_options->use_smoothing);
break;
case PROP_SMOOTHING_SETTINGS_SHOWN:
g_value_set_boolean (value, options->smoothing_settings_shown);
break;
case PROP_SMOOTHING_QUALITY:
g_value_set_int (value, smoothing_options->smoothing_quality);
break;
@@ -840,6 +890,9 @@ gimp_paint_options_get_property (GObject *object,
case PROP_EXPAND_USE:
g_value_set_boolean (value, options->expand_use);
break;
case PROP_EXPAND_LAYERS_SETTINGS_SHOWN:
g_value_set_boolean (value, options->expand_use_shown);
break;
case PROP_EXPAND_AMOUNT:
g_value_set_double (value, options->expand_amount);
break;

View File

@@ -104,16 +104,21 @@ struct _GimpPaintOptions
gboolean hard;
gboolean expand_use;
gboolean expand_use_shown;
gdouble expand_amount;
GimpFillType expand_fill_type;
GimpAddMaskType expand_mask_fill_type;
gboolean jitter_settings_shown;
GimpJitterOptions *jitter_options;
gboolean dynamics_enabled;
gboolean dynamics_settings_shown;
GimpFadeOptions *fade_options;
GimpGradientPaintOptions *gradient_options;
GimpSmoothingOptions *smoothing_options;
gboolean smoothing_settings_shown;
GimpViewType brush_view_type;
GimpViewSize brush_view_size;

View File

@@ -322,8 +322,9 @@ dynamics_options_gui (GimpPaintOptions *paint_options,
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
frame = gimp_prop_expanding_frame_new (config, "dynamics-enabled",
NULL, vbox, NULL);
frame = gimp_prop_check_expander_new (config, "dynamics-enabled",
"dynamics-settings-shown",
vbox);
button = gimp_prop_dynamics_box_new (NULL,
GIMP_CONTEXT (config),
_("Dynamics"), 2,
@@ -415,8 +416,9 @@ jitter_options_gui (GimpPaintOptions *paint_options,
0.01, 1.0, 2);
gimp_spin_scale_set_scale_limits (GIMP_SPIN_SCALE (scale), 0.0, 5.0);
frame = gimp_prop_expanding_frame_new (config, "use-jitter", NULL,
scale, NULL);
frame = gimp_prop_check_expander_new (config, "use-jitter",
"jitter-settings-shown",
scale);
return frame;
}
@@ -432,8 +434,9 @@ smoothing_options_gui (GimpPaintOptions *paint_options,
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
frame = gimp_prop_expanding_frame_new (config, "use-smoothing", NULL,
vbox, NULL);
frame = gimp_prop_check_expander_new (config, "use-smoothing",
"smoothing-settings-shown",
vbox);
scale = gimp_prop_spin_scale_new (config, "smoothing-quality",
1, 10, 1);
@@ -532,8 +535,9 @@ expand_options_gui (GimpPaintOptions *paint_options,
_("Fill Layer Mask With"), 0, 1);
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
frame = gimp_prop_expanding_frame_new (config, "expand-use", NULL,
vbox, NULL);
frame = gimp_prop_check_expander_new (config, "expand-use",
"expand-layers-settings-shown",
vbox);
return frame;
}

View File

@@ -0,0 +1,395 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpcheckexpander.c
* Copyright (C) 2025 Jehan
*
* 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 <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "widgets-types.h"
#include "libgimpbase/gimpbase.h"
#include "libgimpwidgets/gimpwidgets.h"
#include "core/gimp.h"
#include "gimpcheckexpander.h"
#include "gimpwidgets-utils.h"
#define GIMP_CHECK_EXPANDER_ACTION_KEY "gimp-expander-action"
/**
* GimpCheckExpander:
*
* A checkbox widget which is also an expander in the same time, showing
* sub-contents when the box is checked.
*
* With a side "triangle" button, it is also possible to collapse or
* expand the contents independently to the box being checked or not.
*/
enum
{
PROP_0,
PROP_LABEL,
PROP_CHECKED,
PROP_EXPANDED,
PROP_CHILD,
N_PROPS
};
struct _GimpCheckExpanderPrivate
{
GtkWidget *frame_title;
GtkWidget *checkbox;
GtkWidget *expander;
gboolean expanded;
};
static void gimp_check_expander_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void gimp_check_expander_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static void gimp_check_expander_size_allocate (GtkWidget *widget,
GtkAllocation *allocation);
static gboolean gimp_check_expander_triangle_draw (GtkWidget *triangle,
cairo_t *cr,
GimpCheckExpander *expander);
static gboolean gimp_check_expander_triangle_clicked (GtkWidget *triangle,
GdkEventButton *event,
GimpCheckExpander *expander);
static void gimp_check_expander_checked (GtkToggleButton *checkbox,
GimpCheckExpander *expander);
G_DEFINE_TYPE_WITH_PRIVATE (GimpCheckExpander, gimp_check_expander, GIMP_TYPE_FRAME)
#define parent_class gimp_check_expander_parent_class
static GParamSpec *props[N_PROPS] = { NULL, };
/* Class functions */
static void
gimp_check_expander_class_init (GimpCheckExpanderClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->get_property = gimp_check_expander_get_property;
object_class->set_property = gimp_check_expander_set_property;
widget_class->size_allocate = gimp_check_expander_size_allocate;
props[PROP_LABEL] = g_param_spec_string ("label", NULL, NULL,
NULL,
GIMP_PARAM_READWRITE | G_PARAM_CONSTRUCT);
props[PROP_CHECKED] = g_param_spec_boolean ("checked",
NULL, NULL,
FALSE,
GIMP_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY);
props[PROP_EXPANDED] = g_param_spec_boolean ("expanded",
NULL, NULL,
FALSE,
GIMP_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
props[PROP_CHILD] = g_param_spec_object ("child",
"Child widget",
"The child widget which is shown when this widget is expanded",
GTK_TYPE_WIDGET,
GIMP_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_properties (object_class, N_PROPS, props);
}
static void
gimp_check_expander_init (GimpCheckExpander *expander)
{
GtkWidget *title;
expander->priv = gimp_check_expander_get_instance_private (expander);
expander->priv->expanded = FALSE;
title = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 1.0);
expander->priv->frame_title = title;
gtk_widget_set_hexpand (title, TRUE);
gtk_frame_set_label_widget (GTK_FRAME (expander), title);
gtk_widget_set_visible (title, TRUE);
expander->priv->checkbox = gtk_check_button_new ();
gtk_button_set_use_underline (GTK_BUTTON (expander->priv->checkbox), TRUE);
gtk_box_pack_start (GTK_BOX (title), expander->priv->checkbox, FALSE, FALSE, 0.0);
gtk_widget_set_visible (expander->priv->checkbox, TRUE);
expander->priv->expander = gtk_drawing_area_new ();
gtk_widget_set_hexpand (expander->priv->expander, TRUE);
gtk_widget_set_size_request (expander->priv->expander, 12, 12);
gtk_box_pack_start (GTK_BOX (title), expander->priv->expander, TRUE, TRUE, 0.0);
gtk_widget_set_visible (expander->priv->expander, TRUE);
g_signal_connect (G_OBJECT (expander->priv->expander), "draw",
G_CALLBACK (gimp_check_expander_triangle_draw),
expander);
gtk_widget_add_events (expander->priv->expander, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
g_signal_connect (G_OBJECT (expander->priv->expander), "button-release-event",
G_CALLBACK (gimp_check_expander_triangle_clicked),
expander);
g_signal_connect (expander->priv->checkbox, "toggled",
G_CALLBACK (gimp_check_expander_checked),
expander);
}
static void
gimp_check_expander_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
GimpCheckExpander *expander = GIMP_CHECK_EXPANDER (object);
switch (property_id)
{
case PROP_LABEL:
gtk_button_set_label (GTK_BUTTON (expander->priv->checkbox), g_value_get_string (value));
break;
case PROP_CHECKED:
gimp_check_expander_set_checked (expander, g_value_get_boolean (value), FALSE);
break;
case PROP_EXPANDED:
gimp_check_expander_set_expanded (expander, g_value_get_boolean (value));
break;
case PROP_CHILD:
gtk_container_add (GTK_CONTAINER (expander), g_value_get_object (value));
gtk_widget_set_visible (g_value_get_object (value), expander->priv->expanded);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gimp_check_expander_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GimpCheckExpander *expander = GIMP_CHECK_EXPANDER (object);
switch (property_id)
{
case PROP_LABEL:
g_value_set_string (value, gtk_button_get_label (GTK_BUTTON (expander->priv->checkbox)));
break;
case PROP_CHECKED:
g_value_set_boolean (value, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (expander->priv->checkbox)));
break;
case PROP_EXPANDED:
g_value_set_boolean (value, expander->priv->expanded);
break;
case PROP_CHILD:
g_value_set_object (value, gtk_bin_get_child (GTK_BIN (expander)));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gimp_check_expander_size_allocate (GtkWidget *widget,
GtkAllocation *allocation)
{
GimpCheckExpander *expander = GIMP_CHECK_EXPANDER (widget);
GtkAllocation title_allocation;
GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation);
gtk_widget_get_allocation (expander->priv->frame_title, &title_allocation);
if (title_allocation.width < allocation->width - 1)
{
title_allocation.width = allocation->width - 1;
gtk_widget_size_allocate (expander->priv->frame_title, &title_allocation);
}
}
/* Public functions */
GtkWidget *
gimp_check_expander_new (const gchar *label,
GtkWidget *child)
{
return g_object_new (GIMP_TYPE_CHECK_EXPANDER,
"label", label,
"child", child,
NULL);
}
void
gimp_check_expander_set_label (GimpCheckExpander *expander,
const gchar *label)
{
g_return_if_fail (GIMP_IS_CHECK_EXPANDER (expander));
g_object_set (expander, "label", label, NULL);
}
const gchar *
gimp_check_expander_get_label (GimpCheckExpander *expander,
const gchar *label)
{
g_return_val_if_fail (GIMP_IS_CHECK_EXPANDER (expander), NULL);
return gtk_button_get_label (GTK_BUTTON (expander->priv->checkbox));
}
void
gimp_check_expander_set_checked (GimpCheckExpander *expander,
gboolean checked,
gboolean auto_expand)
{
g_signal_handlers_block_by_func (expander->priv->checkbox,
G_CALLBACK (gimp_check_expander_checked),
expander);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (expander->priv->checkbox), checked);
g_signal_handlers_unblock_by_func (expander->priv->checkbox,
G_CALLBACK (gimp_check_expander_checked),
expander);
if (auto_expand)
gimp_check_expander_set_expanded (expander, checked);
g_object_notify_by_pspec (G_OBJECT (expander), props[PROP_CHECKED]);
}
void
gimp_check_expander_set_expanded (GimpCheckExpander *expander,
gboolean expanded)
{
g_return_if_fail (GIMP_IS_CHECK_EXPANDER (expander));
if (expander->priv->expanded != expanded)
{
GtkWidget *child = gtk_bin_get_child (GTK_BIN (expander));
expander->priv->expanded = expanded;
gtk_widget_set_visible (child, expanded);
g_object_notify_by_pspec (G_OBJECT (expander), props[PROP_EXPANDED]);
gtk_widget_queue_draw (GTK_WIDGET (expander));
}
}
/* Private functions */
static void
gimp_check_expander_checked (GtkToggleButton *checkbox,
GimpCheckExpander *expander)
{
gimp_check_expander_set_expanded (expander, gtk_toggle_button_get_active (checkbox));
g_object_notify_by_pspec (G_OBJECT (expander), props[PROP_CHECKED]);
}
static gboolean
gimp_check_expander_triangle_draw (GtkWidget *triangle,
cairo_t *cr,
GimpCheckExpander *expander)
{
GtkStyleContext *context;
PangoFontDescription *font_desc;
GdkRGBA *color;
gint width;
gint height;
gint font_size;
gdouble triangle_side;
context = gtk_widget_get_style_context (triangle);
width = gtk_widget_get_allocated_width (triangle);
height = gtk_widget_get_allocated_height (triangle);
gtk_render_background (context, cr, 0, 0, width, height);
gtk_style_context_get (context,
gtk_style_context_get_state (context),
GTK_STYLE_PROPERTY_FONT, &font_desc,
GTK_STYLE_PROPERTY_COLOR, &color,
NULL);
/* Get the font size in pixels */
if (pango_font_description_get_size_is_absolute (font_desc))
font_size = pango_font_description_get_size (font_desc);
else
font_size = pango_font_description_get_size (font_desc) / PANGO_SCALE;
pango_font_description_free (font_desc);
triangle_side = MIN (font_size, MIN (width, height));
if ((gint) triangle_side % 2 == 1)
triangle_side -= 1;
if (expander->priv->expanded)
{
gdk_cairo_set_source_rgba (cr, color);
cairo_move_to (cr, width - triangle_side - 2.0, (height - triangle_side) / 2.0);
cairo_line_to (cr, (gdouble) width - 2.0, (height - triangle_side) / 2.0);
cairo_line_to (cr, width - 2.0 - triangle_side / 2.0, (gdouble) height - (height - triangle_side) / 2.0);
cairo_line_to (cr, width - triangle_side - 2.0, (height - triangle_side) / 2.0);
}
else
{
color->alpha /= 2;
gdk_cairo_set_source_rgba (cr, color);
cairo_move_to (cr, width - triangle_side - 2.0, (height - triangle_side) / 2.0);
cairo_line_to (cr, width - triangle_side - 2.0, (gdouble) height - (height - triangle_side) / 2.0);
cairo_line_to (cr, (gdouble) (width - 2.0), height / 2.0);
cairo_line_to (cr, width - triangle_side - 2.0, (height - triangle_side) / 2.0);
}
cairo_fill (cr);
gdk_rgba_free (color);
return FALSE;
}
static
gboolean gimp_check_expander_triangle_clicked (GtkWidget *triangle,
GdkEventButton *event,
GimpCheckExpander *expander)
{
gimp_check_expander_set_expanded (expander, ! expander->priv->expanded);
return TRUE;
}

View File

@@ -0,0 +1,66 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpcheckexpander.h
* Copyright (C) 2025 Jehan
*
* 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 <https://www.gnu.org/licenses/>.
*/
#ifndef __GIMP_CHECK_EXPANDER_H__
#define __GIMP_CHECK_EXPANDER_H__
#define GIMP_TYPE_CHECK_EXPANDER (gimp_check_expander_get_type ())
#define GIMP_CHECK_EXPANDER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_CHECK_EXPANDER, GimpCheckExpander))
#define GIMP_CHECK_EXPANDER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_CHECK_EXPANDER, GimpCheckExpanderClass))
#define GIMP_IS_CHECK_EXPANDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GIMP_TYPE_CHECK_EXPANDER))
#define GIMP_IS_CHECK_EXPANDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_CHECK_EXPANDER))
#define GIMP_CHECK_EXPANDER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_CHECK_EXPANDER, GimpCheckExpanderClass))
typedef struct _GimpCheckExpanderPrivate GimpCheckExpanderPrivate;
typedef struct _GimpCheckExpanderClass GimpCheckExpanderClass;
struct _GimpCheckExpander
{
GimpFrame parent_instance;
GimpCheckExpanderPrivate *priv;
};
struct _GimpCheckExpanderClass
{
GimpFrameClass parent_class;
};
GType gimp_check_expander_get_type (void) G_GNUC_CONST;
GtkWidget * gimp_check_expander_new (const gchar *label,
GtkWidget *child);
void gimp_check_expander_set_label (GimpCheckExpander *expander,
const gchar *label);
const gchar * gimp_check_expander_get_label (GimpCheckExpander *expander,
const gchar *label);
void gimp_check_expander_set_checked (GimpCheckExpander *expander,
gboolean checked,
gboolean auto_expand);
void gimp_check_expander_set_expanded (GimpCheckExpander *expander,
gboolean expanded);
#endif /* __GIMP_CHECK_EXPANDER_H__ */

View File

@@ -40,6 +40,7 @@
#include "core/gimpcontext.h"
#include "core/gimpviewable.h"
#include "gimpcheckexpander.h"
#include "gimpcolorbar.h"
#include "gimpcolorpanel.h"
#include "gimpcompressioncombobox.h"
@@ -146,6 +147,58 @@ gimp_prop_expanding_frame_new (GObject *config,
return frame;
}
/**
* gimp_prop_check_expander_new:
* @config: #GimpConfig object to which properties are attached.
* @property_name: Name of boolean property controlling the checkbox.
* @expand_property_name: Name of boolean property controlling the expansion.
* @child: Child #GtkWidget being expanded.
*
* Creates a #GimpCheckExpander expanding @child.
*
* Returns: A new #GimpCheckExpander widget.
*
* Since: 3.2
*/
GtkWidget *
gimp_prop_check_expander_new (GObject *config,
const gchar *property_name,
const gchar *expand_property_name,
GtkWidget *child)
{
GParamSpec *param_spec;
GtkWidget *frame;
const gchar *check_label;
param_spec = check_param_spec_w (config, property_name,
G_TYPE_PARAM_BOOLEAN, G_STRFUNC);
if (! param_spec)
return NULL;
check_label = g_param_spec_get_nick (param_spec);
param_spec = check_param_spec_w (config, expand_property_name,
G_TYPE_PARAM_BOOLEAN, G_STRFUNC);
if (! param_spec)
return NULL;
frame = gimp_check_expander_new (check_label, child);
g_object_bind_property (G_OBJECT (config), property_name,
G_OBJECT (frame), "checked",
G_BINDING_BIDIRECTIONAL |
G_BINDING_SYNC_CREATE);
g_object_bind_property (G_OBJECT (config), expand_property_name,
G_OBJECT (frame), "expanded",
G_BINDING_BIDIRECTIONAL |
G_BINDING_SYNC_CREATE);
gimp_widget_set_bound_property (frame, config, property_name);
gtk_widget_set_visible (frame, TRUE);
return frame;
}
/**********************/
/* boolean icon box */

View File

@@ -28,6 +28,10 @@ GtkWidget * gimp_prop_expanding_frame_new (GObject *config,
const gchar *button_label,
GtkWidget *child,
GtkWidget **button);
GtkWidget * gimp_prop_check_expander_new (GObject *config,
const gchar *property_name,
const gchar *expand_property_name,
GtkWidget *child);
GtkWidget * gimp_prop_boolean_icon_box_new (GObject *config,
const gchar *property_name,

View File

@@ -45,6 +45,7 @@ libappwidgets_sources = [
'gimpcellrendererdashes.c',
'gimpcellrendererviewable.c',
'gimpchanneltreeview.c',
'gimpcheckexpander.c',
'gimpcircle.c',
'gimpclipboard.c',
'gimpcolorbar.c',

View File

@@ -175,6 +175,7 @@ typedef struct _GimpActionEditor GimpActionEditor;
typedef struct _GimpActionView GimpActionView;
typedef struct _GimpBlobEditor GimpBlobEditor;
typedef struct _GimpBufferSourceBox GimpBufferSourceBox;
typedef struct _GimpCheckExpander GimpCheckExpander;
typedef struct _GimpCircle GimpCircle;
typedef struct _GimpColorBar GimpColorBar;
typedef struct _GimpColorDisplayEditor GimpColorDisplayEditor;