Gimp/app/propgui/gimppropgui-spiral.c
Ell dad521e334 app: add misc. parameters to GimpControllerSlider
Add parameters, controlling the behavior and appearance of sliders,
to GimpControllerSlider.  The macro GIMP_CONTROLLER_SLIDER_DEFAULT
expands to a nonmodifiable lvalue of type GimpControllerSlider,
whose members are initialized with the most common default values.

Handle the new parameters in GimpToolLine.  A slider using the new
"autohide" mode is only visible when selected, or when the cursor
is close enough to the line, between the slider's min and max
values, and no other handle is grabbed or hovered-over.
2017-10-09 12:48:50 -04:00

239 lines
7.2 KiB
C

/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
*
* gimppropgui-spiral.c
* Copyright (C) 2017 Michael Natterer <mitch@gimp.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libgimpmath/gimpmath.h"
#include "libgimpwidgets/gimpwidgets.h"
#include "propgui-types.h"
#include "core/gimpcontext.h"
#include "gimppropgui.h"
#include "gimppropgui-generic.h"
#include "gimppropgui-spiral.h"
#include "gimp-intl.h"
typedef enum
{
GEGL_SPIRAL_TYPE_LINEAR,
GEGL_SPIRAL_TYPE_LOGARITHMIC
} GeglSpiralType;
static void
slider_line_callback (GObject *config,
GeglRectangle *area,
gdouble x1,
gdouble y1,
gdouble x2,
gdouble y2,
const GimpControllerSlider *sliders,
gint n_sliders)
{
GeglSpiralType type;
gdouble x, y;
gdouble radius;
gdouble rotation;
gdouble base;
gdouble balance;
g_object_set_data_full (G_OBJECT (config), "area",
g_memdup (area, sizeof (GeglRectangle)),
(GDestroyNotify) g_free);
g_object_get (config,
"type", &type,
"base", &base,
"balance", &balance,
NULL);
x = x1 / area->width;
y = y1 / area->height;
radius = sqrt (SQR (x2 - x1) + SQR (y2 - y1));
rotation = atan2 (-(y2 - y1), x2 - x1) * 180 / G_PI;
if (rotation < 0)
rotation += 360.0;
switch (type)
{
case GEGL_SPIRAL_TYPE_LINEAR:
balance = 3.0 - 4.0 * sliders[0].value;
break;
case GEGL_SPIRAL_TYPE_LOGARITHMIC:
{
gdouble old_base = base;
base = 1.0 / sliders[1].value;
base = MIN (base, 1000000.0);
/* keep "balance" fixed when changing "base", or when "base" is 1, in
* which case there's no inverse mapping for the slider value, and we
* can get NaN.
*/
if (base == old_base && base > 1.0)
{
balance = -4.0 * log (sliders[0].value) / log (base) - 1.0;
balance = CLAMP (balance, -1.0, 1.0);
}
}
break;
}
g_object_set (config,
"x", x,
"y", y,
"radius", radius,
"base", base,
"rotation", rotation,
"balance", balance,
NULL);
}
static void
config_notify (GObject *config,
const GParamSpec *pspec,
gpointer set_data)
{
GimpControllerSliderLineCallback set_func;
GeglRectangle *area;
GeglSpiralType type;
gdouble x, y;
gdouble radius;
gdouble rotation;
gdouble base;
gdouble balance;
gdouble x1, y1, x2, y2;
GimpControllerSlider sliders[2];
gint n_sliders = 0;
set_func = g_object_get_data (G_OBJECT (config), "set-func");
area = g_object_get_data (G_OBJECT (config), "area");
g_object_get (config,
"type", &type,
"x", &x,
"y", &y,
"radius", &radius,
"rotation", &rotation,
"base", &base,
"balance", &balance,
NULL);
x1 = x * area->width;
y1 = y * area->height;
x2 = x1 + cos (rotation * (G_PI / 180.0)) * radius;
y2 = y1 - sin (rotation * (G_PI / 180.0)) * radius;
switch (type)
{
case GEGL_SPIRAL_TYPE_LINEAR:
n_sliders = 1;
/* balance */
sliders[0] = GIMP_CONTROLLER_SLIDER_DEFAULT;
sliders[0].min = 0.5;
sliders[0].max = 1.0;
sliders[0].value = 0.5 + (1.0 - balance) / 4.0;
break;
case GEGL_SPIRAL_TYPE_LOGARITHMIC:
n_sliders = 2;
/* balance */
sliders[0] = GIMP_CONTROLLER_SLIDER_DEFAULT;
sliders[0].min = 1.0 / sqrt (base);
sliders[0].max = 1.0;
sliders[0].value = pow (base, -(balance + 1.0) / 4.0);
/* base */
sliders[1] = GIMP_CONTROLLER_SLIDER_DEFAULT;
sliders[1].min = 0.0;
sliders[1].max = 1.0;
sliders[1].value = 1.0 / base;
break;
}
set_func (set_data, area, x1, y1, x2, y2, sliders, n_sliders);
}
GtkWidget *
_gimp_prop_gui_new_spiral (GObject *config,
GParamSpec **param_specs,
guint n_param_specs,
GeglRectangle *area,
GimpContext *context,
GimpCreatePickerFunc create_picker_func,
GimpCreateControllerFunc create_controller_func,
gpointer creator)
{
GtkWidget *vbox;
g_return_val_if_fail (G_IS_OBJECT (config), NULL);
g_return_val_if_fail (param_specs != NULL, NULL);
g_return_val_if_fail (n_param_specs > 0, NULL);
g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
vbox = _gimp_prop_gui_new_generic (config,
param_specs, n_param_specs,
area, context,
create_picker_func,
create_controller_func,
creator);
if (create_controller_func)
{
GCallback set_func;
gpointer set_data;
set_func = create_controller_func (creator,
GIMP_CONTROLLER_TYPE_SLIDER_LINE,
_("Spiral: "),
(GCallback) slider_line_callback,
config,
&set_data);
g_object_set_data (G_OBJECT (config), "set-func", set_func);
g_object_set_data_full (G_OBJECT (config), "area",
g_memdup (area, sizeof (GeglRectangle)),
(GDestroyNotify) g_free);
config_notify (config, NULL, set_data);
g_signal_connect (config, "notify",
G_CALLBACK (config_notify),
set_data);
}
return vbox;
}