libgimpwidgets: fix percentage use in size-entry arithmetic when lower-bound != 0
In GimpSizeEntry, the value corresponding to 0%, as per gimp_size_entry_set_size(), may be non-zero. This works correctly when using the size entry in percentage mode, but not when using precentage as part of arithmetic. Fix this by adding an 'offset' parameter to eevl's unit-resolution callback, which can be specifies a constant value to add as part of unit conversion, after scaling the converted value by the conversion factor. In GimpSizeEntry, use this parameter to offset percentages by their lower bound.
This commit is contained in:
@ -237,6 +237,7 @@ gimp_eevl_complete (GimpEevl *eva)
|
|||||||
{
|
{
|
||||||
GimpEevlQuantity result = {0, 0};
|
GimpEevlQuantity result = {0, 0};
|
||||||
GimpEevlQuantity default_unit_factor;
|
GimpEevlQuantity default_unit_factor;
|
||||||
|
gdouble default_unit_offset;
|
||||||
|
|
||||||
/* Empty expression evaluates to 0 */
|
/* Empty expression evaluates to 0 */
|
||||||
if (gimp_eevl_accept (eva, GIMP_EEVL_TOKEN_END, NULL))
|
if (gimp_eevl_accept (eva, GIMP_EEVL_TOKEN_END, NULL))
|
||||||
@ -249,6 +250,7 @@ gimp_eevl_complete (GimpEevl *eva)
|
|||||||
|
|
||||||
eva->options.unit_resolver_proc (NULL,
|
eva->options.unit_resolver_proc (NULL,
|
||||||
&default_unit_factor,
|
&default_unit_factor,
|
||||||
|
&default_unit_offset,
|
||||||
eva->options.data);
|
eva->options.data);
|
||||||
|
|
||||||
/* Entire expression is dimensionless, apply default unit if
|
/* Entire expression is dimensionless, apply default unit if
|
||||||
@ -257,6 +259,7 @@ gimp_eevl_complete (GimpEevl *eva)
|
|||||||
if (result.dimension == 0 && default_unit_factor.dimension != 0)
|
if (result.dimension == 0 && default_unit_factor.dimension != 0)
|
||||||
{
|
{
|
||||||
result.value /= default_unit_factor.value;
|
result.value /= default_unit_factor.value;
|
||||||
|
result.value += default_unit_offset;
|
||||||
result.dimension = default_unit_factor.dimension;
|
result.dimension = default_unit_factor.dimension;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@ -282,21 +285,25 @@ gimp_eevl_expression (GimpEevl *eva)
|
|||||||
if (new_term.dimension != evaluated_terms.dimension)
|
if (new_term.dimension != evaluated_terms.dimension)
|
||||||
{
|
{
|
||||||
GimpEevlQuantity default_unit_factor;
|
GimpEevlQuantity default_unit_factor;
|
||||||
|
gdouble default_unit_offset;
|
||||||
|
|
||||||
eva->options.unit_resolver_proc (NULL,
|
eva->options.unit_resolver_proc (NULL,
|
||||||
&default_unit_factor,
|
&default_unit_factor,
|
||||||
|
&default_unit_offset,
|
||||||
eva->options.data);
|
eva->options.data);
|
||||||
|
|
||||||
if (new_term.dimension == 0 &&
|
if (new_term.dimension == 0 &&
|
||||||
evaluated_terms.dimension == default_unit_factor.dimension)
|
evaluated_terms.dimension == default_unit_factor.dimension)
|
||||||
{
|
{
|
||||||
new_term.value /= default_unit_factor.value;
|
new_term.value /= default_unit_factor.value;
|
||||||
|
new_term.value += default_unit_offset;
|
||||||
new_term.dimension = default_unit_factor.dimension;
|
new_term.dimension = default_unit_factor.dimension;
|
||||||
}
|
}
|
||||||
else if (evaluated_terms.dimension == 0 &&
|
else if (evaluated_terms.dimension == 0 &&
|
||||||
new_term.dimension == default_unit_factor.dimension)
|
new_term.dimension == default_unit_factor.dimension)
|
||||||
{
|
{
|
||||||
evaluated_terms.value /= default_unit_factor.value;
|
evaluated_terms.value /= default_unit_factor.value;
|
||||||
|
evaluated_terms.value += default_unit_offset;
|
||||||
evaluated_terms.dimension = default_unit_factor.dimension;
|
evaluated_terms.dimension = default_unit_factor.dimension;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -438,7 +445,8 @@ gimp_eevl_quantity (GimpEevl *eva)
|
|||||||
if (eva->current_token.type == GIMP_EEVL_TOKEN_IDENTIFIER)
|
if (eva->current_token.type == GIMP_EEVL_TOKEN_IDENTIFIER)
|
||||||
{
|
{
|
||||||
gchar *identifier;
|
gchar *identifier;
|
||||||
GimpEevlQuantity result;
|
GimpEevlQuantity factor;
|
||||||
|
gdouble offset;
|
||||||
|
|
||||||
gimp_eevl_accept (eva,
|
gimp_eevl_accept (eva,
|
||||||
GIMP_EEVL_TOKEN_ANY,
|
GIMP_EEVL_TOKEN_ANY,
|
||||||
@ -450,7 +458,8 @@ gimp_eevl_quantity (GimpEevl *eva)
|
|||||||
identifier[consumed_token.value.size] = '\0';
|
identifier[consumed_token.value.size] = '\0';
|
||||||
|
|
||||||
if (eva->options.unit_resolver_proc (identifier,
|
if (eva->options.unit_resolver_proc (identifier,
|
||||||
&result,
|
&factor,
|
||||||
|
&offset,
|
||||||
eva->options.data))
|
eva->options.data))
|
||||||
{
|
{
|
||||||
if (gimp_eevl_accept (eva, '^', NULL))
|
if (gimp_eevl_accept (eva, '^', NULL))
|
||||||
@ -465,12 +474,19 @@ gimp_eevl_quantity (GimpEevl *eva)
|
|||||||
"Exponent is not a dimensionless quantity");
|
"Exponent is not a dimensionless quantity");
|
||||||
}
|
}
|
||||||
|
|
||||||
result.value = pow (result.value, evaluated_exponent.value);
|
if (offset != 0.0)
|
||||||
result.dimension *= evaluated_exponent.value;
|
{
|
||||||
|
gimp_eevl_error (eva,
|
||||||
|
"Invalid unit exponent");
|
||||||
|
}
|
||||||
|
|
||||||
|
factor.value = pow (factor.value, evaluated_exponent.value);
|
||||||
|
factor.dimension *= evaluated_exponent.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
evaluated_quantity.value /= result.value;
|
evaluated_quantity.value /= factor.value;
|
||||||
evaluated_quantity.dimension += result.dimension;
|
evaluated_quantity.value += offset;
|
||||||
|
evaluated_quantity.dimension += factor.dimension;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -42,16 +42,18 @@ typedef struct
|
|||||||
* GimpEevlUnitResolverProc:
|
* GimpEevlUnitResolverProc:
|
||||||
* @identifier: Identifier of unit to resolve or %NULL if default unit
|
* @identifier: Identifier of unit to resolve or %NULL if default unit
|
||||||
* should be resolved.
|
* should be resolved.
|
||||||
* @result: Units per reference unit. For example, in GIMP the
|
* @factor: Units per reference unit. For example, in GIMP the
|
||||||
* reference unit is inches so resolving "mm" should
|
* reference unit is inches so resolving "mm" should
|
||||||
* return 25.4 since there are 25.4 millimeters per inch.
|
* return 25.4 since there are 25.4 millimeters per inch.
|
||||||
|
* @offset: Offset to apply after scaling the value according to @factor.
|
||||||
* @data: Data given to gimp_eevl_evaluate().
|
* @data: Data given to gimp_eevl_evaluate().
|
||||||
*
|
*
|
||||||
* Returns: If the unit was successfully resolved or not.
|
* Returns: If the unit was successfully resolved or not.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
typedef gboolean (* GimpEevlUnitResolverProc) (const gchar *identifier,
|
typedef gboolean (* GimpEevlUnitResolverProc) (const gchar *identifier,
|
||||||
GimpEevlQuantity *result,
|
GimpEevlQuantity *factor,
|
||||||
|
gdouble *offset,
|
||||||
gpointer data);
|
gpointer data);
|
||||||
|
|
||||||
|
|
||||||
|
@ -122,7 +122,8 @@ static gint gimp_size_entry_eevl_input_callback (GtkSpinButton *spinne
|
|||||||
gdouble *return_val,
|
gdouble *return_val,
|
||||||
gpointer *data);
|
gpointer *data);
|
||||||
static gboolean gimp_size_entry_eevl_unit_resolver (const gchar *ident,
|
static gboolean gimp_size_entry_eevl_unit_resolver (const gchar *ident,
|
||||||
GimpEevlQuantity *result,
|
GimpEevlQuantity *factor,
|
||||||
|
gdouble *offset,
|
||||||
gpointer data);
|
gpointer data);
|
||||||
|
|
||||||
|
|
||||||
@ -1287,6 +1288,7 @@ gimp_size_entry_eevl_input_callback (GtkSpinButton *spinner,
|
|||||||
{
|
{
|
||||||
GimpSizeEntryField *other_gsef;
|
GimpSizeEntryField *other_gsef;
|
||||||
GimpEevlQuantity default_unit_factor;
|
GimpEevlQuantity default_unit_factor;
|
||||||
|
gdouble default_unit_offset;
|
||||||
|
|
||||||
options.ratio_expressions = TRUE;
|
options.ratio_expressions = TRUE;
|
||||||
|
|
||||||
@ -1303,7 +1305,9 @@ gimp_size_entry_eevl_input_callback (GtkSpinButton *spinner,
|
|||||||
options.ratio_invert = TRUE;
|
options.ratio_invert = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
options.unit_resolver_proc (NULL, &default_unit_factor, options.data);
|
options.unit_resolver_proc (NULL,
|
||||||
|
&default_unit_factor, &default_unit_offset,
|
||||||
|
options.data);
|
||||||
|
|
||||||
options.ratio_quantity.value = other_gsef->value /
|
options.ratio_quantity.value = other_gsef->value /
|
||||||
default_unit_factor.value;
|
default_unit_factor.value;
|
||||||
@ -1392,7 +1396,8 @@ gimp_size_entry_eevl_input_callback (GtkSpinButton *spinner,
|
|||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gimp_size_entry_eevl_unit_resolver (const gchar *identifier,
|
gimp_size_entry_eevl_unit_resolver (const gchar *identifier,
|
||||||
GimpEevlQuantity *result,
|
GimpEevlQuantity *factor,
|
||||||
|
gdouble *offset,
|
||||||
gpointer data)
|
gpointer data)
|
||||||
{
|
{
|
||||||
GimpSizeEntryField *gsef = (GimpSizeEntryField *) data;
|
GimpSizeEntryField *gsef = (GimpSizeEntryField *) data;
|
||||||
@ -1400,9 +1405,11 @@ gimp_size_entry_eevl_unit_resolver (const gchar *identifier,
|
|||||||
GimpUnit unit;
|
GimpUnit unit;
|
||||||
|
|
||||||
g_return_val_if_fail (gsef, FALSE);
|
g_return_val_if_fail (gsef, FALSE);
|
||||||
g_return_val_if_fail (result != NULL, FALSE);
|
g_return_val_if_fail (factor != NULL, FALSE);
|
||||||
|
g_return_val_if_fail (offset != NULL, FALSE);
|
||||||
g_return_val_if_fail (GIMP_IS_SIZE_ENTRY (gsef->gse), FALSE);
|
g_return_val_if_fail (GIMP_IS_SIZE_ENTRY (gsef->gse), FALSE);
|
||||||
|
|
||||||
|
*offset = 0.0;
|
||||||
|
|
||||||
for (unit = 0;
|
for (unit = 0;
|
||||||
unit <= gimp_unit_get_number_of_units ();
|
unit <= gimp_unit_get_number_of_units ();
|
||||||
@ -1422,34 +1429,36 @@ gimp_size_entry_eevl_unit_resolver (const gchar *identifier,
|
|||||||
case GIMP_UNIT_PERCENT:
|
case GIMP_UNIT_PERCENT:
|
||||||
if (gsef->gse->unit == GIMP_UNIT_PERCENT)
|
if (gsef->gse->unit == GIMP_UNIT_PERCENT)
|
||||||
{
|
{
|
||||||
result->value = 1;
|
factor->value = 1;
|
||||||
result->dimension = 0;
|
factor->dimension = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* gsef->upper contains the '100%'-value */
|
/* gsef->upper contains the '100%'-value */
|
||||||
result->value = 100*gsef->resolution/gsef->upper;
|
factor->value = 100*gsef->resolution/(gsef->upper - gsef->lower);
|
||||||
result->dimension = 1;
|
/* gsef->lower contains the '0%'-value */
|
||||||
|
*offset = gsef->lower/gsef->resolution;
|
||||||
|
factor->dimension = 1;
|
||||||
}
|
}
|
||||||
/* return here, don't perform percentage conversion */
|
/* return here, don't perform percentage conversion */
|
||||||
return TRUE;
|
return TRUE;
|
||||||
case GIMP_UNIT_PIXEL:
|
case GIMP_UNIT_PIXEL:
|
||||||
result->value = gsef->resolution;
|
factor->value = gsef->resolution;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
result->value = gimp_unit_get_factor (unit);
|
factor->value = gimp_unit_get_factor (unit);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gsef->gse->unit == GIMP_UNIT_PERCENT)
|
if (gsef->gse->unit == GIMP_UNIT_PERCENT)
|
||||||
{
|
{
|
||||||
/* map non-percentages onto percent */
|
/* map non-percentages onto percent */
|
||||||
result->value = gsef->upper/(100*gsef->resolution);
|
factor->value = gsef->upper/(100*gsef->resolution);
|
||||||
result->dimension = 0;
|
factor->dimension = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
result->dimension = 1;
|
factor->dimension = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We are done */
|
/* We are done */
|
||||||
|
@ -42,24 +42,27 @@ typedef struct
|
|||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
test_units (const gchar *ident,
|
test_units (const gchar *ident,
|
||||||
GimpEevlQuantity *result,
|
GimpEevlQuantity *factor,
|
||||||
|
gdouble *offset,
|
||||||
gpointer data)
|
gpointer data)
|
||||||
{
|
{
|
||||||
gboolean resolved = FALSE;
|
gboolean resolved = FALSE;
|
||||||
gboolean default_unit = (ident == NULL);
|
gboolean default_unit = (ident == NULL);
|
||||||
|
|
||||||
|
*offset = 0.0;
|
||||||
|
|
||||||
if (default_unit ||
|
if (default_unit ||
|
||||||
(ident && strcmp ("in", ident) == 0))
|
(ident && strcmp ("in", ident) == 0))
|
||||||
{
|
{
|
||||||
result->dimension = 1;
|
factor->dimension = 1;
|
||||||
result->value = 1.;
|
factor->value = 1.;
|
||||||
|
|
||||||
resolved = TRUE;
|
resolved = TRUE;
|
||||||
}
|
}
|
||||||
else if (ident && strcmp ("mm", ident) == 0)
|
else if (ident && strcmp ("mm", ident) == 0)
|
||||||
{
|
{
|
||||||
result->dimension = 1;
|
factor->dimension = 1;
|
||||||
result->value = 25.4;
|
factor->value = 25.4;
|
||||||
|
|
||||||
resolved = TRUE;
|
resolved = TRUE;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user