Adding Picker size support and Displayed values support (RGB/HSV/LAB)
This commit is contained in:
@@ -273,6 +273,38 @@ void CropWindow::flawnOver (bool isFlawnOver)
|
|||||||
this->isFlawnOver = isFlawnOver;
|
this->isFlawnOver = isFlawnOver;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CropWindow::scroll (int state, GdkScrollDirection direction, int x, int y)
|
||||||
|
{
|
||||||
|
if ((state & GDK_CONTROL_MASK) && onArea(ColorPicker, x, y)) {
|
||||||
|
// resizing a color picker
|
||||||
|
if (direction == GDK_SCROLL_UP) {
|
||||||
|
hoveredPicker->incSize();
|
||||||
|
rtengine::Coord imgPos;
|
||||||
|
screenCoordToImage(x, y, imgPos.x, imgPos.y);
|
||||||
|
updateHoveredPicker(imgPos);
|
||||||
|
iarea->redraw ();
|
||||||
|
}else if (direction == GDK_SCROLL_DOWN) {
|
||||||
|
hoveredPicker->decSize();
|
||||||
|
rtengine::Coord imgPos;
|
||||||
|
screenCoordToImage(x, y, imgPos.x, imgPos.y);
|
||||||
|
updateHoveredPicker(imgPos);
|
||||||
|
iarea->redraw ();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// not over a color picker, we zoom in/out
|
||||||
|
int newCenterX = x;
|
||||||
|
int newCenterY = y;
|
||||||
|
|
||||||
|
screenCoordToImage(newCenterX, newCenterY, newCenterX, newCenterY);
|
||||||
|
|
||||||
|
if (direction == GDK_SCROLL_UP && !isMaxZoom()) {
|
||||||
|
zoomIn (true, newCenterX, newCenterY);
|
||||||
|
} else if (!isMinZoom()) {
|
||||||
|
zoomOut (true, newCenterX, newCenterY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CropWindow::buttonPress (int button, int type, int bstate, int x, int y)
|
void CropWindow::buttonPress (int button, int type, int bstate, int x, int y)
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -282,7 +314,7 @@ void CropWindow::buttonPress (int button, int type, int bstate, int x, int y)
|
|||||||
iarea->grabFocus (this);
|
iarea->grabFocus (this);
|
||||||
|
|
||||||
if (button == 1) {
|
if (button == 1) {
|
||||||
if (type == GDK_2BUTTON_PRESS && onArea (CropImage, x, y) && (state == SNormal || state == SCropImgMove)) {
|
if (type == GDK_2BUTTON_PRESS && onArea (CropImage, x, y) && !onArea (ColorPicker, x, y) && (state == SNormal || state == SCropImgMove)) {
|
||||||
if (fitZoomEnabled) {
|
if (fitZoomEnabled) {
|
||||||
if (fitZoom) {
|
if (fitZoom) {
|
||||||
state = SNormal;
|
state = SNormal;
|
||||||
@@ -318,23 +350,27 @@ void CropWindow::buttonPress (int button, int type, int bstate, int x, int y)
|
|||||||
if (onArea (CropImage, x, y)) { // events inside of the image domain
|
if (onArea (CropImage, x, y)) { // events inside of the image domain
|
||||||
if (iarea->getToolMode () == TMColorPicker) {
|
if (iarea->getToolMode () == TMColorPicker) {
|
||||||
if (hoveredPicker) {
|
if (hoveredPicker) {
|
||||||
// Color Picker drag starts
|
if ((bstate & GDK_CONTROL_MASK) && !(bstate & GDK_SHIFT_MASK)) {
|
||||||
state = SDragPicker;
|
hoveredPicker->decSize();
|
||||||
|
rtengine::Coord imgPos;
|
||||||
|
screenCoordToImage(x, y, imgPos.x, imgPos.y);
|
||||||
|
updateHoveredPicker(imgPos);
|
||||||
|
needRedraw = true;
|
||||||
|
} else if (!(bstate & GDK_CONTROL_MASK) && (bstate & GDK_SHIFT_MASK)) {
|
||||||
|
hoveredPicker->rollDisplayedValues();
|
||||||
|
needRedraw = true;
|
||||||
|
} else if (!(bstate & GDK_CONTROL_MASK) && !(bstate & GDK_SHIFT_MASK)) {
|
||||||
|
// Color Picker drag starts
|
||||||
|
state = SDragPicker;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Add a new Color Picker
|
// Add a new Color Picker
|
||||||
rtengine::Coord imgPos, cropPos;
|
rtengine::Coord imgPos;
|
||||||
screenCoordToImage(x, y, imgPos.x, imgPos.y);
|
screenCoordToImage(x, y, imgPos.x, imgPos.y);
|
||||||
LockableColorPicker *newPicker = new LockableColorPicker(imgPos.x, imgPos.y, LockableColorPicker::Size::S15, 0., 0., 0., this, &cropHandler.colorParams.output, &cropHandler.colorParams.working);
|
LockableColorPicker *newPicker = new LockableColorPicker(imgPos.x, imgPos.y, LockableColorPicker::Size::S15, 0., 0., 0., this, &cropHandler.colorParams.output, &cropHandler.colorParams.working);
|
||||||
colorPickers.push_back(newPicker);
|
colorPickers.push_back(newPicker);
|
||||||
hoveredPicker = newPicker;
|
hoveredPicker = newPicker;
|
||||||
imageCoordToCropImage(imgPos.x, imgPos.y, cropPos.x, cropPos.y);
|
updateHoveredPicker(imgPos);
|
||||||
float r=0.f, g=0.f, b=0.f;
|
|
||||||
LockableColorPicker::Validity validity = checkValidity (hoveredPicker, cropPos);
|
|
||||||
hoveredPicker->setValidity (validity);
|
|
||||||
if (validity == LockableColorPicker::Validity::INSIDE) {
|
|
||||||
cropHandler.colorPick(cropPos, r, g, b, hoveredPicker->getSize());
|
|
||||||
hoveredPicker->setRGB (r, g, b);
|
|
||||||
}
|
|
||||||
state = SDragPicker;
|
state = SDragPicker;
|
||||||
press_x = x;
|
press_x = x;
|
||||||
press_y = y;
|
press_y = y;
|
||||||
@@ -465,8 +501,18 @@ void CropWindow::buttonPress (int button, int type, int bstate, int x, int y)
|
|||||||
action_y = 0;
|
action_y = 0;
|
||||||
}
|
}
|
||||||
} else if (iarea->getToolMode () == TMColorPicker && hoveredPicker) {
|
} else if (iarea->getToolMode () == TMColorPicker && hoveredPicker) {
|
||||||
// Color Picker drag starts
|
if ((bstate & GDK_CONTROL_MASK) && !(bstate & GDK_SHIFT_MASK)) {
|
||||||
state = SDragPicker;
|
hoveredPicker->decSize();
|
||||||
|
rtengine::Coord imgPos;
|
||||||
|
screenCoordToImage(x, y, imgPos.x, imgPos.y);
|
||||||
|
updateHoveredPicker(imgPos);
|
||||||
|
needRedraw = true;
|
||||||
|
} else if (!(bstate & GDK_CONTROL_MASK) && (bstate & GDK_SHIFT_MASK)) {
|
||||||
|
hoveredPicker->rollDisplayedValues();
|
||||||
|
} else if (!(bstate & GDK_CONTROL_MASK) && !(bstate & GDK_SHIFT_MASK)) {
|
||||||
|
// Color Picker drag starts
|
||||||
|
state = SDragPicker;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -521,6 +567,12 @@ void CropWindow::buttonPress (int button, int type, int bstate, int x, int y)
|
|||||||
hoveredPicker = nullptr;
|
hoveredPicker = nullptr;
|
||||||
state = SDeletePicker;
|
state = SDeletePicker;
|
||||||
needRedraw = true;
|
needRedraw = true;
|
||||||
|
} else if ((bstate & GDK_CONTROL_MASK) && !(bstate & GDK_SHIFT_MASK)) {
|
||||||
|
hoveredPicker->incSize();
|
||||||
|
rtengine::Coord imgPos;
|
||||||
|
screenCoordToImage(x, y, imgPos.x, imgPos.y);
|
||||||
|
updateHoveredPicker(imgPos);
|
||||||
|
needRedraw = true;
|
||||||
} else if (!(bstate & GDK_CONTROL_MASK) && !(bstate & GDK_SHIFT_MASK)) {
|
} else if (!(bstate & GDK_CONTROL_MASK) && !(bstate & GDK_SHIFT_MASK)) {
|
||||||
// Deleting the hovered picker
|
// Deleting the hovered picker
|
||||||
for (std::vector<LockableColorPicker*>::iterator i = colorPickers.begin(); i != colorPickers.end(); i++) {
|
for (std::vector<LockableColorPicker*>::iterator i = colorPickers.begin(); i != colorPickers.end(); i++) {
|
||||||
@@ -2018,6 +2070,23 @@ void CropWindow::redrawNeeded (LWButton* button)
|
|||||||
iarea->redraw ();
|
iarea->redraw ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CropWindow::updateHoveredPicker (rtengine::Coord &imgPos)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!hoveredPicker) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rtengine::Coord cropPos;
|
||||||
|
imageCoordToCropImage(imgPos.x, imgPos.y, cropPos.x, cropPos.y);
|
||||||
|
float r=0.f, g=0.f, b=0.f;
|
||||||
|
LockableColorPicker::Validity validity = checkValidity (hoveredPicker, cropPos);
|
||||||
|
hoveredPicker->setValidity (validity);
|
||||||
|
if (validity == LockableColorPicker::Validity::INSIDE) {
|
||||||
|
cropHandler.colorPick(cropPos, r, g, b, hoveredPicker->getSize());
|
||||||
|
hoveredPicker->setRGB (r, g, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
void CropWindow::changeZoom (int zoom, bool notify, int centerx, int centery)
|
void CropWindow::changeZoom (int zoom, bool notify, int centerx, int centery)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@@ -104,6 +104,7 @@ class CropWindow : public LWButtonListener, public CropDisplayHandler, public Ed
|
|||||||
void drawUnscaledSpotRectangle (Cairo::RefPtr<Cairo::Context> cr, int rectSize);
|
void drawUnscaledSpotRectangle (Cairo::RefPtr<Cairo::Context> cr, int rectSize);
|
||||||
void drawObservedFrame (Cairo::RefPtr<Cairo::Context> cr, int rw = 0, int rh = 0);
|
void 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);
|
void changeZoom (int zoom, bool notify = true, int centerx = -1, int centery = -1);
|
||||||
|
void updateHoveredPicker (rtengine::Coord &imgPos);
|
||||||
|
|
||||||
LockableColorPicker::Validity checkValidity (LockableColorPicker* picker, const rtengine::Coord &pos);
|
LockableColorPicker::Validity checkValidity (LockableColorPicker* picker, const rtengine::Coord &pos);
|
||||||
|
|
||||||
@@ -166,6 +167,7 @@ public:
|
|||||||
bool isInside (int x, int y);
|
bool isInside (int x, int y);
|
||||||
|
|
||||||
|
|
||||||
|
void scroll (int state, GdkScrollDirection direction, int x, int y);
|
||||||
void buttonPress (int button, int num, int state, int x, int y);
|
void buttonPress (int button, int num, int state, int x, int y);
|
||||||
void buttonRelease (int button, int num, int state, int x, int y);
|
void buttonRelease (int button, int num, int state, int x, int y);
|
||||||
void pointerMoved (int bstate, int x, int y);
|
void pointerMoved (int bstate, int x, int y);
|
||||||
|
@@ -274,18 +274,8 @@ bool ImageArea::on_scroll_event (GdkEventScroll* event)
|
|||||||
{
|
{
|
||||||
|
|
||||||
CropWindow* cw = getCropWindow (event->x, event->y);
|
CropWindow* cw = getCropWindow (event->x, event->y);
|
||||||
|
|
||||||
if (cw) {
|
if (cw) {
|
||||||
int newCenterX = (int)event->x;
|
cw->scroll (event->state, event->direction, event->x, event->y);
|
||||||
int newCenterY = (int)event->y;
|
|
||||||
|
|
||||||
cw->screenCoordToImage(newCenterX, newCenterY, newCenterX, newCenterY);
|
|
||||||
|
|
||||||
if (event->direction == GDK_SCROLL_UP && !cw->isMaxZoom()) {
|
|
||||||
cw->zoomIn (true, newCenterX, newCenterY);
|
|
||||||
} else if (!cw->isMinZoom()) {
|
|
||||||
cw->zoomOut (true, newCenterX, newCenterY);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@@ -38,12 +38,12 @@ LockableColorPicker::LockableColorPicker (int x, int y, Size size, const float R
|
|||||||
r(R), g(G), b(B), L(0.f), a(0.f), bb(0.f)
|
r(R), g(G), b(B), L(0.f), a(0.f), bb(0.f)
|
||||||
{
|
{
|
||||||
float h_, s_, v_;
|
float h_, s_, v_;
|
||||||
rtengine::Color::rgb2hsv((float)r*65535.f, (float)g*65535.f, (float)b*65535.f, h_, s_, v_);
|
rtengine::Color::rgb2hsv(r*65535.f, g*65535.f, b*65535.f, h_, s_, v_);
|
||||||
h = (int)(h_*255.f);
|
h = (int)(h_*255.f);
|
||||||
s = (int)(s_*255.f);
|
s = (int)(s_*255.f);
|
||||||
v = (int)(v_*255.f);
|
v = (int)(v_*255.f);
|
||||||
|
|
||||||
rtengine::Color::rgb2lab (*outputProfile, *workingProfile, r * 0xffff / 0xff, g * 0xffff / 0xff, b * 0xffff / 0xff, L, a, bb, options.rtSettings.HistogramWorking); // TODO: Really sure this function works?
|
rtengine::Color::rgb2lab (*outputProfile, *workingProfile, r * 65535.f, g * 65535.f, b * 65535.f, L, a, bb, options.rtSettings.HistogramWorking); // TODO: Really sure this function works?
|
||||||
}
|
}
|
||||||
|
|
||||||
void LockableColorPicker::updateBackBuffer ()
|
void LockableColorPicker::updateBackBuffer ()
|
||||||
@@ -66,21 +66,29 @@ void LockableColorPicker::updateBackBuffer ()
|
|||||||
|
|
||||||
switch (displayedValues) {
|
switch (displayedValues) {
|
||||||
case ColorPickerType::RGB:
|
case ColorPickerType::RGB:
|
||||||
layout[0][0] = iArea->create_pango_layout(M("NAVIGATOR_R") + " ");
|
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[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][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[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][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)));
|
layout[2][1] = iArea->create_pango_layout(Glib::ustring::format(std::fixed, std::setprecision(0), (int)(b*255.f)));
|
||||||
break;
|
break;
|
||||||
case ColorPickerType::HSV:
|
case ColorPickerType::HSV:
|
||||||
default:
|
layout[0][0] = iArea->create_pango_layout(M("NAVIGATOR_H"));
|
||||||
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[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][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[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][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)));
|
layout[2][1] = iArea->create_pango_layout(Glib::ustring::format(std::fixed, std::setprecision(0), (int)(v*255.f)));
|
||||||
|
break;
|
||||||
|
case ColorPickerType::LAB:
|
||||||
|
default:
|
||||||
|
layout[0][0] = iArea->create_pango_layout(M("NAVIGATOR_LAB_L"));
|
||||||
|
layout[0][1] = iArea->create_pango_layout(Glib::ustring::format(std::fixed, std::setprecision(1), L));
|
||||||
|
layout[1][0] = iArea->create_pango_layout(M("NAVIGATOR_LAB_A"));
|
||||||
|
layout[1][1] = iArea->create_pango_layout(Glib::ustring::format(std::fixed, std::setprecision(1), a));
|
||||||
|
layout[2][0] = iArea->create_pango_layout(M("NAVIGATOR_LAB_B"));
|
||||||
|
layout[2][1] = iArea->create_pango_layout(Glib::ustring::format(std::fixed, std::setprecision(1), bb));
|
||||||
}
|
}
|
||||||
|
|
||||||
int w00, w01, w10, w11, w20, w21, h00, h01, h10, h11, h20, h21;
|
int w00, w01, w10, w11, w20, w21, h00, h01, h10, h11, h20, h21;
|
||||||
@@ -256,12 +264,12 @@ void LockableColorPicker::setPosition (const rtengine::Coord &newPos, const floa
|
|||||||
b = B;
|
b = B;
|
||||||
|
|
||||||
float h_, s_, v_;
|
float h_, s_, v_;
|
||||||
rtengine::Color::rgb2hsv((float)r*65535.f, (float)g*65535.f, (float)b*65535.f, h_, s_, v_);
|
rtengine::Color::rgb2hsv(r*65535.f, g*65535.f, b*65535.f, h_, s_, v_);
|
||||||
h = (float)h_;
|
h = (float)h_;
|
||||||
s = (float)s_;
|
s = (float)s_;
|
||||||
v = (float)v_;
|
v = (float)v_;
|
||||||
|
|
||||||
rtengine::Color::rgb2lab (*outputProfile, *workingProfile, r * 0xffff / 0xff, g * 0xffff / 0xff, b * 0xffff / 0xff, L, a, bb, options.rtSettings.HistogramWorking); // TODO: Really sure this function works?
|
rtengine::Color::rgb2lab (*outputProfile, *workingProfile, r * 65535.f, g * 65535.f, b * 65535.f, L, a, bb, options.rtSettings.HistogramWorking); // TODO: Really sure this function works?
|
||||||
|
|
||||||
if (validity != Validity::OUTSIDE) {
|
if (validity != Validity::OUTSIDE) {
|
||||||
setDirty(true);
|
setDirty(true);
|
||||||
@@ -279,12 +287,12 @@ void LockableColorPicker::setRGB (const float R, const float G, const float B)
|
|||||||
b = B;
|
b = B;
|
||||||
|
|
||||||
float h_, s_, v_;
|
float h_, s_, v_;
|
||||||
rtengine::Color::rgb2hsv((float)r*65535.f, (float)g*65535.f, (float)b*65535.f, h_, s_, v_);
|
rtengine::Color::rgb2hsv(r*65535.f, g*65535.f, b*65535.f, h_, s_, v_);
|
||||||
h = (float)h_;
|
h = (float)h_;
|
||||||
s = (float)s_;
|
s = (float)s_;
|
||||||
v = (float)v_;
|
v = (float)v_;
|
||||||
|
|
||||||
rtengine::Color::rgb2lab (*outputProfile, *workingProfile, r * 0xffff / 0xff, g * 0xffff / 0xff, b * 0xffff / 0xff, L, a, bb, options.rtSettings.HistogramWorking); // TODO: Really sure this function works?
|
rtengine::Color::rgb2lab (*outputProfile, *workingProfile, r * 65535.f, g * 65535.f, b * 65535.f, L, a, bb, options.rtSettings.HistogramWorking); // TODO: Really sure this function works?
|
||||||
|
|
||||||
if (validity != Validity::OUTSIDE) {
|
if (validity != Validity::OUTSIDE) {
|
||||||
setDirty(true);
|
setDirty(true);
|
||||||
@@ -340,6 +348,17 @@ LockableColorPicker::Size LockableColorPicker::getSize ()
|
|||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LockableColorPicker::rollDisplayedValues ()
|
||||||
|
{
|
||||||
|
if (displayedValues < ColorPickerType::LAB) {
|
||||||
|
displayedValues = (ColorPickerType)((int)displayedValues + 1);
|
||||||
|
} else {
|
||||||
|
displayedValues = ColorPickerType::RGB;
|
||||||
|
}
|
||||||
|
setDirty(true);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void LockableColorPicker::incSize ()
|
void LockableColorPicker::incSize ()
|
||||||
{
|
{
|
||||||
if (size < Size::S30) {
|
if (size < Size::S30) {
|
||||||
|
@@ -87,6 +87,7 @@ public:
|
|||||||
bool isOver (int x, int y);
|
bool isOver (int x, int y);
|
||||||
void setValidity (Validity isValid);
|
void setValidity (Validity isValid);
|
||||||
void setSize (Size newSize);
|
void setSize (Size newSize);
|
||||||
|
void rollDisplayedValues ();
|
||||||
void incSize ();
|
void incSize ();
|
||||||
void decSize ();
|
void decSize ();
|
||||||
};
|
};
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* This file is part of RawTherapee.
|
* This file is part of RawTherapee.
|
||||||
*
|
*
|
||||||
@@ -371,6 +372,9 @@ void ToolBar::colPicker_pressed (GdkEventButton* event)
|
|||||||
handTool->set_active (false);
|
handTool->set_active (false);
|
||||||
showColorPickers(true);
|
showColorPickers(true);
|
||||||
current = TMColorPicker;
|
current = TMColorPicker;
|
||||||
|
if (pickerListener) {
|
||||||
|
pickerListener->switchPickerVisibility (showColPickers);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Disabling the picker tool, enabling the Hand tool and keeping the "visible pickers" mode
|
// Disabling the picker tool, enabling the Hand tool and keeping the "visible pickers" mode
|
||||||
handTool->set_active (true);
|
handTool->set_active (true);
|
||||||
|
Reference in New Issue
Block a user