hdy-clamp.c 17.7 KB
Newer Older
Adrien Plazas's avatar
Adrien Plazas committed
1
2
3
/*
 * Copyright (C) 2018 Purism SPC
 *
4
 * SPDX-License-Identifier: LGPL-2.1-or-later
Adrien Plazas's avatar
Adrien Plazas committed
5
6
 */

Bastien Nocera's avatar
Bastien Nocera committed
7
#include "config.h"
8
#include "hdy-clamp.h"
Adrien Plazas's avatar
Adrien Plazas committed
9

Bastien Nocera's avatar
Bastien Nocera committed
10
#include <glib/gi18n-lib.h>
Adrien Plazas's avatar
Adrien Plazas committed
11
12
#include <math.h>

Adrien Plazas's avatar
Adrien Plazas committed
13
#include "hdy-animation-private.h"
Adrien Plazas's avatar
Adrien Plazas committed
14
#include "hdy-css-private.h"
Adrien Plazas's avatar
Adrien Plazas committed
15

Adrien Plazas's avatar
Adrien Plazas committed
16
/**
17
 * HdyClamp:
Adrien Plazas's avatar
Adrien Plazas committed
18
 *
19
20
21
 * A widget constraining its child to a given size.
 *
 * The `HdyClamp` widget constrains the size of the widget it contains to a
Adrien Plazas's avatar
Adrien Plazas committed
22
23
24
 * given maximum size. It will constrain the width if it is horizontal, or the
 * height if it is vertical. The expansion of the child from its minimum to its
 * maximum size is eased out for a smooth transition.
Adrien Plazas's avatar
Adrien Plazas committed
25
 *
Adrien Plazas's avatar
Adrien Plazas committed
26
27
 * If the child requires more than the requested maximum size, it will be
 * allocated the minimum size it can fit in instead.
28
 *
29
30
31
 * ## CSS nodes
 *
 * `HdyClamp` has a single CSS node with name `clamp`.
32
 *
33
34
35
 * The node will get the style classes `.large` when its child reached its
 * maximum size, `.small` when the clamp allocates its full size to its child,
 * `.medium` in-between, or none if it didn't compute its size yet.
Adrien Plazas's avatar
Adrien Plazas committed
36
37
 *
 * Since: 1.0
Adrien Plazas's avatar
Adrien Plazas committed
38
39
40
41
42
43
 */

#define HDY_EASE_OUT_TAN_CUBIC 3

enum {
  PROP_0,
44
  PROP_MAXIMUM_SIZE,
45
  PROP_TIGHTENING_THRESHOLD,
Adrien Plazas's avatar
Adrien Plazas committed
46
47
48
49

  /* Overridden properties */
  PROP_ORIENTATION,

50
  LAST_PROP = PROP_TIGHTENING_THRESHOLD + 1,
Adrien Plazas's avatar
Adrien Plazas committed
51
52
};

Adrien Plazas's avatar
Adrien Plazas committed
53
struct _HdyClamp
Adrien Plazas's avatar
Adrien Plazas committed
54
55
56
{
  GtkBin parent_instance;

57
  gint maximum_size;
58
  gint tightening_threshold;
Adrien Plazas's avatar
Adrien Plazas committed
59
60

  GtkOrientation orientation;
Adrien Plazas's avatar
Adrien Plazas committed
61
62
63
64
};

static GParamSpec *props[LAST_PROP];

Adrien Plazas's avatar
Adrien Plazas committed
65
66
67
68
69
70
71
72
73
74
75
76
77
78
G_DEFINE_TYPE_WITH_CODE (HdyClamp, hdy_clamp, GTK_TYPE_BIN,
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, NULL))

static void
set_orientation (HdyClamp       *self,
                 GtkOrientation  orientation)
{
  if (self->orientation == orientation)
    return;

  self->orientation = orientation;
  gtk_widget_queue_resize (GTK_WIDGET (self));
  g_object_notify (G_OBJECT (self), "orientation");
}
Adrien Plazas's avatar
Adrien Plazas committed
79
80

static void
Adrien Plazas's avatar
Adrien Plazas committed
81
82
83
84
hdy_clamp_get_property (GObject    *object,
                        guint       prop_id,
                        GValue     *value,
                        GParamSpec *pspec)
Adrien Plazas's avatar
Adrien Plazas committed
85
{
Adrien Plazas's avatar
Adrien Plazas committed
86
  HdyClamp *self = HDY_CLAMP (object);
Adrien Plazas's avatar
Adrien Plazas committed
87
88

  switch (prop_id) {
89
90
  case PROP_MAXIMUM_SIZE:
    g_value_set_int (value, hdy_clamp_get_maximum_size (self));
91
    break;
92
93
  case PROP_TIGHTENING_THRESHOLD:
    g_value_set_int (value, hdy_clamp_get_tightening_threshold (self));
94
    break;
Adrien Plazas's avatar
Adrien Plazas committed
95
96
97
  case PROP_ORIENTATION:
    g_value_set_enum (value, self->orientation);
    break;
Adrien Plazas's avatar
Adrien Plazas committed
98
99
100
101
102
103
  default:
    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
  }
}

static void
Adrien Plazas's avatar
Adrien Plazas committed
104
105
106
107
hdy_clamp_set_property (GObject      *object,
                        guint         prop_id,
                        const GValue *value,
                        GParamSpec   *pspec)
Adrien Plazas's avatar
Adrien Plazas committed
108
{
Adrien Plazas's avatar
Adrien Plazas committed
109
  HdyClamp *self = HDY_CLAMP (object);
Adrien Plazas's avatar
Adrien Plazas committed
110
111

  switch (prop_id) {
112
113
  case PROP_MAXIMUM_SIZE:
    hdy_clamp_set_maximum_size (self, g_value_get_int (value));
Adrien Plazas's avatar
Adrien Plazas committed
114
    break;
115
116
  case PROP_TIGHTENING_THRESHOLD:
    hdy_clamp_set_tightening_threshold (self, g_value_get_int (value));
117
    break;
Adrien Plazas's avatar
Adrien Plazas committed
118
119
120
  case PROP_ORIENTATION:
    set_orientation (self, g_value_get_enum (value));
    break;
Adrien Plazas's avatar
Adrien Plazas committed
121
122
123
124
125
  default:
    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
  }
}

126
127
128
129
static inline double
inverse_lerp (double a,
              double b,
              double t)
130
{
131
132
  return (t - a) / (b - a);
}
133

134
135
136
137
138
139
140
static int
clamp_size_from_child (HdyClamp *self,
                       int       min,
                       int       nat)
{
  int max = 0, lower = 0, upper = 0;
  double progress;
141

142
143
144
145
146
147
148
149
150
151
152
153
  lower = MAX (MIN (self->tightening_threshold, self->maximum_size), min);
  max = MAX (lower, self->maximum_size);
  upper = lower + HDY_EASE_OUT_TAN_CUBIC * (max - lower);

  if (nat <= lower)
    progress = 0;
  else if (nat >= max)
    progress = 1;
  else {
    double ease = inverse_lerp (lower, max, nat);

    progress = 1 + cbrt (ease - 1); // inverse ease out cubic
Adrien Plazas's avatar
Adrien Plazas committed
154
  }
155

156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
  return ceil (hdy_lerp (lower, upper, progress));
}

static int
child_size_from_clamp (HdyClamp  *self,
                       GtkWidget *child,
                       int        for_size,
                       int       *child_maximum,
                       int       *lower_threshold)
{
  int min = 0, nat = 0, max = 0, lower = 0, upper = 0;
  double progress;

  if (self->orientation == GTK_ORIENTATION_HORIZONTAL)
    gtk_widget_get_preferred_width (child, &min, &nat);
  else
    gtk_widget_get_preferred_height (child, &min, &nat);

174
  lower = MAX (MIN (self->tightening_threshold, self->maximum_size), min);
175
  max = MAX (lower, self->maximum_size);
176
  upper = lower + HDY_EASE_OUT_TAN_CUBIC * (max - lower);
177

178
179
180
181
182
  if (child_maximum)
    *child_maximum = max;
  if (lower_threshold)
    *lower_threshold = lower;

Adrien Plazas's avatar
Adrien Plazas committed
183
  if (for_size < 0)
184
    return MIN (nat, max);
185

Adrien Plazas's avatar
Adrien Plazas committed
186
187
  if (for_size <= lower)
    return for_size;
188

Adrien Plazas's avatar
Adrien Plazas committed
189
  if (for_size >= upper)
190
    return max;
191

192
  progress = inverse_lerp (lower, upper, for_size);
193

194
  return hdy_lerp (lower, max, hdy_ease_out_cubic (progress));
195
196
}

Adrien Plazas's avatar
Adrien Plazas committed
197
/* This private method is prefixed by the call name because it will be a virtual
Oliver Galvin's avatar
Oliver Galvin committed
198
 * method in GTK 4.
Adrien Plazas's avatar
Adrien Plazas committed
199
 */
Adrien Plazas's avatar
Adrien Plazas committed
200
static void
Adrien Plazas's avatar
Adrien Plazas committed
201
202
203
204
205
206
207
hdy_clamp_measure (GtkWidget      *widget,
                   GtkOrientation  orientation,
                   int             for_size,
                   int            *minimum,
                   int            *natural,
                   int            *minimum_baseline,
                   int            *natural_baseline)
Adrien Plazas's avatar
Adrien Plazas committed
208
{
Adrien Plazas's avatar
Adrien Plazas committed
209
  HdyClamp *self = HDY_CLAMP (widget);
Adrien Plazas's avatar
Adrien Plazas committed
210
211
  GtkBin *bin = GTK_BIN (widget);
  GtkWidget *child;
212
213
214
215
  int child_min = 0;
  int child_nat = 0;
  int child_min_baseline = -1;
  int child_nat_baseline = -1;
Adrien Plazas's avatar
Adrien Plazas committed
216

Adrien Plazas's avatar
Adrien Plazas committed
217
218
219
220
221
222
223
224
  if (minimum)
    *minimum = 0;
  if (natural)
    *natural = 0;
  if (minimum_baseline)
    *minimum_baseline = -1;
  if (natural_baseline)
    *natural_baseline = -1;
Adrien Plazas's avatar
Adrien Plazas committed
225
226

  child = gtk_bin_get_child (bin);
Adrien Plazas's avatar
Adrien Plazas committed
227

228
229
230
  if (!child || !gtk_widget_is_visible (child))
    return;

231
232
  for_size = hdy_css_adjust_for_size (widget, orientation, for_size);

233
234
235
236
237
238
239
240
241
242
243
  if (self->orientation == orientation) {
    if (orientation == GTK_ORIENTATION_HORIZONTAL)
      gtk_widget_get_preferred_width (child, &child_min, &child_nat);
    else
      gtk_widget_get_preferred_height_and_baseline_for_width (child, -1,
                                                              &child_min,
                                                              &child_nat,
                                                              &child_min_baseline,
                                                              &child_nat_baseline);

    child_nat = clamp_size_from_child (self, child_min, child_nat);
Adrien Plazas's avatar
Adrien Plazas committed
244
  } else {
245
246
247
248
249
250
251
252
253
254
255
    int child_size = child_size_from_clamp (self, child, for_size, NULL, NULL);

    if (orientation == GTK_ORIENTATION_HORIZONTAL)
      gtk_widget_get_preferred_width_for_height (child, child_size,
                                                 &child_min, &child_nat);
    else
      gtk_widget_get_preferred_height_and_baseline_for_width (child, child_size,
                                                              &child_min,
                                                              &child_nat,
                                                              &child_min_baseline,
                                                              &child_nat_baseline);
Adrien Plazas's avatar
Adrien Plazas committed
256
  }
Adrien Plazas's avatar
Adrien Plazas committed
257

258
259
260
261
262
263
264
265
266
  if (minimum)
    *minimum = child_min;
  if (natural)
    *natural = child_nat;
  if (minimum_baseline && child_min_baseline > -1)
    *minimum_baseline = child_min_baseline;
  if (natural_baseline && child_nat_baseline > -1)
    *natural_baseline = child_nat_baseline;

Adrien Plazas's avatar
Adrien Plazas committed
267
  hdy_css_measure (widget, orientation, minimum, natural);
Adrien Plazas's avatar
Adrien Plazas committed
268
269
}

Adrien Plazas's avatar
Adrien Plazas committed
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
static GtkSizeRequestMode
hdy_clamp_get_request_mode (GtkWidget *widget)
{
  HdyClamp *self = HDY_CLAMP (widget);

  return self->orientation == GTK_ORIENTATION_HORIZONTAL ?
    GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH :
    GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT;
}

static void
hdy_clamp_get_preferred_width_for_height (GtkWidget *widget,
                                          gint       height,
                                          gint      *minimum,
                                          gint      *natural)
{
  hdy_clamp_measure (widget, GTK_ORIENTATION_HORIZONTAL, height,
                     minimum, natural, NULL, NULL);
}

Adrien Plazas's avatar
Adrien Plazas committed
290
static void
Adrien Plazas's avatar
Adrien Plazas committed
291
292
293
hdy_clamp_get_preferred_width (GtkWidget *widget,
                               gint      *minimum,
                               gint      *natural)
Adrien Plazas's avatar
Adrien Plazas committed
294
{
Adrien Plazas's avatar
Adrien Plazas committed
295
296
  hdy_clamp_measure (widget, GTK_ORIENTATION_HORIZONTAL, -1,
                     minimum, natural, NULL, NULL);
Adrien Plazas's avatar
Adrien Plazas committed
297
298
299
}

static void
Adrien Plazas's avatar
Adrien Plazas committed
300
301
302
303
304
305
hdy_clamp_get_preferred_height_and_baseline_for_width (GtkWidget *widget,
                                                       gint       width,
                                                       gint      *minimum,
                                                       gint      *natural,
                                                       gint      *minimum_baseline,
                                                       gint      *natural_baseline)
Adrien Plazas's avatar
Adrien Plazas committed
306
{
Adrien Plazas's avatar
Adrien Plazas committed
307
308
  hdy_clamp_measure (widget, GTK_ORIENTATION_VERTICAL, width,
                     minimum, natural, minimum_baseline, natural_baseline);
Adrien Plazas's avatar
Adrien Plazas committed
309
310
}

Adrien Plazas's avatar
Adrien Plazas committed
311
312
313
314
315
316
317
318
319
320
static void
hdy_clamp_get_preferred_height_for_width (GtkWidget *widget,
                                          gint       width,
                                          gint      *minimum,
                                          gint      *natural)
{
  hdy_clamp_measure (widget, GTK_ORIENTATION_VERTICAL, width,
                     minimum, natural, NULL, NULL);
}

Adrien Plazas's avatar
Adrien Plazas committed
321
static void
Adrien Plazas's avatar
Adrien Plazas committed
322
323
324
hdy_clamp_get_preferred_height (GtkWidget *widget,
                                gint      *minimum,
                                gint      *natural)
Adrien Plazas's avatar
Adrien Plazas committed
325
{
Adrien Plazas's avatar
Adrien Plazas committed
326
327
  hdy_clamp_measure (widget, GTK_ORIENTATION_VERTICAL, -1,
                     minimum, natural, NULL, NULL);
Adrien Plazas's avatar
Adrien Plazas committed
328
329
330
}

static void
Adrien Plazas's avatar
Adrien Plazas committed
331
332
hdy_clamp_size_allocate (GtkWidget     *widget,
                         GtkAllocation *allocation)
Adrien Plazas's avatar
Adrien Plazas committed
333
{
Adrien Plazas's avatar
Adrien Plazas committed
334
  HdyClamp *self = HDY_CLAMP (widget);
Adrien Plazas's avatar
Adrien Plazas committed
335
  GtkBin *bin = GTK_BIN (widget);
Adrien Plazas's avatar
Adrien Plazas committed
336
  GtkAllocation child_allocation, base_child_allocation;
Adrien Plazas's avatar
Adrien Plazas committed
337
338
  gint baseline;
  GtkWidget *child;
339
340
  GtkStyleContext *context = gtk_widget_get_style_context (widget);
  gint child_maximum = 0, lower_threshold = 0;
Adrien Plazas's avatar
Adrien Plazas committed
341
  gint child_clamped_size;
Adrien Plazas's avatar
Adrien Plazas committed
342

Adrien Plazas's avatar
Adrien Plazas committed
343
  hdy_css_size_allocate_self (widget, allocation);
Adrien Plazas's avatar
Adrien Plazas committed
344
345
346
  gtk_widget_set_allocation (widget, allocation);

  child = gtk_bin_get_child (bin);
347
  if (!(child && gtk_widget_get_visible (child))) {
Adrien Plazas's avatar
Adrien Plazas committed
348
    gtk_style_context_remove_class (context, "small");
349
    gtk_style_context_remove_class (context, "medium");
Adrien Plazas's avatar
Adrien Plazas committed
350
    gtk_style_context_remove_class (context, "large");
351

Adrien Plazas's avatar
Adrien Plazas committed
352
    return;
353
  }
Adrien Plazas's avatar
Adrien Plazas committed
354

Adrien Plazas's avatar
Adrien Plazas committed
355
356
357
358
  child_allocation = *allocation;
  hdy_css_size_allocate_children (widget, &child_allocation);
  base_child_allocation = child_allocation;

Adrien Plazas's avatar
Adrien Plazas committed
359
  if (self->orientation == GTK_ORIENTATION_HORIZONTAL) {
360
361
362
363
    child_allocation.width = child_size_from_clamp (self, child,
                                                    child_allocation.width,
                                                    &child_maximum,
                                                    &lower_threshold);
Adrien Plazas's avatar
Adrien Plazas committed
364
365

    child_clamped_size = child_allocation.width;
366
367
368
369
370
  } else {
    child_allocation.height = child_size_from_clamp (self, child,
                                                     child_allocation.height,
                                                     &child_maximum,
                                                     &lower_threshold);
Adrien Plazas's avatar
Adrien Plazas committed
371
372
373

    child_clamped_size = child_allocation.height;
  }
Adrien Plazas's avatar
Adrien Plazas committed
374

Adrien Plazas's avatar
Adrien Plazas committed
375
376
  if (child_clamped_size >= child_maximum) {
    gtk_style_context_remove_class (context, "small");
377
    gtk_style_context_remove_class (context, "medium");
Adrien Plazas's avatar
Adrien Plazas committed
378
379
380
    gtk_style_context_add_class (context, "large");
  } else if (child_clamped_size <= lower_threshold) {
    gtk_style_context_add_class (context, "small");
381
    gtk_style_context_remove_class (context, "medium");
Adrien Plazas's avatar
Adrien Plazas committed
382
    gtk_style_context_remove_class (context, "large");
383
  } else {
Adrien Plazas's avatar
Adrien Plazas committed
384
    gtk_style_context_remove_class (context, "small");
385
    gtk_style_context_add_class (context, "medium");
Adrien Plazas's avatar
Adrien Plazas committed
386
    gtk_style_context_remove_class (context, "large");
387
388
  }

389
  /* Always center the child on the side of the orientation. */
Adrien Plazas's avatar
Adrien Plazas committed
390
391
392
393
  if (self->orientation == GTK_ORIENTATION_HORIZONTAL)
    child_allocation.x += (base_child_allocation.width - child_allocation.width) / 2;
  else
    child_allocation.y += (base_child_allocation.height - child_allocation.height) / 2;
Adrien Plazas's avatar
Adrien Plazas committed
394
395
396
397
398
399

  baseline = gtk_widget_get_allocated_baseline (widget);
  gtk_widget_size_allocate_with_baseline (child, &child_allocation, baseline);
}

static void
Adrien Plazas's avatar
Adrien Plazas committed
400
hdy_clamp_class_init (HdyClampClass *klass)
Adrien Plazas's avatar
Adrien Plazas committed
401
402
403
404
405
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
  GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);

Adrien Plazas's avatar
Adrien Plazas committed
406
407
  object_class->get_property = hdy_clamp_get_property;
  object_class->set_property = hdy_clamp_set_property;
Adrien Plazas's avatar
Adrien Plazas committed
408

Adrien Plazas's avatar
Adrien Plazas committed
409
  widget_class->get_request_mode = hdy_clamp_get_request_mode;
Adrien Plazas's avatar
Adrien Plazas committed
410
  widget_class->get_preferred_width = hdy_clamp_get_preferred_width;
Adrien Plazas's avatar
Adrien Plazas committed
411
  widget_class->get_preferred_width_for_height = hdy_clamp_get_preferred_width_for_height;
Adrien Plazas's avatar
Adrien Plazas committed
412
  widget_class->get_preferred_height = hdy_clamp_get_preferred_height;
Adrien Plazas's avatar
Adrien Plazas committed
413
  widget_class->get_preferred_height_for_width = hdy_clamp_get_preferred_height_for_width;
Adrien Plazas's avatar
Adrien Plazas committed
414
415
  widget_class->get_preferred_height_and_baseline_for_width = hdy_clamp_get_preferred_height_and_baseline_for_width;
  widget_class->size_allocate = hdy_clamp_size_allocate;
Adrien Plazas's avatar
Adrien Plazas committed
416
  widget_class->draw = hdy_css_draw_bin;
Adrien Plazas's avatar
Adrien Plazas committed
417
418
419

  gtk_container_class_handle_border_width (container_class);

Adrien Plazas's avatar
Adrien Plazas committed
420
421
422
423
  g_object_class_override_property (object_class,
                                    PROP_ORIENTATION,
                                    "orientation");

Adrien Plazas's avatar
Adrien Plazas committed
424
  /**
425
   * HdyClamp:maximum-size: (attributes org.gtk.Property.get=hdy_clamp_get_maximum_size org.gtk.Property.set=hdy_clamp_set_maximum_size)
Adrien Plazas's avatar
Adrien Plazas committed
426
   *
427
428
429
430
   * The maximum size to allocate the children.
   *
   * It is the width if the clamp is horizontal, or the height if it is
   * vertical.
Adrien Plazas's avatar
Adrien Plazas committed
431
432
   *
   * Since: 1.0
Adrien Plazas's avatar
Adrien Plazas committed
433
   */
434
435
436
437
  props[PROP_MAXIMUM_SIZE] =
      g_param_spec_int ("maximum-size",
                        _("Maximum size"),
                        _("The maximum size allocated to the child"),
438
                        0, G_MAXINT, 600,
Adrien Plazas's avatar
Adrien Plazas committed
439
440
                        G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);

441
  /**
442
443
444
   * HdyClamp:tightening-threshold: (attributes org.gtk.Property.get=hdy_clamp_get_tightening_threshold org.gtk.Property.set=hdy_clamp_set_tightening_threshold)
   *
   * The size above which the child is clamped.
445
   *
446
   * Starting from this size, the layout will tighten its grip on the children,
447
   * slowly allocating less and less of the available size up to the maximum
448
449
   * allocated size. Below that threshold and below the maximum size, the
   * children will be allocated all the available size.
450
   *
451
452
453
454
   * If the threshold is greater than the maximum size to allocate to the
   * children, they will be allocated the whole size up to the maximum. If the
   * threshold is lower than the minimum size to allocate to the children, that
   * size will be used as the tightening threshold.
455
   *
456
   * Effectively, tightening the grip on a child before it reaches its maximum
457
   * size makes transitions to and from the maximum size smoother when resizing.
Adrien Plazas's avatar
Adrien Plazas committed
458
459
   *
   * Since: 1.0
460
   */
461
462
463
464
  props[PROP_TIGHTENING_THRESHOLD] =
      g_param_spec_int ("tightening-threshold",
                        _("Tightening threshold"),
                        _("The size from which the clamp will tighten its grip on the child"),
465
                        0, G_MAXINT, 400,
466
467
                        G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);

Adrien Plazas's avatar
Adrien Plazas committed
468
  g_object_class_install_properties (object_class, LAST_PROP, props);
Adrien Plazas's avatar
Adrien Plazas committed
469

Adrien Plazas's avatar
Adrien Plazas committed
470
  gtk_widget_class_set_css_name (widget_class, "clamp");
Adrien Plazas's avatar
Adrien Plazas committed
471
472
473
}

static void
Adrien Plazas's avatar
Adrien Plazas committed
474
hdy_clamp_init (HdyClamp *self)
Adrien Plazas's avatar
Adrien Plazas committed
475
{
476
477
  self->maximum_size = 600;
  self->tightening_threshold = 400;
Adrien Plazas's avatar
Adrien Plazas committed
478
479
480
}

/**
Adrien Plazas's avatar
Adrien Plazas committed
481
482
 * hdy_clamp_new:
 *
483
 * Creates a new `HdyClamp`.
Adrien Plazas's avatar
Adrien Plazas committed
484
 *
485
 * Returns: the newly created `HdyClamp`
Adrien Plazas's avatar
Adrien Plazas committed
486
 *
Adrien Plazas's avatar
Adrien Plazas committed
487
 * Since: 1.0
Adrien Plazas's avatar
Adrien Plazas committed
488
 */
Ujjwal Kumar's avatar
Ujjwal Kumar committed
489
GtkWidget *
Adrien Plazas's avatar
Adrien Plazas committed
490
hdy_clamp_new (void)
Adrien Plazas's avatar
Adrien Plazas committed
491
{
Adrien Plazas's avatar
Adrien Plazas committed
492
  return g_object_new (HDY_TYPE_CLAMP, NULL);
Adrien Plazas's avatar
Adrien Plazas committed
493
494
495
}

/**
496
497
 * hdy_clamp_get_maximum_size: (attributes org.gtk.Method.get_property=maximum-size)
 * @self: a clamp
Adrien Plazas's avatar
Adrien Plazas committed
498
 *
499
 * Gets the maximum size allocated to the children.
Adrien Plazas's avatar
Adrien Plazas committed
500
 *
501
 * Returns: the maximum size to allocate to the children
Adrien Plazas's avatar
Adrien Plazas committed
502
503
 *
 * Since: 1.0
Adrien Plazas's avatar
Adrien Plazas committed
504
505
 */
gint
506
hdy_clamp_get_maximum_size (HdyClamp *self)
Adrien Plazas's avatar
Adrien Plazas committed
507
{
Adrien Plazas's avatar
Adrien Plazas committed
508
  g_return_val_if_fail (HDY_IS_CLAMP (self), 0);
Adrien Plazas's avatar
Adrien Plazas committed
509

510
  return self->maximum_size;
Adrien Plazas's avatar
Adrien Plazas committed
511
512
513
}

/**
514
515
 * hdy_clamp_set_maximum_size: (attributes org.gtk.Method.set_property=maximum-size)
 * @self: a clamp
516
 * @maximum_size: the maximum size
Adrien Plazas's avatar
Adrien Plazas committed
517
 *
518
 * Sets the maximum size allocated to the children.
Adrien Plazas's avatar
Adrien Plazas committed
519
520
 *
 * Since: 1.0
Adrien Plazas's avatar
Adrien Plazas committed
521
522
 */
void
523
524
hdy_clamp_set_maximum_size (HdyClamp *self,
                            gint      maximum_size)
Adrien Plazas's avatar
Adrien Plazas committed
525
{
Adrien Plazas's avatar
Adrien Plazas committed
526
  g_return_if_fail (HDY_IS_CLAMP (self));
Adrien Plazas's avatar
Adrien Plazas committed
527

528
  if (self->maximum_size == maximum_size)
529
530
    return;

531
  self->maximum_size = maximum_size;
532
533

  gtk_widget_queue_resize (GTK_WIDGET (self));
534

535
  g_object_notify_by_pspec (G_OBJECT (self), props[PROP_MAXIMUM_SIZE]);
Adrien Plazas's avatar
Adrien Plazas committed
536
}
537
538

/**
539
540
 * hdy_clamp_get_tightening_threshold: (attributes org.gtk.Method.get_property=tightening-threshold)
 * @self: a clamp
541
 *
542
 * Gets the size above which the children are clamped.
543
 *
544
 * Returns: the size above which the children are clamped
Adrien Plazas's avatar
Adrien Plazas committed
545
546
 *
 * Since: 1.0
547
548
 */
gint
549
hdy_clamp_get_tightening_threshold (HdyClamp *self)
550
{
Adrien Plazas's avatar
Adrien Plazas committed
551
  g_return_val_if_fail (HDY_IS_CLAMP (self), 0);
552

553
  return self->tightening_threshold;
554
555
556
}

/**
557
558
 * hdy_clamp_set_tightening_threshold: (attributes org.gtk.Method.set_property=tightening-threshold)
 * @self: a clamp
559
 * @tightening_threshold: the tightening threshold
560
 *
561
 * Sets the size above which the children are clamped.
562
 *
Adrien Plazas's avatar
Adrien Plazas committed
563
 * Since: 1.0
564
565
 */
void
566
567
hdy_clamp_set_tightening_threshold (HdyClamp *self,
                                    gint      tightening_threshold)
568
{
Adrien Plazas's avatar
Adrien Plazas committed
569
  g_return_if_fail (HDY_IS_CLAMP (self));
570

571
  if (self->tightening_threshold == tightening_threshold)
572
573
    return;

574
  self->tightening_threshold = tightening_threshold;
575
576

  gtk_widget_queue_resize (GTK_WIDGET (self));
577

578
  g_object_notify_by_pspec (G_OBJECT (self), props[PROP_TIGHTENING_THRESHOLD]);
579
}