diff --git a/rtengine/coord.cc b/rtengine/coord.cc index 4b5dcf40b..8a3d7d080 100644 --- a/rtengine/coord.cc +++ b/rtengine/coord.cc @@ -41,7 +41,7 @@ PolarCoord& PolarCoord::operator= (const Coord& other) const double y = other.y; radius = rtengine::norm2 (x, y); - angle = std::atan2 (x, y) * 180.0 / M_PI; + angle = std::atan2 (y, x) * 180.0 / M_PI; return *this; } diff --git a/rtgui/cropwindow.cc b/rtgui/cropwindow.cc index dcb06792e..ed843c3e1 100644 --- a/rtgui/cropwindow.cc +++ b/rtgui/cropwindow.cc @@ -66,20 +66,19 @@ ZoomStep zoomSteps[] = { #define ZOOM11INDEX 13 CropWindow::CropWindow (ImageArea* parent, rtengine::StagedImageProcessor* ipc_, bool isLowUpdatePriority_, bool isDetailWindow) - : ObjectMOBuffer(parent), onResizeArea(false), deleted(false), fitZoomEnabled(true), fitZoom(false), isLowUpdatePriority(isLowUpdatePriority_), - backColor(options.bgcolor), decorated(true), titleHeight(30), - sideBorderWidth(3), lowerBorderWidth(3), upperBorderWidth(1), sepWidth(2), - xpos(30), ypos(30), imgX(-1), imgY(-1), imgW(1), imgH(1), iarea(parent), - cropZoom(0), cropgl(NULL), pmlistener(NULL), observedCropWin(NULL), ipc(ipc_), isFlawnOver(false) + : ObjectMOBuffer(parent), state(SNormal), press_x(0), press_y(0), action_x(0), action_y(0), pickedObject(-1), pickModifierKey(0), rot_deg(0), onResizeArea(false), deleted(false), + fitZoomEnabled(true), fitZoom(false), isLowUpdatePriority(isLowUpdatePriority_), cropLabel(Glib::ustring("100%")), + backColor(options.bgcolor), decorated(true), isFlawnOver(false), titleHeight(30), sideBorderWidth(3), lowerBorderWidth(3), + upperBorderWidth(1), sepWidth(2), xpos(30), ypos(30), width(0), height(0), imgAreaX(0), imgAreaY(0), imgAreaW(0), imgAreaH(0), + imgX(-1), imgY(-1), imgW(1), imgH(1), iarea(parent), cropZoom(0), zoomVersion(0), exposeVersion(0), cropgl(NULL), + pmlistener(NULL), pmhlistener(NULL), observedCropWin(NULL), ipc(ipc_) { Glib::RefPtr context = parent->get_pango_context () ; Pango::FontDescription fontd = context->get_font_description (); fontd.set_weight (Pango::WEIGHT_BOLD); fontd.set_size(8 * Pango::SCALE); context->set_font_description (fontd); - cropLabel = "100%"; Glib::RefPtr cllayout = parent->create_pango_layout("1000%"); - exposeVersion = zoomVersion = 0; int iw, ih; cllayout->get_pixel_size (iw, ih); @@ -111,8 +110,6 @@ CropWindow::CropWindow (ImageArea* parent, rtengine::StagedImageProcessor* ipc_, cropHandler.setDisplayHandler(this); cropHandler.newImage (ipc_, isDetailWindow); - - state = SNormal; } void CropWindow::enable() @@ -272,109 +269,182 @@ void CropWindow::buttonPress (int button, int type, int bstate, int x, int y) { bool needRedraw = true; // most common case ; not redrawing are exceptions + EditSubscriber *editSubscriber = iarea->getCurrSubscriber(); iarea->grabFocus (this); - if (button == 1 && type == GDK_2BUTTON_PRESS && onArea (CropImage, x, y) && (state == SNormal || state == SCropImgMove)) { - if (fitZoomEnabled) { - if (fitZoom) { - state = SNormal; - zoomVersion = exposeVersion; - screenCoordToImage (x, y, action_x, action_y); - changeZoom (ZOOM11INDEX, true, action_x, action_y); - fitZoom = false; + if (button == 1) { + if (type == GDK_2BUTTON_PRESS && onArea (CropImage, x, y) && (state == SNormal || state == SCropImgMove)) { + if (fitZoomEnabled) { + if (fitZoom) { + state = SNormal; + zoomVersion = exposeVersion; + screenCoordToImage (x, y, action_x, action_y); + changeZoom (ZOOM11INDEX, true, action_x, action_y); + fitZoom = false; + } else { + zoomFit (); + } } else { - zoomFit (); + zoom11 (); } - } else { - zoom11 (); - } - state = SNormal; - } - else if (button == 1 && type == GDK_BUTTON_PRESS && state == SNormal && onArea (CropToolBar, x, y)) { - if (!decorated || !buttonSet.pressNotify (x, y)) { - state = SCropWinMove; - action_x = x; - action_y = y; - press_x = xpos; - press_y = ypos; + state = SNormal; } - } else if (button == 1 && type == GDK_BUTTON_PRESS && state == SNormal && onArea (CropResize, x, y)) { - state = SCropWinResize; - action_x = x; - action_y = y; - press_x = width; - press_y = height; - } else if (type == GDK_BUTTON_PRESS && state == SNormal && onArea (CropImage, x, y)) { - if (button == 1 && onArea (CropTopLeft, x, y)) { - state = SResizeTL; - press_x = x; - action_x = cropHandler.cropParams.x; - press_y = y; - action_y = cropHandler.cropParams.y; - } else if (button == 1 && onArea (CropTopRight, x, y)) { - state = SResizeTR; - press_x = x; - action_x = cropHandler.cropParams.w; - press_y = y; - action_y = cropHandler.cropParams.y; - } else if (button == 1 && onArea (CropBottomLeft, x, y)) { - state = SResizeBL; - press_x = x; - action_x = cropHandler.cropParams.x; - press_y = y; - action_y = cropHandler.cropParams.h; - } else if (button == 1 && onArea (CropBottomRight, x, y)) { - state = SResizeBR; - press_x = x; - action_x = cropHandler.cropParams.w; - press_y = y; - action_y = cropHandler.cropParams.h; - } else if (button == 1 && onArea (CropTop, x, y)) { - state = SResizeH1; - press_y = y; - action_y = cropHandler.cropParams.y; - } else if (button == 1 && onArea (CropBottom, x, y)) { - state = SResizeH2; - press_y = y; - action_y = cropHandler.cropParams.h; - } else if (button == 1 && onArea (CropLeft, x, y)) { - state = SResizeW1; - press_x = x; - action_x = cropHandler.cropParams.x; - } else if (button == 1 && onArea (CropRight, x, y)) { - state = SResizeW2; - press_x = x; - action_x = cropHandler.cropParams.w; - } else if (button == 1 && (bstate & GDK_SHIFT_MASK) && onArea (CropInside, x, y)) { - state = SCropMove; - press_x = x; - press_y = y; - action_x = cropHandler.cropParams.x; - action_y = cropHandler.cropParams.y; - } else if (iarea->getToolMode () == TMHand) { + else if (type == GDK_BUTTON_PRESS && state == SNormal) { + if (onArea (CropToolBar, x, y)) { + if (!decorated || !buttonSet.pressNotify (x, y)) { + state = SCropWinMove; + action_x = x; + action_y = y; + press_x = xpos; + press_y = ypos; + } + } else if (onArea (CropResize, x, y)) { + state = SCropWinResize; + action_x = x; + action_y = y; + press_x = width; + press_y = height; + } else { + if (onArea (CropImage, x, y)) { // events inside of the image domain + if (onArea (CropTopLeft, x, y)) { + state = SResizeTL; + press_x = x; + action_x = cropHandler.cropParams.x; + press_y = y; + action_y = cropHandler.cropParams.y; + } else if (onArea (CropTopRight, x, y)) { + state = SResizeTR; + press_x = x; + action_x = cropHandler.cropParams.w; + press_y = y; + action_y = cropHandler.cropParams.y; + } else if (onArea (CropBottomLeft, x, y)) { + state = SResizeBL; + press_x = x; + action_x = cropHandler.cropParams.x; + press_y = y; + action_y = cropHandler.cropParams.h; + } else if (onArea (CropBottomRight, x, y)) { + state = SResizeBR; + press_x = x; + action_x = cropHandler.cropParams.w; + press_y = y; + action_y = cropHandler.cropParams.h; + } else if (onArea (CropTop, x, y)) { + state = SResizeH1; + press_y = y; + action_y = cropHandler.cropParams.y; + } else if (onArea (CropBottom, x, y)) { + state = SResizeH2; + press_y = y; + action_y = cropHandler.cropParams.h; + } else if (onArea (CropLeft, x, y)) { + state = SResizeW1; + press_x = x; + action_x = cropHandler.cropParams.x; + } else if (onArea (CropRight, x, y)) { + state = SResizeW2; + press_x = x; + action_x = cropHandler.cropParams.w; + } else if ((bstate & GDK_SHIFT_MASK) && onArea (CropInside, x, y)) { + state = SCropMove; + press_x = x; + press_y = y; + action_x = cropHandler.cropParams.x; + action_y = cropHandler.cropParams.y; + } else if (onArea (CropObserved, x, y)) { + state = SObservedMove; + press_x = x; + press_y = y; + action_x = 0; + action_y = 0; + } else if (iarea->getToolMode () == TMStraighten) { + state = SRotateSelecting; + press_x = x; + press_y = y; + action_x = x; + action_y = y; + rot_deg = 0; + } else if (iarea->getToolMode () == TMSpotWB) { + int spotx, spoty; + screenCoordToImage (x, y, spotx, spoty); + iarea->spotWBSelected (spotx, spoty); + } else if (iarea->getToolMode () == TMCropSelect && cropgl) { + state = SCropSelecting; + screenCoordToImage (x, y, press_x, press_y); + cropHandler.cropParams.enabled = true; + cropHandler.cropParams.x = press_x; + cropHandler.cropParams.y = press_y; + cropHandler.cropParams.w = cropHandler.cropParams.h = 1; + cropgl->cropInit (cropHandler.cropParams.x, cropHandler.cropParams.y, cropHandler.cropParams.w, cropHandler.cropParams.h); + } else if (iarea->getToolMode () == TMHand) { + if (editSubscriber) { + needRedraw = editSubscriber->button1Pressed(bstate); + if ((cropgl && cropgl->inImageArea(iarea->posImage.x, iarea->posImage.y) && (editSubscriber->getEditingType() == ET_PIPETTE && (bstate & GDK_CONTROL_MASK))) || editSubscriber->getEditingType() == ET_OBJECTS) { + if (editSubscriber->isDragging()) { + state = SEditDrag1; + } else if (editSubscriber->isPicking()) { + state = SEditPick1; + pickedObject = iarea->object; + pickModifierKey = bstate; + } + press_x = x; + press_y = y; + action_x = 0; + action_y = 0; + } + } + if (state != SEditDrag1) { + state = SCropImgMove; + press_x = x; + press_y = y; + action_x = 0; + action_y = 0; + } + } else { // if(zoomSteps[cropZoom].zoom > cropHandler.getFitZoom()) { // only allow move when image is only partial visible + state = SCropImgMove; + press_x = x; + press_y = y; + action_x = 0; + action_y = 0; + } + + } else if (iarea->getToolMode () == TMHand) { // events outside of the image domain + EditSubscriber *editSubscriber = iarea->getCurrSubscriber(); + + if (editSubscriber && editSubscriber->getEditingType() == ET_OBJECTS) { + needRedraw = editSubscriber->button1Pressed(bstate); + + if (editSubscriber->isDragging()) { + state = SEditDrag1; + } else if (editSubscriber->isPicking()) { + state = SEditPick1; + pickedObject = iarea->object; + pickModifierKey = bstate; + } + + press_x = x; + press_y = y; + action_x = 0; + action_y = 0; + } + } + } + } + } else if (button == 2) { + if (iarea->getToolMode () == TMHand) { EditSubscriber *editSubscriber = iarea->getCurrSubscriber(); - if (editSubscriber && editSubscriber->getEditingType() == ET_OBJECTS) { - if (button == 1) { - needRedraw = editSubscriber->button1Pressed(bstate); + needRedraw = editSubscriber->button2Pressed(bstate); - if (editSubscriber->isDragging()) { - state = SEditDrag1; - } - } else if (button == 2) { - needRedraw = editSubscriber->button2Pressed(bstate); - - if (editSubscriber->isDragging()) { - state = SEditDrag2; - } - } else if (button == 3) { - needRedraw = editSubscriber->button3Pressed(bstate); - - if (editSubscriber->isDragging()) { - state = SEditDrag3; - } + if (editSubscriber->isDragging()) { + state = SEditDrag2; + } else if (editSubscriber->isPicking()) { + state = SEditPick2; + pickedObject = iarea->object; + pickModifierKey = bstate; } press_x = x; @@ -382,100 +452,26 @@ void CropWindow::buttonPress (int button, int type, int bstate, int x, int y) action_x = 0; action_y = 0; } - - if (state != SEditDrag1 && state != SEditDrag2 && state != SEditDrag3) { - if (button == 1 && onArea (CropObserved, x, y)) { - state = SObservedMove; - press_x = x; - press_y = y; - action_x = 0; - action_y = 0; - } else if (button == 1 && editSubscriber && cropgl && cropgl->inImageArea(iarea->posImage.x, iarea->posImage.y) && (editSubscriber->getEditingType() == ET_PIPETTE && (bstate & GDK_CONTROL_MASK)) ) { - editSubscriber->button1Pressed(bstate); - state = SEditDrag1; - press_x = x; - press_y = y; - action_x = 0; - action_y = 0; - } else if (button == 1) { // if(zoomSteps[cropZoom].zoom > cropHandler.getFitZoom()) { // only allow move when image is only partial visible - state = SCropImgMove; - press_x = x; - press_y = y; - action_x = 0; - action_y = 0; - } - } - } else if (button == 1 && onArea (CropObserved, x, y)) { - state = SObservedMove; - press_x = x; - press_y = y; - action_x = 0; - action_y = 0; - } else if (button == 1 && iarea->getToolMode () == TMStraighten) { - state = SRotateSelecting; - press_x = x; - press_y = y; - action_x = x; - action_y = y; - rot_deg = 0; - } else if (button == 1 && iarea->getToolMode () == TMSpotWB) { - int spotx, spoty; - screenCoordToImage (x, y, spotx, spoty); - iarea->spotWBSelected (spotx, spoty); - } else if (button == 1 && iarea->getToolMode () == TMCropSelect && cropgl) { - state = SCropSelecting; - screenCoordToImage (x, y, press_x, press_y); - cropHandler.cropParams.enabled = true; - cropHandler.cropParams.x = press_x; - cropHandler.cropParams.y = press_y; - cropHandler.cropParams.w = cropHandler.cropParams.h = 1; - cropgl->cropInit (cropHandler.cropParams.x, cropHandler.cropParams.y, cropHandler.cropParams.w, cropHandler.cropParams.h); } - } else if (type == GDK_BUTTON_PRESS && state == SNormal && iarea->getToolMode () == TMHand) { - // Any other case... i.e. we're assuming to be on the canvas, looking for editing objects - EditSubscriber *editSubscriber = iarea->getCurrSubscriber(); - - if (editSubscriber && editSubscriber->getEditingType() == ET_OBJECTS) { - if (button == 1) { - needRedraw = editSubscriber->button1Pressed(bstate); - - if (editSubscriber->isDragging()) { - state = SEditDrag1; - } - } else if (button == 2) { - needRedraw = editSubscriber->button2Pressed(bstate); - - if (editSubscriber->isDragging()) { - state = SEditDrag2; - } - } else if (button == 3) { + } else if (button == 3) { + if (iarea->getToolMode () == TMHand) { + EditSubscriber *editSubscriber = iarea->getCurrSubscriber(); + if (editSubscriber && editSubscriber->getEditingType() == ET_OBJECTS) { needRedraw = editSubscriber->button3Pressed(bstate); if (editSubscriber->isDragging()) { state = SEditDrag3; + } else if (editSubscriber->isPicking()) { + state = SEditPick3; + pickedObject = iarea->object; + pickModifierKey = bstate; } + + press_x = x; + press_y = y; + action_x = 0; + action_y = 0; } - - press_x = x; - press_y = y; - action_x = 0; - action_y = 0; - } - } - - if (button == 3) { - iarea->pipetteVal[0] = iarea->pipetteVal[1] = iarea->pipetteVal[2] = -1.f; - EditSubscriber *editSubscriber = iarea->getCurrSubscriber(); - - if (editSubscriber && editSubscriber->getEditingType() == ET_PIPETTE) { - editSubscriber->mouseOver(0); - } - - state = SNormal; - iarea->setToolHand (); - - if (pmhlistener) { - pmhlistener->toggleFreeze(); } } @@ -529,7 +525,7 @@ void CropWindow::buttonRelease (int button, int num, int bstate, int x, int y) state = SNormal; needRedraw = true; } else if (state == SEditDrag1 || state == SEditDrag2 || state == SEditDrag3) { - if (state == SEditDrag1) { + if (state == SEditDrag1) { needRedraw = editSubscriber->button1Released(); } else if (state == SEditDrag2) { needRedraw = editSubscriber->button2Released(); @@ -562,12 +558,7 @@ void CropWindow::buttonRelease (int button, int num, int bstate, int x, int y) } } else if (editSubscriber->getEditingType() == ET_OBJECTS) { screenCoordToCropCanvas (x, y, cropPos.x, cropPos.y); - - if (onArea (CropImage, x, y)) { - iarea->object = ObjectMOBuffer::getObjectID(cropPos); - } else { - iarea->object = -1; - } + iarea->object = ObjectMOBuffer::getObjectID(cropPos); } needRedraw |= editSubscriber->mouseOver(bstate); @@ -579,7 +570,38 @@ void CropWindow::buttonRelease (int button, int num, int bstate, int x, int y) iarea->deltaScreen.set(0, 0); iarea->deltaPrevImage.set(0, 0); iarea->deltaPrevScreen.set(0, 0); - state = SNormal; + } else if (state == SEditPick1 || state == SEditPick2 || state == SEditPick3) { + if (editSubscriber) { + Coord imgPos; + action_x = x; + action_y = y; + screenCoordToImage (x, y, imgPos.x, imgPos.y); + + iarea->posImage.set (imgPos.x, imgPos.y); + iarea->posScreen.set (x, y); + + Coord cropPos; + screenCoordToCropCanvas (x, y, cropPos.x, cropPos.y); + + iarea->object = ObjectMOBuffer::getObjectID(cropPos); + + bool elemPicked = iarea->object == pickedObject && bstate == pickModifierKey; + + if (state == SEditPick1) { + needRedraw = editSubscriber->pick1 (elemPicked); + } else if (state == SEditPick2) { + needRedraw = editSubscriber->pick2 (elemPicked); + } else if (state == SEditPick3) { + needRedraw = editSubscriber->pick3 (elemPicked); + } + + iarea->object = pickedObject = -1; + pickModifierKey = 0; + + needRedraw |= editSubscriber->mouseOver (bstate); + } else { + iarea->object = 0; + } } if (cropgl && (state == SCropSelecting || state == SResizeH1 || state == SResizeH2 || state == SResizeW1 || state == SResizeW2 || state == SResizeTL || state == SResizeTR || state == SResizeBL || state == SResizeBR || state == SCropMove)) { @@ -598,6 +620,20 @@ void CropWindow::buttonRelease (int button, int num, int bstate, int x, int y) return; } + if (state != SEditDrag3 && state != SEditPick3 && button == 3 && !(bstate & (GDK_SHIFT_MASK|GDK_CONTROL_MASK))) { + iarea->pipetteVal[0] = iarea->pipetteVal[1] = iarea->pipetteVal[2] = -1.f; + + if (editSubscriber && editSubscriber->getEditingType() == ET_PIPETTE) { + editSubscriber->mouseOver(0); + } + + iarea->setToolHand (); + + if (pmhlistener) { + pmhlistener->toggleFreeze(); + } + } + state = SNormal; iarea->grabFocus (NULL); @@ -743,7 +779,7 @@ void CropWindow::pointerMoved (int bstate, int x, int y) } else if (editSubscriber) { rtengine::Crop* crop = static_cast(cropHandler.getCrop()); - if (state == SNormal) { + if (state == SNormal || state == SEditPick1 || state == SEditPick2 || state == SEditPick3) { Coord imgPos; action_x = x; action_y = y; diff --git a/rtgui/cropwindow.h b/rtgui/cropwindow.h index c74664814..d9f738f66 100644 --- a/rtgui/cropwindow.h +++ b/rtgui/cropwindow.h @@ -47,9 +47,11 @@ class CropWindow : public LWButtonListener, public CropDisplayHandler, public Ed { // state management - ImgEditState state; // current state of user (see enum State) + ImgEditState state; // current state of user (see enum State) int press_x, press_y; // position of the cursor in the GUI space on button press int action_x, action_y; // parameter that will evolve during a pan or drag action + int pickedObject; + int pickModifierKey; double rot_deg; bool onResizeArea; bool deleted; diff --git a/rtgui/curveeditor.cc b/rtgui/curveeditor.cc index 3cfe335b2..8ad521d06 100644 --- a/rtgui/curveeditor.cc +++ b/rtgui/curveeditor.cc @@ -392,7 +392,7 @@ void CurveEditor::switchOffEditMode () EditSubscriber::switchOffEditMode(); // disconnect } -bool CurveEditor::mouseOver(int modifierKey) +bool CurveEditor::mouseOver(const int modifierKey) { EditDataProvider* provider = getEditProvider(); subGroup->pipetteMouseOver(provider, modifierKey); @@ -400,7 +400,7 @@ bool CurveEditor::mouseOver(int modifierKey) return true; // return true will ask the preview to be redrawn, for the cursor } -bool CurveEditor::button1Pressed(int modifierKey) +bool CurveEditor::button1Pressed(const int modifierKey) { EditDataProvider* provider = getEditProvider(); @@ -422,7 +422,7 @@ bool CurveEditor::button1Released() return true; } -bool CurveEditor::drag1(int modifierKey) +bool CurveEditor::drag1(const int modifierKey) { EditDataProvider* provider = getEditProvider(); subGroup->pipetteDrag(provider, modifierKey); @@ -430,7 +430,7 @@ bool CurveEditor::drag1(int modifierKey) return false; } -CursorShape CurveEditor::getCursor(int objectID) +CursorShape CurveEditor::getCursor(const int objectID) { if (remoteDrag) { return CSResizeHeight; diff --git a/rtgui/curveeditor.h b/rtgui/curveeditor.h index 10e3d9668..a3ba68436 100644 --- a/rtgui/curveeditor.h +++ b/rtgui/curveeditor.h @@ -127,11 +127,11 @@ public: sigc::signal signal_curvepoint_release(); void switchOffEditMode (); - bool mouseOver(int modifierKey); - bool button1Pressed(int modifierKey); + bool mouseOver(const int modifierKey); + bool button1Pressed(const int modifierKey); bool button1Released(); - bool drag1(int modifierKey); - CursorShape getCursor(int objectID); + bool drag1(const int modifierKey); + CursorShape getCursor(const int objectID); }; diff --git a/rtgui/edit.cc b/rtgui/edit.cc index 598ee8da5..87ccfde57 100644 --- a/rtgui/edit.cc +++ b/rtgui/edit.cc @@ -747,7 +747,294 @@ void Rectangle::drawToMOChannel(Cairo::RefPtr &cr, unsigned shor } } -EditSubscriber::EditSubscriber (EditType editType) : ID(EUID_None), editingType(editType), bufferType(BT_SINGLEPLANE_FLOAT), provider(NULL), dragging(false) {} +void OPIcon::drivenPointToRectangle(rtengine::Coord &pos, + rtengine::Coord &topLeft, rtengine::Coord &bottomRight, int W, int H) +{ + switch (drivenPoint) { + case (DP_CENTERCENTER): + topLeft.x = pos.x - W / 2; + topLeft.y = pos.y - H / 2; + break; + + case (DP_TOPLEFT): + topLeft.x = pos.x; + topLeft.y = pos.y; + break; + + case (DP_TOPCENTER): + topLeft.x = pos.x - W / 2; + topLeft.y = pos.y; + break; + + case (DP_TOPRIGHT): + topLeft.x = pos.x - W; + topLeft.y = pos.y; + break; + + case (DP_CENTERRIGHT): + topLeft.x = pos.x - W; + topLeft.y = pos.y - H / 2; + break; + + case (DP_BOTTOMRIGHT): + topLeft.x = pos.x - W; + topLeft.y = pos.y - H; + break; + + case (DP_BOTTOMCENTER): + topLeft.x = pos.x - W / 2; + topLeft.y = pos.y - H; + break; + + case (DP_BOTTOMLEFT): + topLeft.x = pos.x; + topLeft.y = pos.y - H; + break; + + case (DP_CENTERLEFT): + topLeft.x = pos.x; + topLeft.y = pos.y - H / 2; + break; + } + + bottomRight.x = topLeft.x + W - 1; + bottomRight.y = topLeft.y + H - 1; +} + +OPIcon::OPIcon(Cairo::RefPtr *normal, + Cairo::RefPtr *active, + Cairo::RefPtr *prelight, + Cairo::RefPtr *dragged, + Cairo::RefPtr *insensitive, + enum DrivenPoint drivenPoint) : + drivenPoint(drivenPoint) +{ + if (normal) { + normalImg = *normal; + } + + if (prelight) { + prelightImg = *prelight; + } + + if (active) { + activeImg = *active; + } + + if (dragged) { + draggedImg = *active; + } + + if (insensitive) { + insensitiveImg = *insensitive; + } +} + +OPIcon::OPIcon(Glib::ustring normalImage, Glib::ustring activeImage, Glib::ustring prelightImage, + Glib::ustring draggedImage, Glib::ustring insensitiveImage, enum DrivenPoint drivenPoint) : drivenPoint(drivenPoint) +{ + if (!normalImage.empty()) { + normalImg = Cairo::ImageSurface::create_from_png( RTImage::findIconAbsolutePath(normalImage) ); + } + + if (!prelightImage.empty()) { + prelightImg = Cairo::ImageSurface::create_from_png( RTImage::findIconAbsolutePath(prelightImage) ); + } + + if (!activeImage.empty()) { + activeImg = Cairo::ImageSurface::create_from_png( RTImage::findIconAbsolutePath(activeImage) ); + } + + if (!draggedImage.empty()) { + draggedImg = Cairo::ImageSurface::create_from_png( RTImage::findIconAbsolutePath(draggedImage) ); + } + + if (!insensitiveImage.empty()) { + insensitiveImg = Cairo::ImageSurface::create_from_png( RTImage::findIconAbsolutePath(insensitiveImage) ); + } +} + +Cairo::RefPtr OPIcon::getNormalImg() +{ + return normalImg; +} +Cairo::RefPtr OPIcon::getPrelightImg() +{ + return prelightImg; +} +Cairo::RefPtr OPIcon::getActiveImg() +{ + return activeImg; +} +Cairo::RefPtr OPIcon::getDraggedImg() +{ + return draggedImg; +} +Cairo::RefPtr OPIcon::getInsensitiveImg() +{ + return insensitiveImg; +} + +void OPIcon::drawImage(Cairo::RefPtr img, + Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, + EditCoordSystem &coordSystem) +{ + int imgW = img->get_width(); + int imgH = img->get_height(); + + rtengine::Coord pos; + + if (datum == IMAGE) { + coordSystem.imageCoordToScreen(position.x, position.y, pos.x, pos.y); + } else if (datum == CLICKED_POINT) { + pos = position + objectBuffer->getDataProvider()->posScreen; + } else if (datum == CURSOR) + pos = position + objectBuffer->getDataProvider()->posScreen + + objectBuffer->getDataProvider()->deltaScreen; + + rtengine::Coord tl, br; // Coordinate of the rectangle in the CropBuffer coordinate system + drivenPointToRectangle(pos, tl, br, imgW, imgH); + + cr->set_source(img, tl.x, tl.y); + cr->set_line_width(0.); + cr->rectangle(tl.x, tl.y, imgW, imgH); + cr->fill(); +} + +void OPIcon::drawMOImage(Cairo::RefPtr img, Cairo::RefPtr &cr, + unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) +{ + // test of F_HOVERABLE has already been done + + int imgW = img->get_width(); + int imgH = img->get_height(); + + rtengine::Coord pos; + + if (datum == IMAGE) + coordSystem.imageCoordToCropCanvas (position.x, position.y, pos.x, pos.y); + else if (datum == CLICKED_POINT) { + pos = position + objectBuffer->getDataProvider()->posScreen; + } else if (datum == CURSOR) + pos = position + objectBuffer->getDataProvider()->posScreen + + objectBuffer->getDataProvider()->deltaScreen; + + rtengine::Coord tl, br; // Coordinate of the rectangle in the CropBuffer coordinate system + drivenPointToRectangle(pos, tl, br, imgW, imgH); + + // drawing the lower byte's value + if (objectBuffer->getObjectMode() == OM_255) { + cr->set_source_rgba (0., 0., 0., ((id + 1) & 0xFF) / 255.); + } else { + cr->set_source_rgba (0., 0., 0., (id + 1) / 65535.); + } + cr->set_line_width(0.); + cr->rectangle(tl.x, tl.y, imgW, imgH); + cr->fill(); +} + +void OPIcon::drawOuterGeometry(Cairo::RefPtr &cr, + ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) {} + +void OPIcon::drawInnerGeometry(Cairo::RefPtr &cr, + ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) +{ + if (flags & F_VISIBLE) { + // Here we will handle fallback solutions + State tmpState = state; + + if (tmpState == INSENSITIVE) { + if (!insensitiveImg) { + tmpState = NORMAL; + } else { + OPIcon::drawImage(insensitiveImg, cr, objectBuffer, coordSystem); + return; + } + } + + if (tmpState == DRAGGED) { + if (!draggedImg) { + tmpState = ACTIVE; + } else { + OPIcon::drawImage(draggedImg, cr, objectBuffer, coordSystem); + return; + } + } + + if (tmpState == ACTIVE) { + if (!activeImg) { + tmpState = PRELIGHT; + } else { + OPIcon::drawImage(activeImg, cr, objectBuffer, coordSystem); + return; + } + } + + if (tmpState == PRELIGHT) { + if (!prelightImg) { + tmpState = NORMAL; + } else { + OPIcon::drawImage(prelightImg, cr, objectBuffer, coordSystem); + return; + } + } + + if (tmpState == NORMAL && normalImg) { + OPIcon::drawImage(normalImg, cr, objectBuffer, coordSystem); + } + } +} + +void OPIcon::drawToMOChannel(Cairo::RefPtr &cr, unsigned short id, + ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) +{ + if (flags & F_HOVERABLE) { + // Here we will handle fallback solutions + State tmpState = state; + + if (tmpState == INSENSITIVE) { + if (!insensitiveImg) { + tmpState = NORMAL; + } else { + OPIcon::drawMOImage(insensitiveImg, cr, id, objectBuffer, coordSystem); + return; + } + } + + if (tmpState == DRAGGED) { + if (!draggedImg) { + tmpState = ACTIVE; + } else { + OPIcon::drawMOImage(draggedImg, cr, id, objectBuffer, coordSystem); + return; + } + } + + if (tmpState == ACTIVE) { + if (!activeImg) { + tmpState = PRELIGHT; + } else { + OPIcon::drawMOImage(activeImg, cr, id, objectBuffer, coordSystem); + return; + } + } + + if (tmpState == PRELIGHT) { + if (!prelightImg) { + tmpState = NORMAL; + } else { + OPIcon::drawMOImage(prelightImg, cr, id, objectBuffer, coordSystem); + return; + } + } + + if (tmpState == NORMAL && normalImg) { + OPIcon::drawMOImage(normalImg, cr, id, objectBuffer, coordSystem); + } + } +} + +EditSubscriber::EditSubscriber (EditType editType) : ID(EUID_None), editingType(editType), bufferType(BT_SINGLEPLANE_FLOAT), provider(NULL), action(ES_ACTION_NONE) {} void EditSubscriber::setEditProvider(EditDataProvider *provider) { @@ -791,24 +1078,29 @@ void EditSubscriber::switchOffEditMode() unsubscribe(); } -EditUniqueID EditSubscriber::getEditID() +const EditUniqueID EditSubscriber::getEditID() { return ID; } -EditType EditSubscriber::getEditingType() +const EditType EditSubscriber::getEditingType() { return editingType; } -BufferType EditSubscriber::getPipetteBufferType() +const BufferType EditSubscriber::getPipetteBufferType() { return bufferType; } -bool EditSubscriber::isDragging() +const bool EditSubscriber::isDragging() { - return dragging; + return action == ES_ACTION_DRAGGING; +} + +const bool EditSubscriber::isPicking() +{ + return action == ES_ACTION_PICKING; } //-------------------------------------------------------------------------------------------------- diff --git a/rtgui/edit.h b/rtgui/edit.h index 5268e82e5..c4213af40 100644 --- a/rtgui/edit.h +++ b/rtgui/edit.h @@ -63,10 +63,10 @@ class EditSubscriber; * ### Event handling * * The mouseOver method is called on each mouse movement, excepted when dragging a point. This method can then access - * the pipetteVal array values, which contain the mean of the pixel read in the buffer, or -1 of the cursor is outside + * the pipetteVal array values, which contain the mean of the pixel read in the buffer, or -1 if the cursor is outside * of the image. In this case, EditDataProvider::object is also set to 0 (and 1 if over the image). * - * When the user will click on the left mouse button while pressing the CTRL key, the button1Pressed will be called. + * When the user will click on the left mouse button while pressing the CTRL key, button1Pressed will be called. * Setting "dragging" to true (or false) is not required for the pipette type editing. * * The drag1 method will be called on all subsequent mouse move. The pipetteVal[3] array will already be filled with @@ -79,7 +79,7 @@ class EditSubscriber; * * By using this class, objects can be drawn and manipulated on the preview. * - * The developer has to handle the buttonPress, buttonRelease, drag and mouseOver method that he needs. There + * The developer has to handle the buttonPress, buttonRelease, drag and mouseOver methods that he needs. There * are buttonPress, buttonRelease and drag methods dedicated to each mouse button, for better flexibility * (e.g.button2Press, button2Release, drag2 will handle event when mouse button 2 is used first). RT actually * does not handle multiple mouse button event (e.g. button1 + button2), only one at a time. The first button pressed @@ -93,10 +93,11 @@ class EditSubscriber; * specific values. To be displayed, the F_VISIBLE flag has to be set through the setActive or setVisible methods. * * The second list (mouseOverGeometry) is used in a backbuffer, the color used to draw the shape being the id of the - * mouseOverGeometry. As an example, you could use a circle line to represent the line to the user, but use another - * Circle object, filled, to be used as mouseOver detection. The association between both shape (visible and mouseOver) + * mouseOverGeometry. As an example, you could create a line to be shown in the preview, but create 2 filled Circle object + * to be used as mouseOver detection, one on each end of the line. The association between both shape (visible and mouseOver) * is handled by the developer. To be displayed on this backbuffer, the F_HOVERABLE flag has to be set through the - * setActive or setHoverable methods. + * setActive or setHoverable methods. For overlapping mouse over geometry, the priority is set by the order in the list : + * the last item is detected first (think of it like a stack piled up). * * * ### Event handling @@ -106,17 +107,28 @@ class EditSubscriber; * * RT will call the mouseOver method on each mouse movement where no mouse button is pressed. * - * On mouse button press over a mouseOverGeometry, it will call the button press method corresponding to the button - * (e.g. button1Pressed for mouse button 1), with the modifier key as parameter. Any other mouse button pressed at - * the same time will be ignored. It's up to the developer to decide whether it leads to a drag movement or not, - * by setting the "dragging" boolean to true. + * On mouse button press over a mouseOverGeometry (that has F_HOVERABLE set), it will call the button press method corresponding + * to the button (e.g. button1Pressed for mouse button 1), with the modifier key as parameter. Any other mouse button pressed at + * the same time will be ignored. It's up to the developer to decide whether this action is starting a 'drag' or 'pick' action, + * by setting the 'action' parameter to the appropriated value. * - * In this case, RT will then sent drag1 event (to stay with our button 1 pressed example) on each mouse movement. It's up - * to the developer of the tool to handle the dragging. The EditProvider class will help you in this by handling the actual - * position in various coordinate system and ways. + * If the user sets action to ES_ACTION_DRAGGING, RT will then send drag1 events (to stay with our button 1 pressed example) on each + * mouse movement. It's up to the developer of the tool to handle the dragging. The EditProvider class will help you in this by + * handling the actual position in various coordinate system and ways. * * When the user will release the mouse button, RT will call the button1Release event (in our example). The developer have - * then to set the "dragging" flag to false. + * then to set action to ES_ACTION_NONE. + * + * If the user sets action to ES_ACTION_PICKING, RT will keep in memory the mouseOver object that was selected when pressing the mouse + * (e.g. button 1), as well as the modifier keys. + * + * The element is said to be picked when the mouse button is released over the same mouse over object and with the same active + * modifier keys. In this case, the corresponding picked event (e.g. picked1 in our example) and the 'picked' flag will be true. + * If any of those condition is false, picked1 will still be be called to terminate the initiated picking action, but 'picked' + * will be false. This is necessary because the user may want to update the geometry if the picking is aborted. The developer have + * then to set action to ES_ACTION_NONE. + * + * Picking an on-screen element correspond to single-clicking on it. No double click is supported so far. * * Each of these methods have to returns a boolean value saying that the preview has to be refreshed or not (i.e. the displayed * geometry). @@ -134,11 +146,9 @@ class EditSubscriber; * the HSV tool, the Hue and Saturation and Value curves are applied on the current state of the image. That's why the pipette * of the H, S and V curve will share the same data of this "current state", otherwise the read value would be wrong. * - * When the mouse button 1 is pressed while pressing the CTRL key, the button1Pressed method will be called. - * * When the Edit process stops, the Subscriber is removed from the DataProvider, so buffers can be freed up. * A new ToolPanelListener::panelChanged event is also thrown to update the preview again, without the tool's - * graphical objects. The Edit button is also toggled off (by the user or programmatically). + * graphical objects. The Edit button is also toggled off (by the user or programatically). * * It means that each Edit buttons toggled on will start an update of the preview which might or might not create * a new History entry, depending on the ProcEvent used. @@ -315,12 +325,13 @@ public: bool isHoverable (); void setHoverable (bool visible); + // setActive will enable/disable the visible and hoverable flags in one shot! void setActive (bool active); - virtual void drawOuterGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *parent, EditCoordSystem &coordSystem) = 0; - virtual void drawInnerGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *parent, EditCoordSystem &coordSystem) = 0; - virtual void drawToMOChannel (Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *pipetteBuffer, EditCoordSystem &coordSystem) = 0; + virtual void drawOuterGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) = 0; + virtual void drawInnerGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) = 0; + virtual void drawToMOChannel (Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) = 0; }; class Circle : public Geometry @@ -335,9 +346,9 @@ public: Circle (rtengine::Coord& center, int radius, bool filled = false, bool radiusInImageSpace = false); Circle (int centerX, int centerY, int radius, bool filled = false, bool radiusInImageSpace = false); - void drawOuterGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *pipetteBuffer, EditCoordSystem &coordSystem); - void drawInnerGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *pipetteBuffer, EditCoordSystem &coordSystem); - void drawToMOChannel (Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *pipetteBuffer, EditCoordSystem &coordSystem); + void drawOuterGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem); + void drawInnerGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem); + void drawToMOChannel (Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem); }; class Line : public Geometry @@ -350,9 +361,9 @@ public: Line (rtengine::Coord& begin, rtengine::Coord& end); Line (int beginX, int beginY, int endX, int endY); - void drawOuterGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *pipetteBuffer, EditCoordSystem &coordSystem); - void drawInnerGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *pipetteBuffer, EditCoordSystem &coordSystem); - void drawToMOChannel (Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *pipetteBuffer, EditCoordSystem &coordSystem); + void drawOuterGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem); + void drawInnerGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem); + void drawToMOChannel (Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem); }; class Polyline : public Geometry @@ -363,9 +374,9 @@ public: Polyline (); - void drawOuterGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *pipetteBuffer, EditCoordSystem &coordSystem); - void drawInnerGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *pipetteBuffer, EditCoordSystem &coordSystem); - void drawToMOChannel (Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *pipetteBuffer, EditCoordSystem &coordSystem); + void drawOuterGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem); + void drawInnerGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem); + void drawToMOChannel (Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem); }; class Rectangle : public Geometry @@ -381,9 +392,49 @@ public: void setXYXY(int left, int top, int right, int bottom); void setXYWH(rtengine::Coord topLeft, rtengine::Coord widthHeight); void setXYXY(rtengine::Coord topLeft, rtengine::Coord bottomRight); - void drawOuterGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *pipetteBuffer, EditCoordSystem &coordSystem); - void drawInnerGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *pipetteBuffer, EditCoordSystem &coordSystem); - void drawToMOChannel (Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *pipetteBuffer, EditCoordSystem &coordSystem); + void drawOuterGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem); + void drawInnerGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem); + void drawToMOChannel (Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem); +}; + +class OPIcon : public Geometry // OP stands for "On Preview" +{ + +protected: + Cairo::RefPtr normalImg; + Cairo::RefPtr prelightImg; + Cairo::RefPtr activeImg; + Cairo::RefPtr draggedImg; + Cairo::RefPtr insensitiveImg; + + static void setPaths(Options &opt); + static void updateImages(); + void changeImage(Glib::ustring &newImage); + static Glib::ustring findIconAbsolutePath(const Glib::ustring &iconFName); + void drawImage (Cairo::RefPtr img, Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem); + void drawMOImage (Cairo::RefPtr img, Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem); + void drivenPointToRectangle(rtengine::Coord &pos, rtengine::Coord &topLeft, rtengine::Coord &bottomRight, int W, int H); + +public: + enum DrivenPoint drivenPoint; + rtengine::Coord position; + + OPIcon (Cairo::RefPtr *normal, Cairo::RefPtr *active, Cairo::RefPtr *prelight = NULL, Cairo::RefPtr *dragged = NULL, Cairo::RefPtr *insensitive = NULL, + enum DrivenPoint drivenPoint = DP_CENTERCENTER); + OPIcon (Glib::ustring normalImage, Glib::ustring activeImage, Glib::ustring prelightImage = "", Glib::ustring draggedImage = "", Glib::ustring insensitiveImage = "", enum DrivenPoint drivenPoint = DP_CENTERCENTER); + Cairo::RefPtr getNormalImg(); + Cairo::RefPtr getPrelightImg(); + Cairo::RefPtr getActiveImg(); + Cairo::RefPtr getDraggedImg(); + Cairo::RefPtr getInsensitiveImg(); + void drawOuterGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem); + void drawInnerGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem); + void drawToMOChannel (Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem); +}; + +class OPAdjuster : public Geometry // OP stands for "On Preview" +{ + }; /// @brief Method for client tools needing Edit information @@ -401,7 +452,11 @@ private: protected: std::vector visibleGeometry; /// displayed geometry std::vector mouseOverGeometry; /// mouseOver geometry, drawn in a hidden buffer - bool dragging; /// in object mode, set this to true in buttonPressed events to start dragging and ask for drag event (ignored in pipette mode) + enum { + ES_ACTION_NONE, /// + ES_ACTION_DRAGGING, /// set action to this value in the buttonPressed event to start dragging and ask for drag event + ES_ACTION_PICKING /// set action to this value in the buttonPressed event whenever the user is picking something through a single click. In this case, the pickX events will be called INSTEAD of buttonXReleased ! + } action; /// object mode only, ignored in Pipette mode public: EditSubscriber (EditType editType); @@ -409,31 +464,32 @@ public: void setEditProvider(EditDataProvider *provider); EditDataProvider* getEditProvider (); - void setEditID(EditUniqueID ID, BufferType buffType); - bool isCurrentSubscriber(); - virtual void subscribe(); - virtual void unsubscribe(); - virtual void switchOffEditMode (); /// Occurs when the user want to stop the editing mode - EditUniqueID getEditID(); - EditType getEditingType(); - BufferType getPipetteBufferType(); - bool isDragging(); /// Returns true if something is being dragged and drag events has to be sent (object mode only) + void setEditID(EditUniqueID ID, BufferType buffType); + bool isCurrentSubscriber(); + virtual void subscribe(); + virtual void unsubscribe(); + virtual void switchOffEditMode (); /// Occurs when the user want to stop the editing mode + const EditUniqueID getEditID(); + const EditType getEditingType(); + const BufferType getPipetteBufferType(); + const bool isDragging(); /// Returns true if something is being dragged and drag events has to be sent (object mode only) + const bool isPicking(); /// Returns true if something is being picked /** @brief Get the cursor to be displayed when above handles @param objectID object currently "hovered" */ - virtual CursorShape getCursor (int objectID); + virtual CursorShape getCursor (const int objectID); /** @brief Triggered when the mouse is moving over an object This method is also triggered when the cursor is moving over the image in ET_PIPETTE mode @param modifierKey Gtk's event modifier key (GDK_CONTROL_MASK | GDK_SHIFT_MASK | ...) @return true if the preview has to be redrawn, false otherwise */ - virtual bool mouseOver (int modifierKey); + virtual bool mouseOver (const int modifierKey); /** @brief Triggered when mouse button 1 is pressed, together with the CTRL modifier key if the subscriber is of type ET_PIPETTE Once the key is pressed, RT will enter in drag1 mode on subsequent mouse movements @param modifierKey Gtk's event modifier key (GDK_CONTROL_MASK | GDK_SHIFT_MASK | ...) @return true if the preview has to be redrawn, false otherwise */ - virtual bool button1Pressed (int modifierKey); + virtual bool button1Pressed (const int modifierKey); /** @brief Triggered when mouse button 1 is released @return true if the preview has to be redrawn, false otherwise */ @@ -443,7 +499,7 @@ public: Once the key is pressed, RT will enter in drag2 mode on subsequent mouse movements @param modifierKey Gtk's event modifier key (GDK_CONTROL_MASK | GDK_SHIFT_MASK | ...) @return true if the preview has to be redrawn, false otherwise */ - virtual bool button2Pressed (int modifierKey); + virtual bool button2Pressed (const int modifierKey); /** @brief Triggered when mouse button 2 is released (middle button) @return true if the preview has to be redrawn, false otherwise */ @@ -453,7 +509,7 @@ public: Once the key is pressed, RT will enter in drag3 mode on subsequent mouse movements @param modifierKey Gtk's event modifier key (GDK_CONTROL_MASK | GDK_SHIFT_MASK | ...) @return true if the preview has to be redrawn, false otherwise */ - virtual bool button3Pressed (int modifierKey); + virtual bool button3Pressed (const int modifierKey); /** @brief Triggered when mouse button 3 is released (right button) @return true if the preview has to be redrawn, false otherwise */ @@ -462,17 +518,36 @@ public: /** @brief Triggered when the user is moving while holding down mouse button 1 @param modifierKey Gtk's event modifier key (GDK_CONTROL_MASK | GDK_SHIFT_MASK | ...) @return true if the preview has to be redrawn, false otherwise */ - virtual bool drag1 (int modifierKey); + virtual bool drag1 (const int modifierKey); /** @brief Triggered when the user is moving while holding down mouse button 2 @param modifierKey Gtk's event modifier key (GDK_CONTROL_MASK | GDK_SHIFT_MASK | ...) @return true if the preview has to be redrawn, false otherwise */ - virtual bool drag2 (int modifierKey); + virtual bool drag2 (const int modifierKey); /** @brief Triggered when the user is moving while holding down mouse button 3 @param modifierKey Gtk's event modifier key (GDK_CONTROL_MASK | GDK_SHIFT_MASK | ...) @return true if the preview has to be redrawn, false otherwise */ - virtual bool drag3 (int modifierKey); + virtual bool drag3 (const int modifierKey); + + /** @brief Triggered when the user is releasing mouse button 1 while in action==ES_ACTION_PICKING mode + No modifier key is provided, since having a different modifier key than on button press will set picked to false. + @param picked True if the cursor is still above the the same object than on button pressed and with the same modifier keys. + If false, the user moved the cursor away or the modifier key is different, so the element is considered as NOT selected. + @return true if the preview has to be redrawn, false otherwise */ + virtual bool pick1 (const bool picked); + + /** @brief Triggered when the user is releasing mouse button 2 while in action==ES_ACTION_PICKING mode + @param picked True if the cursor is still above the the same object than on button pressed and with the same modifier keys. + If false, the user moved the cursor away or the modifier key is different, so the element is considered as NOT selected. + @return true if the preview has to be redrawn, false otherwise */ + virtual bool pick2 (const bool picked); + + /** @brief Triggered when the user is releasing mouse button 3 while in action==ES_ACTION_PICKING mode + @param picked True if the cursor is still above the the same object than on button pressed and with the same modifier keys. + If false, the user moved the cursor away or the modifier key is different, so the element is considered as NOT selected. + @return true if the preview has to be redrawn, false otherwise */ + virtual bool pick3 (const bool picked); /** @brief Get the geometry to be shown to the user */ const std::vector& getVisibleGeometry (); @@ -617,8 +692,8 @@ inline bool Geometry::isHoverable () { return flags & F_HOVERABLE; } -inline void Geometry::setHoverable (bool visible) { - if (visible) { +inline void Geometry::setHoverable (bool hoverable) { + if (hoverable) { flags |= F_HOVERABLE; } else { flags &= ~F_HOVERABLE; @@ -637,15 +712,15 @@ inline EditDataProvider* EditSubscriber::getEditProvider () { return provider; } -inline CursorShape EditSubscriber::getCursor (int objectID) { +inline CursorShape EditSubscriber::getCursor (const int objectID) { return CSOpenHand; } -inline bool EditSubscriber::mouseOver (int modifierKey) { +inline bool EditSubscriber::mouseOver (const int modifierKey) { return false; } -inline bool EditSubscriber::button1Pressed (int modifierKey) { +inline bool EditSubscriber::button1Pressed (const int modifierKey) { return false; } @@ -653,7 +728,7 @@ inline bool EditSubscriber::button1Released () { return false; } -inline bool EditSubscriber::button2Pressed (int modifierKey) { +inline bool EditSubscriber::button2Pressed (const int modifierKey) { return false; } @@ -661,7 +736,7 @@ inline bool EditSubscriber::button2Released () { return false; } -inline bool EditSubscriber::button3Pressed (int modifierKey) { +inline bool EditSubscriber::button3Pressed (const int modifierKey) { return false; } @@ -669,15 +744,27 @@ inline bool EditSubscriber::button3Released () { return false; } -inline bool EditSubscriber::drag1 (int modifierKey) { +inline bool EditSubscriber::drag1 (const int modifierKey) { return false; } -inline bool EditSubscriber::drag2 (int modifierKey) { +inline bool EditSubscriber::drag2 (const int modifierKey) { return false; } -inline bool EditSubscriber::drag3 (int modifierKey) { +inline bool EditSubscriber::drag3 (const int modifierKey) { + return false; +} + +inline bool EditSubscriber::pick1 (const bool picked) { + return false; +} + +inline bool EditSubscriber::pick2 (const bool picked) { + return false; +} + +inline bool EditSubscriber::pick3 (const bool picked) { return false; } diff --git a/rtgui/editenums.h b/rtgui/editenums.h index e51918426..557912222 100644 --- a/rtgui/editenums.h +++ b/rtgui/editenums.h @@ -20,7 +20,8 @@ #define _EDITENUMS_ enum ImgEditState {SNormal, SCropMove, SHandMove, SResizeW1, SResizeW2, SResizeH1, SResizeH2, SResizeTL, SResizeTR, SResizeBL, SResizeBR, - SCropSelecting, SRotateSelecting, SCropWinMove, SCropFrameMove, SCropImgMove, SCropWinResize, SObservedMove, SEditDrag1, SEditDrag2, SEditDrag3 + SCropSelecting, SRotateSelecting, SCropWinMove, SCropFrameMove, SCropImgMove, SCropWinResize, SObservedMove, + SEditDrag1, SEditDrag2, SEditDrag3, SEditPick1, SEditPick2, SEditPick3 }; enum CursorArea {CropWinButtons, CropToolBar, CropImage, CropBorder, CropTop, CropTopLeft, CropTopRight, CropBottom, CropBottomLeft, CropBottomRight, CropLeft, CropRight, CropInside, CropResize, CropObserved diff --git a/rtgui/editid.h b/rtgui/editid.h index 6bc808c87..c4f9315c0 100644 --- a/rtgui/editid.h +++ b/rtgui/editid.h @@ -57,9 +57,9 @@ enum EditType { /// @brief Buffer type for ET_PIPETTE type editing enum BufferType { - BT_IMAGEFLOAT, - BT_LABIMAGE, - BT_SINGLEPLANE_FLOAT + BT_IMAGEFLOAT, /// Imagefloat buffer type (3 channels of float values) + BT_LABIMAGE, /// LabImage buffer type (3 channels of float values) + BT_SINGLEPLANE_FLOAT /// All purpose, 1 channel buffer of float values }; /// @brief Number of object to be handled (for optimization purpose) diff --git a/rtgui/gradient.cc b/rtgui/gradient.cc index 7492d456b..50625251e 100644 --- a/rtgui/gradient.cc +++ b/rtgui/gradient.cc @@ -323,7 +323,7 @@ void Gradient::editToggled () } } -CursorShape Gradient::getCursor(int objectID) +CursorShape Gradient::getCursor(const int objectID) { switch (objectID) { case (0): @@ -349,7 +349,7 @@ CursorShape Gradient::getCursor(int objectID) } } -bool Gradient::mouseOver(int modifierKey) +bool Gradient::mouseOver(const int modifierKey) { EditDataProvider* editProvider = getEditProvider(); @@ -379,7 +379,7 @@ bool Gradient::mouseOver(int modifierKey) return false; } -bool Gradient::button1Pressed(int modifierKey) +bool Gradient::button1Pressed(const int modifierKey) { if (lastObject < 0) { return false; @@ -433,7 +433,7 @@ bool Gradient::button1Pressed(int modifierKey) draggedFeatherOffset -= (feather->getValue() / 200. * diagonal); } - EditSubscriber::dragging = true; + EditSubscriber::action = ES_ACTION_DRAGGING; return false; } else { // should theoretically always be true // this will let this class ignore further drag events @@ -454,11 +454,11 @@ bool Gradient::button1Pressed(int modifierKey) bool Gradient::button1Released() { draggedPointOldAngle = -1000.; - EditSubscriber::dragging = false; + EditSubscriber::action = ES_ACTION_NONE; return true; } -bool Gradient::drag1(int modifierKey) +bool Gradient::drag1(const int modifierKey) { // compute the polar coordinate of the mouse position EditDataProvider *provider = getEditProvider(); diff --git a/rtgui/gradient.h b/rtgui/gradient.h index f59fb07e5..d1acb764b 100644 --- a/rtgui/gradient.h +++ b/rtgui/gradient.h @@ -51,11 +51,11 @@ public: void setEditProvider (EditDataProvider* provider); // EditSubscriber interface - CursorShape getCursor(int objectID); - bool mouseOver(int modifierKey); - bool button1Pressed(int modifierKey); + CursorShape getCursor(const int objectID); + bool mouseOver(const int modifierKey); + bool button1Pressed(const int modifierKey); bool button1Released(); - bool drag1(int modifierKey); + bool drag1(const int modifierKey); void switchOffEditMode (); };