Spot removal : differentiating source/dest, betted cursor handling

+ some code cleanup from floessie (see issue #2239)
This commit is contained in:
Hombre 2019-09-01 02:08:48 +02:00
parent 4b7e8b7705
commit 82e7caa635
14 changed files with 222 additions and 132 deletions

View File

@ -23,18 +23,6 @@
#include "imagesource.h" #include "imagesource.h"
#include <iostream> #include <iostream>
namespace
{
// "ceil" rounding
template<typename T>
constexpr T skips(T a, T b)
{
return a / b + static_cast<bool>(a % b);
}
}
namespace rtengine namespace rtengine
{ {
@ -48,14 +36,12 @@ public:
}; };
struct Rectangle { struct Rectangle {
public:
int x1; int x1;
int y1; int y1;
int x2; int x2;
int y2; int y2;
Rectangle() : x1(0), y1(0), x2(0), y2(0) {} Rectangle() : Rectangle(0, 0, 0, 0) {}
Rectangle(const Rectangle &other) : x1(other.x1), y1(other.y1), x2(other.x2), y2(other.y2) {}
Rectangle(int X1, int Y1, int X2, int Y2) : x1(X1), y1(Y1), x2(X2), y2(Y2) {} Rectangle(int X1, int Y1, int X2, int Y2) : x1(X1), y1(Y1), x2(X2), y2(Y2) {}
bool intersects(const Rectangle &other) const { bool intersects(const Rectangle &other) const {
@ -65,21 +51,24 @@ public:
bool getIntersection(const Rectangle &other, std::unique_ptr<Rectangle> &intersection) const { bool getIntersection(const Rectangle &other, std::unique_ptr<Rectangle> &intersection) const {
if (intersects(other)) { if (intersects(other)) {
if (!intersection) { std::unique_ptr<Rectangle> intsec(
intersection.reset(new Rectangle()); new Rectangle(
} rtengine::max(x1, other.x1),
intersection->x1 = rtengine::max(x1, other.x1); rtengine::max(y1, other.y1),
intersection->x2 = rtengine::min(x2, other.x2); rtengine::min(x2, other.x2),
intersection->y1 = rtengine::max(y1, other.y1); rtengine::min(y2, other.y2)
intersection->y2 = rtengine::min(y2, other.y2); )
);
if (intersection->x1 > intersection->x2 || intersection->y1 > intersection->y2) { if (intsec->x1 > intsec->x2 || intsec->y1 > intsec->y2) {
intersection.release();
return false; return false;
} }
intersection = std::move(intsec);
return true; return true;
} }
if (intersection) { if (intersection) {
// There's no intersection, we delete the Rectangle structure
intersection.release(); intersection.release();
} }
return false; return false;
@ -101,15 +90,15 @@ public:
return *this; return *this;
} }
Rectangle& operator/=(const int &v) { Rectangle& operator/=(int v) {
if (v == 1) { if (v == 1) {
return *this; return *this;
} }
int w = x2 - x1 + 1; int w = x2 - x1 + 1;
int h = y2 - y1 + 1; int h = y2 - y1 + 1;
w = w / v + (w % v > 0); w = w / v + static_cast<bool>(w % v);
h = h / v + (h % v > 0); h = h / v + static_cast<bool>(h % v);
x1 /= v; x1 /= v;
y1 /= v; y1 /= v;
x2 = x1 + w - 1; x2 = x1 + w - 1;
@ -173,7 +162,7 @@ public:
} }
} }
SpotBox& operator /=(const int& v) { SpotBox& operator /=(int v) {
if (v == 1) { if (v == 1) {
return *this; return *this;
} }

View File

@ -497,7 +497,7 @@ void CropWindow::buttonPress (int button, int type, int bstate, int x, int y)
cropgl->cropInit (cropHandler.cropParams->x, cropHandler.cropParams->y, cropHandler.cropParams->w, cropHandler.cropParams->h); cropgl->cropInit (cropHandler.cropParams->x, cropHandler.cropParams->y, cropHandler.cropParams->w, cropHandler.cropParams->h);
} else if (iarea->getToolMode () == TMHand) { } else if (iarea->getToolMode () == TMHand) {
if (editSubscriber) { if (editSubscriber) {
if ((cropgl && cropgl->inImageArea(iarea->posImage.x, iarea->posImage.y) && editSubscriber->getEditingType() == ET_PIPETTE && (bstate & GDK_CONTROL_MASK))) { if ((cropgl && cropgl->inImageArea(iarea->posImage.x, iarea->posImage.y) && (editSubscriber->getEditingType() == ET_PIPETTE && (bstate & GDK_CONTROL_MASK))) || editSubscriber->getEditingType() == ET_OBJECTS) {
needRedraw = editSubscriber->button1Pressed(bstate); needRedraw = editSubscriber->button1Pressed(bstate);
if (editSubscriber->isDragging()) { if (editSubscriber->isDragging()) {
state = SEditDrag1; state = SEditDrag1;
@ -1277,7 +1277,10 @@ void CropWindow::updateCursor (int x, int y)
} else if (onArea (CropToolBar, x, y)) { } else if (onArea (CropToolBar, x, y)) {
newType = CSMove; newType = CSMove;
} else if (iarea->getObject() > -1 && editSubscriber && editSubscriber->getEditingType() == ET_OBJECTS) { } else if (iarea->getObject() > -1 && editSubscriber && editSubscriber->getEditingType() == ET_OBJECTS) {
newType = editSubscriber->getCursor(iarea->getObject()); int cursorX;
int cursorY;
screenCoordToImage (x, y, cursorX, cursorY);
newType = editSubscriber->getCursor(iarea->getObject(), cursorX, cursorY);
} else if (onArea (CropResize, x, y)) { } else if (onArea (CropResize, x, y)) {
newType = CSResizeDiagonal; newType = CSResizeDiagonal;
} else if (tm == TMColorPicker && hoveredPicker) { } else if (tm == TMColorPicker && hoveredPicker) {
@ -1304,7 +1307,10 @@ void CropWindow::updateCursor (int x, int y)
} }
if (objectID > -1) { if (objectID > -1) {
newType = editSubscriber->getCursor(objectID); int cursorX;
int cursorY;
screenCoordToImage (x, y, cursorX, cursorY);
newType = editSubscriber->getCursor(objectID, cursorX, cursorY);
} else if (tm == TMHand) { } else if (tm == TMHand) {
if (onArea (CropObserved, x, y)) { if (onArea (CropObserved, x, y)) {
newType = CSMove; newType = CSMove;
@ -1330,7 +1336,10 @@ void CropWindow::updateCursor (int x, int y)
} }
if (objectID > -1) { if (objectID > -1) {
newType = editSubscriber->getCursor(objectID); int cursorX;
int cursorY;
screenCoordToImage (x, y, cursorX, cursorY);
newType = editSubscriber->getCursor(objectID, cursorX, cursorY);
} else { } else {
newType = CSArrow; newType = CSArrow;
} }
@ -1359,6 +1368,16 @@ void CropWindow::updateCursor (int x, int y)
newType = CSResizeDiagonal; newType = CSResizeDiagonal;
} else if (state == SDragPicker) { } else if (state == SDragPicker) {
newType = CSMove2D; newType = CSMove2D;
} else if (editSubscriber && editSubscriber->getEditingType() == ET_OBJECTS) {
int objectID = iarea->getObject();
if (objectID > -1) {
int cursorX;
int cursorY;
screenCoordToImage (x, y, cursorX, cursorY);
newType = editSubscriber->getCursor(objectID, cursorX, cursorY);
} else {
newType = CSArrow;
}
} }
if (newType != cursor_type) { if (newType != cursor_type) {

View File

@ -490,7 +490,7 @@ bool CurveEditor::drag1(int modifierKey)
return false; return false;
} }
CursorShape CurveEditor::getCursor(int objectID) const CursorShape CurveEditor::getCursor(int objectID, int xPos, int yPos) const
{ {
if (remoteDrag) { if (remoteDrag) {
return CSResizeHeight; return CSResizeHeight;

View File

@ -133,7 +133,7 @@ public:
bool button1Pressed(int modifierKey) override; bool button1Pressed(int modifierKey) override;
bool button1Released() override; bool button1Released() override;
bool drag1(int modifierKey) override; bool drag1(int modifierKey) override;
CursorShape getCursor(int objectID) const override; CursorShape getCursor(int objectID, int xPos, int yPos) const override;
}; };

View File

@ -172,10 +172,10 @@ void EditDataProvider::setPipetteVal3(float newVal)
pipetteVal3 = newVal; pipetteVal3 = newVal;
} }
CursorShape EditDataProvider::getCursor(int objectID) const CursorShape EditDataProvider::getCursor(int objectID, int xPos, int yPos) const
{ {
if (currSubscriber) { if (currSubscriber) {
currSubscriber->getCursor(objectID); currSubscriber->getCursor(objectID, xPos, yPos);
} }
return CSHandOpen; return CSHandOpen;
@ -186,12 +186,12 @@ EditSubscriber* EditDataProvider::getCurrSubscriber() const
return currSubscriber; return currSubscriber;
} }
EditDataProvider* EditSubscriber::getEditProvider() EditDataProvider* EditSubscriber::getEditProvider() const
{ {
return provider; return provider;
} }
CursorShape EditSubscriber::getCursor(int objectID) const CursorShape EditSubscriber::getCursor(int objectID, int xPos, int yPos) const
{ {
return CSHandOpen; return CSHandOpen;
} }

View File

@ -57,7 +57,7 @@ public:
virtual ~EditSubscriber () = default; virtual ~EditSubscriber () = default;
void setEditProvider(EditDataProvider *provider); void setEditProvider(EditDataProvider *provider);
EditDataProvider* getEditProvider (); EditDataProvider* getEditProvider () const;
void setEditID(EditUniqueID ID, BufferType buffType); void setEditID(EditUniqueID ID, BufferType buffType);
bool isCurrentSubscriber() const; bool isCurrentSubscriber() const;
virtual void subscribe(); virtual void subscribe();
@ -70,8 +70,10 @@ public:
bool isPicking() const; /// Returns true if something is being picked bool isPicking() const; /// Returns true if something is being picked
/** @brief Get the cursor to be displayed when above handles /** @brief Get the cursor to be displayed when above handles
@param objectID object currently "hovered" */ @param objectID object currently "hovered"
virtual CursorShape getCursor (int objectID) const; @param xPos X cursor position in image space
@param yPos Y cursor position in image space */
virtual CursorShape getCursor (int objectID, int xPos, int yPos) const;
/** @brief Triggered when the mouse is moving over an object /** @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 This method is also triggered when the cursor is moving over the image in ET_PIPETTE mode
@ -188,7 +190,7 @@ public:
void setPipetteVal1(float newVal); void setPipetteVal1(float newVal);
void setPipetteVal2(float newVal); void setPipetteVal2(float newVal);
void setPipetteVal3(float newVal); void setPipetteVal3(float newVal);
virtual CursorShape getCursor(int objectID) const; virtual CursorShape getCursor(int objectID, int xPos, int yPos) const;
int getPipetteRectSize () const; int getPipetteRectSize () const;
EditSubscriber* getCurrSubscriber() const; EditSubscriber* getCurrSubscriber() const;
virtual void getImageSize (int &w, int&h) = 0; virtual void getImageSize (int &w, int&h) = 0;

View File

@ -20,7 +20,11 @@
#include "editwidgets.h" #include "editwidgets.h"
#include "editbuffer.h" #include "editbuffer.h"
#include "editcallbacks.h" #include "editcallbacks.h"
#include "../rtengine/rt_math.h"
const std::vector<double> Geometry::dash = {3., 1.5};
#define INNERGEOM_OPACITY 1.
#define OUTERGEOM_OPACITY 0.7
RGBColor Geometry::getInnerLineColor () RGBColor Geometry::getInnerLineColor ()
{ {
@ -65,7 +69,8 @@ RGBColor Geometry::getOuterLineColor ()
void Circle::drawOuterGeometry(Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) void Circle::drawOuterGeometry(Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem)
{ {
if ((flags & F_VISIBLE) && state != INSENSITIVE) { double lineWidth = getOuterLineWidth();
if ((flags & F_VISIBLE) && state != INSENSITIVE && lineWidth > 0. && innerLineWidth > 0.) {
RGBColor color; RGBColor color;
if (flags & F_AUTO_COLOR) { if (flags & F_AUTO_COLOR) {
@ -74,8 +79,9 @@ void Circle::drawOuterGeometry(Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuffer
color = outerLineColor; color = outerLineColor;
} }
cr->set_source_rgb (color.getR(), color.getG(), color.getB()); cr->set_source_rgba (color.getR(), color.getG(), color.getB(), OUTERGEOM_OPACITY * rtengine::min(innerLineWidth / 2.f, 1.f));
cr->set_line_width( getOuterLineWidth() ); cr->set_line_width (lineWidth);
cr->set_line_cap(Cairo::LINE_CAP_ROUND);
rtengine::Coord center_ = center; rtengine::Coord center_ = center;
double radius_ = radiusInImageSpace ? coordSystem.scaleValueToCanvas(double(radius)) : double(radius); double radius_ = radiusInImageSpace ? coordSystem.scaleValueToCanvas(double(radius)) : double(radius);
@ -105,10 +111,11 @@ void Circle::drawInnerGeometry(Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuffer
color = innerLineColor; color = innerLineColor;
} }
cr->set_source_rgb(color.getR(), color.getG(), color.getB()); cr->set_source_rgba (color.getR(), color.getG(), color.getB(), INNERGEOM_OPACITY);
} }
cr->set_line_width(innerLineWidth); cr->set_line_width(innerLineWidth);
cr->set_line_cap(flags & F_DASHED ? Cairo::LINE_CAP_BUTT : Cairo::LINE_CAP_ROUND);
rtengine::Coord center_ = center; rtengine::Coord center_ = center;
double radius_ = radiusInImageSpace ? coordSystem.scaleValueToCanvas(double(radius)) : double(radius); double radius_ = radiusInImageSpace ? coordSystem.scaleValueToCanvas(double(radius)) : double(radius);
@ -121,9 +128,12 @@ void Circle::drawInnerGeometry(Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuffer
center_ += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen; center_ += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen;
} }
if (filled && state != INSENSITIVE) { if (flags & F_DASHED) {
cr->arc(center_.x + 0.5, center_.y + 0.5, radius_, 0., 2.*rtengine::RT_PI); cr->set_dash(dash, 0.);
}
if (filled) {
cr->arc(center_.x + 0.5, center_.y + 0.5, radius_, 0., 2.*rtengine::RT_PI);
if (innerLineWidth > 0.) { if (innerLineWidth > 0.) {
cr->fill_preserve(); cr->fill_preserve();
cr->stroke(); cr->stroke();
@ -132,20 +142,11 @@ void Circle::drawInnerGeometry(Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuffer
} }
} else if (innerLineWidth > 0.) { } else if (innerLineWidth > 0.) {
cr->arc(center_.x + 0.5, center_.y + 0.5, radius_, 0., 2.*rtengine::RT_PI); cr->arc(center_.x + 0.5, center_.y + 0.5, radius_, 0., 2.*rtengine::RT_PI);
if (state == INSENSITIVE) {
std::valarray<double> ds(1);
ds[0] = 4;
cr->set_source_rgba(1.0, 1.0, 1.0, 0.618);
cr->stroke_preserve();
cr->set_source_rgba(0.0, 0.0, 0.0, 0.618);
cr->set_dash(ds, 0);
cr->stroke();
ds.resize(0);
cr->set_dash(ds, 0);
} else {
cr->stroke(); cr->stroke();
} }
if (flags & F_DASHED) {
cr->unset_dash();
} }
} }
} }
@ -154,6 +155,7 @@ void Circle::drawToMOChannel (Cairo::RefPtr<Cairo::Context> &cr, unsigned short
{ {
if (flags & F_HOVERABLE) { if (flags & F_HOVERABLE) {
cr->set_line_width( getMouseOverLineWidth() ); cr->set_line_width( getMouseOverLineWidth() );
cr->set_line_cap(Cairo::LINE_CAP_ROUND);
rtengine::Coord center_ = center; rtengine::Coord center_ = center;
double radius_ = radiusInImageSpace ? coordSystem.scaleValueToCanvas(double(radius)) : double(radius); double radius_ = radiusInImageSpace ? coordSystem.scaleValueToCanvas(double(radius)) : double(radius);
@ -188,7 +190,8 @@ void Circle::drawToMOChannel (Cairo::RefPtr<Cairo::Context> &cr, unsigned short
void Line::drawOuterGeometry(Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) void Line::drawOuterGeometry(Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem)
{ {
if ((flags & F_VISIBLE) && state != INSENSITIVE) { double lineWidth = getOuterLineWidth();
if ((flags & F_VISIBLE) && state != INSENSITIVE && lineWidth > 0. && innerLineWidth > 0.) {
RGBColor color; RGBColor color;
if (flags & F_AUTO_COLOR) { if (flags & F_AUTO_COLOR) {
@ -197,8 +200,9 @@ void Line::drawOuterGeometry(Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuffer *
color = outerLineColor; color = outerLineColor;
} }
cr->set_source_rgb (color.getR(), color.getG(), color.getB()); cr->set_source_rgba (color.getR(), color.getG(), color.getB(), OUTERGEOM_OPACITY * rtengine::min(innerLineWidth / 2.f, 1.f));
cr->set_line_width( getOuterLineWidth() ); cr->set_line_width (lineWidth);
cr->set_line_cap(Cairo::LINE_CAP_ROUND);
rtengine::Coord begin_ = begin; rtengine::Coord begin_ = begin;
rtengine::Coord end_ = end; rtengine::Coord end_ = end;
@ -232,10 +236,11 @@ void Line::drawInnerGeometry(Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuffer *
color = innerLineColor; color = innerLineColor;
} }
cr->set_source_rgb (color.getR(), color.getG(), color.getB()); cr->set_source_rgba (color.getR(), color.getG(), color.getB(), INNERGEOM_OPACITY);
} }
cr->set_line_width(innerLineWidth); cr->set_line_width(innerLineWidth);
cr->set_line_cap(flags & F_DASHED ? Cairo::LINE_CAP_BUTT : Cairo::LINE_CAP_ROUND);
rtengine::Coord begin_ = begin; rtengine::Coord begin_ = begin;
rtengine::Coord end_ = end; rtengine::Coord end_ = end;
@ -251,21 +256,16 @@ void Line::drawInnerGeometry(Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuffer *
end_ += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen; end_ += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen;
} }
if (flags & F_DASHED) {
cr->set_dash(dash, 0.);
}
cr->move_to(begin_.x + 0.5, begin_.y + 0.5); cr->move_to(begin_.x + 0.5, begin_.y + 0.5);
cr->line_to(end_.x + 0.5, end_.y + 0.5); cr->line_to(end_.x + 0.5, end_.y + 0.5);
cr->stroke();
if (state == INSENSITIVE) { if (flags & F_DASHED) {
std::valarray<double> ds(1); cr->unset_dash();
ds[0] = 4;
cr->set_source_rgba(1.0, 1.0, 1.0, 0.618);
cr->stroke_preserve();
cr->set_source_rgba(0.0, 0.0, 0.0, 0.618);
cr->set_dash(ds, 0);
cr->stroke();
ds.resize(0);
cr->set_dash(ds, 0);
} else {
cr->stroke();
} }
} }
} }
@ -274,6 +274,7 @@ void Line::drawToMOChannel(Cairo::RefPtr<Cairo::Context> &cr, unsigned short id,
{ {
if (flags & F_HOVERABLE) { if (flags & F_HOVERABLE) {
cr->set_line_width( getMouseOverLineWidth() ); cr->set_line_width( getMouseOverLineWidth() );
cr->set_line_cap(Cairo::LINE_CAP_ROUND);
rtengine::Coord begin_ = begin; rtengine::Coord begin_ = begin;
rtengine::Coord end_ = end; rtengine::Coord end_ = end;
@ -302,7 +303,8 @@ void Line::drawToMOChannel(Cairo::RefPtr<Cairo::Context> &cr, unsigned short id,
void Polyline::drawOuterGeometry(Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) void Polyline::drawOuterGeometry(Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem)
{ {
if ((flags & F_VISIBLE) && state != INSENSITIVE && points.size() > 1) { double lineWidth = getOuterLineWidth();
if ((flags & F_VISIBLE) && state != INSENSITIVE && points.size() > 1 && lineWidth > 0.) {
RGBColor color; RGBColor color;
if (flags & F_AUTO_COLOR) { if (flags & F_AUTO_COLOR) {
@ -311,8 +313,10 @@ void Polyline::drawOuterGeometry(Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuff
color = outerLineColor; color = outerLineColor;
} }
cr->set_source_rgb (color.getR(), color.getG(), color.getB()); cr->set_source_rgba (color.getR(), color.getG(), color.getB(), OUTERGEOM_OPACITY * rtengine::min(innerLineWidth / 2.f, 1.f));
cr->set_line_width( getOuterLineWidth() ); cr->set_line_width (lineWidth);
cr->set_line_cap(Cairo::LINE_CAP_ROUND);
cr->set_line_join(Cairo::LINE_JOIN_ROUND);
rtengine::Coord currPos; rtengine::Coord currPos;
@ -355,10 +359,16 @@ void Polyline::drawInnerGeometry(Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuff
color = innerLineColor; color = innerLineColor;
} }
cr->set_source_rgb (color.getR(), color.getG(), color.getB()); cr->set_source_rgba (color.getR(), color.getG(), color.getB(), INNERGEOM_OPACITY);
} }
cr->set_line_width(innerLineWidth); cr->set_line_width(innerLineWidth);
cr->set_line_cap(flags & F_DASHED ? Cairo::LINE_CAP_BUTT : Cairo::LINE_CAP_ROUND);
cr->set_line_join(Cairo::LINE_JOIN_ROUND);
if (flags & F_DASHED) {
cr->set_dash(dash, 0.);
}
if (filled && state != INSENSITIVE) { if (filled && state != INSENSITIVE) {
rtengine::Coord currPos; rtengine::Coord currPos;
@ -407,20 +417,11 @@ void Polyline::drawInnerGeometry(Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuff
cr->line_to(currPos.x + 0.5, currPos.y + 0.5); cr->line_to(currPos.x + 0.5, currPos.y + 0.5);
} }
} }
if (state == INSENSITIVE) {
std::valarray<double> ds(1);
ds[0] = 4;
cr->set_source_rgba(1.0, 1.0, 1.0, 0.618);
cr->stroke_preserve();
cr->set_source_rgba(0.0, 0.0, 0.0, 0.618);
cr->set_dash(ds, 0);
cr->stroke();
ds.resize(0);
cr->set_dash(ds, 0);
} else {
cr->stroke(); cr->stroke();
} }
if (flags & F_DASHED) {
cr->unset_dash();
} }
} }
} }
@ -437,8 +438,11 @@ void Polyline::drawToMOChannel (Cairo::RefPtr<Cairo::Context> &cr, unsigned shor
cr->set_source_rgba (0., 0., 0., (id + 1) / 65535.); cr->set_source_rgba (0., 0., 0., (id + 1) / 65535.);
} }
for (unsigned int i = 0; i < points.size(); ++i) {
cr->set_line_width( getMouseOverLineWidth() ); cr->set_line_width( getMouseOverLineWidth() );
cr->set_line_cap(Cairo::LINE_CAP_ROUND);
cr->set_line_join(Cairo::LINE_JOIN_ROUND);
for (unsigned int i = 0; i < points.size(); ++i) {
currPos = points.at(i); currPos = points.at(i);
if (datum == IMAGE) { if (datum == IMAGE) {
@ -495,7 +499,8 @@ void Rectangle::setXYXY(rtengine::Coord topLeft, rtengine::Coord bottomRight)
void Rectangle::drawOuterGeometry(Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) void Rectangle::drawOuterGeometry(Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem)
{ {
if ((flags & F_VISIBLE) && state != INSENSITIVE) { double lineWidth = getOuterLineWidth();
if ((flags & F_VISIBLE) && state != INSENSITIVE && lineWidth > 0. && innerLineWidth > 0.) {
RGBColor color; RGBColor color;
if (flags & F_AUTO_COLOR) { if (flags & F_AUTO_COLOR) {
@ -504,8 +509,9 @@ void Rectangle::drawOuterGeometry(Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuf
color = outerLineColor; color = outerLineColor;
} }
cr->set_source_rgb (color.getR(), color.getG(), color.getB()); cr->set_source_rgba (color.getR(), color.getG(), color.getB(), OUTERGEOM_OPACITY * rtengine::min(innerLineWidth / 2.f, 1.f));
cr->set_line_width( getOuterLineWidth() ); cr->set_line_width (lineWidth);
cr->set_line_join(Cairo::LINE_JOIN_BEVEL);
rtengine::Coord tl, br; rtengine::Coord tl, br;
@ -548,10 +554,11 @@ void Rectangle::drawInnerGeometry(Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuf
color = innerLineColor; color = innerLineColor;
} }
cr->set_source_rgb (color.getR(), color.getG(), color.getB()); cr->set_source_rgba (color.getR(), color.getG(), color.getB(), INNERGEOM_OPACITY);
} }
cr->set_line_width(innerLineWidth); cr->set_line_width(innerLineWidth);
cr->set_line_join(Cairo::LINE_JOIN_BEVEL);
rtengine::Coord tl, br; rtengine::Coord tl, br;
@ -571,7 +578,11 @@ void Rectangle::drawInnerGeometry(Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuf
br = bottomRight + objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen; br = bottomRight + objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen;
} }
if (filled && state != INSENSITIVE) { if (flags & F_DASHED) {
cr->set_dash(dash, 0.);
}
if (filled) {
cr->rectangle(tl.x + 0.5, tl.y + 0.5, br.x - tl.x, br.y - tl.y); cr->rectangle(tl.x + 0.5, tl.y + 0.5, br.x - tl.x, br.y - tl.y);
if (innerLineWidth > 0.) { if (innerLineWidth > 0.) {
@ -582,20 +593,11 @@ void Rectangle::drawInnerGeometry(Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuf
} }
} else if (innerLineWidth > 0.) { } else if (innerLineWidth > 0.) {
cr->rectangle(tl.x + 0.5, tl.y + 0.5, br.x - tl.x, br.y - tl.y); cr->rectangle(tl.x + 0.5, tl.y + 0.5, br.x - tl.x, br.y - tl.y);
if (state == INSENSITIVE) {
std::valarray<double> ds(1);
ds[0] = 4;
cr->set_source_rgba(1.0, 1.0, 1.0, 0.618);
cr->stroke_preserve();
cr->set_source_rgba(0.0, 0.0, 0.0, 0.618);
cr->set_dash(ds, 0);
cr->stroke();
ds.resize(0);
cr->set_dash(ds, 0);
} else {
cr->stroke(); cr->stroke();
} }
if (flags & F_DASHED) {
cr->unset_dash();
} }
} }
} }
@ -604,6 +606,7 @@ void Rectangle::drawToMOChannel(Cairo::RefPtr<Cairo::Context> &cr, unsigned shor
{ {
if (flags & F_HOVERABLE) { if (flags & F_HOVERABLE) {
cr->set_line_width( getMouseOverLineWidth() ); cr->set_line_width( getMouseOverLineWidth() );
cr->set_line_join(Cairo::LINE_JOIN_ROUND);
rtengine::Coord tl, br; rtengine::Coord tl, br;

View File

@ -24,6 +24,7 @@
#include "editbuffer.h" #include "editbuffer.h"
#include "editcoordsys.h" #include "editcoordsys.h"
#include "../rtengine/coord.h" #include "../rtengine/coord.h"
#include "../rtengine/rt_math.h"
class ObjectMOBuffer; class ObjectMOBuffer;
@ -208,6 +209,8 @@ public:
F_VISIBLE = 1 << 0, /// true if the geometry have to be drawn on the visible layer F_VISIBLE = 1 << 0, /// true if the geometry have to be drawn on the visible layer
F_HOVERABLE = 1 << 1, /// true if the geometry have to be drawn on the "mouse over" layer F_HOVERABLE = 1 << 1, /// true if the geometry have to be drawn on the "mouse over" layer
F_AUTO_COLOR = 1 << 2, /// true if the color depend on the state value, not the color field above F_AUTO_COLOR = 1 << 2, /// true if the color depend on the state value, not the color field above
F_DASHED = 1 << 3, /// true if the geometry have to be drawn as a dash line
// (TODO: add a F_LARGE_DASH to have two different dash size ?)
}; };
/// @brief Key point of the image's rectangle that is used to locate the icon copy to the target point: /// @brief Key point of the image's rectangle that is used to locate the icon copy to the target point:
@ -224,6 +227,7 @@ public:
}; };
protected: protected:
static const std::vector<double> dash;
RGBColor innerLineColor; RGBColor innerLineColor;
RGBColor outerLineColor; RGBColor outerLineColor;
short flags; short flags;
@ -249,6 +253,8 @@ public:
void setVisible (bool visible); void setVisible (bool visible);
bool isHoverable (); bool isHoverable ();
void setHoverable (bool visible); void setHoverable (bool visible);
bool isDashed ();
void setDashed (bool dashed);
// setActive will enable/disable the visible and hoverable flags in one shot! // setActive will enable/disable the visible and hoverable flags in one shot!
@ -427,7 +433,7 @@ inline void Geometry::setOuterLineColor (char r, char g, char b) {
} }
inline double Geometry::getMouseOverLineWidth () { inline double Geometry::getMouseOverLineWidth () {
return getOuterLineWidth () + 2.; return rtengine::max(double(innerLineWidth), 1.) + 2.;
} }
inline void Geometry::setAutoColor (bool aColor) { inline void Geometry::setAutoColor (bool aColor) {
@ -462,6 +468,18 @@ inline void Geometry::setHoverable (bool hoverable) {
} }
} }
inline bool Geometry::isDashed () {
return flags & F_DASHED;
}
inline void Geometry::setDashed (bool dashed) {
if (dashed) {
flags |= F_DASHED;
} else {
flags &= ~F_DASHED;
}
}
inline void Geometry::setActive (bool active) { inline void Geometry::setActive (bool active) {
if (active) { if (active) {
flags |= (F_VISIBLE | F_HOVERABLE); flags |= (F_VISIBLE | F_HOVERABLE);

View File

@ -225,7 +225,7 @@ void FilmNegative::setEditProvider(EditDataProvider* provider)
EditSubscriber::setEditProvider(provider); EditSubscriber::setEditProvider(provider);
} }
CursorShape FilmNegative::getCursor(int objectID) const CursorShape FilmNegative::getCursor(int objectID, int xPos, int yPos) const
{ {
return CSSpotWB; return CSSpotWB;
} }

View File

@ -59,7 +59,7 @@ public:
void setEditProvider(EditDataProvider* provider) override; void setEditProvider(EditDataProvider* provider) override;
// EditSubscriber interface // EditSubscriber interface
CursorShape getCursor(int objectID) const override; CursorShape getCursor(int objectID, int xPos, int yPos) const override;
bool mouseOver(int modifierKey) override; bool mouseOver(int modifierKey) override;
bool button1Pressed(int modifierKey) override; bool button1Pressed(int modifierKey) override;
bool button1Released() override; bool button1Released() override;

View File

@ -327,7 +327,7 @@ void Gradient::editToggled ()
} }
} }
CursorShape Gradient::getCursor(int objectID) const CursorShape Gradient::getCursor(int objectID, int xPos, int yPos) const
{ {
switch (objectID) { switch (objectID) {
case (0): case (0):

View File

@ -51,7 +51,7 @@ public:
void setEditProvider (EditDataProvider* provider) override; void setEditProvider (EditDataProvider* provider) override;
// EditSubscriber interface // EditSubscriber interface
CursorShape getCursor(int objectID) const override; CursorShape getCursor(int objectID, int xPos, int yPos) const override;
bool mouseOver(int modifierKey) override; bool mouseOver(int modifierKey) override;
bool button1Pressed(int modifierKey) override; bool button1Pressed(int modifierKey) override;
bool button1Released() override; bool button1Released() override;

View File

@ -32,8 +32,14 @@ using namespace rtengine::procparams;
#define STATIC_VISIBLE_OBJ_NBR 6 #define STATIC_VISIBLE_OBJ_NBR 6
#define STATIC_MO_OBJ_NBR 6 #define STATIC_MO_OBJ_NBR 6
Spot::Spot() : FoldableToolPanel (this, "spot", M ("TP_SPOT_LABEL"), true, true), EditSubscriber (ET_OBJECTS), lastObject (-1), activeSpot (-1), Spot::Spot() :
sourceIcon ("spot-normal.png", "spot-active.png", "spot-active.png", "spot-prelight.png", "", Geometry::DP_CENTERCENTER), editedCheckBox (nullptr) FoldableToolPanel(this, "spot", M ("TP_SPOT_LABEL"), true, true),
EditSubscriber(ET_OBJECTS),
draggedSide(DraggedSide::NONE),
lastObject(-1),
activeSpot(-1),
sourceIcon("spot-normal.png", "spot-active.png", "spot-prelight.png", "", "", Geometry::DP_CENTERCENTER),
editedCheckBox(nullptr)
{ {
countLabel = Gtk::manage (new Gtk::Label (Glib::ustring::compose (M ("TP_SPOT_COUNTLABEL"), 0))); countLabel = Gtk::manage (new Gtk::Label (Glib::ustring::compose (M ("TP_SPOT_COUNTLABEL"), 0)));
@ -61,6 +67,7 @@ Spot::Spot() : FoldableToolPanel (this, "spot", M ("TP_SPOT_LABEL"), true, true)
sourceCircle.datum = Geometry::IMAGE; sourceCircle.datum = Geometry::IMAGE;
sourceCircle.setActive (false); sourceCircle.setActive (false);
sourceCircle.radiusInImageSpace = true; sourceCircle.radiusInImageSpace = true;
sourceCircle.setDashed(true);
sourceMODisc.datum = Geometry::IMAGE; sourceMODisc.datum = Geometry::IMAGE;
sourceMODisc.setActive (false); sourceMODisc.setActive (false);
sourceMODisc.radiusInImageSpace = true; sourceMODisc.radiusInImageSpace = true;
@ -77,9 +84,12 @@ Spot::Spot() : FoldableToolPanel (this, "spot", M ("TP_SPOT_LABEL"), true, true)
sourceFeatherCircle.datum = Geometry::IMAGE; sourceFeatherCircle.datum = Geometry::IMAGE;
sourceFeatherCircle.setActive (false); sourceFeatherCircle.setActive (false);
sourceFeatherCircle.radiusInImageSpace = true; sourceFeatherCircle.radiusInImageSpace = true;
sourceFeatherCircle.setDashed(true);
sourceFeatherCircle.innerLineWidth = 0.7;
targetFeatherCircle.datum = Geometry::IMAGE; targetFeatherCircle.datum = Geometry::IMAGE;
targetFeatherCircle.setActive (false); targetFeatherCircle.setActive (false);
targetFeatherCircle.radiusInImageSpace = true; targetFeatherCircle.radiusInImageSpace = true;
targetFeatherCircle.innerLineWidth = 0.7;
link.datum = Geometry::IMAGE; link.datum = Geometry::IMAGE;
link.setActive (false); link.setActive (false);
@ -241,6 +251,10 @@ Geometry* Spot::getVisibleGeometryFromMO (int MOID)
return &sourceIcon; return &sourceIcon;
} }
if (MOID > STATIC_MO_OBJ_NBR) {
return EditSubscriber::visibleGeometry.at(MOID - STATIC_MO_OBJ_NBR);
}
return EditSubscriber::mouseOverGeometry.at (MOID); return EditSubscriber::mouseOverGeometry.at (MOID);
} }
@ -259,10 +273,12 @@ void Spot::createGeometry ()
delete EditSubscriber::visibleGeometry.at (i); delete EditSubscriber::visibleGeometry.at (i);
} }
size_t i = 0, j = 0; // mouse over geometry starts with the static geometry, then the spot's icon geometry
EditSubscriber::mouseOverGeometry.resize (STATIC_MO_OBJ_NBR + nbrEntry); EditSubscriber::mouseOverGeometry.resize (STATIC_MO_OBJ_NBR + nbrEntry);
// visible geometry starts with the spot's icon geometry, then the static geometry
EditSubscriber::visibleGeometry.resize (nbrEntry + STATIC_VISIBLE_OBJ_NBR); EditSubscriber::visibleGeometry.resize (nbrEntry + STATIC_VISIBLE_OBJ_NBR);
size_t i = 0, j = 0;
EditSubscriber::mouseOverGeometry.at (i++) = &targetMODisc; // STATIC_MO_OBJ_NBR + 0 EditSubscriber::mouseOverGeometry.at (i++) = &targetMODisc; // STATIC_MO_OBJ_NBR + 0
EditSubscriber::mouseOverGeometry.at (i++) = &sourceMODisc; // STATIC_MO_OBJ_NBR + 1 EditSubscriber::mouseOverGeometry.at (i++) = &sourceMODisc; // STATIC_MO_OBJ_NBR + 1
EditSubscriber::mouseOverGeometry.at (i++) = &targetCircle; // STATIC_MO_OBJ_NBR + 2 EditSubscriber::mouseOverGeometry.at (i++) = &targetCircle; // STATIC_MO_OBJ_NBR + 2
@ -351,6 +367,10 @@ void Spot::updateGeometry()
} else { } else {
link.setActive (false); link.setActive (false);
} }
sourceCircle.setVisible(draggedSide != DraggedSide::SOURCE);
targetCircle.setVisible(draggedSide != DraggedSide::TARGET);
link.setVisible(draggedSide == DraggedSide::NONE);
} else { } else {
targetCircle.setActive (false); targetCircle.setActive (false);
targetMODisc.setActive (false); targetMODisc.setActive (false);
@ -432,10 +452,37 @@ void Spot::deleteSelectedEntry()
} }
} }
// TODO CursorShape Spot::getCursor (int objectID, int xPos, int yPos) const
CursorShape Spot::getCursor (int objectID) const
{ {
return CSHandOpen; const EditDataProvider* editProvider = getEditProvider();
if (editProvider) {
if (draggedSide != DraggedSide::NONE) {
return CSEmpty;
}
int object = editProvider->getObject();
if (object == 0 || object == 1) {
return CSMove2D;
}
if (object >= 2 || object <= 5) {
Coord delta(Coord(xPos, yPos) - ((object == 3 || object == 5) ? spots.at(activeSpot).sourcePos : spots.at(activeSpot).targetPos));
PolarCoord polarPos(delta);
if (polarPos.angle < 0.) {
polarPos.angle += 180.;
}
if (polarPos.angle < 22.5 || polarPos.angle >= 157.5) {
return CSMove1DH;
}
if (polarPos.angle < 67.5) {
return CSResizeBottomRight;
}
if (polarPos.angle < 112.5) {
return CSMove1DV;
}
return CSResizeBottomLeft;
}
}
return CSCrosshair;
} }
bool Spot::mouseOver (int modifierKey) bool Spot::mouseOver (int modifierKey)
@ -494,10 +541,12 @@ bool Spot::button1Pressed (int modifierKey)
if (editProvider) { if (editProvider) {
if (lastObject == -1 && (modifierKey & GDK_CONTROL_MASK)) { if (lastObject == -1 && (modifierKey & GDK_CONTROL_MASK)) {
draggedSide = DraggedSide::SOURCE;
addNewEntry(); addNewEntry();
EditSubscriber::action = EditSubscriber::Action::DRAGGING; EditSubscriber::action = EditSubscriber::Action::DRAGGING;
return true; return true;
} else if (lastObject > -1) { } else if (lastObject > -1) {
draggedSide = lastObject == 0 ? DraggedSide::TARGET : lastObject == 1 ? DraggedSide::SOURCE : DraggedSide::NONE;
getVisibleGeometryFromMO (lastObject)->state = Geometry::DRAGGED; getVisibleGeometryFromMO (lastObject)->state = Geometry::DRAGGED;
EditSubscriber::action = EditSubscriber::Action::DRAGGING; EditSubscriber::action = EditSubscriber::Action::DRAGGING;
return true; return true;
@ -519,6 +568,7 @@ bool Spot::button1Released()
loGeom->state = Geometry::PRELIGHT; loGeom->state = Geometry::PRELIGHT;
EditSubscriber::action = EditSubscriber::Action::NONE; EditSubscriber::action = EditSubscriber::Action::NONE;
draggedSide = DraggedSide::NONE;
updateGeometry(); updateGeometry();
return true; return true;
} }
@ -552,6 +602,7 @@ bool Spot::button3Pressed (int modifierKey)
lastObject = 1; // sourceMODisc lastObject = 1; // sourceMODisc
sourceIcon.state = Geometry::DRAGGED; sourceIcon.state = Geometry::DRAGGED;
EditSubscriber::action = EditSubscriber::Action::DRAGGING; EditSubscriber::action = EditSubscriber::Action::DRAGGING;
draggedSide = DraggedSide::SOURCE;
return true; return true;
} else if (! (modifierKey & (GDK_SHIFT_MASK | GDK_SHIFT_MASK))) { } else if (! (modifierKey & (GDK_SHIFT_MASK | GDK_SHIFT_MASK))) {
EditSubscriber::action = EditSubscriber::Action::PICKING; EditSubscriber::action = EditSubscriber::Action::PICKING;
@ -571,6 +622,7 @@ bool Spot::button3Released()
lastObject = -1; lastObject = -1;
sourceIcon.state = Geometry::ACTIVE; sourceIcon.state = Geometry::ACTIVE;
draggedSide = DraggedSide::NONE;
updateGeometry(); updateGeometry();
EditSubscriber::action = EditSubscriber::Action::NONE; EditSubscriber::action = EditSubscriber::Action::NONE;
return true; return true;

View File

@ -57,6 +57,13 @@ class Spot : public ToolParamBlock, public FoldableToolPanel, public rtengine::T
{ {
private: private:
enum class DraggedSide {
NONE,
SOURCE,
TARGET
};
DraggedSide draggedSide; // tells which of source or target is being dragged
int lastObject; // current object that is hovered int lastObject; // current object that is hovered
int activeSpot; // currently active spot, being edited int activeSpot; // currently active spot, being edited
std::vector<rtengine::procparams::SpotEntry> spots; // list of edited spots std::vector<rtengine::procparams::SpotEntry> spots; // list of edited spots
@ -103,7 +110,7 @@ public:
void setBatchMode (bool batchMode) override; void setBatchMode (bool batchMode) override;
// EditSubscriber interface // EditSubscriber interface
CursorShape getCursor (int objectID) const override; CursorShape getCursor (int objectID, int xPos, int yPos) const override;
bool mouseOver (int modifierKey) override; bool mouseOver (int modifierKey) override;
bool button1Pressed (int modifierKey) override; bool button1Pressed (int modifierKey) override;
bool button1Released () override; bool button1Released () override;