diff --git a/rtengine/CMakeLists.txt b/rtengine/CMakeLists.txt index bf9ec442b..682d6ff3f 100644 --- a/rtengine/CMakeLists.txt +++ b/rtengine/CMakeLists.txt @@ -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 diff --git a/rtengine/coord.h b/rtengine/coord.h index 0b134ce21..359fb3a96 100644 --- a/rtengine/coord.h +++ b/rtengine/coord.h @@ -187,23 +187,23 @@ public: { radius *= scale; } - PolarCoord operator+(PolarCoord & rhs) + PolarCoord operator+ (const PolarCoord& rhs) const { + PolarCoord result; Coord thisCoord, rhsCoord; thisCoord.setFromPolar(*this); rhsCoord.setFromPolar(rhs); thisCoord += rhsCoord; - PolarCoord result; result.setFromCartesian(thisCoord); return result; } - PolarCoord operator-(PolarCoord & rhs) + PolarCoord operator- (const PolarCoord& rhs) const { + PolarCoord result; Coord thisCoord, rhsCoord; thisCoord.setFromPolar(*this); rhsCoord.setFromPolar(rhs); thisCoord -= rhsCoord; - PolarCoord result; result.setFromCartesian(thisCoord); return result; } diff --git a/rtengine/curves.h b/rtengine/curves.h index e55d7bc2a..fffd7dcb7 100644 --- a/rtengine/curves.h +++ b/rtengine/curves.h @@ -28,7 +28,7 @@ #include "../rtgui/mydiagonalcurve.h" #include "color.h" #include "procparams.h" -#include "editbuffer.h" +#include "pipettebuffer.h" #include "LUT.h" diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index 2220f68c5..89e39c1da 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -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,13 @@ 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; + if (const auto editProvider = PipetteBuffer::getDataProvider ()) { + if (const auto editSubscriber = editProvider->getCurrSubscriber ()) { + editType = editSubscriber->getEditingType (); + } + } + if (cw != cropw || ch != croph || orW != trafw || orH != trafh) { cropw = cw; @@ -1223,7 +1223,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; diff --git a/rtengine/dcrop.h b/rtengine/dcrop.h index 57f388a51..f1230bf01 100644 --- a/rtengine/dcrop.h +++ b/rtengine/dcrop.h @@ -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 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; diff --git a/rtengine/demosaic_algos.cc b/rtengine/demosaic_algos.cc index 5f5e07139..f8036f24e 100644 --- a/rtengine/demosaic_algos.cc +++ b/rtengine/demosaic_algos.cc @@ -3910,7 +3910,7 @@ void RawImageSource::cielab (const float (*rgb)[3], float* l, float* a, float *b for(int i = 0; i < height; i++) { for(int j = 0; j < labWidth; j++) { - float xyz[3] = {0.5f}; + float xyz[3] = {0.5f, 0.5f, 0.5f}; int c; FORC3 { xyz[0] += xyz_cam[0][c] * rgb[i * width + j][c]; diff --git a/rtengine/helpersse2.h b/rtengine/helpersse2.h index 3e4365e99..d4290bacc 100644 --- a/rtengine/helpersse2.h +++ b/rtengine/helpersse2.h @@ -21,12 +21,12 @@ typedef __m128i vint2; // #ifdef __GNUC__ -#if (__GNUC__ == 4 && __GNUC_MINOR__ >= 9) || __GNUC__ > 4 +#if ((__GNUC__ == 4 && __GNUC_MINOR__ >= 9) || __GNUC__ > 4) && (!defined(WIN32) || defined( __x86_64__ )) #define LVF(x) _mm_load_ps(&x) #define LVFU(x) _mm_loadu_ps(&x) #define STVF(x,y) _mm_store_ps(&x,y) #define STVFU(x,y) _mm_storeu_ps(&x,y) -#else // there is a bug in gcc 4.7.x when using openmp and aligned memory and -O3 +#else // there is a bug in gcc 4.7.x when using openmp and aligned memory and -O3, also need to map the aligned functions to unaligned functions for WIN32 builds #define LVF(x) _mm_loadu_ps(&x) #define LVFU(x) _mm_loadu_ps(&x) #define STVF(x,y) _mm_storeu_ps(&x,y) diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index b1f47c3a9..468abbe13 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -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* 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; } } diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index 44224fa2e..996f91c58 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -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); diff --git a/rtengine/ipsharpen.cc b/rtengine/ipsharpen.cc index a3d624b65..279b77762 100644 --- a/rtengine/ipsharpen.cc +++ b/rtengine/ipsharpen.cc @@ -170,7 +170,6 @@ void ImProcFunctions::sharpening (LabImage* lab, float** b2, SharpeningParams &s // Rest is UNSHARP MASK int W = lab->W, H = lab->H; float** b3 = nullptr; - float** labCopy = nullptr; if (sharpenParam.edgesonly) { b3 = new float*[H]; @@ -180,15 +179,6 @@ void ImProcFunctions::sharpening (LabImage* lab, float** b2, SharpeningParams &s } } - if (sharpenParam.halocontrol && !sharpenParam.edgesonly) { - // We only need the lab channel copy in this special case - labCopy = new float*[H]; - - for( int i = 0; i < H; i++ ) { - labCopy[i] = new float[W]; - } - } - #ifdef _OPENMP #pragma omp parallel #endif @@ -200,55 +190,60 @@ void ImProcFunctions::sharpening (LabImage* lab, float** b2, SharpeningParams &s bilateral (lab->L, (float**)b3, b2, W, H, sharpenParam.edges_radius / scale, sharpenParam.edges_tolerance, multiThread); gaussianBlur (b3, b2, W, H, sharpenParam.radius / scale); } + } + float** base = lab->L; - float** base = lab->L; + if (sharpenParam.edgesonly) { + base = b3; + } - if (sharpenParam.edgesonly) { - base = b3; - } - - if (sharpenParam.halocontrol == false) { + if (!sharpenParam.halocontrol) { #ifdef _OPENMP - #pragma omp for + #pragma omp parallel for #endif - for (int i = 0; i < H; i++) - for (int j = 0; j < W; j++) { - const float upperBound = 2000.f; // WARNING: Duplicated value, it's baaaaaad ! - float diff = base[i][j] - b2[i][j]; - float delta = sharpenParam.threshold.multiply( - min(ABS(diff), upperBound), // X axis value = absolute value of the difference, truncated to the max value of this field - sharpenParam.amount * diff * 0.01f // Y axis max value - ); - lab->L[i][j] = lab->L[i][j] + delta; - } - } else { - if (!sharpenParam.edgesonly) { - // make a deep copy of lab->L -#ifdef _OPENMP - #pragma omp for -#endif + for (int i = 0; i < H; i++) + for (int j = 0; j < W; j++) { + const float upperBound = 2000.f; // WARNING: Duplicated value, it's baaaaaad ! + float diff = base[i][j] - b2[i][j]; + float delta = sharpenParam.threshold.multiply( + min(ABS(diff), upperBound), // X axis value = absolute value of the difference, truncated to the max value of this field + sharpenParam.amount * diff * 0.01f // Y axis max value + ); + lab->L[i][j] = lab->L[i][j] + delta; + } + } else { + float** labCopy = nullptr; - for( int i = 0; i < H; i++ ) - for( int j = 0; j < W; j++ ) { - labCopy[i][j] = lab->L[i][j]; - } + if (!sharpenParam.edgesonly) { + // make a deep copy of lab->L + labCopy = new float*[H]; - base = labCopy; + for( int i = 0; i < H; i++ ) { + labCopy[i] = new float[W]; } - sharpenHaloCtrl (lab->L, b2, base, W, H, sharpenParam); +#ifdef _OPENMP + #pragma omp parallel for +#endif + + for( int i = 0; i < H; i++ ) + for( int j = 0; j < W; j++ ) { + labCopy[i][j] = lab->L[i][j]; + } + + base = labCopy; } - } // end parallel + sharpenHaloCtrl (lab->L, b2, base, W, H, sharpenParam); - if (sharpenParam.halocontrol && !sharpenParam.edgesonly) { - // delete the deep copy - for( int i = 0; i < H; i++ ) { - delete[] labCopy[i]; + if (labCopy) { + for( int i = 0; i < H; i++ ) { + delete[] labCopy[i]; + } + + delete[] labCopy; } - - delete[] labCopy; } if (sharpenParam.edgesonly) { @@ -268,7 +263,7 @@ void ImProcFunctions::sharpenHaloCtrl (float** luminance, float** blurmap, float float** nL = base; #ifdef _OPENMP - #pragma omp for + #pragma omp parallel for #endif for (int i = 2; i < H - 2; i++) { @@ -940,7 +935,6 @@ void ImProcFunctions::sharpeningcam (CieImage* ncie, float** b2) int W = ncie->W, H = ncie->H; float** b3; - float** ncieCopy; if (params->sharpening.edgesonly) { b3 = new float*[H]; @@ -950,15 +944,6 @@ void ImProcFunctions::sharpeningcam (CieImage* ncie, float** b2) } } - if (params->sharpening.halocontrol && !params->sharpening.edgesonly) { - // We only need the lab parameter copy in this special case - ncieCopy = new float*[H]; - - for( int i = 0; i < H; i++ ) { - ncieCopy[i] = new float[W]; - } - } - #ifdef _OPENMP #pragma omp parallel #endif @@ -970,58 +955,64 @@ void ImProcFunctions::sharpeningcam (CieImage* ncie, float** b2) bilateral (ncie->sh_p, (float**)b3, b2, W, H, params->sharpening.edges_radius / scale, params->sharpening.edges_tolerance, multiThread); gaussianBlur (b3, b2, W, H, params->sharpening.radius / scale); } + } - float** base = ncie->sh_p; + float** base = ncie->sh_p; - if (params->sharpening.edgesonly) { - base = b3; - } + if (params->sharpening.edgesonly) { + base = b3; + } - if (params->sharpening.halocontrol == false) { + if (!params->sharpening.halocontrol) { #ifdef _OPENMP - #pragma omp for + #pragma omp parallel for #endif - for (int i = 0; i < H; i++) - for (int j = 0; j < W; j++) { - const float upperBound = 2000.f; // WARNING: Duplicated value, it's baaaaaad ! - float diff = base[i][j] - b2[i][j]; - float delta = params->sharpening.threshold.multiply( - min(ABS(diff), upperBound), // X axis value = absolute value of the difference, truncated to the max value of this field - params->sharpening.amount * diff * 0.01f // Y axis max value - ); + for (int i = 0; i < H; i++) + for (int j = 0; j < W; j++) { + const float upperBound = 2000.f; // WARNING: Duplicated value, it's baaaaaad ! + float diff = base[i][j] - b2[i][j]; + float delta = params->sharpening.threshold.multiply( + min(ABS(diff), upperBound), // X axis value = absolute value of the difference, truncated to the max value of this field + params->sharpening.amount * diff * 0.01f // Y axis max value + ); - if(ncie->J_p[i][j] > 8.0f && ncie->J_p[i][j] < 92.0f) { - ncie->sh_p[i][j] = ncie->sh_p[i][j] + delta; - } + if(ncie->J_p[i][j] > 8.0f && ncie->J_p[i][j] < 92.0f) { + ncie->sh_p[i][j] = ncie->sh_p[i][j] + delta; } - } else { - if (!params->sharpening.edgesonly) { - // make a deep copy of lab->L -#ifdef _OPENMP - #pragma omp for -#endif + } + } else { + float** ncieCopy = nullptr; - for( int i = 0; i < H; i++ ) - for( int j = 0; j < W; j++ ) { - ncieCopy[i][j] = ncie->sh_p[i][j]; - } + if (!params->sharpening.edgesonly) { + // make deep copy of ncie->sh_p + ncieCopy = new float*[H]; - base = ncieCopy; + for( int i = 0; i < H; i++ ) { + ncieCopy[i] = new float[W]; } - sharpenHaloCtrl (ncie->sh_p, b2, base, W, H, params->sharpening); +#ifdef _OPENMP + #pragma omp parallel for +#endif + + for( int i = 0; i < H; i++ ) + for( int j = 0; j < W; j++ ) { + ncieCopy[i][j] = ncie->sh_p[i][j]; + } + + base = ncieCopy; } - } // end parallel + sharpenHaloCtrl (ncie->sh_p, b2, base, W, H, params->sharpening); - if (params->sharpening.halocontrol && !params->sharpening.edgesonly) { - // delete the deep copy - for( int i = 0; i < H; i++ ) { - delete[] ncieCopy[i]; + if(ncieCopy) { + for( int i = 0; i < H; i++ ) { + delete[] ncieCopy[i]; + } + + delete[] ncieCopy; } - - delete[] ncieCopy; } if (params->sharpening.edgesonly) { diff --git a/rtengine/opthelper.h b/rtengine/opthelper.h index fc49ad12e..555ea587c 100644 --- a/rtengine/opthelper.h +++ b/rtengine/opthelper.h @@ -55,10 +55,10 @@ #define RESTRICT __restrict__ #define LIKELY(x) __builtin_expect (!!(x), 1) #define UNLIKELY(x) __builtin_expect (!!(x), 0) - #if (__GNUC__ == 4 && __GNUC_MINOR__ >= 9) || __GNUC__ > 4 + #if ((__GNUC__ == 4 && __GNUC_MINOR__ >= 9) || __GNUC__ > 4) && (!defined(WIN32) || defined( __x86_64__ )) #define ALIGNED64 __attribute__ ((aligned (64))) #define ALIGNED16 __attribute__ ((aligned (16))) - #else // there is a bug in gcc 4.7.x when using openmp and aligned memory and -O3 + #else // there is a bug in gcc 4.7.x when using openmp and aligned memory and -O3, also needed for WIN32 builds #define ALIGNED64 #define ALIGNED16 #endif diff --git a/rtengine/editbuffer.cc b/rtengine/pipettebuffer.cc similarity index 50% rename from rtengine/editbuffer.cc rename to rtengine/pipettebuffer.cc index caf657070..d76589e99 100644 --- a/rtengine/editbuffer.cc +++ b/rtengine/pipettebuffer.cc @@ -17,16 +17,15 @@ * along with RawTherapee. If not, see . */ -#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); diff --git a/rtengine/editbuffer.h b/rtengine/pipettebuffer.h similarity index 57% rename from rtengine/editbuffer.h rename to rtengine/pipettebuffer.h index 1a55a39ed..e6db8eb68 100644 --- a/rtengine/editbuffer.h +++ b/rtengine/pipettebuffer.h @@ -16,8 +16,8 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ -#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 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 objectMap2; - ObjectMode objectMode; - protected: // To avoid duplicated information, we points to a EditDataProvider that contains the current EditSubscriber @@ -52,39 +44,38 @@ protected: bool ready; // flag that indicates if the _pipette_ buffer is ready - void createBuffer(int width, int height); - void resize(int newWidth, int newHeight, EditSubscriber* newSubscriber); - void resize(int newWidth, int newHeight); - void flush(); + void createBuffer(int width, int height); + void resize(int newWidth, int newHeight, EditSubscriber* newSubscriber); + void resize(int newWidth, int newHeight); + void flush(); public: - EditBuffer(::EditDataProvider *dataProvider); - ~EditBuffer(); + PipetteBuffer(::EditDataProvider *dataProvider); + ~PipetteBuffer(); /** @brief Getter to know if the pipette buffer is correctly filled */ - bool isReady() + bool isReady() { return ready; } /** @brief Setter to tell that the pipette buffer is correctly filled * You have to use this method once the pipette is filled, so it can be read. */ - void setReady() + void setReady() { ready = true; } - void setObjectMode(ObjectMode newType); - ::EditDataProvider* getDataProvider() + ::EditDataProvider* getDataProvider() { return dataProvider; } - EditUniqueID getEditID(); - Imagefloat* getImgFloatBuffer() + EditUniqueID getEditID(); + Imagefloat* getImgFloatBuffer() { return imgFloatBuffer; } - LabImage* getLabBuffer() + LabImage* getLabBuffer() { return LabBuffer; } @@ -92,26 +83,12 @@ public: { return &singlePlaneBuffer; } - ObjectMode getObjectMode() - { - return objectMode; - } - - Cairo::RefPtr &getObjectMap () - { - return objectMap; - } - Cairo::RefPtr &getObjectMap2() - { - return objectMap2; - } // return true if the buffer has been allocated - bool bufferCreated(); + bool bufferCreated(); - int getObjectID(const Coord& location); // get the pipette values - void getPipetteData(float* v, int x, int y, int squareSize); + void getPipetteData(float* v, int x, int y, int squareSize); }; } diff --git a/rtengine/rawimage.cc b/rtengine/rawimage.cc index 89731992a..040d0276b 100644 --- a/rtengine/rawimage.cc +++ b/rtengine/rawimage.cc @@ -88,17 +88,17 @@ void RawImage::get_colorsCoeff( float *pre_mul_, float *scale_mul_, float *cblac float val; double dsum[8], dmin, dmax; - if ((this->get_cblack(4) + 1) / 2 == 1 && (this->get_cblack(5) + 1) / 2 == 1) { - for (int c = 0; c < 4; c++) { - cblack_[FC(c / 2, c % 2)] = this->get_cblack(6 + c / 2 % this->get_cblack(4) * this->get_cblack(5) + c % 2 % this->get_cblack(5)); - pre_mul_[c] = this->get_pre_mul(c); - } - } else if(isXtrans()) { + if(isXtrans()) { // for xtrans files dcraw stores black levels in cblack[6] .. cblack[41], but all are equal, so we just use cblack[6] for (int c = 0; c < 4; c++) { cblack_[c] = (float) this->get_cblack(6); pre_mul_[c] = this->get_pre_mul(c); } + } else if ((this->get_cblack(4) + 1) / 2 == 1 && (this->get_cblack(5) + 1) / 2 == 1) { + for (int c = 0; c < 4; c++) { + cblack_[FC(c / 2, c % 2)] = this->get_cblack(6 + c / 2 % this->get_cblack(4) * this->get_cblack(5) + c % 2 % this->get_cblack(5)); + pre_mul_[c] = this->get_pre_mul(c); + } } else { for (int c = 0; c < 4; c++) { cblack_[c] = (float) this->get_cblack(c); diff --git a/rtengine/rt_math.h b/rtengine/rt_math.h index 44c29fd97..898f1397c 100644 --- a/rtengine/rt_math.h +++ b/rtengine/rt_math.h @@ -80,7 +80,8 @@ inline const _Tp& max(const _Tp& a, const _Tp& b, const _Tp& c, const _Tp& d) } template -inline const _Tp intp(const _Tp a, const _Tp b, const _Tp c) { +inline const _Tp intp(const _Tp a, const _Tp b, const _Tp c) +{ // calculate a * b + (1 - a) * c // following is valid: // intp(a, b+x, c+x) = intp(a, b, c) + x @@ -88,5 +89,23 @@ inline const _Tp intp(const _Tp a, const _Tp b, const _Tp c) { return a * (b-c) + c; } +template +T norm1(const T& x, const T& y) +{ + return std::abs(x) + std::abs(y); +} + +template +T norm2(const T& x, const T& y) +{ + return std::sqrt(x * x + y * y); +} + +template< typename T > +T norminf(const T& x, const T& y) +{ + return std::max(std::abs(x), std::abs(y)); +} + } #endif diff --git a/rtgui/crophandler.cc b/rtgui/crophandler.cc index 1253407bc..4d20dabd1 100644 --- a/rtgui/crophandler.cc +++ b/rtgui/crophandler.cc @@ -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(listener) : NULL; + CropWindow *cropWin = displayHandler ? static_cast(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 (); @@ -278,11 +332,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; } } @@ -363,7 +417,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 (); @@ -426,41 +480,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; -void CropHandler::cutRectToImgBounds (int& x, int& y, int& w, int& h) -{ + cax = rtengine::LIM(cax, 0, fullW-1); + cay = rtengine::LIM(cay, 0, fullH-1); - if (ipc) { - if (w > ipc->getFullWidth()) { - w = ipc->getFullWidth(); - } - - if (h > ipc->getFullHeight()) { - h = ipc->getFullHeight(); - } - - if (x < 0) { - x = 0; - } - - if (y < 0) { - y = 0; - } - - if (x + w >= ipc->getFullWidth()) { - x = ipc->getFullWidth() - w; - } - - if (y + h >= ipc->getFullHeight()) { - y = ipc->getFullHeight() - h; - } + 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; } + + imgX = ww / 2 - scaledCAX; + if (imgX < 0) { + imgX = 0; + } + imgY = wh / 2 - scaledCAY; + if (imgY < 0) { + imgY = 0; + } + + cropX = cax - (wwImgSpace/2); + cropY = cay - (whImgSpace/2); + cropW = wwImgSpace; + cropH = whImgSpace; + + if (cropX + cropW > fullW) { + cropW = fullW - cropX; + } + + if (cropY + cropH > fullH) { + cropH = fullH - cropY; + } + + if (cropX < 0) { + cropW += cropX; + cropX = 0; + } + + if (cropY < 0) { + cropH += cropY; + cropY = 0; + } + + // 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); } diff --git a/rtgui/crophandler.h b/rtgui/crophandler.h index 60d7956ca..6e479bb16 100644 --- a/rtgui/crophandler.h +++ b/rtgui/crophandler.h @@ -24,14 +24,15 @@ #include "edit.h" #include -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 diff --git a/rtgui/cropwindow.cc b/rtgui/cropwindow.cc index bb7204b1d..6b07761f8 100644 --- a/rtgui/cropwindow.cc +++ b/rtgui/cropwindow.cc @@ -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_), cursor_type(CSUndefined), 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 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::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); } } @@ -220,6 +211,7 @@ void CropWindow::setSize (int w, int h, bool norefresh) } if (!norefresh) { + ObjectMOBuffer::resize(imgAreaW, imgAreaH); cropHandler.setWSize (imgAreaW, imgAreaH); } @@ -240,6 +232,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 +290,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 +304,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 +354,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 +382,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 +395,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 +403,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 +429,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 +503,14 @@ void CropWindow::buttonRelease (int button, int num, int bstate, int x, int y) state = SNormal; - for (std::list::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::iterator i = listeners.begin(); i != listeners.end(); i++) { @@ -519,9 +546,9 @@ void CropWindow::buttonRelease (int button, int num, int bstate, int x, int y) iarea->posScreen.set(x, y); Coord cropPos; - screenCoordToCropBuffer(x, y, cropPos.x, cropPos.y); - if (state == SEditDrag1 && 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; @@ -532,8 +559,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 +617,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::iterator i = listeners.begin(); i != listeners.end(); i++) { - (*i)->cropWindowSizeChanged (this); + for (auto listener : listeners) { + listener->cropWindowSizeChanged (this); } iarea->redraw (); @@ -602,11 +631,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::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 +732,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(cropHandler.getCrop()); @@ -710,9 +751,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 +765,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 +889,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 @@ -987,10 +1026,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(cropHandler.getCrop())->getObjectID(cropPos); + screenCoordToCropCanvas (iarea->posScreen.x, iarea->posScreen.y, cropPos.x, cropPos.y); + objectID = ObjectMOBuffer::getObjectID(cropPos); } if (objectID > -1) { @@ -1009,7 +1048,19 @@ void CropWindow::updateCursor (int x, int y) newType = CSStraighten; } } else { - newType = CSArrow; + 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) { + newType = editSubscriber->getCursor(objectID); + } else { + newType = CSArrow; + } } } else if (state == SCropSelecting) { newType = CSCropSelect; @@ -1077,18 +1128,13 @@ void CropWindow::expose (Cairo::RefPtr cr) int cropX, cropY; cropHandler.getPosition (cropX, cropY); - if (state == SCropImgMove) { - cropX += action_x; - cropY += action_y; - } - Glib::RefPtr rough = iarea->getPreviewHandler()->getRoughImage (cropX, cropY, imgAreaW, imgAreaH, zoomSteps[cropZoom].zoom); if (rough) { - int posX = x + imgAreaX + (imgAreaW - rough->get_width()) / 2; - int posY = y + imgAreaY + (imgAreaH - rough->get_height()) / 2; + int posX = x + imgAreaX + imgX; + int posY = y + imgAreaY + imgY; Gdk::Cairo::set_source_pixbuf(cr, rough, posX, posY); - cr->rectangle(posX, posY, rough->get_width(), rough->get_height()); + cr->rectangle(posX, posY, rtengine::min (rough->get_width (), imgAreaW-imgX), rtengine::min (rough->get_height (), imgAreaH-imgY)); cr->fill(); // if (cropHandler.cropParams.enabled) // drawCrop (cr, x+imgX, y+imgY, imgW, imgH, cropX, cropY, zoomSteps[cropZoom].zoom, cropHandler.cropParams); @@ -1101,8 +1147,6 @@ void CropWindow::expose (Cairo::RefPtr 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(); @@ -1252,8 +1296,8 @@ void CropWindow::expose (Cairo::RefPtr 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 @@ -1496,24 +1540,23 @@ void CropWindow::expose (Cairo::RefPtr cr) } } -//printf("zoomSteps[cropZoom].zoom=%d\n",zoomSteps[cropZoom].zoom); - int posX = x + imgX; - int posY = y + imgY; + int posX = x + imgAreaX + imgX; + int posY = y + imgAreaY + imgY; Gdk::Cairo::set_source_pixbuf(cr, tmp, posX, posY); - cr->rectangle(posX, posY, tmp->get_width(), tmp->get_height()); + cr->rectangle(posX, posY, rtengine::min (tmp->get_width (), imgAreaW-imgX), rtengine::min (tmp->get_height (), imgAreaH-imgY)); cr->fill(); } else { - int posX = x + imgX; - int posY = y + imgY; + int posX = x + imgAreaX + imgX; + int posY = y + imgAreaY + imgY; Gdk::Cairo::set_source_pixbuf(cr, cropHandler.cropPixbuf, posX, posY); - cr->rectangle(posX, posY, cropHandler.cropPixbuf->get_width(), cropHandler.cropPixbuf->get_height()); + cr->rectangle(posX, posY, rtengine::min (cropHandler.cropPixbuf->get_width (), imgAreaW-imgX), rtengine::min (cropHandler.cropPixbuf->get_height (), imgAreaH-imgY)); cr->fill(); } 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) { @@ -1521,13 +1564,11 @@ void CropWindow::expose (Cairo::RefPtr cr) } EditSubscriber *editSubscriber = iarea->getCurrSubscriber(); - rtengine::Crop* crop = static_cast(cropHandler.getCrop()); - - if (editSubscriber && crop->bufferCreated()) { + if (editSubscriber && editSubscriber->getEditingType() == ET_OBJECTS && 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(); } @@ -1538,90 +1579,47 @@ void CropWindow::expose (Cairo::RefPtr cr) cr->set_line_join(Cairo::LINE_JOIN_ROUND); // drawing outer lines - for (std::vector::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::const_iterator i = visibleGeom.begin(); i != visibleGeom.end(); ++i) { - (*i)->drawInnerGeometry(cr, crop, *this); + for (auto geom : visibleGeom) { + geom->drawInnerGeometry(cr, this, *this); } + // drawing to the "mouse over" channel + const auto mouseOverGeom = editSubscriber->getMouseOverGeometry(); + if (mouseOverGeom.size()) { + if (mouseOverGeom.size() > 65534) { + // once it has been switched to OM_65535, it won't return back to OM_255 + // to avoid constant memory allocations in some particular situation. + // It will return to OM_255 on a new editing session + setObjectMode(OM_65535); + } + + Cairo::RefPtr 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); + crMO->set_operator(Cairo::OPERATOR_SOURCE); + + // clear the bitmap + crMO->set_source_rgba(0., 0., 0., 0.); + crMO->rectangle(0., 0., ObjectMOBuffer::getObjectMap()->get_width(), ObjectMOBuffer::getObjectMap()->get_height()); + crMO->set_line_width(0.); + crMO->fill(); + + int a=0; + for (auto moGeom : mouseOverGeom) { + moGeom->drawToMOChannel(crMO, a, this, *this); + ++a; + } + } if (this != iarea->mainCropWindow) { cr->reset_clip(); } - // drawing to the "mouse over" channel - if (editSubscriber->getEditingType() == ET_OBJECTS) { - const std::vector mouseOverGeom = editSubscriber->getMouseOverGeometry(); - - if (mouseOverGeom.size()) { - //printf("ObjectMap (%d x %d)\n", crop->getObjectMap()->get_width(), crop->getObjectMap()->get_height()); - Cairo::RefPtr crMO = Cairo::Context::create(crop->getObjectMap()); - crMO->set_antialias(Cairo::ANTIALIAS_NONE); - crMO->set_line_cap(Cairo::LINE_CAP_SQUARE); - crMO->set_line_join(Cairo::LINE_JOIN_ROUND); - crMO->set_operator(Cairo::OPERATOR_SOURCE); - - // clear the bitmap - crMO->set_source_rgba(0., 0., 0., 0.); - crMO->rectangle(0., 0., crop->getObjectMap()->get_width(), crop->getObjectMap()->get_height()); - crMO->set_line_width(0.); - crMO->fill(); - - Cairo::RefPtr crMO2; - - if (crop->getObjectMode() > OM_255) { - crMO2 = Cairo::Context::create(crop->getObjectMap2()); - crMO2->set_antialias(Cairo::ANTIALIAS_NONE); - crMO2->set_line_cap(Cairo::LINE_CAP_SQUARE); - crMO2->set_line_join(Cairo::LINE_JOIN_ROUND); - crMO2->set_operator(Cairo::OPERATOR_SOURCE); - - // clear the bitmap - crMO2->set_source_rgba(0., 0., 0., 0.); - crMO2->rectangle(0., 0., crop->getObjectMap2()->get_width(), crop->getObjectMap2()->get_height()); - crMO2->set_line_width(0.); - crMO2->fill(); - } - - std::vector::const_iterator i; - int a; - - for (a = 0, i = mouseOverGeom.begin(); i != mouseOverGeom.end(); ++i, ++a) { - (*i)->drawToMOChannel(crMO, crMO2, a, crop, *this); - } - - // 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(); - Glib::RefPtr 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; - memcpy(dst, src1, w * h); - - for (int n = 0, n3 = 0; n < w * h;) { - dst[n3++] = src1[n]; - - if (src2) { - dst[n3++] = src2[n]; - } else { - dst[n3++] = 0; - } - - dst[n3++] = 0; - ++n; - } - - img->save(Glib::ustring::compose("mouseOverImage-%1.png", count++), "png"); - } -#endif - } - } } } else { // cropHandler.cropPixbuf is null @@ -1630,18 +1628,18 @@ void CropWindow::expose (Cairo::RefPtr cr) Glib::RefPtr rough = iarea->getPreviewHandler()->getRoughImage (cropX, cropY, imgAreaW, imgAreaH, zoomSteps[cropZoom].zoom); if (rough) { - int posX = x + imgAreaX + (imgAreaW - rough->get_width()) / 2; - int posY = y + imgAreaY + (imgAreaH - rough->get_height()) / 2; + int posX = x + imgAreaX + imgX; + int posY = y + imgAreaY + imgY; Gdk::Cairo::set_source_pixbuf(cr, rough, posX, posY); - cr->rectangle(posX, posY, rough->get_width(), rough->get_height()); + cr->rectangle(posX, posY, rtengine::min (rough->get_width (), imgAreaW-imgX), rtengine::min (rough->get_height (), imgAreaH-imgY)); cr->fill(); 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); } } } @@ -1667,24 +1665,14 @@ void CropWindow::expose (Cairo::RefPtr 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 + if (newSubscriber) { + ObjectMOBuffer::resize (imgAreaW, imgAreaH); + } else { + ObjectMOBuffer::flush (); + } + cropHandler.setEditSubscriber(newSubscriber); } // zoom* is called from the zoomPanel or the scroll wheel in the preview area @@ -1832,7 +1820,7 @@ double CropWindow::getZoomFitVal () } -void CropWindow::zoomFit (bool skipZoomIfUnchanged) +void CropWindow::zoomFit () { double z = cropHandler.getFitZoom (); @@ -1848,7 +1836,7 @@ void CropWindow::zoomFit (bool skipZoomIfUnchanged) } zoomVersion = exposeVersion; - changeZoom (cz, true, -1, -1, skipZoomIfUnchanged); + changeZoom (cz, true, -1, -1); fitZoom = true; } @@ -1871,7 +1859,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; } } @@ -1900,7 +1888,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) { @@ -1909,19 +1897,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::iterator i = listeners.begin(); i != listeners.end(); i++) { - (*i)->cropZoomChanged (this); + for (auto listener : listeners) { + listener->cropZoomChanged (this); } iarea->redraw (); @@ -1931,8 +1914,8 @@ void CropWindow::screenCoordToCropBuffer (int phyx, int phyy, int& cropx, int& c { rtengine::Crop* crop = static_cast(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); @@ -1952,11 +1935,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) @@ -1964,9 +1947,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) @@ -1976,7 +1967,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) @@ -1994,17 +1984,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; } @@ -2139,7 +2129,7 @@ void CropWindow::drawScaledSpotRectangle (Cairo::RefPtr 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); @@ -2161,7 +2151,7 @@ void CropWindow::drawUnscaledSpotRectangle (Cairo::RefPtr 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); @@ -2177,22 +2167,22 @@ void CropWindow::drawUnscaledSpotRectangle (Cairo::RefPtr 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 cr, int rw, int rh) @@ -2232,35 +2222,35 @@ void CropWindow::cropWindowChanged () void CropWindow::initialImageArrived () { - for (std::list::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::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::iterator i = listeners.begin(); i != listeners.end(); i++) { - (*i)->cropPositionChanged (this); + for (auto listener : listeners) { + listener->cropPositionChanged (this); } } diff --git a/rtgui/cropwindow.h b/rtgui/cropwindow.h index 69b3e566a..3434eb52e 100644 --- a/rtgui/cropwindow.h +++ b/rtgui/cropwindow.h @@ -29,6 +29,7 @@ #include "cropguilistener.h" #include "pointermotionlistener.h" #include "cursormanager.h" +#include "edit.h" class CropWindow; class CropWindowListener @@ -43,12 +44,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; + ImgEditState state; // current state of user (see enum State) + int press_x, press_y; // position of the cursor in the GUI space on button press + int action_x, action_y; // parameter that will evolve during a pan or drag action double rot_deg; bool onResizeArea; bool deleted; @@ -87,7 +89,7 @@ class CropWindow : public LWButtonListener, public CropHandlerListener, public E PointerMotionListener* pmhlistener; std::list listeners; - CropWindow* observedCropWin; + CropWindow* observedCropWin; // Pointer to the currently active detail CropWindow rtengine::StagedImageProcessor* ipc; bool onArea (CursorArea a, int x, int y); @@ -97,7 +99,9 @@ class CropWindow : public LWButtonListener, public CropHandlerListener, public E void drawScaledSpotRectangle (Cairo::RefPtr cr, int rectSize); void drawUnscaledSpotRectangle (Cairo::RefPtr cr, int rectSize); void drawObservedFrame (Cairo::RefPtr 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: @@ -119,15 +123,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); @@ -142,14 +147,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); @@ -159,15 +163,20 @@ public: void expose (Cairo::RefPtr cr); + void setEditSubscriber (EditSubscriber* newSubscriber); + // interface lwbuttonlistener void buttonPressed (LWButton* button, int actionCode, void* actionData); void redrawNeeded (LWButton* button); // crop handling - 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 getCropSize (int& w, int& h); + 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) @@ -194,6 +203,7 @@ public: void cropImageUpdated (); void cropWindowChanged (); void initialImageArrived (); + void setDisplayPosition (int x, int y); void remoteMove (int deltaX, int deltaY); void remoteMoveReady (); diff --git a/rtgui/edit.cc b/rtgui/edit.cc index 3efdea7f4..598ee8da5 100644 --- a/rtgui/edit.cc +++ b/rtgui/edit.cc @@ -18,9 +18,115 @@ */ #include "edit.h" -#include "../rtengine/editbuffer.h" #include "rtimage.h" +ObjectMOBuffer::ObjectMOBuffer(EditDataProvider *dataProvider) : objectMap(NULL), objectMode(OM_255), dataProvider(dataProvider) {} + +ObjectMOBuffer::~ObjectMOBuffer() +{ + flush(); +} + + +/* Upgrade or downgrade the objectModeType */ +void ObjectMOBuffer::setObjectMode(ObjectMode newType) +{ + if (!objectMap) { + objectMode = newType; + return; + } + + int w = objectMap->get_width (); + int h = objectMap->get_height (); + if (w && h) { + switch (newType) { + case (OM_255): + if (objectMode==OM_65535) { + objectMap->unreference(); + objectMap = Cairo::ImageSurface::create(Cairo::FORMAT_A8, w, h); + } + break; + + case (OM_65535): + if (objectMode==OM_255) { + objectMap->unreference(); + objectMap = Cairo::ImageSurface::create(Cairo::FORMAT_RGB16_565, w, h); + } + break; + } + } + objectMode = newType; +} + +void ObjectMOBuffer::flush() +{ + if (objectMap ) { + objectMap.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) +{ + if (!dataProvider) { + return; + } + + if (const auto currSubscriber = dataProvider->getCurrSubscriber ()) { + if (currSubscriber->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(objectMode==OM_255?Cairo::FORMAT_A8:Cairo::FORMAT_RGB16_565, newWidth, newHeight); + } + + } 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()) { + return -1; + } + + if (objectMode == OM_255) { + id = (unsigned char)(*( objectMap->get_data() + location.y * objectMap->get_stride() + location.x )); + } else { + id = (unsigned short)(*( objectMap->get_data() + location.y * objectMap->get_stride() + location.x )); + } + + 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 +166,7 @@ RGBColor Geometry::getOuterLineColor () return color; } -void Circle::drawOuterGeometry(Cairo::RefPtr &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem) +void Circle::drawOuterGeometry(Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) { if ((flags & F_VISIBLE) && state != INSENSITIVE) { RGBColor color; @@ -75,14 +181,14 @@ void Circle::drawOuterGeometry(Cairo::RefPtr &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); + 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 +196,7 @@ void Circle::drawOuterGeometry(Cairo::RefPtr &cr, rtengine::Edit } } -void Circle::drawInnerGeometry(Cairo::RefPtr &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem) +void Circle::drawInnerGeometry(Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) { if (flags & F_VISIBLE) { if (state != INSENSITIVE) { @@ -108,14 +214,14 @@ void Circle::drawInnerGeometry(Cairo::RefPtr &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); + 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,24 +253,27 @@ void Circle::drawInnerGeometry(Cairo::RefPtr &cr, rtengine::Edit } } -void Circle::drawToMOChannel (Cairo::RefPtr &cr, Cairo::RefPtr &cr2, unsigned short id, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem) +void Circle::drawToMOChannel (Cairo::RefPtr &cr, 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 - unsigned short a = (id + 1) & 0xFF; - cr->set_source_rgba (0., 0., 0., double(a) / 255.); + // setting the color to the objet's ID + if (objectBuffer->getObjectMode() == OM_255) { + cr->set_source_rgba (0., 0., 0., ((id + 1) & 0xFF) / 255.); + } else { + cr->set_source_rgba (0., 0., 0., (id + 1) / 65535.); + } cr->arc(center_.x + 0.5, center_.y + 0.5, radius_, 0, 2.*M_PI); if (filled) { @@ -177,28 +286,10 @@ void Circle::drawToMOChannel (Cairo::RefPtr &cr, Cairo::RefPtrstroke(); } - - // drawing the higher byte's value - if (editBuffer->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); - - if (filled) { - if (innerLineWidth > 0.) { - cr2->fill_preserve(); - cr2->stroke(); - } else { - cr2->fill(); - } - } else { - cr2->stroke(); - } - } } } -void Line::drawOuterGeometry(Cairo::RefPtr &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem) +void Line::drawOuterGeometry(Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) { if ((flags & F_VISIBLE) && state != INSENSITIVE) { RGBColor color; @@ -216,14 +307,14 @@ void Line::drawOuterGeometry(Cairo::RefPtr &cr, rtengine::EditBu rtengine::Coord end_ = end; if (datum == IMAGE) { - coordSystem.imageCoordToScreen(begin.x, begin.y, begin_.x, begin_.y); - coordSystem.imageCoordToScreen(end.x, end.y, end_.x, end_.y); + 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 +323,7 @@ void Line::drawOuterGeometry(Cairo::RefPtr &cr, rtengine::EditBu } } -void Line::drawInnerGeometry(Cairo::RefPtr &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem) +void Line::drawInnerGeometry(Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) { if ((flags & F_VISIBLE) && innerLineWidth > 0.) { if (state != INSENSITIVE) { @@ -253,14 +344,14 @@ void Line::drawInnerGeometry(Cairo::RefPtr &cr, rtengine::EditBu rtengine::Coord end_ = end; if (datum == IMAGE) { - coordSystem.imageCoordToScreen(begin.x, begin.y, begin_.x, begin_.y); - coordSystem.imageCoordToScreen(end.x, end.y, end_.x, end_.y); + 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); @@ -282,9 +373,7 @@ void Line::drawInnerGeometry(Cairo::RefPtr &cr, rtengine::EditBu } } -void Line::drawToMOChannel(Cairo::RefPtr &cr, - Cairo::RefPtr &cr2, unsigned short id, - rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem) +void Line::drawToMOChannel(Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) { if (flags & F_HOVERABLE) { cr->set_line_width( getMouseOverLineWidth() ); @@ -292,35 +381,29 @@ void Line::drawToMOChannel(Cairo::RefPtr &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 - unsigned short a = (id + 1) & 0xFF; - cr->set_source_rgba (0., 0., 0., double(a) / 255.); + // setting the color to the objet's ID + if (objectBuffer->getObjectMode() == OM_255) { + cr->set_source_rgba (0., 0., 0., ((id + 1) & 0xFF) / 255.); + } else { + cr->set_source_rgba (0., 0., 0., (id + 1) / 65535.); + } cr->move_to(begin_.x + 0.5, begin_.y + 0.5); cr->line_to(end_.x + 0.5, end_.y + 0.5); cr->stroke(); - - // drawing the higher byte's value - if (editBuffer->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); - cr2->line_to(end_.x + 0.5, end_.y + 0.5); - cr2->stroke(); - } } } -void Polyline::drawOuterGeometry(Cairo::RefPtr &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem) +void Polyline::drawOuterGeometry(Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) { if ((flags & F_VISIBLE) && state != INSENSITIVE && points.size() > 1) { RGBColor color; @@ -340,11 +423,11 @@ void Polyline::drawOuterGeometry(Cairo::RefPtr &cr, rtengine::Ed currPos = points.at(i); if (datum == IMAGE) { - coordSystem.imageCoordToScreen(points.at(i).x, points.at(i).y, currPos.x, currPos.y); + 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 +446,7 @@ void Polyline::drawOuterGeometry(Cairo::RefPtr &cr, rtengine::Ed } } -void Polyline::drawInnerGeometry(Cairo::RefPtr &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem) +void Polyline::drawInnerGeometry(Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) { if ((flags & F_VISIBLE) && points.size() > 1) { if (state != INSENSITIVE) { @@ -387,11 +470,11 @@ void Polyline::drawInnerGeometry(Cairo::RefPtr &cr, rtengine::Ed currPos = points.at(i); if (datum == IMAGE) { - coordSystem.imageCoordToScreen(points.at(i).x, points.at(i).y, currPos.x, currPos.y); + 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) { @@ -414,11 +497,11 @@ void Polyline::drawInnerGeometry(Cairo::RefPtr &cr, rtengine::Ed currPos = points.at(i); if (datum == IMAGE) { - coordSystem.imageCoordToScreen(points.at(i).x, points.at(i).y, currPos.x, currPos.y); + 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,25 +528,28 @@ void Polyline::drawInnerGeometry(Cairo::RefPtr &cr, rtengine::Ed } } -void Polyline::drawToMOChannel (Cairo::RefPtr &cr, Cairo::RefPtr &cr2, unsigned short id, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem) +void Polyline::drawToMOChannel (Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) { if ((flags & F_HOVERABLE) && points.size() > 1) { rtengine::Coord currPos; - // drawing the lower byte's value - unsigned short a = (id + 1) & 0xFF; - cr->set_source_rgba (0., 0., 0., double(a) / 255.); + // setting the color to the objet's ID + if (objectBuffer->getObjectMode() == OM_255) { + cr->set_source_rgba (0., 0., 0., ((id + 1) & 0xFF) / 255.); + } else { + cr->set_source_rgba (0., 0., 0., (id + 1) / 65535.); + } for (unsigned int i = 0; i < points.size(); ++i) { cr->set_line_width( getMouseOverLineWidth() ); 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) { @@ -483,42 +569,6 @@ void Polyline::drawToMOChannel (Cairo::RefPtr &cr, Cairo::RefPtr } else { cr->stroke(); } - - // drawing the higher byte's value - if (editBuffer->getObjectMode() == OM_65535) { - a = (id + 1) >> 8; - cr2->set_source_rgba (0., 0., 0., double(a) / 255.); - - for (unsigned int i = 0; i < points.size(); ++i) { - cr2->set_line_width( getMouseOverLineWidth() ); - currPos = points.at(i); - - if (datum == IMAGE) { - coordSystem.imageCoordToCropBuffer(points.at(i).x, points.at(i).y, currPos.x, currPos.y); - } else if (datum == CLICKED_POINT) { - currPos += editBuffer->getDataProvider()->posScreen; - } else if (datum == CURSOR) { - currPos += editBuffer->getDataProvider()->posScreen + editBuffer->getDataProvider()->deltaScreen; - } - - if (!i) { - cr2->move_to(currPos.x + 0.5, currPos.y + 0.5); - } else { - cr2->line_to(currPos.x + 0.5, currPos.y + 0.5); - } - } - - if (filled) { - if (innerLineWidth > 0.) { - cr2->fill_preserve(); - cr2->stroke(); - } else { - cr2->fill(); - } - } else { - cr2->stroke(); - } - } } } @@ -546,7 +596,7 @@ void Rectangle::setXYXY(rtengine::Coord topLeft, rtengine::Coord bottomRight) this->bottomRight = bottomRight; } -void Rectangle::drawOuterGeometry(Cairo::RefPtr &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem) +void Rectangle::drawOuterGeometry(Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) { if ((flags & F_VISIBLE) && state != INSENSITIVE) { RGBColor color; @@ -563,19 +613,19 @@ void Rectangle::drawOuterGeometry(Cairo::RefPtr &cr, rtengine::E rtengine::Coord tl, br; if (datum == IMAGE) { - coordSystem.imageCoordToScreen(topLeft.x, topLeft.y, tl.x, tl.y); + 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); + 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 +639,7 @@ void Rectangle::drawOuterGeometry(Cairo::RefPtr &cr, rtengine::E } } -void Rectangle::drawInnerGeometry(Cairo::RefPtr &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem) +void Rectangle::drawInnerGeometry(Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) { if (flags & F_VISIBLE) { if (state != INSENSITIVE) { @@ -609,19 +659,19 @@ void Rectangle::drawInnerGeometry(Cairo::RefPtr &cr, rtengine::E rtengine::Coord tl, br; if (datum == IMAGE) { - coordSystem.imageCoordToScreen(topLeft.x, topLeft.y, tl.x, tl.y); + 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); + 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 +703,7 @@ void Rectangle::drawInnerGeometry(Cairo::RefPtr &cr, rtengine::E } } -void Rectangle::drawToMOChannel(Cairo::RefPtr &cr, Cairo::RefPtr &cr2, unsigned short id, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem) +void Rectangle::drawToMOChannel(Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) { if (flags & F_HOVERABLE) { cr->set_line_width( getMouseOverLineWidth() ); @@ -661,24 +711,27 @@ void Rectangle::drawToMOChannel(Cairo::RefPtr &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 - unsigned short a = (id + 1) & 0xFF; - cr->set_source_rgba (0., 0., 0., double(a) / 255.); + // setting the color to the objet's ID + if (objectBuffer->getObjectMode() == OM_255) { + cr->set_source_rgba (0., 0., 0., ((id + 1) & 0xFF) / 255.); + } else { + cr->set_source_rgba (0., 0., 0., (id + 1) / 65535.); + } cr->rectangle(tl.x + 0.5, tl.y + 0.5, br.x - tl.x, br.y - tl.y); if (filled) { @@ -691,24 +744,6 @@ void Rectangle::drawToMOChannel(Cairo::RefPtr &cr, Cairo::RefPtr } else { cr->stroke(); } - - // drawing the higher byte's value - if (editBuffer->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); - - if (filled) { - if (innerLineWidth > 0.) { - cr2->fill_preserve(); - cr2->stroke(); - } else { - cr2->fill(); - } - } else { - cr2->stroke(); - } - } } } @@ -766,7 +801,7 @@ EditType EditSubscriber::getEditingType() return editingType; } -BufferType EditSubscriber::getEditBufferType() +BufferType EditSubscriber::getPipetteBufferType() { return bufferType; } diff --git a/rtgui/edit.h b/rtgui/edit.h index c8b8090fb..5268e82e5 100644 --- a/rtgui/edit.h +++ b/rtgui/edit.h @@ -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,44 @@ 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 objectMap; + 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); + void flush(); + EditSubscriber *getEditSubscriber (); + +public: + explicit ObjectMOBuffer (EditDataProvider *dataProvider); + ~ObjectMOBuffer(); + + EditDataProvider* getDataProvider (); + void setObjectMode (ObjectMode newType); + ObjectMode getObjectMode (); + + Cairo::RefPtr& getObjectMap (); + + // 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 +198,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 +209,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 @@ -190,36 +223,16 @@ class RGBColor double b; public: - RGBColor () : r(0.), g(0.), b(0.) {} - explicit RGBColor (double r, double g, double b) : r(r), g(g), b(b) {} - explicit RGBColor (char r, char g, char b) : r(double(r) / 255.), g(double(g) / 255.), b(double(b) / 255.) {} + RGBColor (); + explicit RGBColor (double r, double g, double b); + explicit RGBColor (char r, char g, char b); - void setColor(double r, double g, double b) - { - this->r = r; - this->g = g; - this->b = b; - } + void setColor (double r, double g, double b); + void setColor (char r, char g, char b); - void setColor(char r, char g, char b) - { - this->r = double(r) / 255.; - this->g = double(g) / 255.; - this->b = double(b) / 255.; - } - - double getR() - { - return r; - } - double getG() - { - return g; - } - double getB() - { - return b; - } + double getR (); + double getG (); + double getB (); }; class RGBAColor : public RGBColor @@ -227,26 +240,14 @@ class RGBAColor : public RGBColor double a; public: - RGBAColor () : RGBColor(0., 0., 0.), a(0.) {} - explicit RGBAColor (double r, double g, double b, double a) : RGBColor(r, g, b), a(a) {} - explicit RGBAColor (char r, char g, char b, char a) : RGBColor(r, g, b), a(double(a) / 255.) {} + RGBAColor (); + explicit RGBAColor (double r, double g, double b, double a); + explicit RGBAColor (char r, char g, char b, char a); - void setColor(double r, double g, double b, double a) - { - RGBColor::setColor(r, g, b); - this->a = a; - } + void setColor (double r, double g, double b, double a); + void setColor (char r, char g, char b, char a); - void setColor(char r, char g, char b, char a) - { - RGBColor::setColor(r, g, b); - this->a = double(a) / 255.; - } - - double getA() - { - return a; - } + double getA (); }; /// @brief Displayable and MouseOver geometry base class @@ -297,85 +298,29 @@ public: Datum datum; State state; // set by the Subscriber - Geometry () : innerLineColor(char(255), char(255), char(255)), outerLineColor(char(0), char(0), char(0)), flags(F_VISIBLE | F_HOVERABLE | F_AUTO_COLOR), innerLineWidth(1.5f), datum(IMAGE), state(NORMAL) {} + Geometry (); virtual ~Geometry() {} - void setInnerLineColor (double r, double g, double b) - { - innerLineColor.setColor(r, g, b); - flags &= ~F_AUTO_COLOR; - } - void setInnerLineColor (char r, char g, char b) - { - innerLineColor.setColor(r, g, b); - flags &= ~F_AUTO_COLOR; - } - RGBColor getInnerLineColor (); - void setOuterLineColor (double r, double g, double b) - { - outerLineColor.setColor(r, g, b); - flags &= ~F_AUTO_COLOR; - } - void setOuterLineColor (char r, char g, char b) - { - outerLineColor.setColor(r, g, b); - flags &= ~F_AUTO_COLOR; - } - RGBColor getOuterLineColor (); - double getOuterLineWidth () - { - return double(innerLineWidth) + 2.; - } - double getMouseOverLineWidth () - { - return getOuterLineWidth() + 2.; - } - void setAutoColor (bool aColor) - { - if (aColor) { - flags |= F_AUTO_COLOR; - } else { - flags &= ~F_AUTO_COLOR; - } - } - bool isVisible () - { - return flags & F_VISIBLE; - } - void setVisible (bool visible) - { - if (visible) { - flags |= F_VISIBLE; - } else { - flags &= ~F_VISIBLE; - } - } - bool isHoverable () - { - return flags & F_HOVERABLE; - } - void setHoverable (bool visible) - { - if (visible) { - flags |= F_HOVERABLE; - } else { - flags &= ~F_HOVERABLE; - } - } + void setInnerLineColor (double r, double g, double b); + void setInnerLineColor (char r, char g, char b); + RGBColor getInnerLineColor (); + void setOuterLineColor (double r, double g, double b); + void setOuterLineColor (char r, char g, char b); + RGBColor getOuterLineColor (); + double getOuterLineWidth (); + double getMouseOverLineWidth (); + void setAutoColor (bool aColor); + bool isVisible (); + void setVisible (bool visible); + bool isHoverable (); + void setHoverable (bool visible); // setActive will enable/disable the visible and hoverable flags in one shot! - void setActive (bool active) - { - if (active) { - flags |= (F_VISIBLE | F_HOVERABLE); - } else { - flags &= ~(F_VISIBLE | F_HOVERABLE); - } - } + void setActive (bool active); - virtual void drawOuterGeometry (Cairo::RefPtr &cr, rtengine::EditBuffer *parent, EditCoordSystem &coordSystem) = 0; - virtual void drawInnerGeometry (Cairo::RefPtr &cr, rtengine::EditBuffer *parent, EditCoordSystem &coordSystem) = 0; - virtual void drawToMOChannel (Cairo::RefPtr &cr, Cairo::RefPtr &cr2, unsigned short id, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem) = 0; + virtual void drawOuterGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *parent, EditCoordSystem &coordSystem) = 0; + virtual void drawInnerGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *parent, EditCoordSystem &coordSystem) = 0; + virtual void drawToMOChannel (Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *pipetteBuffer, EditCoordSystem &coordSystem) = 0; }; class Circle : public Geometry @@ -386,13 +331,13 @@ public: bool filled; bool radiusInImageSpace; /// If true, the radius depend on the image scale; if false, it is a fixed 'screen' size - Circle () : center(100, 100), radius(10), filled(false), radiusInImageSpace(false) {} - Circle (rtengine::Coord ¢er, 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) {} + Circle (); + Circle (rtengine::Coord& center, int radius, bool filled = false, bool radiusInImageSpace = false); + Circle (int centerX, int centerY, int radius, bool filled = false, bool radiusInImageSpace = false); - void drawOuterGeometry (Cairo::RefPtr &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem); - void drawInnerGeometry (Cairo::RefPtr &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem); - void drawToMOChannel (Cairo::RefPtr &cr, Cairo::RefPtr &cr2, unsigned short id, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem); + void drawOuterGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *pipetteBuffer, EditCoordSystem &coordSystem); + void drawInnerGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *pipetteBuffer, EditCoordSystem &coordSystem); + void drawToMOChannel (Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *pipetteBuffer, EditCoordSystem &coordSystem); }; class Line : public Geometry @@ -401,13 +346,13 @@ public: rtengine::Coord begin; rtengine::Coord end; - Line () : begin(10, 10), end(100, 100) {} - 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) {} + Line (); + Line (rtengine::Coord& begin, rtengine::Coord& end); + Line (int beginX, int beginY, int endX, int endY); - void drawOuterGeometry (Cairo::RefPtr &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem); - void drawInnerGeometry (Cairo::RefPtr &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem); - void drawToMOChannel (Cairo::RefPtr &cr, Cairo::RefPtr &cr2, unsigned short id, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem); + void drawOuterGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *pipetteBuffer, EditCoordSystem &coordSystem); + void drawInnerGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *pipetteBuffer, EditCoordSystem &coordSystem); + void drawToMOChannel (Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *pipetteBuffer, EditCoordSystem &coordSystem); }; class Polyline : public Geometry @@ -416,11 +361,11 @@ public: std::vector points; bool filled; - Polyline() : filled(false) {} + Polyline (); - void drawOuterGeometry (Cairo::RefPtr &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem); - void drawInnerGeometry (Cairo::RefPtr &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem); - void drawToMOChannel (Cairo::RefPtr &cr, Cairo::RefPtr &cr2, unsigned short id, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem); + void drawOuterGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *pipetteBuffer, EditCoordSystem &coordSystem); + void drawInnerGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *pipetteBuffer, EditCoordSystem &coordSystem); + void drawToMOChannel (Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *pipetteBuffer, EditCoordSystem &coordSystem); }; class Rectangle : public Geometry @@ -430,15 +375,15 @@ public: rtengine::Coord bottomRight; bool filled; - Rectangle() : topLeft(0, 0), bottomRight(10, 10), filled(false) {} + Rectangle (); void setXYWH(int left, int top, int width, int height); void setXYXY(int left, int top, int right, int bottom); void setXYWH(rtengine::Coord topLeft, rtengine::Coord widthHeight); void setXYXY(rtengine::Coord topLeft, rtengine::Coord bottomRight); - void drawOuterGeometry (Cairo::RefPtr &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem); - void drawInnerGeometry (Cairo::RefPtr &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem); - void drawToMOChannel (Cairo::RefPtr &cr, Cairo::RefPtr &cr2, unsigned short id, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem); + void drawOuterGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *pipetteBuffer, EditCoordSystem &coordSystem); + void drawInnerGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *pipetteBuffer, EditCoordSystem &coordSystem); + void drawToMOChannel (Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *pipetteBuffer, EditCoordSystem &coordSystem); }; /// @brief Method for client tools needing Edit information @@ -463,10 +408,7 @@ public: virtual ~EditSubscriber () {} void setEditProvider(EditDataProvider *provider); - EditDataProvider* getEditProvider() - { - return provider; - } + EditDataProvider* getEditProvider (); void setEditID(EditUniqueID ID, BufferType buffType); bool isCurrentSubscriber(); virtual void subscribe(); @@ -474,109 +416,69 @@ 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 @param objectID object currently "hovered" */ - virtual CursorShape getCursor(int objectID) - { - return CSOpenHand; - } + virtual CursorShape getCursor (int objectID); /** @brief Triggered when the mouse is moving over an object This method is also triggered when the cursor is moving over the image in ET_PIPETTE mode @param modifierKey Gtk's event modifier key (GDK_CONTROL_MASK | GDK_SHIFT_MASK | ...) - @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) - { - return false; - } + virtual bool mouseOver (int modifierKey); /** @brief Triggered when mouse button 1 is pressed, together with the CTRL modifier key if the subscriber is of type ET_PIPETTE Once the key is pressed, RT will enter in drag1 mode on subsequent mouse movements @param modifierKey Gtk's event modifier key (GDK_CONTROL_MASK | GDK_SHIFT_MASK | ...) @return true if the preview has to be redrawn, false otherwise */ - virtual bool button1Pressed(int modifierKey) - { - return false; - } + virtual bool button1Pressed (int modifierKey); /** @brief Triggered when mouse button 1 is released @return true if the preview has to be redrawn, false otherwise */ - virtual bool button1Released() - { - return false; - } + virtual bool button1Released (); /** @brief Triggered when mouse button 2 is pressed (middle button) Once the key is pressed, RT will enter in drag2 mode on subsequent mouse movements @param modifierKey Gtk's event modifier key (GDK_CONTROL_MASK | GDK_SHIFT_MASK | ...) @return true if the preview has to be redrawn, false otherwise */ - virtual bool button2Pressed(int modifierKey) - { - return false; - } + virtual bool button2Pressed (int modifierKey); /** @brief Triggered when mouse button 2 is released (middle button) @return true if the preview has to be redrawn, false otherwise */ - virtual bool button2Released() - { - return false; - } + virtual bool button2Released (); /** @brief Triggered when mouse button 3 is pressed (right button) Once the key is pressed, RT will enter in drag3 mode on subsequent mouse movements @param modifierKey Gtk's event modifier key (GDK_CONTROL_MASK | GDK_SHIFT_MASK | ...) @return true if the preview has to be redrawn, false otherwise */ - virtual bool button3Pressed(int modifierKey) - { - return false; - } + virtual bool button3Pressed (int modifierKey); /** @brief Triggered when mouse button 3 is released (right button) @return true if the preview has to be redrawn, false otherwise */ - virtual bool button3Released() - { - return false; - } + virtual bool button3Released (); /** @brief Triggered when the user is moving while holding down mouse button 1 @param modifierKey Gtk's event modifier key (GDK_CONTROL_MASK | GDK_SHIFT_MASK | ...) @return true if the preview has to be redrawn, false otherwise */ - virtual bool drag1(int modifierKey) - { - return false; - } + virtual bool drag1 (int modifierKey); /** @brief Triggered when the user is moving while holding down mouse button 2 @param modifierKey Gtk's event modifier key (GDK_CONTROL_MASK | GDK_SHIFT_MASK | ...) @return true if the preview has to be redrawn, false otherwise */ - virtual bool drag2(int modifierKey) - { - return false; - } + virtual bool drag2 (int modifierKey); /** @brief Triggered when the user is moving while holding down mouse button 3 @param modifierKey Gtk's event modifier key (GDK_CONTROL_MASK | GDK_SHIFT_MASK | ...) @return true if the preview has to be redrawn, false otherwise */ - virtual bool drag3(int modifierKey) - { - return false; - } + virtual bool drag3 (int modifierKey); /** @brief Get the geometry to be shown to the user */ - const std::vector & getVisibleGeometry() - { - return visibleGeometry; - } + const std::vector& getVisibleGeometry (); /** @brief Get the geometry to be drawn in the "mouse over" channel, hidden from the user */ - const std::vector & getMouseOverGeometry() - { - return mouseOverGeometry; - } + const std::vector& getMouseOverGeometry (); }; /** @brief Class to handle the furniture of data to the subscribers. @@ -608,12 +510,255 @@ public: virtual void unsubscribe(); /// Occurs when the subscriber has been switched off first virtual void switchOffEditMode (); /// Occurs when the user want to stop the editing mode virtual CursorShape getCursor(int objectID); - int getPipetteRectSize() - { - return 8; // TODO: make a GUI - } + int getPipetteRectSize (); EditSubscriber* getCurrSubscriber(); virtual void getImageSize (int &w, int&h) = 0; }; +inline EditDataProvider* ObjectMOBuffer::getDataProvider () { + return dataProvider; +} + +inline ObjectMode ObjectMOBuffer::getObjectMode () { + return objectMode; +} + +inline Cairo::RefPtr& ObjectMOBuffer::getObjectMap () { + return objectMap; +} + +inline void RGBColor::setColor (double r, double g, double b) { + this->r = r; + this->g = g; + this->b = b; +} + +inline void RGBColor::setColor (char r, char g, char b) { + this->r = double (r) / 255.; + this->g = double (g) / 255.; + this->b = double (b) / 255.; +} + +inline double RGBColor::getR () { + return r; +} + +inline double RGBColor::getG () { + return g; +} + +inline double RGBColor::getB () { + return b; +} + +inline void RGBAColor::setColor (double r, double g, double b, double a) { + RGBColor::setColor (r, g, b); + this->a = a; +} + +inline void RGBAColor::setColor (char r, char g, char b, char a) { + RGBColor::setColor (r, g, b); + this->a = double (a) / 255.; +} + +inline double RGBAColor::getA () { + return a; +} + +inline void Geometry::setInnerLineColor (double r, double g, double b) { + innerLineColor.setColor (r, g, b); + flags &= ~F_AUTO_COLOR; +} + +inline void Geometry::setInnerLineColor (char r, char g, char b) { + innerLineColor.setColor (r, g, b); + flags &= ~F_AUTO_COLOR; +} + +inline void Geometry::setOuterLineColor (double r, double g, double b) { + outerLineColor.setColor (r, g, b); + flags &= ~F_AUTO_COLOR; +} + +inline double Geometry::getOuterLineWidth () { + return double (innerLineWidth) + 2.; +} + +inline void Geometry::setOuterLineColor (char r, char g, char b) { + outerLineColor.setColor (r, g, b); + flags &= ~F_AUTO_COLOR; +} + +inline double Geometry::getMouseOverLineWidth () { + return getOuterLineWidth () + 2.; +} + +inline void Geometry::setAutoColor (bool aColor) { + if (aColor) { + flags |= F_AUTO_COLOR; + } else { + flags &= ~F_AUTO_COLOR; + } +} + +inline bool Geometry::isVisible () { + return flags & F_VISIBLE; +} + +inline void Geometry::setVisible (bool visible) { + if (visible) { + flags |= F_VISIBLE; + } else { + flags &= ~F_VISIBLE; + } +} + +inline bool Geometry::isHoverable () { + return flags & F_HOVERABLE; +} + +inline void Geometry::setHoverable (bool visible) { + if (visible) { + flags |= F_HOVERABLE; + } else { + flags &= ~F_HOVERABLE; + } +} + +inline void Geometry::setActive (bool active) { + if (active) { + flags |= (F_VISIBLE | F_HOVERABLE); + } else { + flags &= ~(F_VISIBLE | F_HOVERABLE); + } +} + +inline EditDataProvider* EditSubscriber::getEditProvider () { + return provider; +} + +inline CursorShape EditSubscriber::getCursor (int objectID) { + return CSOpenHand; +} + +inline bool EditSubscriber::mouseOver (int modifierKey) { + return false; +} + +inline bool EditSubscriber::button1Pressed (int modifierKey) { + return false; +} + +inline bool EditSubscriber::button1Released () { + return false; +} + +inline bool EditSubscriber::button2Pressed (int modifierKey) { + return false; +} + +inline bool EditSubscriber::button2Released () { + return false; +} + +inline bool EditSubscriber::button3Pressed (int modifierKey) { + return false; +} + +inline bool EditSubscriber::button3Released () { + return false; +} + +inline bool EditSubscriber::drag1 (int modifierKey) { + return false; +} + +inline bool EditSubscriber::drag2 (int modifierKey) { + return false; +} + +inline bool EditSubscriber::drag3 (int modifierKey) { + return false; +} + +inline const std::vector& EditSubscriber::getVisibleGeometry () { + return visibleGeometry; +} + +inline const std::vector& EditSubscriber::getMouseOverGeometry () { + return mouseOverGeometry; +} + +inline int EditDataProvider::getPipetteRectSize () { + return 8; // TODO: make a GUI +} + +inline Geometry::Geometry () : + innerLineColor (char (255), char (255), char (255)), outerLineColor ( + char (0), char (0), char (0)), flags ( + F_VISIBLE | F_HOVERABLE | F_AUTO_COLOR), innerLineWidth (1.5f), datum ( + IMAGE), state (NORMAL) { +} + +inline Circle::Circle () : + center (100, 100), radius (10), filled (false), radiusInImageSpace ( + false) { +} + +inline Rectangle::Rectangle () : + topLeft (0, 0), bottomRight (10, 10), filled (false) { +} + +inline Polyline::Polyline () : + filled (false) { +} + +inline Line::Line () : + begin (10, 10), end (100, 100) { +} + +inline RGBAColor::RGBAColor () : + RGBColor (0., 0., 0.), a (0.) { +} + +inline RGBColor::RGBColor () : + r (0.), g (0.), b (0.) { +} + +inline RGBColor::RGBColor (double r, double g, double b) : + r (r), g (g), b (b) { +} + +inline RGBColor::RGBColor (char r, char g, char b) : + r (double (r) / 255.), g (double (g) / 255.), b (double (b) / 255.) { +} + +inline RGBAColor::RGBAColor (double r, double g, double b, double a) : + RGBColor (r, g, b), a (a) { +} + +inline RGBAColor::RGBAColor (char r, char g, char b, char a) : + RGBColor (r, g, b), a (double (a) / 255.) { +} + +inline Circle::Circle (rtengine::Coord& center, int radius, bool filled, + bool radiusInImageSpace) : + center (center), radius (radius), filled (filled), radiusInImageSpace ( + radiusInImageSpace) { +} + +inline Circle::Circle (int centerX, int centerY, int radius, bool filled, + bool radiusInImageSpace) : + center (centerX, centerY), radius (radius), filled (filled), radiusInImageSpace ( + radiusInImageSpace) { +} + +inline Line::Line (rtengine::Coord& begin, rtengine::Coord& end) : + begin (begin), end (end) { +} + +inline Line::Line (int beginX, int beginY, int endX, int endY) : + begin (beginX, beginY), end (endX, endY) { +} + #endif diff --git a/rtgui/gradient.cc b/rtgui/gradient.cc index 49cc3ee59..93011f55b 100644 --- a/rtgui/gradient.cc +++ b/rtgui/gradient.cc @@ -136,88 +136,77 @@ 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) { - int imW, imH; - PolarCoord polCoord1, polCoord2; - dataProvider->getImageSize(imW, imH); - 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); - - Line *currLine; - Circle *currCircle; - // update horizontal line - currLine = static_cast(visibleGeometry.at(0)); - polCoord1.set(1500.f, float(-degree_ + 180)); - currLine->begin.setFromPolar(polCoord1); - currLine->begin += origin; - polCoord1.set(1500.f, float(-degree_ )); - currLine->end.setFromPolar (polCoord1); - currLine->end += origin; - currLine = static_cast(mouseOverGeometry.at(0)); - polCoord1.set(1500.f, float(-degree_ + 180)); - currLine->begin.setFromPolar(polCoord1); - currLine->begin += origin; - polCoord1.set(1500.f, float(-degree_ )); - currLine->end.setFromPolar (polCoord1); - currLine->end += origin; - // update vertical line - currLine = static_cast(visibleGeometry.at(1)); - polCoord1.set( 700.f, float(-degree_ + 90 )); - currLine->begin.setFromPolar(polCoord1); - currLine->begin += origin; - polCoord1.set( 700.f, float(-degree_ + 270)); - currLine->end.setFromPolar (polCoord1); - currLine->end += origin; - currLine = static_cast(mouseOverGeometry.at(1)); - polCoord1.set( 700.f, float(-degree_ + 90 )); - currLine->begin.setFromPolar(polCoord1); - currLine->begin += origin; - polCoord1.set( 700.f, float(-degree_ + 270)); - currLine->end.setFromPolar (polCoord1); - currLine->end += origin; - // update upper feather line - currLine = static_cast(visibleGeometry.at(2)); - polCoord2.set(decay, float(-degree_ + 270)); - polCoord1.set(350.f, float(-degree_ + 180)); - currLine->begin.setFromPolar(polCoord1 + polCoord2); - currLine->begin += origin; - polCoord1.set(350.f, float(-degree_ )); - currLine->end.setFromPolar (polCoord1 + polCoord2); - currLine->end += origin; - currLine = static_cast(mouseOverGeometry.at(2)); - polCoord1.set(350.f, float(-degree_ + 180)); - currLine->begin.setFromPolar(polCoord1 + polCoord2); - currLine->begin += origin; - polCoord1.set(350.f, float(-degree_ )); - currLine->end.setFromPolar (polCoord1 + polCoord2); - currLine->end += origin; - // update lower feather line - currLine = static_cast(visibleGeometry.at(3)); - polCoord2.set(decay, float(-degree_ + 90)); - polCoord1.set(350.f, float(-degree_ + 180)); - currLine->begin.setFromPolar(polCoord1 + polCoord2); - currLine->begin += origin; - polCoord1.set(350.f, float(-degree_ )); - currLine->end.setFromPolar (polCoord1 + polCoord2); - currLine->end += origin; - currLine = static_cast(mouseOverGeometry.at(3)); - polCoord1.set(350.f, float(-degree_ + 180)); - currLine->begin.setFromPolar(polCoord1 + polCoord2); - currLine->begin += origin; - polCoord1.set(350.f, float(-degree_ )); - currLine->end.setFromPolar (polCoord1 + polCoord2); - currLine->end += origin; - // update circle's position - currCircle = static_cast(visibleGeometry.at(4)); - currCircle->center = origin; - currCircle = static_cast(mouseOverGeometry.at(4)); - currCircle->center = origin; + if (!dataProvider) { + return; } + + int imW=0; + int imH=0; + if (fullWidth != -1 && fullHeight != -1) { + imW = fullWidth; + imH = fullHeight; + } else { + dataProvider->getImageSize(imW, imH); + if (!imW || !imH) { + return; + } + } + + PolarCoord polCoord1, polCoord2; + double decay = feather * rtengine::norm2(imW, imH) / 200.; + + rtengine::Coord origin(imW / 2 + centerX * imW / 200, imH / 2 + centerY * imH / 200); + + Line *currLine; + Circle *currCircle; + + const auto updateLine = [&](Geometry* geometry, const float radius, const float begin, const float end) + { + const auto line = static_cast(geometry); + line->begin.setFromPolar(PolarCoord(radius, -degree + begin)); + line->begin += origin; + line->end.setFromPolar(PolarCoord(radius, -degree + end)); + line->end += origin; + }; + + const auto updateLineWithDecay = [&](Geometry* geometry, const float radius, const float offSetAngle) + { + const auto line = static_cast(geometry); + line->begin.setFromPolar(PolarCoord(radius, -degree + 180.) + PolarCoord(decay, -degree + offSetAngle)); + line->begin += origin; + line->end.setFromPolar(PolarCoord(radius, -degree) + PolarCoord(decay, -degree + offSetAngle)); + line->end += origin; + }; + + const auto updateCircle = [&](Geometry* geometry) + { + const auto circle = static_cast(geometry); + circle->center = origin; + }; + + // update horizontal line + updateLine (visibleGeometry.at(0), 1500., 0., 180.); + updateLine (mouseOverGeometry.at(0), 1500., 0., 180.); + + // update vertical line + updateLine (visibleGeometry.at(1), 700., 90., 270.); + updateLine (mouseOverGeometry.at(1), 700., 90., 270.); + + // update upper feather line + updateLineWithDecay (visibleGeometry.at(2), 350., 270.); + updateLineWithDecay (mouseOverGeometry.at(2), 350., 270.); + + // update lower feather line + updateLineWithDecay (visibleGeometry.at(3), 350., 90.); + updateLineWithDecay (mouseOverGeometry.at(3), 350., 90.); + + // update circle's position + updateCircle (visibleGeometry.at(4)); + updateCircle (mouseOverGeometry.at(4)); } void Gradient::write (ProcParams* pp, ParamsEdited* pedited) @@ -397,6 +386,10 @@ bool Gradient::mouseOver(int modifierKey) bool Gradient::button1Pressed(int modifierKey) { + if (lastObject < 0) { + return false; + } + EditDataProvider *provider = getEditProvider(); if (!(modifierKey & GDK_CONTROL_MASK)) { @@ -447,20 +440,20 @@ bool Gradient::button1Pressed(int modifierKey) EditSubscriber::dragging = true; return false; - } else { + } else { // 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; - } + 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() diff --git a/rtgui/gradient.h b/rtgui/gradient.h index 4117c3859..f59fb07e5 100644 --- a/rtgui/gradient.h +++ b/rtgui/gradient.h @@ -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); diff --git a/rtgui/imagearea.cc b/rtgui/imagearea.cc index a1f18c892..a37aa210d 100644 --- a/rtgui/imagearea.cc +++ b/rtgui/imagearea.cc @@ -56,8 +56,8 @@ ImageArea::ImageArea (ImageAreaPanel* p) : parent(p), firstOpen(true) ImageArea::~ImageArea () { - for (std::list::iterator i = cropWins.begin(); i != cropWins.end(); i++) { - delete *i; + for (auto cropWin : cropWins) { + delete cropWin; } cropWins.clear (); @@ -96,10 +96,10 @@ void ImageArea::on_resized (Gtk::Allocation& req) mainCropWindow->setPointerMotionListener (pmlistener); mainCropWindow->setPointerMotionHListener (pmhlistener); mainCropWindow->setPosition (0, 0); - mainCropWindow->setSize (get_width(), get_height(), false); // this execute the refresh itself + mainCropWindow->setSize (get_width(), get_height()); // this execute the refresh itself mainCropWindow->enable(); // start processing ! } else { - mainCropWindow->setSize (get_width(), get_height()); + mainCropWindow->setSize (get_width(), get_height()); // this execute the refresh itself } parent->syncBeforeAfterViews(); @@ -110,10 +110,9 @@ void ImageArea::setImProcCoordinator (rtengine::StagedImageProcessor* ipc_) { if( !ipc_ ) { focusGrabber = NULL; - std::list::iterator i = cropWins.begin(); - for( ; i != cropWins.end(); i++ ) { - delete *i; + for (auto cropWin : cropWins) { + delete cropWin; } cropWins.clear(); @@ -170,10 +169,11 @@ CropWindow* ImageArea::getCropWindow (int x, int y) CropWindow* cw = mainCropWindow; - for (std::list::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_draw(const ::Cairo::RefPtr< Cairo::Context> &cr) */ if (mainCropWindow) { - //printf("MainCropWindow (%d x %d)\n", window->get_width(), window->get_height()); mainCropWindow->expose (cr); } @@ -277,11 +276,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); } } @@ -329,19 +328,18 @@ bool ImageArea::on_leave_notify_event (GdkEventCrossing* event) void ImageArea::subscribe(EditSubscriber *subscriber) { - mainCropWindow->cropHandler.setEditSubscriber(subscriber); - - for (std::list::iterator i = cropWins.begin(); i != cropWins.end(); i++) { - (*i)->cropHandler.setEditSubscriber(subscriber); - } - EditDataProvider::subscribe(subscriber); + mainCropWindow->setEditSubscriber(subscriber); + for (auto cropWin : cropWins) { + cropWin->setEditSubscriber(subscriber); + } + if (listener && listener->getToolBar()) { 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(); } @@ -357,11 +355,11 @@ void ImageArea::unsubscribe() } EditDataProvider::unsubscribe(); - // Ask the Crops to free-up edit mode buffers - mainCropWindow->cropHandler.setEditSubscriber(NULL); - for (std::list::iterator i = cropWins.begin(); i != cropWins.end(); i++) { - (*i)->cropHandler.setEditSubscriber(NULL); + // Ask the Crops to free-up edit mode buffers + mainCropWindow->setEditSubscriber(NULL); + for (auto cropWin : cropWins) { + cropWin->setEditSubscriber(NULL); } setToolHand(); @@ -475,12 +473,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 @@ -541,9 +537,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; } @@ -553,10 +548,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; } @@ -567,7 +559,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); } } @@ -620,19 +612,15 @@ 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); - } else { - mainCropWindow->zoomFit (false); + if(w != fullImageWidth || h != fullImageHeight) { + mainCropWindow->zoomFit (); } fullImageWidth = w; @@ -651,8 +639,8 @@ void ImageArea::setCropGUIListener (CropGUIListener* l) cropgl = l; - for (std::list::iterator i = cropWins.begin(); i != cropWins.end(); i++) { - (*i)->setCropGUIListener (cropgl); + for (auto cropWin : cropWins) { + cropWin->setCropGUIListener (cropgl); } if (mainCropWindow) { @@ -665,8 +653,8 @@ void ImageArea::setPointerMotionListener (PointerMotionListener* pml) pmlistener = pml; - for (std::list::iterator i = cropWins.begin(); i != cropWins.end(); i++) { - (*i)->setPointerMotionListener (pml); + for (auto cropWin : cropWins) { + cropWin->setPointerMotionListener (pml); } if (mainCropWindow) { @@ -679,8 +667,8 @@ void ImageArea::setPointerMotionHListener (PointerMotionListener* pml) pmhlistener = pml; - for (std::list::iterator i = cropWins.begin(); i != cropWins.end(); i++) { - (*i)->setPointerMotionHListener (pml); + for (auto cropWin : cropWins) { + cropWin->setPointerMotionHListener (pml); } if (mainCropWindow) { diff --git a/rtgui/imageareapanel.cc b/rtgui/imageareapanel.cc index b456de2c7..9a351d66a 100644 --- a/rtgui/imageareapanel.cc +++ b/rtgui/imageareapanel.cc @@ -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 (); } } diff --git a/rtgui/previewhandler.cc b/rtgui/previewhandler.cc index e2b635e07..9ba62230f 100644 --- a/rtgui/previewhandler.cc +++ b/rtgui/previewhandler.cc @@ -204,27 +204,14 @@ Glib::RefPtr 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 (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; - } + w = rtengine::LIM(w, 0, int(previewImg->get_width() * totalZoom) - x); + h = rtengine::LIM(h, 0, int(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; diff --git a/rtgui/previewwindow.cc b/rtgui/previewwindow.cc index a1308cb54..bc30754a4 100644 --- a/rtgui/previewwindow.cc +++ b/rtgui/previewwindow.cc @@ -111,47 +111,49 @@ void PreviewWindow::on_resized (Gtk::Allocation& req) bool PreviewWindow::on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr) { - if (backBuffer) { - int bufferW, bufferH; - bufferW = backBuffer->getWidth(); - bufferH = backBuffer->getHeight(); + if (!backBuffer) { + return true; + } - if (!mainCropWin && imageArea) { - mainCropWin = imageArea->getMainCropWindow (); + int bufferW, bufferH; + bufferW = backBuffer->getWidth(); + bufferH = backBuffer->getHeight(); - if (mainCropWin) { - mainCropWin->addCropWindowListener (this); - } + if (!mainCropWin && imageArea) { + mainCropWin = imageArea->getMainCropWindow (); + + if (mainCropWin) { + mainCropWin->addCropWindowListener (this); } + } - if ((get_width() != bufferW && get_height() != bufferH) || needsUpdate) { - needsUpdate = false; - updatePreviewImage (); - } + if ((get_width() != bufferW && get_height() != bufferH) || needsUpdate) { + needsUpdate = false; + updatePreviewImage (); + } - backBuffer->copySurface(cr, NULL); + backBuffer->copySurface(cr, NULL); - if (mainCropWin && zoom > 0.0) { - if(mainCropWin->getZoom() > mainCropWin->cropHandler.getFitZoom()) { - int x, y, w, h; - getObservedFrameArea (x, y, w, h); - double rectX = x + 0.5; - double rectY = y + 0.5; - double rectW = std::min(w, (int)(imgW - (x - imgX) - 1)); - double rectH = std::min(h, (int)(imgH - (y - imgY) - 1)); + if (mainCropWin && zoom > 0.0) { + int x, y, w, h; + getObservedFrameArea (x, y, w, h); + if (x>imgX || y>imgY || w < imgW || h < imgH) { + double rectX = x + 0.5; + double rectY = y + 0.5; + double rectW = std::min(w, (int)(imgW - (x - imgX) - 1)); + double rectH = std::min(h, (int)(imgH - (y - imgY) - 1)); - // draw a black "shadow" line - cr->set_source_rgba (0.0, 0.0, 0.0, 0.65); - cr->set_line_width (1.); - cr->set_line_join(Cairo::LINE_JOIN_MITER); - cr->rectangle (rectX + 1., rectY + 1, rectW, rectH); - cr->stroke (); + // draw a black "shadow" line + cr->set_source_rgba (0.0, 0.0, 0.0, 0.65); + cr->set_line_width (1.); + cr->set_line_join(Cairo::LINE_JOIN_MITER); + cr->rectangle (rectX + 1., rectY + 1, rectW, rectH); + cr->stroke (); - // draw a "frame" line. Color of frame line can be set in preferences - cr->set_source_rgba(options.navGuideBrush[0], options.navGuideBrush[1], options.navGuideBrush[2], options.navGuideBrush[3]); //( 1.0, 1.0, 1.0, 1.0); - cr->rectangle (rectX, rectY, rectW, rectH); - cr->stroke (); - } + // draw a "frame" line. Color of frame line can be set in preferences + cr->set_source_rgba(options.navGuideBrush[0], options.navGuideBrush[1], options.navGuideBrush[2], options.navGuideBrush[3]); //( 1.0, 1.0, 1.0, 1.0); + cr->rectangle (rectX, rectY, rectW, rectH); + cr->stroke (); } } @@ -201,10 +203,9 @@ bool PreviewWindow::on_motion_notify_event (GdkEventMotion* event) return true; } - - if(mainCropWin->getZoom() > mainCropWin->cropHandler.getFitZoom()) { - int x, y, w, h; - getObservedFrameArea (x, y, w, h); + int x, y, w, h; + getObservedFrameArea (x, y, w, h); + if (x>imgX || y>imgY || w < imgW || h < imgH) { bool inside = event->x > x - 6 && event->x < x + w - 1 + 6 && event->y > y - 6 && event->y < y + h - 1 + 6; bool moreInside = event->x > x + 6 && event->x < x + w - 1 - 6 && event->y > y + 6 && event->y < y + h - 1 - 6; @@ -212,6 +213,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) { newType = CSClosedHand; } else { @@ -234,9 +237,9 @@ bool PreviewWindow::on_button_press_event (GdkEventButton* event) return true; } - if(mainCropWin->getZoom() > mainCropWin->cropHandler.getFitZoom()) { - int x, y, w, h; - getObservedFrameArea (x, y, w, h); + int x, y, w, h; + getObservedFrameArea (x, y, w, h); + if (x>imgX || y>imgY || w < imgW || h < imgH) { bool inside = event->x > x - 6 && event->x < x + w - 1 + 6 && event->y > y - 6 && event->y < y + h - 1 + 6; bool moreInside = event->x > x + 6 && event->x < x + w - 1 - 6 && event->y > y + 6 && event->y < y + h - 1 - 6; diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index e3e5f2f6b..6198e4662 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -271,8 +271,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); @@ -319,8 +319,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 @@ -332,6 +332,23 @@ 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; + ipc->getInitialImage()->getImageSource()->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 (); @@ -353,8 +370,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); } } @@ -399,33 +416,32 @@ 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 - rtengine::ImageSource *ii = (rtengine::ImageSource*)ipc->getInitialImage(); - ii->getFullSize (fw, fh, tr); + ipc->getInitialImage()->getImageSource()->getFullSize (fw, fh, tr); 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 ); @@ -435,8 +451,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); } } @@ -444,8 +460,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); } } @@ -742,9 +758,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 diff --git a/tools/coordinate_system.svg b/tools/coordinate_system.svg index 73227e6ac..2c3efc42b 100644 --- a/tools/coordinate_system.svg +++ b/tools/coordinate_system.svg @@ -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"> + + + + + + + + + @@ -94,6 +135,27 @@ inkscape:label="Layer 1" inkscape:groupmode="layer" id="layer1"> + + + imgAreaW + x="393.50574" + y="1104.9916">imgAreaW imgAreaH + x="-931.88525" + y="925.78394">imgAreaH - leftBorder + style="font-size:14px">cropHandler.getCrop()->getLeftBorder() upperBorder + style="font-size:14px">cropHandler.getCrop()->getUpperBorder() imgX imgY + style="fill:#ffffff;fill-opacity:1;stroke:none" /> @@ -377,19 +434,19 @@ style="font-size:14px">xpos ypos - imgX + sodipodi:role="line">imgAreaX imgY - + sodipodi:role="line">imgAreaY CropWindow (mainCropWindow) + x="10.089189" + y="-4.9809637">CropWindow (mainCropWindow) CropWindow + sodipodi:role="line">CropWindow (detail) + Scaled full image + + Editing canvas = Full image + padding, Scaled + + cropHandler.getCrop()->getPadding() + + + + CropWindow class, geometry explained + + + imgX + + + + + imgY + imgAreaW + imgAreaH + + + + + + + + + imgW + + + + + + + + + + width + + + + height