rawTherapee/rtgui/thresholdselector.h
Hombre 8b2eac9a3d 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...
2014-01-21 23:37:36 +01:00

219 lines
8.7 KiB
C++

/*
* 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 _THRESHOLDSELECTOR_
#define _THRESHOLDSELECTOR_
#include "guiutils.h"
#include "../rtengine/procparams.h"
#include "coloredbar.h"
#include <iomanip>
class ThresholdSelector;
/*
* This class let the instanciator to provide the background curve
*/
class ThresholdCurveProvider {
public:
virtual ~ThresholdCurveProvider() {};
/*
* The curve provider has to send back a list of point (at least 2 points) in the [0.0 ; 1.0] range
* for both X and Y axis; X and Y values are streamlined ( X1, Y1, X2, Y2, X3, Y3, ...)
*/
virtual std::vector<double> getCurvePoints(ThresholdSelector* tAdjuster) const = 0;
};
/*
* This widget will let you select a linearly variable threshold, creating a ramp up
* if you want to go from a null effect to a full effect
* 0-0-ramp up-1-1
* or a ramp down if you want the contrary
* 1-1-ramp down-0-0
*
* You can optionally create a double threshold
* 0-0-ramp up-1-1-ramp down-0-0
* or
* 1-1-ramp down-0-0-ramp up-1-1
*
* Please note that the values are related to the cursors, depending on their position
* on the graph. E.g. the "bottomLeft" value is related to the bottom left cursor.
*
* It is also possible to have a threshold with 2 totally independent cursors, each one having his own range,
* man/max/default values and precision. This let developers create their own threshold curve, that they will
* have to provide through the
*
*/
class ThresholdSelector : public Gtk::DrawingArea, public ColoredBar {
public:
enum ThreshCursorId {
TS_UNDEFINED=-1,
TS_BOTTOMLEFT,
TS_TOPLEFT,
TS_BOTTOMRIGHT,
TS_TOPRIGHT
};
protected:
sigc::signal<void> sig_val_changed;
ThresholdCurveProvider* bgCurveProvider;
Glib::ustring additionalTTip;
Glib::ustring separatedLabelBottom; // Label for the bottom cursor, displayed if separatedSliders==true only
Glib::ustring separatedLabelTop; // Label for the top cursor, displayed if separatedSliders==true only
bool separatedSliders; // If true, the Top and Bottom sliders are totally separate and can be drag through the full range; for simple threshold only!
bool doubleThresh; // If true: there curve is a double threshold (0 to 1 to 0, or 1 to 0 to 1).
bool initalEq1; // If true: the curve start at 1 (top); if false: the curve start at 0 (bottom)
unsigned int precisionTop; // Decimal number if this object has to handle "double" values, for the Top slider
unsigned int precisionBottom; // Decimal number if this object has to handle "double" values, for the Bottom slider
ThreshCursorId litCursor;
ThreshCursorId oldLitCursor;
double boundary1[2], boundary2[2];
double tmpX, tmpPos;
ThreshCursorId movedCursor, secondaryMovedCursor;
double minValTop, maxValTop;
double minValBottom, maxValBottom;
double defPos[4];
double positions[4];
unsigned short wslider;
const static int hb = 3; // horizontal border
const static int vb = 2; // vertical border
void initValues ();
void findLitCursor(int posX, int posY);
void findSecondaryMovedCursor(guint state);
void findBoundaries(double &min, double &max);
double to01(ThreshCursorId cursorId);
void updateTooltip();
public:
sigc::signal<void> signal_value_changed();
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);
ThresholdSelector(double minValue, double maxValue, double defBottom, double defTop, unsigned int precision, bool startAtOne);
ThresholdSelector(double minValue, double maxValue, double defBottomLeft, double defTopLeft, double defBottomRight, double defTopRight, unsigned int precision, bool startAtOne);
double shapePositionValue (ThreshCursorId cursorId);
template <typename T>
void setDefaults (const rtengine::procparams::Threshold<T> &t) {
defPos[TS_BOTTOMLEFT] = double(t.value[0]); // should we use shapeValue() ?
defPos[TS_TOPLEFT] = double(t.value[1]);
if (doubleThresh) {
defPos[TS_BOTTOMRIGHT] = double(t.value[2]);
defPos[TS_TOPRIGHT] = double(t.value[3]);
}
}
void setDefaults (double bottom, double top);
void setDefaults (double bottomLeft, double topLeft, double bottomRight, double topRight);
template <typename T>
void setPositions (const rtengine::procparams::Threshold<T> &tValues) {
positions[TS_BOTTOMLEFT] = static_cast<double>(tValues.value[TS_BOTTOMLEFT]);
positions[TS_TOPLEFT] = static_cast<double>(tValues.value[TS_TOPLEFT]);
if (tValues.isDouble()) {
positions[TS_BOTTOMRIGHT] = static_cast<double>(tValues.value[TS_BOTTOMRIGHT]);
positions[TS_TOPRIGHT] = static_cast<double>(tValues.value[TS_TOPRIGHT]);
}
updateTooltip();
queue_draw();
}
void setPositions (double bottom, double top);
void setPositions (double bottomLeft, double topLeft, double bottomRight, double topRight);
template <typename T>
rtengine::procparams::Threshold<T> getPositions () {
if (doubleThresh) {
rtengine::procparams::Threshold<T> rThresh(
static_cast<T>(shapePositionValue(TS_BOTTOMLEFT)),
static_cast<T>(shapePositionValue(TS_TOPLEFT)),
static_cast<T>(shapePositionValue(TS_BOTTOMRIGHT)),
static_cast<T>(shapePositionValue(TS_TOPRIGHT)),
initalEq1
);
return rThresh;
}
else {
rtengine::procparams::Threshold<T> rThresh(
static_cast<T>(shapePositionValue(TS_BOTTOMLEFT)),
static_cast<T>(shapePositionValue(TS_TOPLEFT)),
initalEq1
);
return rThresh;
}
}
template <typename T>
void getPositions (T &bottom, T &top) {
bottom = static_cast<T>(shapePositionValue(TS_BOTTOMLEFT));
top = static_cast<T>(shapePositionValue(TS_TOPLEFT));
}
template <typename T>
void getPositions (T &bottomLeft, T &topLeft, T &bottomRight, T &topRight) {
bottomLeft = static_cast<T>(shapePositionValue(TS_BOTTOMLEFT));
topLeft = static_cast<T>(shapePositionValue(TS_TOPLEFT));
bottomRight = static_cast<T>(shapePositionValue(TS_BOTTOMRIGHT));
topRight = static_cast<T>(shapePositionValue(TS_TOPRIGHT));
}
void setSeparatedSliders(bool separated);
bool getSeparatedSliders();
void setBgCurveProvider (ThresholdCurveProvider* provider);
bool isStartAtOne() { return initalEq1; }
bool isDouble() { return doubleThresh; }
void on_realize ();
bool on_expose_event(GdkEventExpose* event);
bool on_button_press_event (GdkEventButton* event);
bool on_button_release_event (GdkEventButton* event);
bool on_motion_notify_event (GdkEventMotion* event);
bool on_leave_notify_event (GdkEventCrossing* event);
void styleChanged (const Glib::RefPtr<Gtk::Style>& style);
unsigned int getPrecision () { return precisionTop; }
void reset ();
void set_tooltip_markup(const Glib::ustring& markup);
// this set_tooltip_text method is to set_tooltip_markup, and text can contain markups
void set_tooltip_text(const Glib::ustring& text);
};
template<>
inline void ThresholdSelector::getPositions<Glib::ustring> (Glib::ustring& bottom, Glib::ustring& top) {
bottom = Glib::ustring::format(std::fixed, std::setprecision(precisionBottom), shapePositionValue(TS_BOTTOMLEFT));
top = Glib::ustring::format(std::fixed, std::setprecision(precisionTop), shapePositionValue(TS_TOPLEFT));
}
template<>
inline void ThresholdSelector::getPositions<Glib::ustring> (Glib::ustring& bottomLeft, Glib::ustring& topLeft, Glib::ustring& bottomRight, Glib::ustring& topRight) {
bottomLeft = Glib::ustring::format(std::fixed, std::setprecision(precisionBottom), shapePositionValue(TS_BOTTOMLEFT));
topLeft = Glib::ustring::format(std::fixed, std::setprecision(precisionTop), shapePositionValue(TS_TOPLEFT));
bottomRight = Glib::ustring::format(std::fixed, std::setprecision(precisionBottom), shapePositionValue(TS_BOTTOMRIGHT));
topRight = Glib::ustring::format(std::fixed, std::setprecision(precisionTop), shapePositionValue(TS_TOPRIGHT));
}
#endif