Modified Preview Canvas

- Now the Preview can show free space around the image (the image's
corner will coincide with the center of the preview area)
- Editing objects can now be manipulated in this free space
- The editing mechanism has been split : it was completely handled in
rtengine before, now rtengine still handle the pipette's data provider,
but rtgui now handle the objects data provider.
- Bugfix: when using coarse rotate in the Editor panel, the Gradient
widgets are now correctly displayed
This commit is contained in:
Hombre 2016-01-29 22:09:56 +01:00
parent 8c3e6eab95
commit 4665b88788
22 changed files with 1413 additions and 848 deletions

View File

@ -11,7 +11,7 @@ set (RTENGINESOURCEFILES safegtk.cc colortemp.cc curves.cc flatcurves.cc diagona
dfmanager.cc ffmanager.cc gauss.cc rawimage.cc image8.cc image16.cc imagefloat.cc imagedata.cc imageio.cc improcfun.cc init.cc dcrop.cc
loadinitial.cc procparams.cc rawimagesource.cc demosaic_algos.cc shmap.cc simpleprocess.cc refreshmap.cc
fast_demo.cc amaze_demosaic_RT.cc CA_correct_RT.cc cfa_linedn_RT.cc green_equil_RT.cc hilite_recon.cc expo_before_b.cc
stdimagesource.cc myfile.cc iccjpeg.cc hlmultipliers.cc improccoordinator.cc editbuffer.cc coord.cc
stdimagesource.cc myfile.cc iccjpeg.cc hlmultipliers.cc improccoordinator.cc pipettebuffer.cc coord.cc
processingjob.cc rtthumbnail.cc utils.cc labimage.cc slicer.cc cieimage.cc
iplab2rgb.cc ipsharpen.cc iptransform.cc ipresize.cc ipvibrance.cc
imagedimensions.cc jpeg_memsrc.cc jdatasrc.cc iimage.cc

View File

@ -28,7 +28,7 @@
#include "../rtgui/mydiagonalcurve.h"
#include "color.h"
#include "procparams.h"
#include "editbuffer.h"
#include "pipettebuffer.h"
#include "LUT.h"

View File

@ -31,7 +31,7 @@ namespace rtengine
extern const Settings* settings;
Crop::Crop (ImProcCoordinator* parent, EditDataProvider *editDataProvider, bool isDetailWindow)
: EditBuffer(editDataProvider), origCrop(NULL), laboCrop(NULL), labnCrop(NULL),
: PipetteBuffer(editDataProvider), origCrop(NULL), laboCrop(NULL), labnCrop(NULL),
cropImg(NULL), cbuf_real(NULL), cshmap(NULL), transCrop(NULL), cieCrop(NULL), cbuffer(NULL),
updating(false), newUpdatePending(false), skip(10),
cropx(0), cropy(0), cropw(-1), croph(-1),
@ -77,7 +77,7 @@ void Crop::setListener (DetailedCropListener* il)
EditUniqueID Crop::getCurrEditID()
{
EditSubscriber *subscriber = EditBuffer::dataProvider ? EditBuffer::dataProvider->getCurrSubscriber() : NULL;
EditSubscriber *subscriber = PipetteBuffer::dataProvider ? PipetteBuffer::dataProvider->getCurrSubscriber() : NULL;
return subscriber ? subscriber->getEditID() : EUID_None;
}
@ -90,32 +90,25 @@ void Crop::setEditSubscriber(EditSubscriber* newSubscriber)
MyMutex::MyLock lock(cropMutex);
// At this point, editCrop.dataProvider->currSubscriber is the old subscriber
EditSubscriber *oldSubscriber = EditBuffer::dataProvider ? EditBuffer::dataProvider->getCurrSubscriber() : NULL;
EditSubscriber *oldSubscriber = PipetteBuffer::dataProvider ? PipetteBuffer::dataProvider->getCurrSubscriber() : NULL;
if (newSubscriber == NULL || (oldSubscriber != NULL && oldSubscriber->getEditBufferType() != newSubscriber->getEditBufferType())) {
if (EditBuffer::imgFloatBuffer != NULL) {
delete EditBuffer::imgFloatBuffer;
EditBuffer::imgFloatBuffer = NULL;
if (newSubscriber == NULL || (oldSubscriber != NULL && oldSubscriber->getPipetteBufferType() != newSubscriber->getPipetteBufferType())) {
if (PipetteBuffer::imgFloatBuffer != NULL) {
delete PipetteBuffer::imgFloatBuffer;
PipetteBuffer::imgFloatBuffer = NULL;
}
if (EditBuffer::LabBuffer != NULL) {
delete EditBuffer::LabBuffer;
EditBuffer::LabBuffer = NULL;
if (PipetteBuffer::LabBuffer != NULL) {
delete PipetteBuffer::LabBuffer;
PipetteBuffer::LabBuffer = NULL;
}
if (EditBuffer::singlePlaneBuffer.getW() != -1) {
EditBuffer::singlePlaneBuffer.flushData();
if (PipetteBuffer::singlePlaneBuffer.getW() != -1) {
PipetteBuffer::singlePlaneBuffer.flushData();
}
}
if (newSubscriber == NULL && oldSubscriber != NULL && oldSubscriber->getEditingType() == ET_OBJECTS) {
printf("Free object buffers\n");
EditBuffer::resize(0, 0); // This will delete the objects buffer
} else if (newSubscriber && newSubscriber->getEditingType() == ET_OBJECTS) {
EditBuffer::resize(cropw, croph, newSubscriber);
}
// If oldSubscriber == NULL && newSubscriber != NULL -> the image will be allocated when necessary
// If oldSubscriber == NULL && newSubscriber != NULL && newSubscriber->getEditingType() == ET_PIPETTE-> the image will be allocated when necessary
}
void Crop::update (int todo)
@ -984,7 +977,7 @@ void Crop::update (int todo)
}
// all pipette buffer processing should be finished now
EditBuffer::setReady();
PipetteBuffer::setReady();
// switch back to rgb
parent->ipf.lab2monitorRgb (labnCrop, cropImg);
@ -1085,7 +1078,7 @@ void Crop::freeAll ()
cshmap = NULL;
}
EditBuffer::flush();
PipetteBuffer::flush();
}
cropAllocated = false;
@ -1157,6 +1150,15 @@ bool Crop::setCropSizes (int rcx, int rcy, int rcw, int rch, int skip, bool inte
printf ("setsizes starts (%d, %d, %d, %d, %d, %d)\n", orW, orH, trafw, trafh, cw, ch);
}
EditType editType = ET_PIPETTE;
EditDataProvider *editProvider = PipetteBuffer::getDataProvider();
if (editProvider) {
EditSubscriber *editSubscriber = editProvider->getCurrSubscriber();
if (editSubscriber) {
editType = editSubscriber->getEditingType();
}
}
if (cw != cropw || ch != croph || orW != trafw || orH != trafh) {
cropw = cw;
@ -1223,7 +1225,11 @@ bool Crop::setCropSizes (int rcx, int rcy, int rcw, int rch, int skip, bool inte
cshmap = new SHMap (cropw, croph, true);
}
EditBuffer::resize(cropw, croph);
if (editType == ET_PIPETTE) {
PipetteBuffer::resize(cropw, croph);
} else if (PipetteBuffer::bufferCreated()) {
PipetteBuffer::flush();
}
cropAllocated = true;
@ -1235,7 +1241,12 @@ bool Crop::setCropSizes (int rcx, int rcy, int rcw, int rch, int skip, bool inte
trafx = orx;
trafy = ory;
if (settings->verbose) {
if (changed) {
printf("new crop size: cropx=%d, cropy=%d, cropw=%d, croph=%d / rqcropx=%d, rqcropy=%d, rqcropw=%d, rqcroph=%d / leftBorder=%d, upperBorder=%d\n",
cropx, cropy, cropw, croph, rqcropx, rqcropy, rqcropw, rqcroph, leftBorder, upperBorder);
}
printf ("setsizes ends\n");
}

View File

@ -26,7 +26,7 @@
#include "image16.h"
#include "imagesource.h"
#include "procevents.h"
#include "editbuffer.h"
#include "pipettebuffer.h"
#include "../rtgui/threadutils.h"
namespace rtengine
@ -36,7 +36,7 @@ using namespace procparams;
class ImProcCoordinator;
class Crop : public DetailedCrop, public EditBuffer
class Crop : public DetailedCrop, public PipetteBuffer
{
protected:
@ -57,6 +57,7 @@ protected:
bool updating; /// Flag telling if an updater thread is currently processing
bool newUpdatePending; /// Flag telling the updater thread that a new update is pending
int skip;
int padding; /// Minimum space allowed around image in the display area
int cropx, cropy, cropw, croph; /// size of the detail crop image ('skip' taken into account), with border
int trafx, trafy, trafw, trafh; /// the size and position to get from the imagesource that is transformed to the requested crop area
int rqcropx, rqcropy, rqcropw, rqcroph; /// size of the requested detail crop image (the image might be smaller) (without border)
@ -70,7 +71,7 @@ protected:
ImProcCoordinator* parent;
bool isDetailWindow;
EditUniqueID getCurrEditID();
bool setCropSizes (int cx, int cy, int cw, int ch, int skip, bool internal);
bool setCropSizes (int cropX, int cropY, int cropW, int cropH, int skip, bool internal);
void freeAll ();
public:
@ -91,9 +92,9 @@ public:
return cropImageListener;
}
void update (int todo);
void setWindow (int cx, int cy, int cw, int ch, int skip)
void setWindow (int cropX, int cropY, int cropW, int cropH, int canvasX, int canvasY, int canvasW, int canvasH, int skip)
{
setCropSizes (cx, cy, cw, ch, skip, false);
setCropSizes (cropX, cropY, cropW, cropH, skip, false);
}
/** @brief Synchronously look out if a full update is necessary
@ -109,6 +110,10 @@ public:
{
return skip;
}
int getPadding ()
{
return padding;
}
int getLeftBorder ()
{
return leftBorder;

View File

@ -3106,15 +3106,15 @@ filmlike_clip(float *r, float *g, float *b)
}
}
void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, EditBuffer *editBuffer, LUTf & hltonecurve, LUTf & shtonecurve, LUTf & tonecurve,
void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer *pipetteBuffer, LUTf & hltonecurve, LUTf & shtonecurve, LUTf & tonecurve,
SHMap* shmap, int sat, LUTf & rCurve, LUTf & gCurve, LUTf & bCurve, float satLimit , float satLimitOpacity, const ColorGradientCurve & ctColorCurve, const OpacityCurve & ctOpacityCurve, bool opautili, LUTf & clToningcurve, LUTf & cl2Toningcurve,
const ToneCurve & customToneCurve1, const ToneCurve & customToneCurve2, const ToneCurve & customToneCurvebw1, const ToneCurve & customToneCurvebw2, double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, DCPProfile *dcpProf )
{
rgbProc (working, lab, editBuffer, hltonecurve, shtonecurve, tonecurve, shmap, sat, rCurve, gCurve, bCurve, satLimit , satLimitOpacity, ctColorCurve, ctOpacityCurve, opautili, clToningcurve, cl2Toningcurve, customToneCurve1, customToneCurve2, customToneCurvebw1, customToneCurvebw2, rrm, ggm, bbm, autor, autog, autob, params->toneCurve.expcomp, params->toneCurve.hlcompr, params->toneCurve.hlcomprthresh, dcpProf);
rgbProc (working, lab, pipetteBuffer, hltonecurve, shtonecurve, tonecurve, shmap, sat, rCurve, gCurve, bCurve, satLimit , satLimitOpacity, ctColorCurve, ctOpacityCurve, opautili, clToningcurve, cl2Toningcurve, customToneCurve1, customToneCurve2, customToneCurvebw1, customToneCurvebw2, rrm, ggm, bbm, autor, autog, autob, params->toneCurve.expcomp, params->toneCurve.hlcompr, params->toneCurve.hlcomprthresh, dcpProf);
}
// Process RGB image and convert to LAB space
void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, EditBuffer *editBuffer, LUTf & hltonecurve, LUTf & shtonecurve, LUTf & tonecurve,
void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer *pipetteBuffer, LUTf & hltonecurve, LUTf & shtonecurve, LUTf & tonecurve,
SHMap* shmap, int sat, LUTf & rCurve, LUTf & gCurve, LUTf & bCurve, float satLimit , float satLimitOpacity, const ColorGradientCurve & ctColorCurve, const OpacityCurve & ctOpacityCurve, bool opautili, LUTf & clToningcurve, LUTf & cl2Toningcurve,
const ToneCurve & customToneCurve1, const ToneCurve & customToneCurve2, const ToneCurve & customToneCurvebw1, const ToneCurve & customToneCurvebw2, double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, double expcomp, int hlcompr, int hlcomprthresh, DCPProfile *dcpProf)
{
@ -3125,20 +3125,20 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, EditBuffer *e
Imagefloat* editImgFloat = NULL;
LabImage* editLab = NULL;
PlanarWhateverData<float>* editWhatever = NULL;
EditUniqueID editID = editBuffer ? editBuffer->getEditID() : EUID_None;
EditUniqueID editID = pipetteBuffer ? pipetteBuffer->getEditID() : EUID_None;
if (editID != EUID_None) {
switch (editBuffer->getDataProvider()->getCurrSubscriber()->getEditBufferType()) {
switch (pipetteBuffer->getDataProvider()->getCurrSubscriber()->getPipetteBufferType()) {
case (BT_IMAGEFLOAT):
editImgFloat = editBuffer->getImgFloatBuffer();
editImgFloat = pipetteBuffer->getImgFloatBuffer();
break;
case (BT_LABIMAGE):
editLab = editBuffer->getLabBuffer();
editLab = pipetteBuffer->getLabBuffer();
break;
case (BT_SINGLEPLANE_FLOAT):
editWhatever = editBuffer->getSinglePlaneBuffer();
editWhatever = pipetteBuffer->getSinglePlaneBuffer();
break;
}
}
@ -3447,7 +3447,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, EditBuffer *e
int tW;
int tH;
// Allocating buffer for the EditBuffer
// Allocating buffer for the PipetteBuffer
float *editIFloatTmpR, *editIFloatTmpG, *editIFloatTmpB, *editWhateverTmp;
if (editImgFloat) {
@ -5552,7 +5552,7 @@ void ImProcFunctions::luminanceCurve (LabImage* lold, LabImage* lnew, LUTf & cur
SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (EditBuffer *editBuffer, int pW, LabImage* lold, LabImage* lnew, LUTf & acurve, LUTf & bcurve, LUTf & satcurve, LUTf & lhskcurve, LUTf & clcurve, LUTf & curve, bool utili, bool autili, bool butili, bool ccutili, bool cclutili, bool clcutili, LUTu &histCCurve, LUTu &histCLurve, LUTu &histLLCurve, LUTu &histLCurve)
SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW, LabImage* lold, LabImage* lnew, LUTf & acurve, LUTf & bcurve, LUTf & satcurve, LUTf & lhskcurve, LUTf & clcurve, LUTf & curve, bool utili, bool autili, bool butili, bool ccutili, bool cclutili, bool clcutili, LUTu &histCCurve, LUTu &histCLurve, LUTu &histLLCurve, LUTu &histLCurve)
{
int W = lold->W;
int H = lold->H;
@ -5566,23 +5566,23 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (EditBuffer *editBuffer,
EditUniqueID editID = EUID_None;
bool editPipette = false;
if (editBuffer) {
editID = editBuffer->getEditID();
if (pipetteBuffer) {
editID = pipetteBuffer->getEditID();
if (editID != EUID_None) {
editPipette = true;
switch (editBuffer->getDataProvider()->getCurrSubscriber()->getEditBufferType()) {
switch (pipetteBuffer->getDataProvider()->getCurrSubscriber()->getPipetteBufferType()) {
case (BT_IMAGEFLOAT):
editImgFloat = editBuffer->getImgFloatBuffer();
editImgFloat = pipetteBuffer->getImgFloatBuffer();
break;
case (BT_LABIMAGE):
editLab = editBuffer->getLabBuffer();
editLab = pipetteBuffer->getLabBuffer();
break;
case (BT_SINGLEPLANE_FLOAT):
editWhatever = editBuffer->getSinglePlaneBuffer();
editWhatever = pipetteBuffer->getSinglePlaneBuffer();
break;
}
}

View File

@ -33,7 +33,7 @@
#include "dcp.h"
#include "curves.h"
#include "cplx_wavelet_dec.h"
#include "editbuffer.h"
#include "pipettebuffer.h"
#define PIX_SORT(a,b) { if ((a)>(b)) {temp=(a);(a)=(b);(b)=temp;} }
@ -235,10 +235,10 @@ public:
void firstAnalysis (Imagefloat* working, const ProcParams* params, LUTu & vhist16);
void updateColorProfiles (const ColorManagementParams& icm, const Glib::ustring& monitorProfile, RenderingIntent monitorIntent);
void rgbProc (Imagefloat* working, LabImage* lab, EditBuffer *editBuffer, LUTf & hltonecurve, LUTf & shtonecurve, LUTf & tonecurve,
void rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer *pipetteBuffer, LUTf & hltonecurve, LUTf & shtonecurve, LUTf & tonecurve,
SHMap* shmap, int sat, LUTf & rCurve, LUTf & gCurve, LUTf & bCurve, float satLimit , float satLimitOpacity, const ColorGradientCurve & ctColorCurve, const OpacityCurve & ctOpacityCurve, bool opautili, LUTf & clcurve, LUTf & cl2curve, const ToneCurve & customToneCurve1, const ToneCurve & customToneCurve2,
const ToneCurve & customToneCurvebw1, const ToneCurve & customToneCurvebw2, double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, DCPProfile *dcpProf);
void rgbProc (Imagefloat* working, LabImage* lab, EditBuffer *editBuffer, LUTf & hltonecurve, LUTf & shtonecurve, LUTf & tonecurve,
void rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer *pipetteBuffer, LUTf & hltonecurve, LUTf & shtonecurve, LUTf & tonecurve,
SHMap* shmap, int sat, LUTf & rCurve, LUTf & gCurve, LUTf & bCurve, float satLimit , float satLimitOpacity, const ColorGradientCurve & ctColorCurve, const OpacityCurve & ctOpacityCurve, bool opautili, LUTf & clcurve, LUTf & cl2curve, const ToneCurve & customToneCurve1, const ToneCurve & customToneCurve2,
const ToneCurve & customToneCurvebw1, const ToneCurve & customToneCurvebw2, double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob,
double expcomp, int hlcompr, int hlcomprthresh, DCPProfile *dcpProf);
@ -259,7 +259,7 @@ public:
void ciecam_02 (CieImage* ncie, double adap, int begh, int endh, int pW, int pwb, LabImage* lab, const ProcParams* params,
const ColorAppearance & customColCurve1, const ColorAppearance & customColCurve, const ColorAppearance & customColCurve3,
LUTu &histLCAM, LUTu &histCCAM, LUTf & CAMBrightCurveJ, LUTf & CAMBrightCurveQ, float &mean, int Iterates, int scale, bool execsharp, double &d, int scalecd, int rtt);
void chromiLuminanceCurve (EditBuffer *editBuffer, int pW, LabImage* lold, LabImage* lnew, LUTf &acurve, LUTf &bcurve, LUTf & satcurve, LUTf & satclcurve, LUTf &clcurve, LUTf &curve, bool utili, bool autili, bool butili, bool ccutili, bool cclutili, bool clcutili, LUTu &histCCurve, LUTu &histCLurve, LUTu &histLCurve, LUTu &histLurve);
void chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW, LabImage* lold, LabImage* lnew, LUTf &acurve, LUTf &bcurve, LUTf & satcurve, LUTf & satclcurve, LUTf &clcurve, LUTf &curve, bool utili, bool autili, bool butili, bool ccutili, bool cclutili, bool clcutili, LUTu &histCCurve, LUTu &histCLurve, LUTu &histLCurve, LUTu &histLurve);
void vibrance (LabImage* lab);//Jacques' vibrance
void colorCurve (LabImage* lold, LabImage* lnew);
void sharpening (LabImage* lab, float** buffer, SharpeningParams &sharpenParam);

View File

@ -17,16 +17,15 @@
* along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
*/
#include "editbuffer.h"
#include "pipettebuffer.h"
namespace rtengine
{
EditBuffer::EditBuffer(::EditDataProvider *dataProvider) :
objectMap(NULL), objectMap2(NULL), objectMode(OM_255), dataProvider(dataProvider),
imgFloatBuffer(NULL), LabBuffer(NULL), singlePlaneBuffer(), ready(false) {}
PipetteBuffer::PipetteBuffer(::EditDataProvider *dataProvider) :
dataProvider(dataProvider), imgFloatBuffer(NULL), LabBuffer(NULL), singlePlaneBuffer(), ready(false) {}
EditBuffer::~EditBuffer()
PipetteBuffer::~PipetteBuffer()
{
flush();
#ifndef NDEBUG
@ -37,13 +36,13 @@ EditBuffer::~EditBuffer()
#endif
}
void EditBuffer::createBuffer(int width, int height)
void PipetteBuffer::createBuffer(int width, int height)
{
//printf("Appel de createBuffer %d x %d\n", width, height);
resize (width, height);
}
void EditBuffer::flush()
void PipetteBuffer::flush()
{
if (imgFloatBuffer) {
delete imgFloatBuffer;
@ -59,29 +58,7 @@ void EditBuffer::flush()
ready = false;
}
/* Upgrade or downgrade the objectModeType; we're assuming that objectMap has been allocated */
void EditBuffer::setObjectMode(ObjectMode newType)
{
switch (newType) {
case (OM_255):
if (objectMap2) {
objectMap2->unreference();
}
objectMode = OM_255;
break;
case (OM_65535):
if (!objectMap2) {
objectMap2 = Cairo::ImageSurface::create(Cairo::FORMAT_A8, objectMap->get_width(), objectMap->get_height());
}
objectMode = OM_65535;
break;
}
}
EditUniqueID EditBuffer::getEditID()
EditUniqueID PipetteBuffer::getEditID()
{
if (dataProvider && dataProvider->getCurrSubscriber()) {
return dataProvider->getCurrSubscriber()->getEditID();
@ -90,58 +67,17 @@ EditUniqueID EditBuffer::getEditID()
}
}
void EditBuffer::resize(int newWidth, int newHeight)
void PipetteBuffer::resize(int newWidth, int newHeight)
{
resize(newWidth, newHeight, dataProvider ? dataProvider->getCurrSubscriber() : NULL);
}
// Resize buffers if they already exist
void EditBuffer::resize(int newWidth, int newHeight, EditSubscriber* newSubscriber)
void PipetteBuffer::resize(int newWidth, int newHeight, EditSubscriber* newSubscriber)
{
if (newSubscriber) {
if (newSubscriber->getEditingType() == ET_OBJECTS) {
if (objectMap && (objectMap->get_width() != newWidth || objectMap->get_height() != newHeight)) {
objectMap.clear();
}
if (!objectMap && newWidth && newHeight) {
objectMap = Cairo::ImageSurface::create(Cairo::FORMAT_A8, newWidth, newHeight);
}
if (objectMode == OM_65535) {
if (objectMap2) {
if (objectMap2->get_width() != newWidth || objectMap2->get_height() != newHeight) {
objectMap2.clear();
}
}
if (!objectMap2 && newWidth && newHeight) {
objectMap2 = Cairo::ImageSurface::create(Cairo::FORMAT_A8, newWidth, newHeight);
}
}
// OM_255 -> deleting objectMap2, if any
else if (objectMap2) {
objectMap2.clear();
}
// Should never happen!
if (imgFloatBuffer) {
delete imgFloatBuffer;
imgFloatBuffer = NULL;
}
if (LabBuffer) {
delete LabBuffer;
LabBuffer = NULL;
}
if (singlePlaneBuffer.data) {
singlePlaneBuffer.allocate(0, 0);
}
}
if (newSubscriber->getEditingType() == ET_PIPETTE) {
if (newSubscriber->getEditBufferType() == BT_IMAGEFLOAT) {
if (newSubscriber->getPipetteBufferType() == BT_IMAGEFLOAT) {
if (!imgFloatBuffer) {
imgFloatBuffer = new Imagefloat(newWidth, newHeight);
} else {
@ -152,7 +88,7 @@ void EditBuffer::resize(int newWidth, int newHeight, EditSubscriber* newSubscrib
imgFloatBuffer = NULL;
}
if (newSubscriber->getEditBufferType() == BT_LABIMAGE) {
if (newSubscriber->getPipetteBufferType() == BT_LABIMAGE) {
if (LabBuffer && (LabBuffer->W != newWidth && LabBuffer->H != newHeight)) {
delete LabBuffer;
LabBuffer = NULL;
@ -166,73 +102,46 @@ void EditBuffer::resize(int newWidth, int newHeight, EditSubscriber* newSubscrib
LabBuffer = NULL;
}
if (newSubscriber->getEditBufferType() == BT_SINGLEPLANE_FLOAT) {
if (newSubscriber->getPipetteBufferType() == BT_SINGLEPLANE_FLOAT) {
singlePlaneBuffer.allocate(newWidth, newHeight);
} else if (singlePlaneBuffer.data) {
singlePlaneBuffer.allocate(0, 0);
}
// Should never happen!
if (objectMap ) {
objectMap.clear();
}
if (objectMap2) {
objectMap2.clear();
}
} else {
// Should never happen
flush();
}
}
ready = false;
}
bool EditBuffer::bufferCreated()
bool PipetteBuffer::bufferCreated()
{
EditSubscriber* subscriber;
if (dataProvider && (subscriber = dataProvider->getCurrSubscriber())) {
switch (subscriber->getEditingType()) {
case ET_PIPETTE:
switch (dataProvider->getCurrSubscriber()->getEditBufferType()) {
if (subscriber->getEditingType() == ET_PIPETTE) {
switch (dataProvider->getCurrSubscriber()->getPipetteBufferType()) {
case (BT_IMAGEFLOAT):
return imgFloatBuffer != NULL;
case (BT_LABIMAGE):
return LabBuffer != NULL;
case (BT_SINGLEPLANE_FLOAT):
return singlePlaneBuffer.data != NULL;
}
break;
case (ET_OBJECTS):
return bool(objectMap);
} else {
return false;
}
}
return false;
}
int EditBuffer::getObjectID(const Coord& location)
{
int id = 0;
if (objectMap && location.x > 0 && location.y > 0 && location.x < objectMap->get_width() && location.y < objectMap->get_height()) {
id = (unsigned short)(*( objectMap->get_data() + location.y * objectMap->get_stride() + location.x ));
if (objectMap2) {
id |= (unsigned short)(*( objectMap->get_data() + location.y * objectMap->get_stride() + location.x )) << 8;
}
}
return id - 1;
}
void EditBuffer::getPipetteData(float* v, int x, int y, int squareSize)
void PipetteBuffer::getPipetteData(float* v, int x, int y, int squareSize)
{
if (ready && dataProvider && dataProvider->getCurrSubscriber()) {
switch (dataProvider->getCurrSubscriber()->getEditBufferType()) {
switch (dataProvider->getCurrSubscriber()->getPipetteBufferType()) {
case (BT_IMAGEFLOAT):
if (imgFloatBuffer) {
imgFloatBuffer->getPipetteData(v[0], v[1], v[2], x, y, squareSize, 0);

View File

@ -16,8 +16,8 @@
* You should have received a copy of the GNU General Public License
* along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _EDITBUFFER_H_
#define _EDITBUFFER_H_
#ifndef _PIPETTEBUFFER_H_
#define _PIPETTEBUFFER_H_
#include "../rtgui/edit.h"
#include "array2D.h"
@ -28,16 +28,8 @@ namespace rtengine
{
/// @brief Structure that contains information about and pointers to the Edit buffer
class EditBuffer
class PipetteBuffer
{
private:
// Used to draw the objects where the color correspond to the object's ID, in order to find the correct object when hovering
Cairo::RefPtr<Cairo::ImageSurface> objectMap;
// If more than 254 objects has to be handled, objectMap2 contains the "upper part" of the 16 bit int value. objectMap2 will be NULL otherwise.
Cairo::RefPtr<Cairo::ImageSurface> objectMap2;
ObjectMode objectMode;
protected:
// To avoid duplicated information, we points to a EditDataProvider that contains the current EditSubscriber
@ -58,8 +50,8 @@ protected:
void flush();
public:
EditBuffer(::EditDataProvider *dataProvider);
~EditBuffer();
PipetteBuffer(::EditDataProvider *dataProvider);
~PipetteBuffer();
/** @brief Getter to know if the pipette buffer is correctly filled */
bool isReady()
@ -74,7 +66,6 @@ public:
ready = true;
}
void setObjectMode(ObjectMode newType);
::EditDataProvider* getDataProvider()
{
return dataProvider;
@ -92,24 +83,10 @@ public:
{
return &singlePlaneBuffer;
}
ObjectMode getObjectMode()
{
return objectMode;
}
Cairo::RefPtr<Cairo::ImageSurface> &getObjectMap ()
{
return objectMap;
}
Cairo::RefPtr<Cairo::ImageSurface> &getObjectMap2()
{
return objectMap2;
}
// return true if the buffer has been allocated
bool bufferCreated();
int getObjectID(const Coord& location);
// get the pipette values
void getPipetteData(float* v, int x, int y, int squareSize);
};

View File

@ -24,13 +24,16 @@
#include "cropwindow.h"
#include "../rtengine/dcrop.h"
#include "../rtengine/refreshmap.h"
#include "../rtengine/rt_math.h"
using namespace rtengine;
CropHandler::CropHandler ()
: zoom(10), ww(0), wh(0), cx(0), cy(0), cw(0), ch(0),
cropX(0), cropY(0), cropW(0), cropH(0), enabled(false),
cropimg(NULL), cropimgtrue(NULL), ipc(NULL), crop(NULL), listener(NULL), isLowUpdatePriority(false)
: zoom(10), ww(0), wh(0), imx(-1), imy(-1), imw(0), imh(0), cax(-1), cay(-1),
cx(0), cy(0), cw(0), ch(0), cropX(0), cropY(0), cropW(0), cropH(0), enabled(false),
cropimg(NULL), cropimgtrue(NULL), cropimg_width(0), cropimg_height(0),
initial(false), isLowUpdatePriority(false), ipc(NULL), crop(NULL),
displayHandler(NULL)
{
chi = new CropHandlerIdleHelper;
@ -82,7 +85,7 @@ void CropHandler::newImage (StagedImageProcessor* ipc_, bool isDetailWindow)
}
EditDataProvider *editDataProvider = NULL;
CropWindow *cropWin = listener ? static_cast<CropWindow*>(listener) : NULL;
CropWindow *cropWin = displayHandler ? static_cast<CropWindow*>(displayHandler) : NULL;
if (cropWin) {
editDataProvider = cropWin->getImageArea();
@ -126,16 +129,28 @@ double CropHandler::getFitZoom ()
void CropHandler::setZoom (int z, int centerx, int centery)
{
assert (ipc);
int x = cx + cw / 2;
int y = cy + ch / 2;
float oldScale = zoom >= 1000 ? float(zoom / 1000) : 1.f / float(zoom);
float newScale = z >= 1000 ? float(z / 1000) : 1.f / float(z);
if (centerx >= 0) {
x = centerx;
int oldcax = cax;
int oldcay = cay;
if (centerx == -1) {
cax = ipc->getFullWidth () / 2;
} else {
float distToAnchor = float(cax - centerx);
distToAnchor = distToAnchor / newScale * oldScale;
cax = centerx + int(distToAnchor);
}
if (centery >= 0) {
y = centery;
if (centery == -1) {
cay = ipc->getFullHeight () / 2;
} else {
float distToAnchor = float(cay - centery);
distToAnchor = distToAnchor / newScale * oldScale;
cay = centery + int(distToAnchor);
}
// maybe demosaic etc. if we cross the border to >100%
@ -151,12 +166,18 @@ void CropHandler::setZoom (int z, int centerx, int centery)
ch = wh * zoom;
}
cx = x - cw / 2;
cy = y - ch / 2;
cx = cax - cw / 2;
cy = cay - ch / 2;
int oldCropX = cropX;
int oldCropY = cropY;
int oldCropW = cropW;
int oldCropH = cropH;
compDim ();
if (enabled) {
if (enabled && (oldcax != cax || oldcay != cay || oldCropX != cropX || oldCropY != cropY || oldCropW != cropW || oldCropH != cropH)) {
if (needsFullRefresh) {
ipc->startProcessing(M_HIGHQUAL);
} else {
@ -194,11 +215,44 @@ void CropHandler::getWSize (int& w, int &h)
h = wh;
}
void CropHandler::setPosition (int x, int y, bool update_)
void CropHandler::getAnchorPosition (int& x, int& y)
{
x = cax;
y = cay;
}
cx = x;
cy = y;
void CropHandler::setAnchorPosition (int x, int y, bool update_)
{
cax = x;
cay = y;
compDim ();
if (enabled && update_) {
update ();
}
}
void CropHandler::moveAnchor (int deltaX, int deltaY, bool update_)
{
cax += deltaX;
cay += deltaY;
compDim ();
if (enabled && update_) {
update ();
}
}
void CropHandler::centerAnchor (bool update_)
{
assert (ipc);
// Computes the crop's size and position given the anchor's position and display size
cax = ipc->getFullWidth() / 2;
cay = ipc->getFullHeight() / 2;
compDim ();
@ -280,11 +334,11 @@ int createpixbufs (void* data)
ch->cimg.unlock ();
if (ch->listener) {
ch->listener->cropImageUpdated ();
if (ch->displayHandler) {
ch->displayHandler->cropImageUpdated ();
if (ch->initial) {
ch->listener->initialImageArrived ();
ch->displayHandler->initialImageArrived ();
ch->initial = false;
}
}
@ -365,7 +419,7 @@ bool CropHandler::getWindow (int& cwx, int& cwy, int& cww, int& cwh, int& cskip)
void CropHandler::update ()
{
if (crop) {
if (crop && enabled) {
// crop->setWindow (cropX, cropY, cropW, cropH, zoom>=1000 ? 1 : zoom); --> we use the "getWindow" hook instead of setting the size before
crop->setListener (this);
cropPixbuf.clear ();
@ -428,41 +482,78 @@ void CropHandler::getFullImageSize (int& w, int& h)
void CropHandler::compDim ()
{
assert (ipc && displayHandler);
cropX = cx;
cropY = cy;
cropW = cw;
cropH = ch;
// Computes the crop's size and position given the anchor's position and display size
cutRectToImgBounds (cropX, cropY, cropW, cropH);
int fullW = ipc->getFullWidth();
int fullH = ipc->getFullHeight();
int imgX = -1, imgY = -1;
//int scaledFullW, scaledFullH;
int scaledCAX, scaledCAY;
int wwImgSpace;
int whImgSpace;
cax = rtengine::LIM(cax, 0, fullW-1);
cay = rtengine::LIM(cay, 0, fullH-1);
if (zoom >= 1000) {
wwImgSpace = int(float(ww) / float(zoom/1000) + 0.5f);
whImgSpace = int(float(wh) / float(zoom/1000) + 0.5f);
//scaledFullW = fullW * (zoom/1000);
//scaledFullH = fullH * (zoom/1000);
scaledCAX = cax * (zoom/1000);
scaledCAY = cay * (zoom/1000);
} else {
wwImgSpace = int(float(ww) * float(zoom) + 0.5f);
whImgSpace = int(float(wh) * float(zoom) + 0.5f);
//scaledFullW = fullW / zoom;
//scaledFullH = fullH / zoom;
scaledCAX = cax / zoom;
scaledCAY = cay / zoom;
}
void CropHandler::cutRectToImgBounds (int& x, int& y, int& w, int& h)
{
if (ipc) {
if (w > ipc->getFullWidth()) {
w = ipc->getFullWidth();
imgX = ww / 2 - scaledCAX;
if (imgX < 0) {
imgX = 0;
}
imgY = wh / 2 - scaledCAY;
if (imgY < 0) {
imgY = 0;
}
if (h > ipc->getFullHeight()) {
h = ipc->getFullHeight();
cropX = cax - (wwImgSpace/2);
cropY = cay - (whImgSpace/2);
cropW = wwImgSpace;
cropH = whImgSpace;
if (cropX + cropW > fullW) {
cropW = fullW - cropX;
}
if (x < 0) {
x = 0;
if (cropY + cropH > fullH) {
cropH = fullH - cropY;
}
if (y < 0) {
y = 0;
if (cropX < 0) {
cropW += cropX;
cropX = 0;
}
if (x + w >= ipc->getFullWidth()) {
x = ipc->getFullWidth() - w;
if (cropY < 0) {
cropH += cropY;
cropY = 0;
}
if (y + h >= ipc->getFullHeight()) {
y = ipc->getFullHeight() - h;
// Should be good already, but this will correct eventual rounding error
if (cropW > fullW) {
cropW = fullW;
}
if (cropH > fullH) {
cropH = fullH;
}
displayHandler->setDisplayPosition(imgX, imgY);
}

View File

@ -24,14 +24,15 @@
#include "edit.h"
#include <gtkmm.h>
class CropHandlerListener
class CropDisplayHandler
{
public:
virtual ~CropHandlerListener() {}
virtual ~CropDisplayHandler() {}
virtual void cropImageUpdated () {}
virtual void cropWindowChanged () {}
virtual void initialImageArrived () {}
virtual void setDisplayPosition (int x, int y) {}
};
class CropHandler;
@ -41,16 +42,22 @@ struct CropHandlerIdleHelper {
int pending;
};
/**
* This class handle the displayed part of the image, ask for the initial data and process it so it can display it.
* Its position on the preview is handled not set by this class but by the CropHandlerListener (i.e. CropWindow) with which it works closely.
*/
class CropHandler : public rtengine::DetailedCropListener, public rtengine::SizeListener
{
friend int createpixbufs (void* data);
protected:
int zoom;
int ww, wh; // size of the crop view on the screen
int cx, cy, cw, ch; // position and size of the requested crop
int cropX, cropY, cropW, cropH; // position and size of the crop corresponding to cropPixbuf
int zoom; // scale factor (e.g. 5 if 1:5 scale) ; if 1:1 scale and bigger, factor is multiplied by 1000 (i.e. 1000 for 1:1 scale, 2000 for 2:1, etc...)
int ww, wh; // size of the crop's canvas on the screen ; might be bigger than the displayed image, but not smaller
int imx, imy, imw, imh; // this is a copy of the cropwindow's parameters
int cax, cay; // clamped crop anchor's coordinate, i.e. point of the image that coincide to the center of the display area, expressed in image coordinates; cannot be outside the image's bounds; but if cax==cay==-1, designate the center of the image
int cx, cy, cw, ch; // position and size of the requested crop ; position expressed in image coordinates, so cx and cy might be negative and cw and ch higher than the image's 1:1 size
int cropX, cropY, cropW, cropH; // cropPixbuf's displayed area (position and size), i.e. coordinates in 1:1 scale, i.e. cx, cy, cw & ch trimmed to the image's bounds
bool enabled;
unsigned char* cropimg;
unsigned char* cropimgtrue;
@ -61,7 +68,7 @@ protected:
rtengine::StagedImageProcessor* ipc;
rtengine::DetailedCrop* crop;
CropHandlerListener* listener;
CropDisplayHandler* displayHandler;
CropHandlerIdleHelper* chi;
void compDim ();
@ -81,9 +88,9 @@ public:
CropHandler ();
~CropHandler ();
void setCropHandlerListener (CropHandlerListener* l)
void setDisplayHandler (CropDisplayHandler* l)
{
listener = l;
displayHandler = l;
}
void setEditSubscriber (EditSubscriber* newSubscriber);
@ -93,7 +100,10 @@ public:
double getFitCropZoom();
void setWSize (int w, int h);
void getWSize (int& w, int &h);
void setPosition (int x, int y, bool update = true);
void getAnchorPosition (int& x, int& y);
void setAnchorPosition (int x, int y, bool update = true);
void moveAnchor (int deltaX, int deltaY, bool update = true);
void centerAnchor (bool update = true);
void getPosition (int& x, int& y);
void getSize (int& w, int& h);
void getFullImageSize (int& w, int& h);
@ -112,8 +122,6 @@ public:
bool getWindow (int& cwx, int& cwy, int& cww, int& cwh, int& cskip);
// SizeListener interface
void sizeChanged (int w, int h, int ow, int oh);
void cutRectToImgBounds (int& x, int& y, int& w, int& h);
};
#endif

View File

@ -64,10 +64,10 @@ ZoomStep zoomSteps[] = {
#define ZOOM11INDEX 13
CropWindow::CropWindow (ImageArea* parent, rtengine::StagedImageProcessor* ipc_, bool isLowUpdatePriority_, bool isDetailWindow)
: onResizeArea(false), deleted(false), fitZoomEnabled(true), fitZoom(false), isLowUpdatePriority(isLowUpdatePriority_),
: 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(0), imgY(0), imgW(1), imgH(1), iarea(parent),
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)
{
Glib::RefPtr<Pango::Context> context = parent->get_pango_context () ;
@ -107,7 +107,7 @@ CropWindow::CropWindow (ImageArea* parent, rtengine::StagedImageProcessor* ipc_,
minWidth = bsw + iw + 2 * sideBorderWidth;
cropHandler.setCropHandlerListener (this);
cropHandler.setDisplayHandler(this);
cropHandler.newImage (ipc_, isDetailWindow);
state = SNormal;
@ -158,36 +158,27 @@ void CropWindow::getCropPosition (int& x, int& y)
void CropWindow::getCropRectangle (int& x, int& y, int& w, int& h)
{
int cropX, cropY, cropW, cropH;
cropHandler.getPosition (cropX, cropY);
cropHandler.getSize (cropW, cropH);
if (state != SCropImgMove) {
x = cropX;
y = cropY;
} else {
x = cropX + action_x;
y = cropY + action_y;
}
if (state != SCropWinResize) {
w = cropW;
h = cropH;
} else {
w = imgAreaW;
h = imgAreaH;
}
cropHandler.cutRectToImgBounds (x, y, w, h);
cropHandler.getPosition (x, y);
cropHandler.getSize (w, h);
}
void CropWindow::setCropPosition (int x, int y, bool update)
{
cropHandler.setPosition (x, y, update);
cropHandler.setAnchorPosition (x, y, update);
for (std::list<CropWindowListener*>::iterator i = listeners.begin(); i != listeners.end(); i++) {
(*i)->cropPositionChanged (this);
for (auto listener : listeners) {
listener->cropPositionChanged (this);
}
}
void CropWindow::centerCrop (bool update)
{
cropHandler.centerAnchor (update);
for (auto listener : listeners) {
listener->cropPositionChanged (this);
}
}
@ -240,6 +231,16 @@ void CropWindow::getCropSize (int& w, int& h)
h = imgAreaH;
}
void CropWindow::getCropAnchorPosition (int& x, int& y)
{
cropHandler.getAnchorPosition(x, y);
}
void CropWindow::setCropAnchorPosition (int& x, int& y)
{
cropHandler.setAnchorPosition(x, y);
}
bool CropWindow::isInside (int x, int y)
{
@ -288,11 +289,6 @@ void CropWindow::buttonPress (int button, int type, int bstate, int x, int y)
state = SNormal;
}
//below code is no longer working/needed after adding buttons for each of the backColor values
/*else if (button==1 && type==GDK_2BUTTON_PRESS && onArea (CropBorder, x, y)) {
backColor = (backColor+1) % 3;
options.bgcolor = backColor;
}*/
else if (button == 1 && type == GDK_BUTTON_PRESS && state == SNormal && onArea (CropToolBar, x, y)) {
if (!decorated || !buttonSet.pressNotify (x, y)) {
state = SCropWinMove;
@ -307,48 +303,48 @@ void CropWindow::buttonPress (int button, int type, int bstate, int x, int y)
action_y = y;
press_x = width;
press_y = height;
} else if (button == 1 && type == GDK_BUTTON_PRESS && state == SNormal && onArea (CropImage, x, y)) {
if (onArea (CropTopLeft, x, y)) {
} 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 (onArea (CropTopRight, x, 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 (onArea (CropBottomLeft, x, 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 (onArea (CropBottomRight, x, y)) {
} 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 (onArea (CropTop, x, y)) {
} else if (button == 1 && onArea (CropTop, x, y)) {
state = SResizeH1;
press_y = y;
action_y = cropHandler.cropParams.y;
} else if (onArea (CropBottom, x, y)) {
} else if (button == 1 && onArea (CropBottom, x, y)) {
state = SResizeH2;
press_y = y;
action_y = cropHandler.cropParams.h;
} else if (onArea (CropLeft, x, y)) {
} else if (button == 1 && onArea (CropLeft, x, y)) {
state = SResizeW1;
press_x = x;
action_x = cropHandler.cropParams.x;
} else if (onArea (CropRight, x, y)) {
} else if (button == 1 && onArea (CropRight, x, y)) {
state = SResizeW2;
press_x = x;
action_x = cropHandler.cropParams.w;
} else if ((bstate & GDK_SHIFT_MASK) && onArea (CropInside, x, y)) {
} else if (button == 1 && (bstate & GDK_SHIFT_MASK) && onArea (CropInside, x, y)) {
state = SCropMove;
press_x = x;
press_y = y;
@ -357,7 +353,7 @@ void CropWindow::buttonPress (int button, int type, int bstate, int x, int y)
} else if (iarea->getToolMode () == TMHand) {
EditSubscriber *editSubscriber = iarea->getCurrSubscriber();
if (editSubscriber && cropgl && cropgl->inImageArea(iarea->posImage.x, iarea->posImage.y) && (editSubscriber->getEditingType() == ET_OBJECTS)) {
if (editSubscriber && editSubscriber->getEditingType() == ET_OBJECTS) {
if (button == 1) {
needRedraw = editSubscriber->button1Pressed(bstate);
@ -385,7 +381,7 @@ void CropWindow::buttonPress (int button, int type, int bstate, int x, int y)
}
if (state != SEditDrag1 && state != SEditDrag2 && state != SEditDrag3) {
if (onArea (CropObserved, x, y)) {
if (button == 1 && onArea (CropObserved, x, y)) {
state = SObservedMove;
press_x = x;
press_y = y;
@ -398,7 +394,7 @@ void CropWindow::buttonPress (int button, int type, int bstate, int x, int y)
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
} 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;
@ -406,22 +402,24 @@ void CropWindow::buttonPress (int button, int type, int bstate, int x, int y)
action_y = 0;
}
}
} else if (onArea (CropObserved, x, y)) {
} else if (button == 1 && onArea (CropObserved, x, y)) {
state = SObservedMove;
press_x = x;
press_y = y;
} else if (iarea->getToolMode () == TMStraighten) {
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 (iarea->getToolMode () == TMSpotWB) {
} else if (button == 1 && iarea->getToolMode () == TMSpotWB) {
int spotx, spoty;
screenCoordToImage (x, y, spotx, spoty);
iarea->spotWBSelected (spotx, spoty);
} else if (iarea->getToolMode () == TMCropSelect && cropgl) {
} else if (button == 1 && iarea->getToolMode () == TMCropSelect && cropgl) {
state = SCropSelecting;
screenCoordToImage (x, y, press_x, press_y);
cropHandler.cropParams.enabled = true;
@ -430,6 +428,36 @@ void CropWindow::buttonPress (int button, int type, int bstate, int x, int 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) {
needRedraw = editSubscriber->button3Pressed(bstate);
if (editSubscriber->isDragging()) {
state = SEditDrag3;
}
}
press_x = x;
press_y = y;
action_x = 0;
action_y = 0;
}
}
if (button == 3) {
@ -474,16 +502,14 @@ void CropWindow::buttonRelease (int button, int num, int bstate, int x, int y)
state = SNormal;
for (std::list<CropWindowListener*>::iterator i = listeners.begin(); i != listeners.end(); i++) {
(*i)->cropWindowSizeChanged (this);
for (auto listener : listeners) {
listener->cropWindowSizeChanged (this);
}
needRedraw = true;
} else if (state == SCropImgMove) {
int cropX, cropY;
cropHandler.getPosition (cropX, cropY);
cropHandler.setPosition (cropX + action_x, cropY + action_y);
cropHandler.getPosition (cropX, cropY);
cropHandler.update ();
state = SNormal;
for (std::list<CropWindowListener*>::iterator i = listeners.begin(); i != listeners.end(); i++) {
@ -519,9 +545,9 @@ void CropWindow::buttonRelease (int button, int num, int bstate, int x, int y)
iarea->posScreen.set(x, y);
Coord cropPos;
if (state == SEditDrag1 && editSubscriber->getEditingType() == ET_PIPETTE) {
screenCoordToCropBuffer (x, y, cropPos.x, cropPos.y);
if (state == SEditDrag1 && editSubscriber->getEditingType() == ET_PIPETTE) {
iarea->object = onArea (CropImage, x, y) && !onArea (CropObserved, x, y) ? 1 : 0;
//iarea->object = cropgl && cropgl->inImageArea(iarea->posImage.x, iarea->posImage.y) ? 1 : 0;
@ -532,8 +558,10 @@ void CropWindow::buttonRelease (int button, int num, int bstate, int x, int y)
iarea->pipetteVal[0] = iarea->pipetteVal[1] = iarea->pipetteVal[2] = -1.f;
}
} else if (editSubscriber->getEditingType() == ET_OBJECTS) {
screenCoordToCropCanvas (x, y, cropPos.x, cropPos.y);
if (onArea (CropImage, x, y)) {
iarea->object = crop->getObjectID(cropPos);
iarea->object = ObjectMOBuffer::getObjectID(cropPos);
} else {
iarea->object = -1;
}
@ -588,8 +616,8 @@ void CropWindow::pointerMoved (int bstate, int x, int y)
} else if (state == SCropWinResize) {
setSize (press_x + x - action_x, press_y + y - action_y, true);
for (std::list<CropWindowListener*>::iterator i = listeners.begin(); i != listeners.end(); i++) {
(*i)->cropWindowSizeChanged (this);
for (auto listener : listeners) {
listener->cropWindowSizeChanged (this);
}
iarea->redraw ();
@ -602,11 +630,19 @@ void CropWindow::pointerMoved (int bstate, int x, int y)
factor = 1.0;
}
action_x = (press_x - x) / zoomSteps[cropZoom].zoom * factor;
action_y = (press_y - y) / zoomSteps[cropZoom].zoom * factor;
int newAction_x = (press_x - x) / zoomSteps[cropZoom].zoom * factor;
int newAction_y = (press_y - y) / zoomSteps[cropZoom].zoom * factor;
for (std::list<CropWindowListener*>::iterator i = listeners.begin(); i != listeners.end(); i++) {
(*i)->cropPositionChanged (this);
int deltaX = newAction_x - action_x;
int deltaY = newAction_y - action_y;
action_x = newAction_x;
action_y = newAction_y;
cropHandler.moveAnchor(deltaX, deltaY, false);
for (auto listener : listeners) {
listener->cropPositionChanged (this);
}
iarea->redraw ();
@ -695,7 +731,11 @@ void CropWindow::pointerMoved (int bstate, int x, int y)
iarea->redraw ();
} else if (state == SObservedMove) {
observedCropWin->remoteMove ((x - press_x) / zoomSteps[cropZoom].zoom, (y - press_y) / zoomSteps[cropZoom].zoom);
int new_action_x = x - press_x;
int new_action_y = y - press_y;
observedCropWin->remoteMove ((new_action_x - action_x) / zoomSteps[cropZoom].zoom, (new_action_y - action_y) / zoomSteps[cropZoom].zoom);
action_x = new_action_x;
action_y = new_action_y;
iarea->redraw ();
} else if (editSubscriber) {
rtengine::Crop* crop = static_cast<rtengine::Crop*>(cropHandler.getCrop());
@ -710,9 +750,10 @@ void CropWindow::pointerMoved (int bstate, int x, int y)
iarea->posScreen.set(x, y);
Coord cropPos;
screenCoordToCropBuffer(x, y, cropPos.x, cropPos.y);
if (editSubscriber->getEditingType() == ET_PIPETTE) {
screenCoordToCropBuffer (x, y, cropPos.x, cropPos.y);
iarea->object = onArea (CropImage, x, y) && !onArea (CropObserved, x, y) ? 1 : 0;
//iarea->object = cropgl && cropgl->inImageArea(iarea->posImage.x, iarea->posImage.y) ? 1 : 0;
@ -723,11 +764,8 @@ void CropWindow::pointerMoved (int bstate, int x, int y)
iarea->pipetteVal[0] = iarea->pipetteVal[1] = iarea->pipetteVal[2] = -1.f;
}
} else if (editSubscriber->getEditingType() == ET_OBJECTS) {
if (onArea (CropImage, x, y)) {
iarea->object = crop->getObjectID(cropPos);
} else {
iarea->object = -1;
}
screenCoordToCropCanvas (x, y, cropPos.x, cropPos.y);
iarea->object = ObjectMOBuffer::getObjectID(cropPos);
}
if (editSubscriber->mouseOver(bstate)) {
@ -850,7 +888,7 @@ bool CropWindow::onArea (CursorArea a, int x, int y)
return x > xpos && y > ypos && x < xpos + width - 1 && y < ypos + imgAreaY;
case CropImage:
return x >= xpos + imgX && y >= ypos + imgY && x < xpos + imgX + imgW && y < ypos + imgY + imgH;
return x >= xpos + imgX + imgAreaX && y >= ypos + imgY + imgAreaY && x < xpos + imgX + imgAreaX + imgW && y < ypos + imgY + imgAreaY + imgH;
case CropBorder:
return
@ -985,10 +1023,10 @@ void CropWindow::updateCursor (int x, int y)
} else if (onArea (CropImage, x, y)) {
int objectID = -1;
if (editSubscriber) {
if (editSubscriber && editSubscriber->getEditingType() == ET_OBJECTS) {
Coord cropPos;
screenCoordToCropBuffer(iarea->posScreen.x, iarea->posScreen.y, cropPos.x, cropPos.y);
objectID = static_cast<rtengine::Crop*>(cropHandler.getCrop())->getObjectID(cropPos);
screenCoordToCropCanvas (iarea->posScreen.x, iarea->posScreen.y, cropPos.x, cropPos.y);
objectID = ObjectMOBuffer::getObjectID(cropPos);
}
if (objectID > -1) {
@ -1006,9 +1044,21 @@ void CropWindow::updateCursor (int x, int y)
} else if (tm == TMStraighten) {
cursorManager.setCursor (iarea->get_window(), CSStraighten);
}
} else {
int objectID = -1;
if (editSubscriber && editSubscriber->getEditingType() == ET_OBJECTS) {
Coord cropPos;
screenCoordToCropCanvas (iarea->posScreen.x, iarea->posScreen.y, cropPos.x, cropPos.y);
objectID = ObjectMOBuffer::getObjectID(cropPos);
}
if (objectID > -1) {
cursorManager.setCursor (iarea->get_window(), editSubscriber->getCursor(objectID));
} else {
cursorManager.setCursor (iarea->get_window(), CSArrow);
}
}
} else if (state == SCropSelecting) {
cursorManager.setCursor (iarea->get_window(), CSCropSelect);
} else if (state == SRotateSelecting) {
@ -1042,7 +1092,7 @@ void CropWindow::expose (Cairo::RefPtr<Cairo::Context> cr)
drawDecoration (cr);
}
int x = xpos, y = ypos, h = height, w = width;
int x = xpos, y = ypos;
// draw the background
backColor = iarea->previewModePanel->GetbackColor();
@ -1069,15 +1119,10 @@ void CropWindow::expose (Cairo::RefPtr<Cairo::Context> cr)
int cropX, cropY;
cropHandler.getPosition (cropX, cropY);
if (state == SCropImgMove) {
cropX += action_x;
cropY += action_y;
}
Glib::RefPtr<Gdk::Pixbuf> rough = iarea->getPreviewHandler()->getRoughImage (cropX, cropY, imgAreaW, imgAreaH, zoomSteps[cropZoom].zoom);
if (rough) {
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);
iarea->get_window()->draw_pixbuf (iarea->get_style()->get_base_gc(Gtk::STATE_NORMAL), rough, 0, 0, x + imgAreaX + imgX, y + imgAreaY + imgY, rtengine::min (rough->get_width (), imgAreaW-imgX), rtengine::min (rough->get_height (), imgAreaH-imgY), Gdk::RGB_DITHER_NORMAL, 0, 0);
// if (cropHandler.cropParams.enabled)
// drawCrop (cr, x+imgX, y+imgY, imgW, imgH, cropX, cropY, zoomSteps[cropZoom].zoom, cropHandler.cropParams);
}
@ -1089,8 +1134,6 @@ void CropWindow::expose (Cairo::RefPtr<Cairo::Context> cr)
if (cropHandler.cropPixbuf) {
imgW = cropHandler.cropPixbuf->get_width ();
imgH = cropHandler.cropPixbuf->get_height ();
imgX = imgAreaX + (imgAreaW - imgW) / 2;
imgY = imgAreaY + (imgAreaH - imgH) / 2;
exposeVersion++;
bool showcs = iarea->indClippedPanel->showClippedShadows();
@ -1240,8 +1283,8 @@ void CropWindow::expose (Cairo::RefPtr<Cairo::Context> cr)
}
}
float sum_L2 = tmpLsum[i * bWidth + j];
float sumsq_L2 = tmpLsumSq[i * bWidth + j];
//float sum_L2 = tmpLsum[i * bWidth + j];
//float sumsq_L2 = tmpLsumSq[i * bWidth + j];
//*************
// averages
// Optimized formulas to avoid divisions
@ -1484,16 +1527,15 @@ void CropWindow::expose (Cairo::RefPtr<Cairo::Context> cr)
}
}
//printf("zoomSteps[cropZoom].zoom=%d\n",zoomSteps[cropZoom].zoom);
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);
iarea->get_window()->draw_pixbuf (iarea->get_style()->get_base_gc(Gtk::STATE_NORMAL), tmp, 0, 0, x + imgAreaX + imgX, y + imgAreaY + imgY, rtengine::min (tmp->get_width (), imgAreaW-imgX), rtengine::min (tmp->get_height (), imgAreaH-imgY), Gdk::RGB_DITHER_NORMAL, 0, 0);
} else {
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);
iarea->get_window()->draw_pixbuf (iarea->get_style()->get_base_gc(Gtk::STATE_NORMAL), cropHandler.cropPixbuf, 0, 0, x + imgAreaX + imgX, y + imgAreaY + imgY, rtengine::min (cropHandler.cropPixbuf->get_width (), imgAreaW-imgX), rtengine::min (cropHandler.cropPixbuf->get_height (), imgAreaH-imgY), Gdk::RGB_DITHER_NORMAL, 0, 0);
}
if (cropHandler.cropParams.enabled) {
int cropX, cropY;
cropHandler.getPosition (cropX, cropY);
drawCrop (cr, x + imgX, y + imgY, imgW, imgH, cropX, cropY, zoomSteps[cropZoom].zoom, cropHandler.cropParams, (this == iarea->mainCropWindow), true, zoomSteps[cropZoom].zoom <= cropHandler.getFitZoom() );
drawCrop (cr, x + imgAreaX + imgX, y + imgAreaY + imgY, imgW, imgH, cropX, cropY, zoomSteps[cropZoom].zoom, cropHandler.cropParams, (this == iarea->mainCropWindow), true, zoomSteps[cropZoom].zoom <= cropHandler.getFitZoom() );
}
if (observedCropWin) {
@ -1501,13 +1543,12 @@ void CropWindow::expose (Cairo::RefPtr<Cairo::Context> cr)
}
EditSubscriber *editSubscriber = iarea->getCurrSubscriber();
rtengine::Crop* crop = static_cast<rtengine::Crop*>(cropHandler.getCrop());
if (editSubscriber && crop->bufferCreated()) {
if (editSubscriber && bufferCreated()) {
if (this != iarea->mainCropWindow) {
cr->set_line_width (0.);
cr->rectangle (x + imgX, y + imgY, imgW, imgH);
cr->rectangle (x + imgAreaX, y + imgAreaY, imgAreaW, imgAreaH);
cr->clip();
}
@ -1518,17 +1559,13 @@ void CropWindow::expose (Cairo::RefPtr<Cairo::Context> cr)
cr->set_line_join(Cairo::LINE_JOIN_ROUND);
// drawing outer lines
for (std::vector<Geometry*>::const_iterator i = visibleGeom.begin(); i != visibleGeom.end(); ++i) {
(*i)->drawOuterGeometry(cr, crop, *this);
for (auto geom : visibleGeom) {
geom->drawOuterGeometry(cr, this, *this);
}
// drawing inner lines
for (std::vector<Geometry*>::const_iterator i = visibleGeom.begin(); i != visibleGeom.end(); ++i) {
(*i)->drawInnerGeometry(cr, crop, *this);
}
if (this != iarea->mainCropWindow) {
cr->reset_clip();
for (auto geom : visibleGeom) {
geom->drawInnerGeometry(cr, this, *this);
}
// drawing to the "mouse over" channel
@ -1536,8 +1573,8 @@ void CropWindow::expose (Cairo::RefPtr<Cairo::Context> cr)
const std::vector<Geometry*> mouseOverGeom = editSubscriber->getMouseOverGeometry();
if (mouseOverGeom.size()) {
//printf("ObjectMap (%d x %d)\n", crop->getObjectMap()->get_width(), crop->getObjectMap()->get_height());
Cairo::RefPtr<Cairo::Context> crMO = Cairo::Context::create(crop->getObjectMap());
//printf("ObjectMap (%d x %d)\n", ObjectMOBuffer::getObjectMap()->get_width(), ObjectMOBuffer::getObjectMap()->get_height());
Cairo::RefPtr<Cairo::Context> crMO = Cairo::Context::create(ObjectMOBuffer::getObjectMap());
crMO->set_antialias(Cairo::ANTIALIAS_NONE);
crMO->set_line_cap(Cairo::LINE_CAP_SQUARE);
crMO->set_line_join(Cairo::LINE_JOIN_ROUND);
@ -1545,14 +1582,14 @@ void CropWindow::expose (Cairo::RefPtr<Cairo::Context> cr)
// clear the bitmap
crMO->set_source_rgba(0., 0., 0., 0.);
crMO->rectangle(0., 0., crop->getObjectMap()->get_width(), crop->getObjectMap()->get_height());
crMO->rectangle(0., 0., ObjectMOBuffer::getObjectMap()->get_width(), ObjectMOBuffer::getObjectMap()->get_height());
crMO->set_line_width(0.);
crMO->fill();
Cairo::RefPtr<Cairo::Context> crMO2;
if (crop->getObjectMode() > OM_255) {
crMO2 = Cairo::Context::create(crop->getObjectMap2());
if (ObjectMOBuffer::getObjectMode() > OM_255) {
crMO2 = Cairo::Context::create(ObjectMOBuffer::getObjectMap2());
crMO2->set_antialias(Cairo::ANTIALIAS_NONE);
crMO2->set_line_cap(Cairo::LINE_CAP_SQUARE);
crMO2->set_line_join(Cairo::LINE_JOIN_ROUND);
@ -1560,28 +1597,29 @@ void CropWindow::expose (Cairo::RefPtr<Cairo::Context> cr)
// clear the bitmap
crMO2->set_source_rgba(0., 0., 0., 0.);
crMO2->rectangle(0., 0., crop->getObjectMap2()->get_width(), crop->getObjectMap2()->get_height());
crMO2->rectangle(0., 0., ObjectMOBuffer::getObjectMap2()->get_width(), ObjectMOBuffer::getObjectMap2()->get_height());
crMO2->set_line_width(0.);
crMO2->fill();
}
std::vector<Geometry*>::const_iterator i;
int a;
int a=0;
for (a = 0, i = mouseOverGeom.begin(); i != mouseOverGeom.end(); ++i, ++a) {
(*i)->drawToMOChannel(crMO, crMO2, a, crop, *this);
for (auto moGeom : mouseOverGeom) {
moGeom->drawToMOChannel(crMO, crMO2, a, this, *this);
++a;
}
// Debug code: save the "mouse over" image to a new file at each occurrence
#if 0
{
static unsigned int count = 0;
int w = crop->getObjectMap()->get_width();
int h = crop->getObjectMap()->get_height();
int w = ObjectMOBuffer::getObjectMap()->get_width();
int h = ObjectMOBuffer::getObjectMap()->get_height();
Glib::RefPtr<Gdk::Pixbuf> img = Gdk::Pixbuf::create(Gdk::COLORSPACE_RGB, false, 8, w, h);
guint8 *dst = img->get_pixels();
unsigned char *src1 = crop->getObjectMap()->get_data();
unsigned char *src2 = crop->getObjectMode() > OM_255 ? crop->getObjectMap()->get_data() : NULL;
unsigned char *src1 = ObjectMOBuffer::getObjectMap()->get_data();
unsigned char *src2 = ObjectMOBuffer::getObjectMode() > OM_255 ? ObjectMOBuffer::getObjectMap()->get_data() : NULL;
memcpy(dst, src1, w * h);
for (int n = 0, n3 = 0; n < w * h;) {
@ -1602,6 +1640,10 @@ void CropWindow::expose (Cairo::RefPtr<Cairo::Context> cr)
#endif
}
}
if (this != iarea->mainCropWindow) {
cr->reset_clip();
}
}
} else {
// cropHandler.cropPixbuf is null
@ -1610,14 +1652,14 @@ void CropWindow::expose (Cairo::RefPtr<Cairo::Context> cr)
Glib::RefPtr<Gdk::Pixbuf> rough = iarea->getPreviewHandler()->getRoughImage (cropX, cropY, imgAreaW, imgAreaH, zoomSteps[cropZoom].zoom);
if (rough) {
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);
iarea->get_window()->draw_pixbuf (iarea->get_style()->get_base_gc(Gtk::STATE_NORMAL), rough, 0, 0, x + imgAreaX + imgX, y + imgAreaY + imgY, rtengine::min (rough->get_width (), imgAreaW-imgX), rtengine::min (rough->get_height (), imgAreaH-imgY), Gdk::RGB_DITHER_NORMAL, 0, 0);
if (cropHandler.cropParams.enabled) {
drawCrop (cr, x + imgAreaX + (imgAreaW - rough->get_width()) / 2, y + imgAreaY + (imgAreaH - rough->get_height()) / 2, rough->get_width(), rough->get_height(), cropX, cropY, zoomSteps[cropZoom].zoom, cropHandler.cropParams, (this == iarea->mainCropWindow), true, zoomSteps[cropZoom].zoom <= cropHandler.getFitZoom());
drawCrop (cr, x + imgAreaX + imgX, y + imgAreaY + imgY, rough->get_width(), rough->get_height(), cropX, cropY, zoomSteps[cropZoom].zoom, cropHandler.cropParams, (this == iarea->mainCropWindow), true, zoomSteps[cropZoom].zoom <= cropHandler.getFitZoom());
}
if (observedCropWin) {
drawObservedFrame (cr, rough->get_width(), rough->get_height());
drawObservedFrame (cr);
}
}
}
@ -1641,24 +1683,10 @@ void CropWindow::expose (Cairo::RefPtr<Cairo::Context> cr)
// printf ("etime --> %d, %d\n", t2.etime (t1), t4.etime (t3));
}
// calculate the center of the zoomed in/out preview given a cursor position
void CropWindow::findCenter (int deltaZoom, int& x, int& y)
{
int cursorX, cursorY;
screenCoordToImage(x, y, cursorX, cursorY);
int cropX, cropY, cropW, cropH, skip;
cropHandler.getWindow (cropX, cropY, cropW, cropH, skip);
int currCenterX = cropX + cropW / 2;
int currCenterY = cropY + cropH / 2;
int deltaX = currCenterX - cursorX;
int deltaY = currCenterY - cursorY;
double factor = zoomSteps[cropZoom].zoom / zoomSteps[cropZoom + deltaZoom].zoom;
x = cursorX + (int)((double)(deltaX) * factor);
y = cursorY + (int)((double)(deltaY) * factor);
void CropWindow::setEditSubscriber (EditSubscriber* newSubscriber) {
// Delete, create, update all buffers based upon newSubscriber's type
ObjectMOBuffer::resize(imgAreaW, imgAreaH, newSubscriber);
cropHandler.setEditSubscriber(newSubscriber);
}
// zoom* is called from the zoomPanel or the scroll wheel in the preview area
@ -1806,7 +1834,7 @@ double CropWindow::getZoomFitVal ()
}
void CropWindow::zoomFit (bool skipZoomIfUnchanged)
void CropWindow::zoomFit ()
{
double z = cropHandler.getFitZoom ();
@ -1822,7 +1850,7 @@ void CropWindow::zoomFit (bool skipZoomIfUnchanged)
}
zoomVersion = exposeVersion;
changeZoom (cz, true, -1, -1, skipZoomIfUnchanged);
changeZoom (cz, true, -1, -1);
fitZoom = true;
}
@ -1845,7 +1873,7 @@ void CropWindow::zoomFitCrop ()
int centerX, centerY;
centerX = cropHandler.cropParams.x + cropHandler.cropParams.w / 2;
centerY = cropHandler.cropParams.y + cropHandler.cropParams.h / 2;
changeZoom (cz, true, centerX, centerY, false);
changeZoom (cz, true, centerX, centerY);
fitZoom = false;
}
}
@ -1874,7 +1902,7 @@ void CropWindow::redrawNeeded (LWButton* button)
iarea->redraw ();
}
void CropWindow::changeZoom (int zoom, bool notify, int centerx, int centery, bool skipZoomIfUnchanged)
void CropWindow::changeZoom (int zoom, bool notify, int centerx, int centery)
{
if (zoom < 0) {
@ -1883,19 +1911,14 @@ void CropWindow::changeZoom (int zoom, bool notify, int centerx, int centery, b
zoom = MAXZOOMSTEPS;
}
if (cropZoom == zoom && skipZoomIfUnchanged) {
// We are already at the start/end of the zoom range, so we do nothing
return;
}
cropZoom = zoom;
cropLabel = zoomSteps[cropZoom].label;
cropHandler.setZoom (zoomSteps[cropZoom].czoom, centerx, centery);
if (notify)
for (std::list<CropWindowListener*>::iterator i = listeners.begin(); i != listeners.end(); i++) {
(*i)->cropZoomChanged (this);
for (auto listener : listeners) {
listener->cropZoomChanged (this);
}
iarea->redraw ();
@ -1905,8 +1928,8 @@ void CropWindow::screenCoordToCropBuffer (int phyx, int phyy, int& cropx, int& c
{
rtengine::Crop* crop = static_cast<rtengine::Crop*>(cropHandler.getCrop());
cropx = phyx - xpos - imgX;
cropy = phyy - ypos - imgY;
cropx = phyx - xpos - imgX - imgAreaX;
cropy = phyy - ypos - imgY - imgAreaY;
if (zoomSteps[cropZoom].zoom > 1.) {
cropx = int(double(cropx) / zoomSteps[cropZoom].zoom);
@ -1926,11 +1949,11 @@ void CropWindow::screenCoordToImage (int phyx, int phyy, int& imgx, int& imgy)
imgy = cropY + (phyy - ypos - imgY) / zoomSteps[cropZoom].zoom;
}
void CropWindow::screenCoordToPreview (int phyx, int phyy, int& prevx, int& prevy)
void CropWindow::screenCoordToCropCanvas (int phyx, int phyy, int& prevx, int& prevy)
{
prevx = phyx - xpos - imgX;
prevy = phyy - ypos - imgY;
prevx = phyx - xpos - imgAreaX;
prevy = phyy - ypos - imgAreaY;
}
void CropWindow::imageCoordToScreen (int imgx, int imgy, int& phyx, int& phyy)
@ -1938,9 +1961,17 @@ void CropWindow::imageCoordToScreen (int imgx, int imgy, int& phyx, int& phyy)
int cropX, cropY;
cropHandler.getPosition (cropX, cropY);
phyx = (imgx - cropX) * zoomSteps[cropZoom].zoom + xpos + imgX;
phyy = (imgy - cropY) * zoomSteps[cropZoom].zoom + ypos + imgY;
// printf("imgx:%d / imgy:%d / cropX:%d / cropY:%d / xpos:%d / ypos:%d / imgX:%d / imgY:%d / leftBorder: %d / upperBorder:%d / phyx:%d / phyy:%d\n", imgx, imgy, cropX, cropY, xpos, ypos, imgX, imgY, crop->getLeftBorder(), crop->getUpperBorder(), phyx, phyy);
phyx = (imgx - cropX) * zoomSteps[cropZoom].zoom + xpos + imgX + imgAreaX;
phyy = (imgy - cropY) * zoomSteps[cropZoom].zoom + ypos + imgY + imgAreaY;
}
void CropWindow::imageCoordToCropCanvas (int imgx, int imgy, int& phyx, int& phyy)
{
int cropX, cropY;
cropHandler.getPosition (cropX, cropY);
phyx = (imgx - cropX) * zoomSteps[cropZoom].zoom + imgX;
phyy = (imgy - cropY) * zoomSteps[cropZoom].zoom + imgY;
}
void CropWindow::imageCoordToCropBuffer (int imgx, int imgy, int& phyx, int& phyy)
@ -1950,7 +1981,6 @@ void CropWindow::imageCoordToCropBuffer (int imgx, int imgy, int& phyx, int& phy
cropHandler.getPosition (cropX, cropY);
phyx = (imgx - cropX) * zoomSteps[cropZoom].zoom + /*xpos + imgX +*/ crop->getLeftBorder();
phyy = (imgy - cropY) * zoomSteps[cropZoom].zoom + /*ypos + imgY +*/ crop->getUpperBorder();
//printf("imgx:%d / imgy:%d / cropX:%d / cropY:%d / xpos:%d / ypos:%d / imgX:%d / imgY:%d / leftBorder: %d / upperBorder:%d / phyx:%d / phyy:%d\n", imgx, imgy, cropX, cropY, xpos, ypos, imgX, imgY, crop->getLeftBorder(), crop->getUpperBorder(), phyx, phyy);
}
int CropWindow::scaleValueToImage (int value)
@ -1968,17 +1998,17 @@ double CropWindow::scaleValueToImage (double value)
return value / zoomSteps[cropZoom].zoom;
}
int CropWindow::scaleValueToScreen (int value)
int CropWindow::scaleValueToCanvas (int value)
{
return int(double(value) * zoomSteps[cropZoom].zoom);
}
float CropWindow::scaleValueToScreen (float value)
float CropWindow::scaleValueToCanvas (float value)
{
return float(double(value) * zoomSteps[cropZoom].zoom);
}
double CropWindow::scaleValueToScreen (double value)
double CropWindow::scaleValueToCanvas (double value)
{
return value * zoomSteps[cropZoom].zoom;
}
@ -2113,7 +2143,7 @@ void CropWindow::drawScaledSpotRectangle (Cairo::RefPtr<Cairo::Context> cr, int
int x2 = action_x / zoomSteps[cropZoom].zoom + rectSize;
cr->set_line_width (1.0);
cr->rectangle (xpos + imgX - 0.5, ypos + imgY - 0.5, imgW, imgH);
cr->rectangle (xpos + imgX + imgAreaX - 0.5, ypos + imgY + imgAreaY - 0.5, imgAreaW, imgAreaH);
cr->clip ();
cr->set_source_rgb (1.0, 1.0, 1.0);
@ -2135,7 +2165,7 @@ void CropWindow::drawUnscaledSpotRectangle (Cairo::RefPtr<Cairo::Context> cr, in
int x2 = action_x + rectSize;
cr->set_line_width (1.0);
cr->rectangle (xpos + imgX - 0.5, ypos + imgY - 0.5, imgW, imgH);
cr->rectangle (xpos + imgX + imgAreaX - 0.5, ypos + imgY + imgAreaY - 0.5, imgAreaW, imgAreaH);
cr->clip ();
cr->set_source_rgb (1.0, 1.0, 1.0);
@ -2151,22 +2181,22 @@ void CropWindow::drawUnscaledSpotRectangle (Cairo::RefPtr<Cairo::Context> cr, in
void CropWindow::getObservedFrameArea (int& x, int& y, int& w, int& h, int rw, int rh)
{
int cropX, cropY, cropW, cropH;
observedCropWin->getCropRectangle (cropX, cropY, cropW, cropH);
int myCropX, myCropY, myCropW, myCropH;
getCropRectangle (myCropX, myCropY, myCropW, myCropH);
int observedCropX, observedCropY, observedCropW, observedCropH;
observedCropWin->getCropRectangle (observedCropX, observedCropY, observedCropW, observedCropH);
int mainCropX, mainCropY, mainCropW, mainCropH;
getCropRectangle (mainCropX, mainCropY, mainCropW, mainCropH);
// translate it to screen coordinates
if (rw) {
x = xpos + imgAreaX + (imgAreaW - rw) / 2 + (cropX - myCropX) * zoomSteps[cropZoom].zoom;
y = ypos + imgAreaY + (imgAreaH - rh) / 2 + (cropY - myCropY) * zoomSteps[cropZoom].zoom;
if (rw) { // rw and rh are the rough image's dimension
x = xpos + imgAreaX + (imgAreaW - rw) / 2 + (observedCropX - mainCropX) * zoomSteps[cropZoom].zoom;
y = ypos + imgAreaY + (imgAreaH - rh) / 2 + (observedCropY - mainCropY) * zoomSteps[cropZoom].zoom;
} else {
x = xpos + imgX + (cropX - myCropX) * zoomSteps[cropZoom].zoom;
y = ypos + imgY + (cropY - myCropY) * zoomSteps[cropZoom].zoom;
x = xpos + imgX + (observedCropX - mainCropX) * zoomSteps[cropZoom].zoom;
y = ypos + imgY + (observedCropY - mainCropY) * zoomSteps[cropZoom].zoom;
}
w = cropW * zoomSteps[cropZoom].zoom;
h = cropH * zoomSteps[cropZoom].zoom;
w = observedCropW * zoomSteps[cropZoom].zoom;
h = observedCropH * zoomSteps[cropZoom].zoom;
}
void CropWindow::drawObservedFrame (Cairo::RefPtr<Cairo::Context> cr, int rw, int rh)
@ -2206,35 +2236,35 @@ void CropWindow::cropWindowChanged ()
void CropWindow::initialImageArrived ()
{
for (std::list<CropWindowListener*>::iterator i = listeners.begin(); i != listeners.end(); i++) {
(*i)->initialImageArrived (this);
for (auto listener : listeners) {
listener->initialImageArrived (this);
}
}
void CropWindow::setDisplayPosition (int x, int y) {
imgX = x;
imgY = y;
}
void CropWindow::remoteMove (int deltaX, int deltaY)
{
state = SCropImgMove;
action_x = deltaX;
action_y = deltaY;
cropHandler.moveAnchor(deltaX, deltaY, false);
for (std::list<CropWindowListener*>::iterator i = listeners.begin(); i != listeners.end(); i++) {
(*i)->cropPositionChanged (this);
for (auto listener : listeners) {
listener->cropPositionChanged (this);
}
}
void CropWindow::remoteMoveReady ()
{
int cropX, cropY;
cropHandler.getPosition (cropX, cropY);
cropHandler.setPosition (cropX + action_x, cropY + action_y);
cropHandler.getPosition (cropX, cropY);
cropHandler.update ();
state = SNormal;
for (std::list<CropWindowListener*>::iterator i = listeners.begin(); i != listeners.end(); i++) {
(*i)->cropPositionChanged (this);
for (auto listener : listeners) {
listener->cropPositionChanged (this);
}
}

View File

@ -28,6 +28,7 @@
#include <list>
#include "cropguilistener.h"
#include "pointermotionlistener.h"
#include "edit.h"
class CropWindow;
class CropWindowListener
@ -42,12 +43,13 @@ public:
};
class ImageArea;
class CropWindow : public LWButtonListener, public CropHandlerListener, public EditCoordSystem
class CropWindow : public LWButtonListener, public CropDisplayHandler, public EditCoordSystem, public ObjectMOBuffer
{
// state management
ImgEditState state; // current state of user (see enum State)
int action_x, action_y, press_x, press_y;
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
double rot_deg;
bool onResizeArea;
bool deleted;
@ -85,7 +87,7 @@ class CropWindow : public LWButtonListener, public CropHandlerListener, public E
PointerMotionListener* pmhlistener;
std::list<CropWindowListener*> listeners;
CropWindow* observedCropWin;
CropWindow* observedCropWin; // Pointer to the currently active detail CropWindow
rtengine::StagedImageProcessor* ipc;
bool onArea (CursorArea a, int x, int y);
@ -95,7 +97,9 @@ class CropWindow : public LWButtonListener, public CropHandlerListener, public E
void drawScaledSpotRectangle (Cairo::RefPtr<Cairo::Context> cr, int rectSize);
void drawUnscaledSpotRectangle (Cairo::RefPtr<Cairo::Context> cr, int rectSize);
void drawObservedFrame (Cairo::RefPtr<Cairo::Context> cr, int rw = 0, int rh = 0);
void changeZoom (int zoom, bool notify = true, int centerx = -1, int centery = -1, bool skipZoomIfUnchanged = true);
void changeZoom (int zoom, bool notify = true, int centerx = -1, int centery = -1);
// Used by the mainCropWindow only
void getObservedFrameArea (int& x, int& y, int& w, int& h, int rw = 0, int rh = 0);
public:
@ -117,15 +121,16 @@ public:
void screenCoordToCropBuffer (int phyx, int phyy, int& cropx, int& cropy);
void screenCoordToImage (int phyx, int phyy, int& imgx, int& imgy);
void screenCoordToPreview (int phyx, int phyy, int& prevx, int& prevy);
void screenCoordToCropCanvas (int phyx, int phyy, int& prevx, int& prevy);
void imageCoordToCropCanvas (int imgx, int imgy, int& phyx, int& phyy);
void imageCoordToScreen (int imgx, int imgy, int& phyx, int& phyy);
void imageCoordToCropBuffer (int imgx, int imgy, int& phyx, int& phyy);
int scaleValueToImage (int value);
float scaleValueToImage (float value);
double scaleValueToImage (double value);
int scaleValueToScreen (int value);
float scaleValueToScreen (float value);
double scaleValueToScreen (double value);
int scaleValueToCanvas (int value);
float scaleValueToCanvas (float value);
double scaleValueToCanvas (double value);
double getZoomFitVal ();
void setPosition (int x, int y);
void getPosition (int& x, int& y);
@ -140,14 +145,13 @@ public:
void zoomIn (bool toCursor = false, int cursorX = -1, int cursorY = -1);
void zoomOut (bool toCursor = false, int cursorX = -1, int cursorY = -1);
void zoom11 ();
void zoomFit (bool skipZoomIfUnchanged = true);
void zoomFit ();
void zoomFitCrop ();
double getZoom ();
bool isMinZoom ();
bool isMaxZoom ();
void setZoom (double zoom);
void findCenter (int deltaZoom, int& x, int& y);
bool isInside (int x, int y);
@ -157,6 +161,8 @@ public:
void expose (Cairo::RefPtr<Cairo::Context> cr);
void setEditSubscriber (EditSubscriber* newSubscriber);
// interface lwbuttonlistener
void buttonPressed (LWButton* button, int actionCode, void* actionData);
void redrawNeeded (LWButton* button);
@ -165,7 +171,10 @@ public:
void getCropRectangle (int& x, int& y, int& w, int& h);
void getCropPosition (int& x, int& y);
void setCropPosition (int x, int y, bool update = true);
void centerCrop (bool update = true);
void getCropSize (int& w, int& h);
void getCropAnchorPosition (int& w, int& h);
void setCropAnchorPosition (int& w, int& h);
// listeners
void setCropGUIListener (CropGUIListener* cgl)
@ -192,6 +201,7 @@ public:
void cropImageUpdated ();
void cropWindowChanged ();
void initialImageArrived ();
void setDisplayPosition (int x, int y);
void remoteMove (int deltaX, int deltaY);
void remoteMoveReady ();

View File

@ -18,9 +18,119 @@
*/
#include "edit.h"
#include "../rtengine/editbuffer.h"
#include "rtimage.h"
ObjectMOBuffer::ObjectMOBuffer(EditDataProvider *dataProvider) : objectMap(NULL), objectMap2(NULL), objectMode(OM_255), dataProvider(dataProvider) {}
ObjectMOBuffer::~ObjectMOBuffer()
{
flush();
}
/* Upgrade or downgrade the objectModeType; we're assuming that objectMap has been allocated */
void ObjectMOBuffer::setObjectMode(ObjectMode newType)
{
switch (newType) {
case (OM_255):
if (objectMap2) {
objectMap2->unreference();
}
objectMode = OM_255;
break;
case (OM_65535):
if (!objectMap2) {
objectMap2 = Cairo::ImageSurface::create(Cairo::FORMAT_A8, objectMap->get_width(), objectMap->get_height());
}
objectMode = OM_65535;
break;
}
}
void ObjectMOBuffer::flush()
{
if (objectMap ) {
objectMap.clear();
}
if (objectMap2) {
objectMap2.clear();
}
}
EditSubscriber *ObjectMOBuffer::getEditSubscriber () {
if (dataProvider) {
return dataProvider->getCurrSubscriber();
} else {
return NULL;
}
}
// Resize buffers if they already exist
void ObjectMOBuffer::resize(int newWidth, int newHeight, EditSubscriber* newSubscriber)
{
if (newSubscriber) {
if (newSubscriber->getEditingType() == ET_OBJECTS) {
if (objectMap && (objectMap->get_width() != newWidth || objectMap->get_height() != newHeight)) {
objectMap.clear();
}
if (!objectMap && newWidth>0 && newHeight>0) {
objectMap = Cairo::ImageSurface::create(Cairo::FORMAT_A8, newWidth, newHeight);
}
if (objectMode == OM_65535) {
if (objectMap2) {
if (objectMap2->get_width() != newWidth || objectMap2->get_height() != newHeight) {
objectMap2.clear();
}
}
if (!objectMap2 && newWidth>0 && newHeight>0) {
objectMap2 = Cairo::ImageSurface::create(Cairo::FORMAT_A8, newWidth, newHeight);
}
} else if (objectMap2) {
// OM_255 -> deleting objectMap2, if any
objectMap2.clear();
}
} else {
flush();
}
} else {
flush();
}
}
int ObjectMOBuffer::getObjectID(const rtengine::Coord& location)
{
int id = 0;
if (objectMap && location.x > 0 && location.y > 0 && location.x < objectMap->get_width() && location.y < objectMap->get_height()) {
id = (unsigned short)(*( objectMap->get_data() + location.y * objectMap->get_stride() + location.x ));
if (objectMap2) {
id |= (unsigned short)(*( objectMap->get_data() + location.y * objectMap->get_stride() + location.x )) << 8;
}
}
return id - 1;
}
bool ObjectMOBuffer::bufferCreated()
{
EditSubscriber* subscriber;
if (dataProvider && (subscriber = dataProvider->getCurrSubscriber())) {
return subscriber->getEditingType() == ET_OBJECTS ? bool(objectMap) : false;
}
return false;
}
RGBColor Geometry::getInnerLineColor ()
{
RGBColor color;
@ -60,7 +170,7 @@ RGBColor Geometry::getOuterLineColor ()
return color;
}
void Circle::drawOuterGeometry(Cairo::RefPtr<Cairo::Context> &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem)
void Circle::drawOuterGeometry(Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem)
{
if ((flags & F_VISIBLE) && state != INSENSITIVE) {
RGBColor color;
@ -75,14 +185,14 @@ void Circle::drawOuterGeometry(Cairo::RefPtr<Cairo::Context> &cr, rtengine::Edit
cr->set_line_width( getOuterLineWidth() );
rtengine::Coord center_ = center;
double radius_ = radiusInImageSpace ? coordSystem.scaleValueToScreen(double(radius)) : double(radius);
double radius_ = radiusInImageSpace ? coordSystem.scaleValueToCanvas(double(radius)) : double(radius);
if (datum == IMAGE) {
coordSystem.imageCoordToScreen (center.x, center.y, center_.x, center_.y);
} else if (datum == CLICKED_POINT) {
center_ += editBuffer->getDataProvider()->posScreen;
center_ += objectBuffer->getDataProvider()->posScreen;
} else if (datum == CURSOR) {
center_ += editBuffer->getDataProvider()->posScreen + editBuffer->getDataProvider()->deltaScreen;
center_ += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen;
}
cr->arc(center_.x + 0.5, center_.y + 0.5, radius_, 0., 2.*M_PI);
@ -90,7 +200,7 @@ void Circle::drawOuterGeometry(Cairo::RefPtr<Cairo::Context> &cr, rtengine::Edit
}
}
void Circle::drawInnerGeometry(Cairo::RefPtr<Cairo::Context> &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem)
void Circle::drawInnerGeometry(Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem)
{
if (flags & F_VISIBLE) {
if (state != INSENSITIVE) {
@ -108,14 +218,14 @@ void Circle::drawInnerGeometry(Cairo::RefPtr<Cairo::Context> &cr, rtengine::Edit
cr->set_line_width( innerLineWidth );
rtengine::Coord center_ = center;
double radius_ = radiusInImageSpace ? coordSystem.scaleValueToScreen(double(radius)) : double(radius);
double radius_ = radiusInImageSpace ? coordSystem.scaleValueToCanvas(double(radius)) : double(radius);
if (datum == IMAGE) {
coordSystem.imageCoordToScreen (center.x, center.y, center_.x, center_.y);
} else if (datum == CLICKED_POINT) {
center_ += editBuffer->getDataProvider()->posScreen;
center_ += objectBuffer->getDataProvider()->posScreen;
} else if (datum == CURSOR) {
center_ += editBuffer->getDataProvider()->posScreen + editBuffer->getDataProvider()->deltaScreen;
center_ += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen;
}
if (filled && state != INSENSITIVE) {
@ -147,19 +257,19 @@ void Circle::drawInnerGeometry(Cairo::RefPtr<Cairo::Context> &cr, rtengine::Edit
}
}
void Circle::drawToMOChannel (Cairo::RefPtr<Cairo::Context> &cr, Cairo::RefPtr<Cairo::Context> &cr2, unsigned short id, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem)
void Circle::drawToMOChannel (Cairo::RefPtr<Cairo::Context> &cr, Cairo::RefPtr<Cairo::Context> &cr2, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem)
{
if (flags & F_HOVERABLE) {
cr->set_line_width( getMouseOverLineWidth() );
rtengine::Coord center_ = center;
double radius_ = radiusInImageSpace ? coordSystem.scaleValueToScreen(double(radius)) : double(radius);
double radius_ = radiusInImageSpace ? coordSystem.scaleValueToCanvas(double(radius)) : double(radius);
if (datum == IMAGE) {
coordSystem.imageCoordToCropBuffer(center.x, center.y, center_.x, center_.y);
coordSystem.imageCoordToCropCanvas (center.x, center.y, center_.x, center_.y);
} else if (datum == CLICKED_POINT) {
center_ += editBuffer->getDataProvider()->posScreen;
center_ += objectBuffer->getDataProvider()->posScreen;
} else if (datum == CURSOR) {
center_ += editBuffer->getDataProvider()->posScreen + editBuffer->getDataProvider()->deltaScreen;
center_ += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen;
}
// drawing the lower byte's value
@ -179,7 +289,7 @@ void Circle::drawToMOChannel (Cairo::RefPtr<Cairo::Context> &cr, Cairo::RefPtr<C
}
// drawing the higher byte's value
if (editBuffer->getObjectMode() == OM_65535) {
if (objectBuffer->getObjectMode() == OM_65535) {
a = (id + 1) >> 8;
cr2->set_source_rgba (0., 0., 0., double(a) / 255.);
cr2->arc(center_.x + 0.5, center_.y + 0.5, radius_, 0, 2.*M_PI);
@ -198,7 +308,7 @@ void Circle::drawToMOChannel (Cairo::RefPtr<Cairo::Context> &cr, Cairo::RefPtr<C
}
}
void Line::drawOuterGeometry(Cairo::RefPtr<Cairo::Context> &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem)
void Line::drawOuterGeometry(Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem)
{
if ((flags & F_VISIBLE) && state != INSENSITIVE) {
RGBColor color;
@ -219,11 +329,11 @@ void Line::drawOuterGeometry(Cairo::RefPtr<Cairo::Context> &cr, rtengine::EditBu
coordSystem.imageCoordToScreen (begin.x, begin.y, begin_.x, begin_.y);
coordSystem.imageCoordToScreen (end.x, end.y, end_.x, end_.y);
} else if (datum == CLICKED_POINT) {
begin_ += editBuffer->getDataProvider()->posScreen;
end_ += editBuffer->getDataProvider()->posScreen;
begin_ += objectBuffer->getDataProvider()->posScreen;
end_ += objectBuffer->getDataProvider()->posScreen;
} else if (datum == CURSOR) {
begin_ += editBuffer->getDataProvider()->posScreen + editBuffer->getDataProvider()->deltaScreen;
end_ += editBuffer->getDataProvider()->posScreen + editBuffer->getDataProvider()->deltaScreen;
begin_ += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen;
end_ += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen;
}
cr->move_to(begin_.x + 0.5, begin_.y + 0.5);
@ -232,7 +342,7 @@ void Line::drawOuterGeometry(Cairo::RefPtr<Cairo::Context> &cr, rtengine::EditBu
}
}
void Line::drawInnerGeometry(Cairo::RefPtr<Cairo::Context> &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem)
void Line::drawInnerGeometry(Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem)
{
if ((flags & F_VISIBLE) && innerLineWidth > 0.) {
if (state != INSENSITIVE) {
@ -256,11 +366,11 @@ void Line::drawInnerGeometry(Cairo::RefPtr<Cairo::Context> &cr, rtengine::EditBu
coordSystem.imageCoordToScreen (begin.x, begin.y, begin_.x, begin_.y);
coordSystem.imageCoordToScreen (end.x, end.y, end_.x, end_.y);
} else if (datum == CLICKED_POINT) {
begin_ += editBuffer->getDataProvider()->posScreen;
end_ += editBuffer->getDataProvider()->posScreen;
begin_ += objectBuffer->getDataProvider()->posScreen;
end_ += objectBuffer->getDataProvider()->posScreen;
} else if (datum == CURSOR) {
begin_ += editBuffer->getDataProvider()->posScreen + editBuffer->getDataProvider()->deltaScreen;
end_ += editBuffer->getDataProvider()->posScreen + editBuffer->getDataProvider()->deltaScreen;
begin_ += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen;
end_ += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen;
}
cr->move_to(begin_.x + 0.5, begin_.y + 0.5);
@ -284,7 +394,7 @@ void Line::drawInnerGeometry(Cairo::RefPtr<Cairo::Context> &cr, rtengine::EditBu
void Line::drawToMOChannel(Cairo::RefPtr<Cairo::Context> &cr,
Cairo::RefPtr<Cairo::Context> &cr2, unsigned short id,
rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem)
ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem)
{
if (flags & F_HOVERABLE) {
cr->set_line_width( getMouseOverLineWidth() );
@ -292,14 +402,14 @@ void Line::drawToMOChannel(Cairo::RefPtr<Cairo::Context> &cr,
rtengine::Coord end_ = end;
if (datum == IMAGE) {
coordSystem.imageCoordToCropBuffer(begin.x, begin.y, begin_.x, begin_.y);
coordSystem.imageCoordToCropBuffer(end.x, end.y, end_.x, end_.y);
coordSystem.imageCoordToCropCanvas (begin.x, begin.y, begin_.x, begin_.y);
coordSystem.imageCoordToCropCanvas (end.x, end.y, end_.x, end_.y);
} else if (datum == CLICKED_POINT) {
begin_ += editBuffer->getDataProvider()->posScreen;
end_ += editBuffer->getDataProvider()->posScreen;
begin_ += objectBuffer->getDataProvider()->posScreen;
end_ += objectBuffer->getDataProvider()->posScreen;
} else if (datum == CURSOR) {
begin_ += editBuffer->getDataProvider()->posScreen + editBuffer->getDataProvider()->deltaScreen;
end_ += editBuffer->getDataProvider()->posScreen + editBuffer->getDataProvider()->deltaScreen;
begin_ += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen;
end_ += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen;
}
// drawing the lower byte's value
@ -310,7 +420,7 @@ void Line::drawToMOChannel(Cairo::RefPtr<Cairo::Context> &cr,
cr->stroke();
// drawing the higher byte's value
if (editBuffer->getObjectMode() == OM_65535) {
if (objectBuffer->getObjectMode() == OM_65535) {
a = (id + 1) >> 8;
cr2->set_source_rgba (0., 0., 0., double(a) / 255.);
cr2->move_to(begin_.x + 0.5, begin_.y + 0.5);
@ -320,7 +430,7 @@ void Line::drawToMOChannel(Cairo::RefPtr<Cairo::Context> &cr,
}
}
void Polyline::drawOuterGeometry(Cairo::RefPtr<Cairo::Context> &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem)
void Polyline::drawOuterGeometry(Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem)
{
if ((flags & F_VISIBLE) && state != INSENSITIVE && points.size() > 1) {
RGBColor color;
@ -342,9 +452,9 @@ void Polyline::drawOuterGeometry(Cairo::RefPtr<Cairo::Context> &cr, rtengine::Ed
if (datum == IMAGE) {
coordSystem.imageCoordToScreen (points.at(i).x, points.at(i).y, currPos.x, currPos.y);
} else if (datum == CLICKED_POINT) {
currPos += editBuffer->getDataProvider()->posScreen;
currPos += objectBuffer->getDataProvider()->posScreen;
} else if (datum == CURSOR) {
currPos += editBuffer->getDataProvider()->posScreen + editBuffer->getDataProvider()->deltaScreen;
currPos += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen;
}
if (!i) {
@ -363,7 +473,7 @@ void Polyline::drawOuterGeometry(Cairo::RefPtr<Cairo::Context> &cr, rtengine::Ed
}
}
void Polyline::drawInnerGeometry(Cairo::RefPtr<Cairo::Context> &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem)
void Polyline::drawInnerGeometry(Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem)
{
if ((flags & F_VISIBLE) && points.size() > 1) {
if (state != INSENSITIVE) {
@ -389,9 +499,9 @@ void Polyline::drawInnerGeometry(Cairo::RefPtr<Cairo::Context> &cr, rtengine::Ed
if (datum == IMAGE) {
coordSystem.imageCoordToScreen (points.at(i).x, points.at(i).y, currPos.x, currPos.y);
} else if (datum == CLICKED_POINT) {
currPos += editBuffer->getDataProvider()->posScreen;
currPos += objectBuffer->getDataProvider()->posScreen;
} else if (datum == CURSOR) {
currPos += editBuffer->getDataProvider()->posScreen + editBuffer->getDataProvider()->deltaScreen;
currPos += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen;
}
if (!i) {
@ -416,9 +526,9 @@ void Polyline::drawInnerGeometry(Cairo::RefPtr<Cairo::Context> &cr, rtengine::Ed
if (datum == IMAGE) {
coordSystem.imageCoordToScreen (points.at(i).x, points.at(i).y, currPos.x, currPos.y);
} else if (datum == CLICKED_POINT) {
currPos += editBuffer->getDataProvider()->posScreen;
currPos += objectBuffer->getDataProvider()->posScreen;
} else if (datum == CURSOR) {
currPos += editBuffer->getDataProvider()->posScreen + editBuffer->getDataProvider()->deltaScreen;
currPos += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen;
}
if (!i) {
@ -445,7 +555,7 @@ void Polyline::drawInnerGeometry(Cairo::RefPtr<Cairo::Context> &cr, rtengine::Ed
}
}
void Polyline::drawToMOChannel (Cairo::RefPtr<Cairo::Context> &cr, Cairo::RefPtr<Cairo::Context> &cr2, unsigned short id, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem)
void Polyline::drawToMOChannel (Cairo::RefPtr<Cairo::Context> &cr, Cairo::RefPtr<Cairo::Context> &cr2, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem)
{
if ((flags & F_HOVERABLE) && points.size() > 1) {
rtengine::Coord currPos;
@ -459,11 +569,11 @@ void Polyline::drawToMOChannel (Cairo::RefPtr<Cairo::Context> &cr, Cairo::RefPtr
currPos = points.at(i);
if (datum == IMAGE) {
coordSystem.imageCoordToCropBuffer(points.at(i).x, points.at(i).y, currPos.x, currPos.y);
coordSystem.imageCoordToCropCanvas (points.at(i).x, points.at(i).y, currPos.x, currPos.y);
} else if (datum == CLICKED_POINT) {
currPos += editBuffer->getDataProvider()->posScreen;
currPos += objectBuffer->getDataProvider()->posScreen;
} else if (datum == CURSOR) {
currPos += editBuffer->getDataProvider()->posScreen + editBuffer->getDataProvider()->deltaScreen;
currPos += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen;
}
if (!i) {
@ -485,7 +595,7 @@ void Polyline::drawToMOChannel (Cairo::RefPtr<Cairo::Context> &cr, Cairo::RefPtr
}
// drawing the higher byte's value
if (editBuffer->getObjectMode() == OM_65535) {
if (objectBuffer->getObjectMode() == OM_65535) {
a = (id + 1) >> 8;
cr2->set_source_rgba (0., 0., 0., double(a) / 255.);
@ -494,11 +604,11 @@ void Polyline::drawToMOChannel (Cairo::RefPtr<Cairo::Context> &cr, Cairo::RefPtr
currPos = points.at(i);
if (datum == IMAGE) {
coordSystem.imageCoordToCropBuffer(points.at(i).x, points.at(i).y, currPos.x, currPos.y);
coordSystem.imageCoordToCropCanvas (points.at(i).x, points.at(i).y, currPos.x, currPos.y);
} else if (datum == CLICKED_POINT) {
currPos += editBuffer->getDataProvider()->posScreen;
currPos += objectBuffer->getDataProvider()->posScreen;
} else if (datum == CURSOR) {
currPos += editBuffer->getDataProvider()->posScreen + editBuffer->getDataProvider()->deltaScreen;
currPos += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen;
}
if (!i) {
@ -546,7 +656,7 @@ void Rectangle::setXYXY(rtengine::Coord topLeft, rtengine::Coord bottomRight)
this->bottomRight = bottomRight;
}
void Rectangle::drawOuterGeometry(Cairo::RefPtr<Cairo::Context> &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem)
void Rectangle::drawOuterGeometry(Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem)
{
if ((flags & F_VISIBLE) && state != INSENSITIVE) {
RGBColor color;
@ -565,17 +675,17 @@ void Rectangle::drawOuterGeometry(Cairo::RefPtr<Cairo::Context> &cr, rtengine::E
if (datum == IMAGE) {
coordSystem.imageCoordToScreen (topLeft.x, topLeft.y, tl.x, tl.y);
} else if (datum == CLICKED_POINT) {
tl = topLeft + editBuffer->getDataProvider()->posScreen;
tl = topLeft + objectBuffer->getDataProvider()->posScreen;
} else if (datum == CURSOR) {
tl = topLeft + editBuffer->getDataProvider()->posScreen + editBuffer->getDataProvider()->deltaScreen;
tl = topLeft + objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen;
}
if (datum == IMAGE) {
coordSystem.imageCoordToScreen (bottomRight.x, bottomRight.y, br.x, br.y);
} else if (datum == CLICKED_POINT) {
br = bottomRight + editBuffer->getDataProvider()->posScreen;
br = bottomRight + objectBuffer->getDataProvider()->posScreen;
} else if (datum == CURSOR) {
br = bottomRight + editBuffer->getDataProvider()->posScreen + editBuffer->getDataProvider()->deltaScreen;
br = bottomRight + objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen;
}
cr->rectangle(tl.x + 0.5, tl.y + 0.5, br.x - tl.x, br.y - tl.y);
@ -589,7 +699,7 @@ void Rectangle::drawOuterGeometry(Cairo::RefPtr<Cairo::Context> &cr, rtengine::E
}
}
void Rectangle::drawInnerGeometry(Cairo::RefPtr<Cairo::Context> &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem)
void Rectangle::drawInnerGeometry(Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem)
{
if (flags & F_VISIBLE) {
if (state != INSENSITIVE) {
@ -611,17 +721,17 @@ void Rectangle::drawInnerGeometry(Cairo::RefPtr<Cairo::Context> &cr, rtengine::E
if (datum == IMAGE) {
coordSystem.imageCoordToScreen (topLeft.x, topLeft.y, tl.x, tl.y);
} else if (datum == CLICKED_POINT) {
tl = topLeft + editBuffer->getDataProvider()->posScreen;
tl = topLeft + objectBuffer->getDataProvider()->posScreen;
} else if (datum == CURSOR) {
tl = topLeft + editBuffer->getDataProvider()->posScreen + editBuffer->getDataProvider()->deltaScreen;
tl = topLeft + objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen;
}
if (datum == IMAGE) {
coordSystem.imageCoordToScreen (bottomRight.x, bottomRight.y, br.x, br.y);
} else if (datum == CLICKED_POINT) {
br = bottomRight + editBuffer->getDataProvider()->posScreen;
br = bottomRight + objectBuffer->getDataProvider()->posScreen;
} else if (datum == CURSOR) {
br = bottomRight + editBuffer->getDataProvider()->posScreen + editBuffer->getDataProvider()->deltaScreen;
br = bottomRight + objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen;
}
if (filled && state != INSENSITIVE) {
@ -653,7 +763,7 @@ void Rectangle::drawInnerGeometry(Cairo::RefPtr<Cairo::Context> &cr, rtengine::E
}
}
void Rectangle::drawToMOChannel(Cairo::RefPtr<Cairo::Context> &cr, Cairo::RefPtr<Cairo::Context> &cr2, unsigned short id, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem)
void Rectangle::drawToMOChannel(Cairo::RefPtr<Cairo::Context> &cr, Cairo::RefPtr<Cairo::Context> &cr2, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem)
{
if (flags & F_HOVERABLE) {
cr->set_line_width( getMouseOverLineWidth() );
@ -661,19 +771,19 @@ void Rectangle::drawToMOChannel(Cairo::RefPtr<Cairo::Context> &cr, Cairo::RefPtr
rtengine::Coord tl, br;
if (datum == IMAGE) {
coordSystem.imageCoordToCropBuffer(topLeft.x, topLeft.y, tl.x, tl.y);
coordSystem.imageCoordToCropCanvas (topLeft.x, topLeft.y, tl.x, tl.y);
} else if (datum == CLICKED_POINT) {
tl = topLeft + editBuffer->getDataProvider()->posScreen;
tl = topLeft + objectBuffer->getDataProvider()->posScreen;
} else if (datum == CURSOR) {
tl = topLeft + editBuffer->getDataProvider()->posScreen + editBuffer->getDataProvider()->deltaScreen;
tl = topLeft + objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen;
}
if (datum == IMAGE) {
coordSystem.imageCoordToCropBuffer(bottomRight.x, bottomRight.y, br.x, br.y);
coordSystem.imageCoordToCropCanvas (bottomRight.x, bottomRight.y, br.x, br.y);
} else if (datum == CLICKED_POINT) {
br = bottomRight + editBuffer->getDataProvider()->posScreen;
br = bottomRight + objectBuffer->getDataProvider()->posScreen;
} else if (datum == CURSOR) {
br = bottomRight + editBuffer->getDataProvider()->posScreen + editBuffer->getDataProvider()->deltaScreen;
br = bottomRight + objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen;
}
// drawing the lower byte's value
@ -693,7 +803,7 @@ void Rectangle::drawToMOChannel(Cairo::RefPtr<Cairo::Context> &cr, Cairo::RefPtr
}
// drawing the higher byte's value
if (editBuffer->getObjectMode() == OM_65535) {
if (objectBuffer->getObjectMode() == OM_65535) {
a = (id + 1) >> 8;
cr2->set_source_rgba (0., 0., 0., double(a) / 255.);
cr->rectangle(tl.x + 0.5, tl.y + 0.5, br.x - tl.x, br.y - tl.y);
@ -766,7 +876,7 @@ EditType EditSubscriber::getEditingType()
return editingType;
}
BufferType EditSubscriber::getEditBufferType()
BufferType EditSubscriber::getPipetteBufferType()
{
return bufferType;
}

View File

@ -29,11 +29,7 @@
#include "options.h"
class EditDataProvider;
namespace rtengine
{
class EditBuffer;
}
class EditSubscriber;
/** @file
*
@ -41,9 +37,6 @@ class EditBuffer;
* Subscribers will be tools that need to create some graphics in the preview area, to let the user interact
* with it in a more user friendly way.
*
* Subscribers will be tools that need to create some graphics in the preview area, to let the user interact
* with it in a more user friendly way.
*
* Do not confuse with _local_ editing, which is another topic implemented in another class. The Edit feature
* is also not supported in batch editing from the File Browser.
*
@ -84,7 +77,7 @@ class EditBuffer;
*
* ## Object edition
*
* By using this class, object can be drawn and manipulated on the preview.
* 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
* are buttonPress, buttonRelease and drag methods dedicated to each mouse button, for better flexibility
@ -92,7 +85,7 @@ class EditBuffer;
* does not handle multiple mouse button event (e.g. button1 + button2), only one at a time. The first button pressed
* set the mechanism, all other combined button press are ignored.
*
* The developer also have to fill 2 display list with object of the Geometry subclass. Each geometrical shape
* The developer also have to fill 2 display list with object of the Geometry subclass. Each geometric shape
* _can_ be used in one or the other, or both list at a time.
*
* The first list (visibleGeometry) is used to be displayed on the preview. The developer will have to set their state
@ -152,6 +145,59 @@ class EditBuffer;
*
*/
class ObjectMOBuffer
{
private:
// Used to draw the objects where the color correspond to the object's ID, in order to find the correct object when hovering
Cairo::RefPtr<Cairo::ImageSurface> objectMap;
// If more than 254 objects has to be handled, objectMap2 contains the "upper part" of the 16 bit int value. objectMap2 will be NULL otherwise.
Cairo::RefPtr<Cairo::ImageSurface> objectMap2;
ObjectMode objectMode;
protected:
// To avoid duplicated information, we points to a EditDataProvider that contains the current EditSubscriber
// instead of pointing to the EditSubscriber directly
EditDataProvider* dataProvider;
void createBuffer(int width, int height);
void resize(int newWidth, int newHeight, EditSubscriber* newSubscriber);
void flush();
EditSubscriber *getEditSubscriber ();
public:
ObjectMOBuffer(EditDataProvider *dataProvider);
~ObjectMOBuffer();
EditDataProvider* getDataProvider()
{
return dataProvider;
}
void setObjectMode(ObjectMode newType);
ObjectMode getObjectMode()
{
return objectMode;
}
Cairo::RefPtr<Cairo::ImageSurface> &getObjectMap ()
{
return objectMap;
}
Cairo::RefPtr<Cairo::ImageSurface> &getObjectMap2()
{
return objectMap2;
}
// return true if the buffer has been allocated
bool bufferCreated();
int getObjectID(const rtengine::Coord& location);
};
/** @brief Coordinate system where the widgets will be drawn
*
* The EditCoordSystem is used to define a screen and an image coordinate system.
@ -167,6 +213,8 @@ public:
virtual void screenCoordToImage (int phyx, int phyy, int& imgx, int& imgy) = 0;
/// Convert the image coords to the widget's DrawingArea (i.e. preview area) coords
virtual void imageCoordToScreen (int imgx, int imgy, int& phyx, int& phyy) = 0;
/// Convert the image coords to the crop's canvas coords
virtual void imageCoordToCropCanvas (int imgx, int imgy, int& phyx, int& phyy) = 0;
/// Convert the image coords to the edit buffer coords
virtual void imageCoordToCropBuffer (int imgx, int imgy, int& phyx, int& phyy) = 0;
/// Convert a size value from the preview's scale to the image's scale
@ -176,11 +224,11 @@ public:
/// Convert a size value from the preview's scale to the image's scale
virtual double scaleValueToImage (double value) = 0;
/// Convert a size value from the image's scale to the preview's scale
virtual int scaleValueToScreen (int value) = 0;
virtual int scaleValueToCanvas (int value) = 0;
/// Convert a size value from the image's scale to the preview's scale
virtual float scaleValueToScreen (float value) = 0;
virtual float scaleValueToCanvas (float value) = 0;
/// Convert a size value from the image's scale to the preview's scale
virtual double scaleValueToScreen (double value) = 0;
virtual double scaleValueToCanvas (double value) = 0;
};
class RGBColor
@ -373,9 +421,9 @@ public:
}
}
virtual void drawOuterGeometry (Cairo::RefPtr<Cairo::Context> &cr, rtengine::EditBuffer *parent, EditCoordSystem &coordSystem) = 0;
virtual void drawInnerGeometry (Cairo::RefPtr<Cairo::Context> &cr, rtengine::EditBuffer *parent, EditCoordSystem &coordSystem) = 0;
virtual void drawToMOChannel (Cairo::RefPtr<Cairo::Context> &cr, Cairo::RefPtr<Cairo::Context> &cr2, unsigned short id, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem) = 0;
virtual void drawOuterGeometry (Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuffer *parent, EditCoordSystem &coordSystem) = 0;
virtual void drawInnerGeometry (Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuffer *parent, EditCoordSystem &coordSystem) = 0;
virtual void drawToMOChannel (Cairo::RefPtr<Cairo::Context> &cr, Cairo::RefPtr<Cairo::Context> &cr2, unsigned short id, ObjectMOBuffer *pipetteBuffer, EditCoordSystem &coordSystem) = 0;
};
class Circle : public Geometry
@ -390,9 +438,9 @@ public:
Circle (rtengine::Coord &center, int radius, bool filled = false, bool radiusInImageSpace = false) : center(center), radius(radius), filled(filled), radiusInImageSpace(radiusInImageSpace) {}
Circle (int centerX, int centerY, int radius, bool filled = false, bool radiusInImageSpace = false) : center(centerX, centerY), radius(radius), filled(filled), radiusInImageSpace(radiusInImageSpace) {}
void drawOuterGeometry (Cairo::RefPtr<Cairo::Context> &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem);
void drawInnerGeometry (Cairo::RefPtr<Cairo::Context> &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem);
void drawToMOChannel (Cairo::RefPtr<Cairo::Context> &cr, Cairo::RefPtr<Cairo::Context> &cr2, unsigned short id, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem);
void drawOuterGeometry (Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuffer *pipetteBuffer, EditCoordSystem &coordSystem);
void drawInnerGeometry (Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuffer *pipetteBuffer, EditCoordSystem &coordSystem);
void drawToMOChannel (Cairo::RefPtr<Cairo::Context> &cr, Cairo::RefPtr<Cairo::Context> &cr2, unsigned short id, ObjectMOBuffer *pipetteBuffer, EditCoordSystem &coordSystem);
};
class Line : public Geometry
@ -405,9 +453,9 @@ public:
Line (rtengine::Coord &begin, rtengine::Coord &end) : begin(begin), end(end) {}
Line (int beginX, int beginY, int endX, int endY) : begin(beginX, beginY), end(endX, endY) {}
void drawOuterGeometry (Cairo::RefPtr<Cairo::Context> &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem);
void drawInnerGeometry (Cairo::RefPtr<Cairo::Context> &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem);
void drawToMOChannel (Cairo::RefPtr<Cairo::Context> &cr, Cairo::RefPtr<Cairo::Context> &cr2, unsigned short id, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem);
void drawOuterGeometry (Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuffer *pipetteBuffer, EditCoordSystem &coordSystem);
void drawInnerGeometry (Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuffer *pipetteBuffer, EditCoordSystem &coordSystem);
void drawToMOChannel (Cairo::RefPtr<Cairo::Context> &cr, Cairo::RefPtr<Cairo::Context> &cr2, unsigned short id, ObjectMOBuffer *pipetteBuffer, EditCoordSystem &coordSystem);
};
class Polyline : public Geometry
@ -418,9 +466,9 @@ public:
Polyline() : filled(false) {}
void drawOuterGeometry (Cairo::RefPtr<Cairo::Context> &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem);
void drawInnerGeometry (Cairo::RefPtr<Cairo::Context> &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem);
void drawToMOChannel (Cairo::RefPtr<Cairo::Context> &cr, Cairo::RefPtr<Cairo::Context> &cr2, unsigned short id, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem);
void drawOuterGeometry (Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuffer *pipetteBuffer, EditCoordSystem &coordSystem);
void drawInnerGeometry (Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuffer *pipetteBuffer, EditCoordSystem &coordSystem);
void drawToMOChannel (Cairo::RefPtr<Cairo::Context> &cr, Cairo::RefPtr<Cairo::Context> &cr2, unsigned short id, ObjectMOBuffer *pipetteBuffer, EditCoordSystem &coordSystem);
};
class Rectangle : public Geometry
@ -436,9 +484,9 @@ 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<Cairo::Context> &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem);
void drawInnerGeometry (Cairo::RefPtr<Cairo::Context> &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem);
void drawToMOChannel (Cairo::RefPtr<Cairo::Context> &cr, Cairo::RefPtr<Cairo::Context> &cr2, unsigned short id, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem);
void drawOuterGeometry (Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuffer *pipetteBuffer, EditCoordSystem &coordSystem);
void drawInnerGeometry (Cairo::RefPtr<Cairo::Context> &cr, ObjectMOBuffer *pipetteBuffer, EditCoordSystem &coordSystem);
void drawToMOChannel (Cairo::RefPtr<Cairo::Context> &cr, Cairo::RefPtr<Cairo::Context> &cr2, unsigned short id, ObjectMOBuffer *pipetteBuffer, EditCoordSystem &coordSystem);
};
/// @brief Method for client tools needing Edit information
@ -474,7 +522,7 @@ public:
virtual void switchOffEditMode (); /// Occurs when the user want to stop the editing mode
EditUniqueID getEditID();
EditType getEditingType();
BufferType getEditBufferType();
BufferType getPipetteBufferType();
bool isDragging(); /// Returns true if something is being dragged and drag events has to be sent (object mode only)
/** @brief Get the cursor to be displayed when above handles
@ -487,7 +535,6 @@ public:
/** @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 | ...)
@param editBuffer buffer to get the pipette values and the from
@return true if the preview has to be redrawn, false otherwise */
virtual bool mouseOver(int modifierKey)
{

View File

@ -136,14 +136,26 @@ void Gradient::read (const ProcParams* pp, const ParamsEdited* pedited)
enableListener ();
}
void Gradient::updateGeometry(int centerX_, int centerY_, double feather_, double degree_)
void Gradient::updateGeometry(const int centerX_, const int centerY_, const double feather_, const double degree_, const int fullWidth, const int fullHeight)
{
EditDataProvider* dataProvider = getEditProvider();
if (dataProvider) {
if (!dataProvider) {
return;
}
int imW, imH;
PolarCoord polCoord1, polCoord2;
if (fullWidth != -1 && fullHeight != -1) {
imW = fullWidth;
imH = fullHeight;
} else {
dataProvider->getImageSize(imW, imH);
if (!imW || !imH) {
return;
}
}
PolarCoord polCoord1, polCoord2;
double decay = feather_ * sqrt(double(imW) * double(imW) + double(imH) * double(imH)) / 200.;
rtengine::Coord origin(imW / 2 + centerX_ * imW / 200.f, imH / 2 + centerY_ * imH / 200.f);
@ -218,7 +230,6 @@ void Gradient::updateGeometry(int centerX_, int centerY_, double feather_, doubl
currCircle = static_cast<Circle*>(mouseOverGeometry.at(4));
currCircle->center = origin;
}
}
void Gradient::write (ProcParams* pp, ParamsEdited* pedited)
{
@ -399,7 +410,7 @@ bool Gradient::button1Pressed(int modifierKey)
{
EditDataProvider *provider = getEditProvider();
if (!(modifierKey & GDK_CONTROL_MASK)) {
if (!(modifierKey & GDK_CONTROL_MASK) && lastObject > -1) {
// button press is valid (no modifier key)
PolarCoord pCoord;
int imW, imH;
@ -447,20 +458,20 @@ bool Gradient::button1Pressed(int modifierKey)
EditSubscriber::dragging = true;
return false;
} else {
} else if (lastObject > -1) { // should theoretically always be true
// this will let this class ignore further drag events
if (lastObject > -1) { // should theoretically always be true
if (lastObject == 2 || lastObject == 3) {
EditSubscriber::visibleGeometry.at(2)->state = Geometry::NORMAL;
EditSubscriber::visibleGeometry.at(3)->state = Geometry::NORMAL;
} else {
EditSubscriber::visibleGeometry.at(lastObject)->state = Geometry::NORMAL;
}
}
lastObject = -1;
return true;
}
return false;
}
bool Gradient::button1Released()

View File

@ -42,12 +42,11 @@ public:
void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited = NULL);
void setBatchMode (bool batchMode);
void updateGeometry (int centerX_, int centerY_, double feather_, double degree_);
void adjusterChanged (Adjuster* a, double newval);
void enabledChanged ();
void setAdjusterBehavior (bool degreeadd, bool featheradd, bool strengthadd, bool centeradd);
void trimValues (rtengine::procparams::ProcParams* pp);
void updateGeometry (const int centerX_, const int centerY_, const double feather_, const double degree_, const int fullWidth=-1, const int fullHeight=-1);
void setEditProvider (EditDataProvider* provider);

View File

@ -56,8 +56,8 @@ ImageArea::ImageArea (ImageAreaPanel* p) : parent(p), firstOpen(true)
ImageArea::~ImageArea ()
{
for (std::list<CropWindow*>::iterator i = cropWins.begin(); i != cropWins.end(); i++) {
delete *i;
for (auto cropWin : cropWins) {
delete cropWin;
}
cropWins.clear ();
@ -110,10 +110,9 @@ void ImageArea::setImProcCoordinator (rtengine::StagedImageProcessor* ipc_)
{
if( !ipc_ ) {
focusGrabber = NULL;
std::list<CropWindow*>::iterator i = cropWins.begin();
for( ; i != cropWins.end(); i++ ) {
delete *i;
for (auto cropWin : cropWins) {
delete cropWin;
}
cropWins.clear();
@ -170,9 +169,10 @@ CropWindow* ImageArea::getCropWindow (int x, int y)
CropWindow* cw = mainCropWindow;
for (std::list<CropWindow*>::iterator i = cropWins.begin(); i != cropWins.end(); i++)
if ((*i)->isInside (x, y)) {
return *i;
for (auto cropWin : cropWins) {
if (cropWin->isInside (x, y)) {
return cropWin;
}
}
return cw;
@ -200,7 +200,6 @@ bool ImageArea::on_expose_event(GdkEventExpose* event)
Cairo::RefPtr<Cairo::Context> cr = get_window()->create_cairo_context();
if (mainCropWindow) {
//printf("MainCropWindow (%d x %d)\n", window->get_width(), window->get_height());
mainCropWindow->expose (cr);
}
@ -275,11 +274,11 @@ bool ImageArea::on_scroll_event (GdkEventScroll* event)
int newCenterX = (int)event->x;
int newCenterY = (int)event->y;
cw->screenCoordToImage(newCenterX, newCenterY, newCenterX, newCenterY);
if (event->direction == GDK_SCROLL_UP && !cw->isMaxZoom()) {
cw->findCenter (1, newCenterX, newCenterY);
cw->zoomIn (true, newCenterX, newCenterY);
} else if (!cw->isMinZoom()) {
cw->findCenter (-1, newCenterX, newCenterY);
cw->zoomOut (true, newCenterX, newCenterY);
}
}
@ -327,10 +326,10 @@ bool ImageArea::on_leave_notify_event (GdkEventCrossing* event)
void ImageArea::subscribe(EditSubscriber *subscriber)
{
mainCropWindow->cropHandler.setEditSubscriber(subscriber);
mainCropWindow->setEditSubscriber(subscriber);
for (std::list<CropWindow*>::iterator i = cropWins.begin(); i != cropWins.end(); i++) {
(*i)->cropHandler.setEditSubscriber(subscriber);
for (auto cropWin : cropWins) {
cropWin->setEditSubscriber(subscriber);
}
EditDataProvider::subscribe(subscriber);
@ -339,7 +338,7 @@ void ImageArea::subscribe(EditSubscriber *subscriber)
listener->getToolBar()->startEditMode ();
}
if (subscriber->getEditingType() == ET_OBJECTS) {
if (subscriber && subscriber->getEditingType() == ET_OBJECTS) {
// In this case, no need to reprocess the image, so we redraw the image to display the geometry
queue_draw();
}
@ -358,8 +357,8 @@ void ImageArea::unsubscribe()
// Ask the Crops to free-up edit mode buffers
mainCropWindow->cropHandler.setEditSubscriber(NULL);
for (std::list<CropWindow*>::iterator i = cropWins.begin(); i != cropWins.end(); i++) {
(*i)->cropHandler.setEditSubscriber(NULL);
for (auto cropWin : cropWins) {
cropWin->cropHandler.setEditSubscriber(NULL);
}
setToolHand();
@ -473,12 +472,10 @@ void ImageArea::addCropWindow ()
y = cropheight * (N % maxRows);
cw->setPosition (x, y);
cw->setEditSubscriber (getCurrSubscriber());
cw->enable(); // start processing!
int x0, y0, w, h, wc, hc;
mainCropWindow->getCropRectangle(x0, y0, w, h );
cw->getCropSize(wc, hc);
cw->setCropPosition(x0 + w / 2 - wc / 2, y0 + h / 2 - hc / 2);
cw->centerCrop();
mainCropWindow->setObservedCropWin (cropWins.front());
if(cropWins.size() == 1) { // after first detail window we already have high quality
@ -539,9 +536,8 @@ void ImageArea::getScrollImageSize (int& w, int& h)
{
if (mainCropWindow && ipc) {
double z = mainCropWindow->getZoom ();
w = ipc->getFullWidth() * z;
h = ipc->getFullHeight() * z;
w = ipc->getFullWidth();
h = ipc->getFullHeight();
} else {
w = h = 0;
}
@ -551,10 +547,7 @@ void ImageArea::getScrollPosition (int& x, int& y)
{
if (mainCropWindow) {
int cropX, cropY;
mainCropWindow->getCropPosition (cropX, cropY);
x = cropX * mainCropWindow->getZoom ();
y = cropY * mainCropWindow->getZoom ();
mainCropWindow->getCropAnchorPosition (x, y);
} else {
x = y = 0;
}
@ -565,7 +558,7 @@ void ImageArea::setScrollPosition (int x, int y)
if (mainCropWindow) {
mainCropWindow->delCropWindowListener (this);
mainCropWindow->setCropPosition (x / mainCropWindow->getZoom (), y / mainCropWindow->getZoom ());
mainCropWindow->setCropAnchorPosition (x, y);
mainCropWindow->addCropWindowListener (this);
}
}
@ -618,19 +611,18 @@ void ImageArea::initialImageArrived (CropWindow* cw)
if (mainCropWindow) {
if(firstOpen || options.prevdemo != PD_Sidecar || (!options.rememberZoomAndPan) ) {
mainCropWindow->zoomFit (false);
mainCropWindow->zoomFit ();
firstOpen = false;
mainCropWindow->cropHandler.getFullImageSize(fullImageWidth, fullImageHeight);
} else {
int w, h;
mainCropWindow->cropHandler.getFullImageSize(w, h);
if(w == fullImageWidth && h == fullImageHeight) { // && mainCropWindow->getZoom() != mainCropWindow->getZoomFitVal()) {
int x, y;
mainCropWindow->getCropPosition(x, y);
mainCropWindow->setCropPosition(x, y, false);
if(w != fullImageWidth || h != fullImageHeight) {
printf("zoomFit !\n");
mainCropWindow->zoomFit ();
} else {
mainCropWindow->zoomFit (false);
printf("no-zoomFit\n");
}
fullImageWidth = w;
@ -649,8 +641,8 @@ void ImageArea::setCropGUIListener (CropGUIListener* l)
cropgl = l;
for (std::list<CropWindow*>::iterator i = cropWins.begin(); i != cropWins.end(); i++) {
(*i)->setCropGUIListener (cropgl);
for (auto cropWin : cropWins) {
cropWin->setCropGUIListener (cropgl);
}
if (mainCropWindow) {
@ -663,8 +655,8 @@ void ImageArea::setPointerMotionListener (PointerMotionListener* pml)
pmlistener = pml;
for (std::list<CropWindow*>::iterator i = cropWins.begin(); i != cropWins.end(); i++) {
(*i)->setPointerMotionListener (pml);
for (auto cropWin : cropWins) {
cropWin->setPointerMotionListener (pml);
}
if (mainCropWindow) {
@ -677,8 +669,8 @@ void ImageArea::setPointerMotionHListener (PointerMotionListener* pml)
pmhlistener = pml;
for (std::list<CropWindow*>::iterator i = cropWins.begin(); i != cropWins.end(); i++) {
(*i)->setPointerMotionHListener (pml);
for (auto cropWin : cropWins) {
cropWin->setPointerMotionHListener (pml);
}
if (mainCropWindow) {

View File

@ -84,9 +84,7 @@ void ImageAreaPanel::synchronize ()
after->imageArea->getScrollPosition (x, y);
if (imgw > 0 && imgh > 0) {
int bimgw, bimgh;
imageArea->getScrollImageSize (bimgw, bimgh);
imageArea->setScrollPosition (x * bimgw / imgw, y * bimgh / imgh);
imageArea->setScrollPosition (x, y);
imageArea->queue_draw ();
}
} else if (before && this == after) {
@ -95,9 +93,7 @@ void ImageAreaPanel::synchronize ()
before->imageArea->getScrollPosition (x, y);
if (imgw > 0 && imgh > 0) {
int bimgw, bimgh;
imageArea->getScrollImageSize (bimgw, bimgh);
imageArea->setScrollPosition (x * bimgw / imgw, y * bimgh / imgh);
imageArea->setScrollPosition (x, y);
imageArea->queue_draw ();
}
}

View File

@ -204,27 +204,19 @@ Glib::RefPtr<Gdk::Pixbuf> PreviewHandler::getRoughImage (int x, int y, int w, in
h = image->getHeight() * totalZoom;
}
int ix = x * zoom;
int iy = y * zoom;
x *= zoom;
y *= zoom;
if (ix < 0) {
ix = 0;
if ((x + w) / totalZoom > previewImg->get_width()) {
w = previewImg->get_width() * totalZoom - x;
}
if (iy < 0) {
iy = 0;
}
if ((ix + w) / totalZoom > previewImg->get_width()) {
ix = previewImg->get_width() * totalZoom - w;
}
if ((iy + h) / totalZoom > previewImg->get_height()) {
iy = previewImg->get_height() * totalZoom - h;
if ((y + h) / totalZoom > previewImg->get_height()) {
h = previewImg->get_height() * totalZoom - y;
}
resPixbuf = Gdk::Pixbuf::create (Gdk::COLORSPACE_RGB, false, 8, w, h);
previewImg->scale (resPixbuf, 0, 0, w, h, -ix, -iy, totalZoom, totalZoom, Gdk::INTERP_NEAREST);
previewImg->scale (resPixbuf, 0, 0, w, h, -x, -y, totalZoom, totalZoom, Gdk::INTERP_NEAREST);
}
return resPixbuf;

View File

@ -199,6 +199,8 @@ bool PreviewWindow::on_motion_notify_event (GdkEventMotion* event)
if (isMoving) {
mainCropWin->remoteMove ((event->x - press_x) / zoom, (event->y - press_y) / zoom);
press_x = event->x;
press_y = event->y;
} else if (inside && !moreInside) {
cursorManager.setCursor (get_window(), CSClosedHand);
} else {

View File

@ -269,8 +269,8 @@ ToolPanelCoordinator::ToolPanelCoordinator () : ipc(NULL)
toolPanelNotebook->set_scrollable ();
toolPanelNotebook->show_all ();
for (size_t i = 0; i < toolPanels.size(); i++) {
toolPanels[i]->setListener (this);
for (auto toolPanel : toolPanels) {
toolPanel->setListener (this);
}
whitebalance->setWBProvider (this);
@ -323,8 +323,8 @@ void ToolPanelCoordinator::panelChanged (rtengine::ProcEvent event, const Glib::
ProcParams* params = ipc->beginUpdateParams ();
for (size_t i = 0; i < toolPanels.size(); i++) {
toolPanels[i]->write (params);
for (auto toolPanel : toolPanels) {
toolPanel->write (params);
}
// Compensate rotation on flip
@ -336,6 +336,24 @@ void ToolPanelCoordinator::panelChanged (rtengine::ProcEvent event, const Glib::
}
}
int tr = TR_NONE;
if (params->coarse.rotate == 90) {
tr = TR_R90;
} else if (params->coarse.rotate == 180) {
tr = TR_R180;
} else if (params->coarse.rotate == 270) {
tr = TR_R270;
}
// Update "on preview" geometry
if (event == rtengine::EvPhotoLoaded || event == rtengine::EvProfileChanged || event == rtengine::EvHistoryBrowsed || event == rtengine::EvCTRotate) {
// updating the "on preview" geometry
int fw, fh;
rtengine::ImageSource *ii = (rtengine::ImageSource*)ipc->getInitialImage();
ii->getFullSize (fw, fh, tr);
gradient->updateGeometry (params->gradient.centerX, params->gradient.centerY, params->gradient.feather, params->gradient.degree, fw, fh);
}
// some transformations make the crop change for convenience
if (event == rtengine::EvCTHFlip) {
crop->hFlipCrop ();
@ -357,8 +375,8 @@ void ToolPanelCoordinator::panelChanged (rtengine::ProcEvent event, const Glib::
hasChanged = true;
for (size_t i = 0; i < paramcListeners.size(); i++) {
paramcListeners[i]->procParamsChanged (params, event, descr);
for (auto paramcListener : paramcListeners) {
paramcListener->procParamsChanged (params, event, descr);
}
}
@ -403,17 +421,12 @@ void ToolPanelCoordinator::profileChange (const PartialProfile *nparams, rtengi
delete mergedParams;
tr = TR_NONE;
if (params->coarse.rotate == 90) {
tr |= TR_R90;
}
if (params->coarse.rotate == 180) {
tr |= TR_R180;
}
if (params->coarse.rotate == 270) {
tr |= TR_R270;
tr = TR_R90;
} else if (params->coarse.rotate == 180) {
tr = TR_R180;
} else if (params->coarse.rotate == 270) {
tr = TR_R270;
}
// trimming overflowing cropped area
@ -422,14 +435,19 @@ void ToolPanelCoordinator::profileChange (const PartialProfile *nparams, rtengi
crop->trim(params, fw, fh);
// updating the GUI with updated values
for (unsigned int i = 0; i < toolPanels.size(); i++) {
toolPanels[i]->read (params);
for (auto toolPanel : toolPanels) {
toolPanel->read (params);
if (event == rtengine::EvPhotoLoaded || event == rtengine::EvProfileChanged) {
toolPanels[i]->autoOpenCurve();
toolPanel->autoOpenCurve();
}
}
if (event == rtengine::EvPhotoLoaded || event == rtengine::EvProfileChanged || event == rtengine::EvHistoryBrowsed || event == rtengine::EvCTRotate) {
// updating the "on preview" geometry
gradient->updateGeometry (params->gradient.centerX, params->gradient.centerY, params->gradient.feather, params->gradient.degree, fw, fh);
}
// start the IPC processing
if (filterRawRefresh) {
ipc->endUpdateParams ( refreshmap[(int)event] & ALLNORAW );
@ -439,8 +457,8 @@ void ToolPanelCoordinator::profileChange (const PartialProfile *nparams, rtengi
hasChanged = event != rtengine::EvProfileChangeNotification;
for (size_t i = 0; i < paramcListeners.size(); i++) {
paramcListeners[i]->procParamsChanged (params, event, descr);
for (auto paramcListener : paramcListeners) {
paramcListener->procParamsChanged (params, event, descr);
}
}
@ -448,8 +466,8 @@ void ToolPanelCoordinator::setDefaults (ProcParams* defparams)
{
if (defparams)
for (size_t i = 0; i < toolPanels.size(); i++) {
toolPanels[i]->setDefaults (defparams);
for (auto toolPanel : toolPanels) {
toolPanel->setDefaults (defparams);
}
}
@ -746,9 +764,9 @@ void ToolPanelCoordinator::updateCurveBackgroundHistogram (LUTu & histToneCurve,
void ToolPanelCoordinator::foldAllButOne (Gtk::Box* parent, FoldableToolPanel* openedSection)
{
for (size_t i = 0; i < toolPanels.size(); i++) {
if (toolPanels[i]->getParent() != NULL) {
ToolPanel* currentTP = toolPanels[i];
for (auto toolPanel : toolPanels) {
if (toolPanel->getParent() != NULL) {
ToolPanel* currentTP = toolPanel;
if (currentTP->getParent() == parent) {
// Section in the same tab, we unfold it if it's not the one that has been clicked

View File

@ -13,10 +13,38 @@
height="1052.3622047"
id="svg2"
version="1.1"
inkscape:version="0.48.4 r9939"
inkscape:version="0.91 r13725"
sodipodi:docname="coordinate_system.svg">
<defs
id="defs4">
<marker
inkscape:isstock="true"
style="overflow:visible"
id="marker4672"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lstart">
<path
transform="scale(0.8) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#969696;stroke-width:1pt;stroke-opacity:1;fill:#969696;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path4674" />
</marker>
<marker
inkscape:isstock="true"
style="overflow:visible;"
id="marker4626"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Lend">
<path
transform="scale(0.8) rotate(180) translate(12.5,0)"
style="fill-rule:evenodd;stroke:#969696;stroke-width:1pt;stroke-opacity:1;fill:#969696;fill-opacity:1"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path4628" />
</marker>
<marker
inkscape:stockid="Arrow1Lstart"
orient="auto"
@ -57,6 +85,19 @@
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
transform="matrix(-0.8,0,0,-0.8,-10,0)" />
</marker>
<filter
inkscape:collect="always"
style="color-interpolation-filters:sRGB"
id="filter4878"
x="-0.033017408"
width="1.0660348"
y="-0.32826923"
height="1.6565385">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="10.058594"
id="feGaussianBlur4880" />
</filter>
</defs>
<sodipodi:namedview
id="base"
@ -65,16 +106,16 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.70710678"
inkscape:cx="299.66147"
inkscape:cy="714.81018"
inkscape:zoom="0.5"
inkscape:cx="452.14874"
inkscape:cy="827.47718"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="991"
inkscape:window-height="915"
inkscape:window-x="738"
inkscape:window-y="60"
inkscape:window-width="1665"
inkscape:window-height="920"
inkscape:window-x="168"
inkscape:window-y="40"
inkscape:window-maximized="0"
showguides="true"
inkscape:guide-bbox="true" />
@ -94,6 +135,27 @@
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<rect
y="-293.04019"
x="-78.267029"
height="73.539108"
width="731.14844"
id="rect4800"
style="opacity:0.5;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;filter:url(#filter4878)" />
<rect
style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect4798"
width="731.14844"
height="73.539108"
x="-86.267029"
y="-301.04019" />
<rect
y="271.4635"
x="-69.296463"
height="527.3504"
width="885.09576"
id="rect3410"
style="fill:none;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:4,4;stroke-dashoffset:0;stroke-opacity:1" />
<rect
style="opacity:1;fill:#aaaaaa;fill-opacity:1;stroke:none"
id="rect2993"
@ -117,54 +179,49 @@
y="271.4635" />
<text
xml:space="preserve"
style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
x="724.4317"
y="1097.9205"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:125%;font-family:Sans;-inkscape-font-specification:Sans;text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none"
x="393.50574"
y="1104.9916"
id="text3804"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan3806"
x="724.4317"
y="1097.9205">imgAreaW</tspan></text>
x="393.50574"
y="1104.9916">imgAreaW</tspan></text>
<text
xml:space="preserve"
style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
x="-969.88525"
y="783.78394"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:125%;font-family:Sans;-inkscape-font-specification:Sans;text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none"
x="-931.88525"
y="925.78394"
id="text3808"
sodipodi:linespacing="125%"
transform="matrix(0,-1,1,0,0,0)"><tspan
sodipodi:role="line"
id="tspan3810"
x="-969.88525"
y="783.78394">imgAreaH</tspan></text>
x="-931.88525"
y="925.78394">imgAreaH</tspan></text>
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Lend)"
d="m 630.33519,1073.6769 c 81.82235,0 117.17769,0 117.17769,0"
style="fill:none;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow1Lstart);marker-end:url(#Arrow1Lend)"
d="m 1.8732037,1119.6769 c 517.6606863,0 741.3412663,0 741.3412663,0"
id="path3812"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Lend)"
d="m 760.64487,954.37739 0,97.98481"
style="fill:none;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Lend)"
d="m 940.64484,664.46366 0,387.00414"
id="path3814"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 780.84792,1052.3622 -35.35534,0 0,35.3553"
id="path3816"
inkscape:connector-curvature="0" />
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
x="3.2830606"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:125%;font-family:Sans;-inkscape-font-specification:Sans;text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none"
x="163.28305"
y="200.49203"
id="text3804-1"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="3.2830606"
x="163.28305"
y="200.49203"
id="tspan5224"
style="font-size:14px">leftBorder</tspan></text>
style="font-size:14px">cropHandler.getCrop()-&gt;getLeftBorder()</tspan></text>
<path
style="fill:none;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow1Lend-0);marker-end:url(#Arrow1Lstart)"
d="m -20.712438,227.69388 c 15.3477121,0 21.9794413,0 21.9794413,0"
@ -192,17 +249,17 @@
inkscape:connector-curvature="0" />
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
x="-239.34459"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:125%;font-family:Sans;-inkscape-font-specification:Sans;text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none"
x="-221.34459"
y="-85.32505"
id="text5604"
sodipodi:linespacing="125%"
transform="matrix(0,-1,1,0,0,0)"><tspan
sodipodi:role="line"
id="tspan5606"
x="-239.34459"
x="-221.34459"
y="-85.32505"
style="font-size:14px">upperBorder</tspan></text>
style="font-size:14px">cropHandler.getCrop()-&gt;getUpperBorder()</tspan></text>
<rect
y="182.76044"
x="1010.2919"
@ -277,17 +334,17 @@
<path
inkscape:connector-curvature="0"
id="path5630"
d="m -151.14286,272.55957 0,-271.4238"
style="fill:#0000ff;stroke:#0000ff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow1Lend-0);marker-end:url(#Arrow1Lstart);fill-opacity:1"
d="m -211.14286,272.55957 0,-271.4238"
style="fill:#0000ff;fill-opacity:1;stroke:#0000ff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow1Lstart);marker-end:url(#Arrow1Lend)"
sodipodi:nodetypes="cc" />
<path
inkscape:connector-curvature="0"
id="path5632"
d="m -107.42857,270.93361 -48.57143,0"
d="m -107.42857,270.93361 -117.16079,0"
style="fill:none;stroke:#0000ff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
style="fill:none;stroke:#0000ff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m -3.9596642,1.2452264 -156.5142958,0"
d="m -3.9596643,1.2452265 -222.2752357,0"
id="path5634"
inkscape:connector-curvature="0" />
<path
@ -326,16 +383,16 @@
style="font-size:14px">imgX</tspan></text>
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#0000ff;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:125%;font-family:Sans;-inkscape-font-specification:Sans;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#0000ff;fill-opacity:1;stroke:none"
x="-134.76872"
y="-163.5605"
y="-223.5605"
id="text6020"
sodipodi:linespacing="125%"
transform="matrix(0,-1,1,0,0,0)"><tspan
sodipodi:role="line"
id="tspan6022"
x="-134.76872"
y="-163.5605"
y="-223.5605"
style="font-size:14px">imgY</tspan></text>
<rect
y="108.29912"
@ -350,10 +407,10 @@
height="230.92076"
width="273.14529"
id="rect6028"
style="fill:#aaaaaa;fill-opacity:1;stroke:none" />
style="fill:#ffffff;fill-opacity:1;stroke:none" />
<path
style="fill:none;stroke:#00d500;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow1Lend-0);marker-end:url(#Arrow1Lstart)"
d="m -1.7638416,-138.20953 348.7074816,0"
style="fill:none;stroke:#00d500;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow1Lstart);marker-end:url(#Arrow1Lend)"
d="m 1.7050376,-138.20953 342.7697224,0"
id="path6030"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
@ -377,19 +434,19 @@
style="font-size:14px">xpos</tspan></text>
<path
sodipodi:nodetypes="cc"
style="fill:#0101ff;fill-opacity:1;stroke:#00d500;stroke-width:0.99999988px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:none;marker-end:none"
d="m 345.91779,42.117984 0,-189.631354"
style="fill:#0101ff;fill-opacity:1;stroke:#00d500;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:none;marker-end:none"
d="m 345.91781,104.11799 0,-251.63137"
id="path6038"
inkscape:connector-curvature="0" />
<path
sodipodi:nodetypes="cc"
style="fill:#0000ff;fill-opacity:1;stroke:#00d500;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow1Lend-0);marker-end:url(#Arrow1Lstart)"
d="m -43.14286,115.27439 0,-121.8534376"
style="fill:#0000ff;fill-opacity:1;stroke:#00d500;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#Arrow1Lstart);marker-end:url(#Arrow1Lend)"
d="m -43.14286,106.70337 0,-104.461397"
id="path6040"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#00d500;stroke-width:0.99999988px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 279.23572,108.93361 -341.400037,0"
style="fill:none;stroke:#00d500;stroke-width:0.99999982px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 335.23571,108.9336 -397.400024,0"
id="path6042"
inkscape:connector-curvature="0" />
<text
@ -408,43 +465,37 @@
y="-61.683151"
style="font-size:14px">ypos</tspan></text>
<path
style="fill:none;stroke:#0000ff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow1Lend-0);marker-end:url(#Arrow1Lstart)"
d="m 343.23616,54.290469 13.70748,0"
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow1Lend-0);marker-end:url(#Arrow1Lstart)"
d="m 343.23616,-45.709531 13.70748,0"
id="path6048"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
inkscape:connector-curvature="0"
id="path6050"
d="m 345.85714,103.75231 0,-60.735258"
style="fill:#0000ff;fill-opacity:1;stroke:#0000ff;stroke-width:0.99999988px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:none;marker-end:none"
sodipodi:nodetypes="cc" />
<text
sodipodi:linespacing="125%"
id="text6052"
y="34.583218"
x="349.59616"
style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#0000ff;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
y="-54.916779"
x="379.59616"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:125%;font-family:Sans;-inkscape-font-specification:Sans;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
xml:space="preserve"><tspan
y="34.583218"
x="349.59616"
y="-54.916779"
x="379.59616"
id="tspan6054"
sodipodi:role="line">imgX</tspan></text>
sodipodi:role="line">imgAreaX</tspan></text>
<path
sodipodi:nodetypes="cc"
style="fill:#0000ff;fill-opacity:1;stroke:#0101ff;stroke-width:0.99999982px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:none;marker-end:none"
d="m 353.85714,146.29539 0,-102.821417"
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.99999976px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:none;marker-end:none"
d="m 353.85713,146.29539 0,-204.821419"
id="path6056"
inkscape:connector-curvature="0" />
<path
sodipodi:nodetypes="cc"
style="fill:#0000ff;fill-opacity:1;stroke:#0000ff;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow1Lend-0);marker-end:url(#Arrow1Lstart)"
d="m 294.39329,156.93092 0,-59.258382"
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow1Lend-0);marker-end:url(#Arrow1Lstart)"
d="m 294.39329,159.35722 0,-50.11098"
id="path6058"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#0000ff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 345.95545,156.93361 -59.83945,0"
style="fill:none;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 345.95544,156.9336 -129.84302,0"
id="path6060"
inkscape:connector-curvature="0" />
<path
@ -455,25 +506,20 @@
sodipodi:cy="287.11218"
sodipodi:cx="15.25"
id="path6062"
style="fill:#0000ff;fill-opacity:1;stroke:none"
style="fill:#000000;fill-opacity:1;stroke:none"
sodipodi:type="arc" />
<text
transform="matrix(0,-1,1,0,0,0)"
sodipodi:linespacing="125%"
id="text6064"
y="280.43951"
x="-147.26872"
style="font-size:14px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#0000ff;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
y="283.43951"
x="-88.268723"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:125%;font-family:Sans;-inkscape-font-specification:Sans;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
xml:space="preserve"><tspan
y="280.43951"
x="-147.26872"
y="283.43951"
x="-88.268723"
id="tspan6066"
sodipodi:role="line">imgY</tspan></text>
<path
inkscape:connector-curvature="0"
id="path6068"
d="m 337.95545,108.93361 -59.83945,0"
style="fill:none;stroke:#0000ff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
sodipodi:role="line">imgAreaY</tspan></text>
<rect
y="132.46352"
x="330.78668"
@ -501,25 +547,336 @@
y="31.362183" /></text>
<text
xml:space="preserve"
style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
x="479.60809"
y="-14.880458"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:125%;font-family:Sans;-inkscape-font-specification:Sans;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
x="10.089189"
y="-4.9809637"
id="text6082"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan6084"
x="479.60809"
y="-14.880458">CropWindow (mainCropWindow)</tspan></text>
x="10.089189"
y="-4.9809637">CropWindow (mainCropWindow)</tspan></text>
<text
sodipodi:linespacing="125%"
id="text6086"
y="100.36218"
x="532"
style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans"
y="103.7764"
x="432.70352"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:16px;line-height:125%;font-family:Sans;-inkscape-font-specification:Sans;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
xml:space="preserve"><tspan
y="100.36218"
x="532"
y="103.7764"
x="432.70352"
id="tspan6088"
sodipodi:role="line">CropWindow</tspan></text>
sodipodi:role="line">CropWindow (detail)</tspan></text>
<text
inkscape:transform-center-y="-8"
inkscape:transform-center-x="8.5"
sodipodi:linespacing="125%"
id="text4240"
y="425.70987"
x="1114.1865"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:125%;font-family:Sans;-inkscape-font-specification:Sans;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
xml:space="preserve"><tspan
y="425.70987"
x="1114.1865"
id="tspan4242"
sodipodi:role="line">Scaled full image</tspan></text>
<rect
style="fill:none;stroke:#969696;stroke-width:1.99999988;stroke-miterlimit:4;stroke-dasharray:3.99999995, 3.99999994999999990;stroke-dashoffset:0;stroke-opacity:1"
id="rect4244"
width="1065.0957"
height="715.3504"
x="-159.29646"
y="177.4635" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:125%;font-family:Sans;-inkscape-font-specification:Sans;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none"
x="1113.7354"
y="494.30157"
id="text4246"
sodipodi:linespacing="125%"
inkscape:transform-center-x="8.5"
inkscape:transform-center-y="-8"><tspan
sodipodi:role="line"
id="tspan4248"
x="1113.7354"
y="494.30157">Editing canvas = Full image + padding, Scaled</tspan></text>
<path
style="fill:none;fill-rule:evenodd;stroke:#969696;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;marker-start:url(#Arrow1Lstart);marker-end:url(#Arrow1Lend);fill-opacity:1"
d="m 816,653.36218 89,0"
id="path4250"
inkscape:connector-curvature="0" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:14px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#969696;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="954"
y="641.36218"
id="text4608"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4610"
x="954"
y="641.36218">cropHandler.getCrop()-&gt;getPadding()</tspan></text>
<path
inkscape:connector-curvature="0"
id="path4624"
d="m 895.99996,653.36208 319.00004,0"
style="fill:none;fill-rule:evenodd;stroke:#969696;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<rect
style="fill:none;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:4,4;stroke-dashoffset:0;stroke-opacity:1"
id="rect4790"
width="82.92926"
height="44.350399"
x="1010.7867"
y="400.4635" />
<rect
y="468.4635"
x="1010.7867"
height="44.350399"
width="82.92926"
id="rect4792"
style="fill:none;stroke:#969696;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:4, 4;stroke-dashoffset:0;stroke-opacity:1" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="-69.296463"
y="-255.78535"
id="text4794"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4796"
x="-69.296463"
y="-255.78535"
style="font-size:35px">CropWindow class, geometry explained</tspan></text>
<rect
style="fill:#aaaaaa;fill-opacity:1;stroke:none"
id="rect4278"
width="222.23361"
height="185.66592"
x="404.46506"
y="201.20769" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path4280"
d="m 353.46717,64.290469 49.74544,0"
style="fill:none;stroke:#0000ff;stroke-width:0.99999988px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow1Lstart);marker-end:url(#Arrow1Lend)" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:125%;font-family:Sans;-inkscape-font-specification:Sans;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#0000ff;fill-opacity:1;stroke:none"
x="361.09616"
y="46.083218"
id="text4282"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4284"
x="361.09616"
y="46.083218">imgX</tspan></text>
<path
inkscape:connector-curvature="0"
id="path4286"
d="m 403.85714,190.29539 0,-135.321416"
style="fill:#0000ff;fill-opacity:1;stroke:#0101ff;stroke-width:1.51763952px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:none;marker-end:none"
sodipodi:nodetypes="cc" />
<circle
style="fill:#0000ff;fill-opacity:1;stroke:none"
id="path4288"
cx="403.75"
cy="202.61218"
r="3.75" />
<path
inkscape:connector-curvature="0"
id="path4290"
d="m 230.39329,198.88275 0,-41.0199"
style="fill:#0000ff;fill-opacity:1;stroke:#0000ff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow1Lstart);marker-end:url(#Arrow1Lend)"
sodipodi:nodetypes="cc" />
<path
inkscape:connector-curvature="0"
id="path4292"
d="m 393.95546,200.93361 -171.83946,0"
style="fill:none;stroke:#0000ff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:125%;font-family:Sans;-inkscape-font-specification:Sans;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#0000ff;fill-opacity:1;stroke:none"
x="-191.26872"
y="216.43951"
id="text4294"
sodipodi:linespacing="125%"
transform="matrix(0,-1,1,0,0,0)"><tspan
sodipodi:role="line"
id="tspan4296"
x="-191.26872"
y="216.43951">imgY</tspan></text>
<text
sodipodi:linespacing="125%"
id="text4298"
y="459.92047"
x="524.4317"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:125%;font-family:Sans;-inkscape-font-specification:Sans;text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none"
xml:space="preserve"><tspan
y="459.92047"
x="524.4317"
id="tspan4300"
sodipodi:role="line">imgAreaW</tspan></text>
<text
transform="matrix(0,-1,1,0,0,0)"
sodipodi:linespacing="125%"
id="text4302"
y="697.78394"
x="-287.88525"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:125%;font-family:Sans;-inkscape-font-specification:Sans;text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none"
xml:space="preserve"><tspan
y="697.78394"
x="-287.88525"
id="tspan4304"
sodipodi:role="line">imgAreaH</tspan></text>
<path
inkscape:connector-curvature="0"
id="path4306"
d="m 355.1635,467.67688 c 188.54914,0 270.02102,0 270.02102,0"
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow1Lstart);marker-end:url(#Arrow1Lend)" />
<path
inkscape:connector-curvature="0"
id="path4308"
d="m 704.64487,158.81238 0,225.11483"
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow1Lstart);marker-end:url(#Arrow1Lend)" />
<circle
style="fill:#000000;fill-opacity:1;stroke:none"
id="path4312"
cx="626.75"
cy="386.36218"
r="3.75" />
<path
inkscape:connector-curvature="0"
id="path4314"
d="m 353.85715,478.86394 0,-91.88996"
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.99999982px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:none;marker-end:none"
sodipodi:nodetypes="cc" />
<path
sodipodi:nodetypes="cc"
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.99999976px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:none;marker-end:none"
d="m 626.85715,478.36394 0,-81.38996"
id="path4316"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path4318"
d="m 715.55213,386.66896 -81.38996,0"
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.99999976px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:none;marker-end:none"
sodipodi:nodetypes="cc" />
<path
inkscape:connector-curvature="0"
id="path4320"
d="m 717.45546,156.93361 -85.33945,0"
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
style="fill:none;stroke:#0000ff;stroke-width:0.99999988px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow1Lstart);marker-end:url(#Arrow1Lend)"
d="m 403.45131,64.290469 222.64262,0"
id="path4322"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<text
sodipodi:linespacing="125%"
id="text4324"
y="46.583218"
x="489.59619"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:125%;font-family:Sans;-inkscape-font-specification:Sans;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#0000ff;fill-opacity:1;stroke:none"
xml:space="preserve"><tspan
y="46.583218"
x="489.59619"
id="tspan4326"
sodipodi:role="line">imgW</tspan></text>
<path
sodipodi:nodetypes="cc"
style="fill:#0000ff;fill-opacity:1;stroke:#0101ff;stroke-width:1.51763952px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:none;marker-end:none"
d="m 625.85714,196.00755 0,-138.533577"
id="path4328"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path4456"
d="m 294.35713,100.29539 0,-75.82142"
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.99999976px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:none;marker-end:none"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 447.45546,-45.56639 -85.33945,0"
id="path4458"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path4460"
d="m 744.85715,1133.3639 0,-72.3899"
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.99999976px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:none;marker-end:none"
sodipodi:nodetypes="cc" />
<path
sodipodi:nodetypes="cc"
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.99999982px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:none;marker-end:none"
d="m 961.41712,1052.669 -207.25496,0"
id="path4462"
inkscape:connector-curvature="0" />
<path
sodipodi:nodetypes="cc"
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.99999976px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:none;marker-end:none"
d="m 0.85715,1133.3639 0,-72.3899"
id="path4464"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path4466"
d="m 940.64485,643.28784 0,-641.8377393"
style="fill:none;stroke:#000000;stroke-width:0.99999988px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Lend)" />
<path
inkscape:connector-curvature="0"
id="path4468"
d="m 961.41712,0.669 -207.25496,0"
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.99999982px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:none;marker-end:none"
sodipodi:nodetypes="cc" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path4470"
d="m 345.75602,-138.20953 290.99366,0"
style="fill:none;stroke:#00d500;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow1Lstart);marker-end:url(#Arrow1Lend)" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12px;line-height:125%;font-family:Sans;-inkscape-font-specification:Sans;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#00d500;fill-opacity:1;stroke:none"
x="476.66547"
y="-156.65942"
id="text4472"
sodipodi:linespacing="125%"><tspan
style="font-size:14px"
sodipodi:role="line"
id="tspan4474"
x="476.66547"
y="-156.65942">width</tspan></text>
<path
inkscape:connector-curvature="0"
id="path4476"
d="m 637.91781,104.11799 0,-251.63137"
style="fill:#0101ff;fill-opacity:1;stroke:#00d500;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:none;marker-end:none"
sodipodi:nodetypes="cc" />
<path
sodipodi:nodetypes="cc"
style="fill:#0000ff;fill-opacity:1;stroke:#0000ff;stroke-width:0.99999988px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow1Lstart);marker-end:url(#Arrow1Lend)"
d="m 230.39328,385.66718 0,-183.38169"
id="path4478"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#0000ff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 393.95546,386.93361 -171.83946,0"
id="path4480"
inkscape:connector-curvature="0" />
<text
transform="matrix(0,-1,1,0,0,0)"
sodipodi:linespacing="125%"
id="text4482"
y="216.43951"
x="-337.26874"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:125%;font-family:Sans;-inkscape-font-specification:Sans;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#0000ff;fill-opacity:1;stroke:none"
xml:space="preserve"><tspan
y="216.43951"
x="-337.26874"
id="tspan4484"
sodipodi:role="line">height</tspan></text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 40 KiB