rawTherapee/rtgui/thresholdadjuster.cc
Hombre d2fcabea64 The 2 columns of the History list are now of the same width, can't be
resized, and display a tooltip.

The ICM tool has been reworked to avoid loosing space.

The curve's histogram are now displayed.

For Windows users, if you can't build the Gtk3 branch anymore with your
Gcc5.x compiler, try to uncomment line 20-21 of the main CMakeLists.txt.
For some reason, I had to comment that out.
2015-09-17 01:09:02 +02:00

399 lines
13 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/>.
*/
#include "thresholdadjuster.h"
// class_slot is no longer part of the sigc++ source tree, but starting from which version ?
#if 1
#include <sigc++/slot.h>
#else
#include <sigc++/class_slot.h>
#endif
#include <cmath>
#include "multilangmgr.h"
#include "../rtengine/rtengine.h"
#include "options.h"
#include "guiutils.h"
#include "rtimage.h"
#define MIN_RESET_BUTTON_HEIGHT 17
ThresholdAdjuster::ThresholdAdjuster (Glib::ustring label,
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, bool editedCheckBox)
: tSelector(minValueBottom, maxValueBottom, defBottom, labelBottom, precisionBottom, minValueTop, maxValueTop, defTop, labelTop, precisionTop, curveProvider)
{
initialDefaultVal[ThresholdSelector::TS_BOTTOMLEFT] = defBottom;
initialDefaultVal[ThresholdSelector::TS_TOPLEFT] = defTop;
initialDefaultVal[ThresholdSelector::TS_BOTTOMRIGHT] = 0.; // unused
initialDefaultVal[ThresholdSelector::TS_TOPRIGHT] = 0.; // unused
initObject (label, editedCheckBox);
}
ThresholdAdjuster::ThresholdAdjuster (Glib::ustring label, double minValue, double maxValue, double defBottom,
double defTop, unsigned int precision, bool startAtOne, bool editedCheckBox)
: tSelector(minValue, maxValue, defBottom, defTop, precision, startAtOne)
{
initialDefaultVal[ThresholdSelector::TS_BOTTOMLEFT] = defBottom;
initialDefaultVal[ThresholdSelector::TS_TOPLEFT] = defTop;
initialDefaultVal[ThresholdSelector::TS_BOTTOMRIGHT] = maxValue;
initialDefaultVal[ThresholdSelector::TS_TOPRIGHT] = maxValue;
initObject (label, editedCheckBox);
}
ThresholdAdjuster::ThresholdAdjuster (Glib::ustring label, double minValue, double maxValue,
double defBottomLeft, double defTopLeft, double defBottomRight, double defTopRight,
unsigned int precision, bool startAtOne, bool editedCheckBox)
: tSelector(minValue, maxValue, defBottomLeft, defTopLeft,
defBottomRight, defTopRight, precision, startAtOne)
{
initialDefaultVal[ThresholdSelector::TS_BOTTOMLEFT] = defBottomLeft;
initialDefaultVal[ThresholdSelector::TS_TOPLEFT] = defTopLeft;
initialDefaultVal[ThresholdSelector::TS_BOTTOMRIGHT] = defBottomRight;
initialDefaultVal[ThresholdSelector::TS_TOPRIGHT] = defTopRight;
initObject (label, editedCheckBox);
}
void ThresholdAdjuster::initObject (Glib::ustring label, bool editedcb)
{
adjusterListener = NULL;
afterReset = false;
blocked = false;
addMode = false;
// TODO: let the user chose the default value of ThresholdAdjuster::delay, for slow machines
delay = options.adjusterDelay; // delay is no more static, so we can set the delay individually (useful for the RAW editor tab)
set_name("ThresholdAdjuster");
hbox = Gtk::manage (new Gtk::HBox ());
this->label = Gtk::manage (new Gtk::Label (label, Gtk::ALIGN_START));
if (editedcb) {
editedCheckBox = Gtk::manage (new Gtk::CheckButton ());
editedChange = editedCheckBox->signal_toggled().connect( sigc::mem_fun(*this, &ThresholdAdjuster::editedToggled) );
hbox->pack_start (*editedCheckBox);
} else {
editedCheckBox = NULL;
}
hbox->pack_start (*this->label);
reset = Gtk::manage (new Gtk::Button ());
reset->add (*Gtk::manage (new RTImage ("gtk-undo-ltr-small.png", "gtk-undo-rtl-small.png")));
reset->set_relief (Gtk::RELIEF_NONE);
reset->set_border_width (0);
reset->set_tooltip_text (M("ADJUSTER_RESET_TO_DEFAULT"));
hbox->pack_end (*reset, Gtk::PACK_SHRINK, 0);
reset->set_size_request (-1, this->label->get_height() > MIN_RESET_BUTTON_HEIGHT ? this->label->get_height() : MIN_RESET_BUTTON_HEIGHT);
pack_start (*hbox, false, false);
pack_start (tSelector, false, false);
editedState = defEditedState = Irrelevant;
selectorChange = tSelector.signal_value_changed().connect( sigc::mem_fun(*this, &ThresholdAdjuster::selectorChanged) );
reset->signal_button_release_event().connect_notify( sigc::mem_fun(*this, &ThresholdAdjuster::resetPressed) );
show_all ();
}
ThresholdAdjuster::~ThresholdAdjuster ()
{
selectorChange.disconnect();
delayConnection.block(true);
adjusterListener = NULL;
}
void ThresholdAdjuster::setDefault (double bottom, double top)
{
selectorChange.block (true);
tSelector.setPositions(shapeValue(bottom), shapeValue(top));
selectorChange.block (false);
}
void ThresholdAdjuster::setDefault (double bottomLeft, double topLeft, double bottomRight, double topRight)
{
selectorChange.block (true);
tSelector.setPositions(shapeValue(bottomLeft), shapeValue(topLeft), shapeValue(bottomRight), shapeValue(topRight));
selectorChange.block (false);
}
void ThresholdAdjuster::setDefaultEditedState (EditedState eState)
{
defEditedState = eState;
}
void ThresholdAdjuster::resetPressed (GdkEventButton* event)
{
if (editedState != Irrelevant) {
editedState = defEditedState;
if (editedCheckBox) {
editedChange.block (true);
editedCheckBox->set_active (defEditedState == Edited);
editedChange.block (false);
}
refreshLabelStyle ();
}
afterReset = true;
if ((event != NULL) && (event->state & GDK_CONTROL_MASK) && (event->button == 1))
// CTRL pressed : resetting to current default value
{
tSelector.reset();
} else
// no modifier key or addMode=true : resetting to initial default value
tSelector.setPositions(initialDefaultVal[ThresholdSelector::TS_BOTTOMLEFT],
initialDefaultVal[ThresholdSelector::TS_TOPLEFT],
initialDefaultVal[ThresholdSelector::TS_BOTTOMRIGHT],
initialDefaultVal[ThresholdSelector::TS_TOPRIGHT]);
}
double ThresholdAdjuster::shapeValue (double a)
{
unsigned int digit = tSelector.getPrecision();
return round(a * pow(double(10), digit)) / pow(double(10), digit);
}
void ThresholdAdjuster::selectorChanged ()
{
if (delayConnection.connected()) {
delayConnection.disconnect ();
}
if (delay == 0) {
if (adjusterListener && !blocked) {
sendToListener ();
}
} else {
delayConnection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ThresholdAdjuster::notifyListener), delay);
}
if (!afterReset && editedState == UnEdited) {
editedState = Edited;
if (editedCheckBox) {
editedChange.block (true);
editedCheckBox->set_active (true);
editedChange.block (false);
}
refreshLabelStyle ();
}
afterReset = false;
}
void ThresholdAdjuster::setValue (double bottom, double top)
{
selectorChange.block (true);
tSelector.setPositions(bottom, top);
selectorChange.block (false);
afterReset = false;
}
void ThresholdAdjuster::setValue (double bottomLeft, double topLeft, double bottomRight, double topRight)
{
selectorChange.block (true);
tSelector.setPositions(bottomLeft, topLeft, bottomRight, topRight);
selectorChange.block (false);
afterReset = false;
}
void ThresholdAdjuster::getValue (double& bottom, double& top)
{
tSelector.getPositions<double> (bottom, top);
}
void ThresholdAdjuster::getValue (double& bottomLeft, double& topLeft, double& bottomRight, double& topRight)
{
tSelector.getPositions<double> (bottomLeft, topLeft, bottomRight, topRight);
}
void ThresholdAdjuster::getValue (int& bottom, int& top)
{
tSelector.getPositions<int> (bottom, top);
}
void ThresholdAdjuster::getValue (int& bottomLeft, int& topLeft, int& bottomRight, int& topRight)
{
tSelector.getPositions<int> (bottomLeft, topLeft, bottomRight, topRight);
}
void ThresholdAdjuster::getValue (Glib::ustring& bottom, Glib::ustring& top)
{
tSelector.getPositions (bottom, top);
}
void ThresholdAdjuster::getValue (Glib::ustring& bottomLeft, Glib::ustring& topLeft, Glib::ustring& bottomRight, Glib::ustring& topRight)
{
tSelector.getPositions (bottomLeft, topLeft, bottomRight, topRight);
}
bool ThresholdAdjuster::notifyListener ()
{
if (adjusterListener != NULL && !blocked) {
GThreadLock lock;
sendToListener();
}
return false;
}
void ThresholdAdjuster::setBgCurveProvider (ThresholdCurveProvider* provider)
{
tSelector.setBgCurveProvider(provider);
}
void ThresholdAdjuster::setEnabled (bool enabled)
{
tSelector.set_sensitive (enabled);
}
void ThresholdAdjuster::setEditedState (EditedState eState)
{
if (editedState != eState) {
if (editedCheckBox) {
editedChange.block (true);
editedCheckBox->set_active (eState == Edited);
editedChange.block (false);
}
editedState = eState;
refreshLabelStyle ();
}
}
EditedState ThresholdAdjuster::getEditedState ()
{
if (editedState != Irrelevant && editedCheckBox) {
editedState = editedCheckBox->get_active () ? Edited : UnEdited;
}
return editedState;
}
void ThresholdAdjuster::showEditedCB ()
{
if (!editedCheckBox) {
editedCheckBox = Gtk::manage(new Gtk::CheckButton ());
hbox->pack_start (*editedCheckBox, Gtk::PACK_SHRINK, 2);
hbox->reorder_child (*editedCheckBox, 0);
editedChange = editedCheckBox->signal_toggled().connect( sigc::mem_fun(*this, &ThresholdAdjuster::editedToggled) );
}
}
void ThresholdAdjuster::refreshLabelStyle ()
{
/* Glib::RefPtr<Gtk::StyleContext> style = label->get_style_context ();
Pango::FontDescription fd = style->get_font ();
fd.set_weight (editedState==Edited ? Pango::WEIGHT_BOLD : Pango::WEIGHT_NORMAL);
style->set_font (fd);
label->set_style (style);
label->queue_draw ();*/
}
void ThresholdAdjuster::editedToggled ()
{
if (adjusterListener && !blocked) {
sendToListener ();
}
}
void ThresholdAdjuster::sendToListener ()
{
if (tSelector.getPrecision() > 0) {
// if precision is >0, then we assume that the listener is waiting for doubles
rtengine::procparams::Threshold<double> t = tSelector.getPositions<double>();
if (tSelector.isDouble()) {
adjusterListener->adjusterChanged (this, t.value[0], t.value[1], t.value[2], t.value[3]);
adjusterListener->adjusterChanged2 (this, t.value[0], t.value[1], t.value[2], t.value[3]);
} else {
adjusterListener->adjusterChanged (this, t.value[0], t.value[1]);
}
} else {
// if precision is equal to 0, then we assume that the listener is waiting for integers
rtengine::procparams::Threshold<int> t = tSelector.getPositions<int>();
if (tSelector.isDouble()) {
adjusterListener->adjusterChanged (this, t.value[0], t.value[1], t.value[2], t.value[3]);
adjusterListener->adjusterChanged2 (this, t.value[0], t.value[1], t.value[2], t.value[3]);
} else {
adjusterListener->adjusterChanged (this, t.value[0], t.value[1]);
}
}
}
void ThresholdAdjuster::set_tooltip_markup(const Glib::ustring& markup)
{
tSelector.set_tooltip_markup(markup);
}
void ThresholdAdjuster::set_tooltip_text(const Glib::ustring& text)
{
tSelector.set_tooltip_text(text);
}
/* For better readability, this method create the history string of the parameter column,
* so that the parameters list can be read in a more logical way (i.e. corresponding
* to the startAtOne field)
*
* If separatedMode==true, the top slider is assumed to be the primary slider, then the bottom slider as the second one
*/
Glib::ustring ThresholdAdjuster::getHistoryString ()
{
if (tSelector.isDouble()) {
Glib::ustring bl, tl, br, tr;
tSelector.getPositions(bl, tl, br, tr);
return Glib::ustring::compose(tSelector.isStartAtOne() ? "%2, %1, %3, %4" : "%1, %2, %4, %3", bl, tl, br, tr);
} else {
Glib::ustring b, t;
tSelector.getPositions(b, t);
return Glib::ustring::compose(tSelector.isStartAtOne() || separatedMode ? "%2, %1" : "%1, %2", b, t);
}
}