~ubuntu-branches/ubuntu/quantal/shotwell/quantal

« back to all changes in this revision

Viewing changes to src/editing_tools/EditingTools.vala

  • Committer: Package Import Robot
  • Author(s): Robert Ancell
  • Date: 2012-02-21 13:52:58 UTC
  • mto: This revision was merged to the branch mainline in revision 47.
  • Revision ID: package-import@ubuntu.com-20120221135258-ao9jiib5qicomq7q
Tags: upstream-0.11.92
ImportĀ upstreamĀ versionĀ 0.11.92

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright 2011 Yorba Foundation
 
1
/* Copyright 2011-2012 Yorba Foundation
2
2
 *
3
3
 * This software is licensed under the GNU Lesser General Public License
4
4
 * (version 2.1 or later).  See the COPYING file in this distribution.
53
53
        set_accept_focus(true);
54
54
        set_can_focus(true);
55
55
        set_has_resize_grip(false);
 
56
 
 
57
        Log.set_handler("Gdk", LogLevelFlags.LEVEL_WARNING, suppress_warnings);
 
58
    }
 
59
 
 
60
    ~EditingToolWindow() {
 
61
        Log.set_handler("Gdk", LogLevelFlags.LEVEL_WARNING, Log.default_handler);   
56
62
    }
57
63
 
58
64
    public override void add(Gtk.Widget widget) {
64
70
    }
65
71
 
66
72
    public override bool key_press_event(Gdk.EventKey event) {
67
 
       return AppWindow.get_instance().key_press_event(event);
 
73
        if (base.key_press_event(event)) {
 
74
            return true;
 
75
        }
 
76
        return AppWindow.get_instance().key_press_event(event);
68
77
    }
69
78
 
70
79
    public override bool button_press_event(Gdk.EventButton event) {
80
89
 
81
90
    public override void realize() {
82
91
        set_opacity(Resources.TRANSIENT_WINDOW_OPACITY);
83
 
 
 
92
        
84
93
        base.realize();
85
94
    }
86
95
}
115
124
    public signal void resized_scaled_pixbuf(Dimensions old_dim, Gdk.Pixbuf scaled,
116
125
        Gdk.Rectangle scaled_position);
117
126
 
 
127
    public Gdk.Rectangle unscaled_to_raw_rect(Gdk.Rectangle rectangle) {
 
128
        return photo.unscaled_to_raw_rect(rectangle);
 
129
    }
 
130
 
118
131
    public Gdk.Point active_to_unscaled_point(Gdk.Point active_point) {
119
132
        Gdk.Rectangle scaled_position = get_scaled_pixbuf_position();
120
133
        Dimensions unscaled_dims = photo.get_dimensions();
142
155
        upper_left = active_to_unscaled_point(upper_left);
143
156
        lower_right = active_to_unscaled_point(lower_right);
144
157
 
145
 
        Gdk.Rectangle unscaled_rect = {0};
 
158
        Gdk.Rectangle unscaled_rect = Gdk.Rectangle();
146
159
        unscaled_rect.x = upper_left.x;
147
160
        unscaled_rect.y = upper_left.y;
148
161
        unscaled_rect.width = lower_right.x - upper_left.x;
172
185
        upper_left = user_to_active_point(upper_left);
173
186
        lower_right = user_to_active_point(lower_right);
174
187
 
175
 
        Gdk.Rectangle active_rect = {0};
 
188
        Gdk.Rectangle active_rect = Gdk.Rectangle();
176
189
        active_rect.x = upper_left.x;
177
190
        active_rect.y = upper_left.y;
178
191
        active_rect.width = lower_right.x - upper_left.x;
244
257
        default_ctx.save();
245
258
 
246
259
        // paint black background
247
 
        Gdk.cairo_set_source_color(default_ctx, container.style.black);
 
260
        set_source_color_from_string(default_ctx, "#000");
248
261
        default_ctx.rectangle(0, 0, surface_dim.width, surface_dim.height);
249
262
        default_ctx.fill();
250
263
 
259
272
    public void paint_pixbuf_area(Gdk.Pixbuf pixbuf, Box source_area) {
260
273
        default_ctx.save();
261
274
        if (pixbuf.get_has_alpha()) {
262
 
            Gdk.cairo_set_source_color(default_ctx, container.style.black);
 
275
            set_source_color_from_string(default_ctx, "#000");
263
276
            default_ctx.rectangle(scaled_position.x + source_area.left,
264
277
                scaled_position.y + source_area.top,
265
278
                source_area.get_width(), source_area.get_height());
320
333
        ctx.stroke();
321
334
    }
322
335
 
323
 
    public void draw_horizontal_line(Cairo.Context ctx, int x, int y, int width) {
324
 
        x += scaled_position.x;
325
 
        y += scaled_position.y;
 
336
    /**
 
337
     * Draw a horizontal line into the specified Cairo context at the specified position, taking
 
338
     * into account the scaled position of the image unless directed otherwise.
 
339
     *
 
340
     * @param ctx The drawing context of the surface we're drawing to.
 
341
     * @param x The horizontal position to place the line at.
 
342
     * @param y The vertical position to place the line at.
 
343
     * @param width The length of the line.
 
344
     * @param use_scaled_pos Whether to use absolute window positioning or take into account the 
 
345
     *      position of the scaled image.
 
346
     */
 
347
    public void draw_horizontal_line(Cairo.Context ctx, int x, int y, int width, bool use_scaled_pos = true) {
 
348
        if (use_scaled_pos) {
 
349
            x += scaled_position.x;
 
350
            y += scaled_position.y;
 
351
        }
326
352
 
327
353
        ctx.move_to(x + 0.5, y + 0.5);
328
354
        ctx.line_to(x + width - 1, y + 0.5);
329
355
        ctx.stroke();
330
356
    }
331
357
 
332
 
    public void draw_vertical_line(Cairo.Context ctx, int x, int y, int height) {
333
 
        x += scaled_position.x;
334
 
        y += scaled_position.y;
 
358
    /**
 
359
     * Draw a vertical line into the specified Cairo context at the specified position, taking
 
360
     * into account the scaled position of the image unless directed otherwise.
 
361
     *
 
362
     * @param ctx The drawing context of the surface we're drawing to.
 
363
     * @param x The horizontal position to place the line at.
 
364
     * @param y The vertical position to place the line at.
 
365
     * @param width The length of the line.
 
366
     * @param use_scaled_pos Whether to use absolute window positioning or take into account the 
 
367
     *      position of the scaled image.
 
368
     */
 
369
    public void draw_vertical_line(Cairo.Context ctx, int x, int y, int height, bool use_scaled_pos = true) {
 
370
        if (use_scaled_pos) {
 
371
            x += scaled_position.x;
 
372
            y += scaled_position.y;
 
373
        }
335
374
 
336
375
        ctx.move_to(x + 0.5, y + 0.5);
337
376
        ctx.line_to(x + 0.5, y + height - 1);
801
840
        return false;
802
841
    }
803
842
 
804
 
    private void on_width_insert_text(string text, int length, void *position) {
805
 
        on_entry_insert_text(crop_tool_window.custom_width_entry, text, length, position);
806
 
    }
807
 
 
808
 
    private void on_height_insert_text(string text, int length, void *position) {
809
 
        on_entry_insert_text(crop_tool_window.custom_height_entry, text, length, position);
810
 
    }
811
 
 
812
 
    private void on_entry_insert_text(Gtk.Entry sender, string text, int length, void *position) {
 
843
    private void on_width_insert_text(string text, int length, ref int position) {
 
844
        on_entry_insert_text(crop_tool_window.custom_width_entry, text, length, ref position);
 
845
    }
 
846
 
 
847
    private void on_height_insert_text(string text, int length, ref int position) {
 
848
        on_entry_insert_text(crop_tool_window.custom_height_entry, text, length, ref position);
 
849
    }
 
850
 
 
851
    private void on_entry_insert_text(Gtk.Entry sender, string text, int length, ref int position) {
813
852
        if (entry_insert_in_progress)
814
853
            return;
815
854
 
827
866
        }
828
867
 
829
868
        if (new_text.length > 0)
830
 
            sender.insert_text(new_text, (int) new_text.length, position);
 
869
            sender.insert_text(new_text, (int) new_text.length, ref position);
831
870
 
832
871
        Signal.stop_emission_by_name(sender, "insert-text");
833
872
 
961
1000
        if (user_aspect_ratio == ANY_ASPECT_RATIO)
962
1001
            return crop;
963
1002
 
964
 
        float scaled_width = (float) crop.get_width();
965
 
        float scaled_height = (float) crop.get_height();
966
 
        float scaled_center_x = ((float) crop.left) + (scaled_width / 2.0f);
967
 
        float scaled_center_y = ((float) crop.top) + (scaled_height / 2.0f);
968
 
        float scaled_aspect_ratio = scaled_width / scaled_height;
969
 
 
970
 
        // Crop positioning in the presence of constraint is a three-phase process
971
 
 
972
 
        // PHASE 1: Naively rescale the width and the height of the box so that it has the
973
 
        //          user-specified aspect ratio. Even in this initial transformation, the
974
 
        //          box's center and minor axis length are preserved. Preserving the center
975
 
        //          is especially important since this way the subject that the user has framed
976
 
        //          within the crop reticle is preserved.
977
 
        if (scaled_aspect_ratio > 1.0f)
978
 
            scaled_width = scaled_height;
979
 
        else
980
 
            scaled_height = scaled_width;
981
 
        scaled_width *= user_aspect_ratio;
982
 
 
983
 
        // PHASE 2: Now that the box has the correct aspect ratio, grow it or shrink it such
984
 
        //          that it has the same area that it had prior to constraint. This prevents
985
 
        //          the box from growing or shrinking erratically as constraints are set and
986
 
        //          unset.
 
1003
        // PHASE 1: Scale to the desired aspect ratio, preserving area and center.
987
1004
        float old_area = (float) (crop.get_width() * crop.get_height());
988
 
        float new_area = scaled_width * scaled_height;
989
 
        float area_correct_factor = (float) Math.sqrt(old_area / new_area);
990
 
        scaled_width *= area_correct_factor;
991
 
        scaled_height *= area_correct_factor;
992
 
 
993
 
        // PHASE 3: The new crop box may have edges that fall outside of the boundaries of
994
 
        //          the photo. Here, we rescale it such that it fits within the boundaries
995
 
        //          of the photo.
996
 
        int photo_right_edge = canvas.get_scaled_pixbuf_position().width - 1;
997
 
        int photo_bottom_edge = canvas.get_scaled_pixbuf_position().height - 1;
998
 
 
999
 
        int new_box_left = (int) ((scaled_center_x - (scaled_width / 2.0f)));
1000
 
        int new_box_right = (int) ((scaled_center_x + (scaled_width / 2.0f)));
1001
 
        int new_box_top = (int) ((scaled_center_y - (scaled_height / 2.0f)));
1002
 
        int new_box_bottom = (int) ((scaled_center_y + (scaled_height / 2.0f)));
1003
 
 
1004
 
        if(new_box_left < 0) new_box_left = 0;
1005
 
        if(new_box_top < 0) new_box_top = 0;
1006
 
        if(new_box_right > photo_right_edge) new_box_right = photo_right_edge;
1007
 
        if(new_box_bottom > photo_bottom_edge) new_box_bottom = photo_bottom_edge;
1008
 
 
1009
 
        Box new_crop_box = Box((int) (new_box_left),
1010
 
            (int) (new_box_top),
1011
 
            (int) (new_box_right),
1012
 
            (int) (new_box_bottom));
1013
 
 
1014
 
        return new_crop_box;
 
1005
        crop.adjust_height((int) Math.sqrt(old_area / user_aspect_ratio));
 
1006
        crop.adjust_width((int) Math.sqrt(old_area * user_aspect_ratio));
 
1007
        
 
1008
        // PHASE 2: Crop to the image boundary.
 
1009
        Dimensions image_size = get_photo_dimensions();
 
1010
        double angle;
 
1011
        canvas.get_photo().get_straighten(out angle);
 
1012
        crop = clamp_inside_rotated_image(crop, image_size.width, image_size.height, angle, false);
 
1013
 
 
1014
        // PHASE 3: Crop down to the aspect ratio if necessary.
 
1015
        if (crop.get_width() >= crop.get_height() * user_aspect_ratio)  // possibly too wide
 
1016
            crop.adjust_width((int) (crop.get_height() * user_aspect_ratio));
 
1017
        else    // possibly too tall
 
1018
            crop.adjust_height((int) (crop.get_width() / user_aspect_ratio));
 
1019
        
 
1020
        return crop;
1015
1021
    }
1016
1022
 
1017
1023
    public override void activate(PhotoCanvas canvas) {
1035
1041
 
1036
1042
        // set up the constraint combo box
1037
1043
        crop_tool_window.constraint_combo.set_model(constraint_list);
1038
 
        crop_tool_window.constraint_combo.set_active(Config.Facade.get_instance().get_last_crop_menu_choice());
1039
 
 
 
1044
        if(!canvas.get_photo().has_crop()) {
 
1045
            crop_tool_window.constraint_combo.set_active(Config.Facade.get_instance().get_last_crop_menu_choice());
 
1046
        }
 
1047
        
1040
1048
        // set up the pivot reticle button
1041
1049
        update_pivot_button_state();
1042
1050
        reticle_orientation = ReticleOrientation.LANDSCAPE;
1044
1052
        bind_window_handlers();
1045
1053
 
1046
1054
        // obtain crop dimensions and paint against the uncropped photo
1047
 
        Dimensions uncropped_dim = canvas.get_photo().get_original_dimensions();
 
1055
        Dimensions uncropped_dim = canvas.get_photo().get_dimensions(Photo.Exception.CROP);
1048
1056
 
1049
1057
        Box crop;
1050
1058
        if (!canvas.get_photo().get_crop(out crop)) {
1080
1088
        crop_tool_window.hide();
1081
1089
 
1082
1090
        // was 'custom' the most-recently-chosen menu item?
1083
 
        if (constraints[Config.Facade.get_instance().get_last_crop_menu_choice()].aspect_ratio ==
1084
 
            CUSTOM_ASPECT_RATIO) {
1085
 
            // yes, switch to custom mode, make the entry fields appear.
1086
 
            set_custom_constraint_mode();
 
1091
        if(!canvas.get_photo().has_crop()) {
 
1092
            if (constraints[Config.Facade.get_instance().get_last_crop_menu_choice()].aspect_ratio ==
 
1093
                CUSTOM_ASPECT_RATIO) {
 
1094
                // yes, switch to custom mode, make the entry fields appear.
 
1095
                set_custom_constraint_mode();
 
1096
            }
1087
1097
        }
1088
1098
 
1089
1099
        // since we no longer just run with the default, but rather
1189
1199
 
1190
1200
    public override Gdk.Pixbuf? get_display_pixbuf(Scaling scaling, Photo photo,
1191
1201
        out Dimensions max_dim) throws Error {
1192
 
        // show the uncropped photo for editing, but return null if no crop so the current pixbuf
1193
 
        // is used
1194
 
        if (!photo.has_crop()) {
1195
 
            max_dim = Dimensions();
1196
 
 
1197
 
            return null;
1198
 
        }
1199
 
 
1200
 
        max_dim = photo.get_original_dimensions();
 
1202
        max_dim = photo.get_dimensions(Photo.Exception.CROP);
1201
1203
 
1202
1204
        return photo.get_pixbuf_with_options(scaling, Photo.Exception.CROP);
1203
1205
    }
1204
1206
 
1205
1207
    private void prepare_ctx(Cairo.Context ctx, Dimensions dim) {
1206
1208
        wide_black_ctx = new Cairo.Context(ctx.get_target());
1207
 
        Gdk.cairo_set_source_color(wide_black_ctx, fetch_color("#000"));
 
1209
        set_source_color_from_string(wide_black_ctx, "#000");
1208
1210
        wide_black_ctx.set_line_width(1);
1209
1211
 
1210
1212
        wide_white_ctx = new Cairo.Context(ctx.get_target());
1211
 
        Gdk.cairo_set_source_color(wide_white_ctx, fetch_color("#FFF"));
 
1213
        set_source_color_from_string(wide_white_ctx, "#FFF");
1212
1214
        wide_white_ctx.set_line_width(1);
1213
1215
 
1214
1216
        thin_white_ctx = new Cairo.Context(ctx.get_target());
1215
 
        Gdk.cairo_set_source_color(thin_white_ctx, fetch_color("#FFF"));
 
1217
        set_source_color_from_string(thin_white_ctx, "#FFF");
1216
1218
        thin_white_ctx.set_line_width(0.5);
1217
1219
    }
1218
1220
 
1219
1221
    private void on_resized_pixbuf(Dimensions old_dim, Gdk.Pixbuf scaled, Gdk.Rectangle scaled_position) {
1220
1222
        Dimensions new_dim = Dimensions.for_pixbuf(scaled);
1221
 
        Dimensions uncropped_dim = canvas.get_photo().get_original_dimensions();
 
1223
        Dimensions uncropped_dim = canvas.get_photo().get_dimensions(Photo.Exception.CROP);
1222
1224
 
1223
1225
        // rescale to full crop
1224
1226
        Box crop = scaled_crop.get_scaled_similar(old_dim, uncropped_dim);
1313
1315
        // scale screen-coordinate crop to photo's coordinate system
1314
1316
        Box crop = scaled_crop.get_scaled_similar(
1315
1317
            Dimensions.for_rectangle(canvas.get_scaled_pixbuf_position()),
1316
 
            canvas.get_photo().get_original_dimensions());
 
1318
            canvas.get_photo().get_dimensions(Photo.Exception.CROP));
1317
1319
 
1318
1320
        // crop the current pixbuf and offer it to the editing host
1319
1321
        Gdk.Pixbuf cropped = new Gdk.Pixbuf.subpixbuf(canvas.get_scaled_pixbuf(), scaled_crop.left,
1380
1382
        }
1381
1383
    }
1382
1384
 
1383
 
    private void revert_crop(out int left, out int top, out int right, out int bottom) {
1384
 
        left = scaled_crop.left;
1385
 
        top = scaled_crop.top;
1386
 
        right = scaled_crop.right;
1387
 
        bottom = scaled_crop.bottom;
1388
 
    }
1389
 
 
1390
1385
    private int eval_radial_line(double center_x, double center_y, double bounds_x,
1391
1386
        double bounds_y, double user_x) {
1392
1387
        double decision_slope = (bounds_y - center_y) / (bounds_x - center_x);
1395
1390
        return (int) (decision_slope * user_x + decision_intercept);
1396
1391
    }
1397
1392
 
 
1393
    // Return the dimensions of the uncropped source photo scaled to canvas coordinates.
 
1394
    private Dimensions get_photo_dimensions() {
 
1395
        Dimensions photo_dims = canvas.get_photo().get_dimensions(Photo.Exception.CROP);
 
1396
        Dimensions surface_dims = canvas.get_surface_dim();
 
1397
        double scale_factor = double.min((double) surface_dims.width / photo_dims.width,
 
1398
                                         (double) surface_dims.height / photo_dims.height);
 
1399
        scale_factor = double.min(scale_factor, 1.0);
 
1400
 
 
1401
        photo_dims = canvas.get_photo().get_dimensions(
 
1402
            Photo.Exception.CROP | Photo.Exception.STRAIGHTEN);
 
1403
 
 
1404
        return { (int) (photo_dims.width * scale_factor),
 
1405
                 (int) (photo_dims.height * scale_factor) };
 
1406
    }
 
1407
 
1398
1408
    private bool on_canvas_manipulation(int x, int y) {
1399
1409
        Gdk.Rectangle scaled_pos = canvas.get_scaled_pixbuf_position();
1400
1410
 
1420
1430
        int bottom = scaled_crop.bottom;
1421
1431
 
1422
1432
        // get extra geometric information needed to enforce constraints
1423
 
        int photo_right_edge = canvas.get_scaled_pixbuf().width - 1;
1424
 
        int photo_bottom_edge = canvas.get_scaled_pixbuf().height - 1;
1425
1433
        int center_x = (left + right) / 2;
1426
1434
        int center_y = (top + bottom) / 2;
1427
1435
 
1590
1598
        // constraint).
1591
1599
        int width = right - left + 1;
1592
1600
        int height = bottom - top + 1;
 
1601
 
 
1602
        Dimensions photo_dims = get_photo_dimensions();
 
1603
        double angle;
 
1604
        canvas.get_photo().get_straighten(out angle);
 
1605
        
 
1606
        Box new_crop;
1593
1607
        if (get_constraint_aspect_ratio() == ANY_ASPECT_RATIO) {
1594
 
            if (left < 0)
1595
 
                left = 0;
1596
 
            if (top < 0)
1597
 
                top = 0;
1598
 
            if (right > photo_right_edge)
1599
 
                right = photo_right_edge;
1600
 
            if (bottom > photo_bottom_edge)
1601
 
                bottom = photo_bottom_edge;
1602
 
 
1603
1608
            width = right - left + 1;
1604
1609
            height = bottom - top + 1;
1605
1610
 
1640
1645
                default:
1641
1646
                break;
1642
1647
            }
 
1648
 
 
1649
            // preliminary crop region has been chosen, now clamp it inside the
 
1650
            // image as needed.
 
1651
 
 
1652
            new_crop = clamp_inside_rotated_image(
 
1653
                Box(left, top, right, bottom),
 
1654
                photo_dims.width, photo_dims.height, angle,
 
1655
                in_manipulation == BoxLocation.INSIDE);
 
1656
                
1643
1657
        } else {
1644
 
            if ((left < 0) || (top < 0) || (right > photo_right_edge) ||
1645
 
                (bottom > photo_bottom_edge) || (width < CROP_MIN_SIZE) ||
1646
 
                (height < CROP_MIN_SIZE)) {
1647
 
                    revert_crop(out left, out top, out right, out bottom);
 
1658
            // one of the constrained modes is active; revert instead of clamping so
 
1659
            // that aspect ratio stays intact
 
1660
 
 
1661
            new_crop = Box(left, top, right, bottom);
 
1662
            Box adjusted = clamp_inside_rotated_image(new_crop,
 
1663
                photo_dims.width, photo_dims.height, angle,
 
1664
                in_manipulation == BoxLocation.INSIDE);
 
1665
            
 
1666
            if (adjusted != new_crop || width < CROP_MIN_SIZE || height < CROP_MIN_SIZE) {
 
1667
                new_crop = scaled_crop;     // revert crop move
1648
1668
            }
1649
1669
        }
1650
1670
 
1651
 
        Box new_crop = Box(left, top, right, bottom);
1652
 
 
1653
1671
        if (in_manipulation != BoxLocation.INSIDE)
1654
1672
            crop_resized(new_crop);
1655
1673
        else
1707
1725
        erase_crop_tool(scaled_crop);
1708
1726
        canvas.invalidate_area(scaled_crop);
1709
1727
 
1710
 
        Box scaled_horizontal;
1711
 
        Box scaled_vertical;
1712
 
        Box new_horizontal;
1713
 
        Box new_vertical;
1714
 
        BoxComplements complements = scaled_crop.shifted_complements(new_crop, out scaled_horizontal,
1715
 
            out scaled_vertical, out new_horizontal, out new_vertical);
1716
 
 
1717
 
        if (complements == BoxComplements.HORIZONTAL || complements == BoxComplements.BOTH) {
1718
 
            // paint in the horizontal complements appropriately
1719
 
            set_area_alpha(scaled_horizontal, 0.5);
1720
 
            set_area_alpha(new_horizontal, 0.0);
1721
 
        }
1722
 
 
1723
 
        if (complements == BoxComplements.VERTICAL || complements == BoxComplements.BOTH) {
1724
 
            // paint in vertical complements appropriately
1725
 
            set_area_alpha(scaled_vertical, 0.5);
1726
 
            set_area_alpha(new_vertical, 0.0);
1727
 
        }
1728
 
 
1729
 
        if (complements == BoxComplements.NONE) {
1730
 
            // this means the two boxes have no intersection, not that they're equal ... since
1731
 
            // there's no intersection, fill in both new and old with apropriate pixbufs
1732
 
            set_area_alpha(scaled_crop, 0.5);
1733
 
            set_area_alpha(new_crop, 0.0);
1734
 
        }
 
1728
        set_area_alpha(scaled_crop, 0.5);
 
1729
        set_area_alpha(new_crop, 0.0);
 
1730
 
1735
1731
 
1736
1732
        // paint crop in new location
1737
1733
        paint_crop_tool(new_crop);
2436
2432
    }
2437
2433
 
2438
2434
    public static Gdk.Rectangle to_bounds_rect(EditingTools.RedeyeInstance inst) {
2439
 
        Gdk.Rectangle result = {0};
 
2435
        Gdk.Rectangle result = Gdk.Rectangle();
2440
2436
        result.x = inst.center.x - inst.radius;
2441
2437
        result.y = inst.center.y - inst.radius;
2442
2438
        result.width = 2 * inst.radius;
2534
2530
 
2535
2531
    private void prepare_ctx(Cairo.Context ctx, Dimensions dim) {
2536
2532
        wider_gray_ctx = new Cairo.Context(ctx.get_target());
2537
 
        Gdk.cairo_set_source_color(wider_gray_ctx, fetch_color("#111"));
 
2533
        set_source_color_from_string(wider_gray_ctx, "#111");
2538
2534
        wider_gray_ctx.set_line_width(3);
2539
2535
 
2540
2536
        thin_white_ctx = new Cairo.Context(ctx.get_target());
2541
 
        Gdk.cairo_set_source_color(thin_white_ctx, fetch_color("#FFF"));
 
2537
        set_source_color_from_string(thin_white_ctx, "#FFF");
2542
2538
        thin_white_ctx.set_line_width(1);
2543
2539
    }
2544
2540
 
2566
2562
            canvas.user_to_active_rect(bounds_rect_user);
2567
2563
        Gdk.Rectangle bounds_rect_unscaled =
2568
2564
            canvas.active_to_unscaled_rect(bounds_rect_active);
 
2565
        Gdk.Rectangle bounds_rect_raw =
 
2566
            canvas.unscaled_to_raw_rect(bounds_rect_unscaled);
2569
2567
 
2570
 
        RedeyeInstance instance_unscaled =
2571
 
            RedeyeInstance.from_bounds_rect(bounds_rect_unscaled);
 
2568
        RedeyeInstance instance_raw =
 
2569
            RedeyeInstance.from_bounds_rect(bounds_rect_raw);
2572
2570
 
2573
2571
        // transform screen coords back to image coords,
2574
2572
        // taking into account straightening angle.
2575
 
        int img_w = canvas.get_photo().get_master_dimensions().width;
2576
 
        int img_h = canvas.get_photo().get_master_dimensions().height;
 
2573
        Dimensions dimensions = canvas.get_photo().get_dimensions(
 
2574
            Photo.Exception.STRAIGHTEN | Photo.Exception.CROP);
2577
2575
 
2578
2576
        double theta = 0.0;
2579
2577
 
2580
2578
        canvas.get_photo().get_straighten(out theta);
2581
2579
 
2582
 
        instance_unscaled.center = rotate_point_arb(instance_unscaled.center, img_w, img_h, theta);
 
2580
        instance_raw.center = derotate_point_arb(instance_raw.center,
 
2581
                                                 dimensions.width, dimensions.height, theta);
2583
2582
 
2584
 
        RedeyeCommand command = new RedeyeCommand(canvas.get_photo(), instance_unscaled,
 
2583
        RedeyeCommand command = new RedeyeCommand(canvas.get_photo(), instance_raw,
2585
2584
            Resources.RED_EYE_LABEL, Resources.RED_EYE_TOOLTIP);
2586
2585
        AppWindow.get_command_manager().execute(command);
2587
2586
    }