2 * This file is part of RawTherapee.
4 * Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
6 * RawTherapee is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * RawTherapee is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
19 #include <cropwindow.h>
24 #include <imagearea.h>
25 #include <cursormanager.h>
34 ZoomStep zoomSteps
[] = {"10%", 0.1, 10,
49 #define MAXZOOMSTEPS 14
52 CropWindow::CropWindow (ImageArea
* parent
, rtengine::StagedImageProcessor
* ipc_
)
53 : iarea(parent
), cropgl(NULL
), xpos(30), ypos(30), imgX(0), imgY(0), imgW(1), imgH(1),
54 titleHeight(30), sideBorderWidth(3), upperBorderWidth(1), lowerBorderWidth(3), sepWidth(2),
55 cropZoom(ZOOM11INDEX
), deleted(false), onResizeArea(false), fitZoom(false),
56 fitZoomEnabled(true), decorated(true), backColor(0), observedCropWin(NULL
),
59 Glib::RefPtr
<Pango::Context
> context
= parent
->get_pango_context () ;
60 Pango::FontDescription fontd
= context
->get_font_description ();
61 fontd
.set_weight (Pango::WEIGHT_BOLD
);
62 fontd
.set_size(8*Pango::SCALE
);
63 context
->set_font_description (fontd
);
65 Glib::RefPtr
<Pango::Layout
> cllayout
= parent
->create_pango_layout("1000%");
68 cllayout
->get_pixel_size (iw
, ih
);
72 resizeSurface
= Cairo::ImageSurface::create_from_png (GET_DATA_PATH(argv0
)+"/images/resize.png");
73 bZoomIn
= new LWButton (Cairo::ImageSurface::create_from_png (GET_DATA_PATH(argv0
)+"/images/gtk-zoom-in.png"), 0, NULL
, LWButton::Left
, LWButton::Center
, "Zoom In");
74 bZoomOut
= new LWButton (Cairo::ImageSurface::create_from_png (GET_DATA_PATH(argv0
)+"/images/gtk-zoom-out.png"), 1, NULL
, LWButton::Left
, LWButton::Center
, "Zoom Out");
75 bZoom100
= new LWButton (Cairo::ImageSurface::create_from_png (GET_DATA_PATH(argv0
)+"/images/gtk-zoom-100.png"), 2, NULL
, LWButton::Left
, LWButton::Center
, "Zoom 100/%");
76 bZoomFit
= new LWButton (Cairo::ImageSurface::create_from_png (GET_DATA_PATH(argv0
)+"/images/gtk-zoom-fit.png"), 3, NULL
, LWButton::Left
, LWButton::Center
, "Zoom Fit");
77 bClose
= new LWButton (Cairo::ImageSurface::create_from_png (GET_DATA_PATH(argv0
)+"/images/gtk-close.png"), 4, NULL
, LWButton::Right
, LWButton::Center
, "Close");
79 buttonSet
.add (bZoomIn
);
80 buttonSet
.add (bZoomOut
);
81 buttonSet
.add (bZoom100
);
82 buttonSet
.add (bClose
);
84 buttonSet
.setColors (Gdk::Color("black"), Gdk::Color("white"));
85 buttonSet
.setButtonListener (this);
88 buttonSet
.getMinimalDimensions (bsw
, bsh
);
93 minWidth
= bsw
+ iw
+ 2*sideBorderWidth
;
96 cropHandler
.newImage (ipc_
);
97 cropHandler
.setPosition (0,0);
98 cropHandler
.setEnabled (true);
99 cropHandler
.setCropHandlerListener (this);
103 CropWindow::~CropWindow () {
107 void CropWindow::setPosition (int x
, int y
) {
114 buttonSet
.arrangeButtons (xpos
+ sideBorderWidth
, ypos
+ upperBorderWidth
, width
- 2*sideBorderWidth
, titleHeight
);
117 void CropWindow::getPosition (int& x
, int& y
) {
123 void CropWindow::getCropPosition (int& x
, int& y
) {
126 cropHandler
.getPosition (cropX
, cropY
);
127 if (state
!=SCropImgMove
) {
132 x
= cropX
+ action_x
;
133 y
= cropY
+ action_y
;
137 void CropWindow::getCropRectangle (int& x
, int& y
, int& w
, int& h
) {
139 int cropX
, cropY
, cropW
, cropH
;
140 cropHandler
.getPosition (cropX
, cropY
);
141 cropHandler
.getSize (cropW
, cropH
);
142 if (state
!=SCropImgMove
) {
147 x
= cropX
+ action_x
;
148 y
= cropY
+ action_y
;
150 if (state
!=SCropWinResize
) {
158 cropHandler
.cutRectToImgBounds (x
, y
, w
, h
);
161 void CropWindow::setCropPosition (int x
, int y
) {
163 cropHandler
.setPosition (x
, y
);
164 for (std::list
<CropWindowListener
*>::iterator i
=listeners
.begin(); i
!=listeners
.end(); i
++)
165 (*i
)->cropPositionChanged (this);
168 void CropWindow::setSize (int w
, int h
, bool norefresh
) {
181 imgAreaX
= sideBorderWidth
;
182 imgAreaY
= upperBorderWidth
+ titleHeight
+ sepWidth
;
183 imgAreaW
= width
- 2*sideBorderWidth
;
184 imgAreaH
= height
- lowerBorderWidth
- titleHeight
- sepWidth
- upperBorderWidth
;
185 buttonSet
.arrangeButtons (xpos
+ sideBorderWidth
, ypos
+ upperBorderWidth
, width
- 2*sideBorderWidth
, titleHeight
);
188 imgAreaX
= imgAreaY
= 0;
195 cropHandler
.setWSize (imgAreaW
, imgAreaH
);
199 void CropWindow::getSize (int& w
, int& h
) {
205 void CropWindow::getCropSize (int& w
, int& h
) {
211 bool CropWindow::isInside (int x
, int y
) {
213 return x
>=xpos
&& x
<xpos
+width
&& y
>=ypos
&& y
<ypos
+height
;
216 void CropWindow::buttonPress (int button
, int type
, int bstate
, int x
, int y
) {
218 iarea
->grabFocus (this);
219 if (button
==1 && type
==GDK_2BUTTON_PRESS
&& onArea (CropImage
, x
, y
) && (state
==SNormal
|| state
==SCropImgMove
)) {
220 if (fitZoomEnabled
) {
222 translateCoord (x
, y
, action_x
, action_y
);
223 changeZoom (ZOOM11INDEX
, true, action_x
, action_y
);
233 else if (button
==1 && type
==GDK_2BUTTON_PRESS
&& onArea (CropBorder
, x
, y
)) {
234 backColor
= (backColor
+1) % 3;
236 else if (button
==1 && type
==GDK_BUTTON_PRESS
&& state
==SNormal
&& onArea (CropToolBar
, x
, y
)) {
237 if (!decorated
|| !buttonSet
.pressNotify (x
, y
)) {
238 state
= SCropWinMove
;
245 else if (button
==1 && type
==GDK_BUTTON_PRESS
&& state
==SNormal
&& onArea (CropResize
, x
, y
)) {
246 state
= SCropWinResize
;
252 else if (button
==1 && type
==GDK_BUTTON_PRESS
&& state
==SNormal
&& onArea (CropImage
, x
, y
)) {
253 if (onArea (CropTop
, x
, y
)) {
256 action_y
= cropHandler
.cropParams
.y
;
258 else if (onArea (CropBottom
, x
, y
)) {
261 action_y
= cropHandler
.cropParams
.h
;
263 else if (onArea (CropLeft
, x
, y
)) {
266 action_x
= cropHandler
.cropParams
.x
;
268 else if (onArea (CropRight
, x
, y
)) {
271 action_x
= cropHandler
.cropParams
.w
;
273 else if (onArea (CropObserved
, x
, y
)) {
274 state
= SObservedMove
;
278 else if ((bstate
& GDK_SHIFT_MASK
) && onArea (CropInside
, x
, y
)) {
282 action_x
= cropHandler
.cropParams
.x
;
283 action_y
= cropHandler
.cropParams
.y
;
285 else if (iarea
->getToolMode () == TMHand
) {
286 state
= SCropImgMove
;
292 else if (iarea
->getToolMode () == TMStraighten
) {
293 state
= SRotateSelecting
;
300 else if (iarea
->getToolMode () == TMSpotWB
) {
301 translateCoord (x
, y
, action_x
, action_y
);
302 iarea
->spotWBSelected (action_x
, action_y
);
304 else if (iarea
->getToolMode () == TMCropSelect
&& cropgl
) {
305 state
= SCropSelecting
;
306 translateCoord (x
, y
, press_x
, press_y
);
307 cropHandler
.cropParams
.x
= press_x
;
308 cropHandler
.cropParams
.y
= press_y
;
309 cropHandler
.cropParams
.w
= cropHandler
.cropParams
.h
= 1;
310 cropgl
->cropInit (cropHandler
.cropParams
.x
, cropHandler
.cropParams
.y
, cropHandler
.cropParams
.w
, cropHandler
.cropParams
.h
);
315 iarea
->setToolHand ();
321 void CropWindow::buttonRelease (int button
, int num
, int bstate
, int x
, int y
) {
323 if (state
==SCropWinResize
) {
324 setSize (press_x
+ x
- action_x
, press_y
+ y
- action_y
);
326 for (std::list
<CropWindowListener
*>::iterator i
=listeners
.begin(); i
!=listeners
.end(); i
++)
327 (*i
)->cropWindowSizeChanged (this);
329 else if (state
==SCropImgMove
) {
331 cropHandler
.getPosition (cropX
, cropY
);
332 cropHandler
.setPosition (cropX
+ action_x
, cropY
+ action_y
);
333 cropHandler
.getPosition (cropX
, cropY
);
335 for (std::list
<CropWindowListener
*>::iterator i
=listeners
.begin(); i
!=listeners
.end(); i
++)
336 (*i
)->cropPositionChanged (this);
338 else if (state
==SRotateSelecting
) {
339 iarea
->straightenReady (rot_deg
);
340 iarea
->setToolHand ();
342 else if (state
==SObservedMove
) {
343 observedCropWin
->remoteMoveReady ();
346 if (cropgl
&& (state
==SCropSelecting
|| state
==SResizeH1
|| state
==SResizeH2
|| state
==SResizeW1
|| state
==SResizeW2
|| state
==SCropMove
)) {
347 cropgl
->cropManipReady ();
348 iarea
->setToolHand ();
352 buttonSet
.releaseNotify (x
, y
);
357 iarea
->grabFocus (NULL
);
362 void CropWindow::pointerMoved (int x
, int y
) {
364 if (state
==SCropWinMove
) {
365 setPosition (press_x
+ x
- action_x
, press_y
+ y
- action_y
);
368 else if (state
==SCropWinResize
) {
369 setSize (press_x
+ x
- action_x
, press_y
+ y
- action_y
, true);
370 for (std::list
<CropWindowListener
*>::iterator i
=listeners
.begin(); i
!=listeners
.end(); i
++)
371 (*i
)->cropWindowSizeChanged (this);
374 else if (state
==SCropImgMove
) {
375 action_x
= (press_x
- x
) / zoomSteps
[cropZoom
].zoom
;
376 action_y
= (press_y
- y
) / zoomSteps
[cropZoom
].zoom
;
377 for (std::list
<CropWindowListener
*>::iterator i
=listeners
.begin(); i
!=listeners
.end(); i
++)
378 (*i
)->cropPositionChanged (this);
381 else if (state
==SRotateSelecting
) {
386 else if (state
==SNormal
&& iarea
->getToolMode () == TMSpotWB
) {
391 else if (state
==SResizeH1
&& cropgl
) {
392 int oy
= cropHandler
.cropParams
.y
;
393 cropHandler
.cropParams
.y
= action_y
+ (y
-press_y
) / zoomSteps
[cropZoom
].zoom
;
394 cropHandler
.cropParams
.h
+= oy
- cropHandler
.cropParams
.y
;
395 cropgl
->cropHeight1Resized (cropHandler
.cropParams
.x
, cropHandler
.cropParams
.y
, cropHandler
.cropParams
.w
, cropHandler
.cropParams
.h
);
398 else if (state
==SResizeH2
&& cropgl
) {
399 cropHandler
.cropParams
.h
= action_y
+ (y
-press_y
) / zoomSteps
[cropZoom
].zoom
;
400 cropgl
->cropHeight2Resized (cropHandler
.cropParams
.x
, cropHandler
.cropParams
.y
, cropHandler
.cropParams
.w
, cropHandler
.cropParams
.h
);
403 else if (state
==SResizeW1
&& cropgl
) {
404 int ox
= cropHandler
.cropParams
.x
;
405 cropHandler
.cropParams
.x
= action_x
+ (x
-press_x
) / zoomSteps
[cropZoom
].zoom
;
406 cropHandler
.cropParams
.w
+= ox
- cropHandler
.cropParams
.x
;
407 cropgl
->cropWidth1Resized (cropHandler
.cropParams
.x
, cropHandler
.cropParams
.y
, cropHandler
.cropParams
.w
, cropHandler
.cropParams
.h
);
410 else if (state
==SResizeW2
&& cropgl
) {
411 cropHandler
.cropParams
.w
= action_x
+ (x
-press_x
) / zoomSteps
[cropZoom
].zoom
;
412 cropgl
->cropWidth2Resized (cropHandler
.cropParams
.x
, cropHandler
.cropParams
.y
, cropHandler
.cropParams
.w
, cropHandler
.cropParams
.h
);
415 else if (state
==SCropMove
&& cropgl
) {
416 cropHandler
.cropParams
.x
= action_x
+ (x
-press_x
) / zoomSteps
[cropZoom
].zoom
;
417 cropHandler
.cropParams
.y
= action_y
+ (y
-press_y
) / zoomSteps
[cropZoom
].zoom
;
418 cropgl
->cropMoved (cropHandler
.cropParams
.x
, cropHandler
.cropParams
.y
, cropHandler
.cropParams
.w
, cropHandler
.cropParams
.h
);
421 else if (state
==SCropSelecting
&& cropgl
) {
422 translateCoord (x
, y
, action_x
, action_y
);
423 int cx1
= press_x
, cy1
= press_y
;
424 int cx2
= action_x
, cy2
= action_y
;
425 cropgl
->cropResized (cx1
, cy1
, cx2
, cy2
);
427 cropHandler
.cropParams
.x
= cx1
;
428 cropHandler
.cropParams
.w
= cx2
- cx1
+ 1;
431 cropHandler
.cropParams
.x
= cx2
;
432 cropHandler
.cropParams
.w
= cx1
- cx2
+ 1;
435 cropHandler
.cropParams
.y
= cy1
;
436 cropHandler
.cropParams
.h
= cy2
- cy1
+ 1;
439 cropHandler
.cropParams
.y
= cy2
;
440 cropHandler
.cropParams
.h
= cy1
- cy2
+ 1;
444 else if (state
==SObservedMove
) {
445 observedCropWin
->remoteMove ((x
- press_x
)/zoomSteps
[cropZoom
].zoom
, (y
- press_y
)/zoomSteps
[cropZoom
].zoom
);
450 bool oRA
= onArea (CropResize
, x
, y
);
451 if (oRA
!=onResizeArea
) {
457 buttonSet
.motionNotify (x
, y
);
461 translateCoord (x
, y
, mx
, my
);
462 if (!onArea (CropImage
, x
, y
) || !cropHandler
.cropPixbuf
)
463 pmlistener
->pointerMoved (false, mx
, my
, -1, -1, -1);
465 cropHandler
.cimg
.lock ();
466 int vx
= x
- xpos
- imgX
;
467 int vy
= y
- ypos
- imgY
;
468 guint8
* pix
= cropHandler
.cropPixbuf
->get_pixels() + vy
*cropHandler
.cropPixbuf
->get_rowstride() + vx
*3;
469 if (vx
< cropHandler
.cropPixbuf
->get_width() && vy
< cropHandler
.cropPixbuf
->get_height())
470 pmlistener
->pointerMoved (true, mx
, my
, pix
[0], pix
[1], pix
[2]);
471 cropHandler
.cimg
.unlock ();
476 bool CropWindow::onArea (CursorArea a
, int x
, int y
) {
478 int CROPRESIZEBORDER
= 6 / zoomSteps
[cropZoom
].zoom
;
482 return decorated
&& buttonSet
.inside (x
, y
);
484 return x
>xpos
&& y
>ypos
&& x
<xpos
+width
-1 && y
<ypos
+imgAreaY
;
486 return x
>=xpos
+imgX
&& y
>=ypos
+imgY
&& x
<xpos
+imgX
+imgW
&& y
<ypos
+imgY
+imgH
;
489 (x
>=xpos
+imgAreaX
&& y
>=ypos
+imgAreaY
&& x
<xpos
+imgAreaX
+imgAreaW
&& y
<ypos
+imgAreaY
+imgAreaH
) &&
490 !(x
>=xpos
+imgX
&& y
>=ypos
+imgY
&& x
<xpos
+imgX
+imgW
&& y
<ypos
+imgY
+imgH
);
492 translateCoord (x
, y
, x1
, y1
);
493 return cropHandler
.cropParams
.enabled
&&
494 x1
>cropHandler
.cropParams
.x
+CROPRESIZEBORDER
&&
495 x1
<cropHandler
.cropParams
.x
+cropHandler
.cropParams
.w
-1-CROPRESIZEBORDER
&&
496 y1
>cropHandler
.cropParams
.y
-CROPRESIZEBORDER
&&
497 y1
<cropHandler
.cropParams
.y
+CROPRESIZEBORDER
;
499 translateCoord (x
, y
, x1
, y1
);
500 return cropHandler
.cropParams
.enabled
&&
501 x1
>cropHandler
.cropParams
.x
+CROPRESIZEBORDER
&&
502 x1
<cropHandler
.cropParams
.x
+cropHandler
.cropParams
.w
-1-CROPRESIZEBORDER
&&
503 y1
>cropHandler
.cropParams
.y
+cropHandler
.cropParams
.h
-1-CROPRESIZEBORDER
&&
504 y1
<cropHandler
.cropParams
.y
+cropHandler
.cropParams
.h
-1+CROPRESIZEBORDER
;
506 translateCoord (x
, y
, x1
, y1
);
507 return cropHandler
.cropParams
.enabled
&&
508 y1
>cropHandler
.cropParams
.y
+CROPRESIZEBORDER
&&
509 y1
<cropHandler
.cropParams
.y
+cropHandler
.cropParams
.h
-1-CROPRESIZEBORDER
&&
510 x1
>cropHandler
.cropParams
.x
-CROPRESIZEBORDER
&&
511 x1
<cropHandler
.cropParams
.x
+CROPRESIZEBORDER
;
513 translateCoord (x
, y
, x1
, y1
);
514 return cropHandler
.cropParams
.enabled
&&
515 y1
>cropHandler
.cropParams
.y
+CROPRESIZEBORDER
&&
516 y1
<cropHandler
.cropParams
.y
+cropHandler
.cropParams
.h
-1-CROPRESIZEBORDER
&&
517 x1
>cropHandler
.cropParams
.x
+cropHandler
.cropParams
.w
-1-CROPRESIZEBORDER
&&
518 x1
<cropHandler
.cropParams
.x
+cropHandler
.cropParams
.w
-1+CROPRESIZEBORDER
;
520 translateCoord (x
, y
, x1
, y1
);
521 return cropHandler
.cropParams
.enabled
&&
522 y1
>cropHandler
.cropParams
.y
&&
523 y1
<cropHandler
.cropParams
.y
+cropHandler
.cropParams
.h
-1 &&
524 x1
>cropHandler
.cropParams
.x
&&
525 x1
<cropHandler
.cropParams
.x
+cropHandler
.cropParams
.w
-1;
527 return decorated
&& x
>=xpos
+width
-16 && y
>=ypos
+height
-16 && x
<xpos
+width
&& y
<ypos
+height
;
529 if (!observedCropWin
)
531 getObservedFrameArea (x1
, y1
, w
, h
);
532 return x
>x1
-6 && y
>y1
-6 && x
<x1
+w
-1+6 && y
<y1
+h
-1+6 &&
533 !(x
>x1
+2 && y
>y1
+2 && x
<x1
+w
-1-2 && y
<y1
+h
-1-2);
538 void CropWindow::updateCursor (int x
, int y
) {
540 ToolMode tm
= iarea
->getToolMode ();
542 if (state
==SNormal
) {
543 if (onArea (CropWinButtons
, x
, y
))
544 cursorManager
.setCursor (iarea
->get_window(), CSArrow
);
545 else if (onArea (CropToolBar
, x
, y
))
546 cursorManager
.setCursor (iarea
->get_window(), CSMove
);
547 else if (onArea (CropResize
, x
, y
))
548 cursorManager
.setCursor (iarea
->get_window(), CSResizeDiagonal
);
549 else if (tm
==TMHand
&& (onArea (CropTop
, x
, y
) || onArea (CropBottom
, x
, y
)))
550 cursorManager
.setCursor (iarea
->get_window(), CSResizeHeight
);
551 else if (tm
==TMHand
&& (onArea (CropLeft
, x
, y
) || onArea (CropRight
, x
, y
)))
552 cursorManager
.setCursor (iarea
->get_window(), CSResizeWidth
);
553 else if (onArea (CropImage
, x
, y
)) {
555 if (onArea (CropObserved
, x
, y
))
556 cursorManager
.setCursor (iarea
->get_window(), CSMove
);
558 cursorManager
.setCursor (iarea
->get_window(), CSOpenHand
);
560 else if (tm
==TMSpotWB
)
561 cursorManager
.setCursor (iarea
->get_window(), CSSpotWB
);
562 else if (tm
==TMCropSelect
)
563 cursorManager
.setCursor (iarea
->get_window(), CSCropSelect
);
564 else if (tm
==TMStraighten
)
565 cursorManager
.setCursor (iarea
->get_window(), CSStraighten
);
568 cursorManager
.setCursor (iarea
->get_window(), CSArrow
);
570 else if (state
==SCropSelecting
)
571 cursorManager
.setCursor (iarea
->get_window(), CSCropSelect
);
572 else if (state
==SRotateSelecting
)
573 cursorManager
.setCursor (iarea
->get_window(), CSStraighten
);
574 else if (state
==SCropMove
|| state
==SCropWinMove
|| state
==SObservedMove
)
575 cursorManager
.setCursor (iarea
->get_window(), CSMove
);
576 else if (state
==SHandMove
|| state
==SCropImgMove
)
577 cursorManager
.setCursor (iarea
->get_window(), CSClosedHand
);
578 else if (state
==SResizeW1
|| state
==SResizeW2
)
579 cursorManager
.setCursor (iarea
->get_window(), CSResizeWidth
);
580 else if (state
==SResizeH1
|| state
==SResizeH2
)
581 cursorManager
.setCursor (iarea
->get_window(), CSResizeHeight
);
582 else if (state
==SCropWinResize
)
583 cursorManager
.setCursor (iarea
->get_window(), CSResizeDiagonal
);
586 void CropWindow::expose (Cairo::RefPtr
<Cairo::Context
> cr
) {
588 MyTime t1
, t2
, t3
, t4
;
595 int x
= xpos
, y
= ypos
, h
= height
, w
= width
;
599 Gdk::Color cback
= iarea
->get_style()->get_bg(Gtk::STATE_NORMAL
);
600 cr
->set_source_rgb (cback
.get_red_p(), cback
.get_green_p(), cback
.get_blue_p());
602 else if (backColor
==1)
603 cr
->set_source_rgb (0,0,0);
604 else if (backColor
==2)
605 cr
->set_source_rgb (1,1,1);
607 cr
->rectangle (x
+imgAreaX
+0.5, y
+imgAreaY
+0.5, imgAreaW
, imgAreaH
);
608 cr
->stroke_preserve ();
611 cropHandler
.cimg
.lock ();
613 if (state
==SCropImgMove
|| state
==SCropWinResize
) {
614 // draw a rough image
616 cropHandler
.getPosition (cropX
, cropY
);
617 if (state
==SCropImgMove
) {
621 Glib::RefPtr
<Gdk::Pixbuf
> rough
= iarea
->getPreviewHandler()->getRoughImage (cropX
, cropY
, imgAreaW
, imgAreaH
, zoomSteps
[cropZoom
].zoom
);
623 iarea
->get_window()->draw_pixbuf (iarea
->get_style()->get_base_gc(Gtk::STATE_NORMAL
), rough
, 0, 0, x
+imgAreaX
+(imgAreaW
-rough
->get_width())/2, y
+imgAreaY
+(imgAreaH
-rough
->get_height())/2, -1, -1, Gdk::RGB_DITHER_NORMAL
, 0, 0);
624 // if (cropHandler.cropParams.enabled)
625 // drawCrop (cr, x+imgX, y+imgY, imgW, imgH, cropX, cropY, zoomSteps[cropZoom].zoom, cropHandler.cropParams);
629 if (cropHandler
.cropPixbuf
) {
630 imgW
= cropHandler
.cropPixbuf
->get_width ();
631 imgH
= cropHandler
.cropPixbuf
->get_height ();
632 imgX
= imgAreaX
+ (imgAreaW
-imgW
)/2;
633 imgY
= imgAreaY
+ (imgAreaH
-imgH
)/2;
634 // PERFORMANCE BOTTLENECK STARTS HERE
636 bool showcs
= iarea
->indClippedPanel
->showClippedShadows();
637 bool showch
= iarea
->indClippedPanel
->showClippedHighlights();
638 if (showcs
|| showch
) {
639 Glib::RefPtr
<Gdk::Pixbuf
> tmp
= cropHandler
.cropPixbuf
->copy ();
640 guint8
* pix
= tmp
->get_pixels();
641 for (int i
=0; i
<tmp
->get_height(); i
++)
642 for (int j
=0; j
<tmp
->get_width(); j
++) {
643 guint8
* curr
= pix
+ i
*tmp
->get_rowstride () + j
*3;
644 if (showch
&& (curr
[0]>=options
.highlightThreshold
|| curr
[1]>=options
.highlightThreshold
|| curr
[2]>=options
.highlightThreshold
))
645 curr
[0] = curr
[1] = curr
[2] = 0;
646 else if (showcs
&& (curr
[0]<=options
.shadowThreshold
|| curr
[1]<=options
.shadowThreshold
|| curr
[2]<=options
.shadowThreshold
))
647 curr
[0] = curr
[1] = curr
[2] = 255;
649 iarea
->get_window()->draw_pixbuf (iarea
->get_style()->get_base_gc(Gtk::STATE_NORMAL
), tmp
, 0, 0, x
+imgX
, y
+imgY
, -1, -1, Gdk::RGB_DITHER_NONE
, 0, 0);
652 iarea
->get_window()->draw_pixbuf (iarea
->get_style()->get_base_gc(Gtk::STATE_NORMAL
), cropHandler
.cropPixbuf
, 0, 0, x
+imgX
, y
+imgY
, -1, -1, Gdk::RGB_DITHER_NONE
, 0, 0);
655 if (cropHandler
.cropParams
.enabled
) {
657 cropHandler
.getPosition (cropX
, cropY
);
658 drawCrop (cr
, x
+imgX
, y
+imgY
, imgW
, imgH
, cropX
, cropY
, zoomSteps
[cropZoom
].zoom
, cropHandler
.cropParams
);
663 cropHandler
.getPosition (cropX
, cropY
);
664 Glib::RefPtr
<Gdk::Pixbuf
> rough
= iarea
->getPreviewHandler()->getRoughImage (cropX
, cropY
, imgAreaW
, imgAreaH
, zoomSteps
[cropZoom
].zoom
);
666 iarea
->get_window()->draw_pixbuf (iarea
->get_style()->get_base_gc(Gtk::STATE_NORMAL
), rough
, 0, 0, x
+imgAreaX
+(imgAreaW
-rough
->get_width())/2, y
+imgAreaY
+(imgAreaH
-rough
->get_height())/2, -1, -1, Gdk::RGB_DITHER_NORMAL
, 0, 0);
667 if (cropHandler
.cropParams
.enabled
) {
669 cropHandler
.getPosition (cropX
, cropY
);
670 drawCrop (cr
, x
+imgX
, y
+imgY
, imgW
, imgH
, cropX
, cropY
, zoomSteps
[cropZoom
].zoom
, cropHandler
.cropParams
);
677 drawObservedFrame (cr
);
679 // if cursor stays above resize area, draw the icon
680 if (decorated
&& (state
==SCropWinResize
|| onResizeArea
)) {
681 int rw
= resizeSurface
->get_width ();
682 int rh
= resizeSurface
->get_height ();
683 cr
->set_source_rgb (0.5,0.5,0.5);
684 cr
->rectangle (x
+w
-1.5-rw
-1, y
+h
-1.5-rh
-1, rw
+1, rh
+1);
685 cr
->stroke_preserve ();
687 cr
->set_source (resizeSurface
, x
+w
-1.5-rw
, y
+h
-1.5-rh
);
689 cr
->set_source_rgb (0,0,0);
690 cr
->move_to (x
+w
-2.5-rw
, y
+h
-1.5);
691 cr
->line_to (x
+w
-2.5-rw
, y
+h
-2.5-rh
);
692 cr
->line_to (x
+w
-1.5, y
+h
-2.5-rh
);
695 if (state
==SRotateSelecting
)
696 drawStraightenGuide (cr
);
697 if (state
==SNormal
&& iarea
->getToolMode () == TMSpotWB
)
698 drawSpotWBRectangle (cr
);
701 cropHandler
.cimg
.unlock ();
702 // printf ("etime --> %d, %d\n", t2.etime (t1), t4.etime (t3));
705 void CropWindow::zoomIn () {
707 changeZoom (cropZoom
+1);
711 void CropWindow::zoomOut () {
713 changeZoom (cropZoom
-1);
717 void CropWindow::zoom11 () {
719 changeZoom (ZOOM11INDEX
);
723 double CropWindow::getZoom () {
725 return zoomSteps
[cropZoom
].zoom
;
728 void CropWindow::setZoom (double zoom
) {
730 int cz
= MAXZOOMSTEPS
;
731 if (zoom
< zoomSteps
[0].zoom
)
734 for (int i
=0; i
<MAXZOOMSTEPS
; i
++)
735 if (zoomSteps
[i
].zoom
<= zoom
&& zoomSteps
[i
+1].zoom
> zoom
) {
739 changeZoom (cz
, false);
742 void CropWindow::zoomFit () {
744 double z
= cropHandler
.getFitZoom ();
745 int cz
= MAXZOOMSTEPS
;
746 if (z
< zoomSteps
[0].zoom
)
749 for (int i
=0; i
<MAXZOOMSTEPS
; i
++)
750 if (zoomSteps
[i
].zoom
<= z
&& zoomSteps
[i
+1].zoom
> z
) {
758 void CropWindow::buttonPressed (LWButton
* button
, int actionCode
, void* actionData
) {
760 if (button
==bZoomIn
) // zoom in
762 else if (button
==bZoomOut
) // zoom out
764 else if (button
==bZoom100
) // zoom 100
766 else if (button
==bClose
) {// close
768 iarea
->cropWindowClosed (this);
772 void CropWindow::redrawNeeded (LWButton
* button
) {
777 void CropWindow::changeZoom (int zoom
, bool notify
, int centerx
, int centery
) {
782 else if (cropZoom
>MAXZOOMSTEPS
)
783 cropZoom
= MAXZOOMSTEPS
;
785 cropLabel
= zoomSteps
[cropZoom
].label
;
786 cropHandler
.setZoom (zoomSteps
[cropZoom
].czoom
, centerx
, centery
);
788 for (std::list
<CropWindowListener
*>::iterator i
=listeners
.begin(); i
!=listeners
.end(); i
++)
789 (*i
)->cropZoomChanged (this);
793 void CropWindow::translateCoord (int phyx
, int phyy
, int& imgx
, int& imgy
) {
796 cropHandler
.getPosition (cropX
, cropY
);
797 imgx
= cropX
+ (phyx
- xpos
- imgX
)/zoomSteps
[cropZoom
].zoom
;
798 imgy
= cropY
+ (phyy
- ypos
- imgY
)/zoomSteps
[cropZoom
].zoom
;
801 void CropWindow::drawDecoration (Cairo::RefPtr
<Cairo::Context
> cr
) {
803 int x
= xpos
, y
= ypos
;
805 Glib::RefPtr
<Pango::Context
> context
= iarea
->get_pango_context () ;
806 Pango::FontDescription fontd
= context
->get_font_description ();
807 fontd
.set_weight (Pango::WEIGHT_BOLD
);
808 fontd
.set_size(8*Pango::SCALE
);
809 context
->set_font_description (fontd
);
810 Glib::RefPtr
<Pango::Layout
> cllayout
= iarea
->create_pango_layout(cropLabel
);
812 cllayout
->get_pixel_size (iw
, ih
);
814 // draw decoration (border)
815 int h
= height
, w
= width
;
816 cr
->set_source_rgb (0,0,0);
817 cr
->set_line_width (1.0);
818 cr
->move_to (x
+0.5, y
+h
-0.5);
819 cr
->line_to (x
+0.5, y
+0.5);
820 cr
->line_to (x
+w
-0.5, y
+0.5);
822 cr
->set_source_rgb (1,1,1);
823 cr
->move_to (x
+w
-0.5, y
+0.5);
824 cr
->line_to (x
+w
-0.5, y
+h
-0.5);
825 cr
->line_to (x
+0.5, y
+h
-0.5);
827 cr
->set_source_rgb (0.5,0.5,0.5);
828 cr
->rectangle (x
+1.5, y
+1.5+titleHeight
, w
-3, h
-titleHeight
-3);
830 cr
->set_source_rgb (1,1,1);
831 cr
->move_to (x
+2.5, y
+h
-2.5);
832 cr
->line_to (x
+2.5, y
+titleHeight
+2.5);
833 cr
->line_to (x
+w
-2.5, y
+titleHeight
+2.5);
835 cr
->set_source_rgb (0,0,0);
836 cr
->move_to (x
+w
-2.5, y
+titleHeight
+2.5);
837 cr
->line_to (x
+w
-2.5, y
+h
-2.5);
838 cr
->line_to (x
+2.5, y
+h
-2.5);
840 cr
->set_source_rgb (0.5,0.5,0.5);
841 cr
->rectangle (x
+1.5, y
+1.5, w
-3, titleHeight
);
842 cr
->stroke_preserve ();
846 cr
->set_source_rgb (1,1,1);
847 cr
->move_to (x
+6+sideBorderWidth
+bZoomIn
->getIcon()->get_width()+bZoomOut
->getIcon()->get_width()+bZoom100
->getIcon()->get_width(), y
+upperBorderWidth
+(titleHeight
-ih
)/2);
848 cllayout
->add_to_cairo_context (cr
);
851 buttonSet
.redraw (cr
);
854 void CropWindow::drawStraightenGuide (Cairo::RefPtr
<Cairo::Context
> cr
) {
856 if (action_x
!=press_x
|| action_y
!=press_y
) {
857 double arg
= (press_x
-action_x
) / sqrt((press_x
-action_x
)*(press_x
-action_x
)+(press_y
-action_y
)*(press_y
-action_y
));
860 if (press_y
>action_y
) {
861 sol1
= acos(arg
)*180/pi
;
862 sol2
= -acos(-arg
)*180/pi
;
865 sol1
= acos(-arg
)*180/pi
;
866 sol2
= -acos(arg
)*180/pi
;
868 if (fabs(sol1
)<fabs(sol2
))
874 rot_deg
= 90.0 + rot_deg
;
876 rot_deg
= - 90.0 + rot_deg
;
881 Glib::RefPtr
<Pango::Context
> context
= iarea
->get_pango_context () ;
882 Pango::FontDescription fontd
= context
->get_font_description ();
883 fontd
.set_weight (Pango::WEIGHT_BOLD
);
884 fontd
.set_size (8*Pango::SCALE
);
885 context
->set_font_description (fontd
);
886 Glib::RefPtr
<Pango::Layout
> deglayout
= iarea
->create_pango_layout(Glib::ustring::compose ("%1 deg", Glib::ustring::format(std::setprecision(2), rot_deg
)));
896 if (x2>=image->getWidth()) x2 = image->getWidth()-1;
897 if (y2>=image->getHeight()) y2 = image->getHeight()-1;
898 if (x1>=image->getWidth()) x1 = image->getWidth()-1;
899 if (y1>=image->getHeight()) y1 = image->getHeight()-1;
902 cr
->set_line_width (1.5);
903 cr
->set_source_rgb (1.0, 1.0, 1.0);
904 cr
->move_to (x1
, y1
);
905 cr
->line_to (x2
, y2
);
907 cr
->set_source_rgb (0.0, 0.0, 0.0);
908 std::valarray
<double> ds (1);
910 cr
->set_dash (ds
, 0);
911 cr
->move_to (x1
, y1
);
912 cr
->line_to (x2
, y2
);
915 if (press_x
!=action_x
&& press_y
!=action_y
) {
916 cr
->set_source_rgb (0.0, 0.0, 0.0);
917 cr
->move_to ((x1
+x2
)/2+1, (y1
+y2
)/2+1);
918 deglayout
->add_to_cairo_context (cr
);
919 cr
->move_to ((x1
+x2
)/2+1, (y1
+y2
)/2-1);
920 deglayout
->add_to_cairo_context (cr
);
921 cr
->move_to ((x1
+x2
)/2-1, (y1
+y2
)/2+1);
922 deglayout
->add_to_cairo_context (cr
);
923 cr
->move_to ((x1
+x2
)/2+1, (y1
+y2
)/2+1);
924 deglayout
->add_to_cairo_context (cr
);
926 cr
->set_source_rgb (1.0, 1.0, 1.0);
927 cr
->move_to ((x1
+x2
)/2, (y1
+y2
)/2);
928 deglayout
->add_to_cairo_context (cr
);
933 void CropWindow::drawSpotWBRectangle (Cairo::RefPtr
<Cairo::Context
> cr
) {
935 int rectsize
= iarea
->getSpotWBRectSize ();
936 int x1
= action_x
/zoomSteps
[cropZoom
].zoom
- rectsize
;
937 int y1
= action_y
/zoomSteps
[cropZoom
].zoom
- rectsize
;
938 int y2
= action_y
/zoomSteps
[cropZoom
].zoom
+ rectsize
;
939 int x2
= action_x
/zoomSteps
[cropZoom
].zoom
+ rectsize
;
941 cr
->set_line_width (1.0);
942 cr
->rectangle (xpos
+imgX
-0.5, ypos
+imgY
-0.5, imgW
, imgH
);
945 cr
->set_source_rgb (1.0, 1.0, 1.0);
946 cr
->rectangle (x1
*zoomSteps
[cropZoom
].zoom
-1.5, y1
*zoomSteps
[cropZoom
].zoom
-1.5, x2
*zoomSteps
[cropZoom
].zoom
-x1
*zoomSteps
[cropZoom
].zoom
+2, y2
*zoomSteps
[cropZoom
].zoom
-y1
*zoomSteps
[cropZoom
].zoom
+2);
948 cr
->set_source_rgb (0.0, 0.0, 0.0);
949 cr
->rectangle (x1
*zoomSteps
[cropZoom
].zoom
-0.5, y1
*zoomSteps
[cropZoom
].zoom
-0.5, x2
*zoomSteps
[cropZoom
].zoom
-x1
*zoomSteps
[cropZoom
].zoom
, y2
*zoomSteps
[cropZoom
].zoom
-y1
*zoomSteps
[cropZoom
].zoom
);
955 void CropWindow::getObservedFrameArea (int& x
, int& y
, int& w
, int& h
) {
957 int cropX
, cropY
, cropW
, cropH
;
958 observedCropWin
->getCropRectangle (cropX
, cropY
, cropW
, cropH
);
959 int myCropX
, myCropY
, myCropW
, myCropH
;
960 getCropRectangle (myCropX
, myCropY
, myCropW
, myCropH
);
962 // translate it to screen coordinates
963 x
= xpos
+ imgX
+ (cropX
-myCropX
)*zoomSteps
[cropZoom
].zoom
;
964 y
= ypos
+ imgY
+ (cropY
-myCropY
)*zoomSteps
[cropZoom
].zoom
;
965 w
= cropW
* zoomSteps
[cropZoom
].zoom
;
966 h
= cropH
* zoomSteps
[cropZoom
].zoom
;
969 void CropWindow::drawObservedFrame (Cairo::RefPtr
<Cairo::Context
> cr
) {
972 getObservedFrameArea (x
, y
, w
, h
);
974 cr
->set_source_rgb (1.0, 1.0, 1.0);
975 cr
->set_line_width (4);
976 cr
->rectangle (x
-2, y
-2, w
+4, h
+4);
978 cr
->set_source_rgb (1.0, 0.0, 0.0);
979 cr
->set_line_width (2);
980 cr
->rectangle (x
-2, y
-2, w
+4, h
+4);
984 void CropWindow::cropImageUpdated () {
989 void CropWindow::cropWindowChanged () {
992 iarea
->updateScrollbars ();
996 void CropWindow::initialImageArrived () {
998 for (std::list
<CropWindowListener
*>::iterator i
=listeners
.begin(); i
!=listeners
.end(); i
++)
999 (*i
)->initialImageArrived (this);
1003 void CropWindow::remoteMove (int deltaX
, int deltaY
) {
1005 state
= SCropImgMove
;
1008 for (std::list
<CropWindowListener
*>::iterator i
=listeners
.begin(); i
!=listeners
.end(); i
++)
1009 (*i
)->cropPositionChanged (this);
1012 void CropWindow::remoteMoveReady () {
1015 cropHandler
.getPosition (cropX
, cropY
);
1016 cropHandler
.setPosition (cropX
+ action_x
, cropY
+ action_y
);
1017 cropHandler
.getPosition (cropX
, cropY
);
1019 for (std::list
<CropWindowListener
*>::iterator i
=listeners
.begin(); i
!=listeners
.end(); i
++)
1020 (*i
)->cropPositionChanged (this);
1023 void CropWindow::delCropWindowListener (CropWindowListener
* l
) {
1025 std::list
<CropWindowListener
*>::iterator i
=listeners
.begin();
1026 while (i
!=listeners
.end())
1028 i
= listeners
.erase (i
);