First patch of the LockableColorPicker tool.

Still Work In Progress, but can be used without too much hassle.
This commit is contained in:
Hombre 2016-09-30 01:03:57 +02:00
parent db6b43e3c0
commit f904bc8f84
43 changed files with 14509 additions and 97 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 685 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 833 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 851 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 645 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 796 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 810 B

View File

@ -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 <b>Shift</b> 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: <b>c</b>\nDéplacez le recadrage en utilisant Shift + Glisser
TOOLBAR_TOOLTIP_HAND;Outil de navigation\nRaccourci: <b>h</b>
TOOLBAR_TOOLTIP_STRAIGHTEN;Sélection de la ligne d'horizon\nRaccourci: <b>s</b>\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.

View File

@ -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 <b>Shift</b> 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;<b>Crop</b> selection.\nShortcut: <b>c</b>\nMove the crop area using <b>Shift-mouse drag</b>
TOOLBAR_TOOLTIP_HAND;Hand tool.\nShortcut: <b>h</b>
TOOLBAR_TOOLTIP_STRAIGHTEN;<b>Straighten</b> / <b>fine rotation</b>.\nShortcut: <b>s</b>\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.

View File

@ -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;

View File

@ -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

View File

@ -42,6 +42,10 @@ BatchToolPanelCoordinator::BatchToolPanelCoordinator (FilePanel* parent) : ToolP
toolPanels.erase (ipi);
}
if (toolBar) {
toolBar->setBatchMode ();
}
toolPanelNotebook->remove_page (*metadataPanel);
metadataPanel = 0;
toiM = 0;

View File

@ -22,6 +22,7 @@
#include <cstring>
#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)
{

View File

@ -22,6 +22,7 @@
#include "../rtengine/rtengine.h"
#include "threadutils.h"
#include "edit.h"
#include "lockablecolorpicker.h"
#include <gtkmm.h>
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;

View File

@ -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<LockableColorPicker*>::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<rtengine::Crop*>(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<Cairo::Context> 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<Cairo::Context> 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;
}

View File

@ -59,6 +59,10 @@ class CropWindow : public LWButtonListener, public CropDisplayHandler, public Ed
bool fitZoom;
bool isLowUpdatePriority;
// color pickers
std::vector<LockableColorPicker*> 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<Cairo::Context> 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

View File

@ -44,6 +44,7 @@ void CursorManager::init (Glib::RefPtr<Gdk::Window> mainWin)
Glib::RefPtr<Gdk::Pixbuf> hand = RTImage::createFromFile ("cross.png");
Glib::RefPtr<Gdk::Pixbuf> close_hand = RTImage::createFromFile ("closedhand.png");
Glib::RefPtr<Gdk::Pixbuf> wbpick = RTImage::createFromFile ("gtk-color-picker-small.png");
Glib::RefPtr<Gdk::Pixbuf> cpick = RTImage::createFromFile ("gtk-color-picker-add.png");
Glib::RefPtr<Gdk::Pixbuf> empty = RTImage::createFromFile ("empty.png");
Glib::RefPtr<Gdk::Pixbuf> move2D = RTImage::createFromFile ("move-2D.png");
Glib::RefPtr<Gdk::Pixbuf> move1DH = RTImage::createFromFile ("move-1D-h.png");
@ -52,7 +53,8 @@ void CursorManager::init (Glib::RefPtr<Gdk::Window> 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<Gdk::Window> 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) {

View File

@ -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;

View File

@ -59,7 +59,7 @@ std::vector<Glib::ustring> listSubDirs (const Glib::RefPtr<Gio::File>& 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;
}
}

View File

@ -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

View File

@ -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
};

View File

@ -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);

View File

@ -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);

View File

@ -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<Gdk::Window> 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<Gdk::Window> 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<Gdk::Window> window, GdkRectangle *rectangle)
void BackBuffer::copySurface(Glib::RefPtr<Gdk::Window> &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<Cairo::ImageSurface> destSurface, GdkRectangle *rectangle)
void BackBuffer::copySurface(Cairo::RefPtr<Cairo::ImageSurface> &destSurface, GdkRectangle *rectangle)
{
if (surface && destSurface) {
// compute the source offset
@ -1212,3 +1244,23 @@ void BackBuffer::copySurface(Cairo::RefPtr<Cairo::ImageSurface> destSurface, Gdk
}
}
void BackBuffer::copySurface(Cairo::RefPtr<Cairo::Context> &context, GdkRectangle *rectangle)
{
if (surface && context) {
// compute the source offset
int offsetX = rtengine::LIM<int>(offset.x, 0, surface->get_width());
int offsetY = rtengine::LIM<int>(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();
}
}

View File

@ -21,6 +21,7 @@
#include <gtkmm.h>
#include "../rtengine/rtengine.h"
#include "../rtengine/coord.h"
#include <sstream>
#include <iostream>
@ -382,33 +383,6 @@ public:
}
};
/**
* @brief Handle point coordinates
*/
template <class T>
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<int> 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<Cairo::ImageSurface> 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<Gdk::Window> 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<Gdk::Window> 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<Gdk::Window> window, GdkRectangle *rectangle = NULL);
void copySurface(Glib::RefPtr<Gdk::Window> &window, GdkRectangle *rectangle = NULL);
void copySurface(BackBuffer *destBackBuffer, GdkRectangle *rectangle = NULL);
void copySurface(Cairo::RefPtr<Cairo::ImageSurface> destSurface, GdkRectangle *rectangle = NULL);
void copySurface(Cairo::RefPtr<Cairo::ImageSurface> &destSurface, GdkRectangle *rectangle = NULL);
void copySurface(Cairo::RefPtr<Cairo::Context> &context, GdkRectangle *rectangle = NULL);
void setDirty(bool isDirty)
{

View File

@ -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 ()
{

View File

@ -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;

View File

@ -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;

View File

@ -0,0 +1,332 @@
/*
* This file is part of RawTherapee.
*
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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<Cairo::Context> bbcr = BackBuffer::getContext();
Glib::RefPtr<Pango::Context> 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<Pango::Layout> 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>((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<Cairo::Context> 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<Cairo::Context> &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);
}
}

View File

@ -0,0 +1,85 @@
/*
* This file is part of RawTherapee.
*
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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<Cairo::Context> &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

View File

@ -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);

View File

@ -120,6 +120,7 @@ public:
bool editorFilmStripOpened;
int historyPanelWidth;
Glib::ustring font;
Glib::ustring colorPickerFont;
int windowWidth;
int windowHeight;
int windowX;

View File

@ -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);

View File

@ -131,6 +131,7 @@ protected:
Gtk::HBox* hbtheme;
Gtk::CheckButton* chUseSystemTheme;
Gtk::FontButton* fontbutton;
Gtk::FontButton* colorPickerFontButton;
Gtk::ColorButton* butCropCol;
Gtk::ColorButton* butNavGuideCol;

View File

@ -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;
}
}

View File

@ -22,6 +22,7 @@
#include <gtkmm.h>
#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

View File

@ -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

View File

@ -294,12 +294,6 @@ public:
{
return toolBar;
}
void removeWbTool()
{
if (toolBar) {
toolBar->removeWbTool();
}
}
int getSpotWBRectSize ();
CropGUIListener* startCropEditing (Thumbnail* thm = NULL)
{

View File

@ -0,0 +1 @@
colorPickers-hide.png,w22,actions

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 141 KiB

View File

@ -0,0 +1 @@
colorPickers-show.png,w22,actions

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 147 KiB

View File

@ -0,0 +1 @@
gtk-color-picker-add.png,w22,actions

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 178 KiB