~ubuntu-branches/debian/sid/cheese/sid

« back to all changes in this revision

Viewing changes to libcheese/cheese-aspect-frame.c

  • Committer: Bazaar Package Importer
  • Author(s): Laurent Bigonville
  • Date: 2011-07-17 21:04:16 UTC
  • mfrom: (15.1.1 experimental)
  • Revision ID: james.westby@ubuntu.com-20110717210416-nt5qi659qei7a2yy
Tags: 3.0.1-2
* debian/control.in:
  - Change gir1.2-cheese-3.0 Section to libs
  - Make library packages depend against cheese-common package
  - Make cheese package recommends against hicolor-icon-theme
  - Move gst Dependency to libcheese package
* debian/patches/0002-fix-linking.patch: Add missing library to fix linking
* debian/watch:
  - Switch to .bz2 tarballs.
  - Bump version to 3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 
2
/*
 
3
 * mx-aspect-frame.c: A container that respect the aspect ratio of its child
 
4
 *
 
5
 * Copyright 2010, 2011 Intel Corporation.
 
6
 *
 
7
 * This program is free software; you can redistribute it and/or modify it
 
8
 * under the terms and conditions of the GNU Lesser General Public License,
 
9
 * version 2.1, as published by the Free Software Foundation.
 
10
 *
 
11
 * This program is distributed in the hope it will be useful, but WITHOUT ANY
 
12
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 
13
 * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
 
14
 * more details.
 
15
 *
 
16
 * You should have received a copy of the GNU Lesser General Public License
 
17
 * along with this program; if not, write to the Free Software Foundation,
 
18
 * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
 
19
 * Boston, MA 02111-1307, USA.
 
20
 */
 
21
 
 
22
#include "cheese-aspect-frame.h"
 
23
 
 
24
G_DEFINE_TYPE (CheeseAspectFrame, cheese_aspect_frame, MX_TYPE_BIN)
 
25
 
 
26
#define ASPECT_FRAME_PRIVATE(o)                         \
 
27
  (G_TYPE_INSTANCE_GET_PRIVATE ((o),                    \
 
28
                                CHEESE_TYPE_ASPECT_FRAME,   \
 
29
                                CheeseAspectFramePrivate))
 
30
 
 
31
enum
 
32
{
 
33
  PROP_0,
 
34
 
 
35
  PROP_EXPAND,
 
36
  PROP_RATIO
 
37
};
 
38
 
 
39
struct _CheeseAspectFramePrivate
 
40
{
 
41
  guint expand : 1;
 
42
 
 
43
  gfloat ratio;
 
44
};
 
45
 
 
46
 
 
47
static void
 
48
cheese_aspect_frame_get_property (GObject    *object,
 
49
                               guint       property_id,
 
50
                               GValue     *value,
 
51
                               GParamSpec *pspec)
 
52
{
 
53
  CheeseAspectFrame *frame = CHEESE_ASPECT_FRAME (object);
 
54
 
 
55
  switch (property_id)
 
56
    {
 
57
    case PROP_EXPAND:
 
58
      g_value_set_boolean (value, cheese_aspect_frame_get_expand (frame));
 
59
      break;
 
60
 
 
61
    case PROP_RATIO:
 
62
      g_value_set_float (value, cheese_aspect_frame_get_ratio (frame));
 
63
      break;
 
64
 
 
65
    default:
 
66
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 
67
    }
 
68
}
 
69
 
 
70
static void
 
71
cheese_aspect_frame_set_property (GObject      *object,
 
72
                               guint         property_id,
 
73
                               const GValue *value,
 
74
                               GParamSpec   *pspec)
 
75
{
 
76
  switch (property_id)
 
77
    {
 
78
    case PROP_EXPAND:
 
79
      cheese_aspect_frame_set_expand (CHEESE_ASPECT_FRAME (object),
 
80
                                   g_value_get_boolean (value));
 
81
      break;
 
82
 
 
83
    case PROP_RATIO:
 
84
      cheese_aspect_frame_set_ratio (CHEESE_ASPECT_FRAME (object),
 
85
                                  g_value_get_float (value));
 
86
      break;
 
87
 
 
88
    default:
 
89
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 
90
    }
 
91
}
 
92
 
 
93
static void
 
94
cheese_aspect_frame_dispose (GObject *object)
 
95
{
 
96
  G_OBJECT_CLASS (cheese_aspect_frame_parent_class)->dispose (object);
 
97
}
 
98
 
 
99
static void
 
100
cheese_aspect_frame_finalize (GObject *object)
 
101
{
 
102
  G_OBJECT_CLASS (cheese_aspect_frame_parent_class)->finalize (object);
 
103
}
 
104
 
 
105
static void
 
106
cheese_aspect_frame_get_preferred_width (ClutterActor *actor,
 
107
                                      gfloat        for_height,
 
108
                                      gfloat       *min_width_p,
 
109
                                      gfloat       *nat_width_p)
 
110
{
 
111
  gboolean override;
 
112
  MxPadding padding;
 
113
 
 
114
  mx_widget_get_padding (MX_WIDGET (actor), &padding);
 
115
  if (for_height >= 0)
 
116
    for_height = MAX (0, for_height - padding.top - padding.bottom);
 
117
 
 
118
  if (for_height >= 0)
 
119
    override = FALSE;
 
120
  else
 
121
    g_object_get (G_OBJECT (actor), "natural-height-set", &override, NULL);
 
122
 
 
123
  if (override)
 
124
    g_object_get (G_OBJECT (actor), "natural-height", &for_height, NULL);
 
125
 
 
126
  CLUTTER_ACTOR_CLASS (cheese_aspect_frame_parent_class)->
 
127
    get_preferred_width (actor, for_height, min_width_p, nat_width_p);
 
128
 
 
129
  if (min_width_p)
 
130
    *min_width_p += padding.left + padding.right;
 
131
  if (nat_width_p)
 
132
    *nat_width_p += padding.left + padding.right;
 
133
}
 
134
 
 
135
static void
 
136
cheese_aspect_frame_get_preferred_height (ClutterActor *actor,
 
137
                                       gfloat        for_width,
 
138
                                       gfloat       *min_height_p,
 
139
                                       gfloat       *nat_height_p)
 
140
{
 
141
  gboolean override;
 
142
  MxPadding padding;
 
143
 
 
144
  mx_widget_get_padding (MX_WIDGET (actor), &padding);
 
145
  if (for_width >= 0)
 
146
    for_width = MAX (0, for_width - padding.left - padding.right);
 
147
 
 
148
  if (for_width >= 0)
 
149
    override = FALSE;
 
150
  else
 
151
    g_object_get (G_OBJECT (actor), "natural-width-set", &override, NULL);
 
152
 
 
153
  if (override)
 
154
    g_object_get (G_OBJECT (actor), "natural-width", &for_width, NULL);
 
155
 
 
156
  CLUTTER_ACTOR_CLASS (cheese_aspect_frame_parent_class)->
 
157
    get_preferred_height (actor, for_width, min_height_p, nat_height_p);
 
158
}
 
159
 
 
160
static void
 
161
cheese_aspect_frame_allocate (ClutterActor           *actor,
 
162
                           const ClutterActorBox  *box,
 
163
                           ClutterAllocationFlags  flags)
 
164
{
 
165
  MxPadding padding;
 
166
  ClutterActor *child;
 
167
  ClutterActorBox child_box;
 
168
  gfloat aspect, child_aspect, width, height, box_width, box_height;
 
169
 
 
170
  CheeseAspectFramePrivate *priv = CHEESE_ASPECT_FRAME (actor)->priv;
 
171
 
 
172
  CLUTTER_ACTOR_CLASS (cheese_aspect_frame_parent_class)->
 
173
    allocate (actor, box, flags);
 
174
 
 
175
  child = mx_bin_get_child (MX_BIN (actor));
 
176
  if (!child)
 
177
    return;
 
178
 
 
179
  mx_widget_get_padding (MX_WIDGET (actor), &padding);
 
180
 
 
181
  box_width = box->x2 - box->x1 - padding.left - padding.right;
 
182
  box_height = box->y2 - box->y1 - padding.top - padding.bottom;
 
183
  clutter_actor_get_preferred_size (child, NULL, NULL, &width, &height);
 
184
 
 
185
  aspect = box_width / box_height;
 
186
  if (priv->ratio >= 0.f)
 
187
    child_aspect = priv->ratio;
 
188
  else
 
189
    child_aspect = width / height;
 
190
 
 
191
  if ((aspect < child_aspect) ^ priv->expand)
 
192
    {
 
193
      width = box_width;
 
194
      height = box_width / child_aspect;
 
195
    }
 
196
  else
 
197
    {
 
198
      height = box_height;
 
199
      width = box_height * child_aspect;
 
200
    }
 
201
 
 
202
  child_box.x1 = (box_width - width) / 2 + padding.left;
 
203
  child_box.y1 = (box_height - height) / 2 + padding.top;
 
204
  child_box.x2 = child_box.x1 + width;
 
205
  child_box.y2 = child_box.y1 + height;
 
206
 
 
207
  clutter_actor_allocate (child, &child_box, flags);
 
208
}
 
209
 
 
210
static void
 
211
cheese_aspect_frame_paint (ClutterActor *actor)
 
212
{
 
213
  ClutterActor *child = mx_bin_get_child (MX_BIN (actor));
 
214
  CheeseAspectFramePrivate *priv = CHEESE_ASPECT_FRAME (actor)->priv;
 
215
 
 
216
  if (!child)
 
217
    return;
 
218
 
 
219
  if (priv->expand)
 
220
    {
 
221
      MxPadding padding;
 
222
      gfloat width, height;
 
223
 
 
224
      clutter_actor_get_size (actor, &width, &height);
 
225
      mx_widget_get_padding (MX_WIDGET (actor), &padding);
 
226
 
 
227
      /* Special-case textures and just munge their coordinates.
 
228
       * This avoids clipping, which can break Clutter's batching.
 
229
       */
 
230
      if (CLUTTER_IS_TEXTURE (child))
 
231
        {
 
232
          guint8 opacity;
 
233
          gfloat x, y, tx, ty;
 
234
          CoglHandle material;
 
235
 
 
236
          clutter_actor_get_position (child, &x, &y);
 
237
 
 
238
          material =
 
239
            clutter_texture_get_cogl_material (CLUTTER_TEXTURE (child));
 
240
          opacity = clutter_actor_get_paint_opacity (child);
 
241
          cogl_material_set_color4ub (material,
 
242
                                      opacity, opacity, opacity, opacity);
 
243
          cogl_set_source (material);
 
244
 
 
245
          x -= padding.left;
 
246
          y -= padding.top;
 
247
          width -= padding.left + padding.right;
 
248
          height -= padding.top + padding.bottom;
 
249
 
 
250
          tx = (width / (width - (x * 2.f))) / 2.f;
 
251
          ty = (height / (height - (y * 2.f))) / 2.f;
 
252
 
 
253
          cogl_rectangle_with_texture_coords (padding.left, padding.top,
 
254
                                              padding.left + width,
 
255
                                              padding.top + height,
 
256
                                              0.5f - tx, 0.5f - ty,
 
257
                                              0.5f + tx, 0.5f + ty);
 
258
        }
 
259
      else
 
260
        {
 
261
          cogl_clip_push_rectangle (padding.left, padding.top,
 
262
                                    padding.left + width, padding.top + height);
 
263
          clutter_actor_paint (child);
 
264
          cogl_clip_pop ();
 
265
        }
 
266
    }
 
267
  else
 
268
    clutter_actor_paint (child);
 
269
}
 
270
 
 
271
static void
 
272
cheese_aspect_frame_pick (ClutterActor       *actor,
 
273
                       const ClutterColor *color)
 
274
{
 
275
  ClutterActorBox box;
 
276
 
 
277
  ClutterActor *child = mx_bin_get_child (MX_BIN (actor));
 
278
  CheeseAspectFramePrivate *priv = CHEESE_ASPECT_FRAME (actor)->priv;
 
279
 
 
280
  clutter_actor_get_allocation_box (actor, &box);
 
281
 
 
282
  cogl_set_source_color4ub (color->red, color->green,
 
283
                            color->blue, color->alpha);
 
284
  cogl_rectangle (box.x1, box.y1, box.x2, box.y2);
 
285
 
 
286
  if (!child)
 
287
    return;
 
288
 
 
289
  if (priv->expand)
 
290
    {
 
291
      MxPadding padding;
 
292
      mx_widget_get_padding (MX_WIDGET (actor), &padding);
 
293
 
 
294
      cogl_clip_push_rectangle (padding.left, padding.top,
 
295
                                padding.left + (box.x2 - box.x1),
 
296
                                padding.top + (box.y2 - box.y1));
 
297
      clutter_actor_paint (child);
 
298
      cogl_clip_pop ();
 
299
    }
 
300
  else
 
301
    clutter_actor_paint (child);
 
302
}
 
303
 
 
304
static void
 
305
cheese_aspect_frame_class_init (CheeseAspectFrameClass *klass)
 
306
{
 
307
  GParamSpec *pspec;
 
308
 
 
309
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
310
  ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
 
311
 
 
312
  g_type_class_add_private (klass, sizeof (CheeseAspectFramePrivate));
 
313
 
 
314
  object_class->get_property = cheese_aspect_frame_get_property;
 
315
  object_class->set_property = cheese_aspect_frame_set_property;
 
316
  object_class->dispose = cheese_aspect_frame_dispose;
 
317
  object_class->finalize = cheese_aspect_frame_finalize;
 
318
 
 
319
  actor_class->get_preferred_width = cheese_aspect_frame_get_preferred_width;
 
320
  actor_class->get_preferred_height = cheese_aspect_frame_get_preferred_height;
 
321
  actor_class->allocate = cheese_aspect_frame_allocate;
 
322
  actor_class->paint = cheese_aspect_frame_paint;
 
323
  actor_class->pick = cheese_aspect_frame_pick;
 
324
 
 
325
  pspec = g_param_spec_boolean ("expand",
 
326
                                "Expand",
 
327
                                "Fill the allocated area with the child and "
 
328
                                "clip off the excess.",
 
329
                                FALSE,
 
330
                                G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
 
331
  g_object_class_install_property (object_class, PROP_EXPAND, pspec);
 
332
 
 
333
  pspec = g_param_spec_float ("ratio",
 
334
                              "Ratio",
 
335
                              "Override the child's aspect ratio "
 
336
                              "(width/height).",
 
337
                              -1.f, G_MAXFLOAT, -1.f,
 
338
                              G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
 
339
  g_object_class_install_property (object_class, PROP_RATIO, pspec);
 
340
}
 
341
 
 
342
static void
 
343
cheese_aspect_frame_init (CheeseAspectFrame *self)
 
344
{
 
345
  CheeseAspectFramePrivate *priv = self->priv = ASPECT_FRAME_PRIVATE (self);
 
346
  priv->ratio = -1.f;
 
347
}
 
348
 
 
349
ClutterActor *
 
350
cheese_aspect_frame_new (void)
 
351
{
 
352
  return g_object_new (CHEESE_TYPE_ASPECT_FRAME, NULL);
 
353
}
 
354
 
 
355
void
 
356
cheese_aspect_frame_set_expand (CheeseAspectFrame *frame, gboolean expand)
 
357
{
 
358
  CheeseAspectFramePrivate *priv;
 
359
 
 
360
  g_return_if_fail (CHEESE_IS_ASPECT_FRAME (frame));
 
361
 
 
362
  priv = frame->priv;
 
363
  if (priv->expand != expand)
 
364
    {
 
365
      priv->expand = expand;
 
366
      clutter_actor_queue_relayout (CLUTTER_ACTOR (frame));
 
367
      g_object_notify (G_OBJECT (frame), "expand");
 
368
    }
 
369
}
 
370
 
 
371
gboolean
 
372
cheese_aspect_frame_get_expand (CheeseAspectFrame *frame)
 
373
{
 
374
  g_return_val_if_fail (CHEESE_IS_ASPECT_FRAME (frame), FALSE);
 
375
  return frame->priv->expand;
 
376
}
 
377
 
 
378
void
 
379
cheese_aspect_frame_set_ratio (CheeseAspectFrame *frame, gfloat ratio)
 
380
{
 
381
  CheeseAspectFramePrivate *priv;
 
382
 
 
383
  g_return_if_fail (CHEESE_IS_ASPECT_FRAME (frame));
 
384
 
 
385
  priv = frame->priv;
 
386
  if (priv->ratio != ratio)
 
387
    {
 
388
      priv->ratio = ratio;
 
389
      clutter_actor_queue_relayout (CLUTTER_ACTOR (frame));
 
390
      g_object_notify (G_OBJECT (frame), "ratio");
 
391
    }
 
392
}
 
393
 
 
394
gfloat
 
395
cheese_aspect_frame_get_ratio (CheeseAspectFrame *frame)
 
396
{
 
397
  g_return_val_if_fail (CHEESE_IS_ASPECT_FRAME (frame), -1.f);
 
398
  return frame->priv->ratio;
 
399
}