Pipette and "On Preview Widgets" branch. See issue 227
The pipette part is already working quite nice but need to be finished. The widgets part needs more work...
This commit is contained in:
670
rtgui/thresholdselector.cc
Normal file
670
rtgui/thresholdselector.cc
Normal file
@@ -0,0 +1,670 @@
|
||||
/*
|
||||
* 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 "thresholdselector.h"
|
||||
#include "multilangmgr.h"
|
||||
#include <cassert>
|
||||
#include "mycurve.h"
|
||||
|
||||
ThresholdSelector::ThresholdSelector(double minValueBottom, double maxValueBottom, double defBottom, Glib::ustring labelBottom, unsigned int precisionBottom,
|
||||
double minValueTop, double maxValueTop, double defTop, Glib::ustring labelTop, unsigned int precisionTop,
|
||||
ThresholdCurveProvider* curveProvider)
|
||||
: ColoredBar(RTO_Left2Right)
|
||||
{
|
||||
positions[TS_BOTTOMLEFT] = defPos[TS_BOTTOMLEFT] = defBottom;
|
||||
positions[TS_TOPLEFT] = defPos[TS_TOPLEFT] = defTop;
|
||||
positions[TS_BOTTOMRIGHT] = defPos[TS_BOTTOMRIGHT] = 0; // unused
|
||||
positions[TS_TOPRIGHT] = defPos[TS_TOPRIGHT] = 0; // unused
|
||||
this->precisionTop = precisionTop;
|
||||
this->precisionBottom = precisionBottom;
|
||||
doubleThresh = false;
|
||||
|
||||
separatedLabelBottom = labelBottom;
|
||||
separatedLabelTop = labelTop;
|
||||
|
||||
bgCurveProvider = curveProvider;
|
||||
separatedSliders = true;
|
||||
initalEq1 = false; // unused
|
||||
minValBottom = minValueBottom;
|
||||
maxValBottom = maxValueBottom;
|
||||
minValTop = minValueTop;
|
||||
maxValTop = maxValueTop;
|
||||
|
||||
initValues ();
|
||||
}
|
||||
|
||||
ThresholdSelector::ThresholdSelector(double minValue, double maxValue, double defBottom,
|
||||
double defTop, unsigned int precision, bool startAtOne)
|
||||
: ColoredBar(RTO_Left2Right)
|
||||
{
|
||||
positions[TS_BOTTOMLEFT] = defPos[TS_BOTTOMLEFT] = defBottom;
|
||||
positions[TS_TOPLEFT] = defPos[TS_TOPLEFT] = defTop;
|
||||
positions[TS_BOTTOMRIGHT] = defPos[TS_BOTTOMRIGHT] = maxValue;
|
||||
positions[TS_TOPRIGHT] = defPos[TS_TOPRIGHT] = maxValue;
|
||||
this->precisionTop = precision;
|
||||
this->precisionBottom = precision;
|
||||
doubleThresh = false;
|
||||
|
||||
separatedLabelBottom = "";
|
||||
separatedLabelTop = "";
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (startAtOne) {
|
||||
assert (defBottom >= defTop);
|
||||
assert (defTop >= minValue);
|
||||
assert (defBottom <= maxValue);
|
||||
}
|
||||
else {
|
||||
assert (defTop >= defBottom);
|
||||
assert (defBottom >= minValue);
|
||||
assert (defTop <= maxValue);
|
||||
}
|
||||
assert(minValue < maxValue);
|
||||
#endif
|
||||
|
||||
bgCurveProvider = NULL;
|
||||
separatedSliders = false;
|
||||
initalEq1 = startAtOne;
|
||||
minValTop = minValBottom = minValue;
|
||||
maxValTop = maxValBottom = maxValue;
|
||||
|
||||
initValues ();
|
||||
|
||||
}
|
||||
|
||||
ThresholdSelector::ThresholdSelector(double minValue, double maxValue, double defBottomLeft, double defTopLeft,
|
||||
double defBottomRight, double defTopRight, unsigned int precision, bool startAtOne)
|
||||
: ColoredBar(RTO_Left2Right)
|
||||
{
|
||||
positions[TS_BOTTOMLEFT] = defPos[TS_BOTTOMLEFT] = defBottomLeft;
|
||||
positions[TS_TOPLEFT] = defPos[TS_TOPLEFT] = defTopLeft;
|
||||
positions[TS_BOTTOMRIGHT] = defPos[TS_BOTTOMRIGHT] = defBottomRight;
|
||||
positions[TS_TOPRIGHT] = defPos[TS_TOPRIGHT] = defTopRight;
|
||||
this->precisionTop = precision;
|
||||
this->precisionBottom = precision;
|
||||
doubleThresh = true;
|
||||
|
||||
separatedLabelBottom = "";
|
||||
separatedLabelTop = "";
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (startAtOne) {
|
||||
assert (minValue <= defTopLeft);
|
||||
assert (defTopLeft <= defBottomLeft);
|
||||
assert (defBottomLeft <= defBottomRight);
|
||||
assert (defBottomRight <= defTopRight);
|
||||
assert (defTopRight <= maxValue);
|
||||
}
|
||||
else {
|
||||
assert (minValue <= defBottomLeft);
|
||||
assert (defBottomLeft <= defTopLeft);
|
||||
assert (defTopLeft <= defTopRight);
|
||||
assert (defTopRight <= defBottomRight);
|
||||
assert (defBottomRight <= maxValue);
|
||||
}
|
||||
assert(minValue < maxValue);
|
||||
#endif
|
||||
|
||||
bgCurveProvider = NULL;
|
||||
separatedSliders = false;
|
||||
initalEq1 = startAtOne;
|
||||
minValTop = minValBottom = minValue;
|
||||
maxValTop = maxValBottom = maxValue;
|
||||
|
||||
initValues ();
|
||||
}
|
||||
|
||||
void ThresholdSelector::initValues () {
|
||||
|
||||
additionalTTip = "";
|
||||
oldLitCursor = litCursor = TS_UNDEFINED;
|
||||
movedCursor = TS_UNDEFINED;
|
||||
secondaryMovedCursor = TS_UNDEFINED;
|
||||
set_size_request (-1, 30);
|
||||
add_events(Gdk::LEAVE_NOTIFY_MASK);
|
||||
set_name("ThresholdSelector");
|
||||
set_can_focus(false);
|
||||
set_app_paintable(true);
|
||||
updateTooltip();
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the position of the sliders without telling it to the listener
|
||||
*/
|
||||
void ThresholdSelector::setPositions (double bottom, double top) {
|
||||
|
||||
setPositions(bottom, top, maxValBottom, maxValTop);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the position of the sliders without telling it to the listener
|
||||
*/
|
||||
void ThresholdSelector::setPositions (double bottomLeft, double topLeft, double bottomRight, double topRight) {
|
||||
|
||||
bool different = ( (positions[TS_TOPLEFT] != topLeft) || (positions[TS_TOPRIGHT] != topRight) ||
|
||||
(positions[TS_BOTTOMLEFT] != bottomLeft) || (positions[TS_BOTTOMRIGHT] != bottomRight) );
|
||||
positions[TS_BOTTOMLEFT] = bottomLeft;
|
||||
positions[TS_TOPLEFT] = topLeft;
|
||||
positions[TS_BOTTOMRIGHT] = bottomRight;
|
||||
positions[TS_TOPRIGHT] = topRight;
|
||||
|
||||
if (different) {
|
||||
sig_val_changed.emit();
|
||||
updateTooltip();
|
||||
queue_draw ();
|
||||
}
|
||||
}
|
||||
|
||||
void ThresholdSelector::setDefaults (double bottom, double top) {
|
||||
|
||||
setDefaults(bottom, top, maxValBottom, maxValTop);
|
||||
}
|
||||
|
||||
void ThresholdSelector::setDefaults (double bottomLeft, double topLeft, double bottomRight, double topRight) {
|
||||
|
||||
defPos[TS_BOTTOMLEFT] = bottomLeft;
|
||||
defPos[TS_TOPLEFT] = topLeft;
|
||||
if (doubleThresh) {
|
||||
defPos[TS_BOTTOMRIGHT] = bottomRight;
|
||||
defPos[TS_TOPRIGHT] = topRight;
|
||||
}
|
||||
}
|
||||
|
||||
void ThresholdSelector::on_realize() {
|
||||
|
||||
Gtk::DrawingArea::on_realize();
|
||||
|
||||
add_events(Gdk::EXPOSURE_MASK | Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK);
|
||||
}
|
||||
|
||||
bool ThresholdSelector::on_expose_event(GdkEventExpose* event) {
|
||||
|
||||
Gdk::Color c;
|
||||
Glib::RefPtr<Gdk::Window> win = get_window();
|
||||
Cairo::RefPtr<Cairo::Context> cr = win->create_cairo_context();
|
||||
|
||||
double positions01[4];
|
||||
int w = get_width ();
|
||||
int h = get_height ();
|
||||
|
||||
wslider = std::max(int(h / 5), 10);
|
||||
int hwslider = wslider/2;
|
||||
int iw = w-wslider-2*hb; // inner width (excluding padding for sliders)
|
||||
|
||||
positions01[TS_BOTTOMLEFT] = to01(TS_BOTTOMLEFT);
|
||||
positions01[TS_TOPLEFT] = to01(TS_TOPLEFT);
|
||||
positions01[TS_BOTTOMRIGHT] = to01(TS_BOTTOMRIGHT);
|
||||
positions01[TS_TOPRIGHT] = to01(TS_TOPRIGHT);
|
||||
|
||||
Gtk::StateType state = !is_sensitive() ? Gtk::STATE_INSENSITIVE : Gtk::STATE_NORMAL;
|
||||
Glib::RefPtr<Gtk::Style> style = get_style();
|
||||
|
||||
// set the box's colors
|
||||
cr->set_line_width (1.0);
|
||||
cr->set_line_cap(Cairo::LINE_CAP_BUTT);
|
||||
if (is_sensitive() && canGetColors()) {
|
||||
// gradient background
|
||||
Glib::RefPtr<Gdk::Window> win = get_window();
|
||||
// this will eventually create/update the off-screen Surface
|
||||
setDrawRectangle(win, hb+hwslider, int(float(h)*1.5f/7.f+0.5f), iw+1, int(float(h)*4.f/7.f+0.5f));
|
||||
// that we're displaying here
|
||||
ColoredBar::expose(win);
|
||||
}
|
||||
else {
|
||||
// solid background
|
||||
c = style->get_bg (state);
|
||||
cr->set_source_rgb (c.get_red_p()*0.85, c.get_green_p()*0.85, c.get_blue_p()*0.85);
|
||||
|
||||
// draw the box's background
|
||||
cr->rectangle (hb+hwslider-0.5, double(int(float(h)*1.5f/7.f))+0.5, iw+1, double(int(float(h)*4.f/7.f)));
|
||||
cr->fill();
|
||||
}
|
||||
|
||||
// draw curve
|
||||
|
||||
if (bgCurveProvider) {
|
||||
double yStart = double(int(float(h)*5.5f/7.f))-0.5;
|
||||
double yEnd = double(int(float(h)*1.5f/7.f))+1.5;
|
||||
|
||||
std::vector<double> pts = bgCurveProvider->getCurvePoints(this); // the values sent by the provider are not checked (assumed to be correct)
|
||||
if (pts.size() >= 4) {
|
||||
std::vector<double>::iterator i=pts.begin();
|
||||
double x = *i; i++;
|
||||
double y = *i; i++;
|
||||
cr->move_to (hb+hwslider+iw*x+0.5, (yEnd-yStart)*y+yStart);
|
||||
|
||||
for (; i<pts.end(); ) {
|
||||
x = *i; i++;
|
||||
y = *i; i++;
|
||||
cr->line_to (hb+hwslider+iw*x+0.5, (yEnd-yStart)*y+yStart);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Draw a straight line because not enough points has been sent
|
||||
double yStart = double(int(float(h)*5.5f/7.f))-0.5;
|
||||
cr->move_to (hb+hwslider+0.5, yStart);
|
||||
cr->line_to (hb+hwslider+iw+0.5, yStart);
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
double yStart = initalEq1 ? double(int(float(h)*1.5f/7.f))+1.5 : double(int(float(h)*5.5f/7.f))-0.5;
|
||||
double yEnd = initalEq1 ? double(int(float(h)*5.5f/7.f))-0.5 : double(int(float(h)*1.5f/7.f))+1.5;
|
||||
ThreshCursorId p[4];
|
||||
if (initalEq1) { p[0] = TS_TOPLEFT; p[1] = TS_BOTTOMLEFT; p[2] = TS_BOTTOMRIGHT; p[3] = TS_TOPRIGHT; }
|
||||
else { p[0] = TS_BOTTOMLEFT; p[1] = TS_TOPLEFT; p[2] = TS_TOPRIGHT; p[3] = TS_BOTTOMRIGHT; }
|
||||
if (positions[p[1]] > minValTop) // we use minValTop since if this block is executed, it means that we are in a simple Threshold where both bottom and top range are the same
|
||||
cr->move_to (hb+hwslider, yStart);
|
||||
else
|
||||
cr->move_to (hb+hwslider, yEnd);
|
||||
if (positions[p[0]] > minValTop)
|
||||
cr->line_to (hb+hwslider+iw*positions01[p[0]]+0.5, yStart);
|
||||
if (positions[p[1]] > minValTop)
|
||||
cr->line_to (hb+hwslider+iw*positions01[p[1]]+0.5, yEnd);
|
||||
cr->line_to (hb+hwslider+iw*positions01[p[2]]+0.5, yEnd);
|
||||
if (doubleThresh && positions[p[2]] < maxValTop) {
|
||||
cr->line_to (hb+hwslider+iw*positions01[p[3]]+0.5, yStart);
|
||||
if (positions[p[3]] < maxValTop)
|
||||
cr->line_to (hb+hwslider+iw+0.5, yStart);
|
||||
}
|
||||
}
|
||||
if (is_sensitive() && bgGradient.size()>1) {
|
||||
// draw surrounding curve
|
||||
c = style->get_bg (state);
|
||||
cr->set_source_rgb (c.get_red_p()*0.85, c.get_green_p()*0.85, c.get_blue_p()*0.85);
|
||||
cr->set_line_width (5.0);
|
||||
cr->stroke_preserve();
|
||||
}
|
||||
// draw curve
|
||||
if (is_sensitive()) {
|
||||
c = style->get_fg (movedCursor!=TS_UNDEFINED || litCursor!=TS_UNDEFINED ? Gtk::STATE_PRELIGHT : Gtk::STATE_ACTIVE);
|
||||
cr->set_source_rgb (c.get_red_p(), c.get_green_p(), c.get_blue_p());
|
||||
}
|
||||
else {
|
||||
c = style->get_bg (Gtk::STATE_INSENSITIVE);
|
||||
cr->set_source_rgb (c.get_red_p()*0.7, c.get_green_p()*0.7, c.get_blue_p()*0.7);
|
||||
}
|
||||
cr->set_line_width (1.5);
|
||||
cr->stroke ();
|
||||
|
||||
// draw the box's borders
|
||||
cr->set_line_width (1.);
|
||||
cr->rectangle (hb+hwslider-0.5, double(int(float(h)*1.5f/7.f))+0.5, iw+1, double(int(float(h)*4.f/7.f)));
|
||||
c = style->get_bg (state);
|
||||
cr->set_source_rgb (c.get_red_p()*0.7, c.get_green_p()*0.7, c.get_blue_p()*0.7);
|
||||
cr->stroke ();
|
||||
|
||||
// draw sliders
|
||||
//if (!(litCursor == TS_UNDEFINED && movedCursor == TS_UNDEFINED)) {
|
||||
//cr->set_line_width (1.);
|
||||
for (int i=0; i<(doubleThresh?4:2); i++) {
|
||||
double posX = hb+hwslider+iw*positions01[i]+0.5;
|
||||
double arrowY = i==0 || i==2 ? h-(h*2.5/7.-0.5)-vb : h*2.5/7.-0.5+vb;
|
||||
double baseY = i==0 || i==2 ? h-0.5-vb : 0.5+vb;
|
||||
double centerY = (arrowY+baseY)/2.;
|
||||
cr->move_to (posX, arrowY);
|
||||
cr->line_to (posX+hwslider, centerY);
|
||||
cr->line_to (posX+hwslider, baseY);
|
||||
cr->line_to (posX-hwslider, baseY);
|
||||
cr->line_to (posX-hwslider, centerY);
|
||||
cr->close_path();
|
||||
if (i==movedCursor) {
|
||||
// moved (selected)
|
||||
c = style->get_bg (Gtk::STATE_SELECTED);
|
||||
cr->set_source_rgb (c.get_red_p(), c.get_green_p(), c.get_blue_p());
|
||||
cr->fill_preserve ();
|
||||
//c = style->get_dark (Gtk::STATE_SELECTED);
|
||||
//cr->set_source_rgb (c.get_red_p(), c.get_green_p(), c.get_blue_p());
|
||||
c = style->get_bg (state);
|
||||
cr->set_source_rgb (c.get_red_p()*0.55, c.get_green_p()*0.55, c.get_blue_p()*0.55);
|
||||
cr->stroke ();
|
||||
}
|
||||
else if (i==secondaryMovedCursor || (movedCursor==TS_UNDEFINED && i==litCursor)) {
|
||||
// prelight
|
||||
c = style->get_bg (Gtk::STATE_PRELIGHT);
|
||||
cr->set_source_rgb (c.get_red_p(), c.get_green_p(), c.get_blue_p());
|
||||
cr->fill_preserve ();
|
||||
c = style->get_bg (state);
|
||||
cr->set_source_rgb (c.get_red_p()*0.55, c.get_green_p()*0.55, c.get_blue_p()*0.55);
|
||||
cr->stroke ();
|
||||
}
|
||||
else {
|
||||
// normal
|
||||
c = style->get_bg (is_sensitive() ? Gtk::STATE_ACTIVE : Gtk::STATE_INSENSITIVE);
|
||||
cr->set_source_rgb (c.get_red_p(), c.get_green_p(), c.get_blue_p());
|
||||
cr->fill_preserve ();
|
||||
c = style->get_bg (state);
|
||||
cr->set_source_rgb (c.get_red_p()*0.7, c.get_green_p()*0.7, c.get_blue_p()*0.7);
|
||||
cr->stroke ();
|
||||
}
|
||||
}
|
||||
//}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThresholdSelector::on_button_press_event (GdkEventButton* event) {
|
||||
|
||||
if (event->button == 1) {
|
||||
movedCursor = litCursor;
|
||||
findSecondaryMovedCursor(event->state);
|
||||
tmpX = event->x;
|
||||
|
||||
queue_draw ();
|
||||
}
|
||||
grab_focus();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThresholdSelector::on_button_release_event (GdkEventButton* event) {
|
||||
|
||||
if (event->button == 1) {
|
||||
findLitCursor(event->x, event->y);
|
||||
movedCursor = TS_UNDEFINED;
|
||||
secondaryMovedCursor = TS_UNDEFINED;
|
||||
queue_draw ();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThresholdSelector::on_leave_notify_event (GdkEventCrossing* event) {
|
||||
if (movedCursor == TS_UNDEFINED) {
|
||||
litCursor = TS_UNDEFINED;
|
||||
oldLitCursor = TS_UNDEFINED;
|
||||
queue_draw();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThresholdSelector::on_motion_notify_event (GdkEventMotion* event) {
|
||||
|
||||
int w = get_width ();
|
||||
|
||||
findLitCursor(event->x, event->y);
|
||||
|
||||
if (movedCursor != TS_UNDEFINED) {
|
||||
// user is moving a cursor or two
|
||||
double minBound, maxBound, dRange;
|
||||
|
||||
findSecondaryMovedCursor(event->state);
|
||||
|
||||
// computing the boundaries
|
||||
findBoundaries(minBound, maxBound);
|
||||
|
||||
if (movedCursor==TS_BOTTOMLEFT || movedCursor==TS_BOTTOMRIGHT)
|
||||
dRange = maxValBottom-minValBottom;
|
||||
else
|
||||
dRange = maxValTop-minValTop;
|
||||
double dX = ( (event->x-tmpX)*dRange )/( w-2*hb );
|
||||
// slow motion if CTRL is pressed
|
||||
if (event->state & Gdk::CONTROL_MASK)
|
||||
dX *= 0.05;
|
||||
|
||||
// get the new X value, inside bounds
|
||||
double newX = positions[movedCursor] + dX;
|
||||
|
||||
if (newX > maxBound) newX = maxBound;
|
||||
else if (newX < minBound) newX = minBound;
|
||||
|
||||
// compute the effective dX
|
||||
dX = newX - positions[movedCursor];
|
||||
// set the new position of the moved cursor
|
||||
positions[movedCursor] = newX;
|
||||
|
||||
// apply the decay to the secondary moved cursor, if necessary
|
||||
if (secondaryMovedCursor != TS_UNDEFINED) {
|
||||
positions[secondaryMovedCursor] += dX;
|
||||
}
|
||||
|
||||
// set the new reference value for the next move
|
||||
tmpX = event->x;
|
||||
|
||||
// update the tooltip
|
||||
updateTooltip();
|
||||
|
||||
sig_val_changed.emit();
|
||||
|
||||
queue_draw ();
|
||||
}
|
||||
else {
|
||||
if (litCursor != oldLitCursor)
|
||||
queue_draw ();
|
||||
oldLitCursor = litCursor;
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ThresholdSelector::findLitCursor(int posX, int posY) {
|
||||
int w = get_width ();
|
||||
int h = get_height ();
|
||||
|
||||
litCursor = TS_UNDEFINED;
|
||||
if (posY >=0 && posY <= h/2) {
|
||||
if (posX > 0 && posX < w) {
|
||||
litCursor = TS_TOPLEFT;
|
||||
|
||||
if (doubleThresh) {
|
||||
// we use minValTop since if this block is executed, it means that we are in a simple Threshold where both bottom and top range are the same
|
||||
double cursorX = (posX-hb)*(maxValTop-minValTop)/(w-2*hb)+minValTop;
|
||||
|
||||
if (cursorX>positions[TS_TOPRIGHT] || abs(cursorX-positions[TS_TOPRIGHT]) < abs(cursorX-positions[TS_TOPLEFT]))
|
||||
litCursor = TS_TOPRIGHT;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (posY > h/2 && posY < h) {
|
||||
if (posX > 0 && posX < w) {
|
||||
litCursor = TS_BOTTOMLEFT;
|
||||
if (doubleThresh) {
|
||||
// we use minValTop since if this block is executed, it means that we are in a simple Threshold where both bottom and top range are the same
|
||||
double cursorX = (posX-hb)*(maxValTop-minValTop)/(w-2*hb)+minValTop;
|
||||
|
||||
if (cursorX>positions[TS_BOTTOMRIGHT] || abs(cursorX-positions[TS_BOTTOMRIGHT]) < abs(cursorX-positions[TS_BOTTOMLEFT]))
|
||||
litCursor = TS_BOTTOMRIGHT;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ThresholdSelector::findBoundaries(double &min, double &max) {
|
||||
|
||||
switch (movedCursor) {
|
||||
case (TS_BOTTOMLEFT):
|
||||
if (separatedSliders) {
|
||||
if (movedCursor == TS_BOTTOMLEFT) {
|
||||
min = minValBottom;
|
||||
max = maxValBottom;
|
||||
}
|
||||
else if (movedCursor == TS_TOPLEFT) {
|
||||
min = minValTop;
|
||||
max = maxValTop;
|
||||
}
|
||||
}
|
||||
else if (initalEq1) {
|
||||
min = secondaryMovedCursor == TS_UNDEFINED ? positions[TS_TOPLEFT] : minValTop+(positions[TS_BOTTOMLEFT]-positions[TS_TOPLEFT]);
|
||||
max = positions[TS_BOTTOMRIGHT];
|
||||
}
|
||||
else {
|
||||
min = minValTop;
|
||||
max = secondaryMovedCursor == TS_UNDEFINED ? positions[TS_TOPLEFT] : positions[TS_TOPRIGHT]-(positions[TS_TOPLEFT]-positions[TS_BOTTOMLEFT]);
|
||||
}
|
||||
break;
|
||||
case (TS_TOPLEFT):
|
||||
if (separatedSliders) {
|
||||
if (movedCursor == TS_BOTTOMLEFT) {
|
||||
min = minValBottom;
|
||||
max = maxValBottom;
|
||||
}
|
||||
else if (movedCursor == TS_TOPLEFT) {
|
||||
min = minValTop;
|
||||
max = maxValTop;
|
||||
}
|
||||
}
|
||||
else if (initalEq1) {
|
||||
min = minValTop;
|
||||
max = secondaryMovedCursor == TS_UNDEFINED ? positions[TS_BOTTOMLEFT] : positions[TS_BOTTOMRIGHT]-(positions[TS_BOTTOMLEFT]-positions[TS_TOPLEFT]);
|
||||
}
|
||||
else {
|
||||
min = secondaryMovedCursor == TS_UNDEFINED ? positions[TS_BOTTOMLEFT] : minValTop+(positions[TS_TOPLEFT]-positions[TS_BOTTOMLEFT]);
|
||||
max = positions[TS_TOPRIGHT];
|
||||
}
|
||||
break;
|
||||
case (TS_BOTTOMRIGHT):
|
||||
if (initalEq1) {
|
||||
min = positions[TS_BOTTOMLEFT];
|
||||
max = secondaryMovedCursor == TS_UNDEFINED ? positions[TS_TOPRIGHT] : maxValTop-(positions[TS_TOPRIGHT]-positions[TS_BOTTOMRIGHT]);
|
||||
}
|
||||
else {
|
||||
min = secondaryMovedCursor == TS_UNDEFINED ? positions[TS_TOPRIGHT] : positions[TS_TOPLEFT]+(positions[TS_BOTTOMRIGHT]-positions[TS_TOPRIGHT]);
|
||||
max = maxValTop;
|
||||
}
|
||||
break;
|
||||
case (TS_TOPRIGHT):
|
||||
if (initalEq1) {
|
||||
min = secondaryMovedCursor == TS_UNDEFINED ? positions[TS_BOTTOMRIGHT] : positions[TS_BOTTOMLEFT]+(positions[TS_TOPRIGHT]-positions[TS_BOTTOMRIGHT]);
|
||||
max = maxValTop;
|
||||
}
|
||||
else {
|
||||
min = positions[TS_TOPLEFT];
|
||||
max = secondaryMovedCursor == TS_UNDEFINED ? positions[TS_BOTTOMRIGHT] : maxValTop-(positions[TS_BOTTOMRIGHT]-positions[TS_TOPRIGHT]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
min = minValTop;
|
||||
max = maxValTop;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ThresholdSelector::findSecondaryMovedCursor(guint state) {
|
||||
secondaryMovedCursor = TS_UNDEFINED;
|
||||
if (!separatedSliders && !(state & Gdk::SHIFT_MASK)) {
|
||||
switch (movedCursor) {
|
||||
case (TS_BOTTOMLEFT):
|
||||
secondaryMovedCursor = TS_TOPLEFT;
|
||||
break;
|
||||
case (TS_TOPLEFT):
|
||||
secondaryMovedCursor = TS_BOTTOMLEFT;
|
||||
break;
|
||||
case (TS_BOTTOMRIGHT):
|
||||
secondaryMovedCursor = TS_TOPRIGHT;
|
||||
break;
|
||||
case (TS_TOPRIGHT):
|
||||
secondaryMovedCursor = TS_BOTTOMRIGHT;
|
||||
break;
|
||||
default:
|
||||
secondaryMovedCursor = TS_UNDEFINED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ThresholdSelector::styleChanged (const Glib::RefPtr<Gtk::Style>& style) {
|
||||
|
||||
queue_draw ();
|
||||
}
|
||||
|
||||
void ThresholdSelector::reset () {
|
||||
|
||||
positions[0] = defPos[0];
|
||||
positions[1] = defPos[1];
|
||||
positions[2] = defPos[2];
|
||||
positions[3] = defPos[3];
|
||||
updateTooltip();
|
||||
queue_draw ();
|
||||
}
|
||||
|
||||
inline double ThresholdSelector::to01(ThreshCursorId cursorId) {
|
||||
|
||||
double rVal;
|
||||
if (cursorId==TS_BOTTOMLEFT || cursorId==TS_BOTTOMRIGHT)
|
||||
rVal = (positions[cursorId]-minValBottom)/(maxValBottom-minValBottom);
|
||||
else
|
||||
rVal = (positions[cursorId]-minValTop)/(maxValTop-minValTop);
|
||||
if (rVal < 0.) rVal = 0.;
|
||||
else if (rVal > 1.) rVal = 1.;
|
||||
return rVal;
|
||||
}
|
||||
|
||||
inline void ThresholdSelector::setBgCurveProvider (ThresholdCurveProvider* provider) {
|
||||
bgCurveProvider = provider;
|
||||
}
|
||||
|
||||
inline void ThresholdSelector::setSeparatedSliders(bool separated) {
|
||||
separatedSliders = separated;
|
||||
}
|
||||
|
||||
inline bool ThresholdSelector::getSeparatedSliders() {
|
||||
return separatedSliders;
|
||||
}
|
||||
|
||||
void ThresholdSelector::updateTooltip() {
|
||||
|
||||
Glib::ustring tTip;
|
||||
if (doubleThresh) {
|
||||
tTip = Glib::ustring::compose("<b>%1:</b> %2 <b>%3:</b> %4\n<b>%5:</b> %6 <b>%7:</b> %8",
|
||||
M("THRESHOLDSELECTOR_TL"), Glib::ustring::format(std::fixed, std::setprecision(precisionTop), positions[TS_TOPLEFT]),
|
||||
M("THRESHOLDSELECTOR_TR"), Glib::ustring::format(std::fixed, std::setprecision(precisionTop), positions[TS_TOPRIGHT]),
|
||||
M("THRESHOLDSELECTOR_BL"), Glib::ustring::format(std::fixed, std::setprecision(precisionBottom), positions[TS_BOTTOMLEFT]),
|
||||
M("THRESHOLDSELECTOR_BR"), Glib::ustring::format(std::fixed, std::setprecision(precisionBottom), positions[TS_BOTTOMRIGHT])
|
||||
);
|
||||
if (!additionalTTip.empty())
|
||||
tTip += Glib::ustring::compose("\n\n%1", additionalTTip);
|
||||
tTip += Glib::ustring::compose("\n\n%1", M("THRESHOLDSELECTOR_HINT"));
|
||||
}
|
||||
else if (separatedSliders) {
|
||||
tTip = Glib::ustring::compose("<b>%1:</b> %2\n<b>%3:</b> %4",
|
||||
separatedLabelTop, Glib::ustring::format(std::fixed, std::setprecision(precisionTop), positions[TS_TOPLEFT]),
|
||||
separatedLabelBottom, Glib::ustring::format(std::fixed, std::setprecision(precisionBottom), positions[TS_BOTTOMLEFT])
|
||||
);
|
||||
if (!additionalTTip.empty())
|
||||
tTip += Glib::ustring::compose("\n\n%1", additionalTTip);
|
||||
}
|
||||
else {
|
||||
tTip = Glib::ustring::compose("<b>%1:</b> %2\n<b>%3:</b> %4",
|
||||
M("THRESHOLDSELECTOR_T"), Glib::ustring::format(std::fixed, std::setprecision(precisionTop), positions[TS_TOPLEFT]),
|
||||
M("THRESHOLDSELECTOR_B"), Glib::ustring::format(std::fixed, std::setprecision(precisionBottom), positions[TS_BOTTOMLEFT])
|
||||
);
|
||||
if (!additionalTTip.empty())
|
||||
tTip += Glib::ustring::compose("\n\n%1", additionalTTip);
|
||||
tTip += Glib::ustring::compose("\n\n%1", M("THRESHOLDSELECTOR_HINT"));
|
||||
}
|
||||
Gtk::Widget::set_tooltip_markup(tTip);
|
||||
}
|
||||
|
||||
sigc::signal<void> ThresholdSelector::signal_value_changed() {
|
||||
return sig_val_changed;
|
||||
}
|
||||
|
||||
double ThresholdSelector::shapePositionValue (ThreshCursorId cursorId) {
|
||||
unsigned int precision = (cursorId==TS_BOTTOMLEFT || cursorId==TS_BOTTOMRIGHT) ? precisionBottom : precisionTop;
|
||||
return round(positions[cursorId]*pow(double(10), precision)) / pow(double(10), precision);
|
||||
}
|
||||
|
||||
void ThresholdSelector::set_tooltip_markup(const Glib::ustring& markup) {
|
||||
additionalTTip = markup;
|
||||
updateTooltip();
|
||||
}
|
||||
|
||||
void ThresholdSelector::set_tooltip_text(const Glib::ustring& text) {
|
||||
additionalTTip = text;
|
||||
updateTooltip();
|
||||
}
|
Reference in New Issue
Block a user