~ubuntu-branches/ubuntu/precise/cheese/precise-proposed

« back to all changes in this revision

Viewing changes to libcheese/um-crop-area.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher, Jeremy Bicha, Robert Ancell
  • Date: 2011-06-10 11:45:37 UTC
  • mfrom: (1.2.24 upstream)
  • Revision ID: james.westby@ubuntu.com-20110610114537-p9e4zl8m0ehf2b5a
Tags: 3.0.0-0ubuntu1
* Upload to oneiric

[ Jeremy Bicha ]
* Depend on gnome-video-effects since clicking Effects when it is
  not installed results in a segmentation fault.

[ Robert Ancell]
* New upstream version
* debian/control:
  - Use standards version 3.9.1
  - Add build-depends on dh-autoreconf, valac, libclutter-1.0-dev,
    libclutter-gtk-1.0-dev, libclutter-gst-dev, libmx-dev,
    gnome-video-effects-dev, libgee-dev, gnome-common, gobject-introspection, 
    libgirepository1.0-dev, gir1.2-freedesktop, gir1.2-glib-2.0, 
    gir1.2-gstreamer-0.10, gir1.2-clutter-1.0, gir1.2-gdkpixbuf-2.0
  - Drop build-depends on libgconf2-dev, libdbus-1-dev, libdbus-glib-1-dev,
  - Bump build-depends on libglib2.0-dev, libgtk-3-dev,
    libgnome-desktop-3-dev, libgstreamer0.10-dev,
    libgstreamer-plugins-base0.10-dev, libcairo2-dev, libpango1.0-dev,
    librsvg2-dev, libcanberra-gtk3-dev
  - Add new gir1.2-cheese-3.0 package
  - libcheese-gtk18 -> libcheese-gtk19
* debian/cheese.install:
* debian/cheese-common.install:
* debian/libcheese-gtk-dev.install
  - Update for new/changed files
* debian/gir1.2-cheese-3.0.install:
  - Install typelib
* debian/patches/fix-linking.patch:
  - Fix linking issues
* debian/patches/no-gnu-gettext.patch:
  - Don't use both AM_GNU_GETTEXT and IT_PROG_INTLTOOL

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
 * Written by: Matthias Clasen <mclasen@redhat.com>
20
20
 */
21
21
 
 
22
#include "cheese-config.h"
 
23
 
22
24
#include <stdlib.h>
23
25
 
24
26
#include <glib.h>
28
30
#include "um-crop-area.h"
29
31
 
30
32
struct _UmCropAreaPrivate {
31
 
        GdkPixbuf *browse_pixbuf;
32
 
        GdkPixbuf *pixbuf;
33
 
        GdkPixbuf *color_shifted;
34
 
        gdouble scale;
35
 
        GdkRectangle image;
36
 
        GdkCursorType current_cursor;
37
 
        GdkRectangle crop;
38
 
        gint active_region;
39
 
        gint last_press_x;
40
 
        gint last_press_y;
 
33
        GdkPixbuf *browse_pixbuf;
 
34
        GdkPixbuf *pixbuf;
 
35
        GdkPixbuf *color_shifted;
 
36
        gdouble scale;
 
37
        GdkRectangle image;
 
38
        GdkCursorType current_cursor;
 
39
        GdkRectangle crop;
 
40
        gint active_region;
 
41
        gint last_press_x;
 
42
        gint last_press_y;
 
43
        gint base_width;
 
44
        gint base_height;
 
45
        gdouble aspect;
41
46
};
42
47
 
43
48
G_DEFINE_TYPE (UmCropArea, um_crop_area, GTK_TYPE_DRAWING_AREA);
46
51
shift_color_byte (guchar b,
47
52
                  int    shift)
48
53
{
49
 
        return CLAMP(b + shift, 0, 255);
 
54
        return CLAMP(b + shift, 0, 255);
50
55
}
51
56
 
52
57
static void
53
58
shift_colors (GdkPixbuf *pixbuf,
54
 
              gint       red,
55
 
              gint       green,
56
 
              gint       blue,
57
 
              gint       alpha)
 
59
              gint       red,
 
60
              gint       green,
 
61
              gint       blue,
 
62
              gint       alpha)
58
63
{
59
 
        gint x, y, offset, y_offset, rowstride, width, height;
60
 
        guchar *pixels;
61
 
        gint channels;
62
 
 
63
 
        width = gdk_pixbuf_get_width (pixbuf);
64
 
        height = gdk_pixbuf_get_height (pixbuf);
65
 
        rowstride = gdk_pixbuf_get_rowstride (pixbuf);
66
 
        pixels = gdk_pixbuf_get_pixels (pixbuf);
67
 
        channels = gdk_pixbuf_get_n_channels (pixbuf);
68
 
 
69
 
        for (y = 0; y < height; y++) {
70
 
                y_offset = y * rowstride;
71
 
                for (x = 0; x < width; x++) {
72
 
                        offset = y_offset + x * channels;
73
 
                        if (red != 0)
74
 
                                pixels[offset] = shift_color_byte (pixels[offset], red);
75
 
                        if (green != 0)
76
 
                                pixels[offset + 1] = shift_color_byte (pixels[offset + 1], green);
77
 
                        if (blue != 0)
78
 
                                pixels[offset + 2] = shift_color_byte (pixels[offset + 2], blue);
79
 
                        if (alpha != 0 && channels >= 4)
80
 
                                pixels[offset + 3] = shift_color_byte (pixels[offset + 3], blue);
81
 
                }
82
 
        }
 
64
        gint x, y, offset, y_offset, rowstride, width, height;
 
65
        guchar *pixels;
 
66
        gint channels;
 
67
 
 
68
        width = gdk_pixbuf_get_width (pixbuf);
 
69
        height = gdk_pixbuf_get_height (pixbuf);
 
70
        rowstride = gdk_pixbuf_get_rowstride (pixbuf);
 
71
        pixels = gdk_pixbuf_get_pixels (pixbuf);
 
72
        channels = gdk_pixbuf_get_n_channels (pixbuf);
 
73
 
 
74
        for (y = 0; y < height; y++) {
 
75
                y_offset = y * rowstride;
 
76
                for (x = 0; x < width; x++) {
 
77
                        offset = y_offset + x * channels;
 
78
                        if (red != 0)
 
79
                                pixels[offset] = shift_color_byte (pixels[offset], red);
 
80
                        if (green != 0)
 
81
                                pixels[offset + 1] = shift_color_byte (pixels[offset + 1], green);
 
82
                        if (blue != 0)
 
83
                                pixels[offset + 2] = shift_color_byte (pixels[offset + 2], blue);
 
84
                        if (alpha != 0 && channels >= 4)
 
85
                                pixels[offset + 3] = shift_color_byte (pixels[offset + 3], blue);
 
86
                }
 
87
        }
83
88
}
84
89
 
85
90
static void
86
91
update_pixbufs (UmCropArea *area)
87
92
{
88
 
        GtkAllocation allocation;
89
 
        GtkStyle *style;
90
 
        GtkWidget *widget;
91
 
        GdkColor *color;
92
 
        gdouble scale;
93
 
        gint width;
94
 
        gint height;
95
 
        gint dest_x, dest_y, dest_width, dest_height;
96
 
        guint32 pixel;
97
 
 
98
 
        widget = GTK_WIDGET (area);
99
 
        gtk_widget_get_allocation (widget, &allocation);
100
 
 
101
 
        if (area->priv->pixbuf == NULL ||
102
 
            gdk_pixbuf_get_width (area->priv->pixbuf) != allocation.width ||
103
 
            gdk_pixbuf_get_height (area->priv->pixbuf) != allocation.height) {
104
 
                if (area->priv->pixbuf != NULL)
105
 
                        g_object_unref (area->priv->pixbuf);
106
 
                area->priv->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8,
107
 
                                             allocation.width, allocation.height);
108
 
 
109
 
                style = gtk_widget_get_style (widget);
110
 
                color = &style->bg[gtk_widget_get_state (widget)];
111
 
                pixel = ((color->red & 0xff00) << 16) |
112
 
                        ((color->green & 0xff00) << 8) |
113
 
                         (color->blue & 0xff00);
114
 
                gdk_pixbuf_fill (area->priv->pixbuf, pixel);
115
 
 
116
 
                width = gdk_pixbuf_get_width (area->priv->browse_pixbuf);
117
 
                height = gdk_pixbuf_get_height (area->priv->browse_pixbuf);
118
 
 
119
 
                scale = allocation.height / (gdouble)height;
120
 
                if (scale * width > allocation.width)
121
 
                    scale = allocation.width / (gdouble)width;
122
 
 
123
 
                dest_width = width * scale;
124
 
                dest_height = height * scale;
125
 
                dest_x = (allocation.width - dest_width) / 2;
126
 
                dest_y = (allocation.height - dest_height) / 2,
127
 
 
128
 
                gdk_pixbuf_scale (area->priv->browse_pixbuf,
129
 
                                  area->priv->pixbuf,
130
 
                                  dest_x, dest_y,
131
 
                                  dest_width, dest_height,
132
 
                                  dest_x, dest_y,
133
 
                                  scale, scale,
134
 
                                  GDK_INTERP_BILINEAR);
135
 
 
136
 
                if (area->priv->color_shifted)
137
 
                        g_object_unref (area->priv->color_shifted);
138
 
                area->priv->color_shifted = gdk_pixbuf_copy (area->priv->pixbuf);
139
 
                shift_colors (area->priv->color_shifted, -32, -32, -32, 0);
140
 
 
141
 
                if (area->priv->scale == 0.0) {
142
 
                        area->priv->crop.width = 96.0 / scale;
143
 
                        area->priv->crop.height = 96.0 / scale;
144
 
                        area->priv->crop.x = (gdk_pixbuf_get_width (area->priv->browse_pixbuf) - area->priv->crop.width) / 2;
145
 
                        area->priv->crop.y = (gdk_pixbuf_get_height (area->priv->browse_pixbuf) - area->priv->crop.height) / 2;
146
 
                }
147
 
 
148
 
                area->priv->scale = scale;
149
 
                area->priv->image.x = dest_x;
150
 
                area->priv->image.y = dest_y;
151
 
                area->priv->image.width = dest_width;
152
 
                area->priv->image.height = dest_height;
153
 
        }
 
93
        gint width;
 
94
        gint height;
 
95
        GtkAllocation allocation;
 
96
        gdouble scale;
 
97
        GdkRGBA color;
 
98
        guint32 pixel;
 
99
        gint dest_x, dest_y, dest_width, dest_height;
 
100
        GtkWidget *widget;
 
101
        GtkStyleContext *context;
 
102
 
 
103
        widget = GTK_WIDGET (area);
 
104
        gtk_widget_get_allocation (widget, &allocation);
 
105
        context = gtk_widget_get_style_context (widget);
 
106
 
 
107
        if (area->priv->pixbuf == NULL ||
 
108
            gdk_pixbuf_get_width (area->priv->pixbuf) != allocation.width ||
 
109
            gdk_pixbuf_get_height (area->priv->pixbuf) != allocation.height) {
 
110
                if (area->priv->pixbuf != NULL)
 
111
                        g_object_unref (area->priv->pixbuf);
 
112
                area->priv->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
 
113
                                                     gdk_pixbuf_get_has_alpha (area->priv->browse_pixbuf),
 
114
                                                     8,
 
115
                                                     allocation.width, allocation.height);
 
116
 
 
117
                gtk_style_context_get_background_color (context, gtk_style_context_get_state (context), &color);
 
118
                pixel = (((gint)(color.red * 1.0)) << 16) |
 
119
                        (((gint)(color.green * 1.0)) << 8) |
 
120
                         ((gint)(color.blue * 1.0));
 
121
                gdk_pixbuf_fill (area->priv->pixbuf, pixel);
 
122
 
 
123
                width = gdk_pixbuf_get_width (area->priv->browse_pixbuf);
 
124
                height = gdk_pixbuf_get_height (area->priv->browse_pixbuf);
 
125
 
 
126
                scale = allocation.height / (gdouble)height;
 
127
                if (scale * width > allocation.width)
 
128
                    scale = allocation.width / (gdouble)width;
 
129
 
 
130
                dest_width = width * scale;
 
131
                dest_height = height * scale;
 
132
                dest_x = (allocation.width - dest_width) / 2;
 
133
                dest_y = (allocation.height - dest_height) / 2,
 
134
 
 
135
                gdk_pixbuf_scale (area->priv->browse_pixbuf,
 
136
                                  area->priv->pixbuf,
 
137
                                  dest_x, dest_y,
 
138
                                  dest_width, dest_height,
 
139
                                  dest_x, dest_y,
 
140
                                  scale, scale,
 
141
                                  GDK_INTERP_BILINEAR);
 
142
 
 
143
                if (area->priv->color_shifted)
 
144
                        g_object_unref (area->priv->color_shifted);
 
145
                area->priv->color_shifted = gdk_pixbuf_copy (area->priv->pixbuf);
 
146
                shift_colors (area->priv->color_shifted, -32, -32, -32, 0);
 
147
 
 
148
                if (area->priv->scale == 0.0) {
 
149
                        area->priv->crop.width = 2 * area->priv->base_width / scale;
 
150
                        area->priv->crop.height = 2 * area->priv->base_height / scale;
 
151
                        area->priv->crop.x = (gdk_pixbuf_get_width (area->priv->browse_pixbuf) - area->priv->crop.width) / 2;
 
152
                        area->priv->crop.y = (gdk_pixbuf_get_height (area->priv->browse_pixbuf) - area->priv->crop.height) / 2;
 
153
                }
 
154
 
 
155
                area->priv->scale = scale;
 
156
                area->priv->image.x = dest_x;
 
157
                area->priv->image.y = dest_y;
 
158
                area->priv->image.width = dest_width;
 
159
                area->priv->image.height = dest_height;
 
160
        }
154
161
}
155
162
 
156
163
static void
157
164
crop_to_widget (UmCropArea    *area,
158
165
                GdkRectangle  *crop)
159
166
{
160
 
        crop->x = area->priv->image.x + area->priv->crop.x * area->priv->scale;
161
 
        crop->y = area->priv->image.y + area->priv->crop.y * area->priv->scale;
162
 
        crop->width = area->priv->crop.width * area->priv->scale;
163
 
        crop->height = area->priv->crop.height * area->priv->scale;
 
167
        crop->x = area->priv->image.x + area->priv->crop.x * area->priv->scale;
 
168
        crop->y = area->priv->image.y + area->priv->crop.y * area->priv->scale;
 
169
        crop->width = area->priv->crop.width * area->priv->scale;
 
170
        crop->height = area->priv->crop.height * area->priv->scale;
164
171
}
165
172
 
166
173
typedef enum {
167
 
        OUTSIDE,
168
 
        INSIDE,
169
 
        TOP,
170
 
        TOP_LEFT,
171
 
        TOP_RIGHT,
172
 
        BOTTOM,
173
 
        BOTTOM_LEFT,
174
 
        BOTTOM_RIGHT,
175
 
        LEFT,
176
 
        RIGHT
 
174
        OUTSIDE,
 
175
        INSIDE,
 
176
        TOP,
 
177
        TOP_LEFT,
 
178
        TOP_RIGHT,
 
179
        BOTTOM,
 
180
        BOTTOM_LEFT,
 
181
        BOTTOM_RIGHT,
 
182
        LEFT,
 
183
        RIGHT
177
184
} Location;
178
185
 
179
186
static gboolean
180
 
um_crop_area_expose (GtkWidget      *widget,
181
 
                     GdkEventExpose *event)
 
187
um_crop_area_draw (GtkWidget *widget,
 
188
                   cairo_t   *cr)
182
189
{
183
 
        GtkStateType state;
184
 
        GtkStyle *style;
185
 
        cairo_t *cr;
186
 
        GdkRectangle area;
187
 
        GdkRectangle crop;
188
 
        GdkWindow *window;
189
 
        gint width, height;
190
 
        UmCropArea *uarea = UM_CROP_AREA (widget);
191
 
 
192
 
        if (uarea->priv->browse_pixbuf == NULL)
193
 
                return FALSE;
194
 
 
195
 
        update_pixbufs (uarea);
196
 
 
197
 
        window = gtk_widget_get_window (widget);
198
 
        style = gtk_widget_get_style (widget);
199
 
        state = gtk_widget_get_state (widget);
200
 
 
201
 
        width = gdk_pixbuf_get_width (uarea->priv->pixbuf);
202
 
        height = gdk_pixbuf_get_height (uarea->priv->pixbuf);
203
 
        crop_to_widget (uarea, &crop);
204
 
 
205
 
        area.x = 0;
206
 
        area.y = 0;
207
 
        area.width = width;
208
 
        area.height = crop.y;
209
 
        gdk_rectangle_intersect (&area, &event->area, &area);
210
 
        gdk_draw_pixbuf (window,
211
 
                         style->fg_gc[state],
212
 
                         uarea->priv->color_shifted,
213
 
                         area.x, area.y,
214
 
                         area.x, area.y,
215
 
                         area.width, area.height,
216
 
                         GDK_RGB_DITHER_NONE, 0, 0);
217
 
 
218
 
        area.x = 0;
219
 
        area.y = crop.y;
220
 
        area.width = crop.x;
221
 
        area.height = crop.height;
222
 
        gdk_rectangle_intersect (&area, &event->area, &area);
223
 
        gdk_draw_pixbuf (window,
224
 
                         style->fg_gc[state],
225
 
                         uarea->priv->color_shifted,
226
 
                         area.x, area.y,
227
 
                         area.x, area.y,
228
 
                         area.width, area.height,
229
 
                         GDK_RGB_DITHER_NONE, 0, 0);
230
 
 
231
 
        area.x = crop.x;
232
 
        area.y = crop.y;
233
 
        area.width = crop.width;
234
 
        area.height = crop.height;
235
 
        gdk_rectangle_intersect (&area, &event->area, &area);
236
 
        gdk_draw_pixbuf (window,
237
 
                         style->fg_gc[state],
238
 
                         uarea->priv->pixbuf,
239
 
                         area.x, area.y,
240
 
                         area.x, area.y,
241
 
                         area.width, area.height,
242
 
                         GDK_RGB_DITHER_NONE, 0, 0);
243
 
 
244
 
        area.x = crop.x + crop.width;
245
 
        area.y = crop.y;
246
 
        area.width = width - area.x;
247
 
        area.height = crop.height;
248
 
        gdk_rectangle_intersect (&area, &event->area, &area);
249
 
        gdk_draw_pixbuf (window,
250
 
                         style->fg_gc[state],
251
 
                         uarea->priv->color_shifted,
252
 
                         area.x, area.y,
253
 
                         area.x, area.y,
254
 
                         area.width, area.height,
255
 
                         GDK_RGB_DITHER_NONE, 0, 0);
256
 
 
257
 
        area.x = 0;
258
 
        area.y = crop.y + crop.width;
259
 
        area.width = width;
260
 
        area.height = height - area.y;
261
 
        gdk_rectangle_intersect (&area, &event->area, &area);
262
 
        gdk_draw_pixbuf (window,
263
 
                         style->fg_gc[state],
264
 
                         uarea->priv->color_shifted,
265
 
                         area.x, area.y,
266
 
                         area.x, area.y,
267
 
                         area.width, area.height,
268
 
                         GDK_RGB_DITHER_NONE, 0, 0);
269
 
 
270
 
        cr = gdk_cairo_create (window);
271
 
        gdk_cairo_rectangle (cr, &event->area);
272
 
        cairo_clip (cr);
273
 
 
274
 
        if (uarea->priv->active_region != OUTSIDE) {
275
 
                gint x1, x2, y1, y2;
276
 
                gdk_cairo_set_source_color (cr, &style->white);
277
 
                cairo_set_line_width (cr, 1.0);
278
 
                x1 = crop.x + crop.width / 3.0;
279
 
                x2 = crop.x + 2 * crop.width / 3.0;
280
 
                y1 = crop.y + crop.height / 3.0;
281
 
                y2 = crop.y + 2 * crop.height / 3.0;
282
 
 
283
 
                cairo_move_to (cr, x1 + 0.5, crop.y);
284
 
                cairo_line_to (cr, x1 + 0.5, crop.y + crop.height);
285
 
 
286
 
                cairo_move_to (cr, x2 + 0.5, crop.y);
287
 
                cairo_line_to (cr, x2 + 0.5, crop.y + crop.height);
288
 
 
289
 
                cairo_move_to (cr, crop.x, y1 + 0.5);
290
 
                cairo_line_to (cr, crop.x + crop.width, y1 + 0.5);
291
 
 
292
 
                cairo_move_to (cr, crop.x, y2 + 0.5);
293
 
                cairo_line_to (cr, crop.x + crop.width, y2 + 0.5);
294
 
                cairo_stroke (cr);
295
 
        }
296
 
 
297
 
        gdk_cairo_set_source_color (cr, &style->black);
298
 
        cairo_set_line_width (cr, 1.0);
299
 
        cairo_rectangle (cr,
 
190
        GdkRectangle crop;
 
191
        gint width, height;
 
192
        UmCropArea *uarea = UM_CROP_AREA (widget);
 
193
 
 
194
        if (uarea->priv->browse_pixbuf == NULL)
 
195
                return FALSE;
 
196
 
 
197
        update_pixbufs (uarea);
 
198
 
 
199
        width = gdk_pixbuf_get_width (uarea->priv->pixbuf);
 
200
        height = gdk_pixbuf_get_height (uarea->priv->pixbuf);
 
201
        crop_to_widget (uarea, &crop);
 
202
 
 
203
        gdk_cairo_set_source_pixbuf (cr, uarea->priv->color_shifted, 0, 0);
 
204
        cairo_rectangle (cr, 0, 0, width, crop.y);
 
205
        cairo_rectangle (cr, 0, crop.y, crop.x, crop.height);
 
206
        cairo_rectangle (cr, crop.x + crop.width, crop.y, width - crop.x - crop.width, crop.height);
 
207
        cairo_rectangle (cr, 0, crop.y + crop.height, width, height - crop.y - crop.height);
 
208
        cairo_fill (cr);
 
209
 
 
210
        gdk_cairo_set_source_pixbuf (cr, uarea->priv->pixbuf, 0, 0);
 
211
        cairo_rectangle (cr, crop.x, crop.y, crop.width, crop.height);
 
212
        cairo_fill (cr);
 
213
 
 
214
        if (uarea->priv->active_region != OUTSIDE) {
 
215
                gint x1, x2, y1, y2;
 
216
                cairo_set_source_rgb (cr, 1, 1, 1);
 
217
                cairo_set_line_width (cr, 1.0);
 
218
                x1 = crop.x + crop.width / 3.0;
 
219
                x2 = crop.x + 2 * crop.width / 3.0;
 
220
                y1 = crop.y + crop.height / 3.0;
 
221
                y2 = crop.y + 2 * crop.height / 3.0;
 
222
 
 
223
                cairo_move_to (cr, x1 + 0.5, crop.y);
 
224
                cairo_line_to (cr, x1 + 0.5, crop.y + crop.height);
 
225
 
 
226
                cairo_move_to (cr, x2 + 0.5, crop.y);
 
227
                cairo_line_to (cr, x2 + 0.5, crop.y + crop.height);
 
228
 
 
229
                cairo_move_to (cr, crop.x, y1 + 0.5);
 
230
                cairo_line_to (cr, crop.x + crop.width, y1 + 0.5);
 
231
 
 
232
                cairo_move_to (cr, crop.x, y2 + 0.5);
 
233
                cairo_line_to (cr, crop.x + crop.width, y2 + 0.5);
 
234
                cairo_stroke (cr);
 
235
        }
 
236
 
 
237
        cairo_set_source_rgb (cr,  0, 0, 0);
 
238
        cairo_set_line_width (cr, 1.0);
 
239
        cairo_rectangle (cr,
300
240
                         crop.x + 0.5,
301
241
                         crop.y + 0.5,
302
242
                         crop.width - 1.0,
303
243
                         crop.height - 1.0);
304
244
        cairo_stroke (cr);
305
245
 
306
 
        gdk_cairo_set_source_color (cr, &style->white);
307
 
        cairo_set_line_width (cr, 2.0);
308
 
        cairo_rectangle (cr,
 
246
        cairo_set_source_rgb (cr, 1, 1, 1);
 
247
        cairo_set_line_width (cr, 2.0);
 
248
        cairo_rectangle (cr,
309
249
                         crop.x + 2.0,
310
250
                         crop.y + 2.0,
311
251
                         crop.width - 4.0,
312
252
                         crop.height - 4.0);
313
253
        cairo_stroke (cr);
314
254
 
315
 
        cairo_destroy (cr);
316
 
 
317
 
        return FALSE;
 
255
        return FALSE;
318
256
}
319
257
 
320
258
typedef enum {
321
 
        BELOW,
322
 
        LOWER,
323
 
        BETWEEN,
324
 
        UPPER,
325
 
        ABOVE
 
259
        BELOW,
 
260
        LOWER,
 
261
        BETWEEN,
 
262
        UPPER,
 
263
        ABOVE
326
264
} Range;
327
265
 
328
266
static Range
330
268
            gint min,
331
269
            gint max)
332
270
{
333
 
        gint tolerance = 12;
 
271
        gint tolerance = 12;
334
272
 
335
 
        if (x < min - tolerance)
336
 
                return BELOW;
337
 
        if (x <= min + tolerance)
338
 
                return LOWER;
339
 
        if (x < max - tolerance)
340
 
                return BETWEEN;
341
 
        if (x <= max + tolerance)
342
 
                return UPPER;
343
 
        return ABOVE;
 
273
        if (x < min - tolerance)
 
274
                return BELOW;
 
275
        if (x <= min + tolerance)
 
276
                return LOWER;
 
277
        if (x < max - tolerance)
 
278
                return BETWEEN;
 
279
        if (x <= max + tolerance)
 
280
                return UPPER;
 
281
        return ABOVE;
344
282
}
345
283
 
346
284
static Location
347
285
find_location (GdkRectangle *rect,
348
 
               gint          x,
349
 
               gint          y)
 
286
               gint          x,
 
287
               gint          y)
350
288
{
351
 
        Range x_range, y_range;
352
 
        Location location[5][5] = {
353
 
                { OUTSIDE, OUTSIDE,     OUTSIDE, OUTSIDE,      OUTSIDE },
354
 
                { OUTSIDE, TOP_LEFT,    TOP,     TOP_RIGHT,    OUTSIDE },
355
 
                { OUTSIDE, LEFT,        INSIDE,  RIGHT,        OUTSIDE },
356
 
                { OUTSIDE, BOTTOM_LEFT, BOTTOM,  BOTTOM_RIGHT, OUTSIDE },
357
 
                { OUTSIDE, OUTSIDE,     OUTSIDE, OUTSIDE,      OUTSIDE }
358
 
        };
359
 
 
360
 
        x_range = find_range (x, rect->x, rect->x + rect->width);
361
 
        y_range = find_range (y, rect->y, rect->y + rect->height);
362
 
 
363
 
        return location[y_range][x_range];
 
289
        Range x_range, y_range;
 
290
        Location location[5][5] = {
 
291
                { OUTSIDE, OUTSIDE,     OUTSIDE, OUTSIDE,      OUTSIDE },
 
292
                { OUTSIDE, TOP_LEFT,    TOP,     TOP_RIGHT,    OUTSIDE },
 
293
                { OUTSIDE, LEFT,        INSIDE,  RIGHT,        OUTSIDE },
 
294
                { OUTSIDE, BOTTOM_LEFT, BOTTOM,  BOTTOM_RIGHT, OUTSIDE },
 
295
                { OUTSIDE, OUTSIDE,     OUTSIDE, OUTSIDE,      OUTSIDE }
 
296
        };
 
297
 
 
298
        x_range = find_range (x, rect->x, rect->x + rect->width);
 
299
        y_range = find_range (y, rect->y, rect->y + rect->height);
 
300
 
 
301
        return location[y_range][x_range];
364
302
}
365
303
 
366
304
static void
368
306
               gint           x,
369
307
               gint           y)
370
308
{
371
 
        gint cursor_type;
372
 
        GdkRectangle crop;
373
 
 
374
 
        crop_to_widget (area, &crop);
375
 
 
376
 
        switch (find_location (&crop, x, y)) {
377
 
        case OUTSIDE:
378
 
                cursor_type = GDK_LEFT_PTR;
379
 
                break;
380
 
        case TOP_LEFT:
381
 
                cursor_type = GDK_TOP_LEFT_CORNER;
382
 
                break;
383
 
        case TOP:
384
 
                cursor_type = GDK_TOP_SIDE;
385
 
                break;
386
 
        case TOP_RIGHT:
387
 
                cursor_type = GDK_TOP_RIGHT_CORNER;
388
 
                break;
389
 
        case LEFT:
390
 
                cursor_type = GDK_LEFT_SIDE;
391
 
                break;
392
 
        case INSIDE:
393
 
                cursor_type = GDK_FLEUR;
394
 
                break;
395
 
        case RIGHT:
396
 
                cursor_type = GDK_RIGHT_SIDE;
397
 
                break;
398
 
        case BOTTOM_LEFT:
399
 
                cursor_type = GDK_BOTTOM_LEFT_CORNER;
400
 
                break;
401
 
        case BOTTOM:
402
 
                cursor_type = GDK_BOTTOM_SIDE;
403
 
                break;
404
 
        case BOTTOM_RIGHT:
405
 
                cursor_type = GDK_BOTTOM_RIGHT_CORNER;
406
 
                break;
407
 
        }
408
 
 
409
 
        if (cursor_type != area->priv->current_cursor) {
410
 
                GdkCursor *cursor = gdk_cursor_new (cursor_type);
411
 
                gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (area)), cursor);
412
 
                gdk_cursor_unref (cursor);
413
 
                area->priv->current_cursor = cursor_type;
414
 
        }
415
 
}
416
 
 
417
 
static gboolean 
 
309
        gint cursor_type;
 
310
        GdkRectangle crop;
 
311
        gint region;
 
312
 
 
313
        region = area->priv->active_region;
 
314
        if (region == OUTSIDE) {
 
315
                crop_to_widget (area, &crop);
 
316
                region = find_location (&crop, x, y);
 
317
        }
 
318
 
 
319
        switch (region) {
 
320
        case OUTSIDE:
 
321
                cursor_type = GDK_LEFT_PTR;
 
322
                break;
 
323
        case TOP_LEFT:
 
324
                cursor_type = GDK_TOP_LEFT_CORNER;
 
325
                break;
 
326
        case TOP:
 
327
                cursor_type = GDK_TOP_SIDE;
 
328
                break;
 
329
        case TOP_RIGHT:
 
330
                cursor_type = GDK_TOP_RIGHT_CORNER;
 
331
                break;
 
332
        case LEFT:
 
333
                cursor_type = GDK_LEFT_SIDE;
 
334
                break;
 
335
        case INSIDE:
 
336
                cursor_type = GDK_FLEUR;
 
337
                break;
 
338
        case RIGHT:
 
339
                cursor_type = GDK_RIGHT_SIDE;
 
340
                break;
 
341
        case BOTTOM_LEFT:
 
342
                cursor_type = GDK_BOTTOM_LEFT_CORNER;
 
343
                break;
 
344
        case BOTTOM:
 
345
                cursor_type = GDK_BOTTOM_SIDE;
 
346
                break;
 
347
        case BOTTOM_RIGHT:
 
348
                cursor_type = GDK_BOTTOM_RIGHT_CORNER;
 
349
                break;
 
350
        default:
 
351
                g_assert_not_reached ();
 
352
        }
 
353
 
 
354
        if (cursor_type != area->priv->current_cursor) {
 
355
                GdkCursor *cursor = gdk_cursor_new (cursor_type);
 
356
                gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (area)), cursor);
 
357
                g_object_unref (cursor);
 
358
                area->priv->current_cursor = cursor_type;
 
359
        }
 
360
}
 
361
 
 
362
static int
 
363
eval_radial_line (gdouble center_x, gdouble center_y,
 
364
                  gdouble bounds_x, gdouble bounds_y,
 
365
                  gdouble user_x)
 
366
{
 
367
        gdouble decision_slope;
 
368
        gdouble decision_intercept;
 
369
 
 
370
        decision_slope = (bounds_y - center_y) / (bounds_x - center_x);
 
371
        decision_intercept = -(decision_slope * bounds_x);
 
372
 
 
373
        return (int) (decision_slope * user_x + decision_intercept);
 
374
}
 
375
 
 
376
static gboolean
418
377
um_crop_area_motion_notify_event (GtkWidget      *widget,
419
 
                                  GdkEventMotion *event)
 
378
                                  GdkEventMotion *event)
420
379
{
421
 
        gint x, y;
422
 
        gint x2, y2;
423
 
        gint delta_x, delta_y;
424
 
        gint width, height, d;
425
 
        UmCropArea *area = UM_CROP_AREA (widget);
426
 
 
427
 
        width = gdk_pixbuf_get_width (area->priv->browse_pixbuf);
428
 
        height = gdk_pixbuf_get_height (area->priv->browse_pixbuf);
429
 
 
430
 
        x = (event->x - area->priv->image.x) / area->priv->scale;
431
 
        y = (event->y - area->priv->image.y) / area->priv->scale;
432
 
        x = CLAMP (x, 0, width);
433
 
        y = CLAMP (y, 0, height);
434
 
 
435
 
        delta_x = x - area->priv->last_press_x;
436
 
        delta_y = y - area->priv->last_press_y;
437
 
        area->priv->last_press_x = x;
438
 
        area->priv->last_press_y = y;
439
 
 
440
 
        x2 = area->priv->crop.x + area->priv->crop.width;
441
 
        y2 = area->priv->crop.y + area->priv->crop.height;
442
 
 
443
 
        switch (area->priv->active_region) {
444
 
        case INSIDE:
445
 
                area->priv->crop.x = CLAMP (area->priv->crop.x + delta_x, 0, width - area->priv->crop.width);
446
 
                area->priv->crop.y = CLAMP (area->priv->crop.y + delta_y, 0, height - area->priv->crop.height);
447
 
                break;
448
 
 
449
 
        case TOP_LEFT:
450
 
                d = MAX (x2 - x, y2 - y);
451
 
                if (d < 48 / area->priv->scale)
452
 
                        d = 48 / area->priv->scale;
453
 
                if (x2 - d < 0)
454
 
                        d = x2;
455
 
                if (y2 - d < 0)
456
 
                        d = y2;
457
 
                area->priv->crop.x = x2 - d;
458
 
                area->priv->crop.y = y2 - d;
459
 
                area->priv->crop.width = area->priv->crop.height = d;
460
 
                break;
461
 
 
462
 
        case TOP:
463
 
        case TOP_RIGHT:
464
 
                d = MAX (y2 - y, x - area->priv->crop.x);
465
 
                if (d < 48 / area->priv->scale)
466
 
                        d = 48 / area->priv->scale;
467
 
                if (area->priv->crop.x + d > width)
468
 
                        d = width - area->priv->crop.x;
469
 
                if (y2 - d < 0)
470
 
                        d = y2;
471
 
                area->priv->crop.y = y2 - d;
472
 
                area->priv->crop.width = area->priv->crop.height = d;
473
 
                break;
474
 
 
475
 
        case LEFT:
476
 
        case BOTTOM_LEFT:
477
 
                d = MAX (x2 - x, y - area->priv->crop.y);
478
 
                if (d < 48 / area->priv->scale)
479
 
                        d = 48 / area->priv->scale;
480
 
                if (area->priv->crop.y + d > height)
481
 
                        d = height - area->priv->crop.y;
482
 
                if (x2 - d < 0)
483
 
                        d = x2;
484
 
                area->priv->crop.x = x2 - d;
485
 
                area->priv->crop.width = area->priv->crop.height = d;
486
 
                break;
487
 
 
488
 
        case RIGHT:
489
 
        case BOTTOM_RIGHT:
490
 
        case BOTTOM:
491
 
                area->priv->crop.width = MAX (x - area->priv->crop.x, y - area->priv->crop.y);
492
 
                if (area->priv->crop.width < 48 / area->priv->scale)
493
 
                        area->priv->crop.width = 48 / area->priv->scale;
494
 
                if (area->priv->crop.x + area->priv->crop.width > width)
495
 
                        area->priv->crop.width = width - area->priv->crop.x;
496
 
                area->priv->crop.height = area->priv->crop.width;
497
 
                if (area->priv->crop.y + area->priv->crop.height > height)
498
 
                        area->priv->crop.height = height - area->priv->crop.y;
499
 
                area->priv->crop.width = area->priv->crop.height;
500
 
                break;
501
 
 
502
 
        case OUTSIDE:
503
 
                break;
504
 
        default: ;
505
 
        }
506
 
 
507
 
        update_cursor (area, event->x, event->y);
508
 
        gtk_widget_queue_draw (widget);
509
 
 
510
 
        return FALSE;
 
380
        UmCropArea *area = UM_CROP_AREA (widget);
 
381
        gint x, y;
 
382
        gint delta_x, delta_y;
 
383
        gint width, height;
 
384
        gint adj_width, adj_height;
 
385
        gint pb_width, pb_height;
 
386
        GdkRectangle damage;
 
387
        gint left, right, top, bottom;
 
388
        gdouble new_width, new_height;
 
389
        gdouble center_x, center_y;
 
390
        gint min_width, min_height;
 
391
 
 
392
        if (area->priv->browse_pixbuf == NULL)
 
393
                return FALSE;
 
394
 
 
395
        update_cursor (area, event->x, event->y);
 
396
 
 
397
        crop_to_widget (area, &damage);
 
398
        gtk_widget_queue_draw_area (widget,
 
399
                                    damage.x - 1, damage.y - 1,
 
400
                                    damage.width + 2, damage.height + 2);
 
401
 
 
402
        pb_width = gdk_pixbuf_get_width (area->priv->browse_pixbuf);
 
403
        pb_height = gdk_pixbuf_get_height (area->priv->browse_pixbuf);
 
404
 
 
405
        x = (event->x - area->priv->image.x) / area->priv->scale;
 
406
        y = (event->y - area->priv->image.y) / area->priv->scale;
 
407
 
 
408
        delta_x = x - area->priv->last_press_x;
 
409
        delta_y = y - area->priv->last_press_y;
 
410
        area->priv->last_press_x = x;
 
411
        area->priv->last_press_y = y;
 
412
 
 
413
        left = area->priv->crop.x;
 
414
        right = area->priv->crop.x + area->priv->crop.width - 1;
 
415
        top = area->priv->crop.y;
 
416
        bottom = area->priv->crop.y + area->priv->crop.height - 1;
 
417
 
 
418
        center_x = (left + right) / 2.0;
 
419
        center_y = (top + bottom) / 2.0;
 
420
 
 
421
        switch (area->priv->active_region) {
 
422
        case INSIDE:
 
423
                width = right - left + 1;
 
424
                height = bottom - top + 1;
 
425
 
 
426
                left += delta_x;
 
427
                right += delta_x;
 
428
                top += delta_y;
 
429
                bottom += delta_y;
 
430
 
 
431
                if (left < 0)
 
432
                        left = 0;
 
433
                if (top < 0)
 
434
                        top = 0;
 
435
                if (right > pb_width)
 
436
                        right = pb_width;
 
437
                if (bottom > pb_height)
 
438
                        bottom = pb_height;
 
439
 
 
440
                adj_width = right - left + 1;
 
441
                adj_height = bottom - top + 1;
 
442
                if (adj_width != width) {
 
443
                        if (delta_x < 0)
 
444
                                right = left + width - 1;
 
445
                        else
 
446
                                left = right - width + 1;
 
447
                }
 
448
                if (adj_height != height) {
 
449
                        if (delta_y < 0)
 
450
                                bottom = top + height - 1;
 
451
                        else
 
452
                                top = bottom - height + 1;
 
453
                }
 
454
 
 
455
                break;
 
456
 
 
457
        case TOP_LEFT:
 
458
                if (area->priv->aspect < 0) {
 
459
                        top = y;
 
460
                        left = x;
 
461
                }
 
462
                else if (y < eval_radial_line (center_x, center_y, left, top, x)) {
 
463
                        top = y;
 
464
                        new_width = (bottom - top) * area->priv->aspect;
 
465
                        left = right - new_width;
 
466
                }
 
467
                else {
 
468
                        left = x;
 
469
                        new_height = (right - left) / area->priv->aspect;
 
470
                        top = bottom - new_height;
 
471
                }
 
472
                break;
 
473
 
 
474
        case TOP:
 
475
                top = y;
 
476
                if (area->priv->aspect > 0) {
 
477
                        new_width = (bottom - top) * area->priv->aspect;
 
478
                        right = left + new_width;
 
479
                }
 
480
                break;
 
481
 
 
482
        case TOP_RIGHT:
 
483
                if (area->priv->aspect < 0) {
 
484
                        top = y;
 
485
                        right = x;
 
486
                }
 
487
                else if (y < eval_radial_line (center_x, center_y, right, top, x)) {
 
488
                        top = y;
 
489
                        new_width = (bottom - top) * area->priv->aspect;
 
490
                        right = left + new_width;
 
491
                }
 
492
                else {
 
493
                        right = x;
 
494
                        new_height = (right - left) / area->priv->aspect;
 
495
                        top = bottom - new_height;
 
496
                }
 
497
                break;
 
498
 
 
499
        case LEFT:
 
500
                left = x;
 
501
                if (area->priv->aspect > 0) {
 
502
                        new_height = (right - left) / area->priv->aspect;
 
503
                        bottom = top + new_height;
 
504
                }
 
505
                break;
 
506
 
 
507
        case BOTTOM_LEFT:
 
508
                if (area->priv->aspect < 0) {
 
509
                        bottom = y;
 
510
                        left = x;
 
511
                }
 
512
                else if (y < eval_radial_line (center_x, center_y, left, bottom, x)) {
 
513
                        left = x;
 
514
                        new_height = (right - left) / area->priv->aspect;
 
515
                        bottom = top + new_height;
 
516
                }
 
517
                else {
 
518
                        bottom = y;
 
519
                        new_width = (bottom - top) * area->priv->aspect;
 
520
                        left = right - new_width;
 
521
                }
 
522
                break;
 
523
 
 
524
        case RIGHT:
 
525
                right = x;
 
526
                if (area->priv->aspect > 0) {
 
527
                        new_height = (right - left) / area->priv->aspect;
 
528
                        bottom = top + new_height;
 
529
                }
 
530
                break;
 
531
 
 
532
        case BOTTOM_RIGHT:
 
533
                if (area->priv->aspect < 0) {
 
534
                        bottom = y;
 
535
                        right = x;
 
536
                }
 
537
                else if (y < eval_radial_line (center_x, center_y, right, bottom, x)) {
 
538
                        right = x;
 
539
                        new_height = (right - left) / area->priv->aspect;
 
540
                        bottom = top + new_height;
 
541
                }
 
542
                else {
 
543
                        bottom = y;
 
544
                        new_width = (bottom - top) * area->priv->aspect;
 
545
                        right = left + new_width;
 
546
                }
 
547
                break;
 
548
 
 
549
        case BOTTOM:
 
550
                bottom = y;
 
551
                if (area->priv->aspect > 0) {
 
552
                        new_width = (bottom - top) * area->priv->aspect;
 
553
                        right= left + new_width;
 
554
                }
 
555
                break;
 
556
 
 
557
        default:
 
558
                return FALSE;
 
559
        }
 
560
 
 
561
        min_width = area->priv->base_width / area->priv->scale;
 
562
        min_height = area->priv->base_height / area->priv->scale;
 
563
 
 
564
        width = right - left + 1;
 
565
        height = bottom - top + 1;
 
566
        if (area->priv->aspect < 0) {
 
567
                if (left < 0)
 
568
                        left = 0;
 
569
                if (top < 0)
 
570
                        top = 0;
 
571
                if (right > pb_width)
 
572
                        right = pb_width;
 
573
                if (bottom > pb_height)
 
574
                        bottom = pb_height;
 
575
 
 
576
                width = right - left + 1;
 
577
                height = bottom - top + 1;
 
578
 
 
579
                switch (area->priv->active_region) {
 
580
                case LEFT:
 
581
                case TOP_LEFT:
 
582
                case BOTTOM_LEFT:
 
583
                        if (width < min_width)
 
584
                                left = right - min_width;
 
585
                        break;
 
586
                case RIGHT:
 
587
                case TOP_RIGHT:
 
588
                case BOTTOM_RIGHT:
 
589
                        if (width < min_width)
 
590
                                right = left + min_width;
 
591
                        break;
 
592
 
 
593
                default: ;
 
594
                }
 
595
 
 
596
                switch (area->priv->active_region) {
 
597
                case TOP:
 
598
                case TOP_LEFT:
 
599
                case TOP_RIGHT:
 
600
                        if (height < min_height)
 
601
                                top = bottom - min_height;
 
602
                        break;
 
603
                case BOTTOM:
 
604
                case BOTTOM_LEFT:
 
605
                case BOTTOM_RIGHT:
 
606
                        if (height < min_height)
 
607
                                bottom = top + min_height;
 
608
                        break;
 
609
 
 
610
                default: ;
 
611
                }
 
612
        }
 
613
        else {
 
614
                if (left < 0 || top < 0 ||
 
615
                    right > pb_width || bottom > pb_height ||
 
616
                    width < min_width || height < min_height) {
 
617
                        left = area->priv->crop.x;
 
618
                        right = area->priv->crop.x + area->priv->crop.width - 1;
 
619
                        top = area->priv->crop.y;
 
620
                        bottom = area->priv->crop.y + area->priv->crop.height - 1;
 
621
                }
 
622
        }
 
623
 
 
624
        area->priv->crop.x = left;
 
625
        area->priv->crop.y = top;
 
626
        area->priv->crop.width = right - left + 1;
 
627
        area->priv->crop.height = bottom - top + 1;
 
628
 
 
629
        crop_to_widget (area, &damage);
 
630
        gtk_widget_queue_draw_area (widget,
 
631
                                    damage.x - 1, damage.y - 1,
 
632
                                    damage.width + 2, damage.height + 2);
 
633
 
 
634
        return FALSE;
511
635
}
512
636
 
513
637
static gboolean
514
638
um_crop_area_button_press_event (GtkWidget      *widget,
515
 
                                 GdkEventButton *event)
 
639
                                 GdkEventButton *event)
516
640
{
517
 
        GdkRectangle crop;
518
 
        UmCropArea *area = UM_CROP_AREA (widget);
519
 
 
520
 
        crop_to_widget (area, &crop);
521
 
 
522
 
        area->priv->last_press_x = (event->x - area->priv->image.x) / area->priv->scale;
523
 
        area->priv->last_press_y = (event->y - area->priv->image.y) / area->priv->scale;
524
 
        area->priv->active_region = find_location (&crop, event->x, event->y);
525
 
 
526
 
        gtk_widget_queue_draw (widget);
527
 
 
528
 
        return FALSE;
 
641
        UmCropArea *area = UM_CROP_AREA (widget);
 
642
        GdkRectangle crop;
 
643
 
 
644
        if (area->priv->browse_pixbuf == NULL)
 
645
                return FALSE;
 
646
 
 
647
        crop_to_widget (area, &crop);
 
648
 
 
649
        area->priv->last_press_x = (event->x - area->priv->image.x) / area->priv->scale;
 
650
        area->priv->last_press_y = (event->y - area->priv->image.y) / area->priv->scale;
 
651
        area->priv->active_region = find_location (&crop, event->x, event->y);
 
652
 
 
653
        gtk_widget_queue_draw_area (widget,
 
654
                                    crop.x - 1, crop.y - 1,
 
655
                                    crop.width + 2, crop.height + 2);
 
656
 
 
657
        return FALSE;
529
658
}
530
659
 
531
660
static gboolean
532
661
um_crop_area_button_release_event (GtkWidget      *widget,
533
 
                                   GdkEventButton *event)
 
662
                                   GdkEventButton *event)
534
663
{
535
 
        UmCropArea *area = UM_CROP_AREA (widget);
536
 
 
537
 
        area->priv->last_press_x = -1;
538
 
        area->priv->last_press_y = -1;
539
 
        area->priv->active_region = OUTSIDE;
540
 
 
541
 
        gtk_widget_queue_draw (widget);
542
 
 
543
 
        return FALSE;
 
664
        UmCropArea *area = UM_CROP_AREA (widget);
 
665
        GdkRectangle crop;
 
666
 
 
667
        if (area->priv->browse_pixbuf == NULL)
 
668
                return FALSE;
 
669
 
 
670
        crop_to_widget (area, &crop);
 
671
 
 
672
        area->priv->last_press_x = -1;
 
673
        area->priv->last_press_y = -1;
 
674
        area->priv->active_region = OUTSIDE;
 
675
 
 
676
        gtk_widget_queue_draw_area (widget,
 
677
                                    crop.x - 1, crop.y - 1,
 
678
                                    crop.width + 2, crop.height + 2);
 
679
 
 
680
        return FALSE;
544
681
}
545
682
 
546
683
static void
547
684
um_crop_area_finalize (GObject *object)
548
685
{
549
 
        UmCropArea *area = UM_CROP_AREA (object);
 
686
        UmCropArea *area = UM_CROP_AREA (object);
550
687
 
551
 
        if (area->priv->browse_pixbuf) {
552
 
                g_object_unref (area->priv->browse_pixbuf);
553
 
                area->priv->browse_pixbuf = NULL;
554
 
        }
555
 
        if (area->priv->pixbuf) {
556
 
                g_object_unref (area->priv->pixbuf);
557
 
                area->priv->pixbuf = NULL;
558
 
        }
559
 
        if (area->priv->color_shifted) {
560
 
                g_object_unref (area->priv->color_shifted);
561
 
                area->priv->color_shifted = NULL;
562
 
        }
 
688
        if (area->priv->browse_pixbuf) {
 
689
                g_object_unref (area->priv->browse_pixbuf);
 
690
                area->priv->browse_pixbuf = NULL;
 
691
        }
 
692
        if (area->priv->pixbuf) {
 
693
                g_object_unref (area->priv->pixbuf);
 
694
                area->priv->pixbuf = NULL;
 
695
        }
 
696
        if (area->priv->color_shifted) {
 
697
                g_object_unref (area->priv->color_shifted);
 
698
                area->priv->color_shifted = NULL;
 
699
        }
563
700
}
564
701
 
565
702
static void
566
703
um_crop_area_class_init (UmCropAreaClass *klass)
567
704
{
568
 
        GObjectClass   *object_class = G_OBJECT_CLASS (klass);
569
 
        GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
570
 
 
571
 
        object_class->finalize     = um_crop_area_finalize;
572
 
        widget_class->expose_event = um_crop_area_expose;
573
 
        widget_class->button_press_event = um_crop_area_button_press_event;
574
 
        widget_class->button_release_event = um_crop_area_button_release_event;
575
 
        widget_class->motion_notify_event = um_crop_area_motion_notify_event;
576
 
 
577
 
        g_type_class_add_private (klass, sizeof (UmCropAreaPrivate));
 
705
        GObjectClass   *object_class = G_OBJECT_CLASS (klass);
 
706
        GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
 
707
 
 
708
        object_class->finalize = um_crop_area_finalize;
 
709
        widget_class->draw = um_crop_area_draw;
 
710
        widget_class->button_press_event = um_crop_area_button_press_event;
 
711
        widget_class->button_release_event = um_crop_area_button_release_event;
 
712
        widget_class->motion_notify_event = um_crop_area_motion_notify_event;
 
713
 
 
714
        g_type_class_add_private (klass, sizeof (UmCropAreaPrivate));
578
715
}
579
716
 
580
717
static void
581
718
um_crop_area_init (UmCropArea *area)
582
719
{
583
 
        area->priv = (G_TYPE_INSTANCE_GET_PRIVATE ((area), UM_TYPE_CROP_AREA,
584
 
                                                   UmCropAreaPrivate));
585
 
 
586
 
        gtk_widget_add_events (GTK_WIDGET (area), GDK_POINTER_MOTION_MASK |
587
 
                               GDK_BUTTON_PRESS_MASK |
588
 
                               GDK_BUTTON_RELEASE_MASK);
589
 
 
590
 
        area->priv->scale = 0.0;
591
 
        area->priv->image.x = 0;
592
 
        area->priv->image.y = 0;
593
 
        area->priv->image.width = 0;
594
 
        area->priv->image.height = 0;
595
 
        area->priv->active_region = OUTSIDE;
 
720
        area->priv = (G_TYPE_INSTANCE_GET_PRIVATE ((area), UM_TYPE_CROP_AREA,
 
721
                                                   UmCropAreaPrivate));
 
722
 
 
723
        gtk_widget_add_events (GTK_WIDGET (area), GDK_POINTER_MOTION_MASK |
 
724
                               GDK_BUTTON_PRESS_MASK |
 
725
                               GDK_BUTTON_RELEASE_MASK);
 
726
 
 
727
        area->priv->scale = 0.0;
 
728
        area->priv->image.x = 0;
 
729
        area->priv->image.y = 0;
 
730
        area->priv->image.width = 0;
 
731
        area->priv->image.height = 0;
 
732
        area->priv->active_region = OUTSIDE;
 
733
        area->priv->base_width = 48;
 
734
        area->priv->base_height = 48;
 
735
        area->priv->aspect = 1;
596
736
}
597
737
 
598
738
GtkWidget *
599
739
um_crop_area_new (void)
600
740
{
601
 
        return g_object_new (UM_TYPE_CROP_AREA, NULL);
 
741
        return g_object_new (UM_TYPE_CROP_AREA, NULL);
602
742
}
603
743
 
604
744
GdkPixbuf *
605
745
um_crop_area_get_picture (UmCropArea *area)
606
746
{
607
 
        return gdk_pixbuf_new_subpixbuf (area->priv->browse_pixbuf,
608
 
                                         area->priv->crop.x, area->priv->crop.y,
609
 
                                         area->priv->crop.width, area->priv->crop.height);
 
747
        gint width, height;
 
748
 
 
749
        width = gdk_pixbuf_get_width (area->priv->browse_pixbuf);
 
750
        height = gdk_pixbuf_get_height (area->priv->browse_pixbuf);
 
751
        width = MIN (area->priv->crop.width, width - area->priv->crop.x);
 
752
        height = MIN (area->priv->crop.height, height - area->priv->crop.y);
 
753
 
 
754
        return gdk_pixbuf_new_subpixbuf (area->priv->browse_pixbuf,
 
755
                                         area->priv->crop.x,
 
756
                                         area->priv->crop.y,
 
757
                                         width, height);
610
758
}
611
759
 
612
760
void
613
761
um_crop_area_set_picture (UmCropArea *area,
614
 
                          GdkPixbuf  *pixbuf)
615
 
{
616
 
        int width;
617
 
        int height;
618
 
 
619
 
        if (area->priv->browse_pixbuf) {
620
 
                g_object_unref (area->priv->browse_pixbuf);
621
 
                area->priv->browse_pixbuf = NULL;
622
 
        }
623
 
        if (pixbuf) {
624
 
                area->priv->browse_pixbuf = g_object_ref (pixbuf);
625
 
                width = gdk_pixbuf_get_width (pixbuf);
626
 
                height = gdk_pixbuf_get_height (pixbuf);
627
 
        } else {
628
 
                width = 0;
629
 
                height = 0;
630
 
        }
631
 
 
632
 
#if 0
633
 
        gtk_widget_get_allocation (um->browse_drawing_area, &allocation);
634
 
        um->priv->crop.width = 96;
635
 
        um->priv->crop.height = 96;
636
 
        um->priv->crop.x = (allocation.width - um->priv->crop.width) / 2;
637
 
        um->priv->crop.y = (allocation.height - um->priv->crop.height) / 2;
638
 
#else
639
 
        area->priv->crop.width = 96;
640
 
        area->priv->crop.height = 96;
641
 
        area->priv->crop.x = (width - area->priv->crop.width) / 2;
642
 
        area->priv->crop.y = (height - area->priv->crop.height) / 2;
643
 
#endif
644
 
        area->priv->scale = 0.0;
645
 
        area->priv->image.x = 0;
646
 
        area->priv->image.y = 0;
647
 
        area->priv->image.width = 0;
648
 
        area->priv->image.height = 0;
649
 
 
650
 
        gtk_widget_queue_draw (GTK_WIDGET (area));
 
762
                          GdkPixbuf  *pixbuf)
 
763
{
 
764
        int width;
 
765
        int height;
 
766
 
 
767
        if (area->priv->browse_pixbuf) {
 
768
                g_object_unref (area->priv->browse_pixbuf);
 
769
                area->priv->browse_pixbuf = NULL;
 
770
        }
 
771
        if (pixbuf) {
 
772
                area->priv->browse_pixbuf = g_object_ref (pixbuf);
 
773
                width = gdk_pixbuf_get_width (pixbuf);
 
774
                height = gdk_pixbuf_get_height (pixbuf);
 
775
        } else {
 
776
                width = 0;
 
777
                height = 0;
 
778
        }
 
779
 
 
780
        area->priv->crop.width = 2 * area->priv->base_width;
 
781
        area->priv->crop.height = 2 * area->priv->base_height;
 
782
        area->priv->crop.x = (width - area->priv->crop.width) / 2;
 
783
        area->priv->crop.y = (height - area->priv->crop.height) / 2;
 
784
 
 
785
        area->priv->scale = 0.0;
 
786
        area->priv->image.x = 0;
 
787
        area->priv->image.y = 0;
 
788
        area->priv->image.width = 0;
 
789
        area->priv->image.height = 0;
 
790
 
 
791
        gtk_widget_queue_draw (GTK_WIDGET (area));
 
792
}
 
793
 
 
794
void
 
795
um_crop_area_set_min_size (UmCropArea *area,
 
796
                           gint        width,
 
797
                           gint        height)
 
798
{
 
799
        area->priv->base_width = width;
 
800
        area->priv->base_height = height;
 
801
 
 
802
        if (area->priv->aspect > 0) {
 
803
                area->priv->aspect = area->priv->base_width / (gdouble)area->priv->base_height;
 
804
        }
 
805
}
 
806
 
 
807
void
 
808
um_crop_area_set_constrain_aspect (UmCropArea *area,
 
809
                                   gboolean    constrain)
 
810
{
 
811
        if (constrain) {
 
812
                area->priv->aspect = area->priv->base_width / (gdouble)area->priv->base_height;
 
813
        }
 
814
        else {
 
815
                area->priv->aspect = -1;
 
816
        }
651
817
}
652
818