gimpscaleentry.c 18.5 KB
Newer Older
1 2 3
/* LIBGIMP - The GIMP Library
 * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
 *
4
 * gimpscaleentry.c
5 6
 * Copyright (C) 2000 Michael Natterer <mitch@gimp.org>
 *
7
 * This library is free software: you can redistribute it and/or
8 9
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
10
 * version 3 of the License, or (at your option) any later version.
11 12 13 14 15 16 17
 *
 * 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with this library.  If not, see
19
 * <https://www.gnu.org/licenses/>.
20 21 22 23
 */

#include "config.h"

24
#include <gegl.h>
25 26 27 28 29 30 31 32
#include <gtk/gtk.h>

#include "libgimpcolor/gimpcolor.h"
#include "libgimpmath/gimpmath.h"
#include "libgimpbase/gimpbase.h"

#include "gimpwidgets.h"

33

34 35 36 37 38 39 40 41 42 43
static gboolean        gimp_scale_entry_linear_to_log (GBinding     *binding,
                                                       const GValue *from_value,
                                                       GValue       *to_value,
                                                       gpointer      user_data);
static gboolean        gimp_scale_entry_log_to_linear (GBinding     *binding,
                                                       const GValue *from_value,
                                                       GValue       *to_value,
                                                       gpointer      user_data);

static GtkAdjustment * gimp_scale_entry_new_internal  (gboolean      color_scale,
44
                                                       GtkGrid      *grid,
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
                                                       gint          column,
                                                       gint          row,
                                                       const gchar  *text,
                                                       gint          scale_width,
                                                       gint          spinbutton_width,
                                                       gdouble       value,
                                                       gdouble       lower,
                                                       gdouble       upper,
                                                       gdouble       step_increment,
                                                       gdouble       page_increment,
                                                       guint         digits,
                                                       gboolean      constrain,
                                                       gdouble       unconstrained_lower,
                                                       gdouble       unconstrained_upper,
                                                       const gchar  *tooltip,
                                                       const gchar  *help_id);
61 62 63 64 65 66 67


static gboolean
gimp_scale_entry_linear_to_log (GBinding     *binding,
                                const GValue *from_value,
                                GValue       *to_value,
                                gpointer      user_data)
68
{
69 70
  GtkAdjustment *spin_adjustment;
  gdouble        value = g_value_get_double (from_value);
71

72
  spin_adjustment = GTK_ADJUSTMENT (g_binding_get_source (binding));
73

74 75
  if (gtk_adjustment_get_lower (spin_adjustment) <= 0.0)
    value = log (value - gtk_adjustment_get_lower (spin_adjustment) + 0.1);
76
  else
77
    value = log (value);
78

79
  g_value_set_double (to_value, value);
80

81
  return TRUE;
82 83
}

84 85 86 87 88
static gboolean
gimp_scale_entry_log_to_linear (GBinding     *binding,
                                const GValue *from_value,
                                GValue       *to_value,
                                gpointer      user_data)
89
{
90 91
  GtkAdjustment *spin_adjustment;
  gdouble        value = g_value_get_double (from_value);
92

93
  spin_adjustment = GTK_ADJUSTMENT (g_binding_get_target (binding));
94

95
  value = exp (value);
96

97 98
  if (gtk_adjustment_get_lower (spin_adjustment) <= 0.0)
    value += gtk_adjustment_get_lower (spin_adjustment) - 0.1;
99

100 101 102
  g_value_set_double (to_value, value);

  return TRUE;
103 104
}

105
static GtkAdjustment *
106
gimp_scale_entry_new_internal (gboolean     color_scale,
107
                               GtkGrid     *grid,
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
                               gint         column,
                               gint         row,
                               const gchar *text,
                               gint         scale_width,
                               gint         spinbutton_width,
                               gdouble      value,
                               gdouble      lower,
                               gdouble      upper,
                               gdouble      step_increment,
                               gdouble      page_increment,
                               guint        digits,
                               gboolean     constrain,
                               gdouble      unconstrained_lower,
                               gdouble      unconstrained_upper,
                               const gchar *tooltip,
                               const gchar *help_id)
{
125 126 127
  GtkWidget     *label;
  GtkWidget     *scale;
  GtkWidget     *spinbutton;
128 129 130
  GtkAdjustment *scale_adjustment;
  GtkAdjustment *spin_adjustment;
  GBinding      *binding;
131 132

  label = gtk_label_new_with_mnemonic (text);
133
  gtk_label_set_xalign (GTK_LABEL (label), 0.0);
134 135
  gtk_widget_show (label);

136 137
  scale_adjustment = gtk_adjustment_new (value, lower, upper,
                                         step_increment, page_increment, 0.0);
138

139
  if (! constrain &&
140 141
      unconstrained_lower <= lower &&
      unconstrained_upper >= upper)
142
    {
143 144 145 146
      spin_adjustment = gtk_adjustment_new (value,
                                            unconstrained_lower,
                                            unconstrained_upper,
                                            step_increment, page_increment, 0.0);
147 148 149
    }
  else
    {
150 151
      spin_adjustment = gtk_adjustment_new (value, lower, upper,
                                            step_increment, page_increment, 0.0);
152 153
    }

154 155 156 157 158 159 160
  binding = g_object_bind_property (G_OBJECT (spin_adjustment),  "value",
                                    G_OBJECT (scale_adjustment), "value",
                                    G_BINDING_BIDIRECTIONAL |
                                    G_BINDING_SYNC_CREATE);

  spinbutton = gtk_spin_button_new (spin_adjustment, step_increment, digits);
  gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE);
161
  gtk_widget_show (spinbutton);
162

163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
  gtk_label_set_mnemonic_widget (GTK_LABEL (label), spinbutton);

  if (spinbutton_width > 0)
    {
      if (spinbutton_width < 17)
        gtk_entry_set_width_chars (GTK_ENTRY (spinbutton), spinbutton_width);
      else
        gtk_widget_set_size_request (spinbutton, spinbutton_width, -1);
    }

  if (color_scale)
    {
      scale = gimp_color_scale_new (GTK_ORIENTATION_HORIZONTAL,
                                    GIMP_COLOR_SELECTOR_VALUE);

178
      gtk_range_set_adjustment (GTK_RANGE (scale), scale_adjustment);
179 180 181
    }
  else
    {
182
      scale = gtk_scale_new (GTK_ORIENTATION_HORIZONTAL, scale_adjustment);
183 184
      gtk_scale_set_digits (GTK_SCALE (scale), digits);
      gtk_scale_set_draw_value (GTK_SCALE (scale), FALSE);
185 186 187 188
    }

  if (scale_width > 0)
    gtk_widget_set_size_request (scale, scale_width, -1);
189 190
  gtk_widget_show (scale);

191
  gtk_widget_set_hexpand (scale, TRUE);
192

193 194 195
  gtk_grid_attach (grid, label,      column,     row, 1, 1);
  gtk_grid_attach (grid, scale,      column + 1, row, 1, 1);
  gtk_grid_attach (grid, spinbutton, column + 2, row, 1, 1);
196 197 198

  if (tooltip || help_id)
    {
199
      gimp_help_set_help_data (label, tooltip, help_id);
200 201 202 203
      gimp_help_set_help_data (scale, tooltip, help_id);
      gimp_help_set_help_data (spinbutton, tooltip, help_id);
    }

204 205 206 207
  g_object_set_data (G_OBJECT (spin_adjustment), "label",      label);
  g_object_set_data (G_OBJECT (spin_adjustment), "scale",      scale);
  g_object_set_data (G_OBJECT (spin_adjustment), "spinbutton", spinbutton);
  g_object_set_data (G_OBJECT (spin_adjustment), "binding",    binding);
208

209
  return spin_adjustment;
210 211
}

212
/**
213
 * gimp_scale_entry_new:
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
 * @grid:                The #GtkGrid the widgets will be attached to.
 * @column:              The column to start with.
 * @row:                 The row to attach the widgets.
 * @text:                The text for the #GtkLabel which will appear
 *                       left of the #GtkHScale.
 * @scale_width:         The minimum horizontal size of the #GtkHScale.
 * @spinbutton_width:    The minimum horizontal size of the #GtkSpinButton.
 * @value:               The initial value.
 * @lower:               The lower boundary.
 * @upper:               The upper boundary.
 * @step_increment:      The step increment.
 * @page_increment:      The page increment.
 * @digits:              The number of decimal digits.
 * @constrain:           %TRUE if the range of possible values of the
 *                       #GtkSpinButton should be the same as of the #GtkHScale.
 * @unconstrained_lower: The spinbutton's lower boundary
 *                       if @constrain == %FALSE.
 * @unconstrained_upper: The spinbutton's upper boundary
 *                       if @constrain == %FALSE.
 * @tooltip:             A tooltip message for the scale and the spinbutton.
 * @help_id:             The widgets' help_id (see gimp_help_set_help_data()).
 *
 * This function creates a #GtkLabel, a #GtkHScale and a #GtkSpinButton and
 * attaches them to a 3-column #GtkGrid.
 *
 * Returns: The #GtkSpinButton's #GtkAdjustment.
 **/
GtkAdjustment *
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
gimp_scale_entry_new (GtkGrid     *grid,
                      gint         column,
                      gint         row,
                      const gchar *text,
                      gint         scale_width,
                      gint         spinbutton_width,
                      gdouble      value,
                      gdouble      lower,
                      gdouble      upper,
                      gdouble      step_increment,
                      gdouble      page_increment,
                      guint        digits,
                      gboolean     constrain,
                      gdouble      unconstrained_lower,
                      gdouble      unconstrained_upper,
                      const gchar *tooltip,
                      const gchar *help_id)
259 260
{
  return gimp_scale_entry_new_internal (FALSE,
261
                                        grid, column, row,
262 263 264 265 266 267 268 269
                                        text, scale_width, spinbutton_width,
                                        value, lower, upper,
                                        step_increment, page_increment,
                                        digits,
                                        constrain,
                                        unconstrained_lower,
                                        unconstrained_upper,
                                        tooltip, help_id);
270 271
}

272
/**
273
 * gimp_color_scale_entry_new:
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
 * @grid:                The #GtkGrid the widgets will be attached to.
 * @column:              The column to start with.
 * @row:                 The row to attach the widgets.
 * @text:                The text for the #GtkLabel which will appear
 *                       left of the #GtkHScale.
 * @scale_width:         The minimum horizontal size of the #GtkHScale.
 * @spinbutton_width:    The minimum horizontal size of the #GtkSpinButton.
 * @value:               The initial value.
 * @lower:               The lower boundary.
 * @upper:               The upper boundary.
 * @step_increment:      The step increment.
 * @page_increment:      The page increment.
 * @digits:              The number of decimal digits.
 * @tooltip:             A tooltip message for the scale and the spinbutton.
 * @help_id:             The widgets' help_id (see gimp_help_set_help_data()).
 *
 * This function creates a #GtkLabel, a #GimpColorScale and a
 * #GtkSpinButton and attaches them to a 3-column #GtkGrid.
 *
 * Returns: The #GtkSpinButton's #GtkAdjustment.
 **/
GtkAdjustment *
296 297 298 299 300 301 302 303 304 305 306 307 308 309
gimp_color_scale_entry_new (GtkGrid     *grid,
                            gint         column,
                            gint         row,
                            const gchar *text,
                            gint         scale_width,
                            gint         spinbutton_width,
                            gdouble      value,
                            gdouble      lower,
                            gdouble      upper,
                            gdouble      step_increment,
                            gdouble      page_increment,
                            guint        digits,
                            const gchar *tooltip,
                            const gchar *help_id)
310 311
{
  return gimp_scale_entry_new_internal (TRUE,
312
                                        grid, column, row,
313 314 315 316 317 318
                                        text, scale_width, spinbutton_width,
                                        value, lower, upper,
                                        step_increment, page_increment,
                                        digits,
                                        TRUE, 0.0, 0.0,
                                        tooltip, help_id);
319 320 321 322 323 324 325 326 327 328 329 330 331
}

/**
 * gimp_scale_entry_set_logarithmic:
 * @adjustment:  a  #GtkAdjustment as returned by gimp_scale_entry_new()
 * @logarithmic: a boolean value to set or reset logarithmic behaviour
 *               of the scale widget
 *
 * Sets whether the scale_entry's scale widget will behave in a linear
 * or logharithmic fashion. Useful when an entry has to attend large
 * ranges, but smaller selections on that range require a finer
 * adjustment.
 *
332
 * Since: 2.2
333 334
 **/
void
335 336
gimp_scale_entry_set_logarithmic (GtkAdjustment *adjustment,
                                  gboolean       logarithmic)
337
{
338
  GtkAdjustment *spin_adj;
339
  GtkAdjustment *scale_adj;
340
  GBinding      *binding;
341 342 343

  g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));

344
  spin_adj  = adjustment;
345
  scale_adj = GIMP_SCALE_ENTRY_SCALE_ADJ (adjustment);
346 347 348 349 350 351
  binding   = g_object_get_data (G_OBJECT (adjustment), "binding");

  g_return_if_fail (GTK_IS_ADJUSTMENT (scale_adj));
  g_return_if_fail (G_IS_BINDING (binding));

  logarithmic = logarithmic ? TRUE : FALSE;
352

353 354 355
  if (logarithmic == gimp_scale_entry_get_logarithmic (adjustment))
    return;

356 357
  g_object_unref (binding);

358 359
  if (logarithmic)
    {
360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377
      gdouble correction;
      gdouble log_value, log_lower, log_upper;
      gdouble log_step_increment, log_page_increment;

      correction = (gtk_adjustment_get_lower (scale_adj) > 0 ?
                    0 : 0.1 + - gtk_adjustment_get_lower (scale_adj));

      log_value = log (gtk_adjustment_get_value (scale_adj) + correction);
      log_lower = log (gtk_adjustment_get_lower (scale_adj) + correction);
      log_upper = log (gtk_adjustment_get_upper (scale_adj) + correction);
      log_step_increment =
        (log_upper - log_lower) / ((gtk_adjustment_get_upper (scale_adj) -
                                    gtk_adjustment_get_lower (scale_adj)) /
                                   gtk_adjustment_get_step_increment (scale_adj));
      log_page_increment =
        (log_upper - log_lower) / ((gtk_adjustment_get_upper (scale_adj) -
                                    gtk_adjustment_get_lower (scale_adj)) /
                                   gtk_adjustment_get_page_increment (scale_adj));
378

379 380 381 382
      gtk_adjustment_configure (scale_adj,
                                log_value, log_lower, log_upper,
                                log_step_increment, log_page_increment, 0.0);

383 384 385 386 387 388 389
      binding = g_object_bind_property_full (G_OBJECT (spin_adj),  "value",
                                             G_OBJECT (scale_adj), "value",
                                             G_BINDING_BIDIRECTIONAL |
                                             G_BINDING_SYNC_CREATE,
                                             gimp_scale_entry_linear_to_log,
                                             gimp_scale_entry_log_to_linear,
                                             NULL, NULL);
390 391 392 393 394
    }
  else
    {
      gdouble lower, upper;

395 396
      lower = exp (gtk_adjustment_get_lower (scale_adj));
      upper = exp (gtk_adjustment_get_upper (scale_adj));
397

398
      if (gtk_adjustment_get_lower (spin_adj) <= 0.0)
399
        {
400 401
          lower += - 0.1 + gtk_adjustment_get_lower (spin_adj);
          upper += - 0.1 + gtk_adjustment_get_lower (spin_adj);
402 403
        }

404
      gtk_adjustment_configure (scale_adj,
405
                                gtk_adjustment_get_value (spin_adj),
406
                                lower, upper,
407 408
                                gtk_adjustment_get_step_increment (spin_adj),
                                gtk_adjustment_get_page_increment (spin_adj),
409
                                0.0);
410

411 412 413 414 415
      binding = g_object_bind_property (G_OBJECT (spin_adj),  "value",
                                        G_OBJECT (scale_adj), "value",
                                        G_BINDING_BIDIRECTIONAL |
                                        G_BINDING_SYNC_CREATE);
    }
416

417
  g_object_set_data (G_OBJECT (spin_adj), "binding", binding);
418

419 420
  g_object_set_data (G_OBJECT (adjustment), "logarithmic",
                     GINT_TO_POINTER (logarithmic));
421 422 423 424 425 426 427 428 429
}

/**
 * gimp_scale_entry_get_logarithmic:
 * @adjustment: a  #GtkAdjustment as returned by gimp_scale_entry_new()
 *
 * Return value: %TRUE if the the entry's scale widget will behave in
 *               logharithmic fashion, %FALSE for linear behaviour.
 *
430
 * Since: 2.2
431 432
 **/
gboolean
433
gimp_scale_entry_get_logarithmic (GtkAdjustment *adjustment)
434 435 436 437 438 439 440 441 442 443 444 445
{
  return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (adjustment),
                                             "logarithmic"));
}

/**
 * gimp_scale_entry_set_sensitive:
 * @adjustment: a #GtkAdjustment returned by gimp_scale_entry_new()
 * @sensitive:  a boolean value with the same semantics as the @sensitive
 *              parameter of gtk_widget_set_sensitive()
 *
 * Sets the sensitivity of the scale_entry's #GtkLabel, #GtkHScale and
446
 * #GtkSpinButton.
447 448
 **/
void
449 450
gimp_scale_entry_set_sensitive (GtkAdjustment *adjustment,
                                gboolean       sensitive)
451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467
{
  GtkWidget *widget;

  g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));

  widget = GIMP_SCALE_ENTRY_LABEL (adjustment);
  if (widget)
    gtk_widget_set_sensitive (widget, sensitive);

  widget = GIMP_SCALE_ENTRY_SCALE (adjustment);
  if (widget)
    gtk_widget_set_sensitive (widget, sensitive);

  widget = GIMP_SCALE_ENTRY_SPINBUTTON (adjustment);
  if (widget)
    gtk_widget_set_sensitive (widget, sensitive);
}