mirror of https://github.com/GNOME/gimp.git
libgimpwidgets: make GimpScaleEntry a child class of GimpLabelSpin.
This commit is contained in:
parent
4ea2b430be
commit
079d8fd7f2
|
@ -42,48 +42,17 @@
|
||||||
* mnemonic on the #GtkSpinButton.
|
* mnemonic on the #GtkSpinButton.
|
||||||
**/
|
**/
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
VALUE_CHANGED,
|
|
||||||
LAST_SIGNAL
|
|
||||||
};
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
PROP_0,
|
|
||||||
PROP_LABEL,
|
|
||||||
PROP_VALUE,
|
|
||||||
PROP_LOWER,
|
|
||||||
PROP_UPPER,
|
|
||||||
PROP_DIGITS,
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct _GimpScaleEntryPrivate
|
typedef struct _GimpScaleEntryPrivate
|
||||||
{
|
{
|
||||||
GtkWidget *label;
|
|
||||||
GtkWidget *spinbutton;
|
|
||||||
GtkWidget *scale;
|
GtkWidget *scale;
|
||||||
|
|
||||||
GBinding *binding;
|
GBinding *binding;
|
||||||
|
|
||||||
GtkAdjustment *spin_adjustment;
|
|
||||||
|
|
||||||
gboolean logarithmic;
|
gboolean logarithmic;
|
||||||
|
gboolean limit_scale;
|
||||||
} GimpScaleEntryPrivate;
|
} GimpScaleEntryPrivate;
|
||||||
|
|
||||||
|
|
||||||
static void gimp_scale_entry_constructed (GObject *object);
|
static void gimp_scale_entry_constructed (GObject *object);
|
||||||
static void gimp_scale_entry_set_property (GObject *object,
|
|
||||||
guint property_id,
|
|
||||||
const GValue *value,
|
|
||||||
GParamSpec *pspec);
|
|
||||||
static void gimp_scale_entry_get_property (GObject *object,
|
|
||||||
guint property_id,
|
|
||||||
GValue *value,
|
|
||||||
GParamSpec *pspec);
|
|
||||||
|
|
||||||
static void gimp_scale_entry_update_spin_width (GimpScaleEntry *entry);
|
|
||||||
static void gimp_scale_entry_update_steps (GimpScaleEntry *entry);
|
|
||||||
|
|
||||||
static gboolean gimp_scale_entry_linear_to_log (GBinding *binding,
|
static gboolean gimp_scale_entry_linear_to_log (GBinding *binding,
|
||||||
const GValue *from_value,
|
const GValue *from_value,
|
||||||
|
@ -93,99 +62,21 @@ static gboolean gimp_scale_entry_log_to_linear (GBinding *binding,
|
||||||
const GValue *from_value,
|
const GValue *from_value,
|
||||||
GValue *to_value,
|
GValue *to_value,
|
||||||
gpointer user_data);
|
gpointer user_data);
|
||||||
|
void gimp_scale_entry_configure (GimpScaleEntry *entry);
|
||||||
|
|
||||||
|
|
||||||
G_DEFINE_TYPE_WITH_PRIVATE (GimpScaleEntry, gimp_scale_entry, GTK_TYPE_GRID)
|
G_DEFINE_TYPE_WITH_PRIVATE (GimpScaleEntry, gimp_scale_entry, GIMP_TYPE_LABEL_SPIN)
|
||||||
|
|
||||||
#define parent_class gimp_scale_entry_parent_class
|
#define parent_class gimp_scale_entry_parent_class
|
||||||
|
|
||||||
static guint gimp_scale_entry_signals[LAST_SIGNAL] = { 0 };
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gimp_scale_entry_class_init (GimpScaleEntryClass *klass)
|
gimp_scale_entry_class_init (GimpScaleEntryClass *klass)
|
||||||
{
|
{
|
||||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||||
|
|
||||||
gimp_scale_entry_signals[VALUE_CHANGED] =
|
|
||||||
g_signal_new ("value-changed",
|
|
||||||
G_TYPE_FROM_CLASS (klass),
|
|
||||||
G_SIGNAL_RUN_FIRST,
|
|
||||||
G_STRUCT_OFFSET (GimpScaleEntryClass, value_changed),
|
|
||||||
NULL, NULL, NULL,
|
|
||||||
G_TYPE_NONE, 0);
|
|
||||||
|
|
||||||
object_class->constructed = gimp_scale_entry_constructed;
|
object_class->constructed = gimp_scale_entry_constructed;
|
||||||
object_class->set_property = gimp_scale_entry_set_property;
|
|
||||||
object_class->get_property = gimp_scale_entry_get_property;
|
|
||||||
|
|
||||||
klass->new_range_widget = NULL;
|
klass->new_range_widget = NULL;
|
||||||
|
|
||||||
/**
|
|
||||||
* GimpScaleEntry:label:
|
|
||||||
*
|
|
||||||
* Since: 3.0
|
|
||||||
**/
|
|
||||||
g_object_class_install_property (object_class, PROP_LABEL,
|
|
||||||
g_param_spec_string ("label",
|
|
||||||
"Label text",
|
|
||||||
"The text of the label part of this widget",
|
|
||||||
NULL,
|
|
||||||
GIMP_PARAM_READWRITE));
|
|
||||||
|
|
||||||
/**
|
|
||||||
* GimpScaleEntry:value:
|
|
||||||
*
|
|
||||||
* Since: 3.0
|
|
||||||
**/
|
|
||||||
g_object_class_install_property (object_class, PROP_VALUE,
|
|
||||||
g_param_spec_double ("value", NULL,
|
|
||||||
"Current value",
|
|
||||||
-G_MAXDOUBLE, G_MAXDOUBLE, 1.0,
|
|
||||||
GIMP_PARAM_READWRITE));
|
|
||||||
|
|
||||||
/**
|
|
||||||
* GimpScaleEntry:lower:
|
|
||||||
*
|
|
||||||
* The lower bound of the widget. If the spin button and the scale
|
|
||||||
* widgets have different limits (see gimp_scale_entry_set_bounds()),
|
|
||||||
* this corresponds to the spin button lower value.
|
|
||||||
*
|
|
||||||
* Since: 3.0
|
|
||||||
**/
|
|
||||||
g_object_class_install_property (object_class, PROP_LOWER,
|
|
||||||
g_param_spec_double ("lower", NULL,
|
|
||||||
"Minimum value",
|
|
||||||
-G_MAXDOUBLE, G_MAXDOUBLE, 1.0,
|
|
||||||
GIMP_PARAM_READWRITE |
|
|
||||||
G_PARAM_CONSTRUCT));
|
|
||||||
|
|
||||||
/**
|
|
||||||
* GimpScaleEntry:upper:
|
|
||||||
*
|
|
||||||
* The upper bound of the widget. If the spin button and the scale
|
|
||||||
* widgets have different limits (see gimp_scale_entry_set_bounds()),
|
|
||||||
* this corresponds to the spin button upper value.
|
|
||||||
*
|
|
||||||
* Since: 3.0
|
|
||||||
**/
|
|
||||||
g_object_class_install_property (object_class, PROP_UPPER,
|
|
||||||
g_param_spec_double ("upper", NULL,
|
|
||||||
"Max value",
|
|
||||||
-G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
|
|
||||||
GIMP_PARAM_READWRITE |
|
|
||||||
G_PARAM_CONSTRUCT));
|
|
||||||
|
|
||||||
/**
|
|
||||||
* GimpScaleEntry:digits:
|
|
||||||
*
|
|
||||||
* Since: 3.0
|
|
||||||
**/
|
|
||||||
g_object_class_install_property (object_class, PROP_DIGITS,
|
|
||||||
g_param_spec_uint ("digits", NULL,
|
|
||||||
"The number of decimal places to display",
|
|
||||||
0, G_MAXUINT, 2,
|
|
||||||
GIMP_PARAM_READWRITE));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -193,13 +84,7 @@ gimp_scale_entry_init (GimpScaleEntry *entry)
|
||||||
{
|
{
|
||||||
GimpScaleEntryPrivate *priv = gimp_scale_entry_get_instance_private (entry);
|
GimpScaleEntryPrivate *priv = gimp_scale_entry_get_instance_private (entry);
|
||||||
|
|
||||||
/* The main adjustment (the scale adjustment in particular might be
|
priv->limit_scale = FALSE;
|
||||||
* smaller). We want it to exist at init so that construction
|
|
||||||
* properties can apply (default values are bogus but should be
|
|
||||||
* properly overrided with expected values if the object was created
|
|
||||||
* with gimp_scale_entry_new().
|
|
||||||
*/
|
|
||||||
priv->spin_adjustment = gtk_adjustment_new (0.0, 0.0, 100.0, 1.0, 10.0, 0.0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -209,23 +94,19 @@ gimp_scale_entry_constructed (GObject *object)
|
||||||
GimpScaleEntry *entry = GIMP_SCALE_ENTRY (object);
|
GimpScaleEntry *entry = GIMP_SCALE_ENTRY (object);
|
||||||
GimpScaleEntryPrivate *priv = gimp_scale_entry_get_instance_private (entry);
|
GimpScaleEntryPrivate *priv = gimp_scale_entry_get_instance_private (entry);
|
||||||
GtkAdjustment *scale_adjustment;
|
GtkAdjustment *scale_adjustment;
|
||||||
|
GtkAdjustment *spin_adjustment;
|
||||||
|
GtkWidget *spinbutton;
|
||||||
|
|
||||||
/* Label */
|
G_OBJECT_CLASS (parent_class)->constructed (object);
|
||||||
priv->label = gtk_label_new_with_mnemonic (NULL);
|
|
||||||
gtk_label_set_xalign (GTK_LABEL (priv->label), 0.0);
|
|
||||||
|
|
||||||
/* Spin button */
|
spinbutton = gimp_label_spin_get_spin_button (GIMP_LABEL_SPIN (entry));
|
||||||
priv->spinbutton = gimp_spin_button_new (priv->spin_adjustment, 2.0, 2.0);
|
spin_adjustment = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spinbutton));
|
||||||
gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (priv->spinbutton), TRUE);
|
scale_adjustment = gtk_adjustment_new (gtk_adjustment_get_value (spin_adjustment),
|
||||||
gtk_label_set_mnemonic_widget (GTK_LABEL (priv->label), priv->spinbutton);
|
gtk_adjustment_get_lower (spin_adjustment),
|
||||||
|
gtk_adjustment_get_upper (spin_adjustment),
|
||||||
/* Scale */
|
gtk_adjustment_get_step_increment (spin_adjustment),
|
||||||
scale_adjustment = gtk_adjustment_new (gtk_adjustment_get_value (priv->spin_adjustment),
|
gtk_adjustment_get_page_increment (spin_adjustment),
|
||||||
gtk_adjustment_get_lower (priv->spin_adjustment),
|
gtk_adjustment_get_page_size (spin_adjustment));
|
||||||
gtk_adjustment_get_upper (priv->spin_adjustment),
|
|
||||||
gtk_adjustment_get_step_increment (priv->spin_adjustment),
|
|
||||||
gtk_adjustment_get_page_increment (priv->spin_adjustment),
|
|
||||||
gtk_adjustment_get_page_size (priv->spin_adjustment));
|
|
||||||
|
|
||||||
klass = GIMP_SCALE_ENTRY_GET_CLASS (entry);
|
klass = GIMP_SCALE_ENTRY_GET_CLASS (entry);
|
||||||
if (klass->new_range_widget)
|
if (klass->new_range_widget)
|
||||||
|
@ -238,273 +119,26 @@ gimp_scale_entry_constructed (GObject *object)
|
||||||
{
|
{
|
||||||
priv->scale = gtk_scale_new (GTK_ORIENTATION_HORIZONTAL, scale_adjustment);
|
priv->scale = gtk_scale_new (GTK_ORIENTATION_HORIZONTAL, scale_adjustment);
|
||||||
gtk_scale_set_draw_value (GTK_SCALE (priv->scale), FALSE);
|
gtk_scale_set_draw_value (GTK_SCALE (priv->scale), FALSE);
|
||||||
|
|
||||||
|
g_object_bind_property (G_OBJECT (spinbutton), "digits",
|
||||||
|
G_OBJECT (priv->scale), "digits",
|
||||||
|
G_BINDING_BIDIRECTIONAL |
|
||||||
|
G_BINDING_SYNC_CREATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
gtk_widget_set_hexpand (priv->scale, TRUE);
|
gtk_widget_set_hexpand (priv->scale, TRUE);
|
||||||
|
|
||||||
gtk_grid_attach (GTK_GRID (entry), priv->label, 0, 0, 1, 1);
|
/* Move the spin button to the right. */
|
||||||
gtk_grid_attach (GTK_GRID (entry), priv->scale, 1, 0, 1, 1);
|
gtk_container_remove (GTK_CONTAINER (entry), g_object_ref (spinbutton));
|
||||||
gtk_grid_attach (GTK_GRID (entry), priv->spinbutton, 2, 0, 1, 1);
|
gtk_grid_attach (GTK_GRID (entry), spinbutton, 2, 0, 1, 1);
|
||||||
gtk_widget_show (priv->label);
|
|
||||||
|
gtk_grid_attach (GTK_GRID (entry), priv->scale, 1, 0, 1, 1);
|
||||||
gtk_widget_show (priv->scale);
|
gtk_widget_show (priv->scale);
|
||||||
gtk_widget_show (priv->spinbutton);
|
|
||||||
|
|
||||||
priv->binding = g_object_bind_property (G_OBJECT (priv->spin_adjustment), "value",
|
g_signal_connect_swapped (spin_adjustment, "changed",
|
||||||
G_OBJECT (scale_adjustment), "value",
|
G_CALLBACK (gimp_scale_entry_configure),
|
||||||
G_BINDING_BIDIRECTIONAL |
|
entry);
|
||||||
G_BINDING_SYNC_CREATE);
|
gimp_scale_entry_configure (entry);
|
||||||
|
|
||||||
/* This is important to make this object into a property widget. It
|
|
||||||
* will allow config object to bind the "value" property of this
|
|
||||||
* widget, and therefore be updated automatically.
|
|
||||||
*/
|
|
||||||
g_object_bind_property (G_OBJECT (priv->spin_adjustment), "value",
|
|
||||||
object, "value",
|
|
||||||
G_BINDING_BIDIRECTIONAL |
|
|
||||||
G_BINDING_SYNC_CREATE);
|
|
||||||
|
|
||||||
gimp_scale_entry_update_spin_width (entry);
|
|
||||||
gimp_scale_entry_update_steps (entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gimp_scale_entry_set_property (GObject *object,
|
|
||||||
guint property_id,
|
|
||||||
const GValue *value,
|
|
||||||
GParamSpec *pspec)
|
|
||||||
{
|
|
||||||
GimpScaleEntry *entry = GIMP_SCALE_ENTRY (object);
|
|
||||||
GimpScaleEntryPrivate *priv = gimp_scale_entry_get_instance_private (entry);
|
|
||||||
|
|
||||||
switch (property_id)
|
|
||||||
{
|
|
||||||
case PROP_LABEL:
|
|
||||||
{
|
|
||||||
/* This should not happen since the property is **not** set with
|
|
||||||
* G_PARAM_CONSTRUCT, hence the label should exist when the
|
|
||||||
* property is first set.
|
|
||||||
*/
|
|
||||||
g_return_if_fail (priv->label);
|
|
||||||
|
|
||||||
gtk_label_set_markup_with_mnemonic (GTK_LABEL (priv->label),
|
|
||||||
g_value_get_string (value));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case PROP_VALUE:
|
|
||||||
{
|
|
||||||
GtkSpinButton *spinbutton;
|
|
||||||
GtkAdjustment *adj;
|
|
||||||
|
|
||||||
g_return_if_fail (priv->spinbutton);
|
|
||||||
|
|
||||||
/* Set on the spin button, because it might have a bigger
|
|
||||||
* range, hence shows the real value.
|
|
||||||
*/
|
|
||||||
spinbutton = GTK_SPIN_BUTTON (priv->spinbutton);
|
|
||||||
adj = gtk_spin_button_get_adjustment (spinbutton);
|
|
||||||
|
|
||||||
/* Avoid looping forever since we have bound this widget's
|
|
||||||
* "value" property with the spin button "value" property.
|
|
||||||
*/
|
|
||||||
if (gtk_adjustment_get_value (adj) != g_value_get_double (value))
|
|
||||||
gtk_adjustment_set_value (adj, g_value_get_double (value));
|
|
||||||
|
|
||||||
g_signal_emit (object, gimp_scale_entry_signals[VALUE_CHANGED], 0);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case PROP_LOWER:
|
|
||||||
{
|
|
||||||
gtk_adjustment_set_lower (priv->spin_adjustment,
|
|
||||||
g_value_get_double (value));
|
|
||||||
|
|
||||||
if (priv->scale)
|
|
||||||
{
|
|
||||||
GtkRange *scale = GTK_RANGE (priv->scale);
|
|
||||||
|
|
||||||
/* If the widget does not exist, it means this is a
|
|
||||||
* pre-constructed property setting.
|
|
||||||
*/
|
|
||||||
gtk_adjustment_set_lower (gtk_range_get_adjustment (scale),
|
|
||||||
g_value_get_double (value));
|
|
||||||
|
|
||||||
gimp_scale_entry_update_spin_width (entry);
|
|
||||||
gimp_scale_entry_update_steps (entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case PROP_UPPER:
|
|
||||||
{
|
|
||||||
gtk_adjustment_set_upper (priv->spin_adjustment,
|
|
||||||
g_value_get_double (value));
|
|
||||||
|
|
||||||
if (priv->scale)
|
|
||||||
{
|
|
||||||
GtkRange *scale = GTK_RANGE (priv->scale);
|
|
||||||
|
|
||||||
gtk_adjustment_set_upper (gtk_range_get_adjustment (scale),
|
|
||||||
g_value_get_double (value));
|
|
||||||
|
|
||||||
gimp_scale_entry_update_spin_width (entry);
|
|
||||||
gimp_scale_entry_update_steps (entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case PROP_DIGITS:
|
|
||||||
{
|
|
||||||
g_return_if_fail (priv->scale && priv->spinbutton);
|
|
||||||
|
|
||||||
if (GTK_IS_SCALE (priv->scale))
|
|
||||||
/* Subclasses may set this to any GtkRange, in particular it
|
|
||||||
* may not be a subclass of GtkScale.
|
|
||||||
*/
|
|
||||||
gtk_scale_set_digits (GTK_SCALE (priv->scale),
|
|
||||||
g_value_get_uint (value));
|
|
||||||
|
|
||||||
gtk_spin_button_set_digits (GTK_SPIN_BUTTON (priv->spinbutton),
|
|
||||||
g_value_get_uint (value));
|
|
||||||
|
|
||||||
gimp_scale_entry_update_spin_width (entry);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gimp_scale_entry_get_property (GObject *object,
|
|
||||||
guint property_id,
|
|
||||||
GValue *value,
|
|
||||||
GParamSpec *pspec)
|
|
||||||
{
|
|
||||||
GimpScaleEntry *entry = GIMP_SCALE_ENTRY (object);
|
|
||||||
GimpScaleEntryPrivate *priv = gimp_scale_entry_get_instance_private (entry);
|
|
||||||
GtkSpinButton *spinbutton = GTK_SPIN_BUTTON (priv->spinbutton);
|
|
||||||
|
|
||||||
switch (property_id)
|
|
||||||
{
|
|
||||||
case PROP_LABEL:
|
|
||||||
g_value_set_string (value, gtk_label_get_label (GTK_LABEL (priv->label)));
|
|
||||||
break;
|
|
||||||
case PROP_VALUE:
|
|
||||||
g_value_set_double (value, gtk_spin_button_get_value (spinbutton));
|
|
||||||
break;
|
|
||||||
case PROP_LOWER:
|
|
||||||
{
|
|
||||||
GtkAdjustment *adj;
|
|
||||||
|
|
||||||
adj = gtk_spin_button_get_adjustment (spinbutton);
|
|
||||||
g_value_set_double (value, gtk_adjustment_get_lower (adj));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case PROP_UPPER:
|
|
||||||
{
|
|
||||||
GtkAdjustment *adj;
|
|
||||||
|
|
||||||
adj = gtk_spin_button_get_adjustment (spinbutton);
|
|
||||||
g_value_set_double (value, gtk_adjustment_get_upper (adj));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case PROP_DIGITS:
|
|
||||||
g_value_set_uint (value, gtk_spin_button_get_digits (spinbutton));
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gimp_scale_entry_update_spin_width (GimpScaleEntry *entry)
|
|
||||||
{
|
|
||||||
GimpScaleEntryPrivate *priv = gimp_scale_entry_get_instance_private (entry);
|
|
||||||
gint width = 0;
|
|
||||||
gdouble lower;
|
|
||||||
gdouble upper;
|
|
||||||
gint digits;
|
|
||||||
|
|
||||||
g_return_if_fail (GIMP_IS_SCALE_ENTRY (entry));
|
|
||||||
|
|
||||||
g_object_get (entry,
|
|
||||||
"lower", &lower,
|
|
||||||
"upper", &upper,
|
|
||||||
"digits", &digits,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
/* Necessary size to display the max/min integer values, with optional
|
|
||||||
* negative sign.
|
|
||||||
*/
|
|
||||||
width = (gint) floor (log10 (upper) + 1) + (upper < 0.0 ? 1 : 0);
|
|
||||||
width = MAX (width, (gint) floor (log10 (lower) + 1) + (lower < 0.0 ? 1 : 0));
|
|
||||||
|
|
||||||
/* Adding decimal digits and separator. */
|
|
||||||
width += (digits > 0 ? 1 + digits : 0);
|
|
||||||
|
|
||||||
/* Overlong spin button are useless. */
|
|
||||||
width = MIN (10, width);
|
|
||||||
|
|
||||||
gtk_entry_set_width_chars (GTK_ENTRY (priv->spinbutton), width);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gimp_scale_entry_update_steps (GimpScaleEntry *entry)
|
|
||||||
{
|
|
||||||
gdouble lower;
|
|
||||||
gdouble upper;
|
|
||||||
gdouble range;
|
|
||||||
|
|
||||||
g_return_if_fail (GIMP_IS_SCALE_ENTRY (entry));
|
|
||||||
|
|
||||||
g_object_get (entry,
|
|
||||||
"lower", &lower,
|
|
||||||
"upper", &upper,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
g_return_if_fail (upper >= lower);
|
|
||||||
|
|
||||||
range = upper - lower;
|
|
||||||
|
|
||||||
if (range > 0 && range <= 1.0)
|
|
||||||
{
|
|
||||||
gdouble places = 10.0;
|
|
||||||
gdouble step;
|
|
||||||
gdouble page;
|
|
||||||
|
|
||||||
/* Compute some acceptable step and page increments always in the
|
|
||||||
* format `10**-X` where X is the rounded precision.
|
|
||||||
* So for instance:
|
|
||||||
* 0.8 will have increments 0.01 and 0.1.
|
|
||||||
* 0.3 will have increments 0.001 and 0.01.
|
|
||||||
* 0.06 will also have increments 0.001 and 0.01.
|
|
||||||
*/
|
|
||||||
while (range * places < 5.0)
|
|
||||||
places *= 10.0;
|
|
||||||
|
|
||||||
|
|
||||||
step = 0.1 / places;
|
|
||||||
page = 1.0 / places;
|
|
||||||
|
|
||||||
gimp_scale_entry_set_increments (entry, step, page);
|
|
||||||
}
|
|
||||||
else if (range <= 2.0)
|
|
||||||
{
|
|
||||||
gimp_scale_entry_set_increments (entry, 0.01, 0.1);
|
|
||||||
}
|
|
||||||
else if (range <= 5.0)
|
|
||||||
{
|
|
||||||
gimp_scale_entry_set_increments (entry, 0.1, 1.0);
|
|
||||||
}
|
|
||||||
else if (range <= 40.0)
|
|
||||||
{
|
|
||||||
gimp_scale_entry_set_increments (entry, 1.0, 2.0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
gimp_scale_entry_set_increments (entry, 1.0, 10.0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
@ -585,83 +219,6 @@ gimp_scale_entry_new (const gchar *text,
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* gimp_scale_entry_set_value:
|
|
||||||
* @entry: The #GtkScaleEntry.
|
|
||||||
* @value: A new value.
|
|
||||||
*
|
|
||||||
* This function sets the value shown by @entry.
|
|
||||||
**/
|
|
||||||
void
|
|
||||||
gimp_scale_entry_set_value (GimpScaleEntry *entry,
|
|
||||||
gdouble value)
|
|
||||||
{
|
|
||||||
g_return_if_fail (GIMP_IS_SCALE_ENTRY (entry));
|
|
||||||
|
|
||||||
g_object_set (entry,
|
|
||||||
"value", value,
|
|
||||||
NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gimp_scale_entry_get_value:
|
|
||||||
* @entry: The #GtkScaleEntry.
|
|
||||||
*
|
|
||||||
* This function returns the value shown by @entry.
|
|
||||||
*
|
|
||||||
* Returns: The value currently set.
|
|
||||||
**/
|
|
||||||
gdouble
|
|
||||||
gimp_scale_entry_get_value (GimpScaleEntry *entry)
|
|
||||||
{
|
|
||||||
gdouble value;
|
|
||||||
|
|
||||||
g_return_val_if_fail (GIMP_IS_SCALE_ENTRY (entry), 0.0);
|
|
||||||
|
|
||||||
g_object_get (entry,
|
|
||||||
"value", &value,
|
|
||||||
NULL);
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gimp_scale_entry_get_label:
|
|
||||||
* @entry: The #GtkScaleEntry.
|
|
||||||
*
|
|
||||||
* This function returns the #GtkLabel packed in @entry. This can be
|
|
||||||
* useful if you need to customize some aspects of the widget.
|
|
||||||
*
|
|
||||||
* Returns: (transfer none): The #GtkLabel contained in @entry.
|
|
||||||
**/
|
|
||||||
GtkWidget *
|
|
||||||
gimp_scale_entry_get_label (GimpScaleEntry *entry)
|
|
||||||
{
|
|
||||||
GimpScaleEntryPrivate *priv = gimp_scale_entry_get_instance_private (entry);
|
|
||||||
|
|
||||||
g_return_val_if_fail (GIMP_IS_SCALE_ENTRY (entry), NULL);
|
|
||||||
|
|
||||||
return priv->label;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gimp_scale_entry_get_spin_button:
|
|
||||||
* @entry: The #GtkScaleEntry.
|
|
||||||
*
|
|
||||||
* This function returns the #GtkSpinButton packed in @entry. This can
|
|
||||||
* be useful if you need to customize some aspects of the widget.
|
|
||||||
*
|
|
||||||
* Returns: (transfer none): The #GtkSpinButton contained in @entry.
|
|
||||||
**/
|
|
||||||
GtkWidget *
|
|
||||||
gimp_scale_entry_get_spin_button (GimpScaleEntry *entry)
|
|
||||||
{
|
|
||||||
GimpScaleEntryPrivate *priv = gimp_scale_entry_get_instance_private (entry);
|
|
||||||
|
|
||||||
g_return_val_if_fail (GIMP_IS_SCALE_ENTRY (entry), NULL);
|
|
||||||
|
|
||||||
return priv->spinbutton;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gimp_scale_entry_get_range:
|
* gimp_scale_entry_get_range:
|
||||||
* @entry: The #GtkScaleEntry.
|
* @entry: The #GtkScaleEntry.
|
||||||
|
@ -697,13 +254,13 @@ gimp_scale_entry_get_range (GimpScaleEntry *entry)
|
||||||
* #GtkScale. If %TRUE, both @lower and @upper must be
|
* #GtkScale. If %TRUE, both @lower and @upper must be
|
||||||
* included in current #GtkSpinButton range.
|
* included in current #GtkSpinButton range.
|
||||||
*
|
*
|
||||||
* By default the #GtkSpinButton and #GtkScale will have the same range
|
* By default the #GtkSpinButton and #GtkScale will have the same range.
|
||||||
* (they will even share their GtkAdjustment). In some case, you want to
|
* In some case, you want to set a different range. In particular when
|
||||||
* set a different range. In particular when the finale range is huge,
|
* the finale range is huge, the #GtkScale might become nearly useless
|
||||||
* the #GtkScale might become nearly useless as every tiny slider move
|
* as every tiny slider move would dramatically update the value. In
|
||||||
* would dramatically update the value. In this case, it is common to
|
* this case, it is common to set the #GtkScale to a smaller common
|
||||||
* set the #GtkScale to a smaller common range, while the #GtkSpinButton
|
* range, while the #GtkSpinButton would allow for the full allowed
|
||||||
* would allow for the full allowed range.
|
* range.
|
||||||
* This function allows this. Obviously the #GtkAdjustment of both
|
* This function allows this. Obviously the #GtkAdjustment of both
|
||||||
* widgets would be synced but if the set value is out of the #GtkScale
|
* widgets would be synced but if the set value is out of the #GtkScale
|
||||||
* range, the slider would simply show at one extreme.
|
* range, the slider would simply show at one extreme.
|
||||||
|
@ -714,7 +271,7 @@ gimp_scale_entry_get_range (GimpScaleEntry *entry)
|
||||||
* Note that the step and page increments are updated when the range is
|
* Note that the step and page increments are updated when the range is
|
||||||
* updated according to some common usage algorithm which should work if
|
* updated according to some common usage algorithm which should work if
|
||||||
* you don't have very specific needs. If you want to customize the step
|
* you don't have very specific needs. If you want to customize the step
|
||||||
* increments yourself, you may call gimp_scale_entry_set_increments()
|
* increments yourself, you may call gimp_label_spin_set_increments()
|
||||||
**/
|
**/
|
||||||
void
|
void
|
||||||
gimp_scale_entry_set_bounds (GimpScaleEntry *entry,
|
gimp_scale_entry_set_bounds (GimpScaleEntry *entry,
|
||||||
|
@ -723,7 +280,7 @@ gimp_scale_entry_set_bounds (GimpScaleEntry *entry,
|
||||||
gboolean limit_scale)
|
gboolean limit_scale)
|
||||||
{
|
{
|
||||||
GimpScaleEntryPrivate *priv;
|
GimpScaleEntryPrivate *priv;
|
||||||
GtkSpinButton *spinbutton;
|
GtkWidget *spinbutton;
|
||||||
GtkAdjustment *spin_adjustment;
|
GtkAdjustment *spin_adjustment;
|
||||||
GtkAdjustment *scale_adjustment;
|
GtkAdjustment *scale_adjustment;
|
||||||
|
|
||||||
|
@ -731,10 +288,13 @@ gimp_scale_entry_set_bounds (GimpScaleEntry *entry,
|
||||||
g_return_if_fail (lower <= upper);
|
g_return_if_fail (lower <= upper);
|
||||||
|
|
||||||
priv = gimp_scale_entry_get_instance_private (entry);
|
priv = gimp_scale_entry_get_instance_private (entry);
|
||||||
spinbutton = GTK_SPIN_BUTTON (priv->spinbutton);
|
|
||||||
spin_adjustment = gtk_spin_button_get_adjustment (spinbutton);
|
|
||||||
scale_adjustment = gtk_range_get_adjustment (GTK_RANGE (priv->scale));
|
scale_adjustment = gtk_range_get_adjustment (GTK_RANGE (priv->scale));
|
||||||
|
|
||||||
|
spinbutton = gimp_label_spin_get_spin_button (GIMP_LABEL_SPIN (entry));
|
||||||
|
spin_adjustment = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spinbutton));
|
||||||
|
|
||||||
|
priv->limit_scale = limit_scale;
|
||||||
|
|
||||||
if (limit_scale)
|
if (limit_scale)
|
||||||
{
|
{
|
||||||
g_return_if_fail (lower >= gtk_adjustment_get_lower (spin_adjustment) &&
|
g_return_if_fail (lower >= gtk_adjustment_get_lower (spin_adjustment) &&
|
||||||
|
@ -742,6 +302,8 @@ gimp_scale_entry_set_bounds (GimpScaleEntry *entry,
|
||||||
|
|
||||||
gtk_adjustment_set_lower (scale_adjustment, lower);
|
gtk_adjustment_set_lower (scale_adjustment, lower);
|
||||||
gtk_adjustment_set_upper (scale_adjustment, upper);
|
gtk_adjustment_set_upper (scale_adjustment, upper);
|
||||||
|
|
||||||
|
gimp_scale_entry_configure (entry);
|
||||||
}
|
}
|
||||||
else if (! limit_scale)
|
else if (! limit_scale)
|
||||||
{
|
{
|
||||||
|
@ -770,41 +332,67 @@ gimp_scale_entry_set_logarithmic (GimpScaleEntry *entry,
|
||||||
gboolean logarithmic)
|
gboolean logarithmic)
|
||||||
{
|
{
|
||||||
GimpScaleEntryPrivate *priv;
|
GimpScaleEntryPrivate *priv;
|
||||||
|
|
||||||
|
g_return_if_fail (GIMP_IS_SCALE_ENTRY (entry));
|
||||||
|
|
||||||
|
priv = gimp_scale_entry_get_instance_private (entry);
|
||||||
|
|
||||||
|
if (logarithmic != priv->logarithmic)
|
||||||
|
{
|
||||||
|
priv->logarithmic = logarithmic;
|
||||||
|
gimp_scale_entry_configure (entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gimp_scale_entry_configure (GimpScaleEntry *entry)
|
||||||
|
{
|
||||||
|
GimpScaleEntryPrivate *priv;
|
||||||
|
GBinding *binding;
|
||||||
|
GtkWidget *spinbutton;
|
||||||
GtkAdjustment *spin_adj;
|
GtkAdjustment *spin_adj;
|
||||||
GtkAdjustment *scale_adj;
|
GtkAdjustment *scale_adj;
|
||||||
GBinding *binding;
|
gdouble scale_lower;
|
||||||
|
gdouble scale_upper;
|
||||||
|
|
||||||
g_return_if_fail (GIMP_IS_SCALE_ENTRY (entry));
|
g_return_if_fail (GIMP_IS_SCALE_ENTRY (entry));
|
||||||
|
|
||||||
priv = gimp_scale_entry_get_instance_private (entry);
|
priv = gimp_scale_entry_get_instance_private (entry);
|
||||||
spin_adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (priv->spinbutton));
|
|
||||||
scale_adj = gtk_range_get_adjustment (GTK_RANGE (priv->scale));
|
scale_adj = gtk_range_get_adjustment (GTK_RANGE (priv->scale));
|
||||||
|
|
||||||
if (logarithmic == priv->logarithmic)
|
spinbutton = gimp_label_spin_get_spin_button (GIMP_LABEL_SPIN (entry));
|
||||||
return;
|
spin_adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spinbutton));
|
||||||
|
|
||||||
g_clear_object (&priv->binding);
|
g_clear_object (&priv->binding);
|
||||||
|
|
||||||
if (logarithmic)
|
if (priv->limit_scale)
|
||||||
|
{
|
||||||
|
scale_lower = gtk_adjustment_get_lower (scale_adj);
|
||||||
|
scale_upper = gtk_adjustment_get_upper (scale_adj);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
scale_lower = gtk_adjustment_get_lower (spin_adj);
|
||||||
|
scale_upper = gtk_adjustment_get_upper (spin_adj);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (priv->logarithmic)
|
||||||
{
|
{
|
||||||
gdouble correction;
|
gdouble correction;
|
||||||
gdouble log_value, log_lower, log_upper;
|
gdouble log_value, log_lower, log_upper;
|
||||||
gdouble log_step_increment, log_page_increment;
|
gdouble log_step_increment, log_page_increment;
|
||||||
|
|
||||||
correction = (gtk_adjustment_get_lower (scale_adj) > 0 ?
|
correction = (scale_lower > 0 ? 0 : 0.1 + - scale_lower);
|
||||||
0 : 0.1 + - gtk_adjustment_get_lower (scale_adj));
|
|
||||||
|
|
||||||
log_value = log (gtk_adjustment_get_value (scale_adj) + correction);
|
log_value = log (gtk_adjustment_get_value (scale_adj) + correction);
|
||||||
log_lower = log (gtk_adjustment_get_lower (scale_adj) + correction);
|
log_lower = log (scale_lower + correction);
|
||||||
log_upper = log (gtk_adjustment_get_upper (scale_adj) + correction);
|
log_upper = log (scale_upper + correction);
|
||||||
log_step_increment =
|
log_step_increment =
|
||||||
(log_upper - log_lower) / ((gtk_adjustment_get_upper (scale_adj) -
|
(log_upper - log_lower) / ((scale_upper - scale_lower) /
|
||||||
gtk_adjustment_get_lower (scale_adj)) /
|
gtk_adjustment_get_step_increment (spin_adj));
|
||||||
gtk_adjustment_get_step_increment (scale_adj));
|
|
||||||
log_page_increment =
|
log_page_increment =
|
||||||
(log_upper - log_lower) / ((gtk_adjustment_get_upper (scale_adj) -
|
(log_upper - log_lower) / ((scale_upper - scale_lower) /
|
||||||
gtk_adjustment_get_lower (scale_adj)) /
|
gtk_adjustment_get_page_increment (spin_adj));
|
||||||
gtk_adjustment_get_page_increment (scale_adj));
|
|
||||||
|
|
||||||
gtk_adjustment_configure (scale_adj,
|
gtk_adjustment_configure (scale_adj,
|
||||||
log_value, log_lower, log_upper,
|
log_value, log_lower, log_upper,
|
||||||
|
@ -820,20 +408,9 @@ gimp_scale_entry_set_logarithmic (GimpScaleEntry *entry,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
gdouble lower, upper;
|
|
||||||
|
|
||||||
lower = exp (gtk_adjustment_get_lower (scale_adj));
|
|
||||||
upper = exp (gtk_adjustment_get_upper (scale_adj));
|
|
||||||
|
|
||||||
if (gtk_adjustment_get_lower (spin_adj) <= 0.0)
|
|
||||||
{
|
|
||||||
lower += - 0.1 + gtk_adjustment_get_lower (spin_adj);
|
|
||||||
upper += - 0.1 + gtk_adjustment_get_lower (spin_adj);
|
|
||||||
}
|
|
||||||
|
|
||||||
gtk_adjustment_configure (scale_adj,
|
gtk_adjustment_configure (scale_adj,
|
||||||
gtk_adjustment_get_value (spin_adj),
|
gtk_adjustment_get_value (spin_adj),
|
||||||
lower, upper,
|
scale_lower, scale_upper,
|
||||||
gtk_adjustment_get_step_increment (spin_adj),
|
gtk_adjustment_get_step_increment (spin_adj),
|
||||||
gtk_adjustment_get_page_increment (spin_adj),
|
gtk_adjustment_get_page_increment (spin_adj),
|
||||||
0.0);
|
0.0);
|
||||||
|
@ -844,8 +421,7 @@ gimp_scale_entry_set_logarithmic (GimpScaleEntry *entry,
|
||||||
G_BINDING_SYNC_CREATE);
|
G_BINDING_SYNC_CREATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
priv->binding = binding;
|
priv->binding = binding;
|
||||||
priv->logarithmic = logarithmic;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -866,56 +442,3 @@ gimp_scale_entry_get_logarithmic (GimpScaleEntry *entry)
|
||||||
|
|
||||||
return priv->logarithmic;
|
return priv->logarithmic;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* gimp_scale_entry_set_increments:
|
|
||||||
* @entry: the #GimpScaleEntry.
|
|
||||||
* @step: the step increment.
|
|
||||||
* @page: the page increment.
|
|
||||||
*
|
|
||||||
* Set the step and page increments for both the spin button and the
|
|
||||||
* scale. By default, these increment values are automatically computed
|
|
||||||
* depending on the range based on common usage. So you will likely not
|
|
||||||
* need to run this for most case. Yet if you want specific increments
|
|
||||||
* (which the widget cannot guess), you can call this function. If you
|
|
||||||
* want even more modularity and have different increments on each
|
|
||||||
* widget, use specific functions on gimp_scale_entry_get_spin_button()
|
|
||||||
* and gimp_scale_entry_get_range().
|
|
||||||
*
|
|
||||||
* Note that there is no `get` function because it could not return
|
|
||||||
* shared values in case you edited each widget separately.
|
|
||||||
* Just use specific functions on the spin button and scale instead if
|
|
||||||
* you need to get existing increments.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
gimp_scale_entry_set_increments (GimpScaleEntry *entry,
|
|
||||||
gdouble step,
|
|
||||||
gdouble page)
|
|
||||||
{
|
|
||||||
GimpScaleEntryPrivate *priv;
|
|
||||||
GtkSpinButton *spinbutton;
|
|
||||||
GtkRange *scale;
|
|
||||||
gdouble lower;
|
|
||||||
gdouble upper;
|
|
||||||
|
|
||||||
g_return_if_fail (GIMP_IS_SCALE_ENTRY (entry));
|
|
||||||
g_return_if_fail (step < page);
|
|
||||||
|
|
||||||
priv = gimp_scale_entry_get_instance_private (entry);
|
|
||||||
spinbutton = GTK_SPIN_BUTTON (priv->spinbutton);
|
|
||||||
scale = GTK_RANGE (priv->scale);
|
|
||||||
|
|
||||||
gtk_spin_button_get_range (spinbutton, &lower, &upper);
|
|
||||||
g_return_if_fail (upper >= lower);
|
|
||||||
g_return_if_fail (step < upper - lower && page < upper - lower);
|
|
||||||
|
|
||||||
gtk_adjustment_set_step_increment (gtk_range_get_adjustment (scale), step);
|
|
||||||
gtk_adjustment_set_step_increment (gtk_spin_button_get_adjustment (spinbutton), step);
|
|
||||||
|
|
||||||
gtk_adjustment_set_page_increment (gtk_range_get_adjustment (scale), page);
|
|
||||||
gtk_adjustment_set_page_increment (gtk_spin_button_get_adjustment (spinbutton), page);
|
|
||||||
|
|
||||||
g_object_set (priv->spinbutton,
|
|
||||||
"climb-rate", step,
|
|
||||||
NULL);
|
|
||||||
}
|
|
||||||
|
|
|
@ -25,17 +25,19 @@
|
||||||
#error "Only <libgimpwidgets/gimpwidgets.h> can be included directly."
|
#error "Only <libgimpwidgets/gimpwidgets.h> can be included directly."
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <libgimpwidgets/gimplabelspin.h>
|
||||||
|
|
||||||
#ifndef __GIMP_SCALE_ENTRY_H__
|
#ifndef __GIMP_SCALE_ENTRY_H__
|
||||||
#define __GIMP_SCALE_ENTRY_H__
|
#define __GIMP_SCALE_ENTRY_H__
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
#define GIMP_TYPE_SCALE_ENTRY (gimp_scale_entry_get_type ())
|
#define GIMP_TYPE_SCALE_ENTRY (gimp_scale_entry_get_type ())
|
||||||
G_DECLARE_DERIVABLE_TYPE (GimpScaleEntry, gimp_scale_entry, GIMP, SCALE_ENTRY, GtkGrid)
|
G_DECLARE_DERIVABLE_TYPE (GimpScaleEntry, gimp_scale_entry, GIMP, SCALE_ENTRY, GimpLabelSpin)
|
||||||
|
|
||||||
struct _GimpScaleEntryClass
|
struct _GimpScaleEntryClass
|
||||||
{
|
{
|
||||||
GtkGridClass parent_class;
|
GimpLabelSpinClass parent_class;
|
||||||
|
|
||||||
/* Signals */
|
/* Signals */
|
||||||
void (* value_changed) (GimpScaleEntry *entry);
|
void (* value_changed) (GimpScaleEntry *entry);
|
||||||
|
@ -60,12 +62,6 @@ GtkWidget * gimp_scale_entry_new (const gchar *text,
|
||||||
gdouble upper,
|
gdouble upper,
|
||||||
guint digits);
|
guint digits);
|
||||||
|
|
||||||
void gimp_scale_entry_set_value (GimpScaleEntry *entry,
|
|
||||||
gdouble value);
|
|
||||||
gdouble gimp_scale_entry_get_value (GimpScaleEntry *entry);
|
|
||||||
|
|
||||||
GtkWidget * gimp_scale_entry_get_label (GimpScaleEntry *entry);
|
|
||||||
GtkWidget * gimp_scale_entry_get_spin_button (GimpScaleEntry *entry);
|
|
||||||
GtkWidget * gimp_scale_entry_get_range (GimpScaleEntry *entry);
|
GtkWidget * gimp_scale_entry_get_range (GimpScaleEntry *entry);
|
||||||
|
|
||||||
void gimp_scale_entry_set_bounds (GimpScaleEntry *entry,
|
void gimp_scale_entry_set_bounds (GimpScaleEntry *entry,
|
||||||
|
@ -77,10 +73,6 @@ void gimp_scale_entry_set_logarithmic (GimpScaleEntry *entry,
|
||||||
gboolean logarithmic);
|
gboolean logarithmic);
|
||||||
gboolean gimp_scale_entry_get_logarithmic (GimpScaleEntry *entry);
|
gboolean gimp_scale_entry_get_logarithmic (GimpScaleEntry *entry);
|
||||||
|
|
||||||
void gimp_scale_entry_set_increments (GimpScaleEntry *entry,
|
|
||||||
gdouble step,
|
|
||||||
gdouble page);
|
|
||||||
|
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue