libgimp, libgimpbase, libgimpwidgets: new gimp_range_estimate_settings()

Similar code was used in 2 places basically (GimpLabelSpin and
GimpProcedureDialog) so just make it an utils function. It's good anyway
to have a generic function to estimate suitable increments and decimal
places depending on a range.

As a consequence also gimp_label_spin_new() now takes a gint digits
(instead of guint), with -1 meaning we want digits computed from the
range.
Similarly gimp_prop_scale_entry_new() docs adds the -1 meaning too.
This commit is contained in:
Jehan 2020-11-25 01:16:34 +01:00
parent 9ca18c37cd
commit 8d5008d76f
7 changed files with 158 additions and 173 deletions

View File

@ -85,12 +85,6 @@ static void gimp_procedure_dialog_load_defaults (GtkWidget *button,
static void gimp_procedure_dialog_save_defaults (GtkWidget *button,
GimpProcedureDialog *dialog);
static void gimp_procedure_dialog_estimate_increments (gdouble lower,
gdouble upper,
gdouble *step,
gdouble *page,
gint *digits);
static gboolean gimp_procedure_dialog_check_mnemonic (GimpProcedureDialog *dialog,
GtkWidget *widget,
const gchar *id,
@ -456,7 +450,7 @@ gimp_procedure_dialog_get_widget (GimpProcedureDialog *dialog,
minimum = pspecdouble->minimum;
maximum = pspecdouble->maximum;
}
gimp_procedure_dialog_estimate_increments (minimum, maximum, &step, &page, &digits);
gimp_range_estimate_settings (minimum, maximum, &step, &page, &digits);
if (widget_type == G_TYPE_NONE || widget_type == GIMP_TYPE_LABEL_SPIN)
{
@ -1186,98 +1180,6 @@ gimp_procedure_dialog_save_defaults (GtkWidget *button,
}
}
/**
* gimp_procedure_dialog_estimate_increments:
* @lower:
* @upper:
* @step:
* @page:
*
* Though sometimes you might want to specify step and page increments
* on widgets explicitly, sometimes you are fine with just anything
* which doesn't give you absurd values. This procedure just tries to
* return such sensible increment values.
*/
static void
gimp_procedure_dialog_estimate_increments (gdouble lower,
gdouble upper,
gdouble *step,
gdouble *page,
gint *digits)
{
gdouble range;
g_return_if_fail (upper >= lower);
g_return_if_fail (step || page || digits);
range = upper - lower;
if (range > 0 && range <= 1.0)
{
gdouble places = 10.0;
if (digits)
*digits = 3;
/* 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;
if (digits)
(*digits)++;
}
if (step)
*step = 0.1 / places;
if (page)
*page = 1.0 / places;
}
else if (range <= 2.0)
{
if (step)
*step = 0.01;
if (page)
*page = 0.1;
if (digits)
*digits = 3;
}
else if (range <= 5.0)
{
if (step)
*step = 0.1;
if (page)
*page = 1.0;
if (digits)
*digits = 2;
}
else if (range <= 40.0)
{
if (step)
*step = 1.0;
if (page)
*page = 2.0;
if (digits)
*digits = 2;
}
else
{
if (step)
*step = 1.0;
if (page)
*page = 10.0;
if (digits)
*digits = 1;
}
}
static gboolean
gimp_procedure_dialog_check_mnemonic (GimpProcedureDialog *dialog,
GtkWidget *widget,

View File

@ -159,6 +159,7 @@ EXPORTS
gimp_plug_in_directory_file
gimp_precision_get_type
gimp_progress_command_get_type
gimp_range_estimate_settings
gimp_rectangle_intersect
gimp_rectangle_union
gimp_repeat_mode_get_type

View File

@ -1521,6 +1521,109 @@ gimp_stack_trace_query (const gchar *prog_name)
#endif
}
/**
* gimp_range_estimate_settings:
* @lower: the lower value.
* @upper: the higher value.
* @step: (out) (optional): the proposed step increment.
* @page: (out) (optional): the proposed page increment.
* @digits: (out) (optional): the proposed decimal places precision.
*
* This function proposes reasonable settings for increments and display
* digits. These can be used for instance on #GtkRange or other widgets
* using a #GtkAdjustment typically.
* Note that it will never return @digits with value 0. If you know that
* your input needs to display integer values, there is no need to set
* @digits.
*
* There is no universal answer to the best increments and number of
* decimal places. It often depends on context of what the value is
* meant to represent. This function only tries to provide sensible
* generic values which can be used when it doesn't matter too much or
* for generated GUI for instance. If you know exactly how you want to
* show and interact with a given range, you don't have to use this
* function.
*/
void
gimp_range_estimate_settings (gdouble lower,
gdouble upper,
gdouble *step,
gdouble *page,
gint *digits)
{
gdouble range;
g_return_if_fail (upper >= lower);
g_return_if_fail (step || page || digits);
range = upper - lower;
if (range > 0 && range <= 1.0)
{
gdouble places = 10.0;
if (digits)
*digits = 3;
/* 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;
if (digits)
(*digits)++;
}
if (step)
*step = 0.1 / places;
if (page)
*page = 1.0 / places;
}
else if (range <= 2.0)
{
if (step)
*step = 0.01;
if (page)
*page = 0.1;
if (digits)
*digits = 3;
}
else if (range <= 5.0)
{
if (step)
*step = 0.1;
if (page)
*page = 1.0;
if (digits)
*digits = 2;
}
else if (range <= 40.0)
{
if (step)
*step = 1.0;
if (page)
*page = 2.0;
if (digits)
*digits = 2;
}
else
{
if (step)
*step = 1.0;
if (page)
*page = 10.0;
if (digits)
*digits = 1;
}
}
/* Private functions. */

View File

@ -82,6 +82,12 @@ gboolean gimp_stack_trace_print (const gchar *prog_na
gchar **trace);
void gimp_stack_trace_query (const gchar *prog_name);
void gimp_range_estimate_settings (gdouble lower,
gdouble upper,
gdouble *step,
gdouble *page,
gint *digits);
G_END_DECLS

View File

@ -60,6 +60,8 @@ typedef struct _GimpLabelSpinPrivate
GtkWidget *spinbutton;
GtkAdjustment *spin_adjustment;
gint digits;
} GimpLabelSpinPrivate;
static void gimp_label_spin_constructed (GObject *object);
@ -78,8 +80,11 @@ static GtkWidget * gimp_label_spin_populate (GimpLabeled *spin,
gint *width,
gint *height);
static void gimp_label_spin_update_spin_width (GimpLabelSpin *spin);
static void gimp_label_spin_update_increments (GimpLabelSpin *spin);
static void gimp_label_spin_update_spin_width (GimpLabelSpin *spin,
gdouble lower,
gdouble upper,
guint digits);
static void gimp_label_spin_update_settings (GimpLabelSpin *spin);
G_DEFINE_TYPE_WITH_PRIVATE (GimpLabelSpin, gimp_label_spin, GIMP_TYPE_LABELED)
@ -151,15 +156,16 @@ gimp_label_spin_class_init (GimpLabelSpinClass *klass)
/**
* GimpLabelSpin:digits:
*
* The number of decimal places to display.
* The number of decimal places to display. If -1, then the number is
* estimated.
*
* 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));
g_param_spec_int ("digits", NULL,
"The number of decimal places to display",
-1, G_MAXINT, -1,
GIMP_PARAM_READWRITE));
}
static void
@ -195,8 +201,7 @@ gimp_label_spin_constructed (GObject *object)
G_BINDING_BIDIRECTIONAL |
G_BINDING_SYNC_CREATE);
gimp_label_spin_update_spin_width (spin);
gimp_label_spin_update_increments (spin);
gimp_label_spin_update_settings (spin);
}
static void
@ -224,8 +229,7 @@ gimp_label_spin_set_property (GObject *object,
g_value_get_double (value));
if (priv->spinbutton)
{
gimp_label_spin_update_spin_width (spin);
gimp_label_spin_update_increments (spin);
gimp_label_spin_update_settings (spin);
}
break;
case PROP_UPPER:
@ -233,18 +237,14 @@ gimp_label_spin_set_property (GObject *object,
g_value_get_double (value));
if (priv->spinbutton)
{
gimp_label_spin_update_spin_width (spin);
gimp_label_spin_update_increments (spin);
gimp_label_spin_update_settings (spin);
}
break;
case PROP_DIGITS:
if (priv->spinbutton)
{
gtk_spin_button_set_digits (GTK_SPIN_BUTTON (priv->spinbutton),
g_value_get_uint (value));
gimp_label_spin_update_spin_width (spin);
gimp_label_spin_update_increments (spin);
priv->digits = g_value_get_int (value);
gimp_label_spin_update_settings (spin);
}
break;
@ -305,22 +305,16 @@ gimp_label_spin_populate (GimpLabeled *labeled,
}
static void
gimp_label_spin_update_spin_width (GimpLabelSpin *spin)
gimp_label_spin_update_spin_width (GimpLabelSpin *spin,
gdouble lower,
gdouble upper,
guint digits)
{
GimpLabelSpinPrivate *priv = gimp_label_spin_get_instance_private (spin);
gint width = 0;
gdouble lower;
gdouble upper;
gint digits;
g_return_if_fail (GIMP_IS_LABEL_SPIN (spin));
g_object_get (spin,
"lower", &lower,
"upper", &upper,
"digits", &digits,
NULL);
/* Necessary size to display the max/min integer values, with optional
* negative sign.
*/
@ -337,11 +331,14 @@ gimp_label_spin_update_spin_width (GimpLabelSpin *spin)
}
static void
gimp_label_spin_update_increments (GimpLabelSpin *spin)
gimp_label_spin_update_settings (GimpLabelSpin *spin)
{
gdouble lower;
gdouble upper;
gdouble range;
GimpLabelSpinPrivate *priv = gimp_label_spin_get_instance_private (spin);
gdouble lower;
gdouble upper;
gdouble step;
gdouble page;
gint digits = priv->digits;
g_return_if_fail (GIMP_IS_LABEL_SPIN (spin));
@ -352,46 +349,11 @@ gimp_label_spin_update_increments (GimpLabelSpin *spin)
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_label_spin_set_increments (spin, step, page);
}
else if (range <= 2.0)
{
gimp_label_spin_set_increments (spin, 0.01, 0.1);
}
else if (range <= 5.0)
{
gimp_label_spin_set_increments (spin, 0.1, 1.0);
}
else if (range <= 40.0)
{
gimp_label_spin_set_increments (spin, 1.0, 2.0);
}
else
{
gimp_label_spin_set_increments (spin, 1.0, 10.0);
}
gimp_range_estimate_settings (lower, upper, &step, &page,
digits < 0 ? &digits: NULL);
gimp_label_spin_set_increments (spin, step, page);
gtk_spin_button_set_digits (GTK_SPIN_BUTTON (priv->spinbutton), (guint) digits);
gimp_label_spin_update_spin_width (spin, lower, upper, (guint) digits);
}
@ -406,6 +368,12 @@ gimp_label_spin_update_increments (GimpLabelSpin *spin)
* @upper: The upper boundary.
* @digits: The number of decimal digits.
*
* Suitable increment values are estimated based on the [@lower, @upper]
* range.
* If @digits is -1, then it will also be estimated based on the same
* range. Digits estimation will always be at least 1, so if you want to
* show integer values only, set 0 explicitly.
*
* Returns: (transfer full): The new #GimpLabelSpin widget.
**/
GtkWidget *
@ -413,10 +381,13 @@ gimp_label_spin_new (const gchar *text,
gdouble value,
gdouble lower,
gdouble upper,
guint digits)
gint digits)
{
GtkWidget *labeled;
g_return_val_if_fail (upper >= lower, NULL);
g_return_val_if_fail (digits >= -1, NULL);
labeled = g_object_new (GIMP_TYPE_LABEL_SPIN,
"label", text,
"value", value,

View File

@ -55,7 +55,7 @@ GtkWidget * gimp_label_spin_new (const gchar *text,
gdouble value,
gdouble lower,
gdouble upper,
guint digits);
gint digits);
void gimp_label_spin_set_value (GimpLabelSpin *spin,
gdouble value);

View File

@ -1513,6 +1513,8 @@ gimp_prop_hscale_new (GObject *config,
* @property_name: Name of integer or double property controlled by the scale.
* @digits: Number of digits after decimal point to display. For
* integer properties, this will be ignored (always 0).
* If set to -1, a reasonable value will be
* approximated depending on @property_name's range.
* @limit_scale: %FALSE if the range of possible values of the
* GtkHScale should be the same as of the GtkSpinButton.
* @lower_limit: The scale's lower boundary if @scale_limits is %TRUE.