mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-11-16 13:40:31 +00:00
cssvalue: Add GtkCssEaseValue
This is supposed to hold the transition-easing-function and animation-easing-function values.
This commit is contained in:
parent
2ff47ed26d
commit
7511109103
@ -426,6 +426,7 @@ gtk_private_h_sources = \
|
||||
gtkcssarrayvalueprivate.h \
|
||||
gtkcsscomputedvaluesprivate.h \
|
||||
gtkcsscustompropertyprivate.h \
|
||||
gtkcsseasevalueprivate.h \
|
||||
gtkcssenumvalueprivate.h \
|
||||
gtkcssimagegradientprivate.h \
|
||||
gtkcssimagelinearprivate.h \
|
||||
@ -631,6 +632,7 @@ gtk_base_c_sources = \
|
||||
gtkcssarrayvalue.c \
|
||||
gtkcsscomputedvalues.c \
|
||||
gtkcsscustomproperty.c \
|
||||
gtkcsseasevalue.c \
|
||||
gtkcssenumvalue.c \
|
||||
gtkcssimage.c \
|
||||
gtkcssimagegradient.c \
|
||||
|
370
gtk/gtkcsseasevalue.c
Normal file
370
gtk/gtkcsseasevalue.c
Normal file
@ -0,0 +1,370 @@
|
||||
/* GTK - The GIMP Toolkit
|
||||
* Copyright (C) 2011 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gtkcsseasevalueprivate.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
typedef enum {
|
||||
GTK_CSS_EASE_CUBIC_BEZIER,
|
||||
GTK_CSS_EASE_STEPS
|
||||
} GtkCssEaseType;
|
||||
|
||||
struct _GtkCssValue {
|
||||
GTK_CSS_VALUE_BASE
|
||||
GtkCssEaseType type;
|
||||
union {
|
||||
struct {
|
||||
double x1;
|
||||
double y1;
|
||||
double x2;
|
||||
double y2;
|
||||
} cubic;
|
||||
struct {
|
||||
guint steps;
|
||||
gboolean start;
|
||||
} steps;
|
||||
} u;
|
||||
};
|
||||
|
||||
static void
|
||||
gtk_css_value_ease_free (GtkCssValue *value)
|
||||
{
|
||||
g_slice_free (GtkCssValue, value);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_css_value_ease_equal (const GtkCssValue *ease1,
|
||||
const GtkCssValue *ease2)
|
||||
{
|
||||
if (ease1->type != ease2->type)
|
||||
return FALSE;
|
||||
|
||||
switch (ease1->type)
|
||||
{
|
||||
case GTK_CSS_EASE_CUBIC_BEZIER:
|
||||
return ease1->u.cubic.x1 == ease2->u.cubic.x1 &&
|
||||
ease1->u.cubic.y1 == ease2->u.cubic.y1 &&
|
||||
ease1->u.cubic.x2 == ease2->u.cubic.x2 &&
|
||||
ease1->u.cubic.y2 == ease2->u.cubic.y2;
|
||||
case GTK_CSS_EASE_STEPS:
|
||||
return ease1->u.steps.steps == ease2->u.steps.steps &&
|
||||
ease1->u.steps.start == ease2->u.steps.start;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static GtkCssValue *
|
||||
gtk_css_value_ease_transition (GtkCssValue *start,
|
||||
GtkCssValue *end,
|
||||
double progress)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_css_value_ease_print (const GtkCssValue *ease,
|
||||
GString *string)
|
||||
{
|
||||
switch (ease->type)
|
||||
{
|
||||
case GTK_CSS_EASE_CUBIC_BEZIER:
|
||||
if (ease->u.cubic.x1 == 0.25 && ease->u.cubic.y1 == 0.1 &&
|
||||
ease->u.cubic.x2 == 0.25 && ease->u.cubic.y2 == 1.0)
|
||||
g_string_append (string, "ease");
|
||||
else if (ease->u.cubic.x1 == 0.0 && ease->u.cubic.y1 == 0.0 &&
|
||||
ease->u.cubic.x2 == 1.0 && ease->u.cubic.y2 == 1.0)
|
||||
g_string_append (string, "linear");
|
||||
else if (ease->u.cubic.x1 == 0.42 && ease->u.cubic.y1 == 0.0 &&
|
||||
ease->u.cubic.x2 == 1.0 && ease->u.cubic.y2 == 1.0)
|
||||
g_string_append (string, "ease-in");
|
||||
else if (ease->u.cubic.x1 == 0.0 && ease->u.cubic.y1 == 0.0 &&
|
||||
ease->u.cubic.x2 == 0.58 && ease->u.cubic.y2 == 1.0)
|
||||
g_string_append (string, "ease-out");
|
||||
else if (ease->u.cubic.x1 == 0.42 && ease->u.cubic.y1 == 0.0 &&
|
||||
ease->u.cubic.x2 == 0.58 && ease->u.cubic.y2 == 1.0)
|
||||
g_string_append (string, "ease-in-out");
|
||||
else
|
||||
g_string_append_printf (string, "cubic-bezier(%g,%g,%g,%g)",
|
||||
ease->u.cubic.x1, ease->u.cubic.y1,
|
||||
ease->u.cubic.x2, ease->u.cubic.y2);
|
||||
break;
|
||||
case GTK_CSS_EASE_STEPS:
|
||||
if (ease->u.steps.steps == 1)
|
||||
{
|
||||
g_string_append (string, ease->u.steps.start ? "step-start" : "step-end");
|
||||
}
|
||||
else
|
||||
{
|
||||
g_string_append_printf (string, "steps(%u%s)", ease->u.steps.steps, ease->u.steps.start ? ",start" : "");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const GtkCssValueClass GTK_CSS_VALUE_EASE = {
|
||||
gtk_css_value_ease_free,
|
||||
gtk_css_value_ease_equal,
|
||||
gtk_css_value_ease_transition,
|
||||
gtk_css_value_ease_print
|
||||
};
|
||||
|
||||
GtkCssValue *
|
||||
_gtk_css_ease_value_new_cubic_bezier (double x1,
|
||||
double y1,
|
||||
double x2,
|
||||
double y2)
|
||||
{
|
||||
GtkCssValue *value;
|
||||
|
||||
g_return_val_if_fail (x1 >= 0.0, NULL);
|
||||
g_return_val_if_fail (x1 <= 1.0, NULL);
|
||||
g_return_val_if_fail (x2 >= 0.0, NULL);
|
||||
g_return_val_if_fail (x2 <= 1.0, NULL);
|
||||
|
||||
value = _gtk_css_value_new (GtkCssValue, >K_CSS_VALUE_EASE);
|
||||
|
||||
value->type = GTK_CSS_EASE_CUBIC_BEZIER;
|
||||
value->u.cubic.x1 = x1;
|
||||
value->u.cubic.y1 = y1;
|
||||
value->u.cubic.x2 = x2;
|
||||
value->u.cubic.y2 = y2;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static GtkCssValue *
|
||||
_gtk_css_ease_value_new_steps (guint n_steps,
|
||||
gboolean start)
|
||||
{
|
||||
GtkCssValue *value;
|
||||
|
||||
g_return_val_if_fail (n_steps > 0, NULL);
|
||||
|
||||
value = _gtk_css_value_new (GtkCssValue, >K_CSS_VALUE_EASE);
|
||||
|
||||
value->type = GTK_CSS_EASE_STEPS;
|
||||
value->u.steps.steps = n_steps;
|
||||
value->u.steps.start = start;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static const struct {
|
||||
const char *name;
|
||||
guint is_bezier :1;
|
||||
guint needs_custom :1;
|
||||
double values[4];
|
||||
} parser_values[] = {
|
||||
{ "linear", TRUE, FALSE, { 0.0, 0.0, 1.0, 1.0 } },
|
||||
{ "ease-in-out", TRUE, FALSE, { 0.42, 0.0, 0.58, 1.0 } },
|
||||
{ "ease-in", TRUE, FALSE, { 0.42, 0.0, 1.0, 1.0 } },
|
||||
{ "ease-out", TRUE, FALSE, { 0.0, 0.0, 0.58, 1.0 } },
|
||||
{ "ease", TRUE, FALSE, { 0.25, 0.1, 0.25, 1.0 } },
|
||||
{ "step-start", FALSE, FALSE, { 1.0, 1.0, 0.0, 0.0 } },
|
||||
{ "step-end", FALSE, FALSE, { 1.0, 0.0, 0.0, 0.0 } },
|
||||
{ "steps", FALSE, TRUE, { 0.0, 0.0, 0.0, 0.0 } },
|
||||
{ "cubic-bezier", TRUE, TRUE, { 0.0, 0.0, 0.0, 0.0 } }
|
||||
};
|
||||
|
||||
gboolean
|
||||
_gtk_css_ease_value_can_parse (GtkCssParser *parser)
|
||||
{
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (parser_values); i++)
|
||||
{
|
||||
if (_gtk_css_parser_has_prefix (parser, parser_values[i].name))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static GtkCssValue *
|
||||
gtk_css_ease_value_parse_cubic_bezier (GtkCssParser *parser)
|
||||
{
|
||||
double values[4];
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
if (!_gtk_css_parser_try (parser, i ? "," : "(", TRUE))
|
||||
{
|
||||
_gtk_css_parser_error (parser, "Expected '%s'", i ? "," : "(");
|
||||
return NULL;
|
||||
}
|
||||
if (!_gtk_css_parser_try_double (parser, &values[i]))
|
||||
{
|
||||
_gtk_css_parser_error (parser, "Expected a number");
|
||||
return NULL;
|
||||
}
|
||||
if ((i == 0 || i == 2) &&
|
||||
(values[i] < 0 || values[i] > 1.0))
|
||||
{
|
||||
_gtk_css_parser_error (parser, "value %g out of range. Must be from 0.0 to 1.0", values[i]);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_gtk_css_parser_try (parser, ")", TRUE))
|
||||
{
|
||||
_gtk_css_parser_error (parser, "Missing closing ')' for cubic-bezier");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return _gtk_css_ease_value_new_cubic_bezier (values[0], values[1], values[2], values[3]);
|
||||
}
|
||||
|
||||
static GtkCssValue *
|
||||
gtk_css_ease_value_parse_steps (GtkCssParser *parser)
|
||||
{
|
||||
guint n_steps;
|
||||
gboolean start;
|
||||
|
||||
if (!_gtk_css_parser_try (parser, "(", TRUE))
|
||||
{
|
||||
_gtk_css_parser_error (parser, "Expected '('");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!_gtk_css_parser_try_uint (parser, &n_steps))
|
||||
{
|
||||
_gtk_css_parser_error (parser, "Expected number of steps");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (_gtk_css_parser_try (parser, ",", TRUE))
|
||||
{
|
||||
if (_gtk_css_parser_try (parser, "start", TRUE))
|
||||
start = TRUE;
|
||||
else if (_gtk_css_parser_try (parser, "end", TRUE))
|
||||
start = FALSE;
|
||||
else
|
||||
{
|
||||
_gtk_css_parser_error (parser, "Only allowed values are 'start' and 'end'");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
start = FALSE;
|
||||
|
||||
if (!_gtk_css_parser_try (parser, ")", TRUE))
|
||||
{
|
||||
_gtk_css_parser_error (parser, "Missing closing ')' for steps");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return _gtk_css_ease_value_new_steps (n_steps, start);
|
||||
}
|
||||
|
||||
GtkCssValue *
|
||||
_gtk_css_ease_value_parse (GtkCssParser *parser)
|
||||
{
|
||||
g_return_val_if_fail (parser != NULL, NULL);
|
||||
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (parser_values); i++)
|
||||
{
|
||||
if (_gtk_css_parser_try (parser, parser_values[i].name, FALSE))
|
||||
{
|
||||
if (parser_values[i].needs_custom)
|
||||
{
|
||||
if (parser_values[i].is_bezier)
|
||||
return gtk_css_ease_value_parse_cubic_bezier (parser);
|
||||
else
|
||||
return gtk_css_ease_value_parse_steps (parser);
|
||||
}
|
||||
|
||||
_gtk_css_parser_skip_whitespace (parser);
|
||||
|
||||
if (parser_values[i].is_bezier)
|
||||
return _gtk_css_ease_value_new_cubic_bezier (parser_values[i].values[0],
|
||||
parser_values[i].values[1],
|
||||
parser_values[i].values[2],
|
||||
parser_values[i].values[3]);
|
||||
else
|
||||
return _gtk_css_ease_value_new_steps (parser_values[i].values[0],
|
||||
parser_values[i].values[1] != 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
_gtk_css_parser_error (parser, "Unknown value");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
double
|
||||
_gtk_css_ease_value_transform (const GtkCssValue *ease,
|
||||
double progress)
|
||||
{
|
||||
g_return_val_if_fail (ease->class == >K_CSS_VALUE_EASE, 1.0);
|
||||
|
||||
if (progress <= 0)
|
||||
return 0;
|
||||
if (progress >= 1)
|
||||
return 1;
|
||||
|
||||
switch (ease->type)
|
||||
{
|
||||
case GTK_CSS_EASE_CUBIC_BEZIER:
|
||||
{
|
||||
static const double epsilon = 0.00001;
|
||||
double tmin, t, tmax;
|
||||
|
||||
tmin = 0.0;
|
||||
tmax = 1.0;
|
||||
t = progress;
|
||||
|
||||
while (tmin < tmax)
|
||||
{
|
||||
double sample;
|
||||
sample = (((1.0 + 3 * ease->u.cubic.x1 - 3 * ease->u.cubic.x2) * t
|
||||
+ -6 * ease->u.cubic.x1 + 3 * ease->u.cubic.x2) * t
|
||||
+ 3 * ease->u.cubic.x1 ) * t;
|
||||
if (fabs(sample - progress) < epsilon)
|
||||
break;
|
||||
|
||||
if (progress > sample)
|
||||
tmin = t;
|
||||
else
|
||||
tmax = t;
|
||||
t = (tmax + tmin) * .5;
|
||||
}
|
||||
|
||||
return (((1.0 + 3 * ease->u.cubic.y1 - 3 * ease->u.cubic.y2) * t
|
||||
+ -6 * ease->u.cubic.y1 + 3 * ease->u.cubic.y2) * t
|
||||
+ 3 * ease->u.cubic.y1 ) * t;
|
||||
}
|
||||
case GTK_CSS_EASE_STEPS:
|
||||
progress *= ease->u.steps.steps;
|
||||
progress = floor (progress) + ease->u.steps.start ? 0 : 1;
|
||||
return progress / ease->u.steps.steps;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
return 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
|
41
gtk/gtkcsseasevalueprivate.h
Normal file
41
gtk/gtkcsseasevalueprivate.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright © 2012 Red Hat Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Alexander Larsson <alexl@gnome.org>
|
||||
*/
|
||||
|
||||
#ifndef __GTK_CSS_EASE_VALUE_PRIVATE_H__
|
||||
#define __GTK_CSS_EASE_VALUE_PRIVATE_H__
|
||||
|
||||
#include "gtkcssparserprivate.h"
|
||||
#include "gtkcssvalueprivate.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
GtkCssValue * _gtk_css_ease_value_new_cubic_bezier (double x1,
|
||||
double y1,
|
||||
double x2,
|
||||
double y2);
|
||||
gboolean _gtk_css_ease_value_can_parse (GtkCssParser *parser);
|
||||
GtkCssValue * _gtk_css_ease_value_parse (GtkCssParser *parser);
|
||||
|
||||
double _gtk_css_ease_value_transform (const GtkCssValue *ease,
|
||||
double progress);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_CSS_EASE_VALUE_PRIVATE_H__ */
|
Loading…
Reference in New Issue
Block a user