diff --git a/rtdata/images/Dark/actions/colorPickers-hide.png b/rtdata/images/Dark/actions/colorPickers-hide.png new file mode 100644 index 000000000..54b33a7fb Binary files /dev/null and b/rtdata/images/Dark/actions/colorPickers-hide.png differ diff --git a/rtdata/images/Dark/actions/colorPickers-show.png b/rtdata/images/Dark/actions/colorPickers-show.png new file mode 100644 index 000000000..d9d039c2b Binary files /dev/null and b/rtdata/images/Dark/actions/colorPickers-show.png differ diff --git a/rtdata/images/Dark/actions/gtk-color-picker-add.png b/rtdata/images/Dark/actions/gtk-color-picker-add.png new file mode 100644 index 000000000..77a30c250 Binary files /dev/null and b/rtdata/images/Dark/actions/gtk-color-picker-add.png differ diff --git a/rtdata/images/Light/actions/colorPickers-hide.png b/rtdata/images/Light/actions/colorPickers-hide.png new file mode 100644 index 000000000..434087f1c Binary files /dev/null and b/rtdata/images/Light/actions/colorPickers-hide.png differ diff --git a/rtdata/images/Light/actions/colorPickers-show.png b/rtdata/images/Light/actions/colorPickers-show.png new file mode 100644 index 000000000..d93deb3eb Binary files /dev/null and b/rtdata/images/Light/actions/colorPickers-show.png differ diff --git a/rtdata/images/Light/actions/gtk-color-picker-add.png b/rtdata/images/Light/actions/gtk-color-picker-add.png new file mode 100644 index 000000000..01d2b6a0b Binary files /dev/null and b/rtdata/images/Light/actions/gtk-color-picker-add.png differ diff --git a/rtdata/languages/Francais b/rtdata/languages/Francais index d35371458..6bec9aa46 100644 --- a/rtdata/languages/Francais +++ b/rtdata/languages/Francais @@ -988,7 +988,8 @@ PREFERENCES_REMEMBERZOOMPAN;Se souvenir de niveau de zoom et de la position de l PREFERENCES_REMEMBERZOOMPAN_TOOLTIP;Retient le niveau de zoom et la position de l'image courante lors de l'ouverture d'une nouvelle image.\n\nCette option ne fonctionne que dans le mode "Éditeur unique" et quand "Méthode de dématriçage utilisé pour l'aperçu à un zoom <100%" is set to "Idem PP3". PREFERENCES_RGBDTL_LABEL;Nombre maximum d'unités de calcul pour la Réduction du bruit PREFERENCES_RGBDTL_TOOLTIP;La réduction du bruit nécessite un minimum d'à peu près 128Mo de RAM pour une image de 10MPix ou 512Mo pour une image de 40MPix, ainsi que 128Mo de RAM supplémentaire par unité de calcul. Plus il y aura d'unités de calcul travaillant en parallèle, plus ce sera rapide. Laissez la valeur à "0" pour utiliser automatiquement autant d'unités de calcul que possible. -PREFERENCES_SELECTFONT;Police de caractère +PREFERENCES_SELECTFONT;Police générale +PREFERENCES_SELECTFONT_COLPICKER;Police des pipette à couleur PREFERENCES_SELECTLANG;Choix de la langue PREFERENCES_SELECTTHEME;Choisissez un thème PREFERENCES_SERIALIZE_TIFF_READ;Réglage de lecture des images TIFF @@ -1089,6 +1090,7 @@ THRESHOLDSELECTOR_HINT;Maintenez la touche Shift appuyée pour déplacer THRESHOLDSELECTOR_T;Haut THRESHOLDSELECTOR_TL;Haut-Gauche THRESHOLDSELECTOR_TR;Haut-droite +TOOLBAR_TOOLTIP_COLORPICKER;Ancre de Vérification Couleur\n\nLorque activé:\nCliquez la zone d'image avec le bouton gauche de la souris pour ajouter une ancre\nDéplacez-le en le "tirant" avec le bouton gauche de la souris\nSupprimez une ancre en cliquant dessus avec le bouton droit de la souris\nSupprimez toutes les ancres avec Shift + click avec le bouton droit\nCliquez avec le bouton droit de la souris en dehors de toute ancre pour revenir au mode Déplacement TOOLBAR_TOOLTIP_CROP;Sélection du recadrage\nRaccourci: c\nDéplacez le recadrage en utilisant Shift + Glisser TOOLBAR_TOOLTIP_HAND;Outil de navigation\nRaccourci: h TOOLBAR_TOOLTIP_STRAIGHTEN;Sélection de la ligne d'horizon\nRaccourci: s\n\nIndiquez la verticale ou l'horizontale en dessinant une ligne à travers l'image de prévisualisation. L'angle de rotation sera affiché près de la ligne guide. Le centre de rotation est le centre géométrique de l'image. diff --git a/rtdata/languages/default b/rtdata/languages/default index 5998c585d..870ee78e6 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1037,7 +1037,8 @@ PREFERENCES_REMEMBERZOOMPAN;Remember zoom % and pan offset PREFERENCES_REMEMBERZOOMPAN_TOOLTIP;Remember the zoom % and pan offset of the current image when opening a new image.\n\nThis option only works in "Single Editor Tab Mode" and when "Demosaicing method used for the preview at <100% zoom" is set to "As in PP3". PREFERENCES_RGBDTL_LABEL;Max number of threads for Noise Reduction and Wavelet Levels PREFERENCES_RGBDTL_TOOLTIP;Leave the setting at "0" to automatically use as many threads as possible. The more threads run in parallel, the faster the computation. Refer to RawPedia for memory requirements. -PREFERENCES_SELECTFONT;Select font +PREFERENCES_SELECTFONT;Select global font +PREFERENCES_SELECTFONT_COLPICKER;Select Color Picker's font PREFERENCES_SELECTLANG;Select language PREFERENCES_SELECTTHEME;Select theme PREFERENCES_SERIALIZE_TIFF_READ;Tiff Read Settings @@ -1140,6 +1141,7 @@ THRESHOLDSELECTOR_HINT;Hold the Shift key to move individual control poin THRESHOLDSELECTOR_T;Top THRESHOLDSELECTOR_TL;Top-left THRESHOLDSELECTOR_TR;Top-right +TOOLBAR_TOOLTIP_COLORPICKER;Lockable Color Picker\n\nWhen enabled:\nClick in the preview with left mouse button to add a color picker\nDrag it around while pressing the left mouse button\nDelete the color picker with a right mouse button click\nDelete all color pickers with Shift + Right mouse button click\nRight click away from any color picker to go back to the Hand tool TOOLBAR_TOOLTIP_CROP;Crop selection.\nShortcut: c\nMove the crop area using Shift-mouse drag TOOLBAR_TOOLTIP_HAND;Hand tool.\nShortcut: h TOOLBAR_TOOLTIP_STRAIGHTEN;Straighten / fine rotation.\nShortcut: s\n\nIndicate the vertical or horizontal by drawing a guide line over the image preview. Angle of rotation will be shown next to the guide line. Center of rotation is the geometrical center of the image. diff --git a/rtengine/coord.h b/rtengine/coord.h index 2242cec1e..0a7d78326 100644 --- a/rtengine/coord.h +++ b/rtengine/coord.h @@ -48,7 +48,10 @@ struct Coord Coord& operator+= (const Coord& other); Coord& operator-= (const Coord& other); Coord& operator*= (const double scale); - + bool operator< (const Coord& rhs) const; + bool operator> (const Coord& rhs) const; + bool operator<=(const Coord& rhs) const; + bool operator>=(const Coord& rhs) const; }; bool operator== (const Coord& lhs, const Coord& rhs); @@ -130,6 +133,26 @@ inline Coord& Coord::operator*= (const double scale) return *this; } +inline bool Coord::operator< (const Coord& rhs) const +{ + return x < rhs.x && y < rhs.y; +} + +inline bool Coord::operator> (const Coord& rhs) const +{ + return x > rhs.x && y > rhs.y; +} + +inline bool Coord::operator<=(const Coord& rhs) const +{ + return x <= rhs.x && y <= rhs.y; +} + +inline bool Coord::operator>=(const Coord& rhs) const +{ + return x >= rhs.x && y >= rhs.y; +} + inline bool operator== (const Coord& lhs, const Coord& rhs) { return lhs.x == rhs.x && lhs.y == rhs.y; diff --git a/rtgui/CMakeLists.txt b/rtgui/CMakeLists.txt index 1adc6ddd4..ad896041f 100644 --- a/rtgui/CMakeLists.txt +++ b/rtgui/CMakeLists.txt @@ -8,7 +8,7 @@ set (BASESOURCEFILES coarsepanel.cc cacorrection.cc chmixer.cc blackwhite.cc resize.cc icmpanel.cc crop.cc shadowshighlights.cc impulsedenoise.cc dirpyrdenoise.cc epd.cc - exifpanel.cc toolpanel.cc lensprofile.cc + exifpanel.cc toolpanel.cc lensprofile.cc lockablecolorpicker.cc sharpening.cc vibrance.cc rgbcurves.cc colortoning.cc whitebalance.cc vignetting.cc gradient.cc pcvignette.cc rotate.cc distortion.cc crophandler.cc dirbrowser.cc diff --git a/rtgui/batchtoolpanelcoord.cc b/rtgui/batchtoolpanelcoord.cc index 0b3d65961..004a2c812 100644 --- a/rtgui/batchtoolpanelcoord.cc +++ b/rtgui/batchtoolpanelcoord.cc @@ -42,6 +42,10 @@ BatchToolPanelCoordinator::BatchToolPanelCoordinator (FilePanel* parent) : ToolP toolPanels.erase (ipi); } + if (toolBar) { + toolBar->setBatchMode (); + } + toolPanelNotebook->remove_page (*metadataPanel); metadataPanel = 0; toiM = 0; diff --git a/rtgui/crophandler.cc b/rtgui/crophandler.cc index a76f23717..d47ec91ff 100644 --- a/rtgui/crophandler.cc +++ b/rtgui/crophandler.cc @@ -22,6 +22,7 @@ #include #include "guiutils.h" #include "cropwindow.h" +#include "imagearea.h" #include "../rtengine/dcrop.h" #include "../rtengine/refreshmap.h" #include "../rtengine/rt_math.h" @@ -188,6 +189,15 @@ void CropHandler::setZoom (int z, int centerx, int centery) } } +float CropHandler::getZoomFactor () +{ + if (zoom >= 1000) { + return zoom / 1000; + } else { + return 1.f / (float)zoom; + } +} + void CropHandler::setWSize (int w, int h) { @@ -465,6 +475,63 @@ bool CropHandler::getEnabled () return enabled; } +void CropHandler::colorPick (rtengine::Coord pickerPos, float &r, float &g, float &b, LockableColorPicker::PickerSize size) +{ + + int xSize = (int)size; + int ySize = (int)size; + int pixbufW = cropPixbuf->get_width(); + rtengine::Coord topLeftPos(pickerPos.x - xSize/2, pickerPos.y - ySize/2); + + if (topLeftPos.x > pixbufW || topLeftPos.y > pixbufW || topLeftPos.x + xSize < 0 || topLeftPos.y + ySize < 0) { + return; + } + + // Store the position of the center of the picker + int radius = (int)size / 2; + + // X/Width clip + if (topLeftPos.x < 0) { + xSize += topLeftPos.x; + topLeftPos.x = 0; + } + if (topLeftPos.x + xSize > pixbufW) { + xSize = pixbufW - topLeftPos.x; + } + // Y/Height clip + if (topLeftPos.y < 0) { + ySize += topLeftPos.y; + topLeftPos.y = 0; + } + if (topLeftPos.y + ySize > cropimg_height) { + ySize = cropimg_height - topLeftPos.y; + } + + // Accumulating the data + std::uint32_t r2=0, g2=0, b2=0; + std::uint32_t count = 0; + const guint8* data = cropPixbuf->get_pixels(); + for (int j = topLeftPos.y ; j < topLeftPos.y + ySize ; ++j) { + const guint8* data2 = data + cropPixbuf->get_rowstride()*j; + for (int i = topLeftPos.x ; i < topLeftPos.x + xSize ; ++i) { + const guint8* data3 = data2 + i*3; + rtengine::Coord currPos(i, j); + rtengine::Coord delta = pickerPos - currPos; + rtengine::PolarCoord p(delta); + if (p.radius <= radius) { + r2 += *data3; + g2 += *(data3+1); + b2 += *(data3+2); + ++count; + } + } + } + // Averaging + r = (float)r2 / (float)count / 255.f; + g = (float)g2 / (float)count / 255.f; + b = (float)b2 / (float)count / 255.f; +} + void CropHandler::getSize (int& w, int& h) { diff --git a/rtgui/crophandler.h b/rtgui/crophandler.h index 6e479bb16..2f7395216 100644 --- a/rtgui/crophandler.h +++ b/rtgui/crophandler.h @@ -22,6 +22,7 @@ #include "../rtengine/rtengine.h" #include "threadutils.h" #include "edit.h" +#include "lockablecolorpicker.h" #include class CropDisplayHandler @@ -94,23 +95,26 @@ public: } void setEditSubscriber (EditSubscriber* newSubscriber); - void newImage (rtengine::StagedImageProcessor* ipc_, bool isDetailWindow); - void setZoom (int z, int centerx = -1, int centery = -1); - double getFitZoom (); + void newImage (rtengine::StagedImageProcessor* ipc_, bool isDetailWindow); + void setZoom (int z, int centerx = -1, int centery = -1); + float getZoomFactor (); + double getFitZoom (); double getFitCropZoom(); - void setWSize (int w, int h); - void getWSize (int& w, int &h); + void setWSize (int w, int h); + void getWSize (int& w, int &h); 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 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); void setEnabled (bool e); bool getEnabled (); + void colorPick (rtengine::Coord pickerPos, float &r, float &g, float &b, LockableColorPicker::PickerSize size); + rtengine::DetailedCrop* getCrop() { return crop; diff --git a/rtgui/cropwindow.cc b/rtgui/cropwindow.cc index c4b555e8f..0a97b3158 100644 --- a/rtgui/cropwindow.cc +++ b/rtgui/cropwindow.cc @@ -30,6 +30,7 @@ #include "cursormanager.h" #include "options.h" #include "imagearea.h" +#include "lockablecolorpicker.h" using namespace rtengine; @@ -67,7 +68,7 @@ ZoomStep zoomSteps[] = { CropWindow::CropWindow (ImageArea* parent, rtengine::StagedImageProcessor* ipc_, bool isLowUpdatePriority_, bool isDetailWindow) : ObjectMOBuffer(parent), state(SNormal), press_x(0), press_y(0), action_x(0), action_y(0), pickedObject(-1), pickModifierKey(0), rot_deg(0), onResizeArea(false), deleted(false), - fitZoomEnabled(true), fitZoom(false), isLowUpdatePriority(isLowUpdatePriority_), cropLabel(Glib::ustring("100%")), + fitZoomEnabled(true), fitZoom(false), isLowUpdatePriority(isLowUpdatePriority_), hoveredPicker(nullptr), cropLabel(Glib::ustring("100%")), backColor(options.bgcolor), decorated(true), isFlawnOver(false), titleHeight(30), sideBorderWidth(3), lowerBorderWidth(3), upperBorderWidth(1), sepWidth(2), xpos(30), ypos(30), width(0), height(0), imgAreaX(0), imgAreaY(0), imgAreaW(0), imgAreaH(0), imgX(-1), imgY(-1), imgW(1), imgH(1), iarea(parent), cropZoom(0), zoomVersion(0), exposeVersion(0), cropgl(NULL), @@ -112,6 +113,13 @@ CropWindow::CropWindow (ImageArea* parent, rtengine::StagedImageProcessor* ipc_, cropHandler.newImage (ipc_, isDetailWindow); } +CropWindow::~CropWindow () +{ + for (auto colorPicker : colorPickers) { + delete colorPicker; + } +} + void CropWindow::enable() { cropHandler.setEnabled (true); @@ -308,7 +316,25 @@ void CropWindow::buttonPress (int button, int type, int bstate, int x, int y) press_y = height; } else { if (onArea (CropImage, x, y)) { // events inside of the image domain - if (onArea (CropTopLeft, x, y)) { + if (iarea->getToolMode () == TMColorPicker) { + if (hoveredPicker) { + // Color Picker drag starts + state = SDragPicker; + } else { + // Add a new Color Picker + int x2, y2; + screenCoordToImage(x, y, x2, y2); + LockableColorPicker *newPicker = new LockableColorPicker(x2, y2, LockableColorPicker::PickerSize::S15, 0., 0., 0., this); + colorPickers.push_back(newPicker); + hoveredPicker = newPicker; + state = SDragPicker; + press_x = x; + press_y = y; + action_x = 0; + action_y = 0; + needRedraw = true; + } + } else if (onArea (CropTopLeft, x, y)) { state = SResizeTL; press_x = x; action_x = cropHandler.cropParams.x; @@ -430,6 +456,9 @@ void CropWindow::buttonPress (int button, int type, int bstate, int x, int y) action_x = 0; action_y = 0; } + } else if (iarea->getToolMode () == TMColorPicker && hoveredPicker) { + // Color Picker drag starts + state = SDragPicker; } } } @@ -473,6 +502,32 @@ void CropWindow::buttonPress (int button, int type, int bstate, int x, int y) action_y = 0; } } + else if (iarea->getToolMode () == TMColorPicker && type == GDK_BUTTON_PRESS && state == SNormal) { + if (hoveredPicker) { + if((bstate & GDK_CONTROL_MASK) && (bstate & GDK_SHIFT_MASK)) { + // Deleting all pickers ! + for (auto colorPicker : colorPickers) { + delete colorPicker; + } + colorPickers.clear(); + hoveredPicker = nullptr; + state = SDeletePicker; + needRedraw = true; + } else if (!(bstate & GDK_CONTROL_MASK) && !(bstate & GDK_SHIFT_MASK)) { + // Deleting the hovered picker + for (std::vector::iterator i = colorPickers.begin(); i != colorPickers.end(); i++) { + if (*i == hoveredPicker) { + colorPickers.erase(i); + delete hoveredPicker; + hoveredPicker = nullptr; + state = SDeletePicker; + needRedraw = true; + break; + } + } + } + } + } } if (needRedraw) { @@ -602,6 +657,10 @@ void CropWindow::buttonRelease (int button, int num, int bstate, int x, int y) } else { iarea->object = 0; } + } else if (state == SDeletePicker) { + needRedraw = true; + } else if (state == SNormal && iarea->getToolMode() == TMColorPicker && !hoveredPicker && button == 3) { + iarea->setToolHand (); } if (cropgl && (state == SCropSelecting || state == SResizeH1 || state == SResizeH2 || state == SResizeW1 || state == SResizeW2 || state == SResizeTL || state == SResizeTR || state == SResizeBL || state == SResizeBR || state == SCropMove)) { @@ -620,7 +679,7 @@ void CropWindow::buttonRelease (int button, int num, int bstate, int x, int y) return; } - if (state != SEditDrag3 && state != SEditPick3 && button == 3 && !(bstate & (GDK_SHIFT_MASK|GDK_CONTROL_MASK))) { + if (state != SDeletePicker && state != SEditDrag3 && state != SEditPick3 && button == 3 && !(bstate & (GDK_SHIFT_MASK|GDK_CONTROL_MASK))) { iarea->pipetteVal[0] = iarea->pipetteVal[1] = iarea->pipetteVal[2] = -1.f; needRedraw = iarea->object == 1; @@ -778,6 +837,33 @@ void CropWindow::pointerMoved (int bstate, int x, int y) action_x = new_action_x; action_y = new_action_y; iarea->redraw (); + } else if (state == SDragPicker) { + Coord imgPos, cropPos; + action_x = x - press_x; + action_x = y - press_y; + screenCoordToImage (x, y, imgPos.x, imgPos.y); + if (imgPos.x < 0) { + imgPos.x = 0; + }else if (imgPos.x >= ipc->getFullWidth()) { + imgPos.x = ipc->getFullWidth()-1; + } + if (imgPos.y < 0) { + imgPos.y = 0; + }else if (imgPos.y >= ipc->getFullHeight()) { + imgPos.y = ipc->getFullHeight()-1; + } + imageCoordToCropImage(imgPos.x, imgPos.y, cropPos.x, cropPos.y); + float r=0.f, g=0.f, b=0.f; + bool isValid = isHoveredPickerFullyInside (cropPos); + hoveredPicker->setValidity (isValid); + if (isValid) { + cropHandler.colorPick(cropPos, r, g, b, hoveredPicker->getSize()); + } + hoveredPicker->setPosition (imgPos, r, g, b); + iarea->redraw (); + } else if (state == SNormal && iarea->getToolMode () == TMColorPicker && onArea(ColorPicker, x, y)) { + // TODO: we could set the hovered picker as Highlighted here + // Keep this if statement, the onArea will find out the hoveredPicker and will be used to update the cursor } else if (editSubscriber) { rtengine::Crop* crop = static_cast(cropHandler.getCrop()); @@ -931,6 +1017,16 @@ bool CropWindow::onArea (CursorArea a, int x, int y) case CropImage: return x >= xpos + imgX + imgAreaX && y >= ypos + imgY + imgAreaY && x < xpos + imgX + imgAreaX + imgW && y < ypos + imgY + imgAreaY + imgH; + case ColorPicker: + for (auto colorPicker : colorPickers) { + if (colorPicker->isOver(x, y)) { + hoveredPicker = colorPicker; + return true; + } + } + hoveredPicker = nullptr; + return false; + case CropBorder: return (x >= xpos + imgAreaX && y >= ypos + imgAreaY && x < xpos + imgAreaX + imgAreaW && y < ypos + imgAreaY + imgAreaH) && @@ -1048,6 +1144,8 @@ void CropWindow::updateCursor (int x, int y) cursorManager.setCursor (iarea->get_window(), CSMove); } else if (onArea (CropResize, x, y)) { cursorManager.setCursor (iarea->get_window(), CSResizeDiagonal); + } else if (tm == TMColorPicker && hoveredPicker) { + cursorManager.setCursor (iarea->get_window(), CSMove); } else if (tm == TMHand && (onArea (CropTopLeft, x, y))) { cursorManager.setCursor (iarea->get_window(), CSResizeTopLeft); } else if (tm == TMHand && (onArea (CropTopRight, x, y))) { @@ -1083,6 +1181,8 @@ void CropWindow::updateCursor (int x, int y) cursorManager.setCursor (iarea->get_window(), CSCropSelect); } else if (tm == TMStraighten) { cursorManager.setCursor (iarea->get_window(), CSStraighten); + } else if (tm == TMColorPicker) { + cursorManager.setCursor (iarea->get_window(), CSAddColPicker); } } else { int objectID = -1; @@ -1121,6 +1221,8 @@ void CropWindow::updateCursor (int x, int y) cursorManager.setCursor (iarea->get_window(), CSResizeBottomRight); } else if (state == SCropWinResize) { cursorManager.setCursor (iarea->get_window(), CSResizeDiagonal); + } else if (state == SDragPicker) { + cursorManager.setCursor (iarea->get_window(), CSMove2D); } } @@ -1674,6 +1776,12 @@ void CropWindow::expose (Cairo::RefPtr cr) } } + if ((state == SNormal || state == SDragPicker) && iarea->showColorPickers()) { + for (auto colorPicker : colorPickers) { + colorPicker->draw(cr); + } + } + //t2.set (); // printf ("etime --> %d, %d\n", t2.etime (t1), t4.etime (t3)); } @@ -1924,6 +2032,25 @@ void CropWindow::changeZoom (int zoom, bool notify, int centerx, int centery) iarea->redraw (); } +bool CropWindow::isHoveredPickerFullyInside (const rtengine::Coord &pos) +{ + + return true; + if (!cropHandler.cropPixbuf) { + return false; + } + rtengine::Coord cropPos; + rtengine::Coord pickerPos, cropPickerPos; + hoveredPicker->getImagePosition(pickerPos); + rtengine::Coord minPos(0, 0); + rtengine::Coord maxPos(cropHandler.cropPixbuf->get_width(), cropHandler.cropPixbuf->get_height()); + rtengine::Coord halfPickerSize((int)hoveredPicker->getSize()/2, (int)hoveredPicker->getSize()/2); + imageCoordToCropImage (pickerPos.x, pickerPos.y, cropPickerPos.x, cropPickerPos.y); + rtengine::Coord pickerMinPos = cropPickerPos - halfPickerSize; + rtengine::Coord pickerMaxPos = cropPickerPos + halfPickerSize; + return pickerMinPos >= minPos && pickerMaxPos <= maxPos; +} + void CropWindow::screenCoordToCropBuffer (int phyx, int phyy, int& cropx, int& cropy) { @@ -1945,8 +2072,8 @@ void CropWindow::screenCoordToImage (int phyx, int phyy, int& imgx, int& imgy) int cropX, cropY; cropHandler.getPosition (cropX, cropY); - imgx = cropX + (phyx - xpos - imgX) / zoomSteps[cropZoom].zoom; - imgy = cropY + (phyy - ypos - imgY) / zoomSteps[cropZoom].zoom; + imgx = cropX + (phyx - xpos - imgX - imgAreaX) / zoomSteps[cropZoom].zoom; + imgy = cropY + (phyy - ypos - imgY - imgAreaY) / zoomSteps[cropZoom].zoom; } void CropWindow::screenCoordToCropCanvas (int phyx, int phyy, int& prevx, int& prevy) @@ -1983,6 +2110,14 @@ void CropWindow::imageCoordToCropBuffer (int imgx, int imgy, int& phyx, int& phy phyy = (imgy - cropY) * zoomSteps[cropZoom].zoom + /*ypos + imgY +*/ crop->getUpperBorder(); } +void CropWindow::imageCoordToCropImage (int imgx, int imgy, int& phyx, int& phyy) +{ + int cropX, cropY; + cropHandler.getPosition (cropX, cropY); + phyx = (imgx - cropX) * zoomSteps[cropZoom].zoom; + phyy = (imgy - cropY) * zoomSteps[cropZoom].zoom; +} + int CropWindow::scaleValueToImage (int value) { return int(double(value) / zoomSteps[cropZoom].zoom); @@ -2220,6 +2355,14 @@ void CropWindow::drawObservedFrame (Cairo::RefPtr cr, int rw, in void CropWindow::cropImageUpdated () { + for (auto colorPicker : colorPickers) { + Coord imgPos, cropPos; + colorPicker->getImagePosition(imgPos); + imageCoordToCropImage(imgPos.x, imgPos.y, cropPos.x, cropPos.y); + float r=0.f, g=0.f, b=0.f; + cropHandler.colorPick(cropPos, r, g, b, colorPicker->getSize()); + colorPicker->setRGB (r, g, b); + } iarea->redraw (); } @@ -2281,7 +2424,7 @@ void CropWindow::delCropWindowListener (CropWindowListener* l) } } -EditDataProvider* CropWindow::getImageArea() +ImageArea* CropWindow::getImageArea() { return iarea; } diff --git a/rtgui/cropwindow.h b/rtgui/cropwindow.h index d9f738f66..d58291776 100644 --- a/rtgui/cropwindow.h +++ b/rtgui/cropwindow.h @@ -59,6 +59,10 @@ class CropWindow : public LWButtonListener, public CropDisplayHandler, public Ed bool fitZoom; bool isLowUpdatePriority; + // color pickers + std::vector colorPickers; + LockableColorPicker* hoveredPicker; + // decoration LWButton *bZoomIn, *bZoomOut, *bZoom100, /**bZoomFit,*/ *bClose; LWButtonSet buttonSet; @@ -101,12 +105,15 @@ class CropWindow : public LWButtonListener, public CropDisplayHandler, public Ed 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 isHoveredPickerFullyInside(const rtengine::Coord &pos); + // Used by the mainCropWindow only void getObservedFrameArea (int& x, int& y, int& w, int& h, int rw = 0, int rh = 0); public: CropHandler cropHandler; CropWindow (ImageArea* parent, rtengine::StagedImageProcessor* ipc_, bool isLowUpdatePriority_, bool isDetailWindow); + ~CropWindow (); void setDecorated (bool decorated) { @@ -127,6 +134,7 @@ public: 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); + void imageCoordToCropImage (int imgx, int imgy, int& phyx, int& phyy); int scaleValueToImage (int value); float scaleValueToImage (float value); double scaleValueToImage (double value); @@ -208,7 +216,7 @@ public: void remoteMove (int deltaX, int deltaY); void remoteMoveReady (); - EditDataProvider* getImageArea(); + ImageArea* getImageArea(); }; #endif diff --git a/rtgui/cursormanager.cc b/rtgui/cursormanager.cc index e011fd969..78e2513a5 100644 --- a/rtgui/cursormanager.cc +++ b/rtgui/cursormanager.cc @@ -44,6 +44,7 @@ void CursorManager::init (Glib::RefPtr mainWin) Glib::RefPtr hand = RTImage::createFromFile ("cross.png"); Glib::RefPtr close_hand = RTImage::createFromFile ("closedhand.png"); Glib::RefPtr wbpick = RTImage::createFromFile ("gtk-color-picker-small.png"); + Glib::RefPtr cpick = RTImage::createFromFile ("gtk-color-picker-add.png"); Glib::RefPtr empty = RTImage::createFromFile ("empty.png"); Glib::RefPtr move2D = RTImage::createFromFile ("move-2D.png"); Glib::RefPtr move1DH = RTImage::createFromFile ("move-1D-h.png"); @@ -52,7 +53,8 @@ void CursorManager::init (Glib::RefPtr mainWin) cHand = hand ? new Gdk::Cursor (cAdd->get_display(), hand, 10, 10) : new Gdk::Cursor (Gdk::HAND2); cClosedHand = close_hand ? new Gdk::Cursor (cAdd->get_display(), close_hand, 10, 10) : new Gdk::Cursor (Gdk::HAND2); - cWB = wbpick ? new Gdk::Cursor (cAdd->get_display(), wbpick, 1, 12) : new Gdk::Cursor (Gdk::ARROW); + cWB = wbpick ? new Gdk::Cursor (cAdd->get_display(), wbpick, 3, 15) : new Gdk::Cursor (Gdk::ARROW); + cAddPicker = cpick ? new Gdk::Cursor (cAdd->get_display(), cpick, 3, 18) : new Gdk::Cursor (Gdk::ARROW); cHidden = empty ? new Gdk::Cursor (cAdd->get_display(), empty, 12, 12) : new Gdk::Cursor (Gdk::FLEUR); cMove2D = move2D ? new Gdk::Cursor (cAdd->get_display(), move2D, 11, 11) : new Gdk::Cursor (Gdk::FLEUR); cMove1DH = move1DH ? new Gdk::Cursor (cAdd->get_display(), move1DH, 11, 11) : new Gdk::Cursor (Gdk::FLEUR); @@ -100,6 +102,8 @@ void CursorManager::setCursor (Glib::RefPtr window, CursorShape sha window->set_cursor (*cMoveRotate); } else if (shape == CSSpotWB) { window->set_cursor (*cWB); + } else if (shape == CSAddColPicker) { + window->set_cursor (*cAddPicker); } else if (shape == CSCropSelect) { window->set_cursor (*cHand); } else if (shape == CSMoveLeft) { diff --git a/rtgui/cursormanager.h b/rtgui/cursormanager.h index b51fb1e38..f256415c1 100644 --- a/rtgui/cursormanager.h +++ b/rtgui/cursormanager.h @@ -26,7 +26,7 @@ enum CursorShape { CSMoveRight, CSResizeWidth, CSResizeHeight, CSResizeDiagonal, CSResizeTopLeft, CSResizeTopRight, CSResizeBottomLeft, CSResizeBottomRight, CSMove2D, CSMove1DH, CSMove1DV, CSMoveRotate, - CSSpotWB, CSCropSelect, CSStraighten, CSPlus, CSWait, CSEmpty + CSSpotWB, CSAddColPicker, CSCropSelect, CSStraighten, CSPlus, CSWait, CSEmpty }; class CursorManager @@ -51,6 +51,7 @@ protected: Gdk::Cursor* cHand; Gdk::Cursor* cClosedHand; Gdk::Cursor* cWB; + Gdk::Cursor* cAddPicker; Gdk::Cursor* cHidden; Gdk::Cursor* cMove2D; Gdk::Cursor* cMove1DH; diff --git a/rtgui/dirbrowser.cc b/rtgui/dirbrowser.cc index d3fc8bf79..6f25f0f47 100644 --- a/rtgui/dirbrowser.cc +++ b/rtgui/dirbrowser.cc @@ -59,7 +59,7 @@ std::vector listSubDirs (const Glib::RefPtr& dir, bool } catch (const Glib::Exception& exception) { if (options.rtSettings.verbose) { - std::cerr << "Failed to list subdirectories of \"" << dir << "\": " << exception.what () << std::endl; + std::cerr << "Failed to list subdirectories of \"" << dir->get_basename() << "\": " << exception.what () << std::endl; } } diff --git a/rtgui/edit.h b/rtgui/edit.h index c49c45408..42d19ebbe 100644 --- a/rtgui/edit.h +++ b/rtgui/edit.h @@ -208,10 +208,12 @@ 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 + /// Convert the image coords to the crop's canvas coords (full image + padding) virtual void imageCoordToCropCanvas (int imgx, int imgy, int& phyx, int& phyy) = 0; - /// Convert the image coords to the edit buffer coords + /// Convert the image coords to the edit buffer coords (includes borders) virtual void imageCoordToCropBuffer (int imgx, int imgy, int& phyx, int& phyy) = 0; + /// Convert the image coords to the displayed image coords (no borders here) + virtual void imageCoordToCropImage (int imgx, int imgy, int& phyx, int& phyy) = 0; /// Convert a size value from the preview's scale to the image's scale virtual int scaleValueToImage (int value) = 0; /// Convert a size value from the preview's scale to the image's scale diff --git a/rtgui/editenums.h b/rtgui/editenums.h index 557912222..264576789 100644 --- a/rtgui/editenums.h +++ b/rtgui/editenums.h @@ -21,9 +21,9 @@ enum ImgEditState {SNormal, SCropMove, SHandMove, SResizeW1, SResizeW2, SResizeH1, SResizeH2, SResizeTL, SResizeTR, SResizeBL, SResizeBR, SCropSelecting, SRotateSelecting, SCropWinMove, SCropFrameMove, SCropImgMove, SCropWinResize, SObservedMove, - SEditDrag1, SEditDrag2, SEditDrag3, SEditPick1, SEditPick2, SEditPick3 + SEditDrag1, SEditDrag2, SEditDrag3, SEditPick1, SEditPick2, SEditPick3, SDragPicker, SDeletePicker }; -enum CursorArea {CropWinButtons, CropToolBar, CropImage, CropBorder, CropTop, CropTopLeft, CropTopRight, CropBottom, CropBottomLeft, +enum CursorArea {CropWinButtons, CropToolBar, CropImage, ColorPicker, CropBorder, CropTop, CropTopLeft, CropTopRight, CropBottom, CropBottomLeft, CropBottomRight, CropLeft, CropRight, CropInside, CropResize, CropObserved }; diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index 80dc3dfae..e8baf7730 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -313,6 +313,7 @@ EditorPanel::EditorPanel (FilePanel* filePanel) iareapanel = new ImageAreaPanel (); tpc->setEditProvider(iareapanel->imageArea); + tpc->getToolBar()->setLockablePickerToolListener(iareapanel->imageArea); Gtk::HBox* toolBarPanel = Gtk::manage (new Gtk::HBox ()); toolBarPanel->pack_start (*hidehp, Gtk::PACK_SHRINK, 1); diff --git a/rtgui/filepanel.cc b/rtgui/filepanel.cc index fd53db555..429c8f430 100644 --- a/rtgui/filepanel.cc +++ b/rtgui/filepanel.cc @@ -52,7 +52,6 @@ FilePanel::FilePanel () : parent(NULL) dirpaned->pack1 (*placespaned, false, true); tpc = new BatchToolPanelCoordinator (this); - tpc->removeWbTool(); fileCatalog = Gtk::manage ( new FileCatalog (tpc->coarse, tpc->getToolBar(), this) ); ribbonPane = Gtk::manage ( new Gtk::Paned() ); ribbonPane->add(*fileCatalog); diff --git a/rtgui/guiutils.cc b/rtgui/guiutils.cc index c984a03f1..e52c83e65 100644 --- a/rtgui/guiutils.cc +++ b/rtgui/guiutils.cc @@ -1080,11 +1080,35 @@ void TextOrIcon::switchTo(TOITypes type) BackBuffer::BackBuffer() : x(0), y(0), w(0), h(0), offset(0, 0), dirty(true) {} +void BackBuffer::setDestPosition(int x, int y) +{ + // values will be clamped when used... + this->x = x; + this->y = y; +} + void BackBuffer::setSrcOffset(int x, int y) { // values will be clamped when used... - offset.x = x; - offset.y = y; + offset.set(x, y); +} + +void BackBuffer::setSrcOffset(const rtengine::Coord &newOffset) +{ + // values will be clamped when used... + offset = newOffset; +} + +void BackBuffer::getSrcOffset(int &x, int &y) +{ + // values will be clamped when used... + offset.get(x, y); +} + +void BackBuffer::getSrcOffset(rtengine::Coord &offset) +{ + // values will be clamped when used... + offset = this->offset; } // Note: newW & newH must be > 0 @@ -1092,12 +1116,16 @@ bool BackBuffer::setDrawRectangle(Glib::RefPtr window, int newX, in { assert(newW && newH); - bool newSize = w != newW || h != newH; + bool newSize = (newW > 0 && w != newW) || (newH > 0 && h != newH); x = newX; y = newY; - w = newW; - h = newH; + if (newH > 0) { + w = newW; + } + if (newH > 0) { + h = newH; + } // WARNING: we're assuming that the surface type won't change during all the execution time of RT. I guess it may be wrong when the user change the gfx card display settings!? if (updateBackBufferSize && newSize && window) { @@ -1113,14 +1141,18 @@ bool BackBuffer::setDrawRectangle(Glib::RefPtr window, int newX, in // Note: newW & newH must be > 0 bool BackBuffer::setDrawRectangle(Cairo::Format format, int newX, int newY, int newW, int newH, bool updateBackBufferSize) { - assert(!newW && !newH); + assert(newW && newH); - bool newSize = w != newW || h != newH; + bool newSize = (newW > 0 && w != newW) || (newH > 0 && h != newH); x = newX; y = newY; - w = newW; - h = newH; + if (newH > 0) { + w = newW; + } + if (newH > 0) { + h = newH; + } // WARNING: we're assuming that the surface type won't change during all the execution time of RT. I guess it may be wrong when the user change the gfx card display settings!? if (updateBackBufferSize && newSize) { @@ -1136,7 +1168,7 @@ bool BackBuffer::setDrawRectangle(Cairo::Format format, int newX, int newY, int /* * Copy the backbuffer to a Gdk::Window */ -void BackBuffer::copySurface(Glib::RefPtr window, GdkRectangle *rectangle) +void BackBuffer::copySurface(Glib::RefPtr &window, GdkRectangle *rectangle) { if (surface && window) { // TODO: look out if window can be different on each call, and if not, store a reference to the window @@ -1190,7 +1222,7 @@ void BackBuffer::copySurface(BackBuffer *destBackBuffer, GdkRectangle *rectangle /* * Copy the BackBuffer to another Cairo::Surface */ -void BackBuffer::copySurface(Cairo::RefPtr destSurface, GdkRectangle *rectangle) +void BackBuffer::copySurface(Cairo::RefPtr &destSurface, GdkRectangle *rectangle) { if (surface && destSurface) { // compute the source offset @@ -1212,3 +1244,23 @@ void BackBuffer::copySurface(Cairo::RefPtr destSurface, Gdk } } +void BackBuffer::copySurface(Cairo::RefPtr &context, GdkRectangle *rectangle) +{ + if (surface && context) { + // compute the source offset + int offsetX = rtengine::LIM(offset.x, 0, surface->get_width()); + int offsetY = rtengine::LIM(offset.y, 0, surface->get_height()); + + // now copy the off-screen Surface to the destination Surface + context->set_source(surface, x - offsetX, y - offsetY); + context->set_line_width(0.); + + if (rectangle) { + context->rectangle(rectangle->x, rectangle->y, rectangle->width, rectangle->height); + } else { + context->rectangle(x, y, w, h); + } + + context->fill(); + } +} diff --git a/rtgui/guiutils.h b/rtgui/guiutils.h index f91bb0245..92f32204a 100644 --- a/rtgui/guiutils.h +++ b/rtgui/guiutils.h @@ -21,6 +21,7 @@ #include #include "../rtengine/rtengine.h" +#include "../rtengine/coord.h" #include #include @@ -382,33 +383,6 @@ public: } }; -/** - * @brief Handle point coordinates - */ -template -class Point -{ -public: - T x, y; - Point() - { - x = T(0); - y = T(0); - } - - Point(T coordX, T coordY) - { - x = coordX; - y = coordY; - } - - void setCoords(T coordX, T coordY) - { - x = coordX; - y = coordY; - } -}; - /** * @brief Handle backbuffers as automatically as possible */ @@ -417,7 +391,7 @@ class BackBuffer protected: int x, y, w, h; // Rectangle where the colored bar has to be drawn - Point offset; // Offset of the source region to draw, relative to the top left corner + rtengine::Coord offset; // Offset of the source region to draw, relative to the top left corner Cairo::RefPtr surface; bool dirty; // mean that the Surface has to be (re)allocated @@ -426,13 +400,19 @@ public: // set the destination drawing rectangle; return true if the dimensions are different // Note: newW & newH must be > 0 - bool setDrawRectangle(Glib::RefPtr window, int newX, int newY, int newW, int newH, bool updateBackBufferSize = true); - bool setDrawRectangle(Cairo::Format format, int newX, int newY, int newW, int newH, bool updateBackBufferSize = true); + bool setDrawRectangle(Glib::RefPtr window, int newX, int newY, int newW=-1, int newH=-1, bool updateBackBufferSize = true); + bool setDrawRectangle(Cairo::Format format, int newX, int newY, int newW=-1, int newH=-1, bool updateBackBufferSize = true); + // set the destination drawing location, do not modify other parameters like size and offset. Use setDrawRectangle to set all parameters at the same time + void setDestPosition(int x, int y); void setSrcOffset(int x, int y); + void setSrcOffset(const rtengine::Coord &newOffset); + void getSrcOffset(int &x, int &y); + void getSrcOffset(rtengine::Coord &offset); - void copySurface(Glib::RefPtr window, GdkRectangle *rectangle = NULL); + void copySurface(Glib::RefPtr &window, GdkRectangle *rectangle = NULL); void copySurface(BackBuffer *destBackBuffer, GdkRectangle *rectangle = NULL); - void copySurface(Cairo::RefPtr destSurface, GdkRectangle *rectangle = NULL); + void copySurface(Cairo::RefPtr &destSurface, GdkRectangle *rectangle = NULL); + void copySurface(Cairo::RefPtr &context, GdkRectangle *rectangle = NULL); void setDirty(bool isDirty) { diff --git a/rtgui/imagearea.cc b/rtgui/imagearea.cc index 0b757d8ec..8827d96e5 100644 --- a/rtgui/imagearea.cc +++ b/rtgui/imagearea.cc @@ -178,7 +178,6 @@ CropWindow* ImageArea::getCropWindow (int x, int y) return cw; } - void ImageArea::redraw () { // dirty prevents multiple updates queued up @@ -188,6 +187,11 @@ void ImageArea::redraw () } } +void ImageArea::switchPickerVisibility (bool isVisible) +{ + redraw(); +} + bool ImageArea::on_expose_event(GdkEventExpose* event) { dirty = false; @@ -690,6 +694,16 @@ ToolMode ImageArea::getToolMode () } } +bool ImageArea::showColorPickers () +{ + + if (listener && listener->getToolBar()) { + return listener->getToolBar()->showColorPickers (); + } else { + return false; + } +} + void ImageArea::setToolHand () { diff --git a/rtgui/imagearea.h b/rtgui/imagearea.h index bd2c19093..deabe8aa7 100644 --- a/rtgui/imagearea.h +++ b/rtgui/imagearea.h @@ -33,7 +33,7 @@ #include "edit.h" class ImageAreaPanel; -class ImageArea : public Gtk::DrawingArea, public CropWindowListener, public EditDataProvider +class ImageArea : public Gtk::DrawingArea, public CropWindowListener, public EditDataProvider, public LockablePickerToolListener { friend class ZoomPanel; @@ -122,6 +122,7 @@ public: void cropWindowSelected (CropWindow* cw); void cropWindowClosed (CropWindow* cw); ToolMode getToolMode (); + bool showColorPickers (); void setToolHand (); void straightenReady (double rotDeg); void spotWBSelected (int x, int y); @@ -143,6 +144,9 @@ public: void cropZoomChanged (CropWindow* cw); void initialImageArrived (CropWindow* cw) ; + // LockablePickerToolListener interface + void switchPickerVisibility (bool isVisible); + CropWindow* getMainCropWindow () { return mainCropWindow; diff --git a/rtgui/imageareatoollistener.h b/rtgui/imageareatoollistener.h index 3f1238810..edb93f030 100644 --- a/rtgui/imageareatoollistener.h +++ b/rtgui/imageareatoollistener.h @@ -27,6 +27,7 @@ class ImageAreaToolListener { public: + virtual ~ImageAreaToolListener() {} virtual void spotWBselected (int x, int y, Thumbnail* thm = NULL) {} virtual int getSpotWBRectSize () { @@ -38,7 +39,6 @@ public: { return NULL; } - virtual void removeWbTool() = 0; virtual CropGUIListener* startCropEditing (Thumbnail* thm = NULL) { return NULL; diff --git a/rtgui/lockablecolorpicker.cc b/rtgui/lockablecolorpicker.cc new file mode 100644 index 000000000..22383c294 --- /dev/null +++ b/rtgui/lockablecolorpicker.cc @@ -0,0 +1,332 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ + +#include "lockablecolorpicker.h" +#include "options.h" +#include "../rtengine/color.h" +#include "../rtengine/rt_math.h" +#include "imagearea.h" +#include "multilangmgr.h" + +extern Options options; + +LockableColorPicker::LockableColorPicker (CropWindow* cropWindow) +: cropWindow(cropWindow), displayedValues(ColorPickerType::RGB), position(0, 0), size(PickerSize::S20), + isValid(false), r(0.f), g(0.f), b(0.f), h(0.f), s(0.f), v(0.f) +{ +} + +LockableColorPicker::LockableColorPicker (int x, int y, PickerSize size, const float R, const float G, const float B, CropWindow* cropWindow) +: cropWindow(cropWindow), displayedValues(ColorPickerType::RGB), position(x, y), size(size), + isValid(false), r(R), g(G), b(B) +{ + float h_, s_, v_; + rtengine::Color::rgb2hsv((float)r*65535.f, (float)g*65535.f, (float)b*65535.f, h_, s_, v_); + h = (int)(h_*255.f); + s = (int)(s_*255.f); + v = (int)(v_*255.f); +} + +void LockableColorPicker::updateBackBuffer () +{ + int newW, newH; + + // -------------------- setting some key constants --------------------- + const float circlePadding = 3.f; + // --------------------------------------------------------------------- + + if (isValid) { + Gtk::DrawingArea *iArea = cropWindow->getImageArea(); + Cairo::RefPtr bbcr = BackBuffer::getContext(); + + Glib::RefPtr pangoContext = iArea->get_pango_context (); + Pango::FontDescription fontd(options.colorPickerFont); + pangoContext->set_font_description (fontd); + + // for drawing text + bbcr->set_line_width (0.); + + Glib::RefPtr layout[3][2]; + + switch (displayedValues) { + case ColorPickerType::RGB: + layout[0][0] = iArea->create_pango_layout(M("NAVIGATOR_R") + " "); + layout[0][1] = iArea->create_pango_layout(Glib::ustring::format(std::fixed, std::setprecision(0), (int)(r*255.f))); + layout[1][0] = iArea->create_pango_layout(M("NAVIGATOR_G") + " "); + layout[1][1] = iArea->create_pango_layout(Glib::ustring::format(std::fixed, std::setprecision(0), (int)(g*255.f))); + layout[2][0] = iArea->create_pango_layout(M("NAVIGATOR_B") + " "); + layout[2][1] = iArea->create_pango_layout(Glib::ustring::format(std::fixed, std::setprecision(0), (int)(b*255.f))); + break; + case ColorPickerType::HSV: + default: + layout[0][0] = iArea->create_pango_layout(M("NAVIGATOR_H") + " "); + layout[0][1] = iArea->create_pango_layout(Glib::ustring::format(std::fixed, std::setprecision(0), (int)(h*255.f))); + layout[1][0] = iArea->create_pango_layout(M("NAVIGATOR_S") + " "); + layout[1][1] = iArea->create_pango_layout(Glib::ustring::format(std::fixed, std::setprecision(0), (int)(s*255.f))); + layout[2][0] = iArea->create_pango_layout(M("NAVIGATOR_V") + " "); + layout[2][1] = iArea->create_pango_layout(Glib::ustring::format(std::fixed, std::setprecision(0), (int)(v*255.f))); + } + + int w00, w01, w10, w11, w20, w21, h00, h01, h10, h11, h20, h21; + layout[0][0]->get_pixel_size(w00, h00); + layout[1][0]->get_pixel_size(w10, h10); + layout[2][0]->get_pixel_size(w20, h20); + layout[0][1]->get_pixel_size(w01, h01); + layout[1][1]->get_pixel_size(w11, h11); + layout[2][1]->get_pixel_size(w21, h21); + int maxWCol0 = rtengine::max(w00, w10, w20); + int maxWCol1 = rtengine::max(w01, w11, w21); + int maxHRow0 = rtengine::max(h00, h01); + int maxHRow1 = rtengine::max(h10, h11); + int maxHRow2 = rtengine::max(h20, h21); + + // -------------------- setting some key constants --------------------- + const int textPadding = 2; + const int textWidth = maxWCol0 + maxWCol1 + textPadding; + const int textHeight = maxHRow0 + maxHRow1 + maxHRow2 + 2*textPadding; + const double opacity = 0.75; + // --------------------------------------------------------------------- + + newW = rtengine::max((int)size + 2 * circlePadding, textWidth + 2 * textPadding); + newH = (int)size + 2 * circlePadding + textHeight + 2 * textPadding; + + setDrawRectangle(Cairo::FORMAT_ARGB32, 0, 0, newW, newH, true); + + float center = (float)size/2.f + circlePadding; + + // black background of the whole color picker + bbcr->set_line_width (0.); + bbcr->arc_negative (center, center, center, 0.f, (float)M_PI); + bbcr->line_to (0, 2.f * center + textHeight + 2*textPadding); + bbcr->line_to (textWidth + 2*textPadding, 2.f * center + textHeight + 2*textPadding); + bbcr->line_to (textWidth + 2*textPadding, 2.f * center); + bbcr->line_to (2.f * center, 2.f * center); + bbcr->close_path(); + bbcr->set_source_rgba (0., 0., 0., opacity); + bbcr->set_line_join (Cairo::LINE_JOIN_BEVEL); + bbcr->set_line_cap (Cairo::LINE_CAP_SQUARE); + bbcr->fill (); + + // light grey circle around the color mark + bbcr->arc (center, center, center - circlePadding / 2.f - 0.5f, 0.f, 2.f * (float)M_PI); + bbcr->set_source_rgb (0.7, 0.7, 0.7); + bbcr->set_line_width (circlePadding-2.f); + bbcr->stroke (); + + // spot disc with picked color + bbcr->arc (center, center, center - circlePadding - 0.5f, 0.f, 2.f * (float)M_PI); + bbcr->set_source_rgb (r, g, b); // <- set the picker color here + bbcr->set_line_width (0.); + bbcr->fill(); + + // adding the font + bbcr->set_line_width (0.); + bbcr->set_line_join (Cairo::LINE_JOIN_ROUND); + bbcr->set_line_cap (Cairo::LINE_CAP_ROUND); + bbcr->set_source_rgb (1., 1., 1.); + double txtOffsetX = textPadding; + double txtOffsetY = (double)size + 2.f * circlePadding + textPadding; + switch (iArea->get_direction()) { + case Gtk::TEXT_DIR_RTL: + bbcr->move_to (txtOffsetX , txtOffsetY); + layout[0][1]->add_to_cairo_context (bbcr); + bbcr->fill (); + bbcr->move_to (txtOffsetX + maxWCol1 + textPadding, txtOffsetY); + layout[0][0]->add_to_cairo_context (bbcr); + bbcr->fill (); + + bbcr->move_to (txtOffsetX , txtOffsetY + maxHRow0 + textPadding); + layout[1][1]->add_to_cairo_context (bbcr); + bbcr->fill (); + bbcr->move_to (txtOffsetX + maxWCol1 + textPadding, txtOffsetY + maxHRow0 + textPadding); + layout[1][0]->add_to_cairo_context (bbcr); + bbcr->fill (); + + bbcr->move_to (txtOffsetX , txtOffsetY + maxHRow0 + maxHRow1 + 2*textPadding); + layout[2][1]->add_to_cairo_context (bbcr); + bbcr->fill (); + bbcr->move_to (txtOffsetX + maxWCol1 + textPadding, txtOffsetY + maxHRow0 + maxHRow1 + 2*textPadding); + layout[2][0]->add_to_cairo_context (bbcr); + bbcr->fill (); + break; + default: + bbcr->move_to (txtOffsetX , txtOffsetY); + layout[0][0]->add_to_cairo_context (bbcr); + bbcr->fill (); + bbcr->move_to (txtOffsetX + maxWCol0 + textPadding, txtOffsetY); + layout[0][1]->add_to_cairo_context (bbcr); + bbcr->fill (); + + bbcr->move_to (txtOffsetX , txtOffsetY + maxHRow0 + textPadding); + layout[1][0]->add_to_cairo_context (bbcr); + bbcr->fill (); + bbcr->move_to (txtOffsetX + maxWCol0 + textPadding, txtOffsetY + maxHRow0 + textPadding); + layout[1][1]->add_to_cairo_context (bbcr); + bbcr->fill (); + + bbcr->move_to (txtOffsetX , txtOffsetY + maxHRow0 + maxHRow1 + 2*textPadding); + layout[2][0]->add_to_cairo_context (bbcr); + bbcr->fill (); + bbcr->move_to (txtOffsetX + maxWCol0 + textPadding, txtOffsetY + maxHRow0 + maxHRow1 + 2*textPadding); + layout[2][1]->add_to_cairo_context (bbcr); + bbcr->fill (); + } + + anchorOffset.set (center, center); + + } else { + newH = newW = (int)size + 2 * circlePadding; + + setDrawRectangle(Cairo::FORMAT_ARGB32, 0, 0, newW, newH, true); + + Cairo::RefPtr bbcr = BackBuffer::getContext(); + + float center = (float)size/2.f + circlePadding; + bbcr->arc (center, center, center - circlePadding/2.f, 0.f, 2.f * (float)M_PI); + bbcr->set_source_rgb (0., 0., 0.); + bbcr->set_line_width(circlePadding); + bbcr->stroke_preserve(); + bbcr->set_source_rgb (1., 1., 1.); + bbcr->set_line_width(circlePadding-2.f); + bbcr->stroke (); + + anchorOffset.set (center, center); + + } + + setDirty (false); +} + +void LockableColorPicker::draw (Cairo::RefPtr &cr) +{ + if (isDirty()) { + updateBackBuffer(); + } + int px, py; + cropWindow->imageCoordToScreen(position.x, position.y, px, py); + setDestPosition(px - anchorOffset.x, py - anchorOffset.y); + + copySurface(cr); +} + +void LockableColorPicker::setPosition (const rtengine::Coord &newPos, const float R, const float G, const float B) +{ + // we're not checking bounds here, this will be done at rendering time + position = newPos; + + r = R; + g = G; + b = B; + + float h_, s_, v_; + rtengine::Color::rgb2hsv((float)r*65535.f, (float)g*65535.f, (float)b*65535.f, h_, s_, v_); + h = (float)h_; + s = (float)s_; + v = (float)v_; + + if (isValid) { + setDirty(true); + } +} + +void LockableColorPicker::setRGB (const float R, const float G, const float B) +{ + if (r==R && g==G && b==B) { + return; + } + + r = R; + g = G; + b = B; + + float h_, s_, v_; + rtengine::Color::rgb2hsv((float)r*65535.f, (float)g*65535.f, (float)b*65535.f, h_, s_, v_); + h = (float)h_; + s = (float)s_; + v = (float)v_; + + if (isValid) { + setDirty(true); + } +} + +void LockableColorPicker::getImagePosition (rtengine::Coord &imgPos) +{ + imgPos = position; +} + +void LockableColorPicker::getScreenPosition (rtengine::Coord &screenPos) +{ + if (cropWindow) { + cropWindow->imageCoordToScreen(position.x, position.y, screenPos.x, screenPos.y); + } +} + +bool LockableColorPicker::isOver (int x, int y) +{ + if (!cropWindow) { + return false; + } + rtengine::Coord pickerScreenPos; + cropWindow->imageCoordToScreen(position.x, position.y, pickerScreenPos.x, pickerScreenPos.y); + + rtengine::Coord mousePos(x, y); + rtengine::Coord wh(getWidth(), getHeight()); + rtengine::Coord tl(pickerScreenPos - anchorOffset); + rtengine::Coord br(tl + wh); + return mousePos >= tl && mousePos <= br; +} + +void LockableColorPicker::setValidity (bool isValid) +{ + if (this->isValid != isValid) { + setDirty(true); + } + this->isValid = isValid; +} + +void LockableColorPicker::setSize (PickerSize newSize) +{ + if (size != newSize) + { + size = newSize; + setDirty(true); + } +} + +LockableColorPicker::PickerSize LockableColorPicker::getSize () +{ + return size; +} + +void LockableColorPicker::incSize () +{ + if (size < PickerSize::S30) { + size = (PickerSize)((int)size + 5); + setDirty(true); + } +} + +void LockableColorPicker::decSize () +{ + if (size > PickerSize::S5) { + size = (PickerSize)((int)size - 5); + setDirty(true); + } +} diff --git a/rtgui/lockablecolorpicker.h b/rtgui/lockablecolorpicker.h new file mode 100644 index 000000000..2f79649fe --- /dev/null +++ b/rtgui/lockablecolorpicker.h @@ -0,0 +1,85 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ + +#ifndef __COLORPICKER__ +#define __COLORPICKER__ + + +#include "../rtengine/coord.h" +#include "guiutils.h" +#include "edit.h" + +class CropWindow; + +class LockablePickerToolListener { +public: + virtual ~LockablePickerToolListener () {} + + /// Callback on Color Picker's visibility switch + virtual void switchPickerVisibility (bool isVisible) {} +}; + +class LockableColorPicker : BackBuffer +{ +public: + enum class PickerSize { + S5=5, + S10=10, + S15=15, + S20=20, + S25=25, + S30=30 + }; +private: + enum class ColorPickerType { + RGB, + HSV + }; + CropWindow* cropWindow; // the color picker is displayed in a single cropWindow, the one that the user has clicked in + ColorPickerType displayedValues; + rtengine::Coord position; // Coordinate in image space + rtengine::Coord anchorOffset; + PickerSize size; + bool isValid; + float r, g, b; // red green blue in [0;1] range + float h, s, v; // hue saturation value in [0;1] range + + void updateBackBuffer (); + +public: + + LockableColorPicker (CropWindow* cropWindow); + LockableColorPicker (int x, int y, PickerSize size, const float R, const float G, const float B, CropWindow* cropWindow); + + void draw (Cairo::RefPtr &cr); + + // Used to update the RGB color, the HSV values will be updated accordingly + void setPosition (const rtengine::Coord &newPos, const float R, const float G, const float B); + void setRGB (const float R, const float G, const float B); + void getImagePosition (rtengine::Coord &imgPos); + void getScreenPosition (rtengine::Coord &screenPos); + PickerSize getSize (); + bool isOver (int x, int y); + void setValidity (bool isValid); + void setSize (PickerSize newSize); + void incSize (); + void decSize (); +}; + +#endif diff --git a/rtgui/options.cc b/rtgui/options.cc index d6a327dc8..a95275035 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -292,6 +292,7 @@ void Options::setDefaults () { font = "sans, 8"; + colorPickerFont = "sans, 8"; windowWidth = 1200; windowHeight = 680; windowX = 0; @@ -1246,6 +1247,10 @@ int Options::readFromFile (Glib::ustring fname) font = keyFile.get_string ("GUI", "Font"); } + if (keyFile.has_key ("GUI", "ColorPickerFont")) { + colorPickerFont = keyFile.get_string ("GUI", "ColorPickerFont"); + } + if (keyFile.has_key ("GUI", "WindowWidth")) { windowWidth = keyFile.get_integer ("GUI", "WindowWidth"); } @@ -1973,6 +1978,7 @@ int Options::saveToFile (Glib::ustring fname) keyFile.set_integer ("Profiles", "CustomProfileBuilderKeys", CPBKeys); keyFile.set_string ("GUI", "Font", font); + keyFile.set_string ("GUI", "ColorPickerFont", colorPickerFont); keyFile.set_integer ("GUI", "WindowWidth", windowWidth); keyFile.set_integer ("GUI", "WindowHeight", windowHeight); keyFile.set_integer ("GUI", "WindowX", windowX); diff --git a/rtgui/options.h b/rtgui/options.h index c25708674..b0cb7b987 100644 --- a/rtgui/options.h +++ b/rtgui/options.h @@ -120,6 +120,7 @@ public: bool editorFilmStripOpened; int historyPanelWidth; Glib::ustring font; + Glib::ustring colorPickerFont; int windowWidth; int windowHeight; int windowX; diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index 14c9cb0eb..e43f3f678 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -931,14 +931,21 @@ Gtk::Widget* Preferences::getGeneralPanel () hbtheme->pack_start (*fontbutton); vbftheme->pack_start(*hbtheme, Gtk::PACK_SHRINK, 0); + Gtk::Label* cpfontlab = Gtk::manage( new Gtk::Label (M("PREFERENCES_SELECTFONT_COLPICKER") + ":") ); + colorPickerFontButton = Gtk::manage( new Gtk::FontButton ()); + colorPickerFontButton->set_use_size(true); + colorPickerFontButton->set_font_name(options.colorPickerFont); + Gtk::HBox* hbcolorchooser = Gtk::manage( new Gtk::HBox () ); hbcolorchooser->set_spacing(4); hbcolorchooser->pack_start (*cutOverlayLabel, Gtk::PACK_SHRINK, 0); hbcolorchooser->pack_start (*butCropCol, Gtk::PACK_SHRINK, 0); - hbcolorchooser->pack_end (*butNavGuideCol, Gtk::PACK_SHRINK, 0); - hbcolorchooser->pack_end (*navGuideLabel, Gtk::PACK_SHRINK, 0); + hbcolorchooser->pack_start (*butNavGuideCol, Gtk::PACK_SHRINK, 0); + hbcolorchooser->pack_start (*navGuideLabel, Gtk::PACK_SHRINK, 0); + hbcolorchooser->pack_start (*cpfontlab, Gtk::PACK_EXPAND_WIDGET, 0); + hbcolorchooser->pack_start (*colorPickerFontButton, Gtk::PACK_SHRINK, 0); vbftheme->pack_start(*hbcolorchooser, Gtk::PACK_SHRINK, 0); @@ -1414,6 +1421,7 @@ void Preferences::storePreferences () moptions.navGuideBrush[3] = butNavGuideCol->get_alpha() / 65535.0; moptions.font = fontbutton->get_font_name(); + moptions.colorPickerFont = colorPickerFontButton->get_font_name(); #ifdef WIN32 moptions.gimpDir = gimpDir->get_filename (); moptions.psDir = psDir->get_filename (); @@ -1629,6 +1637,7 @@ void Preferences::fillPreferences () butNavGuideCol->set_alpha ( (unsigned short)(moptions.navGuideBrush[3] * 65535.0)); fontbutton->set_font_name(moptions.font); + colorPickerFontButton->set_font_name(moptions.colorPickerFont); showDateTime->set_active (moptions.fbShowDateTime); showBasicExif->set_active (moptions.fbShowBasicExif); showExpComp->set_active (moptions.fbShowExpComp); diff --git a/rtgui/preferences.h b/rtgui/preferences.h index 1cfb435cf..84e4ef609 100644 --- a/rtgui/preferences.h +++ b/rtgui/preferences.h @@ -131,6 +131,7 @@ protected: Gtk::HBox* hbtheme; Gtk::CheckButton* chUseSystemTheme; Gtk::FontButton* fontbutton; + Gtk::FontButton* colorPickerFontButton; Gtk::ColorButton* butCropCol; Gtk::ColorButton* butNavGuideCol; diff --git a/rtgui/toolbar.cc b/rtgui/toolbar.cc index 7a7222299..dd425a279 100644 --- a/rtgui/toolbar.cc +++ b/rtgui/toolbar.cc @@ -20,7 +20,7 @@ #include "multilangmgr.h" #include "guiutils.h" -ToolBar::ToolBar () : listener (NULL) +ToolBar::ToolBar () : showColPickers(true), listener (NULL) { editingMode = false; @@ -47,6 +47,19 @@ ToolBar::ToolBar () : listener (NULL) pack_start (*wbTool); + showcolpickersimg = Gtk::manage (new RTImage ("colorPickers-show.png")); + showcolpickersimg->reference(); + hidecolpickersimg = Gtk::manage (new RTImage ("colorPickers-hide.png")); + hidecolpickersimg->reference(); + + colPickerTool = Gtk::manage (new Gtk::ToggleButton ()); + colPickerTool->add (*showcolpickersimg); + showcolpickersimg->show (); + colPickerTool->set_relief(Gtk::RELIEF_NONE); + colPickerTool->show (); + + pack_start (*colPickerTool); + cropTool = Gtk::manage (new Gtk::ToggleButton ()); Gtk::Image* cropimg = Gtk::manage (new RTImage ("crop.png")); cropTool->add (*cropimg); @@ -71,11 +84,13 @@ ToolBar::ToolBar () : listener (NULL) handConn = handTool->signal_toggled().connect( sigc::mem_fun(*this, &ToolBar::hand_pressed)); wbConn = wbTool->signal_toggled().connect( sigc::mem_fun(*this, &ToolBar::wb_pressed)); + cpConn = colPickerTool->signal_button_press_event().connect_notify( sigc::mem_fun(*this, &ToolBar::colPicker_pressed)); cropConn = cropTool->signal_toggled().connect( sigc::mem_fun(*this, &ToolBar::crop_pressed)); straConn = straTool->signal_toggled().connect( sigc::mem_fun(*this, &ToolBar::stra_pressed)); handTool->set_tooltip_markup (M("TOOLBAR_TOOLTIP_HAND")); wbTool->set_tooltip_markup (M("TOOLBAR_TOOLTIP_WB")); + colPickerTool->set_tooltip_markup (M("TOOLBAR_TOOLTIP_COLORPICKER")); cropTool->set_tooltip_markup (M("TOOLBAR_TOOLTIP_CROP")); straTool->set_tooltip_markup (M("TOOLBAR_TOOLTIP_STRAIGHTEN")); } @@ -84,6 +99,8 @@ ToolBar::~ToolBar () { handimg->unreference(); editinghandimg->unreference(); + showcolpickersimg->unreference(); + hidecolpickersimg->unreference(); } // @@ -98,6 +115,9 @@ void ToolBar::setTool (ToolMode tool) if (wbTool) { wbConn.block (true); } + if (colPickerTool) { + cpConn.block (true); + } straConn.block (true); @@ -111,6 +131,9 @@ void ToolBar::setTool (ToolMode tool) cropTool->set_active (false); straTool->set_active (false); + if (colPickerTool) { + colPickerTool->set_active (false); + } if (tool == TMHand) { handTool->set_active (true); @@ -123,6 +146,10 @@ void ToolBar::setTool (ToolMode tool) cropTool->set_active (true); } else if (tool == TMStraighten) { straTool->set_active (true); + } else if (tool == TMColorPicker) { + if (colPickerTool) { + colPickerTool->set_active (true); + } } current = tool; @@ -133,6 +160,9 @@ void ToolBar::setTool (ToolMode tool) if (wbTool) { wbConn.block (false); } + if (colPickerTool) { + cpConn.block (false); + } straConn.block (false); @@ -181,6 +211,9 @@ void ToolBar::hand_pressed () handConn.block (true); cropConn.block (true); + if (colPickerTool) { + cpConn.block (true); + } if (wbTool) { wbConn.block (true); @@ -189,6 +222,9 @@ void ToolBar::hand_pressed () straConn.block (true); if (current != TMHand) { + if (colPickerTool) { + colPickerTool->set_active(false); + } if (wbTool) { wbTool->set_active (false); } @@ -209,7 +245,9 @@ void ToolBar::hand_pressed () handTool->set_active (true); handConn.block (false); cropConn.block (false); - + if (colPickerTool) { + cpConn.block (false); + } if (wbTool) { wbConn.block (false); } @@ -226,7 +264,9 @@ void ToolBar::wb_pressed () handConn.block (true); cropConn.block (true); - + if (colPickerTool) { + cpConn.block (true); + } if (wbTool) { wbConn.block (true); } @@ -237,6 +277,9 @@ void ToolBar::wb_pressed () handTool->set_active (false); cropTool->set_active (false); straTool->set_active (false); + if (colPickerTool) { + colPickerTool->set_active(false); + } current = TMSpotWB; } @@ -246,7 +289,9 @@ void ToolBar::wb_pressed () handConn.block (false); cropConn.block (false); - + if (colPickerTool) { + cpConn.block (false); + } if (wbTool) { wbConn.block (false); } @@ -258,11 +303,92 @@ void ToolBar::wb_pressed () } } +void ToolBar::colPicker_pressed (GdkEventButton* event) +{ + + if (event->button == 1) { + handConn.block (true); + cropConn.block (true); + cpConn.block (true); + if (wbTool) { + wbConn.block (true); + } + + straConn.block (true); + + cropTool->set_active (false); + if (wbTool) { + wbTool->set_active (false); + } + straTool->set_active (false); + + if (current != TMColorPicker) { + // Disabling all other tools, enabling the Picker tool and entering the "visible pickers" mode + handTool->set_active (false); + showColorPickers(true); + current = TMColorPicker; + } else { + // Disabling the picker tool, enabling the Hand tool and keeping the "visible pickers" mode + handTool->set_active (true); + colPickerTool->set_active (false); + current = TMHand; + } + + handConn.block (false); + cropConn.block (false); + cpConn.block (false); + wbConn.block (false); + straConn.block (false); + + if (listener) { + listener->toolSelected (current); + } + } else if (event->button == 3) { + if (current == TMColorPicker) { + // Disabling the Picker tool and entering into the "invisible pickers" mode + cpConn.block (true); + handConn.block (true); + handTool->set_active (true); + colPickerTool->set_active (false); + current = TMHand; + showColorPickers(false); + cpConn.block (false); + handConn.block (false); + } else { + // The Picker tool is already disabled, entering into the "invisible pickers" mode + switchColorPickersVisibility(); + } + if (pickerListener) { + pickerListener->switchPickerVisibility (showColPickers); + } + } +} + +bool ToolBar::showColorPickers(bool showCP) +{ + if (showColPickers != showCP) { + // Inverting the state + colPickerTool->set_image(showCP ? *showcolpickersimg : *hidecolpickersimg); + showColPickers = showCP; + return true; + } + + return false; +} + +void ToolBar::switchColorPickersVisibility() +{ + // Inverting the state + showColPickers = !showColPickers; + colPickerTool->set_image(showColPickers ? *showcolpickersimg : *hidecolpickersimg); +} + void ToolBar::crop_pressed () { handConn.block (true); cropConn.block (true); + cpConn.block(true); if (wbTool) { wbConn.block (true); @@ -272,7 +398,9 @@ void ToolBar::crop_pressed () if (current != TMCropSelect) { handTool->set_active (false); - + if (colPickerTool) { + colPickerTool->set_active(false); + } if (wbTool) { wbTool->set_active (false); } @@ -284,6 +412,7 @@ void ToolBar::crop_pressed () cropTool->set_active (true); handConn.block (false); cropConn.block (false); + cpConn.block(false); wbConn.block (false); straConn.block (false); @@ -297,6 +426,9 @@ void ToolBar::stra_pressed () handConn.block (true); cropConn.block (true); + if (colPickerTool) { + cpConn.block (true); + } if (wbTool) { wbConn.block (true); @@ -306,7 +438,9 @@ void ToolBar::stra_pressed () if (current != TMStraighten) { handTool->set_active (false); - + if (colPickerTool) { + colPickerTool->set_active(false); + } if (wbTool) { wbTool->set_active (false); } @@ -318,6 +452,7 @@ void ToolBar::stra_pressed () straTool->set_active (true); handConn.block (false); cropConn.block (false); + cpConn.block (false); if (wbTool) { wbConn.block (false); @@ -371,12 +506,17 @@ bool ToolBar::handleShortcutKey (GdkEventKey* event) return false; } -void ToolBar::removeWbTool() +void ToolBar::setBatchMode() { if (wbTool) { wbConn.disconnect(); removeIfThere(this, wbTool, false); - wbTool = NULL; + wbTool = nullptr; + } + if (colPickerTool) { + cpConn.disconnect(); + removeIfThere(this, colPickerTool, false); + colPickerTool = nullptr; } } diff --git a/rtgui/toolbar.h b/rtgui/toolbar.h index e00520721..c5bc68696 100644 --- a/rtgui/toolbar.h +++ b/rtgui/toolbar.h @@ -22,6 +22,7 @@ #include #include "toolenum.h" #include "rtimage.h" +#include "lockablecolorpicker.h" class ToolBarListener { @@ -40,17 +41,31 @@ class ToolBar : public Gtk::HBox private: RTImage* handimg; RTImage* editinghandimg; + RTImage* showcolpickersimg; + RTImage* hidecolpickersimg; + bool showColPickers; + + void hand_pressed (); + void wb_pressed (); + void colPicker_pressed (GdkEventButton* event); + void crop_pressed (); + void stra_pressed (); + bool showColorPickers(bool showCP); + void switchColorPickersVisibility(); protected: Gtk::ToggleButton* handTool; Gtk::ToggleButton* wbTool; + Gtk::ToggleButton* colPickerTool; Gtk::ToggleButton* cropTool; Gtk::ToggleButton* straTool; ToolBarListener* listener; + LockablePickerToolListener* pickerListener; ToolMode current; bool editingMode; // true if the cursor is being used to remotely edit tool's values sigc::connection handConn; sigc::connection wbConn; + sigc::connection cpConn; sigc::connection cropConn; sigc::connection straConn; @@ -64,21 +79,25 @@ public: return current; } + bool showColorPickers() { + return showColPickers; + } + void setToolBarListener (ToolBarListener* tpl) { listener = tpl; } + void setLockablePickerToolListener (LockablePickerToolListener* lptl) + { + pickerListener = lptl; + } + void startEditMode(); void stopEditMode(); - void hand_pressed (); - void wb_pressed (); - void crop_pressed (); - void stra_pressed (); - bool handleShortcutKey (GdkEventKey* event); - void removeWbTool(); + void setBatchMode(); }; #endif diff --git a/rtgui/toolenum.h b/rtgui/toolenum.h index f06fda376..06212682a 100644 --- a/rtgui/toolenum.h +++ b/rtgui/toolenum.h @@ -19,6 +19,6 @@ #ifndef _TOOLENUM_ #define _TOOLENUM_ -enum ToolMode {TMHand = 0, TMSpotWB = 1, TMCropSelect = 2, TMStraighten = 3}; +enum ToolMode {TMHand = 0, TMSpotWB = 1, TMCropSelect = 2, TMStraighten = 3, TMColorPicker = 4}; #endif diff --git a/rtgui/toolpanelcoord.h b/rtgui/toolpanelcoord.h index 46285ce3e..14774df48 100644 --- a/rtgui/toolpanelcoord.h +++ b/rtgui/toolpanelcoord.h @@ -294,12 +294,6 @@ public: { return toolBar; } - void removeWbTool() - { - if (toolBar) { - toolBar->removeWbTool(); - } - } int getSpotWBRectSize (); CropGUIListener* startCropEditing (Thumbnail* thm = NULL) { diff --git a/tools/source_icons/scalable/colorPickers-hide.file b/tools/source_icons/scalable/colorPickers-hide.file new file mode 100644 index 000000000..728529716 --- /dev/null +++ b/tools/source_icons/scalable/colorPickers-hide.file @@ -0,0 +1 @@ +colorPickers-hide.png,w22,actions diff --git a/tools/source_icons/scalable/colorPickers-hide.svg b/tools/source_icons/scalable/colorPickers-hide.svg new file mode 100644 index 000000000..fe0c7bf14 --- /dev/null +++ b/tools/source_icons/scalable/colorPickers-hide.svg @@ -0,0 +1,4301 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/tools/source_icons/scalable/colorPickers-show.file b/tools/source_icons/scalable/colorPickers-show.file new file mode 100644 index 000000000..96db803fc --- /dev/null +++ b/tools/source_icons/scalable/colorPickers-show.file @@ -0,0 +1 @@ +colorPickers-show.png,w22,actions diff --git a/tools/source_icons/scalable/colorPickers-show.svg b/tools/source_icons/scalable/colorPickers-show.svg new file mode 100644 index 000000000..d03472020 --- /dev/null +++ b/tools/source_icons/scalable/colorPickers-show.svg @@ -0,0 +1,4372 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/source_icons/scalable/gtk-color-picker-add.file b/tools/source_icons/scalable/gtk-color-picker-add.file new file mode 100644 index 000000000..f51e051bd --- /dev/null +++ b/tools/source_icons/scalable/gtk-color-picker-add.file @@ -0,0 +1 @@ +gtk-color-picker-add.png,w22,actions diff --git a/tools/source_icons/scalable/gtk-color-picker-add.svg b/tools/source_icons/scalable/gtk-color-picker-add.svg new file mode 100644 index 000000000..a12197ffe --- /dev/null +++ b/tools/source_icons/scalable/gtk-color-picker-add.svg @@ -0,0 +1,4839 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +