Issue 2134: removed obsolete raw highlight preservation setting from GUI (still left in procparams for backwards compatilibility)

This commit is contained in:
torger
2015-07-10 12:00:36 +02:00
commit d5ca351c20
1751 changed files with 441944 additions and 0 deletions

74
rtgui/CMakeLists.txt Normal file
View File

@@ -0,0 +1,74 @@
set (BASESOURCEFILES
editwindow.cc batchtoolpanelcoord.cc paramsedited.cc cropwindow.cc previewhandler.cc previewwindow.cc navigator.cc indclippedpanel.cc previewmodepanel.cc filterpanel.cc
exportpanel.cc cursormanager.cc rtwindow.cc renamedlg.cc recentbrowser.cc placesbrowser.cc filepanel.cc editorpanel.cc batchqueuepanel.cc
ilabel.cc thumbbrowserbase.cc adjuster.cc filebrowserentry.cc filebrowser.cc filethumbnailbuttonset.cc
cachemanager.cc cacheimagedata.cc shcselector.cc perspective.cc thresholdselector.cc thresholdadjuster.cc
clipboard.cc thumbimageupdater.cc bqentryupdater.cc lensgeom.cc coloredbar.cc edit.cc coordinateadjuster.cc
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
sharpening.cc vibrance.cc rgbcurves.cc colortoning.cc
whitebalance.cc vignetting.cc gradient.cc pcvignette.cc rotate.cc distortion.cc
crophandler.cc dirbrowser.cc
curveeditor.cc curveeditorgroup.cc diagonalcurveeditorsubgroup.cc flatcurveeditorsubgroup.cc
filecatalog.cc extprog.cc
previewloader.cc rtimage.cc inspector.cc
histogrampanel.cc history.cc imagearea.cc
imageareapanel.cc iptcpanel.cc labcurve.cc main.cc
multilangmgr.cc mycurve.cc myflatcurve.cc mydiagonalcurve.cc options.cc
preferences.cc profilepanel.cc saveasdlg.cc
saveformatpanel.cc soundman.cc splash.cc
thumbnail.cc tonecurve.cc toolbar.cc
guiutils.cc zoompanel.cc toolpanelcoord.cc
thumbbrowserentrybase.cc batchqueueentry.cc
batchqueue.cc lwbutton.cc lwbuttonset.cc
batchqueuebuttonset.cc browserfilter.cc exiffiltersettings.cc
profilestore.cc partialpastedlg.cc
sensorbayer.cc sensorxtrans.cc preprocess.cc bayerpreprocess.cc bayerprocess.cc bayerrawexposure.cc xtransprocess.cc xtransrawexposure.cc
darkframe.cc flatfield.cc rawcacorrection.cc rawexposure.cc wavelet.cc
dirpyrequalizer.cc hsvequalizer.cc defringe.cc
popupcommon.cc popupbutton.cc popuptogglebutton.cc sharpenedge.cc sharpenmicro.cc colorappearance.cc
filmsimulation.cc prsharpening.cc)
include_directories (BEFORE "${CMAKE_CURRENT_BINARY_DIR}")
if (APPLE)
find_package (MacIntegration REQUIRED)
# At the time of writing Cmake has no module finder for gtkmacintegration so here we have it hard-coded, if installed via macports it should be in /opt/local/...
set (EXTRA_LIB_RTGUI ${MacIntegration_LIBRARIES})
set (EXTRA_INCDIR ${EXTRA_INCDIR} ${MacIntegration_INCLUDE_DIRS})
endif (APPLE)
if (WIN32)
set (EXTRA_SRC windirmonitor.cc myicon.rc)
set (EXTRA_LIB_RTGUI winmm)
include_directories (${EXTRA_INCDIR} ${GLIB2_INCLUDE_DIRS} ${GLIBMM_INCLUDE_DIRS}
${GTK_INCLUDE_DIRS} ${GTKMM_INCLUDE_DIRS} ${GIO_INCLUDE_DIRS} ${GIOMM_INCLUDE_DIRS})
link_directories (. "${PROJECT_SOURCE_DIR}/rtexif" ${EXTRA_LIBDIR} ${GLIB2_LIBRARY_DIRS} ${GLIBMM_LIBRARY_DIRS}
${GTK_LIBRARY_DIRS} ${GTKMM_LIBRARY_DIRS} ${GIO_LIBRARY_DIRS} ${GIOMM_LIBRARY_DIRS})
#set_target_properties (rth PROPERTIES LINK_FLAGS "-mwindows")
else (WIN32)
include_directories (${EXTRA_INCDIR} ${GLIB2_INCLUDE_DIRS} ${GLIBMM_INCLUDE_DIRS}
${GTK_INCLUDE_DIRS} ${GTKMM_INCLUDE_DIRS} ${GIO_INCLUDE_DIRS} ${GIOMM_INCLUDE_DIRS} ${IPTCDATA_INCLUDE_DIRS}
${LCMS_INCLUDE_DIRS} ${EXPAT_INCLUDE_DIRS} ${FFTW3F_LIBRARY_DIRS} ${GTHREAD_INCLUDE_DIRS} ${GOBJECT_INCLUDE_DIRS}
${CANBERRA-GTK_INCLUDE_DIRS})
link_directories (${EXTRA_LIBDIR} ${GLIB2_LIBRARY_DIRS} ${GLIBMM_LIBRARY_DIRS}
${GTK_LIBRARY_DIRS} ${GTKMM_LIBRARY_DIRS} ${GIO_LIBRARY_DIRS} ${GIOMM_LIBRARY_DIRS} ${IPTCDATA_LIBRARY_DIRS}
${LCMS_LIBRARY_DIRS} ${EXPAT_LIBRARY_DIRS} ${FFTW3F_LIBRARY_DIRS} ${GTHREAD_LIBRARY_DIRS} ${GOBJECT_LIBRARY_DIRS}
${CANBERRA-GTK_LIBRARY_DIRS})
endif (WIN32)
# create config.h which defines where data are stored
configure_file ("${CMAKE_CURRENT_SOURCE_DIR}/config.h.in" "${CMAKE_CURRENT_BINARY_DIR}/config.h")
add_executable (rth ${EXTRA_SRC} ${BASESOURCEFILES})
add_dependencies (rth AboutFile)
set_target_properties (rth PROPERTIES COMPILE_FLAGS "${CMAKE_CXX_FLAGS}" OUTPUT_NAME rawtherapee)
#target_link_libraries (rth rtengine ${JPEG_LIBRARIES} ${PNG_LIBRARIES} ${ZLIB_LIBRARIES} ${TIFF_LIBRARIES} ${EXTRA_LIB} ${GOBJECT_LIBRARIES} ${GTHREAD_LIBRARIES}
# ${GLIB2_LIBRARIES} ${GLIBMM_LIBRARIES} ${GTK_LIBRARIES} ${GTKMM_LIBRARIES} ${GIO_LIBRARIES} ${GIOMM_LIBRARIES} ${LCMS_LIBRARIES} ${IPTCDATA_LIBRARIES})
target_link_libraries (rth rtengine ${JPEG_LIBRARIES} ${PNG_LIBRARIES} ${ZLIB_LIBRARIES} ${TIFF_LIBRARIES} ${GOBJECT_LIBRARIES} ${GTHREAD_LIBRARIES}
${GLIB2_LIBRARIES} ${GLIBMM_LIBRARIES} ${GTK_LIBRARIES} ${GTKMM_LIBRARIES} ${GIO_LIBRARIES} ${GIOMM_LIBRARIES} ${LCMS_LIBRARIES} ${EXPAT_LIBRARIES}
${FFTW3F_LIBRARIES} ${IPTCDATA_LIBRARIES} ${CANBERRA-GTK_LIBRARIES} ${EXTRA_LIB_RTGUI})
install (TARGETS rth DESTINATION ${BINDIR})

BIN
rtgui/RT.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

114
rtgui/addsetids.h Normal file
View File

@@ -0,0 +1,114 @@
#ifndef _ADDSETIDS_
#define _ADDSETIDS_
// UPDATE THE DEFAULT VALUE IN OPTIONS.CC int babehav[] TOO !!!
#define ADDSET_TC_EXPCOMP 0
#define ADDSET_TC_BRIGHTNESS 1
#define ADDSET_TC_BLACKLEVEL 2
#define ADDSET_TC_CONTRAST 3
#define ADDSET_SH_HIGHLIGHTS 4
#define ADDSET_SH_SHADOWS 5
#define ADDSET_SH_LOCALCONTRAST 6
#define ADDSET_LC_BRIGHTNESS 7
#define ADDSET_LC_CONTRAST 8
#define ADDSET_SHARP_AMOUNT 9
#define ADDSET_WB_TEMPERATURE 10
#define ADDSET_WB_GREEN 11
#define ADDSET_ROTATE_DEGREE 12
#define ADDSET_DIST_AMOUNT 13
#define ADDSET_PERSPECTIVE 14
#define ADDSET_CA 15
#define ADDSET_VIGN_AMOUNT 16
#define ADDSET_VIGN_RADIUS 17
#define ADDSET_VIGN_STRENGTH 18
#define ADDSET_VIGN_CENTER 19
#define ADDSET_LC_CHROMATICITY 20
#define ADDSET_TC_SATURATION 21
#define ADDSET_TC_HLCOMPAMOUNT 22
#define ADDSET_TC_HLCOMPTHRESH 23
#define ADDSET_TC_SHCOMP 24
#define ADDSET_DIRPYREQ 25
#define ADDSET_DIRPYRDN_LUMA 26
#define ADDSET_DIRPYRDN_LUMDET 27
#define ADDSET_DIRPYRDN_CHROMA 28
#define ADDSET_DIRPYRDN_CHROMARED 29
#define ADDSET_DIRPYRDN_CHROMABLUE 30
#define ADDSET_DIRPYRDN_GAMMA 31
#define ADDSET_CHMIXER 32
#define ADDSET_PREPROCESS_GREENEQUIL 33
#define ADDSET_PREPROCESS_LINEDENOISE 34
#define ADDSET_RAWCACORR 35
#define ADDSET_RAWEXPOS_LINEAR 36
#define ADDSET_RAWEXPOS_PRESER 37
#define ADDSET_RAWEXPOS_BLACKS 38
#define ADDSET_SHARPENEDGE_AMOUNT 39
#define ADDSET_SHARPENMICRO_AMOUNT 40
#define ADDSET_SHARPENEDGE_PASS 41
#define ADDSET_SHARPENMICRO_UNIFORMITY 42
#define ADDSET_VIBRANCE_PASTELS 43
#define ADDSET_VIBRANCE_SATURATED 44
#define ADDSET_FREE_OUPUT_GAMMA 45
#define ADDSET_FREE_OUTPUT_SLOPE 46
#define ADDSET_CAT_DEGREE 47
#define ADDSET_CAT_ADAPTSCENE 48
#define ADDSET_CAT_ADAPTVIEWING 49
#define ADDSET_CAT_LIGHT 50
#define ADDSET_CAT_CHROMA 51
#define ADDSET_CAT_CONTRAST 52
#define ADDSET_CAT_RSTPRO 53
#define ADDSET_CAT_BRIGHT 54
#define ADDSET_CAT_CONTRAST_Q 55
#define ADDSET_CAT_CHROMA_S 56
#define ADDSET_CAT_CHROMA_M 57
#define ADDSET_CAT_HUE 58
#define ADDSET_CAT_BADPIX 59
#define ADDSET_WB_EQUAL 60
#define ADDSET_GRADIENT_DEGREE 61
#define ADDSET_GRADIENT_FEATHER 62
#define ADDSET_GRADIENT_STRENGTH 63
#define ADDSET_GRADIENT_CENTER 64
#define ADDSET_PCVIGNETTE_STRENGTH 65
#define ADDSET_PCVIGNETTE_FEATHER 66
#define ADDSET_PCVIGNETTE_ROUNDNESS 67
#define ADDSET_BLACKWHITE_HUES 68
#define ADDSET_BLACKWHITE_GAMMA 69
#define ADDSET_DIRPYREQ_THRESHOLD 70
#define ADDSET_DIRPYREQ_SKINPROTECT 71
#define ADDSET_COLORTONING_SPLIT 72
#define ADDSET_COLORTONING_SATTHRESHOLD 73
#define ADDSET_COLORTONING_SATOPACITY 74
#define ADDSET_COLORTONING_BALANCE 75
#define ADDSET_COLORTONING_STRENGTH 76
#define ADDSET_DIRPYRDN_PASSES 77
#define ADDSET_RAWFFCLIPCONTROL 78
#define ADDSET_FILMSIMULATION_STRENGTH 79
#define ADDSET_WA 80
#define ADDSET_WA_SKINPROTECT 81
#define ADDSET_WA_THRR 82
#define ADDSET_WA_THRRH 83
#define ADDSET_WA_THRES 84
#define ADDSET_WA_THRESHOLD 85
#define ADDSET_WA_THRESHOLD2 86
#define ADDSET_WA_CHRO 87
#define ADDSET_WA_CHROMA 88
#define ADDSET_WA_CONTRAST 89
#define ADDSET_WA_RESCON 90
#define ADDSET_WA_RESCONH 91
#define ADDSET_WA_RESCHRO 92
#define ADDSET_WA_SKYPROTECT 93
#define ADDSET_WA_EDGRAD 94
#define ADDSET_WA_EDGVAL 95
#define ADDSET_WA_STRENGTH 96
#define ADDSET_WA_EDGEDETECT 97
#define ADDSET_WA_EDGEDETECTTHR 98
#define ADDSET_WA_EDGEDETECTTHR2 99
#define ADDSET_WA_TMRS 100
#define ADDSET_WA_GAMMA 101
// When adding items, make sure to update ADDSET_PARAM_NUM
#define ADDSET_PARAM_NUM 102 // THIS IS USED AS A DELIMITER!!
#endif

495
rtgui/adjuster.cc Normal file
View File

@@ -0,0 +1,495 @@
/*
* 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 "adjuster.h"
#include <sigc++/class_slot.h>
#include <cmath>
#include "multilangmgr.h"
#include "../rtengine/rtengine.h"
#include "options.h"
#include "guiutils.h"
#include "rtimage.h"
#define MIN_RESET_BUTTON_HEIGHT 17
static double one2one(double val) { return val; }
Adjuster::Adjuster (Glib::ustring vlabel, double vmin, double vmax, double vstep, double vdefault, Gtk::Image *imgIcon1, Gtk::Image *imgIcon2, double2double_fun slider2value_, double2double_fun value2slider_) {
Gtk::HBox *hbox2=NULL;
label = NULL;
adjusterListener = NULL;
afterReset = false;
blocked = false;
automatic = NULL;
eventPending = false;
slider2value = slider2value_ ? slider2value_ : one2one;
value2slider = value2slider_ ? value2slider_ : one2one;
vMin = vmin;
vMax = vmax;
vStep = vstep;
addMode = false;
// TODO: let the user chose the default value of Adjuster::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_border_width (0);
set_spacing (0);
hbox = Gtk::manage (new Gtk::HBox ());
hbox->set_border_width(0);
hbox->set_spacing(2);
editedCheckBox = NULL;
if (!vlabel.empty()) {
adjustmentName = vlabel;
label = Gtk::manage (new Gtk::Label (adjustmentName, Gtk::ALIGN_LEFT));
}
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"));
reset->set_can_focus(false);
spin = Gtk::manage (new MySpinButton ());
spin->set_has_frame(false);
spin->set_name("FramelessSpinButton");
reset->set_size_request (-1, spin->get_height() > MIN_RESET_BUTTON_HEIGHT ? spin->get_height(): MIN_RESET_BUTTON_HEIGHT);
slider = Gtk::manage (new MyHScale ());
slider->set_draw_value (false);
pack_start (*hbox, true, true);
if (vlabel.empty()) {
// No label, everything goes in hbox
if (imgIcon1) hbox->pack_start (*imgIcon1, Gtk::PACK_SHRINK, 0);
hbox->pack_start (*slider, Gtk::PACK_EXPAND_WIDGET, 0);
if (imgIcon2) hbox->pack_start (*imgIcon2, Gtk::PACK_SHRINK, 0);
hbox->pack_end (*reset, Gtk::PACK_SHRINK, 0);
hbox->pack_end (*spin, Gtk::PACK_SHRINK, 0);
}
else {
// A label is provided, spreading the widgets in 2 rows
hbox->pack_start (*label);
hbox->pack_end (*reset, Gtk::PACK_SHRINK, 0);
hbox->pack_end (*spin, Gtk::PACK_SHRINK, 0);
if (!imgIcon1 || !imgIcon2) {
pack_start (*slider, true, true);
}
else {
// A second HBox is necessary
hbox2 = Gtk::manage (new Gtk::HBox());
if (imgIcon1) hbox2->pack_start (*imgIcon1, Gtk::PACK_SHRINK, 0);
hbox2->pack_start (*slider, true, true);
if (imgIcon2) hbox2->pack_start (*imgIcon2, Gtk::PACK_SHRINK, 0);
pack_start (*hbox2, true, true);
}
}
setLimits (vmin, vmax, vstep, vdefault);
defaultVal = shapeValue (vdefault);
ctorDefaultVal = shapeValue (vdefault);
editedState = defEditedState = Irrelevant;
autoState = Irrelevant;
sliderChange = slider->signal_value_changed().connect( sigc::mem_fun(*this, &Adjuster::sliderChanged) );
spinChange = spin->signal_value_changed().connect ( sigc::mem_fun(*this, &Adjuster::spinChanged), true);
reset->signal_button_release_event().connect_notify( sigc::mem_fun(*this, &Adjuster::resetPressed) );
slider->set_update_policy (Gtk::UPDATE_CONTINUOUS);
show_all ();
}
Adjuster::~Adjuster () {
sliderChange.block (true);
spinChange.block (true);
delayConnection.block (true);
adjusterListener = NULL;
if (automatic) delete automatic;
}
void Adjuster::addAutoButton (Glib::ustring tooltip) {
if (!automatic) {
automatic = new Gtk::CheckButton ();
//automatic->add (*Gtk::manage (new RTImage ("processing.png")));
automatic->set_border_width (0);
automatic->set_tooltip_markup(tooltip.length() ? Glib::ustring::compose("<b>%1</b>\n\n%2", M("GENERAL_AUTO"), tooltip) : M("GENERAL_AUTO"));
autoChange = automatic->signal_toggled().connect( sigc::mem_fun(*this, &Adjuster::autoToggled) );
hbox->pack_end (*automatic, Gtk::PACK_SHRINK, 0);
hbox->reorder_child (*automatic, 0);
}
}
void Adjuster::delAutoButton () {
if (automatic) {
removeIfThere(hbox, automatic);
delete automatic;
automatic = NULL;
}
}
void Adjuster::throwOnButtonRelease(bool throwOnBRelease) {
if (throwOnBRelease) {
if (!buttonReleaseSlider.connected())
buttonReleaseSlider = slider->signal_button_release_event().connect_notify( sigc::mem_fun(*this, &Adjuster::sliderReleased) );
if (!buttonReleaseSpin.connected())
buttonReleaseSpin = spin->signal_button_release_event().connect_notify( sigc::mem_fun(*this, &Adjuster::spinReleased) ); // Use the same callback hook
}
else {
if (buttonReleaseSlider.connected())
buttonReleaseSlider.disconnect();
if (buttonReleaseSpin.connected())
buttonReleaseSpin.disconnect();
}
eventPending = false;
}
void Adjuster::setDefault (double def) {
defaultVal = shapeValue (def);
}
void Adjuster::setDefaultEditedState (EditedState eState) {
defEditedState = eState;
}
void Adjuster::autoToggled () {
if (!editedCheckBox) {
// If not used in the BatchEditor panel
if (automatic->get_active()) {
// Disable the slider and spin button
spin->set_sensitive(false);
slider->set_sensitive(false);
}
else {
// Enable the slider and spin button
spin->set_sensitive(true);
slider->set_sensitive(true);
}
}
if (adjusterListener!=NULL && !blocked) {
adjusterListener->adjusterAutoToggled(this, automatic->get_active());
}
}
void Adjuster::sliderReleased (GdkEventButton* event) {
if ((event != NULL) && (event->button == 1)) {
if (delayConnection.connected())
delayConnection.disconnect ();
notifyListener();
}
}
void Adjuster::spinReleased (GdkEventButton* event) {
if ((event != NULL) && delay==0) {
if (delayConnection.connected())
delayConnection.disconnect ();
notifyListener();
}
}
void Adjuster::resetValue (bool toInitial) {
if (editedState!=Irrelevant) {
editedState = defEditedState;
if (editedCheckBox) {
editedChange.block (true);
editedCheckBox->set_active (defEditedState==Edited);
editedChange.block (false);
}
refreshLabelStyle ();
}
afterReset = true;
if (toInitial) {
// resetting to the initial editing value, when the image has been loaded
slider->set_value (addMode ? defaultVal : value2slider(defaultVal));
}
else {
// resetting to the slider default value
if (addMode)
slider->set_value (0.);
else
slider->set_value (value2slider(ctorDefaultVal));
}
}
// Please note that it won't change the "Auto" CheckBox's state, if there
void Adjuster::resetPressed (GdkEventButton* event) {
if ((event != NULL) && (event->state & GDK_CONTROL_MASK) && (event->button == 1))
resetValue(true);
else
resetValue(false);
}
double Adjuster::shapeValue (double a) {
return round(a*pow(double(10), digits)) / pow(double(10), digits);
}
void Adjuster::setLimits (double vmin, double vmax, double vstep, double vdefault) {
sliderChange.block (true);
spinChange.block (true);
for (digits=0; fabs(vstep*pow(double(10),digits)-floor(vstep*pow(double(10),digits)))>0.000000000001; digits++);
spin->set_digits (digits);
spin->set_increments (vstep, 2.0*vstep);
spin->set_range (vmin, vmax);
spin->updateSize();
spin->set_value (shapeValue(vdefault));
slider->set_digits (digits);
slider->set_increments (vstep, 2.0*vstep);
slider->set_range (addMode ? vmin : value2slider(vmin), addMode ? vmax : value2slider(vmax));
slider->set_value (addMode ? shapeValue(vdefault) : value2slider(shapeValue(vdefault)));
//defaultVal = shapeValue (vdefault);
sliderChange.block (false);
spinChange.block (false);
}
void Adjuster::setAddMode(bool addM) {
if (addM != addMode) {
// Switching the Adjuster to the new mode
addMode = addM;
if (addM) {
// Switching to the relative mode
double range = -vMin + vMax;
if (range < 0.) range = -range;
setLimits(-range, range, vStep, 0);
}
else {
// Switching to the absolute mode
setLimits(vMin, vMax, vStep, defaultVal);
}
}
}
void Adjuster::spinChanged () {
if (delayConnection.connected())
delayConnection.disconnect ();
sliderChange.block (true);
slider->set_value (addMode ? spin->get_value () : value2slider(spin->get_value ()));
sliderChange.block (false);
if (delay==0) {
if (adjusterListener && !blocked) {
if (!buttonReleaseSlider.connected() || afterReset) {
eventPending = false;
adjusterListener->adjusterChanged (this, spin->get_value ());
}
else eventPending = true;
}
}
else {
eventPending = true;
delayConnection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &Adjuster::notifyListener), delay);
}
if (editedState==UnEdited) {
editedState = Edited;
if (editedCheckBox) {
editedChange.block (true);
editedCheckBox->set_active (true);
editedChange.block (false);
}
refreshLabelStyle ();
}
afterReset = false;
}
void Adjuster::sliderChanged () {
if (delayConnection.connected())
delayConnection.disconnect ();
spinChange.block (true);
spin->set_value (addMode ? slider->get_value () : slider2value(slider->get_value ()));
spinChange.block (false);
if (delay==0 || afterReset) {
if (adjusterListener && !blocked) {
if (!buttonReleaseSlider.connected() || afterReset) {
eventPending = false;
adjusterListener->adjusterChanged (this, spin->get_value ());
}
else eventPending = true;
}
}
else {
eventPending = true;
delayConnection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &Adjuster::notifyListener), delay);
}
if (!afterReset && editedState==UnEdited) {
editedState = Edited;
if (editedCheckBox) {
editedChange.block (true);
editedCheckBox->set_active (true);
editedChange.block (false);
}
refreshLabelStyle ();
}
afterReset = false;
}
void Adjuster::setValue (double a) {
spinChange.block (true);
sliderChange.block (true);
spin->set_value (shapeValue (a));
slider->set_value (addMode ? shapeValue(a) : value2slider(shapeValue (a)));
sliderChange.block (false);
spinChange.block (false);
afterReset = false;
}
void Adjuster::setAutoValue (bool a) {
if (automatic) {
bool oldVal = autoChange.block(true);
automatic->set_active(a);
autoChange.block(oldVal);
if (!editedCheckBox) {
// If not used in the BatchEditor panel
if (a) {
// Disable the slider and spin button
spin->set_sensitive(false);
slider->set_sensitive(false);
}
else {
// Enable the slider and spin button
spin->set_sensitive(true);
slider->set_sensitive(true);
}
}
}
}
bool Adjuster::notifyListener () {
if (eventPending && adjusterListener!=NULL && !blocked) {
adjusterListener->adjusterChanged (this, spin->get_value ());
}
eventPending = false;
return false;
}
bool Adjuster::notifyListenerAutoToggled () {
if (adjusterListener!=NULL && !blocked) {
adjusterListener->adjusterAutoToggled(this, automatic->get_active());
}
return false;
}
void Adjuster::setEnabled (bool enabled) {
bool autoVal = automatic && !editedCheckBox ? automatic->get_active() : true;
spin->set_sensitive (enabled && autoVal);
slider->set_sensitive (enabled && autoVal);
if (automatic)
automatic->set_sensitive (enabled);
}
void Adjuster::setEditedState (EditedState eState) {
if (editedState!=eState) {
if (editedCheckBox) {
editedChange.block (true);
editedCheckBox->set_active (eState==Edited);
editedChange.block (false);
}
editedState = eState;
refreshLabelStyle ();
}
}
EditedState Adjuster::getEditedState () {
if (editedState!=Irrelevant && editedCheckBox)
editedState = editedCheckBox->get_active () ? Edited : UnEdited;
return editedState;
}
void Adjuster::showEditedCB () {
if (label)
removeIfThere(hbox, label, false);
if (!editedCheckBox) {
editedCheckBox = Gtk::manage(new Gtk::CheckButton (adjustmentName));
hbox->pack_start (*editedCheckBox, Gtk::PACK_SHRINK, 2);
hbox->reorder_child (*editedCheckBox, 0);
editedChange = editedCheckBox->signal_toggled().connect( sigc::mem_fun(*this, &Adjuster::editedToggled) );
editedCheckBox->show();
}
}
void Adjuster::refreshLabelStyle () {
/* Glib::RefPtr<Gtk::Style> style = label->get_style ();
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 Adjuster::editedToggled () {
if (adjusterListener && !blocked) {
adjusterListener->adjusterChanged (this, spin->get_value ());
}
eventPending = false;
}
double Adjuster::trimValue (double val) {
if (val > vMax) val = vMax; // shapeValue(vMax) ?
else if (val < vMin) val = vMin; // shapeValue(vMin) ?
return val;
}
int Adjuster::trimValue (int val) {
if (val > (int)vMax) val = (int)vMax; // shapeValue(vMax) ?
else if (val < (int)vMin) val = (int)vMin; // shapeValue(vMin) ?
return val;
}
float Adjuster::trimValue (float val) {
if (val > (float)vMax) val = (float)vMax; // shapeValue(vMax) ?
else if (val < (float)vMin) val = (float)vMin; // shapeValue(vMin) ?
return val;
}

134
rtgui/adjuster.h Normal file
View File

@@ -0,0 +1,134 @@
/*
* 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 _ADJUSTER_H_
#define _ADJUSTER_H_
#include <gtkmm.h>
#include "editedstate.h"
#include "guiutils.h"
class Adjuster;
class AdjusterListener {
public:
virtual ~AdjusterListener() {};
virtual void adjusterChanged (Adjuster* a, double newval) {}
virtual void adjusterAutoToggled (Adjuster* a, bool newval) {}
};
typedef double(*double2double_fun)(double val);
class Adjuster : public Gtk::VBox {
protected:
Glib::ustring adjustmentName;
Gtk::HBox* hbox;
Gtk::Label* label;
MyHScale* slider;
MySpinButton* spin;
Gtk::Button* reset;
Gtk::CheckButton* automatic;
AdjusterListener* adjusterListener;
sigc::connection delayConnection;
sigc::connection spinChange;
sigc::connection sliderChange;
sigc::connection editedChange;
sigc::connection autoChange;
sigc::connection buttonReleaseSlider;
sigc::connection buttonReleaseSpin;
bool listenerReady;
double defaultVal; // current default value (it can change when switching from ADD or SET mode)
double ctorDefaultVal; // default value at construction time
EditedState editedState;
EditedState defEditedState;
EditedState autoState;
EditedState defAutoState;
int digits;
Gtk::CheckButton* editedCheckBox;
bool afterReset;
bool blocked;
bool addMode;
bool eventPending;
double vMin;
double vMax;
double vStep;
double shapeValue (double a);
void refreshLabelStyle ();
double2double_fun value2slider, slider2value;
public:
int delay;
Adjuster (Glib::ustring vlabel, double vmin, double vmax, double vstep, double vdefault, Gtk::Image *imgIcon1=NULL, Gtk::Image *imgIcon2=NULL, double2double_fun slider2value=NULL, double2double_fun value2slider=NULL);
virtual ~Adjuster ();
// Add an "Automatic" checkbox next to the reset button.
void addAutoButton(Glib::ustring tooltip="");
// Remove the "Automatic" checkbox next to the reset button.
void delAutoButton();
// Send back the value of og the Auto checkbox
bool getAutoValue () { return automatic!=NULL ? automatic->get_active () : false; }
void setAutoValue (bool a);
bool notifyListenerAutoToggled ();
void autoToggled ();
void setAutoInconsistent (bool i) { if (automatic) automatic->set_inconsistent(i); }
bool getAutoInconsistent () { return automatic ? automatic->get_inconsistent() : true /* we have to return something */; }
void setAdjusterListener (AdjusterListener* alistener) { adjusterListener = alistener; }
// return the value trimmed to the limits at construction time
double getValue () { return shapeValue(spin->get_value ()); }
// return the value trimmed to the limits at construction time
int getIntValue () { return spin->get_value_as_int (); }
// return the value trimmed to the limits at construction time,
// method only used by the history manager, so decoration is added if addMode=true
Glib::ustring getTextValue () { if (addMode) return Glib::ustring::compose("<i>%1</i>", spin->get_text ()); else return spin->get_text (); }
void setLabel (Glib::ustring lbl) { label->set_label(lbl); }
void setValue (double a);
void setLimits (double vmin, double vmax, double vstep, double vdefault);
void setEnabled (bool enabled);
void setDefault (double def);
// will let the adjuster throw it's "changed" signal when the mouse button is released. Can work altogether with the delay value.
void throwOnButtonRelease(bool throwOnBRelease=true);
void setNbDisplayedChars (int nbr) { spin->set_width_chars(nbr); }
void setEditedState (EditedState eState);
EditedState getEditedState ();
void setDefaultEditedState (EditedState eState);
void showEditedCB ();
bool block(bool isBlocked) { bool oldValue = blocked; blocked = isBlocked; return oldValue; }
void setAddMode(bool addM);
bool getAddMode() { return addMode; };
void spinChanged ();
void sliderChanged ();
bool notifyListener ();
void sliderReleased (GdkEventButton* event);
void spinReleased (GdkEventButton* event);
void resetValue (bool toInitial);
void resetPressed (GdkEventButton* event);
void editedToggled ();
double trimValue (double val);
float trimValue (float val);
int trimValue (int val);
};
#endif

961
rtgui/batchqueue.cc Normal file
View File

@@ -0,0 +1,961 @@
/*
* 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 <glibmm.h>
#include <glib/gstdio.h>
#include <cstring>
#include "../rtengine/rt_math.h"
#include <iomanip>
#include <sstream>
#include <string>
#include "thumbnail.h"
#include "batchqueue.h"
#include "multilangmgr.h"
#include "filecatalog.h"
#include "batchqueuebuttonset.h"
#include "guiutils.h"
#include "../rtengine/safegtk.h"
#include "rtimage.h"
using namespace std;
using namespace rtengine;
BatchQueue::BatchQueue (FileCatalog* aFileCatalog) : processing(NULL), fileCatalog(aFileCatalog), sequence(0), listener(NULL) {
location = THLOC_BATCHQUEUE;
int p = 0;
pmenu = new Gtk::Menu ();
pmenu->attach (*Gtk::manage(open = new Gtk::MenuItem (M("FILEBROWSER_POPUPOPENINEDITOR"))), 0, 1, p, p+1); p++;
pmenu->attach (*Gtk::manage(selall = new Gtk::MenuItem (M("FILEBROWSER_POPUPSELECTALL"))), 0, 1, p, p+1); p++;
pmenu->attach (*Gtk::manage(new Gtk::SeparatorMenuItem ()), 0, 1, p, p+1); p++;
pmenu->attach (*Gtk::manage(head = new Gtk::ImageMenuItem (M("FILEBROWSER_POPUPMOVEHEAD"))), 0, 1, p, p+1); p++;
head->set_image(*Gtk::manage(new RTImage ("toleftend.png")));
pmenu->attach (*Gtk::manage(tail = new Gtk::ImageMenuItem (M("FILEBROWSER_POPUPMOVEEND"))), 0, 1, p, p+1); p++;
tail->set_image(*Gtk::manage(new RTImage ("torightend.png")));
pmenu->attach (*Gtk::manage(new Gtk::SeparatorMenuItem ()), 0, 1, p, p+1); p++;
pmenu->attach (*Gtk::manage(cancel = new Gtk::ImageMenuItem (M("FILEBROWSER_POPUPCANCELJOB"))), 0, 1, p, p+1); p++;
cancel->set_image(*Gtk::manage(new RTImage ("gtk-close.png")));
pmenu->show_all ();
// Accelerators
pmaccelgroup = Gtk::AccelGroup::create ();
pmenu->set_accel_group (pmaccelgroup);
open->add_accelerator ("activate", pmenu->get_accel_group(), GDK_e, Gdk::CONTROL_MASK, Gtk::ACCEL_VISIBLE);
selall->add_accelerator ("activate", pmenu->get_accel_group(), GDK_a, Gdk::CONTROL_MASK, Gtk::ACCEL_VISIBLE);
head->add_accelerator ("activate", pmenu->get_accel_group(), GDK_Home, (Gdk::ModifierType)0, Gtk::ACCEL_VISIBLE);
tail->add_accelerator ("activate", pmenu->get_accel_group(), GDK_End, (Gdk::ModifierType)0, Gtk::ACCEL_VISIBLE);
cancel->add_accelerator ("activate", pmenu->get_accel_group(), GDK_Delete, (Gdk::ModifierType)0, Gtk::ACCEL_VISIBLE);
open->signal_activate().connect(sigc::mem_fun(*this, &BatchQueue::openLastSelectedItemInEditor));
cancel->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &BatchQueue::cancelItems), &selected));
head->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &BatchQueue::headItems), &selected));
tail->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &BatchQueue::tailItems), &selected));
selall->signal_activate().connect (sigc::mem_fun(*this, &BatchQueue::selectAll));
setArrangement (ThumbBrowserBase::TB_Vertical);
}
BatchQueue::~BatchQueue ()
{
#if PROTECT_VECTORS
MYWRITERLOCK(l, entryRW);
#endif
// The listener merges parameters with old values, so delete afterwards
for (size_t i=0; i<fd.size(); i++)
{
delete fd.at(i);
}
fd.clear ();
delete pmenu;
}
void BatchQueue::resizeLoadedQueue() {
// TODO: Check for Linux
#if PROTECT_VECTORS
MYWRITERLOCK(l, entryRW);
#endif
for (size_t i=0; i<fd.size(); i++) {
fd.at(i)->resize(getThumbnailHeight());
}
}
// Reduce the max size of a thumb, since thumb is processed synchronously on adding to queue
// leading to very long waiting when adding more images
int BatchQueue::calcMaxThumbnailHeight() {
return std::min(options.maxThumbnailHeight, 200);
}
// Function for virtual override in thumbbrowser base
int BatchQueue::getMaxThumbnailHeight() const {
return calcMaxThumbnailHeight();
}
void BatchQueue::saveThumbnailHeight (int height) {
options.thumbSizeQueue = height;
}
int BatchQueue::getThumbnailHeight () {
// The user could have manually forced the option to a too big value
return std::max(std::min(options.thumbSizeQueue, 200), 10);
}
void BatchQueue::rightClicked (ThumbBrowserEntryBase* entry) {
pmenu->popup (3, this->eventTime);
}
void BatchQueue::doubleClicked(ThumbBrowserEntryBase* entry) {
openItemInEditor(entry);
}
bool BatchQueue::keyPressed (GdkEventKey* event) {
bool ctrl = event->state & GDK_CONTROL_MASK;
if ((event->keyval==GDK_A || event->keyval==GDK_a) && ctrl) {
selectAll ();
return true;
}
else if ((event->keyval==GDK_E || event->keyval== GDK_e) && ctrl) {
openLastSelectedItemInEditor();
return true;
}
else if (event->keyval==GDK_Home) {
headItems (&selected);
return true;
}
else if (event->keyval==GDK_End) {
tailItems (&selected);
return true;
}
else if (event->keyval==GDK_Delete) {
cancelItems (&selected);
return true;
}
return false;
}
void BatchQueue::addEntries ( std::vector<BatchQueueEntry*> &entries, bool head, bool save)
{
{
// TODO: Check for Linux
#if PROTECT_VECTORS
MYWRITERLOCK(l, entryRW);
#endif
for( std::vector<BatchQueueEntry*>::iterator entry = entries.begin(); entry != entries.end();entry++ ){
(*entry)->setParent (this);
// BatchQueueButtonSet HAVE TO be added before resizing to take them into account
BatchQueueButtonSet* bqbs = new BatchQueueButtonSet (*entry);
bqbs->setButtonListener (this);
(*entry)->addButtonSet (bqbs);
(*entry)->resize (getThumbnailHeight()); // batch queue might have smaller, restricted size
Glib::ustring tempFile = getTempFilenameForParams( (*entry)->filename );
// recovery save
if( !(*entry)->params.save( tempFile ) )
(*entry)->savedParamsFile = tempFile;
(*entry)->selected = false;
if (!head)
fd.push_back (*entry);
else {
std::vector<ThumbBrowserEntryBase*>::iterator pos;
for (pos=fd.begin(); pos!=fd.end(); pos++)
if (!(*pos)->processing) {
fd.insert (pos, *entry);
break;
}
if (pos==fd.end())
fd.push_back (*entry);
}
if ((*entry)->thumbnail)
(*entry)->thumbnail->imageEnqueued ();
}
}
if (save)
saveBatchQueue( );
redraw();
notifyListener (false);
}
bool BatchQueue::saveBatchQueue( )
{
Glib::ustring savedQueueFile;
savedQueueFile = options.rtdir+"/batch/queue.csv";
FILE *f = safe_g_fopen (savedQueueFile, "wt");
if (f==NULL)
return false;
{
// TODO: Check for Linux
#if PROTECT_VECTORS
MYREADERLOCK(l, entryRW);
#endif
if (fd.size())
// The column's header is mandatory (the first line will be skipped when loaded)
fprintf(f,"input image full path|param file full path|output image full path|file format|jpeg quality|jpeg subsampling|"
"png bit depth|png compression|tiff bit depth|uncompressed tiff|save output params|force format options|<end of line>\n");
// method is already running with entryLock, so no need to lock again
for (std::vector<ThumbBrowserEntryBase*>::iterator pos=fd.begin(); pos!=fd.end(); pos++){
BatchQueueEntry* bqe = reinterpret_cast<BatchQueueEntry*>(*pos);
// Warning: for code's simplicity in loadBatchQueue, each field must end by the '|' character, safer than ';' or ',' since it can't be used in paths
fprintf(f,"%s|%s|%s|%s|%d|%d|%d|%d|%d|%d|%d|%d|\n",
bqe->filename.c_str(),bqe->savedParamsFile.c_str(), bqe->outFileName.c_str(), bqe->saveFormat.format.c_str(),
bqe->saveFormat.jpegQuality, bqe->saveFormat.jpegSubSamp,
bqe->saveFormat.pngBits, bqe->saveFormat.pngCompression,
bqe->saveFormat.tiffBits, bqe->saveFormat.tiffUncompressed,
bqe->saveFormat.saveParams, bqe->forceFormatOpts
);
}
}
fclose (f);
return true;
}
bool BatchQueue::loadBatchQueue( )
{
Glib::ustring savedQueueFile;
savedQueueFile = options.rtdir+"/batch/queue.csv";
FILE *f = safe_g_fopen (savedQueueFile, "rt");
if (f!=NULL) {
char *buffer = new char[1024];
unsigned numLoaded=0;
// skipping the first line
bool firstLine=true;
// Yes, it's better to get the lock for the whole file reading,
// to update the list in one shot without any other concurrent access!
// TODO: Check for Linux
#if PROTECT_VECTORS
MYWRITERLOCK(l, entryRW);
#endif
while (fgets (buffer, 1024, f)){
if (firstLine) {
// skipping the column's title line
firstLine=false;
continue;
}
size_t pos;
Glib::ustring source;
Glib::ustring paramsFile;
Glib::ustring outputFile;
Glib::ustring saveFmt(options.saveFormat.format);
int jpegQuality=options.saveFormat.jpegQuality, jpegSubSamp =options.saveFormat.jpegSubSamp;
int pngBits =options.saveFormat.pngBits, pngCompression =options.saveFormat.pngCompression;
int tiffBits =options.saveFormat.tiffBits, tiffUncompressed=options.saveFormat.tiffUncompressed;
int saveParams =options.saveFormat.saveParams;
int forceFormatOpts =options.forceFormatOpts;
Glib::ustring currLine(buffer);
int a = 0;
if (currLine.rfind('\n') != Glib::ustring::npos) a++;
if (currLine.rfind('\r') != Glib::ustring::npos) a++;
if (a)
currLine = currLine.substr(0, currLine.length()-a);
// Looking for the image's full path
pos = currLine.find('|');
if (pos != Glib::ustring::npos) {
source = currLine.substr(0, pos);
currLine = currLine.substr(pos+1);
// Looking for the procparams' full path
pos = currLine.find('|');
if (pos != Glib::ustring::npos) {
paramsFile = currLine.substr(0, pos);
currLine = currLine.substr(pos+1);
// Looking for the full output path; if empty, it'll use the template string
pos = currLine.find('|');
if (pos != Glib::ustring::npos) {
outputFile = currLine.substr(0, pos);
currLine = currLine.substr(pos+1);
// No need to bother reading the last options, they will be ignored if outputFile is empty!
if (!outputFile.empty()) {
// Looking for the saving format
pos = currLine.find('|');
if (pos != Glib::ustring::npos) {
saveFmt = currLine.substr(0, pos);
currLine = currLine.substr(pos+1);
// Looking for the jpeg quality
pos = currLine.find('|');
if (pos != Glib::ustring::npos) {
jpegQuality = atoi(currLine.substr(0, pos).c_str());
currLine = currLine.substr(pos+1);
// Looking for the jpeg subsampling
pos = currLine.find('|');
if (pos != Glib::ustring::npos) {
jpegSubSamp = atoi(currLine.substr(0, pos).c_str());
currLine = currLine.substr(pos+1);
// Looking for the png bit depth
pos = currLine.find('|');
if (pos != Glib::ustring::npos) {
pngBits = atoi(currLine.substr(0, pos).c_str());
currLine = currLine.substr(pos+1);
// Looking for the png compression
pos = currLine.find('|');
if (pos != Glib::ustring::npos) {
pngCompression = atoi(currLine.substr(0, pos).c_str());
currLine = currLine.substr(pos+1);
// Looking for the tiff bit depth
pos = currLine.find('|');
if (pos != Glib::ustring::npos) {
tiffBits = atoi(currLine.substr(0, pos).c_str());
currLine = currLine.substr(pos+1);
// Looking for the tiff uncompression
pos = currLine.find('|');
if (pos != Glib::ustring::npos) {
tiffUncompressed = atoi(currLine.substr(0, pos).c_str());
currLine = currLine.substr(pos+1);
// Looking out if we have to save the procparams
pos = currLine.find('|');
if (pos != Glib::ustring::npos) {
saveParams = atoi(currLine.substr(0, pos).c_str());
currLine = currLine.substr(pos+1);
// Looking out if we have to to use the format options
pos = currLine.find('|');
if (pos != Glib::ustring::npos) {
forceFormatOpts = atoi(currLine.substr(0, pos).c_str());
// currLine = currLine.substr(pos+1);
}}}}}}}}}}}}}
if( !source.empty() && !paramsFile.empty() ){
rtengine::procparams::ProcParams pparams;
if( pparams.load( paramsFile ) )
continue;
::Thumbnail *thumb = cacheMgr->getEntry( source );
if( thumb ){
rtengine::ProcessingJob* job = rtengine::ProcessingJob::create(source, thumb->getType() == FT_Raw, pparams);
int prevh = getMaxThumbnailHeight();
int prevw = prevh;
thumb->getThumbnailSize (prevw, prevh, &pparams);
BatchQueueEntry *entry = new BatchQueueEntry(job, pparams,source, prevw, prevh, thumb);
thumb->decreaseRef(); // Removing the refCount acquired by cacheMgr->getEntry
entry->setParent(this);
// BatchQueueButtonSet HAVE TO be added before resizing to take them into account
BatchQueueButtonSet* bqbs = new BatchQueueButtonSet(entry);
bqbs->setButtonListener(this);
entry->addButtonSet(bqbs);
//entry->resize(getThumbnailHeight());
entry->savedParamsFile = paramsFile;
entry->selected = false;
entry->outFileName = outputFile;
if (!outputFile.empty()) {
entry->saveFormat.format = saveFmt;
entry->saveFormat.jpegQuality = jpegQuality;
entry->saveFormat.jpegSubSamp = jpegSubSamp;
entry->saveFormat.pngBits = pngBits;
entry->saveFormat.pngCompression = pngCompression;
entry->saveFormat.tiffBits = tiffBits;
entry->saveFormat.tiffUncompressed = tiffUncompressed!=0;
entry->saveFormat.saveParams = saveParams!=0;
entry->forceFormatOpts = forceFormatOpts!=0;
}
else
entry->forceFormatOpts = false;
fd.push_back(entry);
numLoaded++;
}
}
}
delete [] buffer;
fclose(f);
}
redraw();
notifyListener(false);
return !fd.empty();
}
Glib::ustring BatchQueue::getTempFilenameForParams( const Glib::ustring filename )
{
time_t rawtime;
struct tm *timeinfo;
char stringTimestamp [80];
time ( &rawtime );
timeinfo = localtime ( &rawtime );
strftime (stringTimestamp,sizeof(stringTimestamp),"_%Y%m%d%H%M%S_",timeinfo);
Glib::ustring savedParamPath;
savedParamPath = options.rtdir+"/batch/";
safe_g_mkdir_with_parents (savedParamPath, 0755);
savedParamPath += Glib::path_get_basename (filename);
savedParamPath += stringTimestamp;
savedParamPath += paramFileExtension;
return savedParamPath;
}
int cancelItemUI (void* data)
{
safe_g_remove( (static_cast<BatchQueueEntry*>(data))->savedParamsFile );
delete static_cast<BatchQueueEntry*>(data);
return 0;
}
void BatchQueue::cancelItems (std::vector<ThumbBrowserEntryBase*>* items) {
{
// TODO: Check for Linux
#if PROTECT_VECTORS
MYWRITERLOCK(l, entryRW);
#endif
for (size_t i=0; i<items->size(); i++) {
BatchQueueEntry* entry = (BatchQueueEntry*)(*items)[i];
if (entry->processing)
continue;
std::vector<ThumbBrowserEntryBase*>::iterator pos = std::find (fd.begin(), fd.end(), entry);
if (pos!=fd.end()) {
fd.erase (pos);
rtengine::ProcessingJob::destroy (entry->job);
if (entry->thumbnail)
entry->thumbnail->imageRemovedFromQueue ();
g_idle_add (cancelItemUI, entry);
}
}
for (size_t i=0; i<fd.size(); i++)
fd[i]->selected = false;
lastClicked = NULL;
selected.clear ();
}
saveBatchQueue( );
redraw ();
notifyListener (false);
}
void BatchQueue::headItems (std::vector<ThumbBrowserEntryBase*>* items) {
{
// TODO: Check for Linux
#if PROTECT_VECTORS
MYWRITERLOCK(l, entryRW);
#endif
for (int i=items->size()-1; i>=0; i--) {
BatchQueueEntry* entry = (BatchQueueEntry*)(*items)[i];
if (entry->processing)
continue;
std::vector<ThumbBrowserEntryBase*>::iterator pos = std::find (fd.begin(), fd.end(), entry);
if (pos!=fd.end() && pos!=fd.begin()) {
fd.erase (pos);
// find the first item that is not under processing
for (pos=fd.begin(); pos!=fd.end(); pos++)
if (!(*pos)->processing) {
fd.insert (pos, entry);
break;
}
}
}
}
saveBatchQueue( );
redraw ();
}
void BatchQueue::tailItems (std::vector<ThumbBrowserEntryBase*>* items) {
{
// TODO: Check for Linux
#if PROTECT_VECTORS
MYWRITERLOCK(l, entryRW);
#endif
for (size_t i=0; i<items->size(); i++) {
BatchQueueEntry* entry = (BatchQueueEntry*)(*items)[i];
if (entry->processing)
continue;
std::vector<ThumbBrowserEntryBase*>::iterator pos = std::find (fd.begin(), fd.end(), entry);
if (pos!=fd.end()) {
fd.erase (pos);
fd.push_back (entry);
}
}
}
saveBatchQueue( );
redraw ();
}
void BatchQueue::selectAll () {
{
// TODO: Check for Linux
#if PROTECT_VECTORS
MYWRITERLOCK(l, entryRW);
#endif
lastClicked = NULL;
selected.clear ();
for (size_t i=0; i<fd.size(); i++) {
if (fd[i]->processing)
continue;
fd[i]->selected = true;
selected.push_back (fd[i]);
}
}
queue_draw ();
}
void BatchQueue::openLastSelectedItemInEditor() {
{
// TODO: Check for Linux
#if PROTECT_VECTORS
MYREADERLOCK(l, entryRW);
#endif
if (selected.size() > 0) {
openItemInEditor(selected.back());
}
}
}
void BatchQueue::openItemInEditor(ThumbBrowserEntryBase* item) {
if (item) {
std::vector< ::Thumbnail*> requestedItem;
requestedItem.push_back(item->thumbnail);
fileCatalog->openRequested(requestedItem);
}
}
void BatchQueue::startProcessing () {
if (!processing) {
// TODO: Check for Linux
#if PROTECT_VECTORS
MYWRITERLOCK(l, entryRW);
#endif
if (!fd.empty()) {
BatchQueueEntry* next;
next = static_cast<BatchQueueEntry*>(fd[0]);
// tag it as processing and set sequence
next->processing = true;
next->sequence = sequence = 1;
processing = next;
// remove from selection
if (processing->selected) {
std::vector<ThumbBrowserEntryBase*>::iterator pos = std::find (selected.begin(), selected.end(), processing);
if (pos!=selected.end())
selected.erase (pos);
processing->selected = false;
}
#if PROTECT_VECTORS
MYWRITERLOCK_RELEASE(l);
#endif
// remove button set
next->removeButtonSet ();
// start batch processing
rtengine::startBatchProcessing (next->job, this, options.tunnelMetaData);
queue_draw ();
}
}
}
rtengine::ProcessingJob* BatchQueue::imageReady (rtengine::IImage16* img) {
// save image img
Glib::ustring fname;
SaveFormat saveFormat;
if (processing->outFileName=="") { // auto file name
Glib::ustring s = calcAutoFileNameBase (processing->filename, processing->sequence);
saveFormat = options.saveFormatBatch;
fname = autoCompleteFileName (s, saveFormat.format);
}
else { // use the save-as filename with automatic completion for uniqueness
if (processing->forceFormatOpts)
saveFormat = processing->saveFormat;
else
saveFormat = options.saveFormatBatch;
// The output filename's extension is forced to the current or selected output format,
// despite what the user have set in the fielneame's field of the "Save as" dialgo box
fname = autoCompleteFileName (removeExtension(processing->outFileName), saveFormat.format);
//fname = autoCompleteFileName (removeExtension(processing->outFileName), getExtension(processing->outFileName));
}
//printf ("fname=%s, %s\n", fname.c_str(), removeExtension(fname).c_str());
if (img && fname!="") {
int err = 0;
if (saveFormat.format=="tif")
err = img->saveAsTIFF (fname, saveFormat.tiffBits,saveFormat.tiffUncompressed);
else if (saveFormat.format=="png")
err = img->saveAsPNG (fname, saveFormat.pngCompression, saveFormat.pngBits);
else if (saveFormat.format=="jpg")
err = img->saveAsJPEG (fname, saveFormat.jpegQuality, saveFormat.jpegSubSamp);
img->free ();
if (err)
throw Glib::FileError(Glib::FileError::FAILED, M("MAIN_MSG_CANNOTSAVE")+"\n"+fname);
if (saveFormat.saveParams) {
// We keep the extension to avoid overwriting the profile when we have
// the same output filename with different extension
//processing->params.save (removeExtension(fname) + paramFileExtension);
processing->params.save (fname + ".out" + paramFileExtension);
}
if (processing->thumbnail) {
processing->thumbnail->imageDeveloped ();
processing->thumbnail->imageRemovedFromQueue ();
}
}
// save temporary params file name: delete as last thing
Glib::ustring processedParams = processing->savedParamsFile;
// delete from the queue
bool queueEmptied=false;
bool remove_button_set = false;
{
// TODO: Check for Linux
#if PROTECT_VECTORS
MYWRITERLOCK(l, entryRW);
#endif
delete processing;
processing = NULL;
fd.erase (fd.begin());
// return next job
if (fd.empty()) {
queueEmptied=true;
}
else if (listener && listener->canStartNext ()) {
BatchQueueEntry* next = static_cast<BatchQueueEntry*>(fd[0]);
// tag it as selected and set sequence
next->processing = true;
next->sequence = ++sequence;
processing = next;
// remove from selection
if (processing->selected) {
std::vector<ThumbBrowserEntryBase*>::iterator pos = std::find (selected.begin(), selected.end(), processing);
if (pos!=selected.end())
selected.erase (pos);
processing->selected = false;
}
// remove button set
remove_button_set = true;
}
}
if (remove_button_set) {
// ButtonSet have Cairo::Surface which might be rendered while we're trying to delete them
GThreadLock lock;
processing->removeButtonSet ();
}
if (saveBatchQueue( )) {
safe_g_remove( processedParams );
// Delete all files in directory \batch when finished, just to be sure to remove zombies
// Not sure that locking is necessary, but it should be safer
// TODO: Check for Linux
#if PROTECT_VECTORS
MYREADERLOCK(l, entryRW);
#endif
if( fd.empty() ){
#if PROTECT_VECTORS
MYREADERLOCK_RELEASE(l);
#endif
std::vector<Glib::ustring> names;
Glib::ustring batchdir = Glib::build_filename(options.rtdir, "batch");
Glib::RefPtr<Gio::File> dir = Gio::File::create_for_path (batchdir);
safe_build_file_list (dir, names, batchdir);
for(std::vector<Glib::ustring>::iterator iter=names.begin(); iter != names.end();iter++ )
safe_g_remove( *iter );
}
}
redraw ();
notifyListener (queueEmptied);
return processing ? processing->job : NULL;
}
// Calculates automatic filename of processed batch entry, but just the base name
// example output: "c:\out\converted\dsc0121"
Glib::ustring BatchQueue::calcAutoFileNameBase (const Glib::ustring& origFileName, int sequence) {
std::vector<Glib::ustring> pa;
std::vector<Glib::ustring> da;
for (size_t i=0; i<origFileName.size(); i++) {
while ((i<origFileName.size()) && (origFileName[i]=='\\' || origFileName[i]=='/'))
i++;
if (i>=origFileName.size())
break;
Glib::ustring tok = "";
while ((i<origFileName.size()) && !(origFileName[i]=='\\' || origFileName[i]=='/'))
tok = tok + origFileName[i++];
da.push_back (tok);
}
if (origFileName[0]=='/' || origFileName[0]=='\\')
pa.push_back ("/" + da[0]);
else
pa.push_back (da[0]);
for (size_t i=1; i<da.size(); i++)
pa.push_back (pa[i-1] + "/" + da[i]);
// for (int i=0; i<da.size(); i++)
// printf ("da: %s\n", da[i].c_str());
// for (int i=0; i<pa.size(); i++)
// printf ("pa: %s\n", pa[i].c_str());
// extracting filebase
Glib::ustring filename;
int extpos = origFileName.size()-1;
for (; extpos>=0 && origFileName[extpos]!='.'; extpos--);
for (int k=extpos-1; k>=0 && origFileName[k]!='/' && origFileName[k]!='\\'; k--)
filename = origFileName[k] + filename;
// printf ("%d, |%s|\n", extpos, filename.c_str());
// constructing full output path
// printf ("path=|%s|\n", options.savePath.c_str());
Glib::ustring path="";
if (options.saveUsePathTemplate) {
int ix=0;
while (options.savePathTemplate[ix]!=0) {
if (options.savePathTemplate[ix]=='%') {
ix++;
if (options.savePathTemplate[ix]=='p') {
ix++;
int i = options.savePathTemplate[ix]-'0';
if (i<pa.size())
path = path + pa[pa.size()-i-1] + '/';
ix++;
}
else if (options.savePathTemplate[ix]=='d') {
ix++;
int i = options.savePathTemplate[ix]-'0';
if (i<da.size())
path = path + da[da.size()-i-1];
}
else if (options.savePathTemplate[ix]=='f') {
path = path + filename;
}
else if (options.savePathTemplate[ix]=='r') { // rank from pparams
char rank;
rtengine::procparams::ProcParams pparams;
if( pparams.load(origFileName + paramFileExtension)==0 ){
if (!pparams.inTrash)
rank = pparams.rank + '0';
else
rank = 'x';
}
else
rank = '0'; // if param file not loaded (e.g. does not exist), default to rank=0
path += rank;
}
else if (options.savePathTemplate[ix]=='s') { // sequence
std::ostringstream seqstr;
int w = options.savePathTemplate[ix+1]-'0';
if (w>=1 && w<=9) {
ix++;
seqstr << std::setw (w) << std::setfill ('0');
}
seqstr << sequence;
path += seqstr.str ();
}
}
else
path = path + options.savePathTemplate[ix];
ix++;
}
}
else
path = Glib::build_filename (options.savePathFolder, filename);
return path;
}
Glib::ustring BatchQueue::autoCompleteFileName (const Glib::ustring& fileName, const Glib::ustring& format) {
// separate filename and the path to the destination directory
Glib::ustring dstdir = Glib::path_get_dirname (fileName);
Glib::ustring dstfname = Glib::path_get_basename (fileName);
Glib::ustring fname;
// create directory, if does not exist
if (safe_g_mkdir_with_parents (dstdir, 0755) )
return "";
// In overwrite mode we TRY to delete the old file first.
// if that's not possible (e.g. locked by viewer, R/O), we revert to the standard naming scheme
bool inOverwriteMode=options.overwriteOutputFile;
for (int tries=0; tries<100; tries++) {
if (tries==0)
fname = Glib::ustring::compose ("%1.%2", Glib::build_filename (dstdir, dstfname), format);
else
fname = Glib::ustring::compose ("%1-%2.%3", Glib::build_filename (dstdir, dstfname), tries, format);
int fileExists=safe_file_test (fname, Glib::FILE_TEST_EXISTS);
if (inOverwriteMode && fileExists) {
if (safe_g_remove(fname) == -1)
inOverwriteMode = false; // failed to delete- revert to old naming scheme
else
fileExists = false; // deleted now
}
if (!fileExists) {
return fname;
}
}
return "";
}
int setProgressUI (void* p) {
(static_cast<BatchQueue*>(p))->redraw();
return 0;
}
void BatchQueue::setProgress (double p) {
if (processing)
processing->progress = p;
// No need to acquire the GUI, setProgressUI will do it
g_idle_add (setProgressUI, this);
}
void BatchQueue::buttonPressed (LWButton* button, int actionCode, void* actionData) {
std::vector<ThumbBrowserEntryBase*> bqe;
bqe.push_back (static_cast<BatchQueueEntry*>(actionData));
if (actionCode==10) // cancel
cancelItems (&bqe);
else if (actionCode==8) // to head
headItems (&bqe);
else if (actionCode==9) // to tail
tailItems (&bqe);
}
struct NLParams {
BatchQueueListener* listener;
int qsize;
bool queueEmptied;
bool queueError;
Glib::ustring queueErrorMessage;
};
int bqnotifylistenerUI (void* data) {
GThreadLock lock; // All GUI acces from idle_add callbacks or separate thread HAVE to be protected
NLParams* params = static_cast<NLParams*>(data);
params->listener->queueSizeChanged (params->qsize, params->queueEmptied, params->queueError, params->queueErrorMessage);
delete params;
return 0;
}
void BatchQueue::notifyListener (bool queueEmptied) {
if (listener) {
NLParams* params = new NLParams;
params->listener = listener;
{
// TODO: Check for Linux
#if PROTECT_VECTORS
MYREADERLOCK(l, entryRW);
#endif
params->qsize = fd.size();
}
params->queueEmptied = queueEmptied;
params->queueError = false;
g_idle_add (bqnotifylistenerUI, params);
}
}
void BatchQueue::redrawNeeded (LWButton* button) {
GThreadLock lock;
queue_draw ();
}
void BatchQueue::error (Glib::ustring msg) {
if (processing && processing->processing) {
// restore failed thumb
BatchQueueButtonSet* bqbs = new BatchQueueButtonSet (processing);
bqbs->setButtonListener (this);
processing->addButtonSet (bqbs);
processing->processing = false;
processing->job = rtengine::ProcessingJob::create(processing->filename, processing->thumbnail->getType() == FT_Raw, processing->params);
processing = NULL;
redraw ();
}
if (listener) {
NLParams* params = new NLParams;
params->listener = listener;
params->queueEmptied = false;
params->queueError = true;
params->queueErrorMessage = msg;
g_idle_add (bqnotifylistenerUI, params);
}
}

110
rtgui/batchqueue.h Executable file
View File

@@ -0,0 +1,110 @@
/*
* This file is part of RawTherapee.
*
*
* 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 _BATCHQUEUE_
#define _BATCHQUEUE_
#include <gtkmm.h>
#include "threadutils.h"
#include "batchqueueentry.h"
#include "../rtengine/rtengine.h"
#include "options.h"
#include "lwbuttonset.h"
#include "thumbbrowserbase.h"
class BatchQueueListener {
public:
virtual ~BatchQueueListener () {}
virtual void queueSizeChanged (int qsize, bool queueEmptied, bool queueError, Glib::ustring queueErrorMessage) =0;
virtual bool canStartNext () =0;
};
class FileCatalog;
class BatchQueue : public ThumbBrowserBase,
public rtengine::BatchProcessingListener,
public LWButtonListener {
protected:
int getMaxThumbnailHeight() const;
void saveThumbnailHeight (int height);
int getThumbnailHeight ();
BatchQueueEntry* processing; // holds the currently processed image
FileCatalog* fileCatalog;
int sequence; // holds the current sequence index
Glib::ustring nameTemplate;
Gtk::ImageMenuItem* cancel;
Gtk::ImageMenuItem* head;
Gtk::ImageMenuItem* tail;
Gtk::MenuItem* selall;
Gtk::MenuItem* open;
Gtk::Menu* pmenu;
Glib::RefPtr<Gtk::AccelGroup> pmaccelgroup;
BatchQueueListener* listener;
Glib::ustring autoCompleteFileName (const Glib::ustring& fileName, const Glib::ustring& format);
Glib::ustring getTempFilenameForParams( const Glib::ustring filename );
bool saveBatchQueue( );
void notifyListener (bool queueEmptied);
public:
BatchQueue (FileCatalog* aFileCatalog);
~BatchQueue ();
void addEntries (std::vector<BatchQueueEntry*> &entries, bool head=false, bool save=true);
void cancelItems (std::vector<ThumbBrowserEntryBase*>* items);
void headItems (std::vector<ThumbBrowserEntryBase*>* items);
void tailItems (std::vector<ThumbBrowserEntryBase*>* items);
void selectAll ();
void openItemInEditor(ThumbBrowserEntryBase* item);
void openLastSelectedItemInEditor();
void startProcessing ();
bool hasJobs () {
// not sure that this lock is necessary, but it's safer to keep it...
// TODO: Check for Linux
#if PROTECT_VECTORS
MYREADERLOCK(l, entryRW);
#endif
return (!fd.empty());
}
rtengine::ProcessingJob* imageReady (rtengine::IImage16* img);
void error (Glib::ustring msg);
void setProgress (double p);
void rightClicked (ThumbBrowserEntryBase* entry);
void doubleClicked (ThumbBrowserEntryBase* entry);
bool keyPressed (GdkEventKey* event);
void buttonPressed (LWButton* button, int actionCode, void* actionData);
void redrawNeeded (LWButton* button);
void setBatchQueueListener (BatchQueueListener* l) { listener = l; }
bool loadBatchQueue ();
void resizeLoadedQueue();
static Glib::ustring calcAutoFileNameBase (const Glib::ustring& origFileName, int sequence = 0);
static int calcMaxThumbnailHeight();
};
#endif

View File

@@ -0,0 +1,43 @@
/*
* 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 "batchqueuebuttonset.h"
#include "multilangmgr.h"
#include "../rtengine/safegtk.h"
extern Glib::ustring argv0;
bool BatchQueueButtonSet::iconsLoaded = false;
Cairo::RefPtr<Cairo::ImageSurface> BatchQueueButtonSet::cancelIcon;
Cairo::RefPtr<Cairo::ImageSurface> BatchQueueButtonSet::headIcon;
Cairo::RefPtr<Cairo::ImageSurface> BatchQueueButtonSet::tailIcon;
BatchQueueButtonSet::BatchQueueButtonSet (BatchQueueEntry* myEntry) {
if (!iconsLoaded) {
cancelIcon = safe_create_from_png ("gtk-close.png");
headIcon = safe_create_from_png ("toleftend.png");
tailIcon = safe_create_from_png ("torightend.png");
iconsLoaded = true;
}
add (new LWButton (headIcon, 8, myEntry, LWButton::Left, LWButton::Center, M("FILEBROWSER_POPUPMOVEHEAD")));
add (new LWButton (tailIcon, 9, myEntry, LWButton::Left, LWButton::Center, M("FILEBROWSER_POPUPMOVEEND")));
add (new LWButton (cancelIcon, 10, myEntry, LWButton::Right, LWButton::Center, M("FILEBROWSER_POPUPCANCELJOB")));
}

View File

@@ -0,0 +1,38 @@
/*
* 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 _BATCHQUEUEBUTTONSET_
#define _BATCHQUEUEBUTTONSET_
#include "lwbuttonset.h"
#include <gtkmm.h>
class BatchQueueEntry;
class BatchQueueButtonSet : public LWButtonSet {
static bool iconsLoaded;
public:
static Cairo::RefPtr<Cairo::ImageSurface> cancelIcon;
static Cairo::RefPtr<Cairo::ImageSurface> headIcon;
static Cairo::RefPtr<Cairo::ImageSurface> tailIcon;
BatchQueueButtonSet (BatchQueueEntry* myEntry);
};
#endif

236
rtgui/batchqueueentry.cc Normal file
View File

@@ -0,0 +1,236 @@
/*
* 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 "batchqueueentry.h"
#include "thumbbrowserbase.h"
#include <cstring>
#include "guiutils.h"
#include "threadutils.h"
#include "../rtengine/safegtk.h"
#include "multilangmgr.h"
bool BatchQueueEntry::iconsLoaded(false);
Glib::RefPtr<Gdk::Pixbuf> BatchQueueEntry::savedAsIcon;
BatchQueueEntry::BatchQueueEntry (rtengine::ProcessingJob* pjob, const rtengine::procparams::ProcParams& pparams, Glib::ustring fname, int prevw, int prevh, Thumbnail* thm)
: ThumbBrowserEntryBase(fname),
opreview(NULL), origpw(prevw), origph(prevh), opreviewDone(false),
job(pjob), progress(0), outFileName(""), sequence(0), forceFormatOpts(false) {
thumbnail=thm;
params = pparams;
#if 1 //ndef WIN32
// The BatchQueueEntryIdleHelper tracks if an entry has been deleted while it was sitting waiting for "idle"
bqih = new BatchQueueEntryIdleHelper;
bqih->bqentry = this;
bqih->destroyed = false;
bqih->pending = 0;
#endif
if (!iconsLoaded) {
savedAsIcon = safe_create_from_file ("gtk-save.png");
iconsLoaded = true;
}
if (thumbnail)
thumbnail->increaseRef ();
}
BatchQueueEntry::~BatchQueueEntry () {
batchQueueEntryUpdater.removeJobs (this);
if (opreview) delete [] opreview; opreview=NULL;
if (thumbnail)
thumbnail->decreaseRef ();
if (bqih->pending)
bqih->destroyed = true;
else
delete bqih;
}
void BatchQueueEntry::refreshThumbnailImage () {
if (!opreviewDone) {
// creating the image buffer first
//if (!opreview) opreview = new guint8[(origpw+1) * origph * 3];
// this will asynchronously compute the original preview and land at this.updateImage
batchQueueEntryUpdater.process (NULL, origpw, origph, preh, this, &params, thumbnail);
}
else {
// this will asynchronously land at this.updateImage
batchQueueEntryUpdater.process (opreview, origpw, origph, preh, this);
}
}
void BatchQueueEntry::calcThumbnailSize () {
prew = preh * origpw / origph;
}
void BatchQueueEntry::drawProgressBar (Glib::RefPtr<Gdk::Window> win, Glib::RefPtr<Gdk::GC> gc, const Gdk::Color& foregr, const Gdk::Color& backgr, int x, int w, int y, int h) {
if (processing) {
Cairo::RefPtr<Cairo::Context> cr = win->create_cairo_context();
cr->set_antialias (Cairo::ANTIALIAS_SUBPIXEL);
double px = x + w/6.0;
double pw = w*2.0/3.0;
double py = y + h/4.0;
double ph = h/2.0;
cr->move_to (px, py);
cr->line_to (px+pw, py);
cr->set_line_width (ph);
cr->set_line_cap (Cairo::LINE_CAP_ROUND);
cr->set_source_rgb (foregr.get_red_p(), foregr.get_green_p(), foregr.get_blue_p());
cr->stroke ();
cr->move_to (px, py);
cr->line_to (px+pw, py);
cr->set_line_width (ph*3.0/4.0);
cr->set_source_rgb (backgr.get_red_p(), backgr.get_green_p(), backgr.get_blue_p());
cr->stroke ();
cr->move_to (px, py);
cr->line_to (px+pw*progress, py);
cr->set_line_width (ph/2.0);
cr->set_source_rgb (foregr.get_red_p(), foregr.get_green_p(), foregr.get_blue_p());
cr->stroke ();
}
}
void BatchQueueEntry::removeButtonSet () {
delete buttonSet;
buttonSet = NULL;
}
std::vector<Glib::RefPtr<Gdk::Pixbuf> > BatchQueueEntry::getIconsOnImageArea () {
std::vector<Glib::RefPtr<Gdk::Pixbuf> > ret;
if (!outFileName.empty())
ret.push_back (savedAsIcon);
return ret;
}
void BatchQueueEntry::getIconSize (int& w, int& h) {
w = savedAsIcon->get_width ();
h = savedAsIcon->get_height ();
}
Glib::ustring BatchQueueEntry::getToolTip (int x, int y) {
// get the parent class' tooltip first
Glib::ustring tooltip = ThumbBrowserEntryBase::getToolTip(x, y);
// add the saving param options
if (!outFileName.empty()) {
tooltip += Glib::ustring::compose("\n\n%1: %2", M("BATCHQUEUE_DESTFILENAME"), outFileName);
if (forceFormatOpts) {
tooltip += Glib::ustring::compose("\n\n%1: %2 (%3 bits)", M("SAVEDLG_FILEFORMAT"), saveFormat.format,
saveFormat.format == "png" ? saveFormat.pngBits :
saveFormat.format == "tif" ? saveFormat.tiffBits : 8);
if (saveFormat.format == "jpg") {
tooltip += Glib::ustring::compose("\n%1: %2\n%3: %4",
M("SAVEDLG_JPEGQUAL"), saveFormat.jpegQuality,
M("SAVEDLG_SUBSAMP"),
saveFormat.jpegSubSamp==1 ? M("SAVEDLG_SUBSAMP_1") :
saveFormat.jpegSubSamp==2 ? M("SAVEDLG_SUBSAMP_2") :
M("SAVEDLG_SUBSAMP_3"));
}
else if (saveFormat.format == "png")
tooltip += Glib::ustring::compose("\n%1: %2", M("SAVEDLG_PNGCOMPR"), saveFormat.pngCompression);
else if (saveFormat.format == "tif") {
if (saveFormat.tiffUncompressed)
tooltip += Glib::ustring::compose("\n%1", M("SAVEDLG_TIFFUNCOMPRESSED"));
}
}
}
return tooltip;
}
struct BQUpdateParam {
BatchQueueEntryIdleHelper* bqih;
guint8* img;
int w,h;
};
int updateImageUIThread (void* data) {
BQUpdateParam* params = static_cast<BQUpdateParam*>(data);
BatchQueueEntryIdleHelper* bqih = params->bqih;
GThreadLock tLock; // Acquire the GUI
// If the BQEntry was destroyed meanwhile, remove all the IdleHelper if all entries came through
if (bqih->destroyed) {
if (bqih->pending == 1)
delete bqih;
else
bqih->pending--;
delete [] params->img;
delete params;
return 0;
}
bqih->bqentry->_updateImage (params->img, params->w, params->h);
bqih->pending--;
delete params;
return 0;
}
// Starts a copy of img->preview via GTK thread
void BatchQueueEntry::updateImage (guint8* img, int w, int h, int origw, int origh, guint8* newOPreview) {
// since the update itself is already called in an async thread and there are problem with accessing opreview in thumbbrowserbase,
// it's safer to do this synchronously
{
GThreadLock lock;
_updateImage(img,w,h);
}
}
void BatchQueueEntry::_updateImage (guint8* img, int w, int h) {
if (preh == h) {
#if PROTECT_VECTORS
MYWRITERLOCK(l, lockRW);
#endif
prew = w;
assert (preview == NULL);
preview = new guint8 [prew*preh*3];
memcpy (preview, img, prew*preh*3);
if (parent)
parent->redrawNeeded (this);
}
delete [] img;
}

77
rtgui/batchqueueentry.h Normal file
View File

@@ -0,0 +1,77 @@
/*
* 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 _BATCHQUEUEENTRY_
#define _BATCHQUEUEENTRY_
#include <gtkmm.h>
#include "../rtengine/rtengine.h"
#include "thumbbrowserentrybase.h"
#include "thumbnail.h"
#include "bqentryupdater.h"
class BatchQueueEntry;
struct BatchQueueEntryIdleHelper {
BatchQueueEntry* bqentry;
bool destroyed;
int pending;
};
class BatchQueueEntry : public ThumbBrowserEntryBase, public BQEntryUpdateListener {
guint8* opreview;
int origpw, origph;
BatchQueueEntryIdleHelper* bqih;
bool opreviewDone;
static bool iconsLoaded;
public:
static Glib::RefPtr<Gdk::Pixbuf> savedAsIcon;
rtengine::ProcessingJob* job;
rtengine::procparams::ProcParams params;
Glib::ustring savedParamsFile;
double progress;
Glib::ustring outFileName;
int sequence;
SaveFormat saveFormat;
bool forceFormatOpts;
BatchQueueEntry (rtengine::ProcessingJob* job, const rtengine::procparams::ProcParams& pparams, Glib::ustring fname, int prevw, int prevh, Thumbnail* thm=NULL);
~BatchQueueEntry ();
void refreshThumbnailImage ();
void calcThumbnailSize ();
void drawProgressBar (Glib::RefPtr<Gdk::Window> win, Glib::RefPtr<Gdk::GC> gc, const Gdk::Color& foregr, const Gdk::Color& backgr, int x, int w, int y, int h);
void removeButtonSet ();
virtual std::vector<Glib::RefPtr<Gdk::Pixbuf> > getIconsOnImageArea ();
virtual void getIconSize (int& w, int& h);
virtual Glib::ustring getToolTip (int x, int y);
// bqentryupdatelistener interface
void updateImage (guint8* img, int w, int h, int origw, int origh, guint8* newOPreview);
void _updateImage (guint8* img, int w, int h); // inside gtk thread
};
#endif

347
rtgui/batchqueuepanel.cc Normal file
View File

@@ -0,0 +1,347 @@
/*
* 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 "batchqueuepanel.h"
#include "options.h"
#include "preferences.h"
#include "multilangmgr.h"
#include "rtwindow.h"
#include "soundman.h"
#include "../rtengine/safegtk.h"
#include "rtimage.h"
struct BQProcessLoaded {
BatchQueue* bq;
};
int processLoadedBatchQueueUIThread (void* data) {
BatchQueue* bq = static_cast<BatchQueue*>(data);
bq->resizeLoadedQueue();
return 0;
}
static Glib::ustring makeFolderLabel(Glib::ustring path)
{
if (!safe_file_test (path, Glib::FILE_TEST_IS_DIR))
return "(" + M("GENERAL_NONE") + ")";
if (path.size() > 40) {
size_t last_ds = path.find_last_of (G_DIR_SEPARATOR);
if (last_ds != Glib::ustring::npos && last_ds > 10) {
path = "..." + path.substr(last_ds);
}
}
return path;
}
BatchQueuePanel::BatchQueuePanel (FileCatalog* aFileCatalog) {
batchQueue = Gtk::manage( new BatchQueue(aFileCatalog) );
// construct batch queue panel with the extra "start" and "stop" button
Gtk::VBox* batchQueueButtonBox = Gtk::manage (new Gtk::VBox);
start = Gtk::manage (new Gtk::ToggleButton (M("FILEBROWSER_STARTPROCESSING")));
stop = Gtk::manage (new Gtk::ToggleButton (M("FILEBROWSER_STOPPROCESSING")));
autoStart = Gtk::manage (new Gtk::CheckButton (M("BATCHQUEUE_AUTOSTART")));
start->set_tooltip_markup (M("FILEBROWSER_STARTPROCESSINGHINT"));
stop->set_tooltip_markup (M("FILEBROWSER_STOPPROCESSINGHINT"));
autoStart->set_tooltip_text (M("FILEBROWSER_TOOLTIP_STOPPROCESSING"));
start->set_active (false);
stop->set_active (true);
autoStart->set_active (options.procQueueEnabled);
start->set_image (*Gtk::manage (new RTImage ("gtk-media-play.png")));
startConnection = start->signal_toggled().connect (sigc::mem_fun(*this, &BatchQueuePanel::startBatchProc));
stop->set_image (*Gtk::manage (new RTImage ("gtk-media-stop.png")));
stopConnection = stop->signal_toggled().connect (sigc::mem_fun(*this, &BatchQueuePanel::stopBatchProc));
batchQueueButtonBox->pack_start (*start, Gtk::PACK_SHRINK, 4);
batchQueueButtonBox->pack_start (*stop, Gtk::PACK_SHRINK, 4);
batchQueueButtonBox->pack_start (*autoStart, Gtk::PACK_SHRINK, 4);
// Output directory selection
fdir = Gtk::manage (new Gtk::Frame (M("PREFERENCES_OUTDIR")));
Gtk::VBox* odvb = Gtk::manage (new Gtk::VBox ());
odvb->set_border_width (4);
Gtk::HBox* hb2 = Gtk::manage (new Gtk::HBox ());
useTemplate = Gtk::manage (new Gtk::RadioButton (M("PREFERENCES_OUTDIRTEMPLATE")+":"));
hb2->pack_start (*useTemplate, Gtk::PACK_SHRINK,4);
outdirTemplate = Gtk::manage (new Gtk::Entry ());
hb2->pack_start (*outdirTemplate);
odvb->pack_start (*hb2, Gtk::PACK_SHRINK, 4);
outdirTemplate->set_tooltip_markup (M("PREFERENCES_OUTDIRTEMPLATEHINT"));
useTemplate->set_tooltip_markup (M("PREFERENCES_OUTDIRTEMPLATEHINT"));
Gtk::HBox* hb3 = Gtk::manage (new Gtk::HBox ());
useFolder = Gtk::manage (new Gtk::RadioButton (M("PREFERENCES_OUTDIRFOLDER")+":"));
hb3->pack_start (*useFolder, Gtk::PACK_SHRINK,4);
#if defined(__APPLE__) || defined(__linux__)
// At the time of writing (2013-11-11) the gtkmm FileChooserButton with ACTION_SELECT_FOLDER
// is so buggy on these platforms (OS X and Linux) that we rather employ this ugly button hack.
// When/if GTKMM gets fixed we can go back to use the FileChooserButton, like we do on Windows.
outdirFolderButton = Gtk::manage (new Gtk::Button("(" + M("GENERAL_NONE") + ")"));
outdirFolderButton->set_alignment(0.0, 0.0);
hb3->pack_start (*outdirFolderButton);
outdirFolderButton->signal_pressed().connect( sigc::mem_fun(*this, &BatchQueuePanel::pathFolderButtonPressed) );
outdirFolderButton->set_tooltip_markup (M("PREFERENCES_OUTDIRFOLDERHINT"));
outdirFolderButton->set_label(makeFolderLabel(options.savePathFolder));
Gtk::Image* folderImg = Gtk::manage (new Gtk::Image (Gtk::Stock::DIRECTORY, Gtk::ICON_SIZE_MENU));
folderImg->show ();
outdirFolderButton->set_image (*folderImg);
outdirFolder = 0;
#else
outdirFolder = Gtk::manage (new MyFileChooserButton (M("PREFERENCES_OUTDIRFOLDER"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER));
hb3->pack_start (*outdirFolder);
outdirFolder->signal_current_folder_changed().connect (sigc::mem_fun(*this, &BatchQueuePanel::pathFolderChanged));
outdirFolder->set_tooltip_markup (M("PREFERENCES_OUTDIRFOLDERHINT"));
if (safe_file_test (options.savePathFolder, Glib::FILE_TEST_IS_DIR))
outdirFolder->set_current_folder (options.savePathFolder);
outdirFolderButton = 0;
#endif
odvb->pack_start (*hb3, Gtk::PACK_SHRINK, 4);
useFolder->set_tooltip_markup (M("PREFERENCES_OUTDIRFOLDERHINT"));
Gtk::RadioButton::Group g = useTemplate->get_group();
useFolder->set_group (g);
fdir->add (*odvb);
// Output file format selection
fformat = Gtk::manage (new Gtk::Frame (M("PREFERENCES_FILEFORMAT")));
saveFormatPanel = Gtk::manage (new SaveFormatPanel ());
fformat->add (*saveFormatPanel);
saveFormatPanel->init (options.saveFormatBatch);
outdirTemplate->set_text (options.savePathTemplate);
useTemplate->set_active (options.saveUsePathTemplate);
useFolder->set_active (!options.saveUsePathTemplate);
// setup signal handlers
outdirTemplate->signal_changed().connect (sigc::mem_fun(*this, &BatchQueuePanel::saveOptions));
useTemplate->signal_toggled().connect (sigc::mem_fun(*this, &BatchQueuePanel::saveOptions));
useFolder->signal_toggled().connect (sigc::mem_fun(*this, &BatchQueuePanel::saveOptions));
saveFormatPanel->setListener (this);
// setup button bar
topBox = Gtk::manage (new Gtk::HBox ());
pack_start (*topBox, Gtk::PACK_SHRINK);
topBox->pack_start (*batchQueueButtonBox, Gtk::PACK_SHRINK, 4);
topBox->pack_start (*fdir);
topBox->pack_start (*fformat, Gtk::PACK_SHRINK, 4);
// add middle browser area
pack_start (*batchQueue);
// lower box with thumbnail zoom
bottomBox = Gtk::manage (new Gtk::HBox ());
pack_start (*bottomBox, Gtk::PACK_SHRINK);
// thumbnail zoom
Gtk::HBox* zoomBox = Gtk::manage (new Gtk::HBox ());
zoomBox->pack_start (*Gtk::manage (new Gtk::VSeparator), Gtk::PACK_SHRINK, 4);
Gtk::Label* zoomLabel = Gtk::manage (new Gtk::Label (Glib::ustring("<b>")+M("FILEBROWSER_THUMBSIZE")+":</b>"));
zoomLabel->set_use_markup (true);
zoomBox->pack_start (*zoomLabel, Gtk::PACK_SHRINK, 4);
zoomInButton = Gtk::manage (new Gtk::Button ());
zoomInButton->set_image (*Gtk::manage (new RTImage ("gtk-zoom-in.png")));
zoomInButton->signal_pressed().connect (sigc::mem_fun(*batchQueue, &BatchQueue::zoomIn));
zoomInButton->set_relief (Gtk::RELIEF_NONE);
zoomInButton->set_tooltip_markup (M("FILEBROWSER_ZOOMINHINT"));
zoomBox->pack_end (*zoomInButton, Gtk::PACK_SHRINK);
zoomOutButton = Gtk::manage (new Gtk::Button ());
zoomOutButton->set_image (*Gtk::manage (new RTImage ("gtk-zoom-out.png")));
zoomOutButton->signal_pressed().connect (sigc::mem_fun(*batchQueue, &BatchQueue::zoomOut));
zoomOutButton->set_relief (Gtk::RELIEF_NONE);
zoomOutButton->set_tooltip_markup (M("FILEBROWSER_ZOOMOUTHINT"));
zoomBox->pack_end (*zoomOutButton, Gtk::PACK_SHRINK);
bottomBox->pack_end (*zoomBox, Gtk::PACK_SHRINK);
batchQueue->setBatchQueueListener (this);
show_all ();
if (batchQueue->loadBatchQueue ()) {
g_idle_add_full (G_PRIORITY_LOW, processLoadedBatchQueueUIThread, batchQueue, NULL);
}
}
// it is expected to have a non null forceOrientation value on Preferences update only. In this case, qsize is ingored and computed automatically
void BatchQueuePanel::updateTab (int qsize, int forceOrientation)
{
Gtk::Notebook *nb =(Gtk::Notebook *)(this->get_parent());
if (forceOrientation > 0)
qsize = batchQueue->getEntries().size();
if ((forceOrientation==0 && options.mainNBVertical) || (forceOrientation==2)) {
Gtk::VBox* vbb = Gtk::manage (new Gtk::VBox ());
Gtk::Label* l;
if(!qsize ){
vbb->pack_start (*Gtk::manage (new RTImage ("processing.png")));
l=Gtk::manage (new Gtk::Label (Glib::ustring(" ") + M("MAIN_FRAME_BATCHQUEUE")) );
} else if( start->get_active () ){
vbb->pack_start (*Gtk::manage (new RTImage ("processing-play.png")));
l=Gtk::manage (new Gtk::Label (Glib::ustring(" ") + M("MAIN_FRAME_BATCHQUEUE")+" [" +Glib::ustring::format( qsize )+"]"));
} else {
vbb->pack_start (*Gtk::manage (new RTImage ("processing-pause.png")));
l=Gtk::manage (new Gtk::Label (Glib::ustring(" ") + M("MAIN_FRAME_BATCHQUEUE")+" [" +Glib::ustring::format( qsize )+"]" ));
}
l->set_angle (90);
vbb->pack_start (*l);
vbb->set_spacing (2);
vbb->set_tooltip_markup (M("MAIN_FRAME_BATCHQUEUE_TOOLTIP"));
vbb->show_all ();
nb->set_tab_label(*this,*vbb);
} else {
Gtk::HBox* hbb = Gtk::manage (new Gtk::HBox ());
if (!qsize ) {
hbb->pack_start (*Gtk::manage (new RTImage ("processing.png")));
hbb->pack_start (*Gtk::manage (new Gtk::Label (M("MAIN_FRAME_BATCHQUEUE") )));
} else if ( start->get_active () ){
hbb->pack_start (*Gtk::manage (new RTImage ("processing-play.png")));
hbb->pack_start (*Gtk::manage (new Gtk::Label (M("MAIN_FRAME_BATCHQUEUE")+" [" +Glib::ustring::format( qsize )+"]" )));
} else {
hbb->pack_start (*Gtk::manage (new RTImage ("processing-pause.png")));
hbb->pack_start (*Gtk::manage (new Gtk::Label (M("MAIN_FRAME_BATCHQUEUE")+" [" +Glib::ustring::format( qsize )+"]" )));
}
hbb->set_spacing (2);
hbb->set_tooltip_markup (M("MAIN_FRAME_BATCHQUEUE_TOOLTIP"));
hbb->show_all ();
nb->set_tab_label(*this,*hbb);
}
}
void BatchQueuePanel::queueSizeChanged (int qsize, bool queueEmptied, bool queueError, Glib::ustring queueErrorMessage)
{
updateTab ( qsize);
if (queueEmptied || queueError) {
stopBatchProc ();
fdir->set_sensitive (true);
fformat->set_sensitive (true);
SoundManager::playSoundAsync(options.sndBatchQueueDone);
}
if (queueError) {
Gtk::MessageDialog msgd (queueErrorMessage, true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
msgd.run ();
}
}
void BatchQueuePanel::startBatchProc () {
stopConnection.block (true);
startConnection.block (true);
stop->set_active (false);
start->set_active (true);
stopConnection.block (false);
startConnection.block (false);
if (batchQueue->hasJobs()) {
fdir->set_sensitive (false);
fformat->set_sensitive (false);
saveOptions();
batchQueue->startProcessing ();
}
else
stopBatchProc ();
updateTab (batchQueue->getEntries().size());
}
void BatchQueuePanel::stopBatchProc () {
stopConnection.block (true);
startConnection.block (true);
stop->set_active (true);
start->set_active (false);
stopConnection.block (false);
startConnection.block (false);
updateTab (batchQueue->getEntries().size());
}
void BatchQueuePanel::addBatchQueueJobs ( std::vector<BatchQueueEntry*> &entries, bool head) {
batchQueue->addEntries (entries, head);
if (stop->get_active () && autoStart->get_active ())
startBatchProc ();
}
bool BatchQueuePanel::canStartNext () {
if (start->get_active ())
return true;
else {
fdir->set_sensitive (true);
fformat->set_sensitive (true);
return false;
}
}
void BatchQueuePanel::saveOptions () {
options.savePathTemplate = outdirTemplate->get_text();
options.saveUsePathTemplate = useTemplate->get_active();
options.procQueueEnabled = autoStart->get_active ();
}
void BatchQueuePanel::pathFolderButtonPressed () {
Gtk::FileChooserDialog fc(M("PREFERENCES_OUTDIRFOLDER"),Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER );
fc.add_button( Gtk::StockID("gtk-cancel"), Gtk::RESPONSE_CANCEL);
fc.add_button( Gtk::StockID("gtk-ok"), Gtk::RESPONSE_OK);
fc.set_filename(options.savePathFolder);
fc.set_transient_for(*parent);
int result = fc.run();
if (result == Gtk::RESPONSE_OK) {
if (safe_file_test(fc.get_current_folder(), Glib::FILE_TEST_IS_DIR)) {
options.savePathFolder = fc.get_current_folder();
outdirFolderButton->set_label(makeFolderLabel(options.savePathFolder));
}
}
}
// We only want to save the following when it changes,
// since these settings are shared with editorpanel :
void BatchQueuePanel::pathFolderChanged () {
options.savePathFolder = outdirFolder->get_current_folder();
}
void BatchQueuePanel::formatChanged (Glib::ustring f) {
options.saveFormatBatch = saveFormatPanel->getFormat ();
}
bool BatchQueuePanel::handleShortcutKey (GdkEventKey* event) {
bool ctrl = event->state & GDK_CONTROL_MASK;
if (ctrl){
switch(event->keyval) {
case GDK_s:
if (start->get_active()) {
stopBatchProc();
} else {
startBatchProc();
}
return true;
}
}
return batchQueue->keyPressed (event);
}

79
rtgui/batchqueuepanel.h Normal file
View File

@@ -0,0 +1,79 @@
/*
* 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 _BATCHQUEUEPANEL_
#define _BATCHQUEUEPANEL_
#include <gtkmm.h>
#include "batchqueue.h"
#include "saveformatpanel.h"
#include "guiutils.h"
class RTWindow;
class FileCatalog;
class Thumbnail;
class BatchQueuePanel : public Gtk::VBox,
public BatchQueueListener,
public FormatChangeListener {
Gtk::Button* zoomInButton;
Gtk::Button* zoomOutButton;
Gtk::ToggleButton* start;
Gtk::ToggleButton* stop;
Gtk::CheckButton* autoStart;
sigc::connection startConnection;
sigc::connection stopConnection;
Gtk::Entry* outdirTemplate;
MyFileChooserButton* outdirFolder;
Gtk::Button* outdirFolderButton;
Gtk::RadioButton* useTemplate;
Gtk::RadioButton* useFolder;
SaveFormatPanel* saveFormatPanel;
Gtk::Frame *fdir, *fformat;
RTWindow* parent;
BatchQueue* batchQueue;
Gtk::HBox* bottomBox;
Gtk::HBox* topBox;
public:
BatchQueuePanel (FileCatalog* aFileCatalog);
void setParent (RTWindow* p) { parent = p; }
void addBatchQueueJobs (std::vector<BatchQueueEntry*> &entries , bool head=false);
// batchqueuelistener interface
void queueSizeChanged (int qsize, bool queueEmptied, bool queueError, Glib::ustring queueErrorMessage);
bool canStartNext ();
void startBatchProc ();
void stopBatchProc ();
void saveOptions ();
void pathFolderChanged ();
void pathFolderButtonPressed ();
void formatChanged (Glib::ustring f);
void updateTab (int qsize, int forceOrientation=0); // forceOrientation=0: base on options / 1: horizontal / 2: vertical
bool handleShortcutKey (GdkEventKey* event);
};
#endif

View File

@@ -0,0 +1,634 @@
/*
* 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 "multilangmgr.h"
#include "batchtoolpanelcoord.h"
#include "options.h"
#include "filepanel.h"
#include "procparamchangers.h"
#include "addsetids.h"
using namespace rtengine::procparams;
BatchToolPanelCoordinator::BatchToolPanelCoordinator (FilePanel* parent) : ToolPanelCoordinator(), somethingChanged(false), parent(parent) {
blockedUpdate = false;
// remove exif panel and iptc panel
std::vector<ToolPanel*>::iterator epi = std::find (toolPanels.begin(), toolPanels.end(), exifpanel);
if (epi!=toolPanels.end())
toolPanels.erase (epi);
std::vector<ToolPanel*>::iterator ipi = std::find (toolPanels.begin(), toolPanels.end(), iptcpanel);
if (ipi!=toolPanels.end())
toolPanels.erase (ipi);
toolPanelNotebook->remove_page (*metadataPanel);
metadataPanel = 0;
toiM = 0;
for (size_t i=0; i<toolPanels.size(); i++)
toolPanels[i]->setBatchMode (true);
}
void BatchToolPanelCoordinator::selectionChanged (const std::vector<Thumbnail*>& selected) {
if (selected!=this->selected) {
closeSession ();
this->selected = selected;
selFileNames.clear ();
for (size_t i=0; i<selected.size(); i++)
selFileNames.push_back (selected[i]->getFileName ());
initSession ();
}
}
void BatchToolPanelCoordinator::closeSession (bool save) {
pparamsEdited.set (false);
for (size_t i=0; i<selected.size(); i++)
selected[i]->removeThumbnailListener (this);
if (somethingChanged && save) {
// read new values from the gui
for (size_t i=0; i<toolPanels.size(); i++)
toolPanels[i]->write (&pparams, &pparamsEdited);
// combine with initial parameters and set
ProcParams newParams;
for (size_t i=0; i<selected.size(); i++) {
newParams = initialPP[i];
pparamsEdited.combine (newParams, pparams, selected.size()==1);
// trim new adjuster's values to the adjuster's limits
for (unsigned int j=0; j<toolPanels.size(); j++)
toolPanels[j]->trimValues (&newParams);
selected[i]->setProcParams (newParams, NULL, BATCHEDITOR, true);
}
}
for (size_t i=0; i<paramcListeners.size(); i++)
paramcListeners[i]->clearParamChanges ();
}
void BatchToolPanelCoordinator::initSession () {
somethingChanged = false;
initialPP.resize (selected.size());
for (size_t i=0; i<selected.size(); i++) {
initialPP[i] = selected[i]->getProcParams ();
selected[i]->applyAutoExp (initialPP[i]);
selected[i]->addThumbnailListener (this);
}
// compare all the ProcParams and describe which parameters has different (i.e. inconsistent) values in pparamsEdited
pparamsEdited.initFrom (initialPP);
crop->setDimensions (100000, 100000);
/* if (!selected.empty()) {
pparams = selected[0]->getProcParams ();
for (int i=0; i<toolPanels.size(); i++) {
toolPanels[i]->setDefaults (&pparams, &pparamsEdited);
toolPanels[i]->read (&pparams, &pparamsEdited);
}
for (int i=0; i<paramcListeners.size(); i++)
paramcListeners[i]->procParamsChanged (&pparams, rtengine::EvPhotoLoaded, "batch processing", &pparamsEdited);
}
*/
if (!selected.empty()) {
// The first selected image (in the thumbnail list, not the click list) is used to populate the EditorPanel and set the default values
pparams = selected[0]->getProcParams ();
coarse->initBatchBehavior ();
if (selected.size()==1) {
for (size_t i=0; i<toolPanels.size(); i++)
toolPanels.at(i)->setMultiImage(false);
toneCurve->setAdjusterBehavior (false, false, false, false, false, false, false, false);
lcurve->setAdjusterBehavior (false, false, false);
whitebalance->setAdjusterBehavior (false, false, false);
vibrance->setAdjusterBehavior (false, false);
vignetting->setAdjusterBehavior (false, false, false, false);
colorappearance->setAdjusterBehavior (false, false, false, false, false, false, false, false, false, false, false, false, false);
rotate->setAdjusterBehavior (false);
distortion->setAdjusterBehavior (false);
perspective->setAdjusterBehavior (false);
gradient->setAdjusterBehavior (false, false, false, false);
pcvignette->setAdjusterBehavior (false, false, false);
cacorrection->setAdjusterBehavior (false);
sharpening->setAdjusterBehavior (false);
sharpenEdge->setAdjusterBehavior (false, false);
sharpenMicro->setAdjusterBehavior (false, false);
icm->setAdjusterBehavior (false, false);
chmixer->setAdjusterBehavior (false);
blackwhite->setAdjusterBehavior (false,false);
colortoning->setAdjusterBehavior (false, false, false, false, false);
filmSimulation->setAdjusterBehavior(false);
shadowshighlights->setAdjusterBehavior (false, false, false);
dirpyrequalizer->setAdjusterBehavior (false, false, false);
wavelet->setAdjusterBehavior (false, false, false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false, false, false);
dirpyrdenoise->setAdjusterBehavior (false, false,false,false,false,false, false);
bayerpreprocess->setAdjusterBehavior (false, false);
rawcacorrection->setAdjusterBehavior (false);
flatfield->setAdjusterBehavior(false);
rawexposure->setAdjusterBehavior (false, false);
bayerrawexposure->setAdjusterBehavior (false);
xtransrawexposure->setAdjusterBehavior (false);
}
else {
for (size_t i=0; i<toolPanels.size(); i++)
toolPanels.at(i)->setMultiImage(true);
toneCurve->setAdjusterBehavior (options.baBehav[ADDSET_TC_EXPCOMP], options.baBehav[ADDSET_TC_HLCOMPAMOUNT],options.baBehav[ADDSET_TC_HLCOMPTHRESH], options.baBehav[ADDSET_TC_BRIGHTNESS], options.baBehav[ADDSET_TC_BLACKLEVEL],options.baBehav[ADDSET_TC_SHCOMP], options.baBehav[ADDSET_TC_CONTRAST], options.baBehav[ADDSET_TC_SATURATION]);
lcurve->setAdjusterBehavior (options.baBehav[ADDSET_LC_BRIGHTNESS], options.baBehav[ADDSET_LC_CONTRAST], options.baBehav[ADDSET_LC_CHROMATICITY]);
whitebalance->setAdjusterBehavior (options.baBehav[ADDSET_WB_TEMPERATURE], options.baBehav[ADDSET_WB_GREEN], options.baBehav[ADDSET_WB_EQUAL]);
vibrance->setAdjusterBehavior (options.baBehav[ADDSET_VIBRANCE_PASTELS], options.baBehav[ADDSET_VIBRANCE_SATURATED]);
vignetting->setAdjusterBehavior (options.baBehav[ADDSET_VIGN_AMOUNT], options.baBehav[ADDSET_VIGN_RADIUS], options.baBehav[ADDSET_VIGN_STRENGTH], options.baBehav[ADDSET_VIGN_CENTER]);
colorappearance->setAdjusterBehavior (options.baBehav[ADDSET_CAT_DEGREE], options.baBehav[ADDSET_CAT_ADAPTSCENE], options.baBehav[ADDSET_CAT_ADAPTVIEWING],options.baBehav[ADDSET_CAT_BADPIX], options.baBehav[ADDSET_CAT_LIGHT], options.baBehav[ADDSET_CAT_CHROMA],options.baBehav[ADDSET_CAT_CONTRAST],options.baBehav[ADDSET_CAT_RSTPRO],options.baBehav[ADDSET_CAT_BRIGHT],options.baBehav[ADDSET_CAT_CONTRAST_Q],options.baBehav[ADDSET_CAT_CHROMA_S],options.baBehav[ADDSET_CAT_CHROMA_M],options.baBehav[ADDSET_CAT_HUE]);
rotate->setAdjusterBehavior (options.baBehav[ADDSET_ROTATE_DEGREE]);
distortion->setAdjusterBehavior (options.baBehav[ADDSET_DIST_AMOUNT]);
perspective->setAdjusterBehavior (options.baBehav[ADDSET_PERSPECTIVE]);
gradient->setAdjusterBehavior (options.baBehav[ADDSET_GRADIENT_DEGREE], options.baBehav[ADDSET_GRADIENT_FEATHER], options.baBehav[ADDSET_GRADIENT_STRENGTH], options.baBehav[ADDSET_GRADIENT_CENTER]);
pcvignette->setAdjusterBehavior (options.baBehav[ADDSET_PCVIGNETTE_STRENGTH], options.baBehav[ADDSET_PCVIGNETTE_FEATHER], options.baBehav[ADDSET_PCVIGNETTE_ROUNDNESS]);
cacorrection->setAdjusterBehavior (options.baBehav[ADDSET_CA]);
sharpening->setAdjusterBehavior (options.baBehav[ADDSET_SHARP_AMOUNT]);
sharpenEdge->setAdjusterBehavior (options.baBehav[ADDSET_SHARPENEDGE_AMOUNT],options.baBehav[ADDSET_SHARPENEDGE_PASS]);
sharpenMicro->setAdjusterBehavior (options.baBehav[ADDSET_SHARPENMICRO_AMOUNT],options.baBehav[ADDSET_SHARPENMICRO_UNIFORMITY]);
icm->setAdjusterBehavior (options.baBehav[ADDSET_FREE_OUPUT_GAMMA],options.baBehav[ADDSET_FREE_OUTPUT_SLOPE]);
// colortoning->setAdjusterBehavior (options.baBehav[ADDSET_COLORTONING_SPLIT], options.baBehav[ADDSET_COLORTONING_SATTHRESHOLD], options.baBehav[ADDSET_COLORTONING_SATOPACITY], options.baBehav[ADDSET_COLORTONING_STRPROTECT], options.baBehav[ADDSET_COLORTONING_BALANCE]);
colortoning->setAdjusterBehavior (options.baBehav[ADDSET_COLORTONING_SPLIT], options.baBehav[ADDSET_COLORTONING_SATTHRESHOLD], options.baBehav[ADDSET_COLORTONING_SATOPACITY], options.baBehav[ADDSET_COLORTONING_STRENGTH], options.baBehav[ADDSET_COLORTONING_BALANCE]);
filmSimulation->setAdjusterBehavior(options.baBehav[ADDSET_FILMSIMULATION_STRENGTH]);
chmixer->setAdjusterBehavior (options.baBehav[ADDSET_CHMIXER] );
blackwhite->setAdjusterBehavior (options.baBehav[ADDSET_BLACKWHITE_HUES],options.baBehav[ADDSET_BLACKWHITE_GAMMA]);
shadowshighlights->setAdjusterBehavior (options.baBehav[ADDSET_SH_HIGHLIGHTS], options.baBehav[ADDSET_SH_SHADOWS], options.baBehav[ADDSET_SH_LOCALCONTRAST]);
dirpyrequalizer->setAdjusterBehavior (options.baBehav[ADDSET_DIRPYREQ], options.baBehav[ADDSET_DIRPYREQ_THRESHOLD], options.baBehav[ADDSET_DIRPYREQ_SKINPROTECT]);
wavelet->setAdjusterBehavior (options.baBehav[ADDSET_WA], options.baBehav[ADDSET_WA_THRESHOLD], options.baBehav[ADDSET_WA_THRESHOLD2],options.baBehav[ADDSET_WA_THRES],options.baBehav[ADDSET_WA_CHRO],options.baBehav[ADDSET_WA_CHROMA],options.baBehav[ADDSET_WA_CONTRAST],options.baBehav[ADDSET_WA_SKINPROTECT],options.baBehav[ADDSET_WA_RESCHRO],options.baBehav[ADDSET_WA_TMRS],options.baBehav[ADDSET_WA_RESCON],options.baBehav[ADDSET_WA_RESCONH],options.baBehav[ADDSET_WA_THRR],options.baBehav[ADDSET_WA_THRRH],options.baBehav[ADDSET_WA_SKYPROTECT], options.baBehav[ADDSET_WA_EDGRAD],options.baBehav[ADDSET_WA_EDGVAL],options.baBehav[ADDSET_WA_STRENGTH],options.baBehav[ADDSET_WA_GAMMA],options.baBehav[ADDSET_WA_EDGEDETECT], options.baBehav[ADDSET_WA_EDGEDETECTTHR], options.baBehav[ADDSET_WA_EDGEDETECTTHR2]);
dirpyrdenoise->setAdjusterBehavior (options.baBehav[ADDSET_DIRPYRDN_LUMA],options.baBehav[ADDSET_DIRPYRDN_LUMDET],options.baBehav[ADDSET_DIRPYRDN_CHROMA],options.baBehav[ADDSET_DIRPYRDN_CHROMARED],options.baBehav[ADDSET_DIRPYRDN_CHROMABLUE], options.baBehav[ADDSET_DIRPYRDN_GAMMA], options.baBehav[ADDSET_DIRPYRDN_PASSES]);
bayerpreprocess->setAdjusterBehavior (options.baBehav[ADDSET_PREPROCESS_LINEDENOISE], options.baBehav[ADDSET_PREPROCESS_GREENEQUIL]);
rawcacorrection->setAdjusterBehavior (options.baBehav[ADDSET_RAWCACORR]);
flatfield->setAdjusterBehavior(options.baBehav[ADDSET_RAWFFCLIPCONTROL]);
rawexposure->setAdjusterBehavior (options.baBehav[ADDSET_RAWEXPOS_LINEAR], options.baBehav[ADDSET_RAWEXPOS_PRESER]);
bayerrawexposure->setAdjusterBehavior (options.baBehav[ADDSET_RAWEXPOS_BLACKS]);
xtransrawexposure->setAdjusterBehavior (options.baBehav[ADDSET_RAWEXPOS_BLACKS]);
if (options.baBehav[ADDSET_TC_EXPCOMP]) pparams.toneCurve.expcomp = 0;
if (options.baBehav[ADDSET_TC_HLCOMPAMOUNT]) pparams.toneCurve.hlcompr = 0;
if (options.baBehav[ADDSET_TC_HLCOMPTHRESH]) pparams.toneCurve.hlcomprthresh = 0;
if (options.baBehav[ADDSET_TC_BRIGHTNESS]) pparams.toneCurve.brightness = 0;
if (options.baBehav[ADDSET_TC_BLACKLEVEL]) pparams.toneCurve.black = 0;
if (options.baBehav[ADDSET_TC_SHCOMP]) pparams.toneCurve.shcompr = 0;
if (options.baBehav[ADDSET_TC_CONTRAST]) pparams.toneCurve.contrast = 0;
if (options.baBehav[ADDSET_SH_HIGHLIGHTS]) pparams.sh.highlights = 0;
if (options.baBehav[ADDSET_SH_SHADOWS]) pparams.sh.shadows = 0;
if (options.baBehav[ADDSET_SH_LOCALCONTRAST]) pparams.sh.localcontrast = 0;
if (options.baBehav[ADDSET_LC_BRIGHTNESS]) pparams.labCurve.brightness = 0;
if (options.baBehav[ADDSET_LC_CONTRAST]) pparams.labCurve.contrast = 0;
if (options.baBehav[ADDSET_LC_CHROMATICITY]) pparams.labCurve.chromaticity = 0;
if (options.baBehav[ADDSET_SHARP_AMOUNT]) pparams.sharpening.amount = 0;
if (options.baBehav[ADDSET_SHARPENEDGE_AMOUNT]) pparams.sharpenEdge.amount = 0;
if (options.baBehav[ADDSET_SHARPENMICRO_AMOUNT]) pparams.sharpenMicro.amount = 0;
if (options.baBehav[ADDSET_SHARPENEDGE_PASS]) pparams.sharpenEdge.passes = 0;
if (options.baBehav[ADDSET_SHARPENMICRO_UNIFORMITY]) pparams.sharpenMicro.uniformity = 0;
if (options.baBehav[ADDSET_CHMIXER]) for (int i=0; i<3; i++) pparams.chmixer.red[i] = pparams.chmixer.green[i] = pparams.chmixer.blue[i] = 0;
if (options.baBehav[ADDSET_BLACKWHITE_HUES]) pparams.blackwhite.mixerRed=pparams.blackwhite.mixerOrange=pparams.blackwhite.mixerYellow=
pparams.blackwhite.mixerGreen=pparams.blackwhite.mixerCyan=pparams.blackwhite.mixerBlue=
pparams.blackwhite.mixerMagenta=pparams.blackwhite.mixerPurple=0;
if (options.baBehav[ADDSET_BLACKWHITE_GAMMA]) pparams.blackwhite.gammaRed=pparams.blackwhite.gammaGreen=pparams.blackwhite.gammaBlue = 0;
//if (options.baBehav[ADDSET_LD_EDGETOLERANCE]) pparams.lumaDenoise.edgetolerance = 0;
if (options.baBehav[ADDSET_WB_TEMPERATURE]) pparams.wb.temperature = 0;
if (options.baBehav[ADDSET_WB_GREEN]) pparams.wb.green = 0;
if (options.baBehav[ADDSET_WB_EQUAL]) pparams.wb.equal = 0;
if (options.baBehav[ADDSET_VIBRANCE_PASTELS]) pparams.vibrance.pastels = 0;
if (options.baBehav[ADDSET_VIBRANCE_SATURATED]) pparams.vibrance.saturated = 0;
if (options.baBehav[ADDSET_CAT_DEGREE]) pparams.colorappearance.degree = 0;
if (options.baBehav[ADDSET_CAT_ADAPTSCENE]) pparams.colorappearance.adapscen = 0;
if (options.baBehav[ADDSET_CAT_ADAPTVIEWING]) pparams.colorappearance.adaplum = 0;
if (options.baBehav[ADDSET_CAT_BADPIX]) pparams.colorappearance.badpixsl = 0;
if (options.baBehav[ADDSET_CAT_LIGHT]) pparams.colorappearance.jlight = 0;
if (options.baBehav[ADDSET_CAT_BRIGHT]) pparams.colorappearance.qbright = 0;
if (options.baBehav[ADDSET_CAT_CHROMA]) pparams.colorappearance.chroma = 0;
if (options.baBehav[ADDSET_CAT_CHROMA_S]) pparams.colorappearance.schroma = 0;
if (options.baBehav[ADDSET_CAT_CHROMA_M]) pparams.colorappearance.mchroma = 0;
if (options.baBehav[ADDSET_CAT_RSTPRO]) pparams.colorappearance.rstprotection = 0;
if (options.baBehav[ADDSET_CAT_CONTRAST]) pparams.colorappearance.contrast = 0;
if (options.baBehav[ADDSET_CAT_CONTRAST_Q]) pparams.colorappearance.qcontrast = 0;
if (options.baBehav[ADDSET_CAT_HUE]) pparams.colorappearance.colorh = 0;
if (options.baBehav[ADDSET_FREE_OUPUT_GAMMA]) pparams.icm.gampos = 0;
if (options.baBehav[ADDSET_FREE_OUTPUT_SLOPE]) pparams.icm.slpos = 0;
//if (options.baBehav[ADDSET_CBOOST_AMOUNT]) pparams.colorBoost.amount = 0;
//if (options.baBehav[ADDSET_CS_BLUEYELLOW]) pparams.colorShift.a = 0;
//if (options.baBehav[ADDSET_CS_GREENMAGENTA]) pparams.colorShift.b = 0;
if (options.baBehav[ADDSET_COLORTONING_SPLIT]) pparams.colorToning.redlow = pparams.colorToning.greenlow = pparams.colorToning.bluelow =
pparams.colorToning.redmed = pparams.colorToning.greenmed = pparams.colorToning.bluemed =
pparams.colorToning.redhigh = pparams.colorToning.greenhigh = pparams.colorToning.bluehigh =
pparams.colorToning.satlow = pparams.colorToning.sathigh = 0;
if (options.baBehav[ADDSET_COLORTONING_SATTHRESHOLD]) pparams.colorToning.satProtectionThreshold = 0;
if (options.baBehav[ADDSET_COLORTONING_SATOPACITY]) pparams.colorToning.saturatedOpacity = 0;
if (options.baBehav[ADDSET_COLORTONING_BALANCE]) pparams.colorToning.balance = 0;
if (options.baBehav[ADDSET_COLORTONING_STRENGTH]) pparams.colorToning.strength = 0;
if (options.baBehav[ADDSET_FILMSIMULATION_STRENGTH]) pparams.filmSimulation.strength = 0;
if (options.baBehav[ADDSET_ROTATE_DEGREE]) pparams.rotate.degree = 0;
if (options.baBehav[ADDSET_DIST_AMOUNT]) pparams.distortion.amount = 0;
if (options.baBehav[ADDSET_PERSPECTIVE]) pparams.perspective.horizontal = pparams.perspective.vertical = 0;
if (options.baBehav[ADDSET_GRADIENT_DEGREE]) pparams.gradient.degree = 0;
if (options.baBehav[ADDSET_GRADIENT_FEATHER]) pparams.gradient.feather = 0;
if (options.baBehav[ADDSET_GRADIENT_STRENGTH]) pparams.gradient.strength = 0;
if (options.baBehav[ADDSET_GRADIENT_CENTER]) pparams.gradient.centerX = 0;
if (options.baBehav[ADDSET_GRADIENT_CENTER]) pparams.gradient.centerY = 0;
if (options.baBehav[ADDSET_PCVIGNETTE_STRENGTH]) pparams.pcvignette.strength = 0;
if (options.baBehav[ADDSET_PCVIGNETTE_FEATHER]) pparams.pcvignette.feather = 0;
if (options.baBehav[ADDSET_PCVIGNETTE_ROUNDNESS]) pparams.pcvignette.roundness = 0;
if (options.baBehav[ADDSET_CA]) pparams.cacorrection.red = 0;
if (options.baBehav[ADDSET_CA]) pparams.cacorrection.blue = 0;
if (options.baBehav[ADDSET_VIGN_AMOUNT]) pparams.vignetting.amount = 0;
if (options.baBehav[ADDSET_VIGN_RADIUS]) pparams.vignetting.radius = 0;
if (options.baBehav[ADDSET_VIGN_STRENGTH]) pparams.vignetting.strength = 0;
if (options.baBehav[ADDSET_VIGN_CENTER]) pparams.vignetting.centerX = 0;
if (options.baBehav[ADDSET_VIGN_CENTER]) pparams.vignetting.centerY = 0;
if (options.baBehav[ADDSET_DIRPYREQ]) for (int i=0; i<6; i++) pparams.dirpyrequalizer.mult[i] = 0;
if (options.baBehav[ADDSET_DIRPYREQ_THRESHOLD]) pparams.dirpyrequalizer.threshold = 0;
if (options.baBehav[ADDSET_DIRPYREQ_SKINPROTECT]) pparams.dirpyrequalizer.skinprotect = 0;
if (options.baBehav[ADDSET_WA]) for (int i=0; i<8; i++) pparams.wavelet.c[i] = 0;
if (options.baBehav[ADDSET_WA_THRESHOLD]) pparams.wavelet.threshold = 0;
if (options.baBehav[ADDSET_WA_THRESHOLD2]) pparams.wavelet.threshold2 = 0;
if (options.baBehav[ADDSET_WA_SKINPROTECT]) pparams.wavelet.skinprotect = 0;
if (options.baBehav[ADDSET_WA_CHRO]) pparams.wavelet.chro = 0;
if (options.baBehav[ADDSET_WA_CHROMA]) pparams.wavelet.chroma = 0;
if (options.baBehav[ADDSET_WA_CONTRAST]) pparams.wavelet.contrast = 0;
if (options.baBehav[ADDSET_WA_THRES]) pparams.wavelet.thres = 0;
if (options.baBehav[ADDSET_WA_RESCON]) pparams.wavelet.rescon = 0;
if (options.baBehav[ADDSET_WA_RESCONH]) pparams.wavelet.resconH = 0;
if (options.baBehav[ADDSET_WA_RESCHRO]) pparams.wavelet.reschro = 0;
if (options.baBehav[ADDSET_WA_TMRS]) pparams.wavelet.tmrs = 0;
if (options.baBehav[ADDSET_WA_THRR]) pparams.wavelet.thr = 0;
if (options.baBehav[ADDSET_WA_THRRH]) pparams.wavelet.thrH = 0;
if (options.baBehav[ADDSET_WA_SKYPROTECT]) pparams.wavelet.sky = 0;
if (options.baBehav[ADDSET_WA_EDGRAD]) pparams.wavelet.edgrad = 0;
if (options.baBehav[ADDSET_WA_EDGVAL]) pparams.wavelet.edgval = 0;
if (options.baBehav[ADDSET_WA_STRENGTH]) pparams.wavelet.strength = 0;
if (options.baBehav[ADDSET_WA_EDGEDETECT]) pparams.wavelet.edgedetect = 0;
if (options.baBehav[ADDSET_WA_GAMMA]) pparams.wavelet.gamma = 0;
if (options.baBehav[ADDSET_DIRPYRDN_LUMA]) pparams.dirpyrDenoise.luma = 0;
if (options.baBehav[ADDSET_DIRPYRDN_CHROMA]) pparams.dirpyrDenoise.chroma = 0;
if (options.baBehav[ADDSET_DIRPYRDN_CHROMARED]) pparams.dirpyrDenoise.redchro = 0;
if (options.baBehav[ADDSET_DIRPYRDN_CHROMABLUE]) pparams.dirpyrDenoise.bluechro = 0;
// pparams.dirpyrDenoise.Ldetail = pparams.dirpyrDenoise.luma = pparams.dirpyrDenoise.chroma = 0;
if (options.baBehav[ADDSET_DIRPYRDN_GAMMA]) pparams.dirpyrDenoise.gamma = 0;
if (options.baBehav[ADDSET_RAWCACORR]) pparams.raw.cablue = pparams.raw.cared = 0;
if (options.baBehav[ADDSET_RAWEXPOS_LINEAR]) pparams.raw.expos = 0;
if (options.baBehav[ADDSET_RAWEXPOS_PRESER]) pparams.raw.preser = 0;
if (options.baBehav[ADDSET_RAWEXPOS_BLACKS]) {
pparams.raw.bayersensor.black0 = pparams.raw.bayersensor.black1 = pparams.raw.bayersensor.black2 = pparams.raw.bayersensor.black3 = 0;
pparams.raw.xtranssensor.blackred = pparams.raw.xtranssensor.blackgreen = pparams.raw.xtranssensor.blackblue = 0;
}
if (options.baBehav[ADDSET_RAWFFCLIPCONTROL]) pparams.raw.ff_clipControl = 0;
if (options.baBehav[ADDSET_PREPROCESS_GREENEQUIL]) pparams.raw.bayersensor.greenthresh = 0;
if (options.baBehav[ADDSET_PREPROCESS_LINEDENOISE]) pparams.raw.bayersensor.linenoise = 0;
}
for (size_t i=0; i<toolPanels.size(); i++) {
toolPanels[i]->setDefaults (&pparams, &pparamsEdited);
toolPanels[i]->read (&pparams, &pparamsEdited);
// TODO: autoOpenCurve has been disabled because initSession is called on each parameter change from the editor panel,
// if the thumbnail remains selected in the DirectoryBrowser (i.e. always, unless the user think about deselecting it)
//toolPanels[i]->autoOpenCurve();
}
for (size_t i=0; i<paramcListeners.size(); i++)
// send this initial state to the History
paramcListeners[i]->procParamsChanged (&pparams, rtengine::EvPhotoLoaded, M("BATCH_PROCESSING"), &pparamsEdited);
}
}
void BatchToolPanelCoordinator::panelChanged (rtengine::ProcEvent event, const Glib::ustring& descr) {
if (selected.empty())
return;
somethingChanged = true;
pparamsEdited.set (false);
// read new values from the gui
for (size_t i=0; i<toolPanels.size(); i++)
toolPanels[i]->write (&pparams, &pparamsEdited);
// If only a single item is selected, we emulate the behaviour of the editor tool panel coordinator,
// otherwise we adjust the inital parameters on a per-image basis.
if (selected.size()==1) {
// Compensate rotation on flip
if (event==rtengine::EvCTHFlip || event==rtengine::EvCTVFlip) {
if (fabs(pparams.rotate.degree)>0.001) {
pparams.rotate.degree *= -1;
rotate->read (&pparams);
}
}
int w, h;
selected[0]->getFinalSize (selected[0]->getProcParams (), w, h);
crop->setDimensions(w, h);
// Some transformations change the crop and resize parameter for convenience.
if (event==rtengine::EvCTHFlip) {
crop->hFlipCrop ();
crop->write (&pparams, &pparamsEdited);
}
else if (event==rtengine::EvCTVFlip) {
crop->vFlipCrop ();
crop->write (&pparams, &pparamsEdited);
}
else if (event==rtengine::EvCTRotate) {
crop->rotateCrop (pparams.coarse.rotate, pparams.coarse.hflip, pparams.coarse.vflip);
crop->write (&pparams, &pparamsEdited);
resize->update (pparams.crop.enabled, pparams.crop.w, pparams.crop.h, w, h);
resize->write (&pparams, &pparamsEdited);
}
else if (event==rtengine::EvCrop) {
resize->update (pparams.crop.enabled, pparams.crop.w, pparams.crop.h);
resize->write (&pparams, &pparamsEdited);
}
}
else {
// Compensate rotation on flip
if (event==rtengine::EvCTHFlip || event==rtengine::EvCTVFlip) {
for (size_t i=0; i<selected.size(); i++) {
if (fabs(initialPP[i].rotate.degree) > 0.001) {
initialPP[i].rotate.degree *= -1.0;
pparamsEdited.rotate.degree = false;
}
}
}
// some transformations make the crop change for convenience
if (event==rtengine::EvCTHFlip) {
for (size_t i=0; i<selected.size(); i++) {
int w, h;
selected[i]->getFinalSize (selected[i]->getProcParams (), w, h);
rtengine::procparams::CropParams& crop = initialPP[i].crop;
crop.x = w - crop.x - crop.w;
pparamsEdited.crop.x = false;
}
}
else if (event==rtengine::EvCTVFlip) {
for (size_t i=0; i<selected.size(); i++) {
int w, h;
selected[i]->getFinalSize (selected[i]->getProcParams (), w, h);
rtengine::procparams::CropParams& crop = initialPP[i].crop;
crop.y = h - crop.y - crop.h;
pparamsEdited.crop.y = false;
}
}
else if (event==rtengine::EvCTRotate) {
int newDeg = pparams.coarse.rotate;
for (size_t i=0; i<selected.size(); i++) {
int w, h;
selected[i]->getFinalSize (selected[i]->getProcParams (), w, h);
int oldDeg = initialPP[i].coarse.rotate;
rtengine::procparams::CropParams& crop = initialPP[i].crop;
int rotation = (360 + newDeg - oldDeg) % 360;
ProcParams pptemp = selected[i]->getProcParams(); // Get actual procparams
if((pptemp.coarse.hflip != pptemp.coarse.vflip) && ((rotation%180)==90))
rotation = (rotation + 180)%360;
switch (rotation) {
case 90:
std::swap(crop.x, crop.y);
std::swap(crop.w, crop.h);
crop.x = h - crop.x - crop.w;
break;
case 270:
std::swap(crop.x, crop.y);
std::swap(crop.w, crop.h);
crop.y = w - crop.y - crop.h;
break;
case 180:
crop.x = w - crop.x - crop.w;
crop.y = h - crop.y - crop.h;
break;
}
initialPP[i].coarse.rotate = newDeg;
}
pparamsEdited.crop.x = false;
pparamsEdited.crop.y = false;
pparamsEdited.crop.w = false;
pparamsEdited.crop.h = false;
pparamsEdited.coarse.rotate = false;
}
}
if (event==rtengine::EvAutoExp || event==rtengine::EvClip)
for (size_t i=0; i<selected.size(); i++) {
initialPP[i].toneCurve.autoexp = pparams.toneCurve.autoexp;
initialPP[i].toneCurve.clip = pparams.toneCurve.clip;
// at this stage, we don't know if HL Reconstruction will be enabled or not (depending on the raw histogram),
// so we're forcing its paramseditd value to false (i.e. mixed state)
pparamsEdited.toneCurve.hrenabled = false;
selected[i]->applyAutoExp (initialPP[i]);
}
if (event==rtengine::EvAutoDIST) {
for (size_t i=0; i<selected.size(); i++) {
initialPP[i].distortion.amount = pparams.distortion.amount;
}
}
// combine with initial parameters and set
ProcParams newParams;
for (size_t i=0; i<selected.size(); i++) {
newParams = initialPP[i];
// If only one file is selected, slider's addMode has been set to false, and hence the behave
// like in SET mode like in an editor ; that's why we force the combination to the SET mode too
pparamsEdited.combine (newParams, pparams, selected.size()==1);
// trim new adjuster's values to the adjuster's limits
for (unsigned int j=0; j<toolPanels.size(); j++)
toolPanels[j]->trimValues (&newParams);
selected[i]->setProcParams (newParams, NULL, BATCHEDITOR, false);
}
for (size_t i=0; i<paramcListeners.size(); i++)
paramcListeners[i]->procParamsChanged (&pparams, event, descr, &pparamsEdited);
}
void BatchToolPanelCoordinator::getAutoWB (double& temp, double& green, double equal) {
if (!selected.empty())
selected[0]->getAutoWB (temp, green, equal);
}
void BatchToolPanelCoordinator::getCamWB (double& temp, double& green) {
if (!selected.empty())
selected[0]->getCamWB (temp, green);
}
void BatchToolPanelCoordinator::optionsChanged () {
closeSession ();
initSession ();
}
void BatchToolPanelCoordinator::procParamsChanged (Thumbnail* thm, int whoChangedIt) {
if (whoChangedIt!=BATCHEDITOR && !blockedUpdate) {
closeSession (false);
initSession ();
}
}
void BatchToolPanelCoordinator::beginBatchPParamsChange(int numberOfEntries) {
blockedUpdate = true;
if (numberOfEntries > 50) // Arbitrary amount
parent->set_sensitive(false);
}
// The end of a batch pparams change triggers a close/initsession
void BatchToolPanelCoordinator::endBatchPParamsChange() {
//printf("BatchToolPanelCoordinator::endBatchPParamsChange / Nouvelle session!\n");
closeSession (false);
initSession ();
blockedUpdate = false;
parent->set_sensitive(true);
}
/*
* WARNING: profileChange is actually called by the History only.
* Using a Profile panel in the batch tool panel editor is actually
* not supported by BatchToolPanelCoordinator::profileChange!
*/
void BatchToolPanelCoordinator::profileChange (const rtengine::procparams::PartialProfile* nparams, rtengine::ProcEvent event, const Glib::ustring& descr, const ParamsEdited* paramsEdited) {
if (event==rtengine::EvProfileChanged) {
// a profile has been selected in a hypothetical Profile panel
// -> ACTUALLY NOT SUPPORTED
return;
}
pparams = *(nparams->pparams);
if (paramsEdited)
pparamsEdited = *paramsEdited;
for (size_t i=0; i<toolPanels.size(); i++)
// writing the values to the GUI
toolPanels[i]->read (&pparams, &pparamsEdited);
// I guess we don't want to automatically unfold curve editors here...
somethingChanged = true;
// read new values from the gui
for (size_t i=0; i<toolPanels.size(); i++)
toolPanels[i]->write (&pparams, &pparamsEdited);
// combine with initial parameters of each image and set
ProcParams newParams;
for (size_t i=0; i<selected.size(); i++) {
newParams = initialPP[i];
pparamsEdited.combine (newParams, pparams, selected.size()==1);
selected[i]->setProcParams (newParams, NULL, BATCHEDITOR, false);
}
for (size_t i=0; i<paramcListeners.size(); i++)
paramcListeners[i]->procParamsChanged (&pparams, event, descr, &pparamsEdited);
}
void BatchToolPanelCoordinator::cropSelectionReady () {
toolBar->setTool (TMHand);
}
CropGUIListener* BatchToolPanelCoordinator::startCropEditing (Thumbnail* thm) {
if (thm) {
int w, h;
thm->getFinalSize (thm->getProcParams (), w, h);
crop->setDimensions (w, h);
}
return crop;
}
void BatchToolPanelCoordinator::rotateSelectionReady (double rotate_deg, Thumbnail* thm) {
toolBar->setTool (TMHand);
if (rotate_deg!=0.0)
rotate->straighten (rotate_deg);
}
void BatchToolPanelCoordinator::spotWBselected (int x, int y, Thumbnail* thm) {
// toolBar->setTool (TOOL_HAND);
if (x>0 && y>0 && thm) {
for (size_t i=0; i<selected.size(); i++)
if (selected[i]==thm) {
double temp;
double green;
thm->getSpotWB (x, y, whitebalance->getSize(), temp, green);
double otemp = initialPP[i].wb.temperature;
double ogreen = initialPP[i].wb.green;
if (options.baBehav[12])
temp = temp - otemp;
if (options.baBehav[13])
green = green - ogreen;
whitebalance->setWB (temp, green);
}
}
}

View File

@@ -0,0 +1,82 @@
/*
* 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 __BATCHTOOLPANELCCORD__
#define __BATCHTOOLPANELCCORD__
#include "thumbnail.h"
#include "toolpanelcoord.h"
#include "fileselectionchangelistener.h"
#include "../rtengine/rtengine.h"
#include "paramsedited.h"
#include "thumbnaillistener.h"
class FilePanel;
class BatchToolPanelCoordinator :
public ToolPanelCoordinator,
public FileSelectionChangeListener,
public BatchPParamsChangeListener,
public ThumbnailListener
{
protected:
rtengine::procparams::ProcParams pparams;
ParamsEdited pparamsEdited;
std::vector<Thumbnail*> selected;
std::vector<Glib::ustring> selFileNames;
std::vector<rtengine::procparams::ProcParams> initialPP;
bool somethingChanged;
bool blockedUpdate;
FilePanel* parent;
void closeSession (bool save=true);
void initSession ();
public:
BatchToolPanelCoordinator (FilePanel* parent);
// FileSelectionChangeListener interface
void selectionChanged (const std::vector<Thumbnail*>& selected);
// toolpanellistener interface
void panelChanged (rtengine::ProcEvent event, const Glib::ustring& descr);
// profilechangelistener interface
void profileChange (const rtengine::procparams::PartialProfile* nparams, rtengine::ProcEvent event, const Glib::ustring& descr, const ParamsEdited* paramsEdited=NULL);
// wbprovider interface
void getAutoWB (double& temp, double& green, double equal);
void getCamWB (double& temp, double& green);
// thumbnaillistener interface
void procParamsChanged (Thumbnail* thm, int whoChangedIt);
// batchpparamschangelistener interface
void beginBatchPParamsChange(int numberOfEntries);
void endBatchPParamsChange();
// imageareatoollistener interface
void spotWBselected (int x, int y, Thumbnail* thm=NULL);
void cropSelectionReady ();
void rotateSelectionReady (double rotate_deg, Thumbnail* thm=NULL);
CropGUIListener* startCropEditing (Thumbnail* thm=NULL);
void optionsChanged ();
};
#endif

117
rtgui/bayerpreprocess.cc Normal file
View File

@@ -0,0 +1,117 @@
/*
* 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 "bayerpreprocess.h"
#include "guiutils.h"
#include "../rtengine/safegtk.h"
#include <sstream>
using namespace rtengine;
using namespace rtengine::procparams;
BayerPreProcess::BayerPreProcess () : FoldableToolPanel(this, "bayerpreprocess", M("TP_PREPROCESS_LABEL"), true)
{
lineDenoise = Gtk::manage(new Adjuster (M("TP_PREPROCESS_LINEDENOISE"),0,1000,1,0));
lineDenoise->setAdjusterListener (this);
if (lineDenoise->delay < 1000) lineDenoise->delay = 1000;
lineDenoise->show();
greenEqThreshold = Gtk::manage(new Adjuster (M("TP_PREPROCESS_GREENEQUIL"),0,100,1,0));
greenEqThreshold->setAdjusterListener (this);
if (greenEqThreshold->delay < 1000) greenEqThreshold->delay = 1000;
greenEqThreshold->show();
pack_start( *lineDenoise, Gtk::PACK_SHRINK, 4);
pack_start( *Gtk::manage (new Gtk::HSeparator()));
pack_start( *greenEqThreshold, Gtk::PACK_SHRINK, 4);
}
void BayerPreProcess::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited)
{
disableListener ();
if(pedited ){
lineDenoise->setEditedState( pedited->raw.bayersensor.linenoise ? Edited : UnEdited );
greenEqThreshold->setEditedState( pedited->raw.bayersensor.greenEq ? Edited : UnEdited );
}
lineDenoise->setValue (pp->raw.bayersensor.linenoise);
greenEqThreshold->setValue (pp->raw.bayersensor.greenthresh);
enableListener ();
}
void BayerPreProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pedited)
{
pp->raw.bayersensor.linenoise = lineDenoise->getIntValue();
pp->raw.bayersensor.greenthresh = greenEqThreshold->getIntValue();
if (pedited) {
pedited->raw.bayersensor.linenoise = lineDenoise->getEditedState ();
pedited->raw.bayersensor.greenEq= greenEqThreshold->getEditedState ();
}
}
void BayerPreProcess::adjusterChanged (Adjuster* a, double newval)
{
if (listener) {
Glib::ustring value = a->getTextValue();
if (a == greenEqThreshold)
listener->panelChanged (EvPreProcessGEquilThresh, value );
else if (a == lineDenoise)
listener->panelChanged (EvPreProcessLineDenoise, value );
}
}
void BayerPreProcess::setBatchMode(bool batchMode)
{
ToolPanel::setBatchMode (batchMode);
lineDenoise->showEditedCB ();
greenEqThreshold->showEditedCB ();
}
void BayerPreProcess::setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited)
{
lineDenoise->setDefault( defParams->raw.bayersensor.linenoise);
greenEqThreshold->setDefault (defParams->raw.bayersensor.greenthresh);
if (pedited) {
lineDenoise->setDefaultEditedState( pedited->raw.bayersensor.linenoise ? Edited : UnEdited);
greenEqThreshold->setDefaultEditedState(pedited->raw.bayersensor.greenEq ? Edited : UnEdited);
} else {
lineDenoise->setDefaultEditedState( Irrelevant );
greenEqThreshold->setDefaultEditedState(Irrelevant );
}
}
void BayerPreProcess::setAdjusterBehavior (bool linedenoiseadd, bool greenequiladd) {
lineDenoise->setAddMode(linedenoiseadd);
greenEqThreshold->setAddMode(greenequiladd);
}
void BayerPreProcess::trimValues (rtengine::procparams::ProcParams* pp) {
lineDenoise->trimValue(pp->raw.bayersensor.linenoise);
greenEqThreshold->trimValue(pp->raw.bayersensor.greenthresh);
}

49
rtgui/bayerpreprocess.h Normal file
View File

@@ -0,0 +1,49 @@
/*
* 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 _BAYERPREPROCESS_H_
#define _BAYERPREPROCESS_H_
#include <gtkmm.h>
#include "adjuster.h"
#include "toolpanel.h"
#include "../rtengine/rawimage.h"
class BayerPreProcess : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel {
protected:
Adjuster* lineDenoise;
Adjuster* greenEqThreshold;
public:
BayerPreProcess ();
void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL);
void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL);
void setBatchMode (bool batchMode);
void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL);
void adjusterChanged (Adjuster* a, double newval);
void hotDeadPixelChanged();
void setAdjusterBehavior (bool linedenoiseadd, bool greenequiladd);
void trimValues (rtengine::procparams::ProcParams* pp);
};
#endif

270
rtgui/bayerprocess.cc Normal file
View File

@@ -0,0 +1,270 @@
/*
* 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 "bayerprocess.h"
#include "options.h"
#include "guiutils.h"
using namespace rtengine;
using namespace rtengine::procparams;
BayerProcess::BayerProcess () : FoldableToolPanel(this, "bayerprocess", M("TP_RAW_LABEL"), true)
{
Gtk::HBox* hb1 = Gtk::manage (new Gtk::HBox ());
hb1->pack_start (*Gtk::manage (new Gtk::Label ( M("TP_RAW_DMETHOD") +": ")),Gtk::PACK_SHRINK, 4);
method = Gtk::manage (new MyComboBoxText ());
for( size_t i=0; i<procparams::RAWParams::BayerSensor::numMethods;i++)
method->append_text(procparams::RAWParams::BayerSensor::methodstring[i]);
method->set_active(0);
hb1->set_tooltip_markup (M("TP_RAW_DMETHOD_TOOLTIP"));
hb1->pack_end (*method, Gtk::PACK_EXPAND_WIDGET, 4);
pack_start( *hb1, Gtk::PACK_SHRINK, 4);
dcbOptions = Gtk::manage (new Gtk::VBox ());
dcbOptions->set_border_width(4);
dcbIterations = Gtk::manage (new Adjuster (M("TP_RAW_DCBITERATIONS"),0,5,1,2));
dcbIterations->setAdjusterListener (this);
if (dcbIterations->delay < 1000) dcbIterations->delay = 1000;
dcbIterations->show();
dcbEnhance = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_DCBENHANCE")));
dcbOptions->pack_start(*dcbIterations);
dcbOptions->pack_start(*dcbEnhance);
pack_start( *dcbOptions, Gtk::PACK_SHRINK, 4);
lmmseOptions = Gtk::manage (new Gtk::VBox ());
lmmseOptions->set_border_width(4);
lmmseIterations = Gtk::manage (new Adjuster (M("TP_RAW_LMMSEITERATIONS"),0,6,1,2));
lmmseIterations->setAdjusterListener (this);
lmmseIterations->set_tooltip_markup (M("TP_RAW_LMMSE_TOOLTIP"));
if (lmmseIterations->delay < 1000) lmmseIterations->delay = 1000;
lmmseIterations->show();
lmmseOptions->pack_start(*lmmseIterations);
pack_start( *lmmseOptions, Gtk::PACK_SHRINK, 4);
pack_start( *Gtk::manage( new Gtk::HSeparator()), Gtk::PACK_SHRINK, 0 );
ccSteps = Gtk::manage (new Adjuster (M("TP_RAW_FALSECOLOR"),0,5,1,0 ));
ccSteps->setAdjusterListener (this);
if (ccSteps->delay < 1000) ccSteps->delay = 1000;
ccSteps->show();
pack_start( *ccSteps, Gtk::PACK_SHRINK, 4);
//pack_start( *Gtk::manage( new Gtk::HSeparator()), Gtk::PACK_SHRINK, 0 );
//allOptions = Gtk::manage (new Gtk::VBox ());
//allOptions->set_border_width(2);
//allEnhance = Gtk::manage (new Gtk::CheckButton(M("TP_RAW_ALLENHANCE")));
//allOptions->pack_start(*allEnhance);
//pack_start( *allOptions, Gtk::PACK_SHRINK, 4);
methodconn = method->signal_changed().connect( sigc::mem_fun(*this, &BayerProcess::methodChanged) );
dcbEnhconn = dcbEnhance->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::dcbEnhanceChanged), true);
//allEnhconn = allEnhance->signal_toggled().connect ( sigc::mem_fun(*this, &BayerProcess::allEnhanceChanged), true);
}
void BayerProcess::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited)
{
disableListener ();
methodconn.block (true);
dcbEnhconn.block (true);
//allEnhconn.block (true);
method->set_active(procparams::RAWParams::BayerSensor::numMethods);
for( size_t i=0; i< procparams::RAWParams::BayerSensor::numMethods; i++)
if( pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::methodstring[i]){
method->set_active(i);
oldSelection = i;
break;
}
if(pedited ){
ccSteps->setEditedState (pedited->raw.bayersensor.ccSteps ? Edited : UnEdited);
dcbIterations->setEditedState ( pedited->raw.bayersensor.dcbIterations ? Edited : UnEdited);
dcbEnhance->set_inconsistent(!pedited->raw.bayersensor.dcbEnhance);
//allEnhance->set_inconsistent(!pedited->raw.bayersensor.allEnhance);
lmmseIterations->setEditedState ( pedited->raw.bayersensor.lmmseIterations ? Edited : UnEdited);
if( !pedited->raw.bayersensor.method )
method->set_active(procparams::RAWParams::BayerSensor::numMethods); // No name
}
//allEnhance->set_active(pp->raw.bayersensor.all_enhance);
dcbIterations->setValue (pp->raw.bayersensor.dcb_iterations);
dcbEnhance->set_active(pp->raw.bayersensor.dcb_enhance);
ccSteps->setValue (pp->raw.bayersensor.ccSteps);
if (pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::methodstring[procparams::RAWParams::BayerSensor::dcb] ||
method->get_active_row_number() == procparams::RAWParams::BayerSensor::numMethods)
dcbOptions->show();
else
dcbOptions->hide();
lmmseIterations->setValue (pp->raw.bayersensor.lmmse_iterations);
if (pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::methodstring[procparams::RAWParams::BayerSensor::lmmse] ||
method->get_active_row_number() == procparams::RAWParams::BayerSensor::numMethods)
lmmseOptions->show();
else
lmmseOptions->hide();
// Flase color suppression is applied to all demozaicing method, so don't hide anything
/*if (pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::methodstring[procparams::RAWParams::BayerSensor::eahd] ||
pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::methodstring[procparams::RAWParams::BayerSensor::hphd] ||
pp->raw.bayersensor.method == procparams::RAWParams::BayerSensor::methodstring[procparams::RAWParams::BayerSensor::vng4])
ccSteps->show();
else
ccSteps->hide();*/
lastDCBen = pp->raw.bayersensor.dcb_enhance;
//lastALLen = pp->raw.bayersensor.all_enhance;
methodconn.block (false);
dcbEnhconn.block (false);
//allEnhconn.block (false);
enableListener ();
}
void BayerProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pedited)
{
pp->raw.bayersensor.ccSteps = ccSteps->getIntValue();
pp->raw.bayersensor.dcb_iterations = dcbIterations->getIntValue();
pp->raw.bayersensor.dcb_enhance = dcbEnhance->get_active();
//pp->raw.bayersensor.all_enhance = allEnhance->get_active();
pp->raw.bayersensor.lmmse_iterations = lmmseIterations->getIntValue();
int currentRow = method->get_active_row_number();
if( currentRow>=0 && currentRow < procparams::RAWParams::BayerSensor::numMethods)
pp->raw.bayersensor.method = procparams::RAWParams::BayerSensor::methodstring[currentRow];
if (pedited) {
pedited->raw.bayersensor.ccSteps = ccSteps->getEditedState ();
pedited->raw.bayersensor.method = method->get_active_row_number() != procparams::RAWParams::BayerSensor::numMethods;
pedited->raw.bayersensor.dcbIterations = dcbIterations->getEditedState ();
pedited->raw.bayersensor.dcbEnhance = !dcbEnhance->get_inconsistent();
//pedited->raw.bayersensor.allEnhance = !allEnhance->get_inconsistent();
pedited->raw.bayersensor.lmmseIterations = lmmseIterations->getEditedState ();
}
}
void BayerProcess::setBatchMode(bool batchMode)
{
method->append_text (M("GENERAL_UNCHANGED"));
method->set_active(procparams::RAWParams::BayerSensor::numMethods); // No name
dcbOptions->hide();
lmmseOptions->hide();
ToolPanel::setBatchMode (batchMode);
ccSteps->showEditedCB ();
dcbIterations->showEditedCB ();
lmmseIterations->showEditedCB ();
}
void BayerProcess::setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited)
{
dcbIterations->setDefault( defParams->raw.bayersensor.dcb_iterations);
lmmseIterations->setDefault( defParams->raw.bayersensor.lmmse_iterations);
ccSteps->setDefault (defParams->raw.bayersensor.ccSteps);
if (pedited) {
dcbIterations->setDefaultEditedState( pedited->raw.bayersensor.dcbIterations ? Edited : UnEdited);
lmmseIterations->setDefaultEditedState( pedited->raw.bayersensor.lmmseIterations ? Edited : UnEdited);
ccSteps->setDefaultEditedState(pedited->raw.bayersensor.ccSteps ? Edited : UnEdited);
}else{
dcbIterations->setDefaultEditedState( Irrelevant );
lmmseIterations->setDefaultEditedState( Irrelevant );
ccSteps->setDefaultEditedState(Irrelevant );
}
}
void BayerProcess::adjusterChanged (Adjuster* a, double newval)
{
if (listener) {
if (a == dcbIterations)
listener->panelChanged (EvDemosaicDCBIter, a->getTextValue() );
else if (a == ccSteps)
listener->panelChanged (EvDemosaicFalseColorIter, a->getTextValue() );
else if (a == lmmseIterations)
listener->panelChanged (EvDemosaicLMMSEIter, a->getTextValue() );
}
}
void BayerProcess::methodChanged ()
{
int curSelection = method->get_active_row_number();
if ( curSelection == procparams::RAWParams::BayerSensor::dcb){
dcbOptions->show();
}else{
dcbOptions->hide();
}
if ( curSelection == procparams::RAWParams::BayerSensor::lmmse){
lmmseOptions->show();
}else{
lmmseOptions->hide();
}
Glib::ustring methodName="";
bool ppreq = false;
if( curSelection>=0 && curSelection < procparams::RAWParams::BayerSensor::numMethods) {
methodName = procparams::RAWParams::BayerSensor::methodstring[curSelection];
if (curSelection == procparams::RAWParams::BayerSensor::mono || oldSelection == procparams::RAWParams::BayerSensor::mono) {
ppreq = true;
}
}
oldSelection = curSelection;
if (listener)
listener->panelChanged (ppreq ? EvDemosaicMethodPreProc : EvDemosaicMethod, methodName);
}
void BayerProcess::dcbEnhanceChanged ()
{
if (batchMode) {
if (dcbEnhance->get_inconsistent()) {
dcbEnhance->set_inconsistent (false);
dcbEnhconn.block (true);
dcbEnhance->set_active (false);
dcbEnhconn.block (false);
}
else if (lastDCBen)
dcbEnhance->set_inconsistent (true);
lastDCBen = dcbEnhance->get_active ();
}
if (listener)
listener->panelChanged (EvDemosaicDCBEnhanced, dcbEnhance->get_active()?M("GENERAL_ENABLED"):M("GENERAL_DISABLED"));
}
/*void BayerProcess::allEnhanceChanged ()
{
if (batchMode) {
if (allEnhance->get_inconsistent()) {
allEnhance->set_inconsistent (false);
allEnhconn.block (true);
allEnhance->set_active (false);
allEnhconn.block (false);
}
else if (lastALLen)
allEnhance->set_inconsistent (true);
lastALLen = allEnhance->get_active ();
}
if (listener)
listener->panelChanged (EvDemosaicALLEnhanced, allEnhance->get_active()?M("GENERAL_ENABLED"):M("GENERAL_DISABLED"));
}*/

61
rtgui/bayerprocess.h Normal file
View File

@@ -0,0 +1,61 @@
/*
* 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 _BAYERPROCESS_H_
#define _BAYERPROCESS_H_
#include <gtkmm.h>
#include "adjuster.h"
#include "guiutils.h"
#include "toolpanel.h"
class BayerProcess : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel{
protected:
MyComboBoxText* method;
Adjuster* ccSteps;
Gtk::VBox *dcbOptions;
Adjuster* dcbIterations;
Gtk::CheckButton* dcbEnhance;
//Gtk::VBox *allOptions;
//Gtk::CheckButton* allEnhance;
Gtk::VBox *lmmseOptions;
Adjuster* lmmseIterations;
bool lastDCBen;
int oldSelection;
//bool lastALLen;
sigc::connection methodconn,dcbEnhconn; //,allEnhconn;
public:
BayerProcess ();
void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL);
void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL);
void setBatchMode (bool batchMode);
void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL);
void methodChanged ();
void adjusterChanged (Adjuster* a, double newval);
void dcbEnhanceChanged();
//void allEnhanceChanged();
};
#endif

185
rtgui/bayerrawexposure.cc Normal file
View File

@@ -0,0 +1,185 @@
/*
* 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 "bayerrawexposure.h"
#include "guiutils.h"
#include "../rtengine/safegtk.h"
#include <sstream>
using namespace rtengine;
using namespace rtengine::procparams;
BayerRAWExposure::BayerRAWExposure () : FoldableToolPanel(this, "bayerrawexposure", M("TP_EXPOS_BLACKPOINT_LABEL"), true)
{
PexBlack1 = Gtk::manage(new Adjuster (M("TP_RAWEXPOS_BLACK_1"),-2048,2048,0.1,0));//black level
PexBlack1->setAdjusterListener (this);
if (PexBlack1->delay < 1000) PexBlack1->delay = 1000;
PexBlack1->show();
PexBlack2 = Gtk::manage(new Adjuster (M("TP_RAWEXPOS_BLACK_2"),-2048,2048,0.1,0));//black level
PexBlack2->setAdjusterListener (this);
if (PexBlack2->delay < 1000) PexBlack2->delay = 1000;
PexBlack2->show();
PexBlack3 = Gtk::manage(new Adjuster (M("TP_RAWEXPOS_BLACK_3"),-2048,2048,0.1,0));//black level
PexBlack3->setAdjusterListener (this);
if (PexBlack3->delay < 1000) PexBlack3->delay = 1000;
PexBlack3->show();
PexBlack0 = Gtk::manage(new Adjuster (M("TP_RAWEXPOS_BLACK_0"),-2048,2048,0.1,0));//black level
PexBlack0->setAdjusterListener (this);
if (PexBlack0->delay < 1000) PexBlack0->delay = 1000;
PexBlack0->show();
PextwoGreen = Gtk::manage(new Gtk::CheckButton((M("TP_RAWEXPOS_TWOGREEN"))));// two green
PextwoGreen->set_active (true);
greenconn = PextwoGreen->signal_toggled().connect ( sigc::mem_fun(*this, &BayerRAWExposure::GreenChanged));
pack_start( *PexBlack1, Gtk::PACK_SHRINK, 0);//black R
pack_start( *PexBlack0, Gtk::PACK_SHRINK, 0);//black G1
pack_start( *PexBlack3, Gtk::PACK_SHRINK, 0);//black G2
pack_start( *PexBlack2, Gtk::PACK_SHRINK, 0);//black B
pack_start( *PextwoGreen, Gtk::PACK_SHRINK, 0);//black 2 green
}
void BayerRAWExposure::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited)
{
disableListener ();
if(pedited ){
PexBlack0->setEditedState( pedited->raw.bayersensor.exBlack0 ? Edited : UnEdited );
PexBlack1->setEditedState( pedited->raw.bayersensor.exBlack1 ? Edited : UnEdited );
PexBlack2->setEditedState( pedited->raw.bayersensor.exBlack2 ? Edited : UnEdited );
PexBlack3->setEditedState( pedited->raw.bayersensor.exBlack3 ? Edited : UnEdited );
}
greenconn.block (true);
PextwoGreen->set_active (pp->raw.bayersensor.twogreen);
greenconn.block (false);
lastPextwoGreen = pp->raw.bayersensor.twogreen;
PexBlack0->setValue (pp->raw.bayersensor.black0);//black
PexBlack1->setValue (pp->raw.bayersensor.black1);//black
PexBlack2->setValue (pp->raw.bayersensor.black2);//black
if(!PextwoGreen->get_active())PexBlack3->setValue (pp->raw.bayersensor.black3);else PexBlack3->setValue (PexBlack0->getValue());
enableListener ();
}
void BayerRAWExposure::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pedited)
{
pp->raw.bayersensor.black0 = PexBlack0->getValue();// black
pp->raw.bayersensor.black1 = PexBlack1->getValue();// black
pp->raw.bayersensor.black2 = PexBlack2->getValue();// black
pp->raw.bayersensor.twogreen=PextwoGreen->get_active();
if(PextwoGreen->get_active()){pp->raw.bayersensor.black3=pp->raw.bayersensor.black0;} else {pp->raw.bayersensor.black3 = PexBlack3->getValue();}// active or desactive 2 green together
if (pedited) {
pedited->raw.bayersensor.exBlack0 = PexBlack0->getEditedState ();//black
pedited->raw.bayersensor.exBlack1 = PexBlack1->getEditedState ();//black
pedited->raw.bayersensor.exBlack2 = PexBlack2->getEditedState ();//black
pedited->raw.bayersensor.exBlack3 = PexBlack3->getEditedState ();//black
pedited->raw.bayersensor.exTwoGreen =!PextwoGreen->get_inconsistent();
}
}
void BayerRAWExposure::adjusterChanged (Adjuster* a, double newval)
{
if (listener) {
Glib::ustring value = a->getTextValue();
if (a == PexBlack0) {if(!PextwoGreen->get_active())
listener->panelChanged (EvPreProcessExpBlackzero, value ); else {listener->panelChanged (EvPreProcessExpBlackzero, value );PexBlack3->setValue (PexBlack0->getValue());}}
else if (a == PexBlack1)
listener->panelChanged (EvPreProcessExpBlackone, value );
else if (a == PexBlack2)
listener->panelChanged (EvPreProcessExpBlacktwo, value );
else if (a == PexBlack3) {if(!PextwoGreen->get_active())
listener->panelChanged (EvPreProcessExpBlackthree, value ); else {listener->panelChanged (EvPreProcessExpBlackthree, value );PexBlack0->setValue (PexBlack3->getValue());}}
}
}
void BayerRAWExposure::GreenChanged() {
if (batchMode) {
if (PextwoGreen->get_inconsistent()) {
PextwoGreen->set_inconsistent (false);
greenconn.block (true);
PextwoGreen->set_active (false);
greenconn.block (false);
}
else if (lastPextwoGreen)
PextwoGreen->set_inconsistent (true);
lastPextwoGreen = PextwoGreen->get_active ();
}
if (listener) {
if (PextwoGreen->get_active())
{ listener->panelChanged (EvPreProcessExptwoGreen, M("GENERAL_ENABLED"));
PexBlack3->setValue (PexBlack0->getValue());//two green together
}
else
{ listener->panelChanged (EvPreProcessExptwoGreen, M("GENERAL_DISABLED"));
}
}
}
void BayerRAWExposure::setBatchMode(bool batchMode)
{
ToolPanel::setBatchMode (batchMode);
PexBlack0->showEditedCB ();//black
PexBlack1->showEditedCB ();//black
PexBlack2->showEditedCB ();//black
PexBlack3->showEditedCB ();//black
}
void BayerRAWExposure::setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited)
{
PexBlack0->setDefault( defParams->raw.bayersensor.black0);
PexBlack1->setDefault( defParams->raw.bayersensor.black1);
PexBlack2->setDefault( defParams->raw.bayersensor.black2);
PexBlack3->setDefault( defParams->raw.bayersensor.black3);
if (pedited) {
PexBlack0->setDefaultEditedState( pedited->raw.bayersensor.exBlack0 ? Edited : UnEdited);
PexBlack1->setDefaultEditedState( pedited->raw.bayersensor.exBlack1 ? Edited : UnEdited);
PexBlack2->setDefaultEditedState( pedited->raw.bayersensor.exBlack2 ? Edited : UnEdited);
PexBlack3->setDefaultEditedState( pedited->raw.bayersensor.exBlack3 ? Edited : UnEdited);
} else {
PexBlack0->setDefaultEditedState( Irrelevant );
PexBlack1->setDefaultEditedState( Irrelevant );
PexBlack2->setDefaultEditedState( Irrelevant );
PexBlack3->setDefaultEditedState( Irrelevant );
}
}
void BayerRAWExposure::setAdjusterBehavior (bool pexblackadd) {
PexBlack0->setAddMode(pexblackadd);
PexBlack1->setAddMode(pexblackadd);
PexBlack2->setAddMode(pexblackadd);
PexBlack3->setAddMode(pexblackadd);
}
void BayerRAWExposure::trimValues (rtengine::procparams::ProcParams* pp) {
PexBlack0->trimValue(pp->raw.bayersensor.black0);
PexBlack1->trimValue(pp->raw.bayersensor.black1);
PexBlack2->trimValue(pp->raw.bayersensor.black2);
PexBlack3->trimValue(pp->raw.bayersensor.black3);
}

54
rtgui/bayerrawexposure.h Normal file
View File

@@ -0,0 +1,54 @@
/*
* 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 _BAYERRAWEXPOSURE_H_
#define _BAYERRAWEXPOSURE_H_
#include <gtkmm.h>
#include "adjuster.h"
#include "toolpanel.h"
#include "../rtengine/rawimage.h"
class BayerRAWExposure : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel {
protected:
Adjuster* PexBlack0;
Adjuster* PexBlack1;
Adjuster* PexBlack2;
Adjuster* PexBlack3;
bool lastPextwoGreen;
sigc::connection greenconn;
Gtk::CheckButton* PextwoGreen;
private:
// Gtk::CheckButton* PextwoGreen;
public:
BayerRAWExposure ();
void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL);
void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL);
void setBatchMode (bool batchMode);
void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL);
void GreenChanged() ;
void adjusterChanged (Adjuster* a, double newval);
void setAdjusterBehavior (bool pexblackadd);
void trimValues (rtengine::procparams::ProcParams* pp);
};
#endif

1323
rtgui/blackwhite.cc Normal file

File diff suppressed because it is too large Load Diff

138
rtgui/blackwhite.h Normal file
View File

@@ -0,0 +1,138 @@
/*
* 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 _BLACKWHITE_H_
#define _BLACKWHITE_H_
#include <gtkmm.h>
#include "adjuster.h"
#include "toolpanel.h"
#include "guiutils.h"
#include "curveeditor.h"
#include "curveeditorgroup.h"
#include "mycurve.h"
#include "colorprovider.h"
class BlackWhite : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel, public rtengine::AutoBWListener, public CurveListener, public ColorProvider{
protected:
FlatCurveEditor* luminanceCurve;
Gtk::HSeparator* luminanceSep;
CurveEditorGroup* luminanceCEG;
CurveEditorGroup* beforeCurveCEG;
DiagonalCurveEditor* beforeCurve;
MyComboBoxText* beforeCurveMode;
CurveEditorGroup* afterCurveCEG;
DiagonalCurveEditor* afterCurve;
MyComboBoxText* afterCurveMode;
Gtk::ToggleButton* autoch;
Gtk::HBox* autoHBox;
Gtk::Button* neutral;
Gtk::Label* RGBLabels;
MyComboBoxText* algo;
sigc::connection algoconn;
Gtk::Label* alLabel;
Gtk::HBox* algoHBox;
Adjuster *mixerRed;
Adjuster *mixerGreen;
Adjuster *mixerBlue;
Adjuster *gammaRed;
Adjuster *gammaGreen;
Adjuster *gammaBlue;
Adjuster *mixerOrange;
Adjuster *mixerYellow;
Adjuster *mixerCyan;
Adjuster *mixerMagenta;
Adjuster *mixerPurple;
MyComboBoxText* method;
sigc::connection methodconn;
Gtk::HBox* filterHBox;
Gtk::HSeparator* filterSep, *filterSep2;
MyComboBoxText* filter;
sigc::connection filterconn;
Gtk::HBox* settingHBox;
MyComboBoxText* setting;
sigc::connection settingconn;
Gtk::Frame* mixerFrame;
Gtk::VBox * mixerVBox;
Gtk::Frame* gammaFrame;
Gtk::Image *imgIcon[11];
Gtk::HSeparator* enabledccSep;
Gtk::CheckButton* enabledcc;
bool lastEnabledcc, lastAuto;
sigc::connection enaccconn,tcmodeconn,tcmodeconn2, autoconn, neutralconn;
double nextredbw;
double nextgreenbw;
double nextbluebw;
void showLuminance();
void hideLuminance();
void showFilter();
void hideFilter();
void showEnabledCC();
void hideEnabledCC();
void showMixer(int nChannels, bool RGBIsSensitive=true);
void hideMixer();
void showGamma();
void hideGamma();
public:
BlackWhite ();
~BlackWhite ();
void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL);
void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL);
void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL);
void setBatchMode (bool batchMode);
void autoOpenCurve ();
void setEditProvider (EditDataProvider *provider);
void autoch_toggled ();
void neutral_pressed ();
void updateRGBLabel ();
void adjusterChanged (Adjuster* a, double newval);
void setAdjusterBehavior (bool bwadd, bool bwgadd);
void trimValues (rtengine::procparams::ProcParams* pp);
void enabledcc_toggled ();
void enabledChanged ();
void methodChanged ();
void filterChanged ();
void settingChanged ();
virtual void colorForValue (double valX, double valY, enum ColorCaller::ElemType elemType, int callerId, ColorCaller* caller);
void BWChanged (double redbw, double greenbw, double bluebw);
bool BWComputed_ ();
void curveChanged (CurveEditor* ce);
void curveMode1Changed ();
bool curveMode1Changed_ ();
void curveMode1Changed2 ();
bool curveMode1Changed2_ ();
void algoChanged ();
Glib::ustring getSettingString ();
Glib::ustring getFilterString ();
Glib::ustring getalgoString ();
};
#endif

176
rtgui/bqentryupdater.cc Normal file
View File

@@ -0,0 +1,176 @@
/*
* 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 "bqentryupdater.h"
#include <gtkmm.h>
#include "guiutils.h"
BatchQueueEntryUpdater batchQueueEntryUpdater;
BatchQueueEntryUpdater::BatchQueueEntryUpdater ()
: tostop(false), stopped(true), thread(NULL), qMutex(NULL) {
}
void BatchQueueEntryUpdater::process (guint8* oimg, int ow, int oh, int newh, BQEntryUpdateListener* listener, rtengine::ProcParams* pparams, Thumbnail* thumbnail) {
if (!oimg && (!pparams || !thumbnail)) {
//printf("WARNING! !oimg && (!pparams || !thumbnail)\n");
return;
}
if (!qMutex)
qMutex = new MyMutex ();
qMutex->lock ();
// look up if an older version is in the queue
std::list<Job>::iterator i;
for (i=jqueue.begin(); i!=jqueue.end(); i++)
if (i->oimg==oimg && i->listener==listener) {
i->ow = ow;
i->oh = oh;
i->newh = newh;
i->listener = listener;
i->pparams = pparams;
i->thumbnail = thumbnail;
break;
}
// not found, create and append new job
if (i==jqueue.end ()) {
Job j;
j.oimg = oimg;
j.ow = ow;
j.oh = oh;
j.newh = newh;
j.listener = listener;
j.pparams = pparams;
j.thumbnail = thumbnail;
jqueue.push_back (j);
}
qMutex->unlock ();
// Start thread if not running yet
if (stopped) {
stopped = false;
tostop = false;
#if __GNUC__ == 4 && __GNUC_MINOR__ == 8 && defined( WIN32 ) && defined(__x86_64__)
#undef THREAD_PRIORITY_NORMAL
// See Issue 2384 comment #3
thread = Glib::Thread::create(sigc::mem_fun(*this, &BatchQueueEntryUpdater::processThread), (unsigned long int)0, true, true, Glib::THREAD_PRIORITY_NORMAL);
#else
#undef THREAD_PRIORITY_LOW
thread = Glib::Thread::create(sigc::mem_fun(*this, &BatchQueueEntryUpdater::processThread), (unsigned long int)0, true, true, Glib::THREAD_PRIORITY_LOW);
#endif
}
}
void BatchQueueEntryUpdater::processThread () {
// TODO: process visible jobs first
bool isEmpty=false;
while (!tostop && !isEmpty) {
qMutex->lock ();
isEmpty=jqueue.empty (); // do NOT put into while() since it must be within mutex section
Job current;
if (!isEmpty) {
current = jqueue.front ();
jqueue.pop_front ();
}
qMutex->unlock ();
if(isEmpty)
break;
rtengine::IImage8* img = NULL;
bool newBuffer = false;
if (current.thumbnail && current.pparams) {
// the thumbnail and the pparams are provided, it means that we have to build the original preview image
double tmpscale;
img = current.thumbnail->processThumbImage (*current.pparams, current.oh, tmpscale);
//current.thumbnail->decreaseRef (); // WARNING: decreasing refcount (and maybe deleting) thumbnail, with or without processed image
if (img) {
int prevw = img->getWidth();
int prevh = img->getHeight();
#ifndef NDEBUG
if (current.ow != img->getW() || current.oh != img->getH())
printf("WARNING! Expected image size: %dx%d ; image size is: %dx%d\n", current.ow, current.oh, img->getW(), img->getH());
assert ((current.ow+1)*current.oh >= img->getW()*img->getH());
#endif
current.ow = prevw;
current.oh = prevh;
if (!current.oimg) {
current.oimg = new guint8[prevw*prevh*3];
newBuffer = true;
}
memcpy(current.oimg, img->getData(), prevw * prevh * 3);
img->free();
}
}
if (current.oimg && !isEmpty && current.listener) {
int neww = current.newh * current.ow / current.oh;
guint8* img = new guint8 [current.newh*neww*3];
thumbInterp (current.oimg, current.ow, current.oh, img, neww, current.newh);
current.listener->updateImage (img, neww, current.newh, current.ow, current.oh, newBuffer?current.oimg:NULL);
}
if(current.oimg) {
delete[] current.oimg;
current.oimg = NULL;
}
}
stopped = true;
}
void BatchQueueEntryUpdater::removeJobs (BQEntryUpdateListener* listener) {
if (!qMutex) return;
qMutex->lock ();
bool ready = false;
while (!ready) {
ready = true;
std::list<Job>::iterator i;
for (i=jqueue.begin(); i!=jqueue.end(); i++)
if (i->listener == listener) {
jqueue.erase (i);
ready = false;
break;
}
}
qMutex->unlock ();
}
void BatchQueueEntryUpdater::terminate () {
// never started or currently not running?
if (!qMutex || stopped) return;
if (!stopped) {
// Yield to currently running thread and wait till it's finished
GThreadUnLock lock;
tostop = true;
Glib::Thread::self()->yield();
if (!stopped) thread->join ();
}
// Remove remaining jobs
qMutex->lock ();
while (!jqueue.empty()) jqueue.pop_front ();
qMutex->unlock ();
}

63
rtgui/bqentryupdater.h Normal file
View File

@@ -0,0 +1,63 @@
/*
* 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 _BQENTRYUPDATER_
#define _BQENTRYUPDATER_
#include <glibmm.h>
#include "../rtengine/rtengine.h"
#include "threadutils.h"
#include "thumbnail.h"
class BQEntryUpdateListener {
public:
virtual ~BQEntryUpdateListener () {}
virtual void updateImage (guint8* img, int w, int h, int origw, int origh, guint8* newOPreview) {}
};
class BatchQueueEntryUpdater {
struct Job {
guint8* oimg;
int ow, oh, newh;
BQEntryUpdateListener* listener;
rtengine::ProcParams* pparams;
Thumbnail* thumbnail;
};
protected:
bool tostop;
bool stopped;
std::list<Job> jqueue;
Glib::Thread* thread;
MyMutex* qMutex;
public:
BatchQueueEntryUpdater ();
void process (guint8* oimg, int ow, int oh, int newh, BQEntryUpdateListener* listener, rtengine::ProcParams* pparams=NULL, Thumbnail* thumbnail=NULL);
void removeJobs (BQEntryUpdateListener* listener);
void terminate ();
void processThread ();
};
extern BatchQueueEntryUpdater batchQueueEntryUpdater;
#endif

33
rtgui/browserfilter.cc Normal file
View File

@@ -0,0 +1,33 @@
/*
* 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 "browserfilter.h"
BrowserFilter::BrowserFilter () : exifFilterEnabled (false) {
showTrash = true;
for (int i=0; i<6; i++){
showRanked[i] = true;
showCLabeled[i] = true;
}
for (int i=0; i<2; i++){
showEdited[i] = true;
showRecentlySaved[i] = true;
}
}

45
rtgui/browserfilter.h Normal file
View File

@@ -0,0 +1,45 @@
/*
* 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 _BROWSERFILTER_
#define _BROWSERFILTER_
#include "exiffiltersettings.h"
#include <glibmm.h>
class BrowserFilter {
public:
bool showRanked[6];
bool showCLabeled[6];
bool showTrash;
bool showNotTrash;
bool showEdited[2];
bool showRecentlySaved[2];
bool multiselect;
Glib::ustring queryString;
Glib::ustring queryFileName;
bool exifFilterEnabled;
ExifFilterSettings exifFilter;
BrowserFilter ();
};
#endif

183
rtgui/cacheimagedata.cc Normal file
View File

@@ -0,0 +1,183 @@
/*
* 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 "cacheimagedata.h"
#include <vector>
#include <glib/gstdio.h>
#include "../rtengine/safekeyfile.h"
#include "../rtengine/safegtk.h"
#include "version.h"
#include <locale.h>
CacheImageData::CacheImageData ()
: md5(""), supported(false), format(FT_Invalid), rankOld(-1), inTrashOld(false), recentlySaved(false),
timeValid(false), exifValid(false), redAWBMul(-1.0), greenAWBMul(-1.0), blueAWBMul(-1.0), thumbImgType(0) {
}
/*
* Load the General, DateTime, ExifInfo, File info and ExtraRawInfo sections of the image data file
*/
int CacheImageData::load (const Glib::ustring& fname) {
setlocale(LC_NUMERIC, "C"); // to set decimal point to "."
rtengine::SafeKeyFile keyFile;
try {
if (keyFile.load_from_file (fname)) {
if (keyFile.has_group ("General")) {
if (keyFile.has_key ("General", "MD5")) md5 = keyFile.get_string ("General", "MD5");
if (keyFile.has_key ("General", "Version")) version = keyFile.get_string ("General", "Version");
if (keyFile.has_key ("General", "Supported")) supported = keyFile.get_boolean ("General", "Supported");
if (keyFile.has_key ("General", "Format")) format = (ThFileType)keyFile.get_integer ("General", "Format");
if (keyFile.has_key ("General", "Rank")) rankOld = keyFile.get_integer ("General", "Rank");
if (keyFile.has_key ("General", "InTrash")) inTrashOld = keyFile.get_boolean ("General", "InTrash");
if (keyFile.has_key ("General", "RecentlySaved")) recentlySaved = keyFile.get_boolean ("General", "RecentlySaved");
}
timeValid = keyFile.has_group ("DateTime");
if (timeValid) {
if (keyFile.has_key ("DateTime", "Year")) year = keyFile.get_integer ("DateTime", "Year");
if (keyFile.has_key ("DateTime", "Month")) month = keyFile.get_integer ("DateTime", "Month");
if (keyFile.has_key ("DateTime", "Day")) day = keyFile.get_integer ("DateTime", "Day");
if (keyFile.has_key ("DateTime", "Hour")) hour = keyFile.get_integer ("DateTime", "Hour");
if (keyFile.has_key ("DateTime", "Min")) min = keyFile.get_integer ("DateTime", "Min");
if (keyFile.has_key ("DateTime", "Sec")) sec = keyFile.get_integer ("DateTime", "Sec");
}
exifValid = false;
if (keyFile.has_group ("ExifInfo")) {
exifValid = true;
if (keyFile.has_key ("ExifInfo", "Valid")) exifValid = keyFile.get_boolean ("ExifInfo", "Valid");
if (exifValid) {
if (keyFile.has_key ("ExifInfo", "FNumber")) fnumber = keyFile.get_double ("ExifInfo", "FNumber");
if (keyFile.has_key ("ExifInfo", "Shutter")) shutter = keyFile.get_double ("ExifInfo", "Shutter");
if (keyFile.has_key ("ExifInfo", "FocalLen")) focalLen = keyFile.get_double ("ExifInfo", "FocalLen");
if (keyFile.has_key ("ExifInfo", "FocalLen35mm")) focalLen35mm = keyFile.get_double ("ExifInfo", "FocalLen35mm");
else focalLen35mm=focalLen; // prevent crashes on old files
if (keyFile.has_key ("ExifInfo", "FocusDist")) focusDist = keyFile.get_double ("ExifInfo", "FocusDist");
else focusDist=0;
if (keyFile.has_key ("ExifInfo", "ISO")) iso = keyFile.get_integer ("ExifInfo", "ISO");
if (keyFile.has_key ("ExifInfo", "ExpComp")) expcomp = keyFile.get_string ("ExifInfo", "ExpComp");
}
if (keyFile.has_key ("ExifInfo", "Lens")) lens = keyFile.get_string ("ExifInfo", "Lens");
if (keyFile.has_key ("ExifInfo", "CameraMake")) camMake = keyFile.get_string ("ExifInfo", "CameraMake");
if (keyFile.has_key ("ExifInfo", "CameraModel")) camModel = keyFile.get_string ("ExifInfo", "CameraModel");
}
if (keyFile.has_group ("FileInfo")) {
if (keyFile.has_key ("FileInfo", "Filetype")) filetype = keyFile.get_string ("FileInfo", "Filetype");
}
if (format==FT_Raw && keyFile.has_group ("ExtraRawInfo")) {
if (keyFile.has_key ("ExtraRawInfo", "ThumbImageType")) thumbImgType = keyFile.get_integer ("ExtraRawInfo", "ThumbImageType");
if (keyFile.has_key ("ExtraRawInfo", "ThumbImageOffset")) thumbOffset = keyFile.get_integer ("ExtraRawInfo", "ThumbImageOffset");
}
else {
rotate = 0;
thumbImgType = 0;
}
return 0;
}
}
catch (Glib::Error &err) {
if (options.rtSettings.verbose)
printf("CacheImageData::load / Error code %d while reading values from \"%s\":\n%s\n", err.code(), fname.c_str(), err.what().c_str());
}
catch (...) {
if (options.rtSettings.verbose)
printf("CacheImageData::load / Unknown exception while trying to load \"%s\"!\n", fname.c_str());
}
return 1;
}
/*
* Save the General, DateTime, ExifInfo, File info and ExtraRawInfo sections of the image data file
*/
int CacheImageData::save (const Glib::ustring& fname) {
rtengine::SafeKeyFile keyFile;
if (safe_file_test(fname,Glib::FILE_TEST_EXISTS)) {
try {
keyFile.load_from_file (fname);
}
catch (Glib::Error &err) {
if (options.rtSettings.verbose)
printf("CacheImageData::save / Error code %d while reading values from \"%s\":\n%s\n", err.code(), fname.c_str(), err.what().c_str());
}
catch (...) {
if (options.rtSettings.verbose)
printf("CacheImageData::save / Unknown exception while trying to save \"%s\"!\n", fname.c_str());
}
}
keyFile.set_string ("General", "MD5", md5);
keyFile.set_string ("General", "Version", VERSION); // Application's version
keyFile.set_boolean ("General", "Supported", supported);
keyFile.set_integer ("General", "Format", format);
keyFile.set_boolean ("General", "RecentlySaved", recentlySaved);
// remove the old implementation of Rank and InTrash from cache
if (keyFile.has_key ("General", "Rank")) keyFile.remove_key("General", "Rank");
if (keyFile.has_key ("General", "InTrash")) keyFile.remove_key("General", "InTrash");
if (timeValid) {
keyFile.set_integer ("DateTime", "Year", year);
keyFile.set_integer ("DateTime", "Month", month);
keyFile.set_integer ("DateTime", "Day", day);
keyFile.set_integer ("DateTime", "Hour", hour);
keyFile.set_integer ("DateTime", "Min", min);
keyFile.set_integer ("DateTime", "Sec", sec);
}
keyFile.set_boolean ("ExifInfo", "Valid", exifValid);
if (exifValid) {
keyFile.set_double ("ExifInfo", "FNumber", fnumber);
keyFile.set_double ("ExifInfo", "Shutter", shutter);
keyFile.set_double ("ExifInfo", "FocalLen", focalLen);
keyFile.set_double ("ExifInfo", "FocalLen35mm", focalLen35mm);
keyFile.set_double ("ExifInfo", "FocusDist", focusDist);
keyFile.set_integer ("ExifInfo", "ISO", iso);
keyFile.set_string ("ExifInfo", "ExpComp", expcomp);
}
keyFile.set_string ("ExifInfo", "Lens", lens);
keyFile.set_string ("ExifInfo", "CameraMake", camMake);
keyFile.set_string ("ExifInfo", "CameraModel", camModel);
keyFile.set_string ("FileInfo", "Filetype", filetype);
if (format==FT_Raw) {
keyFile.set_integer ("ExtraRawInfo", "ThumbImageType", thumbImgType);
keyFile.set_integer ("ExtraRawInfo", "ThumbImageOffset", thumbOffset);
}
FILE *f = safe_g_fopen (fname, "wt");
if (!f) {
if (options.rtSettings.verbose)
printf("CacheImageData::save / Error: unable to open file \"%s\" with write access!\n", fname.c_str());
return 1;
}
else {
fprintf (f, "%s", keyFile.to_data().c_str());
fclose (f);
return 0;
}
}

82
rtgui/cacheimagedata.h Normal file
View File

@@ -0,0 +1,82 @@
/*
* 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 _CACHEIMAGEDATA_
#define _CACHEIMAGEDATA_
#include <glibmm.h>
#include "options.h"
class CacheImageData {
public:
// basic informations
Glib::ustring md5;
Glib::ustring version;
bool supported;
ThFileType format;
char rankOld; // old implementation of rank
bool inTrashOld; // old implementation of inTrash
bool recentlySaved;
// time/date info
bool timeValid;
short year;
char month;
char day;
char hour;
char min;
char sec;
// exif info
bool exifValid;
double fnumber;
double shutter;
double focalLen,focalLen35mm;
float focusDist;
unsigned iso;
Glib::ustring lens;
Glib::ustring camMake;
Glib::ustring camModel;
Glib::ustring filetype;
Glib::ustring expcomp;
// store a copy of the autoWB's multipliers computed in Thumbnail::_generateThumbnailImage
// they are not stored in the cache file by this class, but by rtengine::Thumbnail
// -1 = Unknown
double redAWBMul, greenAWBMul, blueAWBMul;
// additional info on raw images
int rotate;
int thumbImgType;
int thumbOffset;
enum
{
FULL_THUMBNAIL = 0, // was the thumbnail generated from whole file
QUICK_THUMBNAIL = 1 // was the thumbnail generated from embedded jpeg
};
CacheImageData ();
int load (const Glib::ustring& fname);
int save (const Glib::ustring& fname);
Glib::ustring getCamera() const { return Glib::ustring(camMake+" "+camModel); }
};
#endif

347
rtgui/cachemanager.cc Normal file
View File

@@ -0,0 +1,347 @@
/*
* 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 "cachemanager.h"
#include "options.h"
#include <glib/gstdio.h>
#include <giomm.h>
#include "guiutils.h"
#include "procparamchangers.h"
#include "../rtengine/safegtk.h"
#ifdef WIN32
#include <windows.h>
#endif
CacheManager*
CacheManager::getInstance(void)
{
static CacheManager* instance_ = 0;
if ( instance_ == 0 )
{
static MyMutex smutex_;
MyMutex::MyLock lock(smutex_);
if ( instance_ == 0 )
{
instance_ = new CacheManager();
}
}
return instance_;
}
void CacheManager::init () {
MyMutex::MyLock lock(mutex_);
openEntries.clear ();
baseDir = options.cacheBaseDir;
if (!safe_file_test (baseDir, Glib::FILE_TEST_IS_DIR))
safe_g_mkdir_with_parents (baseDir, 511);
if (!safe_file_test (Glib::build_filename (baseDir, "profiles"), Glib::FILE_TEST_IS_DIR))
safe_g_mkdir_with_parents (Glib::ustring(Glib::build_filename (baseDir, "profiles")), 511);
if (!safe_file_test (Glib::build_filename (baseDir, "images"), Glib::FILE_TEST_IS_DIR))
safe_g_mkdir_with_parents (Glib::ustring(Glib::build_filename (baseDir, "images")), 511);
if (!safe_file_test (Glib::build_filename (baseDir, "aehistograms"), Glib::FILE_TEST_IS_DIR))
safe_g_mkdir_with_parents (Glib::ustring(Glib::build_filename (baseDir, "aehistograms")), 511);
if (!safe_file_test (Glib::build_filename (baseDir, "embprofiles"), Glib::FILE_TEST_IS_DIR))
safe_g_mkdir_with_parents (Glib::ustring(Glib::build_filename (baseDir, "embprofiles")), 511);
if (!safe_file_test (Glib::build_filename (baseDir, "data"), Glib::FILE_TEST_IS_DIR))
safe_g_mkdir_with_parents (Glib::ustring(Glib::build_filename (baseDir, "data")), 511);
}
Thumbnail* CacheManager::getEntry (const Glib::ustring& fname) {
Thumbnail* res = NULL;
// take manager lock and search for entry, if found return it else release
// lock and create it
{
MyMutex::MyLock lock(mutex_);
string_thumb_map::iterator r = openEntries.find (fname);
// if it is open, return it
if (r!=openEntries.end()) {
r->second->increaseRef ();
return r->second;
}
}
// compute the md5
std::string md5 = getMD5 (fname);
if (md5=="")
return NULL;
// build path name
Glib::ustring cfname = getCacheFileName ("data", fname, md5) + ".txt";
// let's see if we have it in the cache
if (safe_file_test (cfname, Glib::FILE_TEST_EXISTS)) {
CacheImageData* cfs = new CacheImageData ();
int e = cfs->load (cfname);
if (!e && cfs->supported==true)
res = new Thumbnail (this, fname, cfs);
if (res && !res->isSupported ()) {
delete res;
res = NULL;
}
delete cfs;
}
// if not, create a new one
if (!res) {
res = new Thumbnail (this, fname, md5);
if (!res->isSupported ()) {
delete res;
res = NULL;
}
}
// retake the lock and see if it was added while we we're unlocked, if it
// was use it over our version. if not added we create the cache entry
if (res)
{
MyMutex::MyLock lock(mutex_);
string_thumb_map::iterator r = openEntries.find (fname);
if (r!=openEntries.end()) {
delete res;
r->second->increaseRef ();
return r->second;
}
// it wasn't, create a new entry
openEntries[fname] = res;
}
return res;
}
void CacheManager::deleteEntry (const Glib::ustring& fname) {
MyMutex::MyLock lock(mutex_);
// check if it is opened
string_thumb_map::iterator r = openEntries.find (fname);
// if it is open, dont delete it
if (r!=openEntries.end()) {
std::string md5 = r->second->getMD5 ();
// decrease reference count; this will call back into CacheManager so
// we release the lock for it.
{
lock.release();
r->second->decreaseRef ();
lock.acquire();
}
// if in the editor, the thumbnail still exists. If not, delete it:
r = openEntries.find (fname);
if (r==openEntries.end() && md5!="") {
safe_g_remove (getCacheFileName ("data", fname, md5) + ".txt");
safe_g_remove (getCacheFileName ("profiles", fname, md5) + paramFileExtension);
safe_g_remove (getCacheFileName ("images", fname, md5) + ".rtti");
safe_g_remove (getCacheFileName ("images", fname, md5) + ".cust16");
safe_g_remove (getCacheFileName ("images", fname, md5) + ".cust");
safe_g_remove (getCacheFileName ("images", fname, md5) + ".jpg");
safe_g_remove (getCacheFileName ("aehistograms", fname, md5));
safe_g_remove (getCacheFileName ("embprofiles", fname, md5) + ".icc");
}
}
else {
std::string md5 = getMD5 (fname);
if (md5!="") {
safe_g_remove (getCacheFileName ("data", fname, md5) + ".txt");
safe_g_remove (getCacheFileName ("profiles", fname, md5) + paramFileExtension);
safe_g_remove (getCacheFileName ("images", fname, md5) + ".rtti");
safe_g_remove (getCacheFileName ("images", fname, md5) + ".cust16");
safe_g_remove (getCacheFileName ("images", fname, md5) + ".cust");
safe_g_remove (getCacheFileName ("images", fname, md5) + ".jpg");
safe_g_remove (getCacheFileName ("aehistograms", fname, md5));
safe_g_remove (getCacheFileName ("embprofiles", fname, md5) + ".icc");
}
}
}
void CacheManager::clearFromCache (const Glib::ustring& fname, bool leavenotrace) {
std::string md5 = getMD5 (fname);
if (md5!="") {
if (leavenotrace){
safe_g_remove (getCacheFileName ("data", fname, md5) + ".txt");
safe_g_remove (getCacheFileName ("profiles", fname, md5) + paramFileExtension);
}
safe_g_remove (getCacheFileName ("images", fname, md5) + ".rtti");
safe_g_remove (getCacheFileName ("images", fname, md5) + ".cust16");
safe_g_remove (getCacheFileName ("images", fname, md5) + ".cust");
safe_g_remove (getCacheFileName ("images", fname, md5) + ".jpg");
safe_g_remove (getCacheFileName ("aehistograms", fname, md5));
safe_g_remove (getCacheFileName ("embprofiles", fname, md5) + ".icc");
}
}
void CacheManager::renameEntry (const std::string& oldfilename, const std::string& oldmd5, const std::string& newfilename) {
MyMutex::MyLock lock(mutex_);
std::string newmd5 = getMD5 (newfilename);
safe_g_rename (getCacheFileName ("profiles", oldfilename, oldmd5) + paramFileExtension, (getCacheFileName ("profiles", newfilename, newmd5) + paramFileExtension).c_str());
safe_g_rename (getCacheFileName ("images", oldfilename, oldmd5) + ".rtti", getCacheFileName ("images", newfilename, newmd5) + ".rtti");
safe_g_rename (getCacheFileName ("images", oldfilename, oldmd5) + ".cust16", getCacheFileName ("images", newfilename, newmd5) + ".cust16");
safe_g_rename (getCacheFileName ("images", oldfilename, oldmd5) + ".cust", getCacheFileName ("images", newfilename, newmd5) + ".cust");
safe_g_rename (getCacheFileName ("images", oldfilename, oldmd5) + ".jpg", getCacheFileName ("images", newfilename, newmd5) + ".jpg");
safe_g_rename (getCacheFileName ("aehistograms", oldfilename, oldmd5), getCacheFileName ("aehistograms", newfilename, newmd5));
safe_g_rename (getCacheFileName ("embprofiles", oldfilename, oldmd5) + ".icc", getCacheFileName ("embprofiles", newfilename, newmd5) + ".icc");
safe_g_rename (getCacheFileName ("data", oldfilename, oldmd5) + ".txt", getCacheFileName ("data", newfilename, newmd5) + ".txt");
// check if it is opened
string_thumb_map::iterator r = openEntries.find (oldfilename);
// if it is open, update md5
if (r!=openEntries.end()) {
Thumbnail* t = r->second;
openEntries.erase (r);
t->setFileName (newfilename);
openEntries[newfilename] = t;
t->updateCache ();
t->saveThumbnail ();
}
}
void CacheManager::closeThumbnail (Thumbnail* t) {
MyMutex::MyLock lock(mutex_);
// t->updateCache ();
string_thumb_map::iterator r = openEntries.find (t->getFileName());
if (r!=openEntries.end())
openEntries.erase (r);
delete t;
}
void CacheManager::closeCache () {
MyMutex::MyLock lock(mutex_);
applyCacheSizeLimitation ();
}
void CacheManager::clearAll () {
MyMutex::MyLock lock(mutex_);
deleteDir ("images");
deleteDir ("aehistograms");
deleteDir ("embprofiles");
deleteDir ("profiles");
deleteDir ("data");
// re-generate thumbnail images and clear profiles of open thumbnails
//string_thumb_map::iterator i;
//for (i=openEntries.begin(); i!=openEntries.end(); i++) {
// i->second->clearProcParams (CACHEMGR);
// i->second->generateThumbnailImage ();
// i->second->updateCache ();
//}
}
void CacheManager::clearThumbImages () {
MyMutex::MyLock lock(mutex_);
deleteDir ("images");
deleteDir ("aehistograms");
deleteDir ("embprofiles");
}
void CacheManager::clearProfiles () {
MyMutex::MyLock lock(mutex_);
deleteDir ("profiles");
}
void CacheManager::deleteDir (const Glib::ustring& dirName) {
try {
Glib::Dir* dir = new Glib::Dir (Glib::build_filename (baseDir, dirName));
for (Glib::DirIterator i = dir->begin(); i!=dir->end(); ++i)
safe_g_remove (Glib::build_filename (Glib::build_filename (baseDir, dirName), *i));
delete dir;
}
catch (const Glib::Error& e) {
}
}
std::string CacheManager::getMD5 (const Glib::ustring& fname) {
Glib::RefPtr<Gio::File> file = Gio::File::create_for_path (fname);
if (file && file->query_exists()) {
#ifdef WIN32
// Windows: file name + size + creation time
// Safer because e.g. your camera image counter turns over. Do NOT use modified date, since tagging programs will change that
wchar_t *wFname = (wchar_t*)g_utf8_to_utf16 (fname.c_str(), -1, NULL, NULL, NULL);
WIN32_FILE_ATTRIBUTE_DATA fileAttr;
bool success=GetFileAttributesExW(wFname, GetFileExInfoStandard, &fileAttr);
g_free(wFname);
if (success) {
// Just need the low file size, since RAWs are never that large
Glib::ustring fileID= Glib::ustring::compose ("%1-%2-%3-%4", fileAttr.nFileSizeLow, fileAttr.ftCreationTime.dwHighDateTime, fileAttr.ftCreationTime.dwLowDateTime, fname );
return Glib::Checksum::compute_checksum (Glib::Checksum::CHECKSUM_MD5, fileID);
}
#else
// Least common denominator: file name + size to identify a file
Glib::RefPtr<Gio::FileInfo> info = safe_query_file_info (file);
if (info)
return Glib::Checksum::compute_checksum (Glib::Checksum::CHECKSUM_MD5, Glib::ustring::compose ("%1%2", fname, info->get_size()));
#endif
}
return "";
}
Glib::ustring CacheManager::getCacheFileName (const Glib::ustring& subdir, const Glib::ustring& fname, const Glib::ustring& md5) {
Glib::ustring cfn = Glib::build_filename (baseDir, subdir);
Glib::ustring cname = Glib::path_get_basename (fname) + "." + md5;
return Glib::build_filename (cfn, cname);
}
void CacheManager::applyCacheSizeLimitation () {
// TODO: Improve this, it just blindly deletes image without looking at create time or something to keep the current ones
std::vector<FileMTimeInfo> flist;
Glib::ustring dataDir = Glib::build_filename (baseDir, "data");
Glib::RefPtr<Gio::File> dir = Gio::File::create_for_path (dataDir);
safe_build_file_list (dir, flist);
if (flist.size() > options.maxCacheEntries) {
std::sort (flist.begin(), flist.end());
while (flist.size() > options.maxCacheEntries) {
safe_g_remove (Glib::build_filename (Glib::build_filename (baseDir, "data"), flist.front().fname) + ".txt");
safe_g_remove (Glib::build_filename (Glib::build_filename (baseDir, "images"), flist.front().fname) + ".rtti");
safe_g_remove (Glib::build_filename (Glib::build_filename (baseDir, "images"), flist.front().fname) + ".cust16");
safe_g_remove (Glib::build_filename (Glib::build_filename (baseDir, "images"), flist.front().fname) + ".cust");
safe_g_remove (Glib::build_filename (Glib::build_filename (baseDir, "images"), flist.front().fname) + ".jpg");
safe_g_remove (Glib::build_filename (Glib::build_filename (baseDir, "aehistograms"), flist.front().fname));
safe_g_remove (Glib::build_filename (Glib::build_filename (baseDir, "embprofiles"), flist.front().fname) + ".icc");
// safe_g_remove (Glib::build_filename (Glib::build_filename (baseDir, "profiles"), flist.front().fname) + paramFileExtension);
flist.erase (flist.begin());
}
}
}

74
rtgui/cachemanager.h Normal file
View File

@@ -0,0 +1,74 @@
/*
* 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 _CACHEMANAGER_
#define _CACHEMANAGER_
#include <string>
#include <map>
#include <glibmm.h>
#include "thumbnail.h"
#include <cstdio>
#include "../rtengine/procparams.h"
#include "threadutils.h"
class Thumbnail;
class CacheManager {
typedef std::pair<std::string, Thumbnail*> string_thumb_pair;
typedef std::map<std::string, Thumbnail*> string_thumb_map;
string_thumb_map openEntries;
Glib::ustring baseDir;
MyMutex mutex_;
void deleteDir (const Glib::ustring& dirName);
CacheManager () {}
public:
static CacheManager* getInstance(void);
void init ();
Thumbnail* getEntry (const Glib::ustring& fname);
void deleteEntry (const Glib::ustring& fname);
void renameEntry (const std::string& oldfilename, const std::string& oldmd5, const std::string& newfilename);
void closeThumbnail (Thumbnail* t);
const Glib::ustring& getBaseDir () { MyMutex::MyLock lock(mutex_); return baseDir; }
void closeCache ();
static std::string getMD5 (const Glib::ustring& fname);
void clearAll ();
void clearThumbImages ();
void clearProfiles ();
void clearFromCache(const Glib::ustring& fname, bool leavenotrace);
void applyCacheSizeLimitation ();
Glib::ustring getCacheFileName (const Glib::ustring& subdir, const Glib::ustring& fname, const Glib::ustring& md5);
};
#define cacheMgr CacheManager::getInstance()
#endif

109
rtgui/cacorrection.cc Normal file
View File

@@ -0,0 +1,109 @@
/*
* 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 "cacorrection.h"
#include <iomanip>
#include "rtimage.h"
using namespace rtengine;
using namespace rtengine::procparams;
CACorrection::CACorrection () : FoldableToolPanel(this, "cacorrection", M("TP_CACORRECTION_LABEL")) {
Gtk::Image* icaredL = Gtk::manage (new RTImage ("ajd-ca-red1.png"));
Gtk::Image* icaredR = Gtk::manage (new RTImage ("ajd-ca-red2.png"));
Gtk::Image* icablueL = Gtk::manage (new RTImage ("ajd-ca-blue1.png"));
Gtk::Image* icablueR = Gtk::manage (new RTImage ("ajd-ca-blue2.png"));
red = Gtk::manage (new Adjuster (M("TP_CACORRECTION_RED"), -0.005, 0.005, 0.0001, 0, icaredL, icaredR));
red->setAdjusterListener (this);
blue = Gtk::manage (new Adjuster (M("TP_CACORRECTION_BLUE"), -0.005, 0.005, 0.0001, 0, icablueL, icablueR));
blue->setAdjusterListener (this);
pack_start (*red);
pack_start (*blue);
show_all();
}
void CACorrection::read (const ProcParams* pp, const ParamsEdited* pedited) {
disableListener ();
if (pedited) {
red->setEditedState (pedited->cacorrection.red ? Edited : UnEdited);
blue->setEditedState (pedited->cacorrection.blue ? Edited : UnEdited);
}
red->setValue (pp->cacorrection.red);
blue->setValue (pp->cacorrection.blue);
enableListener ();
}
void CACorrection::write (ProcParams* pp, ParamsEdited* pedited) {
pp->cacorrection.red = red->getValue ();
pp->cacorrection.blue = blue->getValue ();
if (pedited) {
pedited->cacorrection.red = red->getEditedState ();
pedited->cacorrection.blue = blue->getEditedState ();
}
}
void CACorrection::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) {
red->setDefault (defParams->cacorrection.red);
blue->setDefault (defParams->cacorrection.blue);
if (pedited) {
red->setDefaultEditedState (pedited->cacorrection.red ? Edited : UnEdited);
blue->setDefaultEditedState (pedited->cacorrection.blue ? Edited : UnEdited);
}
else {
red->setDefaultEditedState (Irrelevant);
blue->setDefaultEditedState (Irrelevant);
}
}
void CACorrection::adjusterChanged (Adjuster* a, double newval) {
if (listener)
listener->panelChanged (EvCACorr, Glib::ustring::compose ("%1=%3\n%2=%4", M("TP_CACORRECTION_RED"), M("TP_CACORRECTION_BLUE"), Glib::ustring::format (std::setw(5), std::fixed, std::setprecision(4), red->getValue()), Glib::ustring::format (std::setw(5), std::fixed, std::setprecision(4), blue->getValue())));
}
void CACorrection::setAdjusterBehavior (bool badd) {
red->setAddMode(badd);
blue->setAddMode(badd);
}
void CACorrection::trimValues (rtengine::procparams::ProcParams* pp) {
red->trimValue(pp->cacorrection.red);
blue->trimValue(pp->cacorrection.blue);
}
void CACorrection::setBatchMode (bool batchMode) {
ToolPanel::setBatchMode (batchMode);
red->showEditedCB ();
blue->showEditedCB ();
}

46
rtgui/cacorrection.h Normal file
View File

@@ -0,0 +1,46 @@
/*
* 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 _CACORRECTION_H_
#define _CACORRECTION_H_
#include <gtkmm.h>
#include "adjuster.h"
#include "toolpanel.h"
class CACorrection : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel {
protected:
Adjuster* red;
Adjuster* blue;
public:
CACorrection ();
void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL);
void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL);
void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL);
void setBatchMode (bool batchMode);
void adjusterChanged (Adjuster* a, double newval);
void setAdjusterBehavior (bool badd);
void trimValues (rtengine::procparams::ProcParams* pp);
};
#endif

183
rtgui/chmixer.cc Normal file
View File

@@ -0,0 +1,183 @@
/*
* 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 "chmixer.h"
#include "rtimage.h"
using namespace rtengine;
using namespace rtengine::procparams;
ChMixer::ChMixer (): FoldableToolPanel(this, "chmixer", M("TP_CHMIXER_LABEL")) {
imgIcon[0] = Gtk::manage (new RTImage ("Chanmixer-RR.png"));
imgIcon[1] = Gtk::manage (new RTImage ("Chanmixer-RG.png"));
imgIcon[2] = Gtk::manage (new RTImage ("Chanmixer-RB.png"));
imgIcon[3] = Gtk::manage (new RTImage ("Chanmixer-GR.png"));
imgIcon[4] = Gtk::manage (new RTImage ("Chanmixer-GG.png"));
imgIcon[5] = Gtk::manage (new RTImage ("Chanmixer-GB.png"));
imgIcon[6] = Gtk::manage (new RTImage ("Chanmixer-BR.png"));
imgIcon[7] = Gtk::manage (new RTImage ("Chanmixer-BG.png"));
imgIcon[8] = Gtk::manage (new RTImage ("Chanmixer-BB.png"));
Gtk::Label* rlabel = Gtk::manage (new Gtk::Label ());
rlabel->set_markup (Glib::ustring("\t<span foreground=\"#b00000\"><b>") + M("TP_CHMIXER_RED") + Glib::ustring(":</b></span>"));
rlabel->set_alignment(Gtk::ALIGN_LEFT);
red[0] = Gtk::manage (new Adjuster ("", -200, 200, 1, 100, imgIcon[0]));
red[1] = Gtk::manage (new Adjuster ("", -200, 200, 1, 0, imgIcon[1]));
red[2] = Gtk::manage (new Adjuster ("", -200, 200, 1, 0, imgIcon[2]));
Gtk::HSeparator* rsep = Gtk::manage (new Gtk::HSeparator ());
pack_start (*rlabel);
for (int i=0; i<3; i++)
pack_start (*red[i]);
pack_start (*rsep, Gtk::PACK_EXPAND_WIDGET, 4);
Gtk::Label* glabel = Gtk::manage (new Gtk::Label ());
glabel->set_markup (Glib::ustring("\t<span foreground=\"#0b8c21\"><b>") + M("TP_CHMIXER_GREEN") + Glib::ustring(":</b></span>"));
glabel->set_alignment(Gtk::ALIGN_LEFT);
green[0] = Gtk::manage (new Adjuster ("", -200, 200, 1, 0, imgIcon[3]));
green[1] = Gtk::manage (new Adjuster ("", -200, 200, 1, 100, imgIcon[4]));
green[2] = Gtk::manage (new Adjuster ("", -200, 200, 1, 0, imgIcon[5]));
Gtk::HSeparator* gsep = Gtk::manage (new Gtk::HSeparator ());
pack_start (*glabel);
for (int i=0; i<3; i++)
pack_start (*green[i]);
pack_start (*gsep, Gtk::PACK_EXPAND_WIDGET, 4);
Gtk::Label* blabel = Gtk::manage (new Gtk::Label ());
blabel->set_markup (Glib::ustring("\t<span foreground=\"#1377d7\"><b>") + M("TP_CHMIXER_BLUE") + Glib::ustring(":</b></span>"));
blabel->set_alignment(Gtk::ALIGN_LEFT);
blue[0] = Gtk::manage (new Adjuster ("", -200, 200, 1, 0, imgIcon[6]));
blue[1] = Gtk::manage (new Adjuster ("", -200, 200, 1, 0, imgIcon[7]));
blue[2] = Gtk::manage (new Adjuster ("", -200, 200, 1, 100, imgIcon[8]));
for (int i=0; i<3; i++) {
red[i]->setAdjusterListener (this);
green[i]->setAdjusterListener (this);
blue[i]->setAdjusterListener (this);
}
pack_start (*blabel);
for (int i=0; i<3; i++)
pack_start (*blue[i]);
show_all();
}
void ChMixer::read (const ProcParams* pp, const ParamsEdited* pedited) {
disableListener ();
if (pedited)
for (int i=0; i<3; i++) {
red[i]->setEditedState (pedited->chmixer.red[i] ? Edited : UnEdited);
green[i]->setEditedState (pedited->chmixer.green[i] ? Edited : UnEdited);
blue[i]->setEditedState (pedited->chmixer.blue[i] ? Edited : UnEdited);
}
for (int i=0; i<3; i++) {
red[i]->setValue (pp->chmixer.red[i]);
green[i]->setValue (pp->chmixer.green[i]);
blue[i]->setValue (pp->chmixer.blue[i]);
}
enableListener ();
}
void ChMixer::write (ProcParams* pp, ParamsEdited* pedited) {
for (int i=0; i<3; i++) {
pp->chmixer.red[i] = (int) red[i]->getValue ();
pp->chmixer.green[i] = (int) green[i]->getValue ();
pp->chmixer.blue[i] = (int) blue[i]->getValue ();
}
if (pedited)
for (int i=0; i<3; i++) {
pedited->chmixer.red[i] = red[i]->getEditedState ();
pedited->chmixer.green[i] = green[i]->getEditedState ();
pedited->chmixer.blue[i] = blue[i]->getEditedState ();
}
}
void ChMixer::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) {
for (int i=0; i<3; i++) {
red[i]->setDefault (defParams->chmixer.red[i]);
green[i]->setDefault (defParams->chmixer.green[i]);
blue[i]->setDefault (defParams->chmixer.blue[i]);
}
if (pedited)
for (int i=0; i<3; i++) {
red[i]->setDefaultEditedState (pedited->chmixer.red[i] ? Edited : UnEdited);
green[i]->setDefaultEditedState (pedited->chmixer.green[i] ? Edited : UnEdited);
blue[i]->setDefaultEditedState (pedited->chmixer.blue[i] ? Edited : UnEdited);
}
else
for (int i=0; i<3; i++) {
red[i]->setDefaultEditedState (Irrelevant);
green[i]->setDefaultEditedState (Irrelevant);
blue[i]->setDefaultEditedState (Irrelevant);
}
}
void ChMixer::adjusterChanged (Adjuster* a, double newval) {
if (listener) {
Glib::ustring descr = Glib::ustring::compose ("R=%1,%2,%3\nG=%4,%5,%6\nB=%7,%8,%9",
(int)red[0]->getValue(), (int)red[1]->getValue(), (int)red[2]->getValue(),
(int)green[0]->getValue(), (int)green[1]->getValue(), (int)green[2]->getValue(),
(int)blue[0]->getValue(), (int)blue[1]->getValue(), (int)blue[2]->getValue());
listener->panelChanged (EvChMixer, descr);
}
}
void ChMixer::setBatchMode (bool batchMode) {
ToolPanel::setBatchMode (batchMode);
for (int i=0; i<3; i++) {
red[i]->showEditedCB ();
green[i]->showEditedCB ();
blue[i]->showEditedCB ();
}
}
void ChMixer::setAdjusterBehavior (bool rgbadd) {
for (int i=0; i<3; i++) {
red[i]->setAddMode(rgbadd);
green[i]->setAddMode(rgbadd);
blue[i]->setAddMode(rgbadd);
}
}
void ChMixer::trimValues (rtengine::procparams::ProcParams* pp) {
for (int i=0; i<3; i++) {
red[i]->trimValue(pp->chmixer.red[i]);
green[i]->trimValue(pp->chmixer.green[i]);
blue[i]->trimValue(pp->chmixer.blue[i]);
}
}

48
rtgui/chmixer.h Normal file
View File

@@ -0,0 +1,48 @@
/*
* 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 _CHMIXER_H_
#define _CHMIXER_H_
#include <gtkmm.h>
#include "adjuster.h"
#include "toolpanel.h"
class ChMixer : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel {
protected:
Adjuster *red[3];
Adjuster *green[3];
Adjuster *blue[3];
Gtk::Image *imgIcon[9];
public:
ChMixer ();
void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL);
void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL);
void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL);
void setBatchMode (bool batchMode);
void adjusterChanged (Adjuster* a, double newval);
void setAdjusterBehavior (bool rgbadd);
void trimValues (rtengine::procparams::ProcParams* pp);
};
#endif

69
rtgui/clipboard.cc Normal file
View File

@@ -0,0 +1,69 @@
/*
* 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 "clipboard.h"
Clipboard clipboard;
Clipboard::Clipboard () : partProfile (false) {}
Clipboard::~Clipboard () {
partProfile.deleteInstance();
}
/*
* set both the "pparams" and "pedited" field of the PartialProfile; each one can be NULL
*/
void Clipboard::setPartialProfile (const rtengine::procparams::PartialProfile& pprofile) {
if (pprofile.pparams) {
if (!partProfile.pparams) partProfile.pparams = new rtengine::procparams::ProcParams();
*partProfile.pparams = *pprofile.pparams;
}
else {
if (partProfile.pparams) {
delete partProfile.pparams;
partProfile.pparams = NULL;
}
}
if (pprofile.pedited) {
if (!partProfile.pedited) partProfile.pedited = new ParamsEdited();
*partProfile.pedited = *pprofile.pedited;
}
else {
if (partProfile.pedited) {
delete partProfile.pedited;
partProfile.pedited = NULL;
}
}
}
/*
* this method copy the procparams to "pparams" and delete "pedited"
*/
void Clipboard::setProcParams (const rtengine::procparams::ProcParams& pparams) {
// copy procparams
if (!partProfile.pparams) partProfile.pparams = new rtengine::procparams::ProcParams();
*partProfile.pparams = pparams;
// delete pedited
if (partProfile.pedited) {
delete partProfile.pedited;
partProfile.pedited = NULL;
}
}

68
rtgui/clipboard.h Normal file
View File

@@ -0,0 +1,68 @@
/*
* 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 _CLIPBOARD_
#define _CLIPBOARD_
#include <vector>
#include "../rtengine/rtengine.h"
#include "../rtengine/procparams.h"
#include "paramsedited.h"
#include "myflatcurve.h"
#include "mydiagonalcurve.h"
class Clipboard {
bool _hasIPTC;
rtengine::procparams::IPTCPairs iptc;
rtengine::procparams::PartialProfile partProfile;
DiagonalCurveType hasDiagonalCurveDataType;
FlatCurveType hasFlatCurveDataType;
std::vector<double> diagonalCurve;
std::vector<double> flatCurve;
public:
void setIPTC (const rtengine::procparams::IPTCPairs& iptcc) { iptc = iptcc; _hasIPTC = true;}
const rtengine::procparams::IPTCPairs& getIPTC () { return iptc; }
bool hasIPTC () { return _hasIPTC; }
void setPartialProfile (const rtengine::procparams::PartialProfile& pprofile);
const rtengine::procparams::PartialProfile& getPartialProfile () { return partProfile; };
void setProcParams (const rtengine::procparams::ProcParams& pparams);
const rtengine::procparams::ProcParams& getProcParams () { return *partProfile.pparams; }
const ParamsEdited& getParamsEdited () { return *partProfile.pedited; }
bool hasProcParams () { return partProfile.pparams; }
bool hasPEdited () { return partProfile.pedited; }
void setDiagonalCurveData (std::vector<double>& p, DiagonalCurveType type ) { diagonalCurve = p; hasDiagonalCurveDataType = type; return; }
const std::vector<double> & getDiagonalCurveData () { return diagonalCurve; }
DiagonalCurveType hasDiagonalCurveData () { return hasDiagonalCurveDataType; }
void setFlatCurveData (std::vector<double>& p, FlatCurveType type ) { flatCurve = p; hasFlatCurveDataType = type; return; }
const std::vector<double> & getFlatCurveData () { return flatCurve; }
FlatCurveType hasFlatCurveData () { return hasFlatCurveDataType; }
Clipboard ();
~Clipboard ();
};
extern Clipboard clipboard;
#endif

154
rtgui/coarsepanel.cc Normal file
View File

@@ -0,0 +1,154 @@
/*
* 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 "coarsepanel.h"
#include "rtimage.h"
using namespace rtengine;
using namespace rtengine::procparams;
CoarsePanel::CoarsePanel () : ToolPanel () {
degree = 0;
degreechanged = true;
Gtk::Image* rotateli = Gtk::manage (new RTImage ("stock-rotate-270.png"));
rotate_left = Gtk::manage (new Gtk::Button ());
rotate_left->add (*rotateli);
rotate_left->set_relief(Gtk::RELIEF_NONE);
pack_start (*rotate_left);
Gtk::Image* rotateri = Gtk::manage (new RTImage ("stock-rotate-90.png"));
rotate_right = Gtk::manage (new Gtk::Button ());
rotate_right->add (*rotateri);
rotate_right->set_relief(Gtk::RELIEF_NONE);
pack_start (*rotate_right);
Gtk::Image* fliphi = Gtk::manage (new RTImage ("stock-flip-horizontal.png"));
hflip = Gtk::manage (new Gtk::ToggleButton ());
hflip->add (*fliphi);
hflip->set_relief(Gtk::RELIEF_NONE);
pack_start (*hflip);
Gtk::Image* flipvi = Gtk::manage (new RTImage ("stock-flip-vertical.png"));
vflip = Gtk::manage (new Gtk::ToggleButton ());
vflip->add (*flipvi);
vflip->set_relief(Gtk::RELIEF_NONE);
pack_start (*vflip);
rotate_left->set_tooltip_markup (M("TP_COARSETRAF_TOOLTIP_ROTLEFT"));
rotate_right->set_tooltip_markup (M("TP_COARSETRAF_TOOLTIP_ROTRIGHT"));
vflip->set_tooltip_text (M("TP_COARSETRAF_TOOLTIP_VFLIP"));
hflip->set_tooltip_text (M("TP_COARSETRAF_TOOLTIP_HFLIP"));
rotate_left->signal_pressed().connect( sigc::mem_fun(*this, &CoarsePanel::rotateLeft) );
rotate_right->signal_pressed().connect( sigc::mem_fun(*this, &CoarsePanel::rotateRight) );
hflip->signal_toggled().connect( sigc::mem_fun(*this, &CoarsePanel::flipHorizontal) );
vflip->signal_toggled().connect( sigc::mem_fun(*this, &CoarsePanel::flipVertical) );
show_all_children ();
}
void CoarsePanel::read (const ProcParams* pp, const ParamsEdited* pedited) {
disableListener ();
degree = pp->coarse.rotate;
if (pedited) {
hflip->set_active (pedited->coarse.hflip ? pp->coarse.hflip : false);
vflip->set_active (pedited->coarse.vflip ? pp->coarse.vflip : false);
degreechanged = false;
oldhflip = pp->coarse.hflip;
oldvflip = pp->coarse.vflip;
}
else {
hflip->set_active (pp->coarse.hflip);
vflip->set_active (pp->coarse.vflip);
}
enableListener ();
}
void CoarsePanel::write (ProcParams* pp, ParamsEdited* pedited) {
if (pedited) {
pedited->coarse.rotate = degreechanged;
pedited->coarse.hflip = oldhflip != hflip->get_active ();
pedited->coarse.vflip = oldvflip != vflip->get_active ();
}
pp->coarse.rotate = degree;
pp->coarse.hflip = hflip->get_active ();
pp->coarse.vflip = vflip->get_active ();
}
void CoarsePanel::initBatchBehavior () {
disableListener ();
degree = 0;
hflip->set_active (false);
vflip->set_active (false);
enableListener ();
}
void CoarsePanel::rotateLeft () {
//Rotate one way or the opposite depending if the image is already flipped or not
if ( (vflip->get_active()) == (hflip->get_active ()) )
degree = (degree + 270) % 360;
else
degree = (degree + 90) % 360;
degreechanged = true;
if (listener)
listener->panelChanged (EvCTRotate, Glib::ustring::format (degree));
}
void CoarsePanel::rotateRight () {
//Rotate one way or the opposite depending if the image is already flipped or not
if ( (vflip->get_active()) == (hflip->get_active ()) )
degree = (degree + 90) % 360;
else
degree = (degree + 270) % 360;
degreechanged = true;
if (listener)
listener->panelChanged (EvCTRotate, Glib::ustring::format (degree));
}
void CoarsePanel::flipHorizontal () {
if (listener) {
if (hflip->get_active ())
listener->panelChanged (EvCTHFlip, M("GENERAL_ENABLED"));
else
listener->panelChanged (EvCTHFlip, M("GENERAL_DISABLED"));
}
}
void CoarsePanel::flipVertical () {
if (listener) {
if (vflip->get_active ())
listener->panelChanged (EvCTVFlip, M("GENERAL_ENABLED"));
else
listener->panelChanged (EvCTVFlip, M("GENERAL_DISABLED"));
}
}

49
rtgui/coarsepanel.h Normal file
View File

@@ -0,0 +1,49 @@
/*
* 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 __COARSEPANEL__
#define __COARSEPANEL__
#include <gtkmm.h>
#include "toolpanel.h"
class CoarsePanel : public Gtk::HBox, public ToolPanel {
protected:
Gtk::Button* rotate_left;
Gtk::Button* rotate_right;
Gtk::ToggleButton* hflip;
Gtk::ToggleButton* vflip;
int degree;
bool oldhflip, oldvflip, degreechanged;
public:
CoarsePanel ();
void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL);
void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL);
void initBatchBehavior ();
void rotateLeft ();
void rotateRight ();
void flipHorizontal ();
void flipVertical ();
};
#endif

1197
rtgui/colorappearance.cc Normal file

File diff suppressed because it is too large Load Diff

137
rtgui/colorappearance.h Normal file
View File

@@ -0,0 +1,137 @@
/*
* 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 _COLORAPPEARANCE_H_
#define _COLORAPPEARANCE_H_
#include <gtkmm.h>
#include "adjuster.h"
#include "toolpanel.h"
#include "curveeditor.h"
#include "curveeditorgroup.h"
#include "mycurve.h"
#include "guiutils.h"
#include "colorprovider.h"
class ColorAppearance : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel, public rtengine::AutoCamListener, public CurveListener, public ColorProvider {
protected:
Glib::RefPtr<Gtk::Tooltip> bgTTips;
Glib::RefPtr<Gtk::Tooltip> srTTips;
Glib::RefPtr<Gdk::Pixbuf> bgPixbuf;
Glib::RefPtr<Gdk::Pixbuf> srPixbuf;
Adjuster* degree;
Adjuster* adapscen;
Adjuster* adaplum;
Adjuster* badpixsl;
Adjuster* jlight;
Adjuster* qbright;
Adjuster* chroma;
Adjuster* schroma;
Adjuster* mchroma;
Adjuster* rstprotection;
Adjuster* contrast;
Adjuster* qcontrast;
Adjuster* colorh;
MyComboBoxText* toneCurveMode;
MyComboBoxText* toneCurveMode2;
MyComboBoxText* toneCurveMode3;
//Adjuster* edge;
Gtk::CheckButton* surrsource;
Gtk::CheckButton* gamut;
// Gtk::CheckButton* badpix;
Gtk::CheckButton* datacie;
Gtk::CheckButton* tonecie;
// Gtk::CheckButton* sharpcie;
MyComboBoxText* surround;
sigc::connection surroundconn;
MyComboBoxText* wbmodel;
sigc::connection wbmodelconn;
MyComboBoxText* algo;
sigc::connection algoconn;
sigc::connection surrconn;
sigc::connection gamutconn, datacieconn, tonecieconn /*,badpixconn , sharpcieconn*/;
sigc::connection tcmodeconn, tcmode2conn, tcmode3conn;
CurveEditorGroup* curveEditorG;
CurveEditorGroup* curveEditorG2;
CurveEditorGroup* curveEditorG3;
DiagonalCurveEditor* shape;
DiagonalCurveEditor* shape2;
DiagonalCurveEditor* shape3;
double nextCcam, nextCadap;
bool lastAutoDegree;
bool lastAutoAdapscen;
bool lastsurr;
bool lastgamut;
// bool lastbadpix;
bool lastdatacie;
bool lasttonecie;
// bool lastsharpcie;
bool bgTTipQuery(int x, int y, bool keyboard_tooltip, const Glib::RefPtr<Gtk::Tooltip>& tooltip);
bool srTTipQuery(int x, int y, bool keyboard_tooltip, const Glib::RefPtr<Gtk::Tooltip>& tooltip);
public:
ColorAppearance ();
~ColorAppearance ();
void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL);
void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL);
void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL);
void setBatchMode (bool batchMode);
void adjusterChanged (Adjuster* a, double newval);
void adjusterAutoToggled (Adjuster* a, bool newval);
// void adjusterAdapToggled (Adjuster* a, bool newval);
void enabledChanged ();
void surroundChanged ();
void wbmodelChanged ();
void algoChanged ();
void surrsource_toggled ();
void gamut_toggled ();
// void badpix_toggled ();
void datacie_toggled ();
void tonecie_toggled ();
// void sharpcie_toggled ();
void autoCamChanged (double ccam);
bool autoCamComputed_ ();
void adapCamChanged (double cadap);
bool adapCamComputed_ ();
void curveChanged (CurveEditor* ce);
void curveMode1Changed ();
bool curveMode1Changed_ ();
void curveMode2Changed ();
bool curveMode2Changed_ ();
void curveMode3Changed ();
bool curveMode3Changed_ ();
void expandCurve (bool isExpanded);
bool isCurveExpanded ();
void autoOpenCurve ();
void setAdjusterBehavior (bool degreeadd, bool adapscenadd, bool adaplumadd, bool badpixsladd, bool jlightadd, bool chromaadd, bool contrastadd, bool rstprotectionadd, bool qbrightadd, bool qcontrastadd, bool schromaadd, bool mchromaadd, bool colorhadd);
void trimValues (rtengine::procparams::ProcParams* pp);
void updateCurveBackgroundHistogram (LUTu & histToneCurve, LUTu & histLCurve, LUTu & histCCurve,/* LUTu & histCLurve, LUTu & histLLCurve,*/ LUTu & histLCAM, LUTu & histCCAM, LUTu & histRed, LUTu & histGreen, LUTu & histBlue, LUTu & histLuma);
virtual void colorForValue (double valX, double valY, enum ColorCaller::ElemType elemType, int callerId, ColorCaller *caller);
};
#endif

177
rtgui/coloredbar.cc Normal file
View File

@@ -0,0 +1,177 @@
/*
* 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 "coloredbar.h"
ColoredBar::ColoredBar (eRTOrientation orient) {
orientation = orient;
dirty = true;
this->x = this->y = this->w = this->h = 0;
}
/*
* Redraw the bar to a Cairo::ImageSurface
*/
void ColoredBar::expose(Cairo::RefPtr<Cairo::ImageSurface> destSurface) {
// look out if the Surface has to be redrawn
if (!surfaceCreated() || !destSurface)
return;
draw();
copySurface(destSurface);
}
/*
* Redraw the bar to a Gdk::Window
*/
void ColoredBar::expose(Glib::RefPtr<Gdk::Window> destWindow) {
// look out if the Surface has to be redrawn
if (!surfaceCreated() || !destWindow)
return;
draw();
copySurface(destWindow);
}
/*
* Redraw the bar to a Gdk::Window
*/
void ColoredBar::expose(BackBuffer *backBuffer) {
// look out if the Surface has to be redrawn
if (!surfaceCreated() || !backBuffer)
return;
draw();
copySurface(backBuffer);
}
void ColoredBar::draw() {
if (isDirty()) {
Cairo::RefPtr<Cairo::Context> cr = getContext();
// the bar has to be drawn to the Surface first
if (!bgGradient.empty()) {
// a gradient has been set, we use it
cr->set_line_width(0.);
// gradient background
Cairo::RefPtr< Cairo::LinearGradient > bggradient;
switch (orientation) {
case (RTO_Left2Right):
bggradient = Cairo::LinearGradient::create (0., 0., double(w), 0.);
break;
case (RTO_Right2Left):
bggradient = Cairo::LinearGradient::create (double(w), 0., 0., 0.);
break;
case (RTO_Bottom2Top):
bggradient = Cairo::LinearGradient::create (0., double(h), 0., 0.);
break;
case (RTO_Top2Bottom):
default:
bggradient = Cairo::LinearGradient::create (0., 0., 0., double(h));
break;
}
for (std::vector<GradientMilestone>::iterator i=bgGradient.begin(); i!=bgGradient.end(); i++) {
bggradient->add_color_stop_rgb (i->position, i->r, i->g, i->b);
}
cr->set_source (bggradient);
cr->rectangle(0, 0, w, h);
cr->fill();
}
else {
// ask the ColorProvider to provide colors :) for each pixels
if (colorProvider) {
cr->set_antialias(Cairo::ANTIALIAS_NONE);
cr->set_line_width(1.);
switch (orientation) {
case (RTO_Left2Right):
for (int x=0; x<w; x++) {
for (int y=0; y<h; y++) {
double x_ = double( x);
double y_ = double((h-1)-y);
double x01 = x_ /double(w-1);
double y01 = double(y)/double(h-1);
colorProvider->colorForValue (x01, y01, CCET_BACKGROUND, colorCallerId, this);
cr->set_source_rgb(ccRed, ccGreen, ccBlue);
cr->rectangle(x_, y_, 1., 1.);
cr->fill();
}
}
break;
case (RTO_Right2Left):
for (int x=0; x<w; x++) {
for (int y=0; y<h; y++) {
double x_ = double((w-1)-x);
double y_ = double((h-1)-y);
double x01 = double(x)/double(w-1);
double y01 = double(y)/double(h-1);
colorProvider->colorForValue (x01, y01, CCET_BACKGROUND, colorCallerId, this);
cr->set_source_rgb(ccRed, ccGreen, ccBlue);
cr->rectangle(x_, y_, 1., 1.);
cr->fill();
}
}
break;
case (RTO_Bottom2Top):
for (int x=0; x<w; x++) {
for (int y=0; y<h; y++) {
double x_ = double((w-1)-x);
double y_ = double((h-1)-y);
double x01 = double(x)/double(w-1);
double y01 = double(y)/double(h-1);
colorProvider->colorForValue (y01, x01, CCET_BACKGROUND, colorCallerId, this);
cr->set_source_rgb(ccRed, ccGreen, ccBlue);
cr->rectangle(x_, y_, 1., 1.);
cr->fill();
}
}
break;
case (RTO_Top2Bottom):
default:
for (int x=0; x<w; x++) {
for (int y=0; y<h; y++) {
double x_ = double( x);
double y_ = double( y);
double x01 = x_/double(w-1);
double y01 = y_/double(h-1);
colorProvider->colorForValue (y01, x01, CCET_BACKGROUND, colorCallerId, this);
cr->set_source_rgb(ccRed, ccGreen, ccBlue);
cr->rectangle(x_, y_, 1., 1.);
cr->fill();
}
}
break;
}
}
}
// has it been updated or not, we assume that the Surface has been correctly set (we don't handle allocation error)
setDirty(false);
}
}
void ColoredBar::setBgGradient (const std::vector<GradientMilestone> &milestones) {
bgGradient = milestones;
setDirty(true);
}
void ColoredBar::clearBgGradient () {
bgGradient.clear();
setDirty(true);
}
bool ColoredBar::canGetColors() {
return colorProvider!=NULL || bgGradient.size()>0;
}

54
rtgui/coloredbar.h Normal file
View File

@@ -0,0 +1,54 @@
/*
* 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 _COLOREDBAR_
#define _COLOREDBAR_
#include "colorprovider.h"
#include "guiutils.h"
/*
* Parent class for all colored bar type; a ColorProvider has to be set
* thanks to "setColorProvider" to be able to display colors inside the bar
*/
class ColoredBar : public BackBuffer, public ColorCaller {
private:
void draw();
protected:
eRTOrientation orientation;
std::vector<GradientMilestone> bgGradient;
public:
ColoredBar (eRTOrientation orient);
void expose(Glib::RefPtr<Gdk::Window> destWindow);
void expose(Cairo::RefPtr<Cairo::ImageSurface> destSurface);
void expose(BackBuffer *backBuffer);
bool canGetColors();
// Method for convenience; if no Gradient provided, the ColoredBar will ask colors on a per pixel basis
void setBgGradient (const std::vector<GradientMilestone> &milestones);
// by clearing the gradient, the ColorProvider will have to provide colors on a per pixel basis if a ColorProvider
// has been set, through ColorProvider::colorForValue on next ColoredBar::expose
void clearBgGradient ();
};
#endif

64
rtgui/colorprovider.h Normal file
View File

@@ -0,0 +1,64 @@
/*
* 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 _COLORPROVIDER_
#define _COLORPROVIDER_
#include <gtkmm.h>
class ColorProvider;
/*
* The ColorCaller is the class that will query the ColorProvider
*/
class ColorCaller {
protected:
// a class can handle several ColorCaller;
// colorCallerId will let the provider identify the caller
int colorCallerId;
ColorProvider* colorProvider;
public:
enum ElemType {
CCET_POINT,
CCET_VERTICAL_BAR,
CCET_HORIZONTAL_BAR,
CCET_BACKGROUND
};
double ccRed;
double ccGreen;
double ccBlue;
ColorCaller() : colorCallerId(-1), colorProvider(NULL), ccRed(0.), ccGreen(0.), ccBlue(0.) {}
void setColorProvider (ColorProvider* p, int id) { colorProvider = p; colorCallerId = id; }
};
/*
* Use it to let your widget feed a colored bar or graph lines with the wanted colors
* If you doesn't need to dynamically feed a widget with colors (e.g. curve's graph),
* you don't need to declare the instanciator class as BEING a ColorProvider, you'll
* still be able to set gradients for e.g. ColoredBar(s)
*/
class ColorProvider {
public:
virtual ~ColorProvider() {};
virtual void colorForValue (double valX, double valY, enum ColorCaller::ElemType elemType, int callerId, ColorCaller* caller) {};
};
#endif

1090
rtgui/colortoning.cc Normal file

File diff suppressed because it is too large Load Diff

107
rtgui/colortoning.h Normal file
View File

@@ -0,0 +1,107 @@
/*
* This file is part of RawTherapee.
*/
#ifndef _COLORTONING_H_
#define _COLORTONING_H_
#include <gtkmm.h>
#include "adjuster.h"
#include "toolpanel.h"
#include "guiutils.h"
#include "curveeditor.h"
#include "curveeditorgroup.h"
#include "thresholdadjuster.h"
#include "colorprovider.h"
class ColorToning : public ToolParamBlock, public FoldableToolPanel, public rtengine::AutoColorTonListener,public CurveListener, public ColorProvider,
public ThresholdAdjusterListener, public AdjusterListener {
protected:
//Gtk::HSeparator* splitSep;
Gtk::HSeparator* satLimiterSep;
Gtk::HSeparator* colorSep;
CurveEditorGroup* colorCurveEditorG;
CurveEditorGroup* opacityCurveEditorG;
CurveEditorGroup* clCurveEditorG;
CurveEditorGroup* cl2CurveEditorG;
FlatCurveEditor* opacityShape;
FlatCurveEditor* colorShape;
DiagonalCurveEditor* clshape;
DiagonalCurveEditor* cl2shape;
Gtk::HBox* ctbox;
Gtk::Frame *p1Frame;
Gtk::VBox* chanMixerBox;
MyComboBoxText* method;
sigc::connection methodconn;
MyComboBoxText* twocolor;
Adjuster* redlow;
Adjuster* greenlow;
Adjuster* bluelow;
Adjuster* redmed;
Adjuster* greenmed;
Adjuster* bluemed;
Adjuster* redhigh;
Adjuster* greenhigh;
Adjuster* bluehigh;
Adjuster* balance;
Gtk::CheckButton* autosat;
ThresholdAdjuster* shadowsColSat;
ThresholdAdjuster* hlColSat;
Adjuster* satProtectionThreshold;
Adjuster* saturatedOpacity;
Adjuster* strength;
Gtk::Image* itot;
Gtk::Image* iby;
Gtk::Image* irg;
Gtk::Button* neutral;
//Gtk::Button* neutralCurves;
Gtk::HBox* neutrHBox;
Gtk::HBox* chromaHbox;
Gtk::Label* colLabel;
Gtk::Label* interLabel;
Gtk::Label* chroLabel;
int nextbw;
int nextsatth;
int nextsatpr;
Glib::ustring nextbalcolor;
Glib::ustring balcolor;
bool lasttwocolor;
sigc::connection neutralconn, twocconn; //, neutralcurvesconn;
bool lastautosat;
sigc::connection autosatConn;
Gtk::CheckButton* lumamode;
bool lastLumamode;
sigc::connection lumamodeConn;
public:
ColorToning ();
~ColorToning();
void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL);
void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL);
void setBatchMode (bool batchMode);
void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL);
void trimValues (rtengine::procparams::ProcParams* pp);
void adjusterChanged (Adjuster* a, double newval);
void adjusterChanged (ThresholdAdjuster* a, double newBottom, double newTop);
void setAdjusterBehavior (bool splitAdd, bool satThresholdAdd, bool satOpacityAdd, bool strprotectAdd, bool balanceAdd);
void neutral_pressed ();
//void neutralCurves_pressed ();
void autoColorTonChanged (int bwct, int satthres, int satprot);
bool CTComp_ ();
void enabledChanged ();
void curveChanged (CurveEditor* ce);
void autosatChanged ();
void autoOpenCurve ();
void methodChanged ();
void twocolorChanged (bool changedbymethod);
void twoColorChangedByGui ();
void lumamodeChanged ();
void colorForValue (double valX, double valY, enum ColorCaller::ElemType elemType, int callerId, ColorCaller* caller);
};
#endif

29
rtgui/config.h.in Normal file
View File

@@ -0,0 +1,29 @@
/*
* This file is part of RawTherapee.
*
* Copyright (c) 2010 Lukas Jirkovsky <l.jirkovsky@gmail.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 __CONFIG_H__
#define __CONFIG_H__
#cmakedefine BUILD_BUNDLE
#define DATA_SEARCH_PATH "${DATADIR}"
#define DOC_SEARCH_PATH "${DOCDIR}"
#define CREDITS_SEARCH_PATH "${CREDITSDIR}"
#define LICENCE_SEARCH_PATH "${LICENCEDIR}"
#endif

163
rtgui/coord.h Normal file
View File

@@ -0,0 +1,163 @@
/*
* 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 _COORD_H_
#define _COORD_H_
class PolarCoord;
// Do not confuse with rtengine::Coord2D, Coord is for the GUI
class Coord {
public:
int x;
int y;
Coord() : x(-1), y(-1) {}
Coord(int x, int y) : x(x), y(y) {}
void set (int x, int y) {
this->x = x;
this->y = y;
}
void setFromPolar(PolarCoord polar);
/// @brief Clip the coord to stay in the width x height bounds
/// @return true if the x or y coordinate has changed
bool clip(int width, int height) {
int trimmedX = rtengine::LIM<int>(x, 0, width);
int trimmedY = rtengine::LIM<int>(y, 0, height);
bool retval = trimmedX!=x || trimmedY!=y;
x = trimmedX;
y = trimmedY;
return retval;
}
void operator+=(const Coord & rhs) {
x += rhs.x;
y += rhs.y;
}
void operator-=(const Coord & rhs) {
x -= rhs.x;
y -= rhs.y;
}
void operator*=(double scale) {
x *= scale;
y *= scale;
}
Coord operator+(Coord & rhs) {
Coord result(x+rhs.x, y+rhs.y);
return result;
}
Coord operator-(Coord & rhs) {
Coord result(x-rhs.x, y-rhs.y);
return result;
}
Coord operator*(double scale) {
Coord result(x*scale, y*scale);
return result;
}
};
class PolarCoord {
public:
double radius;
double angle; // degree
PolarCoord() : radius(1.), angle(0.) {}
PolarCoord(double radius, double angle) : radius(radius), angle(angle) {}
void set (double radius, double angle) {
this->radius = radius;
this->angle = angle;
}
void setFromCartesian(Coord start, Coord end) {
Coord delta(end.x-start.x, end.y-start.y);
setFromCartesian(delta);
}
void setFromCartesian(Coord delta) {
if (!delta.x && !delta.y) {
// null vector, we set to a default value
radius = 1.;
angle = 0.;
return;
}
double x_ = double(delta.x);
double y_ = double(delta.y);
radius = sqrt(x_*x_+y_*y_);
if (delta.x>0.) {
if (delta.y>=0.)
angle = atan(y_/x_)/(2*M_PI)*360.;
else if (delta.y<0.)
angle = (atan(y_/x_)+2*M_PI)/(2*M_PI)*360.;
}
else if (delta.x<0.)
angle = (atan(y_/x_)+M_PI)/(2*M_PI)*360.;
else if (delta.x==0.) {
if (delta.y>0.)
angle = 90.;
else
angle = 270.;
}
}
void operator+=(const PolarCoord & rhs) {
Coord thisCoord, rhsCoord;
thisCoord.setFromPolar(*this);
rhsCoord.setFromPolar(rhs);
thisCoord += rhsCoord;
setFromCartesian(thisCoord);
}
void operator-=(const PolarCoord & rhs) {
Coord thisCoord, rhsCoord;
thisCoord.setFromPolar(*this);
rhsCoord.setFromPolar(rhs);
thisCoord -= rhsCoord;
setFromCartesian(thisCoord);
}
void operator*=(double scale) {
radius *= scale;
}
PolarCoord operator+(PolarCoord & rhs) {
Coord thisCoord, rhsCoord;
thisCoord.setFromPolar(*this);
rhsCoord.setFromPolar(rhs);
thisCoord += rhsCoord;
PolarCoord result;
result.setFromCartesian(thisCoord);
return result;
}
PolarCoord operator-(PolarCoord & rhs) {
Coord thisCoord, rhsCoord;
thisCoord.setFromPolar(*this);
rhsCoord.setFromPolar(rhs);
thisCoord -= rhsCoord;
PolarCoord result;
result.setFromCartesian(thisCoord);
return result;
}
Coord operator*(double scale) {
Coord result(radius*scale, angle);
return result;
}
};
#endif

198
rtgui/coordinateadjuster.cc Normal file
View File

@@ -0,0 +1,198 @@
/*
* 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 "coordinateadjuster.h"
#include "multilangmgr.h"
#include <cassert>
#include "curveeditorgroup.h"
Axis::Axis()
: label(""), decimal(5), increment(0.001), pageIncrement(0.01), rangeLowerBound(0.), rangeUpperBound(1.)
{}
Axis::Axis(Glib::ustring label, unsigned int decimal, double increment, double pageIncrement, double valMin=0.0, double valMax=1.0)
: label(label), decimal(decimal), increment(increment), pageIncrement(pageIncrement), rangeLowerBound(valMin), rangeUpperBound(valMax)
{}
void Axis::setValues(Glib::ustring label, unsigned int decimal, double increment, double pageIncrement, double valMin, double valMax) {
this->label = label;
this->decimal = decimal;
this->increment = increment;
this->pageIncrement = pageIncrement;
this->rangeLowerBound = valMin;
this->rangeUpperBound = valMax;
}
CoordinateAdjuster::AxisAdjuster::AxisAdjuster(CoordinateAdjuster *parent, const Axis *axis, char index) : idx(index), parent(parent) {
label = Gtk::manage( new Gtk::Label(axis->label) );
spinButton = Gtk::manage( new Gtk::SpinButton() );
label = Gtk::manage (new Gtk::Label(axis->label));
//label->set_alignment(Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER);
spinButton = Gtk::manage (new Gtk::SpinButton());
spinButton->set_name("AxisAdjuster");
spinButton->set_digits(axis->decimal);
spinButton->set_increments(axis->increment, axis->pageIncrement);
spinButton->set_range(axis->rangeLowerBound, axis->rangeUpperBound);
spinButton->set_sensitive(false);
spinButtonConn = spinButton->signal_value_changed().connect( sigc::mem_fun(*this, &CoordinateAdjuster::AxisAdjuster::valueChanged) );
//spinButton->signal_key_press_event().connect( sigc::mem_fun(*this, &CoordinateAdjuster::AxisAdjuster::keyPressed) );
}
void CoordinateAdjuster::AxisAdjuster::updateGUI(const Axis &axis) {
label->set_text(axis.label);
spinButton->set_digits(axis.decimal);
spinButton->set_increments(axis.increment, axis.pageIncrement);
spinButton->set_range(axis.rangeLowerBound, axis.rangeUpperBound);
spinButton->set_sensitive(false);
rangeLowerBound = axis.rangeLowerBound;
rangeUpperBound = axis.rangeUpperBound;
}
void CoordinateAdjuster::AxisAdjuster::setValue(double newValue) {
float range = rangeUpperBound-rangeLowerBound;
spinButtonConn.block(true);
spinButton->set_value(newValue*range+rangeLowerBound);
spinButtonConn.block(false);
}
void CoordinateAdjuster::AxisAdjuster::valueChanged() {
float range = rangeUpperBound-rangeLowerBound;
parent->updatePos(idx, (spinButton->get_value()-rangeLowerBound)/range);
}
CoordinateAdjuster::CoordinateAdjuster(CoordinateProvider *provider, CurveEditorSubGroup *parent, const std::vector<Axis> &axis)
: status(CA_STATUS_IDLE), parent(parent), coordinateProvider(provider)
{
provider->setListener(this);
createWidgets(axis);
}
CoordinateAdjuster::CoordinateAdjuster(CoordinateProvider *provider, CurveEditorSubGroup *parent)
: status(CA_STATUS_IDLE), parent(parent), coordinateProvider(provider)
{
std::vector<Axis> defaultAxis;
Axis X(M("CURVEEDITOR_AXIS_IN"), 3, 0.1, 1., 0., 100.);
Axis Y(M("CURVEEDITOR_AXIS_OUT"), 3, 0.1, 1., 0., 100.);
defaultAxis.push_back(X);
defaultAxis.push_back(Y);
provider->setListener(this);
createWidgets(defaultAxis);
}
void CoordinateAdjuster::createWidgets(const std::vector<Axis> &axis) {
unsigned int count = axis.size();
if (!count) {
printf("CoordinateAdjuster - Error: the Axis list is empty!\n");
return;
}
assert (count <= 4);
axisAdjusters.resize(axis.size());
set_spacing(3);
AxisAdjuster *currAdjuster = NULL;
for (unsigned int i=0; i<count; ++i) {
const Axis *currAxis = &(axis.at(i));
axisAdjusters.at(i) = new AxisAdjuster(this, currAxis, i);
currAdjuster = axisAdjusters.at(i);
currAdjuster->rangeLowerBound = currAxis->rangeLowerBound;
currAdjuster->rangeUpperBound = currAxis->rangeUpperBound;
pack_start(*(currAdjuster->label), Gtk::PACK_SHRINK, 0);
pack_start(*(currAdjuster->spinButton), Gtk::PACK_SHRINK, 0);
}
}
void CoordinateAdjuster::updatePos(char index, double value) {
coordinateProvider->setPos(value, index);
}
void CoordinateAdjuster::setAxis(const std::vector<Axis> &axis) {
assert (axis.size() == axisAdjusters.size());
for (size_t i = 0; i<axisAdjusters.size(); ++i) {
axisAdjusters.at(i)->updateGUI(axis.at(i));
}
}
void CoordinateAdjuster::setPos(std::vector<double> &pos) {
if (is_visible()) {
for (size_t i=0; i<pos.size(); ++i) {
axisAdjusters.at(i)->setValue(pos.at(i));
}
}
}
void CoordinateAdjuster::startNumericalAdjustment(const std::vector<Boundaries> &newBoundaries) {
for (size_t i=0; i<axisAdjusters.size(); ++i) {
Gtk::SpinButton *currSpinButton = axisAdjusters.at(i)->spinButton;
currSpinButton->set_sensitive(true);
float range = axisAdjusters.at(i)->rangeUpperBound-axisAdjusters.at(i)->rangeLowerBound;
currSpinButton->set_range(newBoundaries.at(i).minVal*range+axisAdjusters.at(i)->rangeLowerBound, newBoundaries.at(i).maxVal*range+axisAdjusters.at(i)->rangeUpperBound);
}
axisAdjusters.at(0)->spinButton->grab_focus();
status = CA_STATUS_EDITING;
}
void CoordinateAdjuster::switchAdjustedPoint(std::vector<double> &pos, const std::vector<Boundaries> &newBoundaries) {
if (status != CA_STATUS_EDITING)
return;
for (size_t i=0; i<axisAdjusters.size(); ++i) {
AxisAdjuster *currAxis = axisAdjusters.at(i);
// disable events
currAxis->spinButtonConn.block(true);
// To avoid trimmed values, we have to...
// ...enlarge range to the maximum
currAxis->spinButton->set_range(axisAdjusters.at(i)->rangeLowerBound, axisAdjusters.at(i)->rangeUpperBound);
// ...set the new value
currAxis->setValue(pos.at(i));
// ...narrow the range to the new interval
float range = axisAdjusters.at(i)->rangeUpperBound-axisAdjusters.at(i)->rangeLowerBound;
currAxis->spinButton->set_range(newBoundaries.at(i).minVal*range+axisAdjusters.at(i)->rangeLowerBound, newBoundaries.at(i).maxVal*range+axisAdjusters.at(i)->rangeUpperBound);
// enable events
currAxis->spinButtonConn.block(false);
}
axisAdjusters.at(0)->spinButton->grab_focus();
status = CA_STATUS_EDITING;
}
void CoordinateAdjuster::showMe(CoordinateProvider *provider) {
parent->showCoordinateAdjuster(provider);
}
void CoordinateAdjuster::stopNumericalAdjustment() {
for (size_t i=0; i<axisAdjusters.size(); ++i) {
axisAdjusters.at(i)->spinButtonConn.block(true);
axisAdjusters.at(i)->spinButton->set_sensitive(false);
axisAdjusters.at(i)->spinButton->set_range(axisAdjusters.at(i)->rangeLowerBound, axisAdjusters.at(i)->rangeUpperBound);
axisAdjusters.at(i)->spinButtonConn.block(false);
}
status = CA_STATUS_IDLE;
}

157
rtgui/coordinateadjuster.h Normal file
View File

@@ -0,0 +1,157 @@
/*
* 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 _COORDINATEADJUSTER_
#define _COORDINATEADJUSTER_
#include <gtkmm.h>
class CurveEditorSubGroup;
class Axis {
public:
Glib::ustring label;
unsigned int decimal;
double increment;
double pageIncrement;
double rangeLowerBound;
double rangeUpperBound;
Axis();
Axis(Glib::ustring label, unsigned int decimal, double increment, double pageIncrement, double valMin, double valMax);
void setValues(Glib::ustring label, unsigned int decimal, double increment, double pageIncrement, double valMin, double valMax);
};
class CoordinateAdjuster;
/**
* @brief Object that will emit NewCoordinates events
*/
class CoordinateProvider {
protected:
CoordinateAdjuster *coordinateAdjuster;
public:
CoordinateProvider() : coordinateAdjuster(NULL) {}
virtual ~CoordinateProvider() {}
void setListener(CoordinateAdjuster *adjuster) { coordinateAdjuster = adjuster; }
/** @brief Update the position of the edited point ; will trigger events
*
* @param pos New position
* @param chanIdx Chanel index as given in the std::vector upon instantiation
*/
virtual void setPos(double pos, int chanIdx)=0;
virtual void stopNumericalAdjustment()=0;
};
/**
* @brief Widget that displays spin buttons to adjust coordinates
*
* You can set up to 4 axis that will be displayed on a single line, so keep the labels short!
*
* The position of the Axis in the vector will be used in the communication between the Adjuster and the Provider to identify the Axis
*/
class CoordinateAdjuster : public Gtk::HBox {
public:
//-------------------------------- AxisAdjuster -------------------
class AxisAdjuster {
private:
char idx;
public:
CoordinateAdjuster *parent;
Gtk::Label *label;
Gtk::SpinButton *spinButton;
sigc::connection spinButtonConn;
float rangeLowerBound;
float rangeUpperBound;
AxisAdjuster(CoordinateAdjuster *parent, const Axis *axis, char index);
// used to update the AxisAdjuster's parameters
void updateGUI(const Axis &axis);
// useed to update the displayed value
void setValue(double newValue);
//bool keyPressed(GdkEventKey* event);
void valueChanged();
};
//----------------------------------------------------------------
//-------------------------------- Boundaries -------------------
class Boundaries {
public:
double minVal;
double maxVal;
};
//---------------------------------------------------------------
private:
typedef enum {
CA_STATUS_IDLE,
CA_STATUS_EDITING,
CA_STATUS_END_EDITING
} Status;
std::vector<AxisAdjuster*> axisAdjusters;
Status status;
CurveEditorSubGroup *parent;
void createWidgets(const std::vector<Axis> &axis);
protected:
friend class AxisAdjuster;
CoordinateProvider *coordinateProvider;
void updatePos(char index, double value);
public:
/// Basic X/Y adjuster, in the [0-1] range
CoordinateAdjuster(CoordinateProvider *provider, CurveEditorSubGroup *parent);
/// For more complex adjuster
CoordinateAdjuster(CoordinateProvider *provider, CurveEditorSubGroup *parent, const std::vector<Axis> &axis);
virtual ~CoordinateAdjuster() {}
// Update the Axis list, e.g. on Curve change, but MUST have the same axis count
void setAxis(const std::vector<Axis> &axis);
/** @brief Update the numbers in the spin buttons ; doesn't trigger any event
*
* @param pos Vector that gives the values of each channels
*/
void setPos(std::vector<double> &pos);
/// Start the adjustment session (enable the widget)
void startNumericalAdjustment(const std::vector<Boundaries> &newBoundaries);
/// Edit another point
void switchAdjustedPoint(std::vector<double> &pos, const std::vector<Boundaries> &newBoundaries);
/// Trigger the event to show the CoordinateAdjuster
void showMe(CoordinateProvider *provider);
/// Stop the adjustment session (disable the widget, i.e. you won't be able to edit the values)
void stopNumericalAdjustment();
};
#endif

200
rtgui/createicon.cc Normal file
View File

@@ -0,0 +1,200 @@
/*
* 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 <png.h>
void png_read_data(png_structp png_ptr, png_bytep data, png_size_t length) {
png_size_t check;
/* fread() returns 0 on error, so it is OK to store this in a png_size_t
* instead of an int, which is what fread() actually returns.
*/
check = (png_size_t)fread(data, (png_size_t)1, length, (FILE *)png_ptr->io_ptr);
if (check != length)
{
png_error(png_ptr, "Read Error");
}
}
void png_write_data(png_structp png_ptr, png_bytep data, png_size_t length) {
png_uint_32 check;
check = fwrite(data, 1, length, (FILE *)(png_ptr->io_ptr));
if (check != length)
{
png_error(png_ptr, "Write Error");
}
}
void png_flush(png_structp png_ptr) {
FILE *io_ptr;
io_ptr = (FILE *)CVT_PTR((png_ptr->io_ptr));
if (io_ptr != NULL)
fflush(io_ptr);
}
unsigned char* loadPNG (char* fname, int& w, int& h) {
FILE *file = fopen (fname,"rb");
unsigned char header[8];
fread (header, 1, 8, file);
png_structp png = png_create_read_struct (PNG_LIBPNG_VER_STRING, 0, 0, 0);
png_infop info = png_create_info_struct (png);
png_infop end_info = png_create_info_struct (png);
if (setjmp (png_jmpbuf(png))) {
png_destroy_read_struct (&png, &info, &end_info);
fclose (file);
return NULL;
}
//set up png read
png_set_read_fn (png, file, png_read_data);
png_set_sig_bytes (png,8);
png_read_info(png,info);
unsigned long width,height;
int bit_depth,color_type,interlace_type,compression_type,filter_method;
png_get_IHDR(png,info,&width,&height,&bit_depth,&color_type,&interlace_type,
&compression_type, &filter_method);
//converting to 32bpp format
if (color_type==PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png);
if (color_type==PNG_COLOR_TYPE_GRAY || color_type==PNG_COLOR_TYPE_GRAY_ALPHA)
png_set_gray_to_rgb(png);
if (png_get_valid(png,info,PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png);
if (interlace_type!=PNG_INTERLACE_NONE) {
png_destroy_read_struct (&png, &info, &end_info);
fclose (file);
return NULL;
}
if (color_type & PNG_COLOR_MASK_ALPHA)
png_set_strip_alpha(png);
//setting gamma
double gamma;
if (png_get_gAMA(png,info,&gamma))
png_set_gamma(png, 2.0, gamma);
else
png_set_gamma(png,2.0, 0.45455);
int bps = 8;
//updating png info struct
png_read_update_info(png,info);
png_get_IHDR(png,info,&width,&height,&bit_depth,&color_type,&interlace_type,
&compression_type, &filter_method);
if (color_type & PNG_COLOR_MASK_ALPHA)
png_set_strip_alpha(png);
png_read_update_info(png,info);
png_get_IHDR(png,info,&width,&height,&bit_depth,&color_type,&interlace_type,
&compression_type, &filter_method);
unsigned char* data = new unsigned char[width*height*3];
int rowlen = width*3;
unsigned char *row = new unsigned char [rowlen];
for (unsigned int i=0;i<height;i++) {
png_read_row (png, (png_byte*)row, NULL);
memcpy (data+3*i*width, row, 3*width);
}
png_read_end (png, 0);
png_destroy_read_struct (&png, &info, &end_info);
delete [] row;
fclose(file);
w = width;
h = height;
return data;
}
void savePNG (char* fname, unsigned char* data1, unsigned char* data2, int w, int h) {
FILE* file = fopen(fname,"wb");
png_structp png = png_create_write_struct (PNG_LIBPNG_VER_STRING,0,0,0);
png_infop info = png_create_info_struct(png);
if (setjmp(png_jmpbuf(png))) {
png_destroy_write_struct (&png,&info);
fclose(file);
return;
}
png_set_write_fn (png, file, png_write_data, png_flush);
png_set_compression_level(png,6);
int width = w;
int height = h;
int bps = 8;
png_set_IHDR(png, info, width, height, bps, PNG_COLOR_TYPE_RGB_ALPHA,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,PNG_FILTER_TYPE_BASE);
int rowlen = width*4;
unsigned char *row = new unsigned char [rowlen];
png_write_info(png,info);
for (unsigned int i=0;i<height;i++) {
for (int j=0; j<width; j++) {
int ofs = 3*(width*i+j);
unsigned char alpha = data2[ofs] - data1[ofs];
if (i==8 && j==8)
printf ("alpha=%d pix=%d\n",(int)alpha, (int)(data1[ofs+0] / (1.0 - alpha/255.0)));
if (alpha<255) {
row[4*j+0] = data1[ofs+0] / (1.0 - alpha/255.0);
row[4*j+1] = data1[ofs+1] / (1.0 - alpha/255.0);
row[4*j+2] = data1[ofs+2] / (1.0 - alpha/255.0);
}
else {
}
row[4*j+3] = 255-alpha;
}
png_write_row (png, (png_byte*)row);
}
png_write_end(png,info);
png_destroy_write_struct(&png,&info);
delete [] row;
fclose (file);
}
int main (int argc, char* argv[]) {
int w, h;
unsigned char* data1 = loadPNG (argv[1], w, h);
unsigned char* data2 = loadPNG (argv[2], w, h);
savePNG (argv[3], data1, data2, w, h);
}

1052
rtgui/crop.cc Normal file

File diff suppressed because it is too large Load Diff

116
rtgui/crop.h Normal file
View File

@@ -0,0 +1,116 @@
/*
* 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 _CROP_H_
#define _CROP_H_
#include <gtkmm.h>
#include "cropguilistener.h"
#include "toolpanel.h"
#include "guiutils.h"
#include <vector>
class CropPanelListener {
public:
virtual void cropSelectRequested () {}
};
class CropRatio {
public:
Glib::ustring label;
double value;
};
class Crop : public ToolParamBlock, public CropGUIListener, public FoldableToolPanel, public rtengine::SizeListener {
protected:
Gtk::CheckButton* fixr;
MyComboBoxText* ratio;
MyComboBoxText* orientation;
MyComboBoxText* guide;
Gtk::Button* selectCrop;
CropPanelListener* clistener;
int opt;
MySpinButton* x;
MySpinButton* y;
MySpinButton* w;
MySpinButton* h;
MySpinButton* ppi;
Gtk::Label* sizecm;
Gtk::Label* sizein;
Gtk::VBox* ppibox;
Gtk::VBox* sizebox;
int maxw, maxh;
double nx, ny;
int nw, nh;
int lastRotationDeg;
sigc::connection xconn, yconn, wconn, hconn, fconn, rconn, oconn, gconn;
bool wDirty, hDirty, xDirty, yDirty, lastFixRatio;
void adjustCropToRatio();
std::vector<CropRatio> cropratio;
public:
Crop ();
void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL);
void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL);
void setBatchMode (bool batchMode);
void ratioChanged ();
void ratioFixedChanged (); // The toggle button
void refreshSize ();
void selectPressed ();
void setDimensions (int mw, int mh);
void enabledChanged ();
void positionChanged ();
void widthChanged ();
void heightChanged ();
bool refreshSpins (bool notify=false);
void notifyListener ();
void sizeChanged (int w, int h, int ow, int oh);
void trim (rtengine::procparams::ProcParams* pp, int ow, int oh);
void readOptions ();
void writeOptions ();
void cropMoved (int &x, int &y, int &w, int &h);
void cropWidth1Resized (int &x, int &y, int &w, int &h);
void cropWidth2Resized (int &x, int &y, int &w, int &h);
void cropHeight1Resized (int &x, int &y, int &w, int &h);
void cropHeight2Resized (int &x, int &y, int &w, int &h);
void cropTopLeftResized (int &x, int &y, int &w, int &h);
void cropTopRightResized (int &x, int &y, int &w, int &h);
void cropBottomLeftResized (int &x, int &y, int &w, int &h);
void cropBottomRightResized (int &x, int &y, int &w, int &h);
void cropInit (int &x, int &y, int &w, int &h);
void cropResized (int &x, int &y, int& x2, int& y2);
void cropManipReady ();
bool inImageArea (int x, int y);
double getRatio ();
void setCropPanelListener (CropPanelListener* cl) { clistener = cl; }
void resizeScaleChanged (double rsc);
void hFlipCrop ();
void vFlipCrop ();
void rotateCrop (int deg, bool hflip, bool vflip);
};
#endif

42
rtgui/cropguilistener.h Normal file
View File

@@ -0,0 +1,42 @@
/*
* 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 __CROPGUILISTENER__
#define __CROPGUILISTENER__
class CropGUIListener {
public:
virtual ~CropGUIListener() {}
virtual void cropMoved (int &x, int &y, int &w, int &h) =0;
virtual void cropWidth1Resized (int &x, int &y, int &w, int &h) =0;
virtual void cropWidth2Resized (int &x, int &y, int &w, int &h) =0;
virtual void cropHeight1Resized (int &x, int &y, int &w, int &h) =0;
virtual void cropHeight2Resized (int &x, int &y, int &w, int &h) =0;
virtual void cropTopLeftResized (int &x, int &y, int &w, int &h) =0;
virtual void cropTopRightResized (int &x, int &y, int &w, int &h) =0;
virtual void cropBottomLeftResized (int &x, int &y, int &w, int &h) =0;
virtual void cropBottomRightResized (int &x, int &y, int &w, int &h) =0;
virtual void cropInit (int &x, int &y, int &w, int &h) =0;
virtual void cropResized (int &x, int &y, int& x2, int& y2) =0;
virtual void cropManipReady () =0;
virtual bool inImageArea (int x, int y) =0;
virtual double getRatio () =0;
};
#endif

390
rtgui/crophandler.cc Normal file
View File

@@ -0,0 +1,390 @@
/*
* 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 "crophandler.h"
#undef THREAD_PRIORITY_NORMAL
#include <cstring>
#include "guiutils.h"
#include "cropwindow.h"
#include "../rtengine/dcrop.h"
#include "../rtengine/refreshmap.h"
using namespace rtengine;
CropHandler::CropHandler ()
: zoom(10), ww(0), wh(0), cx(0), cy(0), cw(0), ch(0),
cropX(0), cropY(0), cropW(0), cropH(0), enabled(false),
cropimg(NULL), cropimgtrue(NULL), ipc(NULL), crop(NULL), listener(NULL), isLowUpdatePriority(false) {
chi = new CropHandlerIdleHelper;
chi->destroyed = false;
chi->pending = 0;
chi->cropHandler = this;
}
CropHandler::~CropHandler () {
if (ipc)
ipc->delSizeListener (this);
setEnabled (false);
if (crop) {
//crop->destroy ();
delete crop; // will do the same than destroy, plus delete the object
crop = NULL;
}
cimg.lock ();
if (chi->pending)
chi->destroyed = true;
else
delete chi;
cimg.unlock ();
}
void CropHandler::setEditSubscriber (EditSubscriber* newSubscriber) {
(static_cast<rtengine::Crop *>(crop))->setEditSubscriber(newSubscriber);
}
void CropHandler::newImage (StagedImageProcessor* ipc_, bool isDetailWindow) {
ipc = ipc_;
cx = 0;
cy = 0;
if (!ipc)
return;
EditDataProvider *editDataProvider = NULL;
CropWindow *cropWin = listener ? static_cast<CropWindow*>(listener) : NULL;
if (cropWin)
editDataProvider = cropWin->getImageArea();
crop = ipc->createCrop (editDataProvider, isDetailWindow);
ipc->setSizeListener (this);
crop->setListener (enabled ? this : NULL);
initial = true;
}
void CropHandler::sizeChanged (int x, int y, int ow, int oh) { // the ipc notifies it to keep track size changes like rotation
compDim ();
// this should be put into an idle source!!!
/* if (listener)
listener->cropWindowChanged ();
*/
}
double CropHandler::getFitCropZoom () {
double z1 = (double) wh / cropParams.h;
double z2 = (double) ww / cropParams.w;
return z1<z2 ? z1 : z2;
}
double CropHandler::getFitZoom () {
if (ipc) {
double z1 = (double) wh / ipc->getFullHeight ();
double z2 = (double) ww / ipc->getFullWidth ();
return z1<z2 ? z1 : z2;
}
else
return 1.0;
}
void CropHandler::setZoom (int z, int centerx, int centery) {
int x = cx + cw / 2;
int y = cy + ch / 2;
if (centerx>=0)
x = centerx;
if (centery>=0)
y = centery;
// maybe demosaic etc. if we cross the border to >100%
bool needsFullRefresh = (z>=1000 && zoom<1000);
zoom = z;
if (zoom>=1000) {
cw = ww * 1000 / zoom;
ch = wh * 1000 / zoom;
}
else {
cw = ww * zoom;
ch = wh * zoom;
}
cx = x - cw / 2;
cy = y - ch / 2;
compDim ();
if (enabled) {
if (needsFullRefresh)
ipc->startProcessing(M_HIGHQUAL);
else
update ();
}
}
void CropHandler::setWSize (int w, int h) {
ww = w;
wh = h;
if (zoom>=1000) {
cw = ww * 1000 / zoom;
ch = wh * 1000 / zoom;
}
else {
cw = ww * zoom;
ch = wh * zoom;
}
compDim ();
if (enabled)
update ();
}
void CropHandler::getWSize (int& w, int &h) {
w = ww;
h = wh;
}
void CropHandler::setPosition (int x, int y, bool update_) {
cx = x;
cy = y;
compDim ();
if (enabled && update_)
update ();
}
void CropHandler::getPosition (int& x, int& y) {
x = cropX;
y = cropY;
}
int createpixbufs (void* data) {
GThreadLock lock;
CropHandlerIdleHelper* chi = static_cast<CropHandlerIdleHelper*>(data);
if (chi->destroyed) {
if (chi->pending == 1)
delete chi;
else
chi->pending--;
return 0;
}
CropHandler* ch = chi->cropHandler;
ch->cimg.lock ();
ch->cropPixbuf.clear ();
if (!ch->enabled) {
delete [] ch->cropimg;
ch->cropimg = NULL;
delete [] ch->cropimgtrue;
ch->cropimgtrue = NULL;
ch->cimg.unlock ();
return 0;
}
if (ch->cropimg) {
if (ch->cix==ch->cropX && ch->ciy==ch->cropY && ch->ciw==ch->cropW && ch->cih==ch->cropH && ch->cis==(ch->zoom>=1000?1:ch->zoom)) {
// calculate final image size
int czoom = ch->zoom<1000 ? 1000 : ch->zoom;
int imw = ch->cropimg_width * czoom / 1000;
int imh = ch->cropimg_height * czoom / 1000;
if (imw>ch->ww)
imw = ch->ww;
if (imh>ch->wh)
imh = ch->wh;
Glib::RefPtr<Gdk::Pixbuf> tmpPixbuf = Gdk::Pixbuf::create_from_data (ch->cropimg, Gdk::COLORSPACE_RGB, false, 8, ch->cropimg_width, 2*ch->cropimg_height, 3*ch->cropimg_width);
ch->cropPixbuf = Gdk::Pixbuf::create (Gdk::COLORSPACE_RGB, false, 8, imw, imh);
tmpPixbuf->scale (ch->cropPixbuf, 0, 0, imw, imh, 0, 0, czoom/1000.0, czoom/1000.0, Gdk::INTERP_NEAREST);
tmpPixbuf.clear ();
Glib::RefPtr<Gdk::Pixbuf> tmpPixbuftrue = Gdk::Pixbuf::create_from_data (ch->cropimgtrue, Gdk::COLORSPACE_RGB, false, 8, ch->cropimg_width, 2*ch->cropimg_height, 3*ch->cropimg_width);
ch->cropPixbuftrue = Gdk::Pixbuf::create (Gdk::COLORSPACE_RGB, false, 8, imw, imh);
tmpPixbuftrue->scale (ch->cropPixbuftrue, 0, 0, imw, imh, 0, 0, czoom/1000.0, czoom/1000.0, Gdk::INTERP_NEAREST);
tmpPixbuftrue.clear ();
}
delete [] ch->cropimg;
ch->cropimg = NULL;
delete [] ch->cropimgtrue;
ch->cropimgtrue = NULL;
}
ch->cimg.unlock ();
if (ch->listener) {
ch->listener->cropImageUpdated ();
if (ch->initial) {
ch->listener->initialImageArrived ();
ch->initial = false;
}
}
chi->pending--;
return 0;
}
void CropHandler::setDetailedCrop (IImage8* im, IImage8* imtrue, rtengine::procparams::ColorManagementParams cmp,
rtengine::procparams::CropParams cp, int ax, int ay, int aw, int ah, int askip) {
if (!enabled)
return;
cimg.lock ();
cropParams = cp;
colorParams = cmp;
cropPixbuf.clear ();
if (cropimg)
delete [] cropimg;
cropimg = NULL;
if (cropimgtrue)
delete [] cropimgtrue;
cropimgtrue = NULL;
if (ax==cropX && ay==cropY && aw==cropW && ah==cropH && askip==(zoom>=1000?1:zoom)) {
cropimg_width = im->getWidth ();
cropimg_height = im->getHeight ();
cropimg = new unsigned char [3*cropimg_width*cropimg_height];
cropimgtrue = new unsigned char [3*cropimg_width*cropimg_height];
memcpy (cropimg, im->getData(), 3*cropimg_width*cropimg_height);
memcpy (cropimgtrue, imtrue->getData(), 3*cropimg_width*cropimg_height);
cix = ax;
ciy = ay;
ciw = aw;
cih = ah;
cis = askip;
chi->pending++;
g_idle_add (createpixbufs, chi);
}
cimg.unlock ();
}
bool CropHandler::getWindow (int& cwx, int& cwy, int& cww, int& cwh, int& cskip) {
cwx = cropX;
cwy = cropY;
cww = cropW;
cwh = cropH;
// hack: if called before first size allocation the size will be 0
if (cww<10)
cww = 10;
if (cwh<32)
cwh = 32;
cskip = zoom>=1000 ? 1 : zoom;
return true;
}
void CropHandler::update () {
if (crop) {
// crop->setWindow (cropX, cropY, cropW, cropH, zoom>=1000 ? 1 : zoom); --> we use the "getWindow" hook instead of setting the size before
crop->setListener (this);
cropPixbuf.clear ();
// To save threads, try to mark "needUpdate" without a thread first
if (crop->tryUpdate()) {
if (isLowUpdatePriority)
Glib::Thread::create(sigc::mem_fun(*crop, &DetailedCrop::fullUpdate), 0, false, true, Glib::THREAD_PRIORITY_LOW);
else
Glib::Thread::create(sigc::mem_fun(*crop, &DetailedCrop::fullUpdate), false );
}
}
}
void CropHandler::setEnabled (bool e) {
enabled = e;
if (!enabled) {
if (crop)
crop->setListener (NULL);
cimg.lock ();
delete [] cropimg;
cropimg = NULL;
delete [] cropimgtrue;
cropimgtrue = NULL;
cropPixbuf.clear ();
cimg.unlock ();
}
else
update ();
}
bool CropHandler::getEnabled () {
return enabled;
}
void CropHandler::getSize (int& w, int& h) {
w = cropW;
h = cropH;
}
void CropHandler::getFullImageSize (int& w, int& h) {
if (ipc) {
w = ipc->getFullWidth ();
h = ipc->getFullHeight ();
} else {
w=h=0;
}
}
void CropHandler::compDim () {
cropX = cx;
cropY = cy;
cropW = cw;
cropH = ch;
cutRectToImgBounds (cropX, cropY, cropW, cropH);
}
void CropHandler::cutRectToImgBounds (int& x, int& y, int& w, int& h) {
if (ipc) {
if (w > ipc->getFullWidth())
w = ipc->getFullWidth();
if (h > ipc->getFullHeight())
h = ipc->getFullHeight();
if (x < 0)
x = 0;
if (y < 0)
y = 0;
if (x + w >= ipc->getFullWidth())
x = ipc->getFullWidth() - w;
if (y + h >= ipc->getFullHeight())
y = ipc->getFullHeight() - h;
}
}

111
rtgui/crophandler.h Normal file
View File

@@ -0,0 +1,111 @@
/*
* 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 __CROPHANDLER__
#define __CROPHANDLER__
#include "../rtengine/rtengine.h"
#include "threadutils.h"
#include "edit.h"
#include <gtkmm.h>
class CropHandlerListener {
public:
virtual ~CropHandlerListener() {}
virtual void cropImageUpdated () {}
virtual void cropWindowChanged () {}
virtual void initialImageArrived () {}
};
class CropHandler;
struct CropHandlerIdleHelper {
CropHandler* cropHandler;
bool destroyed;
int pending;
};
class CropHandler : public rtengine::DetailedCropListener, public rtengine::SizeListener {
friend int createpixbufs (void* data);
protected:
int zoom;
int ww, wh; // size of the crop view on the screen
int cx, cy, cw, ch; // position and size of the requested crop
int cropX, cropY, cropW, cropH; // position and size of the crop corresponding to cropPixbuf
bool enabled;
unsigned char* cropimg;
unsigned char* cropimgtrue;
int cropimg_width, cropimg_height, cix, ciy, ciw, cih, cis;
bool initial;
bool isLowUpdatePriority;
rtengine::StagedImageProcessor* ipc;
rtengine::DetailedCrop* crop;
CropHandlerListener* listener;
CropHandlerIdleHelper* chi;
void compDim ();
public:
void update ();
rtengine::procparams::CropParams cropParams;
rtengine::procparams::ColorManagementParams colorParams;
Glib::RefPtr<Gdk::Pixbuf> cropPixbuf;
Glib::RefPtr<Gdk::Pixbuf> cropPixbuftrue;
MyMutex cimg;
CropHandler ();
~CropHandler ();
void setCropHandlerListener (CropHandlerListener* l) { listener = l; }
void setEditSubscriber (EditSubscriber* newSubscriber);
void newImage (rtengine::StagedImageProcessor* ipc_, bool isDetailWindow);
void setZoom (int z, int centerx=-1, int centery=-1);
double getFitZoom ();
double getFitCropZoom();
void setWSize (int w, int h);
void getWSize (int& w, int &h);
void setPosition (int x, int y, 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 ();
rtengine::DetailedCrop* getCrop() { return crop; }
// DetailedCropListener interface
void setDetailedCrop (rtengine::IImage8* im, rtengine::IImage8* imworking,rtengine::procparams::ColorManagementParams cmp,
rtengine::procparams::CropParams cp, int cx, int cy, int cw, int ch, int skip);
bool getWindow (int& cwx, int& cwy, int& cww, int& cwh, int& cskip);
// SizeListener interface
void sizeChanged (int w, int h, int ow, int oh);
void cutRectToImgBounds (int& x, int& y, int& w, int& h);
};
#endif

1974
rtgui/cropwindow.cc Executable file

File diff suppressed because it is too large Load Diff

179
rtgui/cropwindow.h Executable file
View File

@@ -0,0 +1,179 @@
/*
* 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 _CROPWINDOW_
#define _CROPWINDOW_
#include "../rtengine/rtengine.h"
#include <gtkmm.h>
#include "lwbutton.h"
#include "lwbuttonset.h"
#include "editenums.h"
#include "crophandler.h"
#include <list>
#include "cropguilistener.h"
#include "pointermotionlistener.h"
class CropWindow;
class CropWindowListener {
public:
virtual ~CropWindowListener() {}
virtual void cropPositionChanged (CropWindow*) {}
virtual void cropWindowSizeChanged (CropWindow*) {}
virtual void cropZoomChanged (CropWindow*) {}
virtual void initialImageArrived (CropWindow*) {}
};
class ImageArea;
class CropWindow : public LWButtonListener, public CropHandlerListener, public EditCoordSystem {
// state management
ImgEditState state; // current state of user (see enum State)
int action_x, action_y, press_x, press_y;
double rot_deg;
bool onResizeArea;
bool deleted;
bool fitZoomEnabled;
bool fitZoom;
bool isLowUpdatePriority;
// decoration
LWButton *bZoomIn, *bZoomOut, *bZoom100, /**bZoomFit,*/ *bClose;
LWButtonSet buttonSet;
Glib::ustring cropLabel;
int backColor;
bool decorated;
bool isFlawnOver;
// crop frame description
int titleHeight, sideBorderWidth, lowerBorderWidth, upperBorderWidth, sepWidth, minWidth;
// size & position of the crop relative to the top left corner
// of the main preview area
int xpos, ypos, width, height;
// size & pos of the drawable area relative to the top left corner of the crop
int imgAreaX, imgAreaY, imgAreaW, imgAreaH;
// size & pos of the piece of preview image relative to the top left corner of the crop
int imgX, imgY, imgW, imgH;
// image handling
ImageArea* iarea;
int cropZoom; // *1000
unsigned int zoomVersion, exposeVersion;
// crop gui listener
CropGUIListener* cropgl;
PointerMotionListener* pmlistener;
PointerMotionListener* pmhlistener;
std::list<CropWindowListener*> listeners;
CropWindow* observedCropWin;
rtengine::StagedImageProcessor* ipc;
bool onArea (CursorArea a, int x, int y);
void updateCursor (int x, int y);
void drawDecoration (Cairo::RefPtr<Cairo::Context> cr);
void drawStraightenGuide (Cairo::RefPtr<Cairo::Context> cr);
void drawScaledSpotRectangle (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 changeZoom (int zoom, bool notify=true, int centerx=-1, int centery=-1, bool skipZoomIfUnchanged = true);
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);
void setDecorated (bool decorated) { this->decorated = decorated; }
void setFitZoomEnabled (bool fze) { fitZoomEnabled = fze; }
void setObservedCropWin (CropWindow* cw) { observedCropWin = cw; }
void screenCoordToCropBuffer (int phyx, int phyy, int& cropx, int& cropy);
void screenCoordToImage (int phyx, int phyy, int& imgx, int& imgy);
void screenCoordToPreview (int phyx, int phyy, int& prevx, int& prevy);
void imageCoordToScreen (int imgx, int imgy, int& phyx, int& phyy);
void imageCoordToCropBuffer (int imgx, int imgy, int& phyx, int& phyy);
int scaleValueToImage (int value);
float scaleValueToImage (float value);
double scaleValueToImage (double value);
int scaleValueToScreen (int value);
float scaleValueToScreen (float value);
double scaleValueToScreen (double value);
double getZoomFitVal ();
void setPosition (int x, int y);
void getPosition (int& x, int& y);
void setSize (int w, int h, bool norefresh=false);
void getSize (int& w, int& h);
void enable ();
void leaveNotify (GdkEventCrossing* event);
void flawnOver (bool isFlawnOver);
// zoomlistener interface
void zoomIn (bool toCursor=false, int cursorX=-1, int cursorY=-1);
void zoomOut (bool toCursor=false, int cursorX=-1, int cursorY=-1);
void zoom11 ();
void zoomFit (bool skipZoomIfUnchanged=true);
void zoomFitCrop ();
double getZoom ();
bool isMinZoom ();
bool isMaxZoom ();
void setZoom (double zoom);
void findCenter (int deltaZoom, int& x, int& y);
bool isInside (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 pointerMoved (int bstate, int x, int y);
void expose (Cairo::RefPtr<Cairo::Context> cr);
// interface lwbuttonlistener
void buttonPressed (LWButton* button, int actionCode, void* actionData);
void redrawNeeded (LWButton* button);
// crop handling
void getCropRectangle (int& x, int& y, int& w, int& h);
void getCropPosition (int& x, int& y);
void setCropPosition (int x, int y, bool update = true);
void getCropSize (int& w, int& h);
// listeners
void setCropGUIListener (CropGUIListener* cgl) { cropgl = cgl; }
void setPointerMotionListener (PointerMotionListener* pml) { pmlistener = pml; }
void setPointerMotionHListener (PointerMotionListener* pml) { pmhlistener = pml; }
// crop window listeners
void addCropWindowListener (CropWindowListener* l) { listeners.push_back (l); }
void delCropWindowListener (CropWindowListener* l);
// crophandlerlistener interface
void cropImageUpdated ();
void cropWindowChanged ();
void initialImageArrived ();
void remoteMove (int deltaX, int deltaY);
void remoteMoveReady ();
EditDataProvider* getImageArea();
};
#endif

120
rtgui/cursormanager.cc Normal file
View File

@@ -0,0 +1,120 @@
/*
* 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 "cursormanager.h"
#include "options.h"
#include "../rtengine/safegtk.h"
#include "rtimage.h"
CursorManager cursorManager;
void CursorManager::init (Glib::RefPtr<Gdk::Window> mainWin) {
cResizeWidth = new Gdk::Cursor (Gdk::SB_H_DOUBLE_ARROW);
cResizeHeight = new Gdk::Cursor (Gdk::SB_V_DOUBLE_ARROW);
cResizeDiag = new Gdk::Cursor (Gdk::BOTTOM_RIGHT_CORNER);
cResizeTopLeft = new Gdk::Cursor (Gdk::TOP_LEFT_CORNER);
cResizeTopRight = new Gdk::Cursor (Gdk::TOP_RIGHT_CORNER);
cResizeBottomLeft = new Gdk::Cursor (Gdk::BOTTOM_LEFT_CORNER);
cResizeBottomRight = new Gdk::Cursor (Gdk::BOTTOM_RIGHT_CORNER);
cCropMove = new Gdk::Cursor (Gdk::FLEUR);
cCropMoving = new Gdk::Cursor (Gdk::HAND2);
cCropSelection = new Gdk::Cursor (Gdk::CROSSHAIR);
cLeftTanMove = new Gdk::Cursor (Gdk::SB_LEFT_ARROW);
cRightTanMove = new Gdk::Cursor (Gdk::SB_RIGHT_ARROW);
cAdd = new Gdk::Cursor (Gdk::PLUS);
cWait = new Gdk::Cursor (Gdk::CLOCK);
Glib::RefPtr<Gdk::Pixbuf> hand = safe_create_from_file("cross.png");
Glib::RefPtr<Gdk::Pixbuf> close_hand = safe_create_from_file("closedhand.png");
Glib::RefPtr<Gdk::Pixbuf> wbpick = safe_create_from_file("gtk-color-picker-small.png");
Glib::RefPtr<Gdk::Pixbuf> empty = safe_create_from_file("empty.png");
Glib::RefPtr<Gdk::Pixbuf> move2D = safe_create_from_file("move-2D.png");
Glib::RefPtr<Gdk::Pixbuf> move1DH = safe_create_from_file("move-1D-h.png");
Glib::RefPtr<Gdk::Pixbuf> move1DV = safe_create_from_file("move-1D-v.png");
Glib::RefPtr<Gdk::Pixbuf> moveRotate = safe_create_from_file("move-rotate.png");
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);
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);
cMove1DV = move1DV ? new Gdk::Cursor (cAdd->get_display(), move1DV, 11, 11) : new Gdk::Cursor (Gdk::FLEUR);
cMoveRotate = moveRotate ? new Gdk::Cursor (cAdd->get_display(), moveRotate, 11, 11) : new Gdk::Cursor (Gdk::CIRCLE);
mainWindow = mainWin;
}
/* Set the cursor of the given window */
void CursorManager::setCursor (Glib::RefPtr<Gdk::Window> window, CursorShape shape) {
if (shape==CSArrow)
// set_cursor without any arguments to select system default
window->set_cursor ();
else if (shape==CSOpenHand)
window->set_cursor (*cHand);
else if (shape==CSClosedHand)
window->set_cursor (*cClosedHand);
else if (shape==CSMove)
window->set_cursor (*cCropMove);
else if (shape==CSResizeWidth)
window->set_cursor (*cResizeWidth);
else if (shape==CSResizeHeight)
window->set_cursor (*cResizeHeight);
else if (shape==CSResizeDiagonal)
window->set_cursor (*cResizeDiag);
else if (shape==CSResizeTopLeft)
window->set_cursor (*cResizeTopLeft);
else if (shape==CSResizeTopRight)
window->set_cursor (*cResizeTopRight);
else if (shape==CSResizeBottomLeft)
window->set_cursor (*cResizeBottomLeft);
else if (shape==CSResizeBottomRight)
window->set_cursor (*cResizeBottomRight);
else if (shape==CSMove2D)
window->set_cursor (*cMove2D);
else if (shape==CSMove1DH)
window->set_cursor (*cMove1DH);
else if (shape==CSMove1DV)
window->set_cursor (*cMove1DV);
else if (shape==CSMoveRotate)
window->set_cursor (*cMoveRotate);
else if (shape==CSSpotWB)
window->set_cursor (*cWB);
else if (shape==CSCropSelect)
window->set_cursor (*cCropSelection);
else if (shape==CSMoveLeft)
window->set_cursor (*cLeftTanMove);
else if (shape==CSMoveRight)
window->set_cursor (*cRightTanMove);
else if (shape==CSStraighten)
window->set_cursor (*cCropSelection);
else if (shape==CSWait)
window->set_cursor (*cWait);
else if (shape==CSPlus)
window->set_cursor (*cAdd);
else if (shape==CSEmpty)
window->set_cursor (*cHidden);
}
/* Set the cursor of the main window */
void CursorManager::setCursor (CursorShape shape) {
setCursor(mainWindow, shape);
}

69
rtgui/cursormanager.h Normal file
View File

@@ -0,0 +1,69 @@
/*
* 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 _CURSORMANAGER_
#define _CURSORMANAGER_
#include <gtkmm.h>
enum CursorShape {
CSArrow, CSOpenHand, CSClosedHand, CSMove, CSMoveLeft,
CSMoveRight, CSResizeWidth, CSResizeHeight, CSResizeDiagonal,
CSResizeTopLeft, CSResizeTopRight, CSResizeBottomLeft, CSResizeBottomRight,
CSMove2D, CSMove1DH, CSMove1DV, CSMoveRotate,
CSSpotWB, CSCropSelect, CSStraighten, CSPlus, CSWait, CSEmpty
};
class CursorManager {
protected:
Gdk::Cursor* cResizeWidth;
Gdk::Cursor* cResizeHeight;
Gdk::Cursor* cResizeDiag;
Gdk::Cursor* cResizeTopLeft;
Gdk::Cursor* cResizeTopRight;
Gdk::Cursor* cResizeBottomLeft;
Gdk::Cursor* cResizeBottomRight;
Gdk::Cursor* cCropMove;
Gdk::Cursor* cCropMoving;
Gdk::Cursor* cLeftTanMove;
Gdk::Cursor* cRightTanMove;
Gdk::Cursor* cNormal;
Gdk::Cursor* cCropSelection;
Gdk::Cursor* cAdd;
Gdk::Cursor* cWait;
Gdk::Cursor* cHand;
Gdk::Cursor* cClosedHand;
Gdk::Cursor* cWB;
Gdk::Cursor* cHidden;
Gdk::Cursor* cMove2D;
Gdk::Cursor* cMove1DH;
Gdk::Cursor* cMove1DV;
Gdk::Cursor* cMoveRotate;
Glib::RefPtr<Gdk::Window> mainWindow;
public:
void init (Glib::RefPtr<Gdk::Window> mainWin);
void setCursor (Glib::RefPtr<Gdk::Window> window, CursorShape shape);
void setCursor (CursorShape shape);
};
extern CursorManager cursorManager;
#endif

373
rtgui/curveeditor.cc Normal file
View File

@@ -0,0 +1,373 @@
/*
* 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.
*
* 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 "curveeditor.h"
#include "curveeditorgroup.h"
#include <fstream>
#include <string>
#include "guiutils.h"
#include "multilangmgr.h"
#include "../rtengine/LUT.h"
#include <cstring>
bool CurveEditor::reset() {
return subGroup->curveReset(this);
}
DiagonalCurveEditor::DiagonalCurveEditor (Glib::ustring text, CurveEditorGroup* ceGroup, CurveEditorSubGroup* ceSubGroup) : CurveEditor::CurveEditor(text, static_cast<CurveEditorGroup*>(ceGroup), ceSubGroup) {
// Order set in the same order than "enum DiagonalCurveType". Shouldn't change, for compatibility reason
curveType->addEntry("curveType-linear.png", M("CURVEEDITOR_LINEAR")); // 0 Linear
curveType->addEntry("curveType-spline.png", M("CURVEEDITOR_CUSTOM")); // 1 Spline
curveType->addEntry("curveType-parametric.png", M("CURVEEDITOR_PARAMETRIC")); // 2 Parametric
curveType->addEntry("curveType-NURBS.png", M("CURVEEDITOR_NURBS")); // 3 NURBS
curveType->setSelected(DCT_Linear);
curveType->show();
rangeLabels[0] = M("CURVEEDITOR_SHADOWS");
rangeLabels[1] = M("CURVEEDITOR_DARKS");
rangeLabels[2] = M("CURVEEDITOR_LIGHTS");
rangeLabels[3] = M("CURVEEDITOR_HIGHLIGHTS");
rangeMilestones[0] = 0.25;
rangeMilestones[1] = 0.50;
rangeMilestones[2] = 0.75;
}
std::vector<double> DiagonalCurveEditor::getCurve () {
std::vector<double> curve;
switch (selected) {
case (DCT_Spline):
return curve = customCurveEd;
case (DCT_Parametric):
return curve = paramCurveEd;
case (DCT_NURBS):
return curve = NURBSCurveEd;
default:
// returning Linear or Unchanged
curve.push_back((double)(selected));
return curve;
}
}
void DiagonalCurveEditor::setResetCurve(DiagonalCurveType cType, const std::vector<double> &resetCurve) {
switch (cType) {
case (DCT_NURBS):
if (resetCurve.size() && DiagonalCurveType(resetCurve.at(0)) == cType)
NURBSResetCurve = resetCurve;
break;
case (DCT_Parametric):
if (resetCurve.size() && DiagonalCurveType(resetCurve.at(0)) == cType)
paramResetCurve = resetCurve;
break;
case (DCT_Spline):
if (resetCurve.size() && DiagonalCurveType(resetCurve.at(0)) == cType)
customResetCurve = resetCurve;
break;
default:
break;
}
}
void DiagonalCurveEditor::setRangeLabels(Glib::ustring r1, Glib::ustring r2, Glib::ustring r3, Glib::ustring r4) {
rangeLabels[0] = r1;
rangeLabels[1] = r2;
rangeLabels[2] = r3;
rangeLabels[3] = r4;
}
void DiagonalCurveEditor::getRangeLabels(Glib::ustring &r1, Glib::ustring &r2, Glib::ustring &r3, Glib::ustring &r4) {
r1 = rangeLabels[0];
r2 = rangeLabels[1];
r3 = rangeLabels[2];
r4 = rangeLabels[3];
}
/*
* Admittedly that this method is called just after the instantiation of this class, we set the shcselector's default values
*/
void DiagonalCurveEditor::setRangeDefaultMilestones(double m1, double m2, double m3) {
rangeMilestones[0] = m1;
rangeMilestones[1] = m2;
rangeMilestones[2] = m3;
paramCurveEd.at(1) = m1;
paramCurveEd.at(2) = m2;
paramCurveEd.at(3) = m3;
}
void DiagonalCurveEditor::getRangeDefaultMilestones(double &m1, double &m2, double &m3) {
m1 = rangeMilestones[0];
m2 = rangeMilestones[1];
m3 = rangeMilestones[2];
}
FlatCurveEditor::FlatCurveEditor (Glib::ustring text, CurveEditorGroup* ceGroup, CurveEditorSubGroup* ceSubGroup, bool isPeriodic) : CurveEditor::CurveEditor(text, static_cast<CurveEditorGroup*>(ceGroup), ceSubGroup) {
periodic = isPeriodic;
identityValue = 0.5;
// Order set in the same order than "enum FlatCurveType". Shouldn't change, for compatibility reason
curveType->addEntry("curveType-flatLinear.png", M("CURVEEDITOR_LINEAR")); // 0 Linear
curveType->addEntry("curveType-controlPoints.png", M("CURVEEDITOR_MINMAXCPOINTS")); // 1 Min/Max ControlPoints
curveType->setSelected(FCT_Linear);
curveType->show();
}
std::vector<double> FlatCurveEditor::getCurve () {
std::vector<double> curve;
switch (selected) {
//case (Parametric):
// return curve = paramCurveEd;
case (FCT_MinMaxCPoints):
return curve = controlPointsCurveEd;
default:
// returning Linear or Unchanged
curve.push_back((double)(selected));
return curve;
}
}
void FlatCurveEditor::setResetCurve(FlatCurveType cType, const std::vector<double> &resetCurve) {
switch (cType) {
case (FCT_MinMaxCPoints):
if (resetCurve.size() && FlatCurveType(resetCurve.at(0)) == cType)
controlPointsResetCurve = resetCurve;
break;
default:
break;
}
}
/*
* CurveEditor (CurveEditorGroup* ceGroup, Glib::ustring text)
*
* parameters:
* ceGroup = NULL or the address of the Widget that will receive the CurveTypeToggleButton
* text = (optional) label of the curve, displayed in the CurveTypeToggleButton, next to the image
*/
CurveEditor::CurveEditor (Glib::ustring text, CurveEditorGroup* ceGroup, CurveEditorSubGroup* ceSubGroup) : EditSubscriber(ET_PIPETTE) {
bgHistValid = false;
remoteDrag = false;
selected = DCT_Linear;
bottomBarCP = NULL;
leftBarCP = NULL;
curveCP = NULL;
relatedWidget = NULL;
group = ceGroup;
subGroup = ceSubGroup;
if (group && text.size())
curveType = new PopUpToggleButton(text + ":");
else
curveType = new PopUpToggleButton();
curveType->set_tooltip_text(M("CURVEEDITOR_TYPE"));
// TODO: Does this signal have to be blocked when on curve type change ?
curveType->signal_toggled().connect ( sigc::mem_fun(*this, &CurveEditor::curveTypeToggled) );
typeconn = curveType->signal_changed().connect (sigc::mem_fun(*this, &CurveEditor::typeSelectionChanged) );
}
void CurveEditor::setCurve (const std::vector<double>& p) {
tempCurve = p;
group->setCurveExternal(this, p);
}
CurveEditor::~CurveEditor () {
delete curveType;
}
void CurveEditor::typeSelectionChanged (int n) {
group->typeSelectionChanged(this, n);
}
void CurveEditor::curveTypeToggled() {
group->curveTypeToggled(this);
}
bool CurveEditor::isUnChanged () {
return curveType->getSelected()==subGroup->getValUnchanged();
}
void CurveEditor::setUnChanged (bool uc) {
group->setUnChanged(uc, this);
}
/*
* Update the backgrounds histograms
*/
void CurveEditor::updateBackgroundHistogram (LUTu & hist) {
// Copy the histogram in the curve editor cache
if (hist) {
histogram=hist;
bgHistValid = true;
}
else
bgHistValid = false;
// Then call the curve editor group to eventually update the histogram
subGroup->updateBackgroundHistogram (this);
}
// Open up the curve if it has modifications and it's not already opened
// Returns: true if curve was non linear and opened
bool CurveEditor::openIfNonlinear() {
bool nonLinear = tempCurve.size() && (tempCurve[0] > subGroup->getValLinear()) && (tempCurve[0] < subGroup->getValUnchanged());
if (nonLinear && !curveType->get_active()) {
// Will trigger the signal_clicked event doing the display
curveType->set_active( true );
}
return nonLinear;
}
// Handles markup tooltips
void CurveEditor::setTooltip(Glib::ustring ttip) {
curveType->set_tooltip_text(ttip.empty() ?
Glib::ustring::compose("<b>%1</b> ", M("CURVEEDITOR_TYPE")) :
Glib::ustring::compose("%1\n<b>%2</b>", ttip, M("CURVEEDITOR_TYPE")));
}
void CurveEditor::setLeftBarColorProvider(ColorProvider* cp, int callerId) {
leftBarCP = cp;
leftBarCId = callerId;
}
void CurveEditor::setBottomBarColorProvider(ColorProvider* cp, int callerId) {
bottomBarCP = cp;
bottomBarCId = callerId;
}
void CurveEditor::setLeftBarBgGradient (const std::vector<GradientMilestone> &milestones) {
leftBarBgGradient = milestones;
}
void CurveEditor::setBottomBarBgGradient (const std::vector<GradientMilestone> &milestones) {
bottomBarBgGradient = milestones;
}
void CurveEditor::refresh () {
subGroup->refresh(this);
}
void CurveEditor::setCurveColorProvider(ColorProvider* cp, int callerId) {
curveCP = cp;
curveCId = callerId;
}
ColorProvider* CurveEditor::getLeftBarColorProvider() {
return leftBarCP;
}
ColorProvider* CurveEditor::getBottomBarColorProvider() {
return bottomBarCP;
}
ColorProvider* CurveEditor::getCurveColorProvider() {
return curveCP;
}
int CurveEditor::getLeftBarCallerId() {
return leftBarCId;
}
int CurveEditor::getBottomBarCallerId() {
return bottomBarCId;
}
int CurveEditor::getCurveCallerId() {
return curveCId;
}
std::vector<GradientMilestone> CurveEditor::getBottomBarBgGradient () const {
return bottomBarBgGradient;
}
std::vector<GradientMilestone> CurveEditor::getLeftBarBgGradient () const {
return leftBarBgGradient;
}
sigc::signal<void> CurveEditor::signal_curvegraph_enter() {
return sig_curvegraph_enter;
}
sigc::signal<void> CurveEditor::signal_curvegraph_leave() {
return sig_curvegraph_leave;
}
sigc::signal<void> CurveEditor::signal_curvepoint_click() {
return sig_curvepoint_click;
}
sigc::signal<void> CurveEditor::signal_curvepoint_release() {
return sig_curvepoint_release;
}
void CurveEditor::switchOffEditMode () {
if (EditSubscriber::getEditID() != EUID_None) {
// switching off the toggle button
if (group->displayedCurve == this) {
subGroup->editModeSwitchedOff();
}
}
EditSubscriber::switchOffEditMode(); // disconnect
}
bool CurveEditor::mouseOver(int modifierKey) {
EditDataProvider* provider = getEditProvider();
subGroup->pipetteMouseOver(provider, modifierKey);
subGroup->refresh(this);
return true; // return true will ask the preview to be redrawn, for the cursor
}
bool CurveEditor::button1Pressed(int modifierKey) {
EditDataProvider* provider = getEditProvider();
if (provider->object) {
subGroup->pipetteButton1Pressed(provider, modifierKey);
remoteDrag = true;
}
subGroup->refresh(this);
return true;
}
bool CurveEditor::button1Released() {
EditDataProvider* provider = getEditProvider();
subGroup->pipetteButton1Released(provider);
remoteDrag = false;
subGroup->refresh(this);
return true;
}
bool CurveEditor::drag(int modifierKey) {
EditDataProvider* provider = getEditProvider();
subGroup->pipetteDrag(provider, modifierKey);
subGroup->refresh(this);
return false;
}
CursorShape CurveEditor::getCursor(int objectID) {
if (remoteDrag)
return CSResizeHeight;
return CSOpenHand;
}

196
rtgui/curveeditor.h Normal file
View File

@@ -0,0 +1,196 @@
/*
* 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 _CURVEEDITOR_
#define _CURVEEDITOR_
#include "popuptogglebutton.h"
#include "../rtengine/LUT.h"
#include "coloredbar.h"
#include "edit.h"
#include "mydiagonalcurve.h"
#include "myflatcurve.h"
class CurveEditorGroup;
class CurveEditorSubGroup;
/*
*********************** Curve Editor ***********************
*/
/*
* This class is an interface between RT and the curve editor group ; it handles the methods
* related to a specific curve. It is created by CurveEditorGroup::addCurve
*/
class CurveEditor : public EditSubscriber {
friend class CurveEditorGroup;
friend class CurveEditorSubGroup;
friend class DiagonalCurveEditorSubGroup;
friend class FlatCurveEditorSubGroup;
friend class DiagonalCurveEditor;
friend class FlatCurveEditor;
protected:
/*
* The curve editor contains only one widget (the curve type button) to receive the signals
* but it's co-handled by the CurveEditorGroup too
*/
PopUpToggleButton* curveType;
LUTu histogram; // histogram values
bool bgHistValid;
bool remoteDrag;
int selected;
CurveEditorGroup* group;
CurveEditorSubGroup* subGroup;
Gtk::Widget* relatedWidget;
std::vector<double> tempCurve;
sigc::connection typeconn;
ColorProvider* bottomBarCP;
ColorProvider* leftBarCP;
ColorProvider* curveCP;
int bottomBarCId;
int leftBarCId;
int curveCId;
std::vector<GradientMilestone> bottomBarBgGradient;
std::vector<GradientMilestone> leftBarBgGradient;
sigc::signal<void> sig_curvegraph_enter;
sigc::signal<void> sig_curvegraph_leave;
sigc::signal<void> sig_curvepoint_click;
sigc::signal<void> sig_curvepoint_release;
public:
CurveEditor (Glib::ustring text, CurveEditorGroup* ceGroup, CurveEditorSubGroup* ceSubGroup);
virtual ~CurveEditor ();
void typeSelectionChanged (int n);
void curveTypeToggled();
bool isUnChanged ();
void setUnChanged (bool uc);
void updateBackgroundHistogram (LUTu & hist);
void setLeftBarColorProvider(ColorProvider* cp, int callerId);
void setBottomBarColorProvider(ColorProvider* cp, int callerId);
void setCurveColorProvider(ColorProvider* cp, int callerId);
void setBottomBarBgGradient (const std::vector<GradientMilestone> &milestones);
void setLeftBarBgGradient (const std::vector<GradientMilestone> &milestones);
ColorProvider* getLeftBarColorProvider();
ColorProvider* getBottomBarColorProvider();
ColorProvider* getCurveColorProvider();
int getLeftBarCallerId();
int getBottomBarCallerId();
int getCurveCallerId();
std::vector<GradientMilestone> getBottomBarBgGradient () const;
std::vector<GradientMilestone> getLeftBarBgGradient () const;
void refresh (); // refresh the display of the CurveEditor (e.g. when a ColoredBar has been changed from the outside)
bool openIfNonlinear(); // Open up the curve if it has modifications and it's not already opened
void setCurve (const std::vector<double>& p);
virtual void setIdentityValue (const double iValue=0.5) {};
virtual double getIdentityValue () { return 0.5; };
virtual std::vector<double> getCurve () = 0;
bool reset();
void setTooltip(Glib::ustring ttip);
sigc::signal<void> signal_curvegraph_enter();
sigc::signal<void> signal_curvegraph_leave();
sigc::signal<void> signal_curvepoint_click();
sigc::signal<void> signal_curvepoint_release();
void switchOffEditMode ();
bool mouseOver(int modifierKey);
bool button1Pressed(int modifierKey);
bool button1Released();
bool drag(int modifierKey);
CursorShape getCursor(int objectID);
};
/*
******************** Diagonal Curve Editor ********************
*/
class DiagonalCurveEditor : public CurveEditor {
friend class DiagonalCurveEditorSubGroup;
protected:
// reflects the buttonType active selection ; used as a pre-'selectionChange' reminder value
std::vector<double> customCurveEd;
std::vector<double> customResetCurve;
std::vector<double> paramCurveEd;
std::vector<double> paramResetCurve;
std::vector<double> NURBSCurveEd;
std::vector<double> NURBSResetCurve;
Glib::ustring rangeLabels[4];
double rangeMilestones[3];
public:
DiagonalCurveEditor (Glib::ustring text, CurveEditorGroup* ceGroup, CurveEditorSubGroup* ceSubGroup);
std::vector<double> getCurve ();
void setRangeLabels(Glib::ustring r1, Glib::ustring r2, Glib::ustring r3, Glib::ustring r4);
void getRangeLabels(Glib::ustring &r1, Glib::ustring &r2, Glib::ustring &r3, Glib::ustring &r4);
void setRangeDefaultMilestones(double m1, double m2, double m3);
void getRangeDefaultMilestones(double &m1, double &m2, double &m3);
// set the reset curve for a given curve type. This is optional; all curve type have a default reset curve
void setResetCurve(DiagonalCurveType cType, const std::vector<double> &resetCurve);
};
/*
********************** Flat Curve Editor **********************
*/
class FlatCurveEditor : public CurveEditor {
friend class FlatCurveEditorSubGroup;
protected:
// reflects the buttonType active selection ; used as a pre-'selectionChange' reminder value
std::vector<double> controlPointsCurveEd;
std::vector<double> controlPointsResetCurve;
bool periodic;
double identityValue;
public:
FlatCurveEditor (Glib::ustring text, CurveEditorGroup* ceGroup, CurveEditorSubGroup* ceSubGroup, bool isPeriodic = true);
virtual void setIdentityValue (const double iValue=0.5) { identityValue = iValue; }
virtual double getIdentityValue () { return identityValue; };
std::vector<double> getCurve ();
// set the reset curve for a given curve type. This is optional; all curve type have a default reset curve
void setResetCurve(FlatCurveType cType, const std::vector<double> &resetCurve);
};
#endif

434
rtgui/curveeditorgroup.cc Normal file
View File

@@ -0,0 +1,434 @@
/*
* 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/>.
*
* Class created by Jean-Christophe FRISCH, aka 'Hombre'
*/
#include "curveeditor.h"
#include "curveeditorgroup.h"
#include "diagonalcurveeditorsubgroup.h"
#include "flatcurveeditorsubgroup.h"
#include "multilangmgr.h"
#include "../rtengine/safegtk.h"
#include "rtimage.h"
CurveEditorGroup::CurveEditorGroup (Glib::ustring& curveDir, Glib::ustring groupLabel) : curveDir(curveDir), curve_reset(NULL),
displayedCurve(0), flatSubGroup(0), diagonalSubGroup(0), cl(NULL), numberOfPackedCurve(0)
{
// We set the label to the one provided as parameter, even if it's an empty string
curveGroupLabel = Gtk::manage (new Gtk::Label (groupLabel+":", Gtk::ALIGN_LEFT));
}
CurveEditorGroup::~CurveEditorGroup() {
for (std::vector<CurveEditor*>::iterator i = curveEditors.begin(); i != curveEditors.end(); ++i)
{
delete *i;
}
delete flatSubGroup;
delete diagonalSubGroup;
}
void CurveEditorGroup::hideCurrentCurve() {
// Setting the curve type to 'Unchanged' hide the CurveEditor
if (diagonalSubGroup)
diagonalSubGroup->stopNumericalAdjustment();
if (flatSubGroup)
flatSubGroup->stopNumericalAdjustment();
if (displayedCurve)
displayedCurve->curveType->set_active(false);
}
/*
* Add a new curve to the curves list
*
* Parameters:
* cType: enum saying which kind of curve type has to be created
* curveLabel: Name of the curve that will be inserted in the toggle button, before the image.
* If empty, no text will prepend the image
* relatedWidget: pointer to a widget (or NULL) that will be inserted next to the curve's toggle button.
* if a smart pointer created by Gtk::manage is passed in, the widget will be deleted by the destructor,
* otherwise it'll have to be delete it manually
* periodic: for FlatCurve only, ask the curve to be periodic (default: True)
*
*/
CurveEditor* CurveEditorGroup::addCurve(CurveType cType, Glib::ustring curveLabel, Gtk::Widget *relatedWidget, bool periodic) {
switch (cType) {
case (CT_Diagonal):
{
if (!diagonalSubGroup) {
diagonalSubGroup = new DiagonalCurveEditorSubGroup(this, curveDir);
}
// We add it to the curve editor list
DiagonalCurveEditor* newCE = diagonalSubGroup->addCurve(curveLabel);
newCE->relatedWidget = relatedWidget;
curveEditors.push_back(newCE);
return (newCE);
}
case (CT_Flat):
{
if (!flatSubGroup) {
flatSubGroup = new FlatCurveEditorSubGroup(this, curveDir);
}
// We add it to the curve editor list
FlatCurveEditor* newCE = flatSubGroup->addCurve(curveLabel, periodic);
newCE->relatedWidget = relatedWidget;
curveEditors.push_back(newCE);
return (newCE);
}
default:
return (static_cast<CurveEditor*>(NULL));
break;
}
return NULL; // to avoid complains from Gcc
}
/*
* Use this method to start a new line of button
*/
void CurveEditorGroup::newLine() {
Gtk::HBox* headerBox;
if (curveEditors.size() > numberOfPackedCurve) {
headerBox = Gtk::manage (new Gtk::HBox ());
if (!numberOfPackedCurve) {
headerBox->pack_start(*curveGroupLabel, Gtk::PACK_SHRINK, 2);
curve_reset = Gtk::manage (new Gtk::Button ());
curve_reset->add (*Gtk::manage (new RTImage ("gtk-undo-ltr-small.png", "gtk-undo-rtl-small.png")));
curve_reset->set_relief (Gtk::RELIEF_NONE);
curve_reset->set_border_width (0);
curve_reset->set_tooltip_text (M("CURVEEDITOR_TOOLTIPLINEAR"));
curve_reset->signal_clicked().connect( sigc::mem_fun(*this, &CurveEditorGroup::curveResetPressed) );
headerBox->pack_end (*curve_reset, Gtk::PACK_SHRINK, 0);
}
int j = numberOfPackedCurve;
bool hasRelatedWidget = false;
for (int i = (int)(curveEditors.size())-1; i >= j; i--) {
if (curveEditors[i]->relatedWidget != NULL)
hasRelatedWidget = true;
}
for (int i = (int)(curveEditors.size())-1; i >= j; i--) {
if (curveEditors[i]->relatedWidget != NULL)
headerBox->pack_end (*curveEditors[i]->relatedWidget, Gtk::PACK_EXPAND_WIDGET, 2);
headerBox->pack_end (*curveEditors[i]->curveType->buttonGroup, hasRelatedWidget ? Gtk::PACK_SHRINK : Gtk::PACK_EXPAND_WIDGET, 2);
numberOfPackedCurve++;
}
pack_start (*headerBox, Gtk::PACK_SHRINK, 2);
}
}
/*
* Create all the widgets now that the curve list is complete
* This method should handle all curve number correctly, i.e. eventually display the curve type buttons
* in a grid (or table)
*/
void CurveEditorGroup::curveListComplete() {
newLine();
// We check the length of the label ; if it contains only one char (':'), we set it to the right default string
if (curveGroupLabel->get_label().size()==1)
curveGroupLabel->set_label(M(curveEditors.size() > 1 ? "CURVEEDITOR_CURVES" : "CURVEEDITOR_CURVE") + ":");
if (curveEditors.size() > 1)
cl->setMulti(true);
}
/*
* Callback method used when a curve type button has changed ;
* it will activate the button, and so emit 'signal_toggled' (-> curveTypeToggled here under)
*/
void CurveEditorGroup::typeSelectionChanged (CurveEditor* ce, int n) {
// Same type : do nothing
if (ce==displayedCurve && n==(int)ce->selected)
return;
if (n<ce->subGroup->valUnchanged)
ce->selected = n;
// The user selected a new type from a toggled off button
if (ce!=displayedCurve)
// We toggle off the other curve: it will emit the toggle off signal
hideCurrentCurve();
// If the button was not pressed before
if (!ce->curveType->get_active()) {
ce->subGroup->storeDisplayedCurve();
// We set it pressed : it will emit the toggle on signal and update the GUI
ce->curveType->set_active( n>ce->subGroup->valLinear && n<ce->subGroup->valUnchanged );
if (n==ce->subGroup->valLinear || n==ce->subGroup->valUnchanged) {
// Since we do not activate the curve when the user switch the toggled off button to 'Linear', we have to
// to call the curve listener manually, because 'curveChanged' uses displayedCurve...
if (cl) {
if (cl->isMulti())
cl->curveChanged (ce);
else
cl->curveChanged ();
}
}
else
curveChanged ();
}
else {
// The button is already pressed so we switch the GUI ourselves
ce->subGroup->switchGUI();
curveChanged ();
}
}
/*
* Callback method used when a button has been toggled on/off
* It then hide any other displayed curve and display it's curve
*/
void CurveEditorGroup::curveTypeToggled(CurveEditor* ce) {
bool curveRestored = false;
if (displayedCurve) {
EditDataProvider* editProvider = displayedCurve->getEditProvider();
if (editProvider && editProvider->getCurrSubscriber() == displayedCurve)
displayedCurve->switchOffEditMode();
}
// Looking for the button state
if (ce->curveType->get_active()) {
// The button is now pressed, so we have to first hide all other CurveEditor
hideCurrentCurve();
displayedCurve = ce;
if (ce->curveType->getSelected()==ce->subGroup->valUnchanged) {
curveRestored = true;
ce->curveType->setSelected(ce->selected);
}
// then show this CurveEditor
int ct = ce->curveType->getSelected();
if (ct < ce->subGroup->valUnchanged)
ce->subGroup->restoreDisplayedHistogram();
}
else {
// The button is now released, so we have to hide this CurveEditor
displayedCurve = 0;
}
ce->subGroup->switchGUI();
if (curveRestored)
curveChanged ();
}
/*
* Update the GUI if the given curveEditor is currently displayed
*/
void CurveEditorGroup::updateGUI (CurveEditor* ce) {
if (!ce) {
return;
}
// we update the curve type button to the corresponding curve type, only if it is not currently set to 'Unchanged'
if (ce->curveType->getSelected()<ce->subGroup->valUnchanged)
ce->curveType->setSelected(ce->selected);
// if not displayed or "unchanged" is selected, do not change gui
if (ce==displayedCurve && ce->curveType->getSelected()<ce->subGroup->valUnchanged) {
ce->subGroup->switchGUI();
}
}
/*
* Called from the outside to set the curve type & values
*/
void CurveEditorGroup::setCurveExternal (CurveEditor* ce, const std::vector<double>& c) {
if (!c.empty()) {
ce->subGroup->storeCurveValues(ce, c); // The new curve is saved in the CurveEditor
(ce)->selected = c[0]; // We set the selected curve type in the CurveEditor to the one of the specified curve
}
updateGUI(static_cast<CurveEditor*>(ce)); // And we update the GUI if necessary
}
/*
* Listener called when the user has modified the curve
*/
void CurveEditorGroup::curveChanged () {
displayedCurve->subGroup->storeDisplayedCurve();
if (cl) {
if (cl->isMulti())
cl->curveChanged (displayedCurve);
else
cl->curveChanged ();
}
}
/*
* Listener called when the user has modified the curve
*/
float CurveEditorGroup::blendPipetteValues (CurveEditor* ce, float chan1, float chan2, float chan3) {
if (cl)
return cl->blendPipetteValues(ce, chan1, chan2, chan3);
return -1.f;
}
/*
* Call back method when the reset button is pressed :
* reset the currently toggled on curve editor
*/
void CurveEditorGroup::curveResetPressed () {
if (displayedCurve) {
if (displayedCurve->subGroup->curveReset(displayedCurve)) {
curveChanged();
}
}
}
/*
* Set the tooltip text of the label of the curve group
*/
void CurveEditorGroup::setTooltip( Glib::ustring ttip) {
curveGroupLabel->set_tooltip_text( ttip );
}
void CurveEditorGroup::setBatchMode (bool batchMode) {
for (std::vector<CurveEditor*>::iterator i = curveEditors.begin(); i != curveEditors.end(); ++i) {
(*i)->curveType->addEntry("curveType-unchanged.png", M("GENERAL_UNCHANGED"));
(*i)->curveType->show();
}
}
void CurveEditorGroup::setUnChanged (bool uc, CurveEditor* ce) {
if (uc) {
// the user selected several thumbnails, so we hide the editors and set the curveEditor selection to 'Unchanged'
//ce->typeconn.block(true);
// we hide the editor widgets
hideCurrentCurve();
// the curve type selected option is set to unchanged
ce->curveType->setSelected(ce->subGroup->valUnchanged);
//ce->typeconn.block(false);
}
else {
// we want it to use back the 'CurveEditor::setCurve' memorized in CurveEditor::tempCurve
//ce->typeconn.block(true);
// we switch back the curve type selected option to the one of the used curve
ce->curveType->setSelected(ce->selected);
updateGUI (ce);
//ce->typeconn.block(false);
}
}
CurveEditorSubGroup::CurveEditorSubGroup(Glib::ustring& curveDir) : curveDir(curveDir), lastFilename("") {
leftBar = NULL;
bottomBar = NULL;
}
CurveEditorSubGroup::~CurveEditorSubGroup() {
if (leftBar) delete leftBar;
if (bottomBar) delete bottomBar;
}
void CurveEditorSubGroup::updateEditButton(CurveEditor* curve, Gtk::ToggleButton *button, sigc::connection &connection) {
if (!curve->getEditProvider() || curve->getEditID() == EUID_None) {
button->hide();
}
else {
button->show();
bool prevstate = connection.block(true);
if (curve->isCurrentSubscriber())
button->set_active(true);
else
button->set_active(false);
if (!prevstate) connection.block(false);
}
}
Glib::ustring CurveEditorSubGroup::outputFile () {
Gtk::FileChooserDialog dialog(M("CURVEEDITOR_SAVEDLGLABEL"), Gtk::FILE_CHOOSER_ACTION_SAVE);
FileChooserLastFolderPersister persister(&dialog, curveDir);
dialog.set_current_name (lastFilename);
dialog.add_button(Gtk::StockID("gtk-cancel"), Gtk::RESPONSE_CANCEL);
dialog.add_button(Gtk::StockID("gtk-save"), Gtk::RESPONSE_APPLY);
Gtk::FileFilter filter_pp;
filter_pp.set_name(M("FILECHOOSER_FILTER_CURVE"));
filter_pp.add_pattern("*.rtc");
dialog.add_filter(filter_pp);
Gtk::FileFilter filter_any;
filter_any.set_name(M("FILECHOOSER_FILTER_ANY"));
filter_any.add_pattern("*");
dialog.add_filter(filter_any);
//dialog.set_do_overwrite_confirmation (true);
Glib::ustring fname;
do {
if (dialog.run() == Gtk::RESPONSE_APPLY) {
fname = dialog.get_filename();
if (getExtension (fname) != "rtc")
fname += ".rtc";
if (confirmOverwrite (dialog, fname)) {
lastFilename = Glib::path_get_basename (fname);
break;
}
} else {
fname = "";
break;
}
} while (1);
return fname;
}
Glib::ustring CurveEditorSubGroup::inputFile () {
Gtk::FileChooserDialog dialog(M("CURVEEDITOR_LOADDLGLABEL"), Gtk::FILE_CHOOSER_ACTION_OPEN);
FileChooserLastFolderPersister persister(&dialog, curveDir);
dialog.add_button(Gtk::StockID("gtk-cancel"), Gtk::RESPONSE_CANCEL);
dialog.add_button(Gtk::StockID("gtk-apply"), Gtk::RESPONSE_APPLY);
Gtk::FileFilter filter_pp;
filter_pp.set_name(M("FILECHOOSER_FILTER_CURVE"));
filter_pp.add_pattern("*.rtc");
dialog.add_filter(filter_pp);
Gtk::FileFilter filter_any;
filter_any.set_name(M("FILECHOOSER_FILTER_ANY"));
filter_any.add_pattern("*");
dialog.add_filter(filter_any);
int result = dialog.run();
Glib::ustring fname;
if (result==Gtk::RESPONSE_APPLY) {
fname = dialog.get_filename();
if (Glib::file_test (fname, Glib::FILE_TEST_EXISTS))
return fname;
}
fname = "";
return fname;
}

156
rtgui/curveeditorgroup.h Normal file
View File

@@ -0,0 +1,156 @@
/*
* 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 _CURVEEDITORGROUP_
#define _CURVEEDITORGROUP_
#include <gtkmm.h>
#include <fstream>
#include <string>
#include "guiutils.h"
#include "mycurve.h"
#include "myflatcurve.h"
#include "mydiagonalcurve.h"
#include "shcselector.h"
#include "adjuster.h"
class CurveEditor;
class DiagonalCurveEditorSubGroup;
class FlatCurveEditorSubGroup;
/*
* This class handle the curve widgets, shared between any number curve
* - to add a curve to the list, use the 'addCurve' method
* - to start a new line of curve button, use the 'newLine' method
* - if you add more than one curve, you must add a "CurveEditor* ce" parameter to your listener
*/
class CurveEditorGroup : public Gtk::VBox, public CurveListener {
friend class CurveEditor;
friend class CurveEditorSubGroup;
friend class DiagonalCurveEditorSubGroup;
friend class FlatCurveEditorSubGroup;
private:
Glib::ustring& curveDir;
protected:
Gtk::Label* curveGroupLabel;
Gtk::Button* curve_reset;
std::vector<CurveEditor*> curveEditors;
CurveEditor* displayedCurve;
FlatCurveEditorSubGroup* flatSubGroup;
DiagonalCurveEditorSubGroup* diagonalSubGroup;
CurveListener* cl;
unsigned int numberOfPackedCurve;
public:
/**
* @param curveDir The folder used by load and save dialogs for the curve.
* This variable will be updated with actions in the
* dialogs.
*/
CurveEditorGroup(Glib::ustring& curveDir, Glib::ustring groupLabel = "");
~CurveEditorGroup();
void newLine();
void curveListComplete();
void setBatchMode (bool batchMode);
void setCurveExternal (CurveEditor* ce, const std::vector<double>& c);
void setCurveListener (CurveListener* l) { cl = l; }
void setTooltip (Glib::ustring ttip);
CurveEditor* getDisplayedCurve () { return displayedCurve; }
//void on_realize ();
CurveEditor* addCurve(CurveType cType, Glib::ustring curveLabel, Gtk::Widget *relatedWidget=NULL, bool periodic=true);
protected:
//void curveTypeToggled ();
void curveTypeToggled (CurveEditor* ce);
//void typeSelectionChanged (int n);
void typeSelectionChanged (CurveEditor* ce, int n);
void hideCurrentCurve ();
void updateGUI (CurveEditor* ce);
void curveResetPressed ();
void curveChanged ();
float blendPipetteValues(CurveEditor* ce, float chan1, float chan2, float chan3);
void setUnChanged (bool uc, CurveEditor* ce);
};
class CoordinateProvider;
class CurveEditorSubGroup {
friend class CurveEditorGroup;
private:
Glib::ustring& curveDir;
Glib::ustring lastFilename;
protected:
int valLinear;
int valUnchanged;
CurveEditorGroup *parent;
int curveBBoxPos; // 0=above, 1=right, 2=below, 3=left
ColoredBar* leftBar;
ColoredBar* bottomBar;
public:
virtual ~CurveEditorSubGroup();
int getValUnchanged() { return valUnchanged; }
int getValLinear() { return valLinear; }
void updateEditButton(CurveEditor* curve, Gtk::ToggleButton *button, sigc::connection &connection);
virtual void updateBackgroundHistogram (CurveEditor* ce) {}
virtual void switchGUI() = 0;
virtual void refresh(CurveEditor *curveToRefresh) = 0;
virtual void editModeSwitchedOff() = 0;
virtual void showCoordinateAdjuster(CoordinateProvider *provider) = 0;
virtual void stopNumericalAdjustment() = 0;
virtual void pipetteMouseOver(EditDataProvider *provider, int modifierKey) =0;
virtual void pipetteButton1Pressed(EditDataProvider *provider, int modifierKey) =0;
virtual void pipetteButton1Released(EditDataProvider *provider) =0;
virtual void pipetteDrag(EditDataProvider *provider, int modifierKey) =0;
virtual bool curveReset (CurveEditor *ce) = 0; // Reset a curve editor, return TRUE if successful (curve changed)
protected:
/**
* @param curveDir The folder used by load and save dialogs for the curve.
* This variable will be updated with actions in the
* dialogs.
*/
CurveEditorSubGroup(Glib::ustring& curveDir);
Glib::ustring outputFile ();
Glib::ustring inputFile ();
virtual void storeCurveValues (CurveEditor* ce, const std::vector<double>& p) = 0;
virtual void storeDisplayedCurve () = 0;
virtual void restoreDisplayedHistogram() {};
virtual void removeEditor () = 0;
virtual const std::vector<double> getCurveFromGUI (int type) = 0;
};
#endif

73
rtgui/curvelistener.h Normal file
View File

@@ -0,0 +1,73 @@
/*
* 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 _CURVELISTENER_
#define _CURVELISTENER_
#include <vector>
class CurveEditor;
class CurveListener {
private:
bool multi;
public:
CurveListener() : multi(false) {}
virtual ~CurveListener() {}
virtual void curveChanged () {}
virtual void curveChanged (CurveEditor* ce) {}
void setMulti(bool value) { multi = value; }
bool isMulti() { return multi; }
/** @brief Ask the reset curve for a given curve type
* @param ce CurveEditor that we want to reset
* @param curve Actual curve for the return value. The actual curve type (given by the first value of the vector)
* should be kept the same. Change the curve type if REALLY necessary! */
virtual bool getResetCurve(CurveEditor *ce, std::vector<double> &curve) { return false; }
/** @brief Blend pipette values from its different channels into a single value
If the buffer has more than one channel and one channel, this method will blend them together.
@param chan1 first channel's value
@param chan2 second channel's value
@param chan3 third channel's value
@return the blended value */
virtual float blendPipetteValues(CurveEditor *ce, float chan1, float chan2, float chan3) {
float retVal = 0.f;
int n = 0;
if (chan1 != -1.f) {
retVal += chan1;
++n;
}
if (chan2 != -1.f) {
retVal += chan2;
++n;
}
if (chan3 != -1.f) {
retVal += chan3;
++n;
}
if (n>1)
retVal /= n;
else if (!n)
retVal = -1.f;
return retVal;
}
};
#endif

212
rtgui/darkframe.cc Normal file
View File

@@ -0,0 +1,212 @@
/*
* 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 "darkframe.h"
#include "options.h"
#include "guiutils.h"
#include "../rtengine/safegtk.h"
#include <sstream>
#include "rtimage.h"
using namespace rtengine;
using namespace rtengine::procparams;
DarkFrame::DarkFrame () : FoldableToolPanel(this, "darkframe", M("TP_DARKFRAME_LABEL"))
{
hbdf = Gtk::manage(new Gtk::HBox());
hbdf->set_spacing(4);
darkFrameFile = Gtk::manage(new MyFileChooserButton(M("TP_DARKFRAME_LABEL"), Gtk::FILE_CHOOSER_ACTION_OPEN));
darkFrameFilePersister.reset(new FileChooserLastFolderPersister(darkFrameFile, options.lastDarkframeDir));
dfLabel = Gtk::manage(new Gtk::Label(M("GENERAL_FILE")));
btnReset = Gtk::manage(new Gtk::Button());
btnReset->set_image (*Gtk::manage(new RTImage ("gtk-cancel.png")));
hbdf->pack_start(*dfLabel, Gtk::PACK_SHRINK, 0);
hbdf->pack_start(*darkFrameFile);
hbdf->pack_start(*btnReset, Gtk::PACK_SHRINK, 0);
dfAuto = Gtk::manage(new Gtk::CheckButton((M("TP_DARKFRAME_AUTOSELECT"))));
dfInfo = Gtk::manage(new Gtk::Label(""));
dfInfo->set_alignment(0,0); //left align
pack_start( *hbdf, Gtk::PACK_SHRINK, 0);
pack_start( *dfAuto, Gtk::PACK_SHRINK, 0);
pack_start( *dfInfo, Gtk::PACK_SHRINK, 0);
dfautoconn = dfAuto->signal_toggled().connect ( sigc::mem_fun(*this, &DarkFrame::dfAutoChanged), true);
dfFile = darkFrameFile->signal_file_set().connect ( sigc::mem_fun(*this, &DarkFrame::darkFrameChanged), true);
btnReset->signal_clicked().connect( sigc::mem_fun(*this, &DarkFrame::darkFrameReset), true );
// Set filename filters
b_filter_asCurrent = false;
Gtk::FileFilter *filter_any = Gtk::manage(new Gtk::FileFilter);
filter_any->add_pattern("*");
filter_any->set_name(M("FILECHOOSER_FILTER_ANY"));
darkFrameFile->add_filter (*filter_any);
// filters for all supported non-raw extensions
for (size_t i=0; i<options.parseExtensions.size(); i++) {
if (options.parseExtensionsEnabled[i] && options.parseExtensions[i].uppercase()!="JPG" && options.parseExtensions[i].uppercase()!="JPEG" && options.parseExtensions[i].uppercase()!="PNG" && options.parseExtensions[i].uppercase()!="TIF" && options.parseExtensions[i].uppercase()!="TIFF" )
{
Gtk::FileFilter *filter_df = Gtk::manage(new Gtk::FileFilter);
filter_df->add_pattern("*." + options.parseExtensions[i]);
filter_df->add_pattern("*." + options.parseExtensions[i].uppercase());
filter_df->set_name(options.parseExtensions[i].uppercase());
darkFrameFile->add_filter (*filter_df);
//printf("adding filter %s \n",options.parseExtensions[i].uppercase().c_str());
}
}
}
void DarkFrame::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited)
{
disableListener ();
dfautoconn.block(true);
dfAuto->set_active( pp->raw.df_autoselect );
if(pedited ){
dfAuto->set_inconsistent(!pedited->raw.dfAuto );
}
if (safe_file_test (pp->raw.dark_frame, Glib::FILE_TEST_EXISTS))
darkFrameFile->set_filename (pp->raw.dark_frame);
else
darkFrameReset();
hbdf->set_sensitive( !pp->raw.df_autoselect );
lastDFauto = pp->raw.df_autoselect;
if( pp->raw.df_autoselect && dfp && !multiImage){
// retrieve the auto-selected df filename
rtengine::RawImage *img = dfp->getDF();
if( img ){
dfInfo->set_text( Glib::ustring::compose("%1: %2ISO %3s", Glib::path_get_basename(img->get_filename()), img->get_ISOspeed(), img->get_shutter()) );
}else{
dfInfo->set_text(Glib::ustring(M("TP_PREPROCESS_NO_FOUND")));
}
}
else dfInfo->set_text("");
dfChanged = false;
dfautoconn.block(false);
enableListener ();
// Add filter with the current file extension if the current file is raw
if (dfp && !batchMode){
if (b_filter_asCurrent){
//First, remove last filter_asCurrent if it was set for a raw file
std::vector<const Gtk::FileFilter*> filters = darkFrameFile->list_filters();
darkFrameFile->remove_filter(**(filters.end()-1));
b_filter_asCurrent = false;
}
Glib::ustring fname = Glib::path_get_basename(dfp->GetCurrentImageFilePath());
Glib::ustring filetype;
if (fname!=""){
// get image filetype, set filter to the same as current image's filetype
std::string::size_type idx;
idx = fname.rfind('.');
if(idx != std::string::npos){
filetype = fname.substr(idx+1);
israw = filetype.uppercase()!="JPG" && filetype.uppercase()!="JPEG" && filetype.uppercase()!="PNG" && filetype.uppercase()!="TIF" && filetype.uppercase()!="TIFF";
//exclude non-raw
if (israw)
{
b_filter_asCurrent = true;
Gtk::FileFilter *filter_asCurrent = Gtk::manage(new Gtk::FileFilter);
filter_asCurrent->add_pattern("*." + filetype);
filter_asCurrent->set_name(M("FILECHOOSER_FILTER_SAME") + " (" + filetype + ")");
darkFrameFile->add_filter (*filter_asCurrent);
darkFrameFile->set_filter (*filter_asCurrent);
}
}
}
}
}
void DarkFrame::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pedited)
{
pp->raw.dark_frame = darkFrameFile->get_filename();
pp->raw.df_autoselect = dfAuto->get_active();
if (pedited) {
pedited->raw.darkFrame = dfChanged;
pedited->raw.dfAuto = !dfAuto->get_inconsistent();
}
}
void DarkFrame::dfAutoChanged()
{
if (batchMode) {
if (dfAuto->get_inconsistent()) {
dfAuto->set_inconsistent (false);
dfautoconn.block (true);
dfAuto->set_active (false);
dfautoconn.block (false);
}
else if (lastDFauto)
dfAuto->set_inconsistent (true);
lastDFauto = dfAuto->get_active ();
}
if(dfAuto->get_active() && dfp && !batchMode){
// retrieve the auto-selected df filename
rtengine::RawImage *img = dfp->getDF();
if( img ){
dfInfo->set_text( Glib::ustring::compose("%1: %2ISO %3s", Glib::path_get_basename(img->get_filename()), img->get_ISOspeed(), img->get_shutter()) );
}else{
dfInfo->set_text(Glib::ustring(M("TP_PREPROCESS_NO_FOUND")));
}
}
else{dfInfo->set_text("");}
hbdf->set_sensitive( !dfAuto->get_active() );
if (listener)
listener->panelChanged (EvPreProcessAutoDF, dfAuto->get_active()?M("GENERAL_ENABLED"):M("GENERAL_DISABLED"));
}
void DarkFrame::darkFrameChanged()
{
dfChanged=true;
if (listener)
listener->panelChanged (EvPreProcessDFFile, Glib::path_get_basename(darkFrameFile->get_filename()));
}
void DarkFrame::darkFrameReset()
{
dfChanged=true;
// caution: I had to make this hack, because set_current_folder() doesn't work correctly!
// Because szeva doesn't exist since he was committed to happy hunting ground in Issue 316
// we can use him now for this hack
darkFrameFile->set_filename (options.lastDarkframeDir + "/szeva");
// end of the hack
if (!options.lastDarkframeDir.empty())
darkFrameFile->set_current_folder(options.lastDarkframeDir);
dfInfo->set_text("");
if (listener)
listener->panelChanged (EvPreProcessDFFile, M("GENERAL_NONE"));
}

66
rtgui/darkframe.h Executable file
View File

@@ -0,0 +1,66 @@
/*
* 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 _DARKFRAME_H_
#define _DARKFRAME_H_
#include <memory>
#include <gtkmm.h>
#include "toolpanel.h"
#include "../rtengine/rawimage.h"
#include "guiutils.h"
class DFProvider {
public:
virtual rtengine::RawImage* getDF() = 0;
virtual Glib::ustring GetCurrentImageFilePath() = 0;
// add other info here
};
class DarkFrame : public ToolParamBlock, public FoldableToolPanel {
protected:
MyFileChooserButton *darkFrameFile;
std::auto_ptr<FileChooserLastFolderPersister> darkFrameFilePersister;
Gtk::HBox *hbdf;
Gtk::Button *btnReset;
Gtk::Label *dfLabel;
Gtk::Label *dfInfo;
Gtk::CheckButton* dfAuto;
bool dfChanged;
bool lastDFauto;
DFProvider *dfp;
sigc::connection dfautoconn, dfFile;
bool b_filter_asCurrent;
bool israw;
public:
DarkFrame ();
void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL);
void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL);
void darkFrameChanged ();
void darkFrameReset ();
void dfAutoChanged ();
void setDFProvider (DFProvider* p) { dfp = p; };
};
#endif

171
rtgui/defringe.cc Normal file
View File

@@ -0,0 +1,171 @@
/*
* 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 "defringe.h"
#include <iomanip>
#include <cmath>
using namespace rtengine;
using namespace rtengine::procparams;
Defringe::Defringe () : FoldableToolPanel(this, "defringe", M("TP_DEFRINGE_LABEL"), true, true) {
std::vector<GradientMilestone> bottomMilestones;
float R, G, B;
for (int i=0; i<7; i++) {
float x = float(i)*(1.0f/6.0);
Color::hsv2rgb01(x, 0.5f, 0.5f, R, G, B);
bottomMilestones.push_back( GradientMilestone(double(x), double(R), double(G), double(B)) );
}
setEnabledTooltipMarkup(M("TP_SHARPENING_TOOLTIP"));
curveEditorPF = new CurveEditorGroup (options.lastPFCurvesDir);
curveEditorPF->setCurveListener (this);
chshape = static_cast<FlatCurveEditor*>(curveEditorPF->addCurve(CT_Flat, M("TP_PFCURVE_CURVEEDITOR_CH")));
chshape->setTooltip(M("TP_PFCURVE_CURVEEDITOR_CH_TOOLTIP"));
chshape->setIdentityValue(0.);
chshape->setBottomBarBgGradient(bottomMilestones);
chshape->setCurveColorProvider(this, 1);
//edgConn = enabled->signal_toggled().connect( sigc::mem_fun(*this, &Defringe::edgeChanged) );
radius = Gtk::manage (new Adjuster (M("TP_DEFRINGE_RADIUS"), 0.5, 5.0, 0.1, 2.0));
threshold = Gtk::manage (new Adjuster (M("TP_DEFRINGE_THRESHOLD"), 0, 100, 1, 13));
radius->setAdjusterListener (this);
threshold->setAdjusterListener (this);
// radius->show();
// threshold->show();
pack_start (*radius);
pack_start (*threshold);
curveEditorPF->curveListComplete();
pack_start (*curveEditorPF, Gtk::PACK_SHRINK, 4);
show ();
}
Defringe::~Defringe () {
delete curveEditorPF;
}
void Defringe::colorForValue (double valX, double valY, enum ColorCaller::ElemType elemType, int callerId, ColorCaller *caller) {
float R, G, B;
if (elemType==ColorCaller::CCET_VERTICAL_BAR)
valY = 0.5;
if (callerId == 1) { // ch
Color::hsv2rgb01(float(valX), float(valY), 0.5f, R, G, B);
}
caller->ccRed = double(R);
caller->ccGreen = double(G);
caller->ccBlue = double(B);
}
void Defringe::read (const ProcParams* pp, const ParamsEdited* pedited) {
disableListener ();
if (pedited) {
radius->setEditedState ( pedited->defringe.radius ? Edited : UnEdited);
threshold->setEditedState ( pedited->defringe.threshold ? Edited : UnEdited);
set_inconsistent (multiImage && !pedited->defringe.enabled);
chshape->setUnChanged (!pedited->defringe.huecurve);
}
setEnabled(pp->defringe.enabled);
radius->setValue (pp->defringe.radius);
threshold->setValue (pp->defringe.threshold);
chshape->setCurve (pp->defringe.huecurve);
enableListener ();
}
void Defringe::autoOpenCurve () {
// WARNING: The following line won't work, since linear is a flat curve at 0.
// chshape->openIfNonlinear();
}
void Defringe::write (ProcParams* pp, ParamsEdited* pedited) {
pp->defringe.radius = radius->getValue ();
pp->defringe.threshold = (int)threshold->getValue ();
pp->defringe.enabled = getEnabled();
pp->defringe.huecurve = chshape->getCurve ();
if (pedited) {
pedited->defringe.radius = radius->getEditedState ();
pedited->defringe.threshold = threshold->getEditedState ();
pedited->defringe.enabled = !get_inconsistent();
pedited->defringe.huecurve = !chshape->isUnChanged ();
}
}
void Defringe::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) {
radius->setDefault (defParams->defringe.radius);
threshold->setDefault (defParams->defringe.threshold);
if (pedited) {
radius->setDefaultEditedState (pedited->defringe.radius ? Edited : UnEdited);
threshold->setDefaultEditedState (pedited->defringe.threshold ? Edited : UnEdited);
}
else {
radius->setDefaultEditedState (Irrelevant);
threshold->setDefaultEditedState (Irrelevant);
}
}
void Defringe::curveChanged () {
if (listener && getEnabled()) listener->panelChanged (EvPFCurve, M("HISTORY_CUSTOMCURVE"));
}
void Defringe::adjusterChanged (Adjuster* a, double newval) {
if (listener && getEnabled()) {
if (a==radius)
listener->panelChanged (EvDefringeRadius, Glib::ustring::format (std::setw(2), std::fixed, std::setprecision(1), a->getValue()));
else if (a==threshold)
listener->panelChanged (EvDefringeThreshold, Glib::ustring::format ((int)a->getValue()));
}
}
void Defringe::enabledChanged () {
if (listener) {
if (get_inconsistent())
listener->panelChanged (EvDefringeEnabled, M("GENERAL_UNCHANGED"));
else if (getEnabled())
listener->panelChanged (EvDefringeEnabled, M("GENERAL_ENABLED"));
else
listener->panelChanged (EvDefringeEnabled, M("GENERAL_DISABLED"));
}
}
void Defringe::setBatchMode (bool batchMode) {
ToolPanel::setBatchMode (batchMode);
radius->showEditedCB ();
threshold->showEditedCB ();
}

57
rtgui/defringe.h Normal file
View File

@@ -0,0 +1,57 @@
/*
* 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 _DEFRINGE_H_
#define _DEFRINGE_H_
#include <gtkmm.h>
#include "adjuster.h"
#include "toolpanel.h"
#include "guiutils.h"
#include "curveeditor.h"
#include "curveeditorgroup.h"
#include "colorprovider.h"
class Defringe : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel, public CurveListener, public ColorProvider{
protected:
CurveEditorGroup* curveEditorPF;
FlatCurveEditor* chshape;
Adjuster* radius;
Adjuster* threshold;
bool edges;
public:
Defringe ();
~Defringe ();
void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL);
void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL);
void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL);
void setBatchMode (bool batchMode);
void autoOpenCurve ();
void curveChanged ();
void adjusterChanged (Adjuster* a, double newval);
void enabledChanged ();
virtual void colorForValue (double valX, double valY, enum ColorCaller::ElemType elemType, int callerId, ColorCaller* caller);
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,113 @@
/*
* 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 _DIAGONALCURVEEDITORSUBGROUP_
#define _DIAGONALCURVEEDITORSUBGROUP_
#include <gtkmm.h>
#include "curveeditorgroup.h"
class DiagonalCurveEditor;
class DiagonalCurveEditorSubGroup : public CurveEditorSubGroup, public SHCListener, public AdjusterListener {
friend class DiagonalCurveEditor;
protected:
Gtk::VBox* customCurveBox;
Gtk::VBox* NURBSCurveBox;
Gtk::VBox* paramCurveBox;
MyDiagonalCurve* customCurve;
MyDiagonalCurve* NURBSCurve;
MyDiagonalCurve* paramCurve;
SHCSelector* shcSelector;
Adjuster* highlights;
Adjuster* lights;
Adjuster* darks;
Adjuster* shadows;
Adjuster *editedAdjuster;
int editedAdjusterValue;
CoordinateAdjuster *customCoordAdjuster;
CoordinateAdjuster *NURBSCoordAdjuster;
Gtk::Button* saveCustom;
Gtk::Button* loadCustom;
Gtk::Button* copyCustom;
Gtk::Button* pasteCustom;
Gtk::ToggleButton* editPointCustom;
Gtk::ToggleButton* editCustom;
sigc::connection editCustomConn, editPointCustomConn;
Gtk::Button* saveNURBS;
Gtk::Button* loadNURBS;
Gtk::Button* copyNURBS;
Gtk::Button* pasteNURBS;
Gtk::ToggleButton* editPointNURBS;
Gtk::ToggleButton* editNURBS;
sigc::connection editNURBSConn, editPointNURBSConn;
Gtk::Button* saveParam;
Gtk::Button* loadParam;
Gtk::Button* copyParam;
Gtk::Button* pasteParam;
Gtk::ToggleButton* editParam;
sigc::connection editParamConn;
int activeParamControl;
public:
DiagonalCurveEditorSubGroup(CurveEditorGroup* prt, Glib::ustring& curveDir);
virtual ~DiagonalCurveEditorSubGroup();
DiagonalCurveEditor* addCurve(Glib::ustring curveLabel = "");
virtual void updateBackgroundHistogram (CurveEditor* ce);
void switchGUI();
void refresh(CurveEditor *curveToRefresh);
void editModeSwitchedOff ();
void pipetteMouseOver(EditDataProvider *provider, int modifierKey);
void pipetteButton1Pressed(EditDataProvider *provider, int modifierKey);
void pipetteButton1Released(EditDataProvider *provider);
void pipetteDrag(EditDataProvider *provider, int modifierKey);
void showCoordinateAdjuster(CoordinateProvider *provider);
void stopNumericalAdjustment();
bool curveReset (CurveEditor *ce);
protected:
void storeCurveValues (CurveEditor* ce, const std::vector<double>& p);
void storeDisplayedCurve ();
void restoreDisplayedHistogram ();
void savePressed ();
void loadPressed ();
void copyPressed ();
void pastePressed ();
void editPointToggled(Gtk::ToggleButton *button);
void editToggled (Gtk::ToggleButton *button);
void removeEditor ();
const std::vector<double> getCurveFromGUI (int type);
void shcChanged ();
void adjusterChanged (Adjuster* a, double newval);
bool adjusterEntered (GdkEventCrossing* ev, int ac);
bool adjusterLeft (GdkEventCrossing* ev, int ac);
void setSubGroupRangeLabels(Glib::ustring r1, Glib::ustring r2, Glib::ustring r3, Glib::ustring r4);
void setSubGroupBottomBarBgGradient();
};
#endif

415
rtgui/dirbrowser.cc Normal file
View File

@@ -0,0 +1,415 @@
/*
* 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 "dirbrowser.h"
#ifdef WIN32
#define _WIN32_WINNT 0x0600
#include <windows.h>
#endif
#include "options.h"
#include "multilangmgr.h"
#include "../rtengine/safegtk.h"
#include <cstring>
#include "guiutils.h"
#include "rtimage.h"
#define CHECKTIME 5000
struct DirNameComparator {
template<class T>
bool operator()(T const &firstDir, T const &secondDir) const {
return options.dirBrowserSortType == Gtk::SORT_ASCENDING ? firstDir < secondDir : firstDir > secondDir;
}
};
DirBrowser::DirBrowser () : dirTreeModel(),
dtColumns(),
tvc(M("DIRBROWSER_FOLDERS")),
expandSuccess(false)
#ifdef WIN32
, volumes(0)
#endif
{
dirtree = Gtk::manage ( new Gtk::TreeView() );
scrolledwindow4 = Gtk::manage ( new Gtk::ScrolledWindow() );
// dirtree->set_flags(Gtk::CAN_FOCUS);
dirtree->set_headers_visible();
dirtree->set_headers_clickable();
dirtree->set_rules_hint(false);
dirtree->set_reorderable(false);
dirtree->set_enable_search(false);
scrolledwindow4->set_flags(Gtk::CAN_FOCUS);
scrolledwindow4->set_border_width(2);
scrolledwindow4->set_shadow_type(Gtk::SHADOW_NONE);
scrolledwindow4->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
scrolledwindow4->property_window_placement().set_value(Gtk::CORNER_TOP_LEFT);
scrolledwindow4->add(*dirtree);
pack_start (*scrolledwindow4);
dirtree->show ();
scrolledwindow4->show ();
}
void DirBrowser::fillDirTree () {
openfolder = safe_create_from_file ("gtk-open.png");
closedfolder = safe_create_from_file ("folder.png");
icdrom = safe_create_from_file ("drive-optical.png");
ifloppy = safe_create_from_file ("drive-removable-media.png");
ihdd = safe_create_from_file ("drive-harddisk.png");
iremovable = safe_create_from_file ("media-usb.png");
inetwork = safe_create_from_file ("network.png");
//Create the Tree model:
dirTreeModel = Gtk::TreeStore::create(dtColumns);
dirtree->set_model (dirTreeModel);
fillRoot ();
Gtk::CellRendererPixbuf* render_pb = Gtk::manage ( new Gtk::CellRendererPixbuf () );
tvc.pack_start (*render_pb, false);
tvc.add_attribute(*render_pb, "pixbuf-expander-closed", dtColumns.icon2);
tvc.add_attribute(*render_pb, "pixbuf", dtColumns.icon2);
tvc.add_attribute(*render_pb, "pixbuf-expander-open", dtColumns.icon1);
tvc.pack_start (crt);
tvc.add_attribute(crt, "text", dtColumns.filename);
dirtree->append_column(tvc);
tvc.set_sort_order(options.dirBrowserSortType);
tvc.set_sort_column(dtColumns.filename);
tvc.set_sort_indicator(true);
tvc.set_clickable();
dirTreeModel->set_sort_column(dtColumns.filename, options.dirBrowserSortType);
crt.property_ypad() = 0;
render_pb->property_ypad() = 0;
dirtree->signal_row_expanded().connect(sigc::mem_fun(*this, &DirBrowser::row_expanded));
dirtree->signal_row_activated().connect(sigc::mem_fun(*this, &DirBrowser::row_activated));
dirTreeModel->signal_sort_column_changed().connect(sigc::mem_fun(*this, &DirBrowser::on_sort_column_changed));
}
#ifdef WIN32
void DirBrowser::addRoot (char letter) {
char volume[4];
volume[0] = letter;
strcpy (volume+1, ":\\");
Gtk::TreeModel::iterator root = dirTreeModel->append();
root->set_value (dtColumns.filename, Glib::ustring(volume));
root->set_value (dtColumns.dirname, Glib::ustring(volume));
int type = GetDriveType (volume);
if (type==DRIVE_CDROM) {
root->set_value (0, icdrom);
root->set_value (1, icdrom);
}
else if (type==DRIVE_REMOVABLE) {
if (letter-'A'<2) {
root->set_value (0, ifloppy);
root->set_value (1, ifloppy);
}
else {
root->set_value (0, iremovable);
root->set_value (1, iremovable);
}
}
else if (type==DRIVE_REMOTE) {
root->set_value (0, inetwork);
root->set_value (1, inetwork);
}
else if (type==DRIVE_FIXED) {
root->set_value (0, ihdd);
root->set_value (1, ihdd);
}
Gtk::TreeModel::iterator child = dirTreeModel->append (root->children());
child->set_value (dtColumns.filename, Glib::ustring("foo"));
}
void DirBrowser::updateDirTreeRoot () {
for (Gtk::TreeModel::iterator i=dirTreeModel->children().begin(); i!=dirTreeModel->children().end(); i++)
updateDirTree (i);
}
void DirBrowser::updateDirTree (const Gtk::TreeModel::iterator& iter) {
if (dirtree->row_expanded (dirTreeModel->get_path (iter))) {
updateDir (iter);
for (Gtk::TreeModel::iterator i=iter->children().begin(); i!=iter->children().end(); i++)
updateDirTree (i);
}
}
void DirBrowser::updateVolumes () {
int nvolumes = GetLogicalDrives ();
if (nvolumes!=volumes) {
GThreadLock lock;
for (int i=0; i<32; i++)
if (((volumes >> i) & 1) && !((nvolumes >> i) & 1)) { // volume i has been deleted
for (Gtk::TreeModel::iterator iter = dirTreeModel->children().begin(); iter!=dirTreeModel->children().end(); iter++)
if (iter->get_value (dtColumns.filename).c_str()[0]-'A' == i) {
dirTreeModel->erase (iter);
break;
}
}
else if (!((volumes >> i) & 1) && ((nvolumes >> i) & 1))
addRoot ('A'+i); // volume i has been added
volumes = nvolumes;
}
}
int updateVolumesUI (void* br) {
(static_cast<DirBrowser*>(br))->updateVolumes ();
return 1;
}
int updateDirTreeUI (void* br) {
(static_cast<DirBrowser*>(br))->updateDirTreeRoot ();
return 0;
}
void DirBrowser::winDirChanged () {
g_idle_add (updateDirTreeUI, this);
}
#endif
void DirBrowser::fillRoot () {
#ifdef WIN32
volumes = GetLogicalDrives ();
for (int i=0; i<32; i++)
if ((volumes >> i) & 1)
addRoot ('A'+i);
// since sigc++ is not thread safe, we have to use the glib function
g_timeout_add (CHECKTIME, updateVolumesUI, this);
#else
Gtk::TreeModel::Row rootRow = *(dirTreeModel->append());
rootRow[dtColumns.filename] = "/";
rootRow[dtColumns.dirname] = "/";
Gtk::TreeModel::Row childRow = *(dirTreeModel->append(rootRow.children()));
childRow[dtColumns.filename] = "foo";
#endif
}
void DirBrowser::on_sort_column_changed() const {
options.dirBrowserSortType = tvc.get_sort_order();
}
void DirBrowser::row_expanded (const Gtk::TreeModel::iterator& iter, const Gtk::TreeModel::Path& path) {
expandSuccess = false;
// We will disable model's sorting because it decreases speed of inserting new items
// in list tree dramatically. Therefore will do:
// 1) Disable sorting in model
// 2) Manually sort data by DirNameComparator
// 3) Enable sorting in model again for UI (sorting by click on header)
int prevSortColumn;
Gtk::SortType prevSortType;
dirTreeModel->get_sort_column_id(prevSortColumn, prevSortType);
dirTreeModel->set_sort_column(Gtk::TreeSortable::DEFAULT_UNSORTED_COLUMN_ID, Gtk::SORT_ASCENDING);
typedef std::vector<Glib::ustring> DirPathType;
DirPathType subDirs;
Glib::RefPtr<Gio::File> dir = Gio::File::create_for_path (iter->get_value (dtColumns.dirname));
safe_build_subdir_list (dir, subDirs, options.fbShowHidden);
if (subDirs.empty()) {
dirtree->collapse_row(path);
}
else {
Gtk::TreeNodeChildren children = iter->children();
std::list<Gtk::TreeIter> forErase(children.begin(), children.end());
DirNameComparator comparator;
sort(subDirs.begin(), subDirs.end(), comparator);
for (DirPathType::const_iterator it = subDirs.begin(), end = subDirs.end(); it != end; ++it) {
addDir(iter, *it);
}
for (std::list<Gtk::TreeIter>::const_iterator it = forErase.begin(), end = forErase.end(); it != end; ++it) {
dirTreeModel->erase(*it);
}
dirTreeModel->set_sort_column(prevSortColumn, prevSortType);
expandSuccess = true;
}
#ifdef WIN32
Glib::RefPtr<WinDirMonitor> monitor = Glib::RefPtr<WinDirMonitor>(new WinDirMonitor (iter->get_value (dtColumns.dirname), this));
iter->set_value (dtColumns.monitor, monitor);
#else
Glib::RefPtr<Gio::FileMonitor> monitor = dir->monitor_directory ();
iter->set_value (dtColumns.monitor, monitor);
monitor->signal_changed().connect (sigc::bind(sigc::mem_fun(*this, &DirBrowser::file_changed), iter, dir->get_parse_name()));
#endif
}
void DirBrowser::updateDir (const Gtk::TreeModel::iterator& iter) {
// first test if some files are deleted
bool change = true;
while (change) {
change = false;
for (Gtk::TreeModel::iterator it=iter->children().begin(); it!=iter->children().end(); it++)
if (!safe_file_test (it->get_value (dtColumns.dirname), Glib::FILE_TEST_EXISTS)
|| !safe_file_test (it->get_value (dtColumns.dirname), Glib::FILE_TEST_IS_DIR)) {
GThreadLock lock;
dirTreeModel->erase (it);
change = true;
break;
}
}
// test if new files are created
std::vector<Glib::ustring> subDirs;
Glib::RefPtr<Gio::File> dir = Gio::File::create_for_path (iter->get_value (dtColumns.dirname));
safe_build_subdir_list (dir, subDirs, options.fbShowHidden);
for (int i=0; i<subDirs.size(); i++) {
bool found = false;
for (Gtk::TreeModel::iterator it=iter->children().begin(); it!=iter->children().end() && !found ; it++)
found = (it->get_value (dtColumns.filename)==subDirs[i]);
if (!found) {
GThreadLock lock;
addDir (iter, subDirs[i]);
}
}
}
void DirBrowser::addDir (const Gtk::TreeModel::iterator& iter, const Glib::ustring& dirname) {
Gtk::TreeModel::iterator child = dirTreeModel->append(iter->children());
child->set_value (dtColumns.filename, dirname);
child->set_value (dtColumns.icon1, openfolder);
child->set_value (dtColumns.icon2, closedfolder);
Glib::ustring fullname = Glib::build_filename (iter->get_value (dtColumns.dirname), dirname);
child->set_value (dtColumns.dirname, fullname);
Gtk::TreeModel::iterator fooRow = dirTreeModel->append(child->children());
fooRow->set_value (dtColumns.filename, Glib::ustring("foo"));
}
void DirBrowser::row_activated (const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column) {
Glib::ustring dname = dirTreeModel->get_iter (path)->get_value (dtColumns.dirname);
if (safe_file_test (dname, Glib::FILE_TEST_IS_DIR))
for (size_t i=0; i<dllisteners.size(); i++)
dllisteners[i]->dirSelected (dname);
}
Gtk::TreePath DirBrowser::expandToDir (const Glib::ustring& absDirPath) {
Gtk::TreeModel::Path path;
path.append_index(0);
char* dcpy = strdup (absDirPath.c_str());
char* dir = strtok (dcpy, "/\\");
int count = 0;
expandSuccess = true;
#ifndef WIN32
Gtk::TreeModel::iterator j = dirTreeModel->get_iter (path);
path.up ();
path.append_index (0);
row_expanded(j, path);
path.append_index (0);
#endif
while (dir) {
Glib::ustring dirstr = dir;
#ifdef WIN32
if (count==0)
dirstr = dirstr + "\\";
#endif
Gtk::TreeModel::iterator i = dirTreeModel->get_iter (path);
int ix = 0;
while (i && expandSuccess) {
Gtk::TreeModel::Row crow = *i;
Glib::ustring str =crow[dtColumns.filename];
#ifdef WIN32
if (str.casefold()==dirstr.casefold()) {
#else
if (str==dirstr) {
#endif
path.up ();
path.append_index (ix);
row_expanded(i, path);
path.append_index (0);
break;
}
ix++;
i++;
}
count++;
dir = strtok(NULL, "/\\");
}
free(dcpy);
path.up ();
dirtree->expand_to_path (path);
return path;
}
void DirBrowser::open (const Glib::ustring& dirname, const Glib::ustring& fileName) {
dirtree->collapse_all ();
// WARNING & TODO: One should test here if the directory/file has R/W access permission to avoid crash
Glib::RefPtr<Gio::File> dir = Gio::File::create_for_path(dirname);
if( !dir->query_exists())
return;
Glib::ustring absDirPath = dir->get_parse_name ();
Gtk::TreePath path = expandToDir (absDirPath);
dirtree->scroll_to_row (path);
dirtree->get_selection()->select (path);
Glib::ustring absFilePath;
if (!fileName.empty())
absFilePath = Glib::build_filename (absDirPath, fileName);
for (size_t i=0; i<dllisteners.size(); i++) {
dllisteners[i]->dirSelected (absDirPath, absFilePath);
}
}
void DirBrowser::file_changed (const Glib::RefPtr<Gio::File>& file, const Glib::RefPtr<Gio::File>& other_file, Gio::FileMonitorEvent event_type, const Gtk::TreeModel::iterator& iter, const Glib::ustring& dirName) {
if (!file || !safe_file_test (dirName, Glib::FILE_TEST_IS_DIR) || event_type==Gio::FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED)
return;
updateDir (iter);
}
void DirBrowser::selectDir (Glib::ustring dir) {
open (dir, "");
}

105
rtgui/dirbrowser.h Normal file
View File

@@ -0,0 +1,105 @@
/*
* 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 _DIRBROWSER_
#define _DIRBROWSER_
#include <gtkmm.h>
#include <giomm.h>
#ifdef WIN32
#include "windirmonitor.h"
#endif
#include "dirselectionlistener.h"
#include "dirbrowserremoteinterface.h"
class DirBrowser : public Gtk::VBox, public DirBrowserRemoteInterface
#ifdef WIN32
, public WinDirChangeListener
#endif
{
private:
Glib::RefPtr<Gtk::TreeStore> dirTreeModel;
struct DirTreeColumns : public Gtk::TreeModelColumnRecord {
public:
Gtk::TreeModelColumn<Glib::ustring> filename;
Gtk::TreeModelColumn<Glib::RefPtr<Gdk::Pixbuf> > icon1;
Gtk::TreeModelColumn<Glib::RefPtr<Gdk::Pixbuf> > icon2;
Gtk::TreeModelColumn<Glib::ustring> dirname;
#ifdef WIN32
Gtk::TreeModelColumn<Glib::RefPtr<WinDirMonitor> > monitor;
#else
Gtk::TreeModelColumn<Glib::RefPtr<Gio::FileMonitor> > monitor;
#endif
DirTreeColumns() { add(icon1); add(icon2); add(filename); add(dirname); add(monitor); }
};
DirTreeColumns dtColumns;
Gtk::TreeViewColumn tvc;
Gtk::CellRendererText crt;
Gtk::CellRendererPixbuf crb;
Gtk::TreeView *dirtree;
Gtk::ScrolledWindow *scrolledwindow4;
std::vector<DirSelectionListener*> dllisteners;
void fillRoot ();
Glib::RefPtr<Gdk::Pixbuf> openfolder;
Glib::RefPtr<Gdk::Pixbuf> closedfolder;
Glib::RefPtr<Gdk::Pixbuf> icdrom;
Glib::RefPtr<Gdk::Pixbuf> ifloppy;
Glib::RefPtr<Gdk::Pixbuf> ihdd;
Glib::RefPtr<Gdk::Pixbuf> inetwork;
Glib::RefPtr<Gdk::Pixbuf> iremovable;
bool expandSuccess;
#ifdef WIN32
int volumes;
public:
void updateVolumes ();
void updateDirTree (const Gtk::TreeModel::iterator& iter);
void updateDirTreeRoot ();
void winDirChanged ();
private:
void addRoot (char letter);
#endif
void addDir (const Gtk::TreeModel::iterator& iter, const Glib::ustring& dirname);
Gtk::TreePath expandToDir (const Glib::ustring& dirName);
void updateDir (const Gtk::TreeModel::iterator& iter);
void notifyListeners ();
public:
DirBrowser ();
void fillDirTree ();
void on_sort_column_changed() const;
void row_expanded (const Gtk::TreeModel::iterator& iter, const Gtk::TreeModel::Path& path);
void row_activated (const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column);
void file_changed (const Glib::RefPtr<Gio::File>& file, const Glib::RefPtr<Gio::File>& other_file, Gio::FileMonitorEvent event_type, const Gtk::TreeModel::iterator& iter, const Glib::ustring& dirName);
void open (const Glib::ustring& dirName, const Glib::ustring& fileName=""); // goes to dir "dirName" and selects file "fileName"
void addDirSelectionListener (DirSelectionListener* l) { dllisteners.push_back (l); }
void selectDir (Glib::ustring dir);
};
#endif

View File

@@ -0,0 +1,31 @@
/*
* 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 _DIRBROWSERREMOTEINTERFACE_
#define _DIRBROWSERREMOTEINTERFACE_
#include <glibmm.h>
class DirBrowserRemoteInterface {
public:
virtual void selectDir (Glib::ustring dir) {}
};
#endif

1220
rtgui/dirpyrdenoise.cc Normal file

File diff suppressed because it is too large Load Diff

140
rtgui/dirpyrdenoise.h Normal file
View File

@@ -0,0 +1,140 @@
/*
* 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 _DIRPYRDENOISE_H_
#define _DIRPYRDENOISE_H_
#include <gtkmm.h>
#include "adjuster.h"
#include "toolpanel.h"
#include "curveeditor.h"
#include "curveeditorgroup.h"
#include "colorprovider.h"
#include "guiutils.h"
#include "options.h"
class DirPyrDenoise : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel, public rtengine::AutoChromaListener, public CurveListener, public ColorProvider {
protected:
CurveEditorGroup* NoiscurveEditorG;
CurveEditorGroup* CCcurveEditorG;
Adjuster* luma;
Adjuster* Ldetail;
Adjuster* chroma;
Adjuster* redchro;
Adjuster* bluechro;
Adjuster* gamma;
Adjuster* passes;
FlatCurveEditor* lshape;
FlatCurveEditor* ccshape;
Gtk::CheckButton* enhance;
bool lastenhance;
sigc::connection enhanConn, medianConn, autochromaConn;
Gtk::CheckButton* median;
bool lastmedian;
Gtk::CheckButton* autochroma;
bool lastautochroma;
Gtk::Label* NoiseLabels;
Gtk::Label* TileLabels;
Gtk::Label* PrevLabels;
// Gtk::CheckButton* perform;
// bool lastperform;
// sigc::connection perfconn;
MyComboBoxText* dmethod;
sigc::connection dmethodconn;
MyComboBoxText* Lmethod;
sigc::connection Lmethodconn;
MyComboBoxText* Cmethod;
sigc::connection Cmethodconn;
MyComboBoxText* C2method;
sigc::connection C2methodconn;
MyComboBoxText* smethod;
sigc::connection smethodconn;
MyComboBoxText* medmethod;
sigc::connection medmethodconn;
Gtk::HBox* ctbox;
MyComboBoxText* methodmed;
sigc::connection methodmedconn;
Gtk::HBox* ctboxm;
MyComboBoxText* rgbmethod;
sigc::connection rgbmethodconn;
Gtk::HBox* ctboxrgb;
double nextchroma;
double nextred;
double nextblue;
double nextnresid;
double nexthighresid;
Gtk::HBox* ctboxL;
Gtk::HBox* ctboxC;
Gtk::HBox* ctboxC2;
int nexttileX;
int nexttileY;
int nextprevX;
int nextprevY;
int nextsizeT;
int nextsizeP;
public:
DirPyrDenoise ();
~DirPyrDenoise ();
void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL);
void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL);
void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL);
void setBatchMode (bool batchMode);
void curveChanged (CurveEditor* ce);
void setEditProvider (EditDataProvider *provider);
void autoOpenCurve ();
void adjusterChanged (Adjuster* a, double newval);
void enabledChanged ();
void enhanceChanged ();
void medianChanged ();
void autochromaChanged ();
void chromaChanged (double autchroma, double autred, double autblue);
bool chromaComputed_ ();
void noiseChanged (double nresid, double highresid);
bool noiseComputed_ ();
void noiseTilePrev (int tileX, int tileY, int prevX, int prevY, int sizeT, int sizeP);
bool TilePrevComputed_ ();
// void perform_toggled ();
void updateNoiseLabel ();
void LmethodChanged ();
void CmethodChanged ();
void C2methodChanged ();
void updateTileLabel ();
void updatePrevLabel ();
void dmethodChanged ();
void medmethodChanged ();
void methodmedChanged ();
void rgbmethodChanged ();
void smethodChanged ();
virtual void colorForValue (double valX, double valY, enum ColorCaller::ElemType elemType, int callerId, ColorCaller* caller);
void setAdjusterBehavior (bool lumaadd, bool lumdetadd, bool chromaadd, bool chromaredadd, bool chromablueadd, bool gammaadd, bool passesadd);
void trimValues (rtengine::procparams::ProcParams* pp);
Glib::ustring getSettingString ();
};
#endif

361
rtgui/dirpyrequalizer.cc Normal file
View File

@@ -0,0 +1,361 @@
/*
* This file is part of RawTherapee.
*
* 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/>.
*
* © 2010 Emil Martinec <ejmartin@uchicago.edu>
*/
#include "dirpyrequalizer.h"
using namespace rtengine;
using namespace rtengine::procparams;
DirPyrEqualizer::DirPyrEqualizer () : FoldableToolPanel(this, "dirpyrequalizer", M("TP_DIRPYREQUALIZER_LABEL"), true, true) {
std::vector<GradientMilestone> milestones;
float r, g, b;
Color::hsv2rgb01(0.7500, 0.5, 0.5, r, g, b); milestones.push_back( GradientMilestone(0. , r, g, b) ); // hsv: 0.75 rad: -0.9
Color::hsv2rgb01(0.8560, 0.5, 0.5, r, g, b); milestones.push_back( GradientMilestone(0.1470, r, g, b) ); // hsv: 0.856 rad: -0.4
Color::hsv2rgb01(0.9200, 0.5, 0.5, r, g, b); milestones.push_back( GradientMilestone(0.2353, r, g, b) ); // hsv: 0.92 rad: -0.1
Color::hsv2rgb01(0.9300, 0.5, 0.5, r, g, b); milestones.push_back( GradientMilestone(0.2647, r, g, b) ); // hsv: 0.93 rad: 0
Color::hsv2rgb01(0.9600, 0.5, 0.5, r, g, b); milestones.push_back( GradientMilestone(0.3380, r, g, b) ); // hsv: 0.96 rad: 0.25
Color::hsv2rgb01(1.0000, 0.5, 0.5, r, g, b); milestones.push_back( GradientMilestone(0.4412, r, g, b) ); // hsv: 1. rad: 0.6
Color::hsv2rgb01(0.0675, 0.5, 0.5, r, g, b); milestones.push_back( GradientMilestone(0.6176, r, g, b) ); // hsv: 0.0675 rad: 1.2
Color::hsv2rgb01(0.0900, 0.5, 0.5, r, g, b); milestones.push_back( GradientMilestone(0.6764, r, g, b) ); // hsv: 0.09 rad: 1.4
Color::hsv2rgb01(0.1700, 0.5, 0.5, r, g, b); milestones.push_back( GradientMilestone(0.7647, r, g, b) ); // hsv: 0.17 rad: 1.7
Color::hsv2rgb01(0.2650, 0.5, 0.5, r, g, b); milestones.push_back( GradientMilestone(0.8824, r, g, b) ); // hsv: 0.265 rad: 2.1
Color::hsv2rgb01(0.3240, 0.5, 0.5, r, g, b); milestones.push_back( GradientMilestone(1. , r, g, b) ); // hsv: 0.324 rad: 2.5
setEnabledTooltipMarkup(M("TP_SHARPENING_TOOLTIP"));
Gtk::HBox * buttonBox1 = Gtk::manage (new Gtk::HBox(true, 10));
pack_start(*buttonBox1);
Gtk::Button * lumacontrastMinusButton = Gtk::manage (new Gtk::Button(M("TP_DIRPYREQUALIZER_LUMACONTRAST_MINUS")));
buttonBox1->pack_start(*lumacontrastMinusButton);
lumacontrastMinusPressedConn = lumacontrastMinusButton->signal_pressed().connect( sigc::mem_fun(*this, &DirPyrEqualizer::lumacontrastMinusPressed));
Gtk::Button * lumaneutralButton = Gtk::manage (new Gtk::Button(M("TP_DIRPYREQUALIZER_LUMANEUTRAL")));
buttonBox1->pack_start(*lumaneutralButton);
lumaneutralPressedConn = lumaneutralButton->signal_pressed().connect( sigc::mem_fun(*this, &DirPyrEqualizer::lumaneutralPressed));
Gtk::Button * lumacontrastPlusButton = Gtk::manage (new Gtk::Button(M("TP_DIRPYREQUALIZER_LUMACONTRAST_PLUS")));
buttonBox1->pack_start(*lumacontrastPlusButton);
lumacontrastPlusPressedConn = lumacontrastPlusButton->signal_pressed().connect( sigc::mem_fun(*this, &DirPyrEqualizer::lumacontrastPlusPressed));
buttonBox1->show_all_children();
Gtk::HSeparator *separator2 = Gtk::manage (new Gtk::HSeparator());
pack_start(*separator2, Gtk::PACK_SHRINK, 2);
for(int i = 0; i < 6; i++)
{
Glib::ustring ss;
ss = Glib::ustring::format(i);
if (i == 0) ss += Glib::ustring::compose(" (%1)", M("TP_DIRPYREQUALIZER_LUMAFINEST"));
else if(i == 5) ss += Glib::ustring::compose(" (%1)", M("TP_DIRPYREQUALIZER_LUMACOARSEST"));
multiplier[i] = Gtk::manage ( new Adjuster (ss, 0, 4, 0.01, 1.0) );
multiplier[i]->setAdjusterListener(this);
pack_start(*multiplier[i]);
}
Gtk::HSeparator *separator3 = Gtk::manage (new Gtk::HSeparator());
pack_start(*separator3, Gtk::PACK_SHRINK, 2);
threshold = Gtk::manage ( new Adjuster (M("TP_DIRPYREQUALIZER_THRESHOLD"), 0, 1, 0.01, 0.2) );
threshold->setAdjusterListener(this);
pack_start(*threshold);
Gtk::HSeparator *separator4 = Gtk::manage (new Gtk::HSeparator());
pack_start(*separator4, Gtk::PACK_SHRINK, 2);
/*
algoHBox = Gtk::manage (new Gtk::HBox ());
algoHBox->set_border_width (0);
algoHBox->set_spacing (2);
algoHBox->set_tooltip_markup (M("TP_DIRPYREQUALIZER_ALGO_TOOLTIP"));
*/
// alLabel = Gtk::manage (new Gtk::Label (M("TP_DIRPYREQUALIZER_ALGO")+":"));
// algoHBox->pack_start (*alLabel, Gtk::PACK_SHRINK);
/*
algo = Gtk::manage (new MyComboBoxText ());
algo->append_text (M("TP_DIRPYREQUALIZER_ALGO_FI"));
algo->append_text (M("TP_DIRPYREQUALIZER_ALGO_LA"));
algo->set_active (1);
// algoHBox->pack_start (*algo);
// pack_start(*algoHBox);
algoconn = algo->signal_changed().connect ( sigc::mem_fun(*this, &DirPyrEqualizer::algoChanged) );
*/
hueskin = Gtk::manage (new ThresholdAdjuster (M("TP_DIRPYREQUALIZER_HUESKIN"), -40., 210., -5., 25., 170., 120., 0, false)); //default (b_l 0, t_l 30, b_r 170, t_r 120);
hueskin->set_tooltip_markup (M("TP_DIRPYREQUALIZER_HUESKIN_TOOLTIP"));
hueskin->setBgGradient(milestones);
pack_start(*hueskin);
skinprotect = Gtk::manage ( new Adjuster (M("TP_DIRPYREQUALIZER_SKIN"), -100, 100, 1, 0.) );
skinprotect->setAdjusterListener(this);
pack_start(*skinprotect);
skinprotect->set_tooltip_markup (M("TP_DIRPYREQUALIZER_SKIN_TOOLTIP"));
gamutlab = Gtk::manage (new Gtk::CheckButton (M("TP_DIRPYREQUALIZER_ARTIF")));
gamutlab->set_active (true);
pack_start(*gamutlab);
gamutlabConn = gamutlab->signal_toggled().connect( sigc::mem_fun(*this, &DirPyrEqualizer::gamutlabToggled) );
gamutlab->set_tooltip_markup (M("TP_DIRPYREQUALIZER_TOOLTIP"));
hueskin->setAdjusterListener (this);
show_all_children ();
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
}
DirPyrEqualizer::~DirPyrEqualizer () {
}
void DirPyrEqualizer::read (const ProcParams* pp, const ParamsEdited* pedited) {
disableListener ();
if (pedited) {
set_inconsistent (multiImage && !pedited->dirpyrequalizer.enabled);
gamutlab->set_inconsistent (!pedited->dirpyrequalizer.gamutlab);
for(int i = 0; i < 6; i++) {
multiplier[i]->setEditedState (pedited->dirpyrequalizer.mult[i] ? Edited : UnEdited);
}
threshold->setEditedState (pedited->dirpyrequalizer.threshold ? Edited : UnEdited);
skinprotect->setEditedState (pedited->dirpyrequalizer.skinprotect ? Edited : UnEdited);
hueskin->setEditedState (pedited->dirpyrequalizer.hueskin ? Edited : UnEdited);
}
setEnabled(pp->dirpyrequalizer.enabled);
/*
algoconn.block(true);
if (pedited && !pedited->dirpyrequalizer.algo)
algo->set_active (2);
else if (pp->dirpyrequalizer.algo=="FI")
algo->set_active (0);
else if (pp->dirpyrequalizer.algo=="LA")
algo->set_active (1);
algoconn.block(false);
algoChanged();
*/
gamutlabConn.block (true);
gamutlab->set_active (pp->dirpyrequalizer.gamutlab);
gamutlabConn.block (false);
lastgamutlab = pp->dirpyrequalizer.gamutlab;
for (int i = 0; i < 6; i++) {
multiplier[i]->setValue(pp->dirpyrequalizer.mult[i]);
}
threshold->setValue(pp->dirpyrequalizer.threshold);
skinprotect->setValue(pp->dirpyrequalizer.skinprotect);
hueskin->setValue<int>(pp->dirpyrequalizer.hueskin);
enableListener ();
}
void DirPyrEqualizer::write (ProcParams* pp, ParamsEdited* pedited) {
pp->dirpyrequalizer.enabled = getEnabled();
pp->dirpyrequalizer.gamutlab = gamutlab->get_active ();
pp->dirpyrequalizer.hueskin = hueskin->getValue<int> ();
for (int i = 0; i < 6; i++) {
pp->dirpyrequalizer.mult[i] = multiplier[i]->getValue();
}
pp->dirpyrequalizer.threshold = threshold->getValue();
pp->dirpyrequalizer.skinprotect = skinprotect->getValue();
if (pedited) {
pedited->dirpyrequalizer.enabled = !get_inconsistent();
pedited->dirpyrequalizer.hueskin = hueskin->getEditedState ();
for(int i = 0; i < 6; i++) {
pedited->dirpyrequalizer.mult[i] = multiplier[i]->getEditedState();
}
pedited->dirpyrequalizer.threshold = threshold->getEditedState();
pedited->dirpyrequalizer.skinprotect = skinprotect->getEditedState();
// pedited->dirpyrequalizer.algo = algo->get_active_text()!=M("GENERAL_UNCHANGED");
}
/* if (algo->get_active_row_number()==0)
pp->dirpyrequalizer.algo = "FI";
else if (algo->get_active_row_number()==1)
pp->dirpyrequalizer.algo = "LA";
*/
}
/*
void DirPyrEqualizer::algoChanged () {
if (listener && (multiImage||enabled->get_active()) ) {
listener->panelChanged (EvDirPyrEqualizeralg, algo->get_active_text ());}
}
*/
void DirPyrEqualizer::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) {
for (int i = 0; i < 6; i++) {
multiplier[i]->setDefault(defParams->dirpyrequalizer.mult[i]);
}
threshold->setDefault(defParams->dirpyrequalizer.threshold);
hueskin->setDefault<int> (defParams->dirpyrequalizer.hueskin);
if (pedited) {
for (int i = 0; i < 6; i++) {
multiplier[i]->setDefaultEditedState(pedited->dirpyrequalizer.mult[i] ? Edited : UnEdited);
}
threshold->setDefaultEditedState(pedited->dirpyrequalizer.threshold ? Edited : UnEdited);
skinprotect->setDefaultEditedState(pedited->dirpyrequalizer.skinprotect ? Edited : UnEdited);
hueskin->setDefaultEditedState (pedited->dirpyrequalizer.hueskin ? Edited : UnEdited);
}
else {
for (int i = 0; i < 6; i++) {
multiplier[i]->setDefaultEditedState(Irrelevant);
}
threshold->setDefaultEditedState(Irrelevant);
skinprotect->setDefaultEditedState(Irrelevant);
hueskin->setDefaultEditedState (Irrelevant);
}
}
void DirPyrEqualizer::adjusterChanged (ThresholdAdjuster* a, int newBottomLeft, int newTopLeft, int newBottomRight, int newTopRight) {
if (listener && (multiImage||getEnabled()) ) {
listener->panelChanged (EvDirPyrEqualizerHueskin, hueskin->getHistoryString());
}
}
void DirPyrEqualizer::setBatchMode (bool batchMode) {
ToolPanel::setBatchMode (batchMode);
for (int i = 0; i < 6; i++) {
multiplier[i]->showEditedCB();
}
threshold->showEditedCB();
skinprotect->showEditedCB();
hueskin->showEditedCB ();
// algo->append_text (M("GENERAL_UNCHANGED"));
}
void DirPyrEqualizer::adjusterChanged (Adjuster* a, double newval) {
if (listener && getEnabled()) {
if (a == threshold) {
listener->panelChanged (EvDirPyrEqualizerThreshold,
Glib::ustring::compose("%1",
Glib::ustring::format(std::fixed, std::setprecision(2), threshold->getValue()))
);
}
else if (a == skinprotect) {
listener->panelChanged (EvDirPyrEqualizerSkin,
Glib::ustring::compose("%1",
Glib::ustring::format(std::fixed, std::setprecision(2), skinprotect->getValue()))
);
}
else {
listener->panelChanged (EvDirPyrEqualizer,
Glib::ustring::compose("%1, %2, %3, %4, %5, %6",
Glib::ustring::format(std::fixed, std::setprecision(2), multiplier[0]->getValue()),
Glib::ustring::format(std::fixed, std::setprecision(2), multiplier[1]->getValue()),
Glib::ustring::format(std::fixed, std::setprecision(2), multiplier[2]->getValue()),
Glib::ustring::format(std::fixed, std::setprecision(2), multiplier[3]->getValue()),
Glib::ustring::format(std::fixed, std::setprecision(2), multiplier[4]->getValue()),
Glib::ustring::format(std::fixed, std::setprecision(2), multiplier[5]->getValue()))
);
}
}
}
void DirPyrEqualizer::enabledChanged () {
if (listener) {
if (get_inconsistent())
listener->panelChanged (EvDirPyrEqlEnabled, M("GENERAL_UNCHANGED"));
else if (getEnabled())
listener->panelChanged (EvDirPyrEqlEnabled, M("GENERAL_ENABLED"));
else
listener->panelChanged (EvDirPyrEqlEnabled, M("GENERAL_DISABLED"));
}
}
void DirPyrEqualizer::gamutlabToggled () {
if (batchMode) {
if (gamutlab->get_inconsistent()) {
gamutlab->set_inconsistent (false);
gamutlabConn.block (true);
gamutlab->set_active (false);
gamutlabConn.block (false);
}
else if (lastgamutlab)
gamutlab->set_inconsistent (true);
lastgamutlab = gamutlab->get_active ();
}
if (listener) {
if (gamutlab->get_active ())
listener->panelChanged (EvDirPyrEqlgamutlab, M("GENERAL_ENABLED"));
else
listener->panelChanged (EvDirPyrEqlgamutlab, M("GENERAL_DISABLED"));
}
}
void DirPyrEqualizer::lumaneutralPressed () {
for (int i = 0; i < 6; i++) {
multiplier[i]->setValue(1.0);
adjusterChanged(multiplier[i], 1.0);
}
}
void DirPyrEqualizer::lumacontrastPlusPressed () {
for (int i = 0; i < 6; i++) {
float inc = 0.05 * (6 - i);
multiplier[i]->setValue(multiplier[i]->getValue() + inc);
adjusterChanged(multiplier[i], multiplier[i]->getValue());
}
}
void DirPyrEqualizer::lumacontrastMinusPressed () {
for (int i = 0; i < 6; i++) {
float inc = -0.05 * (6 - i);
multiplier[i]->setValue(multiplier[i]->getValue() + inc);
adjusterChanged(multiplier[i], multiplier[i]->getValue());
}
}
void DirPyrEqualizer::setAdjusterBehavior (bool multiplieradd, bool thresholdadd, bool skinadd) {
for (int i=0; i<6; i++)
multiplier[i]->setAddMode(multiplieradd);
threshold->setAddMode(thresholdadd);
skinprotect->setAddMode(skinadd);
}
void DirPyrEqualizer::trimValues (rtengine::procparams::ProcParams* pp) {
for (int i=0; i<6; i++)
multiplier[i]->trimValue(pp->dirpyrequalizer.mult[i]);
threshold->trimValue(pp->dirpyrequalizer.threshold);
skinprotect->trimValue(pp->dirpyrequalizer.skinprotect);
}

73
rtgui/dirpyrequalizer.h Normal file
View File

@@ -0,0 +1,73 @@
/*
* This file is part of RawTherapee.
*
* 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/>.
*
* © 2010 Emil Martinec <ejmartin@uchicago.edu>
*/
#ifndef DIRPYREQUALIZER_H_INCLUDED
#define DIRPYREQUALIZER_H_INCLUDED
#include <gtkmm.h>
#include "adjuster.h"
#include "toolpanel.h"
#include "thresholdadjuster.h"
#include "colorprovider.h"
class DirPyrEqualizer : public ToolParamBlock, public ThresholdAdjusterListener, public AdjusterListener, public FoldableToolPanel
{
protected:
Gtk::CheckButton * gamutlab;
Adjuster* multiplier[6];
Adjuster* threshold;
Adjuster* skinprotect;
ThresholdAdjuster* hueskin;
// MyComboBoxText* algo;
// sigc::connection algoconn;
// Gtk::Label* alLabel;
// Gtk::HBox* algoHBox;
sigc::connection gamutlabConn;
sigc::connection lumaneutralPressedConn;
sigc::connection lumacontrastPlusPressedConn;
sigc::connection lumacontrastMinusPressedConn;
bool lastgamutlab;
public:
DirPyrEqualizer ();
virtual ~DirPyrEqualizer ();
void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL);
void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL);
void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL);
void setBatchMode (bool batchMode);
void setAdjusterBehavior (bool multiplieradd, bool thresholdadd, bool skinadd);
void trimValues (rtengine::procparams::ProcParams* pp);
void adjusterChanged (ThresholdAdjuster* a, int newBottomLeft, int newTopLeft, int newBottomRight, int newTopRight);
// void algoChanged ();
void adjusterChanged (Adjuster* a, double newval);
void enabledChanged();
void gamutlabToggled ();
void lumaneutralPressed ();
void lumacontrastPlusPressed ();
void lumacontrastMinusPressed ();
};
#endif

View File

@@ -0,0 +1,31 @@
/*
* 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 _DIRSELECTIONLISTENER_
#define _DIRSELECTIONLISTENER_
#include <glibmm.h>
class DirSelectionListener {
public:
virtual ~DirSelectionListener () {}
virtual void dirSelected (const Glib::ustring& dirname, const Glib::ustring& openfile="") {}
};
#endif

112
rtgui/distortion.cc Normal file
View File

@@ -0,0 +1,112 @@
/*
* 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 "distortion.h"
#include <iomanip>
#include "rtimage.h"
using namespace rtengine;
using namespace rtengine::procparams;
Distortion::Distortion (): FoldableToolPanel(this, "distortion", M("TP_DISTORTION_LABEL")) {
rlistener = NULL;
autoDistor = Gtk::manage (new Gtk::Button (M("TP_DISTORTION_AUTO")));
autoDistor->set_image (*Gtk::manage (new RTImage ("distortion-auto.png")));
autoDistor->set_tooltip_text (M("TP_DISTORTION_AUTO_TIP"));
idConn = autoDistor->signal_pressed().connect( sigc::mem_fun(*this, &Distortion::idPressed) );
autoDistor->show();
pack_start (*autoDistor);
Gtk::Image* idistL = Gtk::manage (new RTImage ("distortion-pincushion.png"));
Gtk::Image* idistR = Gtk::manage (new RTImage ("distortion-barrel.png"));
distor = Gtk::manage (new Adjuster (M("TP_DISTORTION_AMOUNT"), -0.5, 0.5, 0.001, 0, idistL, idistR));
distor->setAdjusterListener (this);
distor->show();
pack_start (*distor);
}
void Distortion::read (const ProcParams* pp, const ParamsEdited* pedited) {
disableListener ();
if (pedited) {
distor->setEditedState (pedited->distortion.amount ? Edited : UnEdited);
}
distor->setValue (pp->distortion.amount);
enableListener ();
}
void Distortion::write (ProcParams* pp, ParamsEdited* pedited) {
pp->distortion.amount = distor->getValue ();
if (pedited) {
pedited->distortion.amount = distor->getEditedState ();
}
}
void Distortion::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) {
distor->setDefault (defParams->distortion.amount);
if (pedited) {
distor->setDefaultEditedState (pedited->distortion.amount ? Edited : UnEdited);
}
else {
distor->setDefaultEditedState (Irrelevant);
}
}
void Distortion::adjusterChanged (Adjuster* a, double newval) {
if (listener)
listener->panelChanged (EvDISTAmount, Glib::ustring::format (std::setw(4), std::fixed, std::setprecision(3), a->getValue()));
}
void Distortion::setBatchMode (bool batchMode) {
ToolPanel::setBatchMode (batchMode);
if (batchMode) {
autoDistor->set_sensitive(false);
}
distor->showEditedCB ();
}
void Distortion::idPressed () {
if (!batchMode) {
if (rlistener) {
double new_amount = rlistener->autoDistorRequested();
distor->setValue(new_amount);
adjusterChanged (distor, new_amount);
}
}
}
void Distortion::setAdjusterBehavior (bool vadd) {
distor->setAddMode(vadd);
}
void Distortion::trimValues (rtengine::procparams::ProcParams* pp) {
distor->trimValue(pp->distortion.amount);
}

51
rtgui/distortion.h Normal file
View File

@@ -0,0 +1,51 @@
/*
* 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 _DISTORTION_H_
#define _DISTORTION_H_
#include <gtkmm.h>
#include "adjuster.h"
#include "toolpanel.h"
#include "lensgeomlistener.h"
class Distortion : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel {
protected:
Gtk::Button* autoDistor;
Adjuster* distor;
sigc::connection idConn;
LensGeomListener * rlistener;
public:
Distortion ();
void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL);
void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL);
void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL);
void setBatchMode (bool batchMode);
void adjusterChanged (Adjuster* a, double newval);
void setAdjusterBehavior (bool vadd);
void trimValues (rtengine::procparams::ProcParams* pp);
void idPressed ();
void setLensGeomListener (LensGeomListener* l) { rlistener = l; }
};
#endif

621
rtgui/edit.cc Normal file
View File

@@ -0,0 +1,621 @@
/*
* 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 "edit.h"
#include "../rtengine/editbuffer.h"
void Coord::setFromPolar(PolarCoord polar) {
while (polar.angle < 0.f) polar.angle += 360.f;
while (polar.angle > 360.f) polar.angle -= 360.f;
x = polar.radius * cos(polar.angle/180.f*M_PI);
y = polar.radius * sin(polar.angle/180.f*M_PI);
}
RGBColor Geometry::getInnerLineColor () {
RGBColor color;
if (flags & AUTO_COLOR) {
if (state == NORMAL) { color.setColor (1., 1., 1.); } // White
else if (state == PRELIGHT) { color.setColor (1., 1., 0.); } // Orange
else if (state == DRAGGED) { color.setColor (1., 0., 0.); } // Red
}
else { color = innerLineColor; }
return color;
}
RGBColor Geometry::getOuterLineColor () {
RGBColor color;
if (flags & AUTO_COLOR) {
/*
if (state == NORMAL) { color.setColor (0., 0., 0.); } // Black
else if (state == PRELIGHT) { color.setColor (0., 0., 0.); } // Black
else if (state == DRAGGED) { color.setColor (1., 0., 0.); } // Black
*/
color.setColor (0., 0., 0.); // Black
}
else { color = outerLineColor; }
return color;
}
void Circle::drawOuterGeometry(Cairo::RefPtr<Cairo::Context> &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem) {
if (flags & ACTIVE) {
RGBColor color;
if (flags & AUTO_COLOR)
color = getOuterLineColor();
else
color = outerLineColor;
cr->set_source_rgb (color.getR(), color.getG(), color.getB());
cr->set_line_width( getOuterLineWidth() );
Coord center_ = center;
double radius_ = radiusInImageSpace ? coordSystem.scaleValueToScreen(double(radius)) : double(radius);
if (datum == IMAGE) {
coordSystem.imageCoordToScreen(center.x, center.y, center_.x, center_.y);
}
else if (datum == CLICKED_POINT) {
center_ += editBuffer->getDataProvider()->posScreen;
}
else if (datum == CURSOR) {
center_ += editBuffer->getDataProvider()->posScreen + editBuffer->getDataProvider()->deltaPrevScreen;
}
cr->arc(center_.x+0.5, center_.y+0.5, radius_, 0., 2.*M_PI);
cr->stroke();
}
}
void Circle::drawInnerGeometry(Cairo::RefPtr<Cairo::Context> &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem) {
if (flags & ACTIVE) {
RGBColor color;
if (flags & AUTO_COLOR)
color = getInnerLineColor();
else
color = innerLineColor;
cr->set_source_rgb (color.getR(), color.getG(), color.getB());
cr->set_line_width( innerLineWidth );
Coord center_ = center;
double radius_ = radiusInImageSpace ? coordSystem.scaleValueToScreen(double(radius)) : double(radius);
if (datum == IMAGE) {
coordSystem.imageCoordToScreen(center.x, center.y, center_.x, center_.y);
}
else if (datum == CLICKED_POINT) {
center_ += editBuffer->getDataProvider()->posScreen;
}
else if (datum == CURSOR) {
center_ += editBuffer->getDataProvider()->posScreen + editBuffer->getDataProvider()->deltaPrevScreen;
}
if (filled) {
cr->arc(center_.x+0.5, center_.y+0.5, radius_, 0., 2.*M_PI);
if (innerLineWidth > 0.) {
cr->fill_preserve();
cr->stroke();
}
else
cr->fill();
}
else if (innerLineWidth > 0.) {
cr->arc(center_.x+0.5, center_.y+0.5, radius_, 0., 2.*M_PI);
cr->stroke();
}
}
}
void Circle::drawToMOChannel (Cairo::RefPtr<Cairo::Context> &cr, Cairo::RefPtr<Cairo::Context> &cr2, unsigned short id, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem) {
if (flags & ACTIVE) {
cr->set_line_width( getMouseOverLineWidth() );
Coord center_ = center;
double radius_ = radiusInImageSpace ? coordSystem.scaleValueToScreen(double(radius)) : double(radius);
if (datum == IMAGE) {
coordSystem.imageCoordToCropBuffer(center.x, center.y, center_.x, center_.y);
}
else if (datum == CLICKED_POINT) {
center_ += editBuffer->getDataProvider()->posScreen;
}
else if (datum == CURSOR) {
center_ += editBuffer->getDataProvider()->posScreen + editBuffer->getDataProvider()->deltaPrevScreen;
}
// drawing the lower byte's value
unsigned short a = (id+1) & 0xFF;
cr->set_source_rgba (0.,0., 0., double(a)/255.);
cr->arc(center_.x+0.5, center_.y+0.5, radius_, 0, 2.*M_PI);
if (filled) {
if (innerLineWidth > 0.) {
cr->fill_preserve();
cr->stroke();
}
else
cr->fill();
}
else
cr->stroke();
// drawing the higher byte's value
if (editBuffer->getObjectMode() == OM_65535) {
a = (id+1)>>8;
cr2->set_source_rgba (0.,0., 0., double(a)/255.);
cr2->arc(center_.x+0.5, center_.y+0.5, radius_, 0, 2.*M_PI);
if (filled) {
if (innerLineWidth > 0.) {
cr2->fill_preserve();
cr2->stroke();
}
else
cr2->fill();
}
else
cr2->stroke();
}
}
}
void Line::drawOuterGeometry(Cairo::RefPtr<Cairo::Context> &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem) {
if (flags & ACTIVE) {
RGBColor color;
if (flags & AUTO_COLOR)
color = getOuterLineColor();
else
color = outerLineColor;
cr->set_source_rgb (color.getR(), color.getG(), color.getB());
cr->set_line_width( getOuterLineWidth() );
Coord begin_ = begin;
Coord end_ = end;
if (datum == IMAGE) {
coordSystem.imageCoordToScreen(begin.x, begin.y, begin_.x, begin_.y);
coordSystem.imageCoordToScreen(end.x, end.y, end_.x, end_.y);
}
else if (datum == CLICKED_POINT) {
begin_ += editBuffer->getDataProvider()->posScreen;
end_ += editBuffer->getDataProvider()->posScreen;
}
else if (datum == CURSOR) {
begin_ += editBuffer->getDataProvider()->posScreen + editBuffer->getDataProvider()->deltaPrevScreen;
end_ += editBuffer->getDataProvider()->posScreen + editBuffer->getDataProvider()->deltaPrevScreen;
}
cr->move_to(begin_.x+0.5, begin_.y+0.5);
cr->line_to(end_.x+0.5, end_.y+0.5);
cr->stroke();
}
}
void Line::drawInnerGeometry(Cairo::RefPtr<Cairo::Context> &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem) {
if ((flags & ACTIVE) && innerLineWidth > 0.) {
RGBColor color;
if (flags & AUTO_COLOR)
color = getInnerLineColor();
else
color = innerLineColor;
cr->set_source_rgb (color.getR(), color.getG(), color.getB());
cr->set_line_width(innerLineWidth);
Coord begin_ = begin;
Coord end_ = end;
if (datum == IMAGE) {
coordSystem.imageCoordToScreen(begin.x, begin.y, begin_.x, begin_.y);
coordSystem.imageCoordToScreen(end.x, end.y, end_.x, end_.y);
}
else if (datum == CLICKED_POINT) {
begin_ += editBuffer->getDataProvider()->posScreen;
end_ += editBuffer->getDataProvider()->posScreen;
}
else if (datum == CURSOR) {
begin_ += editBuffer->getDataProvider()->posScreen + editBuffer->getDataProvider()->deltaPrevScreen;
end_ += editBuffer->getDataProvider()->posScreen + editBuffer->getDataProvider()->deltaPrevScreen;
}
cr->move_to(begin_.x+0.5, begin_.y+0.5);
cr->line_to(end_.x+0.5, end_.y+0.5);
cr->stroke();
}
}
void Line::drawToMOChannel (Cairo::RefPtr<Cairo::Context> &cr, Cairo::RefPtr<Cairo::Context> &cr2, unsigned short id, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem) {
if (flags & ACTIVE) {
cr->set_line_width( getMouseOverLineWidth() );
Coord begin_ = begin;
Coord end_ = end;
if (datum == IMAGE) {
coordSystem.imageCoordToCropBuffer(begin.x, begin.y, begin_.x, begin_.y);
coordSystem.imageCoordToCropBuffer(end.x, end.y, end_.x, end_.y);
}
else if (datum == CLICKED_POINT) {
begin_ += editBuffer->getDataProvider()->posScreen;
end_ += editBuffer->getDataProvider()->posScreen;
}
else if (datum == CURSOR) {
begin_ += editBuffer->getDataProvider()->posScreen + editBuffer->getDataProvider()->deltaPrevScreen;
end_ += editBuffer->getDataProvider()->posScreen + editBuffer->getDataProvider()->deltaPrevScreen;
}
// drawing the lower byte's value
unsigned short a = (id+1) & 0xFF;
cr->set_source_rgba (0.,0., 0., double(a)/255.);
cr->move_to(begin_.x+0.5, begin_.y+0.5);
cr->line_to(end_.x+0.5, end_.y+0.5);
cr->stroke();
// drawing the higher byte's value
if (editBuffer->getObjectMode() == OM_65535) {
a = (id+1)>>8;
cr2->set_source_rgba (0.,0., 0., double(a)/255.);
cr2->move_to(begin_.x+0.5, begin_.y+0.5);
cr2->line_to(end_.x+0.5, end_.y+0.5);
cr2->stroke();
}
}
}
void Polyline::drawOuterGeometry(Cairo::RefPtr<Cairo::Context> &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem) {
if ((flags & ACTIVE) && points.size()>1) {
RGBColor color;
if (flags & AUTO_COLOR)
color = getOuterLineColor();
else
color = outerLineColor;
cr->set_source_rgb (color.getR(), color.getG(), color.getB());
cr->set_line_width( getOuterLineWidth() );
Coord currPos;
for (unsigned int i=0; i<points.size(); ++i) {
currPos = points.at(i);
if (datum == IMAGE) coordSystem.imageCoordToScreen(points.at(i).x, points.at(i).y, currPos.x, currPos.y);
else if (datum == CLICKED_POINT) currPos += editBuffer->getDataProvider()->posScreen;
else if (datum == CURSOR) currPos += editBuffer->getDataProvider()->posScreen + editBuffer->getDataProvider()->deltaPrevScreen;
if (!i) cr->move_to(currPos.x+0.5, currPos.y+0.5);
else cr->line_to(currPos.x+0.5, currPos.y+0.5);
}
if (filled) {
cr->fill_preserve();
cr->stroke();
}
else
cr->stroke();
}
}
void Polyline::drawInnerGeometry(Cairo::RefPtr<Cairo::Context> &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem) {
if ((flags & ACTIVE) && points.size()>1) {
RGBColor color;
if (flags & AUTO_COLOR)
color = getInnerLineColor();
else
color = innerLineColor;
cr->set_source_rgb (color.getR(), color.getG(), color.getB());
cr->set_line_width( getOuterLineWidth() );
if (filled) {
Coord currPos;
for (unsigned int i=0; i<points.size(); ++i) {
currPos = points.at(i);
if (datum == IMAGE) coordSystem.imageCoordToScreen(points.at(i).x, points.at(i).y, currPos.x, currPos.y);
else if (datum == CLICKED_POINT) currPos += editBuffer->getDataProvider()->posScreen;
else if (datum == CURSOR) currPos += editBuffer->getDataProvider()->posScreen + editBuffer->getDataProvider()->deltaPrevScreen;
if (!i) cr->move_to(currPos.x+0.5, currPos.y+0.5);
else cr->line_to(currPos.x+0.5, currPos.y+0.5);
}
if (innerLineWidth > 0.) {
cr->fill_preserve();
cr->stroke();
}
else
cr->fill();
}
else if (innerLineWidth > 0.) {
Coord currPos;
for (unsigned int i=0; i<points.size(); ++i) {
currPos = points.at(i);
if (datum == IMAGE) coordSystem.imageCoordToScreen(points.at(i).x, points.at(i).y, currPos.x, currPos.y);
else if (datum == CLICKED_POINT) currPos += editBuffer->getDataProvider()->posScreen;
else if (datum == CURSOR) currPos += editBuffer->getDataProvider()->posScreen + editBuffer->getDataProvider()->deltaPrevScreen;
if (!i) cr->move_to(currPos.x+0.5, currPos.y+0.5);
else cr->line_to(currPos.x+0.5, currPos.y+0.5);
}
cr->stroke();
}
}
}
void Polyline::drawToMOChannel (Cairo::RefPtr<Cairo::Context> &cr, Cairo::RefPtr<Cairo::Context> &cr2, unsigned short id, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem) {
if ((flags & ACTIVE) && points.size()>1) {
Coord currPos;
// drawing the lower byte's value
unsigned short a = (id+1) & 0xFF;
cr->set_source_rgba (0.,0., 0., double(a)/255.);
for (unsigned int i=0; i<points.size(); ++i) {
cr->set_line_width( getOuterLineWidth() );
currPos = points.at(i);
if (datum == IMAGE) coordSystem.imageCoordToCropBuffer(points.at(i).x, points.at(i).y, currPos.x, currPos.y);
else if (datum == CLICKED_POINT) currPos += editBuffer->getDataProvider()->posScreen;
else if (datum == CURSOR) currPos += editBuffer->getDataProvider()->posScreen + editBuffer->getDataProvider()->deltaPrevScreen;
if (!i) cr->move_to(currPos.x+0.5, currPos.y+0.5);
else cr->line_to(currPos.x+0.5, currPos.y+0.5);
}
if (filled) {
if (innerLineWidth > 0.) {
cr->fill_preserve();
cr->stroke();
}
else
cr->fill();
}
else
cr->stroke();
// drawing the higher byte's value
if (editBuffer->getObjectMode() == OM_65535) {
a = (id+1)>>8;
cr2->set_source_rgba (0.,0., 0., double(a)/255.);
for (unsigned int i=0; i<points.size(); ++i) {
cr2->set_line_width( getOuterLineWidth() );
currPos = points.at(i);
if (datum == IMAGE) coordSystem.imageCoordToCropBuffer(points.at(i).x, points.at(i).y, currPos.x, currPos.y);
else if (datum == CLICKED_POINT) currPos += editBuffer->getDataProvider()->posScreen;
else if (datum == CURSOR) currPos += editBuffer->getDataProvider()->posScreen + editBuffer->getDataProvider()->deltaPrevScreen;
if (!i) cr2->move_to(currPos.x+0.5, currPos.y+0.5);
else cr2->line_to(currPos.x+0.5, currPos.y+0.5);
}
if (filled) {
if (innerLineWidth > 0.) {
cr2->fill_preserve();
cr2->stroke();
}
else
cr2->fill();
}
else
cr2->stroke();
}
}
}
void Rectangle::setXYWH(int left, int top, int width, int height) {
topLeft.set(left, top);
bottomRight.set(left+width, top+height);
}
void Rectangle::setXYXY(int left, int top, int right, int bottom) {
topLeft.set(left, top);
bottomRight.set(right, bottom);
}
void Rectangle::setXYWH(Coord topLeft, Coord widthHeight) {
this->topLeft = topLeft;
this->bottomRight = topLeft + widthHeight;
}
void Rectangle::setXYXY(Coord topLeft, Coord bottomRight) {
this->topLeft = topLeft;
this->bottomRight = bottomRight;
}
void Rectangle::drawOuterGeometry (Cairo::RefPtr<Cairo::Context> &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem) {
if ((flags & ACTIVE)) {
RGBColor color;
if (flags & AUTO_COLOR)
color = getOuterLineColor();
else
color = outerLineColor;
cr->set_source_rgb (color.getR(), color.getG(), color.getB());
cr->set_line_width( getOuterLineWidth() );
Coord tl, br;
if (datum == IMAGE) coordSystem.imageCoordToScreen(topLeft.x, topLeft.y, tl.x, tl.y);
else if (datum == CLICKED_POINT) tl = topLeft + editBuffer->getDataProvider()->posScreen;
else if (datum == CURSOR) tl = topLeft +editBuffer->getDataProvider()->posScreen + editBuffer->getDataProvider()->deltaPrevScreen;
if (datum == IMAGE) coordSystem.imageCoordToScreen(bottomRight.x, bottomRight.y, br.x, br.y);
else if (datum == CLICKED_POINT) br = bottomRight + editBuffer->getDataProvider()->posScreen;
else if (datum == CURSOR) br = bottomRight +editBuffer->getDataProvider()->posScreen + editBuffer->getDataProvider()->deltaPrevScreen;
cr->rectangle(tl.x+0.5, tl.y+0.5, br.x-tl.x, br.y-tl.y);
if (filled) {
cr->fill_preserve();
cr->stroke();
}
else
cr->stroke();
}
}
void Rectangle::drawInnerGeometry (Cairo::RefPtr<Cairo::Context> &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem) {
if (flags & ACTIVE) {
RGBColor color;
if (flags & AUTO_COLOR)
color = getInnerLineColor();
else
color = innerLineColor;
cr->set_source_rgb (color.getR(), color.getG(), color.getB());
cr->set_line_width( innerLineWidth );
Coord tl, br;
if (datum == IMAGE) coordSystem.imageCoordToScreen(topLeft.x, topLeft.y, tl.x, tl.y);
else if (datum == CLICKED_POINT) tl = topLeft + editBuffer->getDataProvider()->posScreen;
else if (datum == CURSOR) tl = topLeft +editBuffer->getDataProvider()->posScreen + editBuffer->getDataProvider()->deltaPrevScreen;
if (datum == IMAGE) coordSystem.imageCoordToScreen(bottomRight.x, bottomRight.y, br.x, br.y);
else if (datum == CLICKED_POINT) br = bottomRight + editBuffer->getDataProvider()->posScreen;
else if (datum == CURSOR) br = bottomRight +editBuffer->getDataProvider()->posScreen + editBuffer->getDataProvider()->deltaPrevScreen;
if (filled) {
cr->rectangle(tl.x+0.5, tl.y+0.5, br.x-tl.x, br.y-tl.y);
if (innerLineWidth > 0.) {
cr->fill_preserve();
cr->stroke();
}
else
cr->fill();
}
else if (innerLineWidth > 0.) {
cr->rectangle(tl.x+0.5, tl.y+0.5, br.x-tl.x, br.y-tl.y);
cr->stroke();
}
}
}
void Rectangle::drawToMOChannel (Cairo::RefPtr<Cairo::Context> &cr, Cairo::RefPtr<Cairo::Context> &cr2, unsigned short id, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem) {
if (flags & ACTIVE) {
cr->set_line_width( getMouseOverLineWidth() );
Coord tl, br;
if (datum == IMAGE) coordSystem.imageCoordToCropBuffer(topLeft.x, topLeft.y, tl.x, tl.y);
else if (datum == CLICKED_POINT) tl = topLeft + editBuffer->getDataProvider()->posScreen;
else if (datum == CURSOR) tl = topLeft +editBuffer->getDataProvider()->posScreen + editBuffer->getDataProvider()->deltaPrevScreen;
if (datum == IMAGE) coordSystem.imageCoordToCropBuffer(bottomRight.x, bottomRight.y, br.x, br.y);
else if (datum == CLICKED_POINT) br = bottomRight + editBuffer->getDataProvider()->posScreen;
else if (datum == CURSOR) br = bottomRight +editBuffer->getDataProvider()->posScreen + editBuffer->getDataProvider()->deltaPrevScreen;
// drawing the lower byte's value
unsigned short a = (id+1) & 0xFF;
cr->set_source_rgba (0.,0., 0., double(a)/255.);
cr->rectangle(tl.x+0.5, tl.y+0.5, br.x-tl.x, br.y-tl.y);
if (filled) {
if (innerLineWidth > 0.) {
cr->fill_preserve();
cr->stroke();
}
else
cr->fill();
}
else
cr->stroke();
// drawing the higher byte's value
if (editBuffer->getObjectMode() == OM_65535) {
a = (id+1)>>8;
cr2->set_source_rgba (0.,0., 0., double(a)/255.);
cr->rectangle(tl.x+0.5, tl.y+0.5, br.x-tl.x, br.y-tl.y);
if (filled) {
if (innerLineWidth > 0.) {
cr2->fill_preserve();
cr2->stroke();
}
else
cr2->fill();
}
else
cr2->stroke();
}
}
}
EditSubscriber::EditSubscriber (EditType editType) : ID(EUID_None), editingType(editType), bufferType(BT_SINGLEPLANE_FLOAT), provider(NULL) {}
void EditSubscriber::setEditProvider(EditDataProvider *provider) {
this->provider = provider;
}
void EditSubscriber::setEditID(EditUniqueID ID, BufferType buffType) {
this->ID = ID;
bufferType = buffType;
}
bool EditSubscriber::isCurrentSubscriber() {
//if (provider && provider->getCurrSubscriber())
// return provider->getCurrSubscriber()->getEditID() == ID;
if (provider)
return provider->getCurrSubscriber() == this;
return false;
}
void EditSubscriber::subscribe() {
if (provider)
provider->subscribe(this);
}
void EditSubscriber::unsubscribe() {
if (provider)
provider->unsubscribe();
}
void EditSubscriber::switchOffEditMode() {
unsubscribe();
}
EditUniqueID EditSubscriber::getEditID() {
return ID;
}
EditType EditSubscriber::getEditingType() {
return editingType;
}
BufferType EditSubscriber::getEditBufferType() {
return bufferType;
}
//--------------------------------------------------------------------------------------------------
EditDataProvider::EditDataProvider() : currSubscriber(NULL), object(0), posScreen(-1,-1), posImage(-1,-1),
deltaScreen(0,0), deltaImage(0,0), deltaPrevScreen(0,0), deltaPrevImage(0,0) {
pipetteVal[0] = pipetteVal[1] = pipetteVal[2] = 0.f;
}
void EditDataProvider::subscribe(EditSubscriber *subscriber) {
if (currSubscriber)
currSubscriber->switchOffEditMode();
currSubscriber = subscriber;
}
void EditDataProvider::unsubscribe() {
currSubscriber = NULL;
}
void EditDataProvider::switchOffEditMode() {
if (currSubscriber)
currSubscriber->switchOffEditMode ();
}
CursorShape EditDataProvider::getCursor(int objectID) {
if (currSubscriber)
currSubscriber->getCursor(objectID);
return CSOpenHand;
}
EditSubscriber* EditDataProvider::getCurrSubscriber() {
return currSubscriber;
}

322
rtgui/edit.h Normal file
View File

@@ -0,0 +1,322 @@
/*
* 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 _EDIT_H_
#define _EDIT_H_
#include <gtkmm.h>
#include "../rtengine/imagefloat.h"
#include "editid.h"
#include "cursormanager.h"
#include "../rtengine/rt_math.h"
#include "coord.h"
class EditDataProvider;
namespace rtengine {
class EditBuffer;
}
/** @file
*
* The Edit mechanism is designed to let tools (subscribers) communicate with the preview area (provider).
* Subscribers will be tools that need to create some graphics in the preview area, to let the user interact
* with it in a more user friendly way.
*
* Do not confuse with a _local_ editing, which is another topic implemented in another class. The Edit feature
* is also not supported in batch editing from the File Browser.
*
* Each Edit tool must have a unique ID, that will identify them, and which let the ImProcCoordinator or other
* mechanism act as appropriated. They are all defined in rtgui/editid.h.
*
* ## How does it works?
*
* When a tool is being constructed, unique IDs are affected to the EditSubscribers. Then the EditorPanel class
* will ask all ToolPanel to register the 'after' preview ImageArea object as data provider. The Subscribers
* have now to provide a toggle button to click on to start the Edit listening. When toggling on, the Subscriber
* register itself to the DataProvider, then an event is thrown through the standard ToolPanelListener::panelChanged
* method to update the preview with new graphics to be displayed, and eventually buffers to create and populate.
*
* When the Edit process stops, the Subscriber is removed from the DataProvider, so buffer can be freed up.
* A new ToolPanelListener::panelChanged event is also thrown to update the preview again, without the tool's
* graphical objects. The Edit button is also toggled off (by the user or programmatically).
*
* It means that each Edit buttons toggled on will start an update of the preview which might or might not create
* a new History entry, depending on the event.
*
*/
/** @brief Coordinate system where the widgets will be drawn
*
* The EditCoordSystem is used to define a screen and an image coordinate system.
*/
class EditCoordSystem {
public:
virtual ~EditCoordSystem() {}
/// Convert the widget's DrawingArea (i.e. preview area) coords to the edit buffer coords
virtual void screenCoordToCropBuffer (int phyx, int phyy, int& cropx, int& cropy) =0;
/// Convert the widget's DrawingArea (i.e. preview area) coords to the full image coords
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 edit buffer coords
virtual void imageCoordToCropBuffer (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
virtual float scaleValueToImage (float value) =0;
/// Convert a size value from the preview's scale to the image's scale
virtual double scaleValueToImage (double value) =0;
/// Convert a size value from the image's scale to the preview's scale
virtual int scaleValueToScreen (int value) =0;
/// Convert a size value from the image's scale to the preview's scale
virtual float scaleValueToScreen (float value) =0;
/// Convert a size value from the image's scale to the preview's scale
virtual double scaleValueToScreen (double value) =0;
};
class RGBColor {
double r;
double g;
double b;
public:
RGBColor () : r(0.), g(0.), b(0.) {}
explicit RGBColor (double r, double g, double b) : r(r), g(g), b(b) {}
explicit RGBColor (char r, char g, char b) : r(double(r)/255.), g(double(g)/255.), b(double(b)/255.) {}
void setColor(double r, double g, double b) {
this->r = r;
this->g = g;
this->b = b;
}
void setColor(char r, char g, char b) {
this->r = double(r)/255.;
this->g = double(g)/255.;
this->b = double(b)/255.;
}
double getR() { return r; }
double getG() { return g; }
double getB() { return b; }
};
class Geometry {
public:
enum State {
NORMAL,
PRELIGHT,
DRAGGED
};
enum Datum {
IMAGE,
CLICKED_POINT,
CURSOR
};
enum Flags {
ACTIVE = 1<<0, // true if the geometry is active and have to be drawn
AUTO_COLOR = 1<<1, // true if the color depend on the state value, not the color field above
};
protected:
RGBColor innerLineColor;
RGBColor outerLineColor;
short flags;
public:
float innerLineWidth; // ...outerLineWidth = innerLineWidth+2
Datum datum;
State state; // set by the Subscriber
Geometry () : innerLineColor(char(255), char(255), char(255)), outerLineColor(char(0), char(0), char(0)), flags(ACTIVE|AUTO_COLOR), innerLineWidth(1.f), datum(IMAGE), state(NORMAL) {}
virtual ~Geometry() {}
void setInnerLineColor (double r, double g, double b) { innerLineColor.setColor(r, g, b); flags &= ~AUTO_COLOR; }
void setInnerLineColor (char r, char g, char b) { innerLineColor.setColor(r, g, b); flags &= ~AUTO_COLOR; }
RGBColor getInnerLineColor ();
void setOuterLineColor (double r, double g, double b) { outerLineColor.setColor(r, g, b); flags &= ~AUTO_COLOR; }
void setOuterLineColor (char r, char g, char b) { outerLineColor.setColor(r, g, b); flags &= ~AUTO_COLOR; }
RGBColor getOuterLineColor ();
double getOuterLineWidth () { return double(innerLineWidth)+2.; }
double getMouseOverLineWidth () { return getOuterLineWidth()+2.; }
void setAutoColor (bool aColor) { if (aColor) flags |= AUTO_COLOR; else flags &= ~AUTO_COLOR; }
void setActive (bool active) { if (active) flags |= ACTIVE; else flags &= ~ACTIVE; }
virtual void drawOuterGeometry (Cairo::RefPtr<Cairo::Context> &cr, rtengine::EditBuffer *parent, EditCoordSystem &coordSystem) =0;
virtual void drawInnerGeometry (Cairo::RefPtr<Cairo::Context> &cr, rtengine::EditBuffer *parent, EditCoordSystem &coordSystem) =0;
virtual void drawToMOChannel (Cairo::RefPtr<Cairo::Context> &cr, Cairo::RefPtr<Cairo::Context> &cr2, unsigned short id, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem) =0;
};
class Circle : public Geometry {
public:
Coord center;
int radius;
bool filled;
bool radiusInImageSpace; /// If true, the radius depend on the image scale; if false, it is a fixed 'screen' size
Circle () : center(100,100), radius(10), filled(false), radiusInImageSpace(false) {}
Circle (Coord &center, int radius, bool filled=false, bool radiusInImageSpace=false) : center(center), radius(radius), filled(filled), radiusInImageSpace(radiusInImageSpace) {}
Circle (int centerX, int centerY, int radius, bool filled=false, bool radiusInImageSpace=false) : center(centerX, centerY), radius(radius), filled(filled), radiusInImageSpace(radiusInImageSpace) {}
void drawOuterGeometry (Cairo::RefPtr<Cairo::Context> &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem);
void drawInnerGeometry (Cairo::RefPtr<Cairo::Context> &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem);
void drawToMOChannel (Cairo::RefPtr<Cairo::Context> &cr, Cairo::RefPtr<Cairo::Context> &cr2, unsigned short id, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem);
};
class Line : public Geometry {
public:
Coord begin;
Coord end;
Line () : begin(10,10), end(100,100) {}
Line (Coord &begin, Coord &end) : begin(begin), end(end) {}
Line (int beginX, int beginY, int endX, int endY) : begin(beginX, beginY), end(endX, endY) {}
void drawOuterGeometry (Cairo::RefPtr<Cairo::Context> &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem);
void drawInnerGeometry (Cairo::RefPtr<Cairo::Context> &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem);
void drawToMOChannel (Cairo::RefPtr<Cairo::Context> &cr, Cairo::RefPtr<Cairo::Context> &cr2, unsigned short id, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem);
};
class Polyline : public Geometry {
public:
std::vector<Coord> points;
bool filled;
Polyline() : filled(false) {}
void drawOuterGeometry (Cairo::RefPtr<Cairo::Context> &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem);
void drawInnerGeometry (Cairo::RefPtr<Cairo::Context> &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem);
void drawToMOChannel (Cairo::RefPtr<Cairo::Context> &cr, Cairo::RefPtr<Cairo::Context> &cr2, unsigned short id, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem);
};
class Rectangle : public Geometry {
public:
Coord topLeft;
Coord bottomRight;
bool filled;
Rectangle() : topLeft(0,0), bottomRight(10,10), filled(false) {}
void setXYWH(int left, int top, int width, int height);
void setXYXY(int left, int top, int right, int bottom);
void setXYWH(Coord topLeft, Coord widthHeight);
void setXYXY(Coord topLeft, Coord bottomRight);
void drawOuterGeometry (Cairo::RefPtr<Cairo::Context> &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem);
void drawInnerGeometry (Cairo::RefPtr<Cairo::Context> &cr, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem);
void drawToMOChannel (Cairo::RefPtr<Cairo::Context> &cr, Cairo::RefPtr<Cairo::Context> &cr2, unsigned short id, rtengine::EditBuffer *editBuffer, EditCoordSystem &coordSystem);
};
/// @brief Method for client tools needing Edit information
class EditSubscriber {
public:
private:
EditUniqueID ID; /// this will be used in improcfun to locate the data that has to be stored in the buffer; it must be unique in RT
EditType editingType;
BufferType bufferType;
EditDataProvider *provider;
protected:
std::vector<Geometry*> visibleGeometry;
std::vector<Geometry*> mouseOverGeometry;
public:
EditSubscriber (EditType editType);
virtual ~EditSubscriber () {}
void setEditProvider(EditDataProvider *provider);
EditDataProvider* getEditProvider() { return provider; }
void setEditID(EditUniqueID ID, BufferType buffType);
bool isCurrentSubscriber();
virtual void subscribe();
virtual void unsubscribe();
virtual void switchOffEditMode (); /// Occurs when the user want to stop the editing mode
EditUniqueID getEditID();
EditType getEditingType();
BufferType getEditBufferType();
/** @brief Get the cursor to be displayed when above handles
@param objectID object currently "hovered" */
virtual CursorShape getCursor(int objectID) { return CSOpenHand; }
/** @brief Triggered when the mouse is moving over an object
This method is also triggered when the cursor is moving over the image in ET_PIPETTE mode
@param modifierKey Gtk's event modifier key (GDK_CONTROL_MASK | GDK_SHIFT_MASK | ...)
@param editBuffer buffer to get the pipette values and the from
@return true if the preview has to be redrawn, false otherwise */
virtual bool mouseOver(int modifierKey) { return false; }
/** @brief Triggered when mouse button 1 is pressed, together with the CTRL modifier key if the subscriber is of type ET_PIPETTE
@param modifierKey Gtk's event modifier key (GDK_CONTROL_MASK | GDK_SHIFT_MASK | ...)
@return true if the preview has to be redrawn, false otherwise */
virtual bool button1Pressed(int modifierKey) { return false; }
/** @brief Triggered when mouse button 1 is released
@return true if the preview has to be redrawn, false otherwise */
virtual bool button1Released() { return false; }
/** @brief Triggered when the user is moving while holding down mouse button 1
@param modifierKey Gtk's event modifier key (GDK_CONTROL_MASK | GDK_SHIFT_MASK | ...)
@return true if the preview has to be redrawn, false otherwise */
virtual bool drag(int modifierKey) { return false; }
/** @brief Get the geometry to be shown to the user */
const std::vector<Geometry*> & getVisibleGeometry() { return visibleGeometry; }
/** @brief Get the geometry to be drawn in the "mouse over" channel, hidden from the user */
const std::vector<Geometry*> & getMouseOverGeometry() { return mouseOverGeometry; }
};
/** @brief Class to handle the furniture of data to the subscribers.
*
* It is admitted that only one Subscriber can ask data at a time. If the Subscriber is of type ET_PIPETTE, it will have to
* trigger the usual event so that the image will be reprocessed to compute the buffer of the current subscriber.
*/
class EditDataProvider {
private:
EditSubscriber *currSubscriber;
public:
int object; /// ET_OBJECTS mode: Object detected under the cursor, 0 otherwise; ET_PIPETTE mode: 1 if above the image, 0 otherwise
float pipetteVal[3]; /// Current pipette values; if bufferType==BT_SINGLEPLANE_FLOAT, #2 & #3 will be set to 0
Coord posScreen; /// Location of the mouse button press, in preview image space
Coord posImage; /// Location of the mouse button press, in the full image space
Coord deltaScreen; /// Delta relative to posScreen
Coord deltaImage; /// Delta relative to posImage
Coord deltaPrevScreen; /// Delta relative to the previous mouse location, in preview image space
Coord deltaPrevImage; /// Delta relative to the previous mouse location, in the full image space
EditDataProvider();
virtual ~EditDataProvider() {}
virtual void subscribe(EditSubscriber *subscriber);
virtual void unsubscribe(); /// Occurs when the subscriber has been switched off first
virtual void switchOffEditMode (); /// Occurs when the user want to stop the editing mode
virtual CursorShape getCursor(int objectID);
int getPipetteRectSize() { return 8; } // TODO: make a GUI
EditSubscriber* getCurrSubscriber();
virtual void getImageSize (int &w, int&h) =0;
};
#endif

25
rtgui/editedstate.h Normal file
View File

@@ -0,0 +1,25 @@
/*
* 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 _EDITEDSTATE_
#define _EDITEDSTATE_
enum EditedState { UnEdited=0, Edited=1, Irrelevant=2 };
#endif

27
rtgui/editenums.h Normal file
View File

@@ -0,0 +1,27 @@
/*
* 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 _EDITENUMS_
#define _EDITENUMS_
enum ImgEditState {SNormal, SCropMove, SHandMove, SResizeW1, SResizeW2, SResizeH1, SResizeH2, SResizeTL, SResizeTR, SResizeBL, SResizeBR,
SCropSelecting, SRotateSelecting, SCropWinMove, SCropFrameMove, SCropImgMove, SCropWinResize, SObservedMove, SEditDrag};
enum CursorArea {CropWinButtons, CropToolBar, CropImage, CropBorder, CropTop, CropTopLeft, CropTopRight, CropBottom, CropBottomLeft,
CropBottomRight, CropLeft, CropRight, CropInside, CropResize, CropObserved};
#endif

71
rtgui/editid.h Normal file
View File

@@ -0,0 +1,71 @@
/*
* 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 _EDITID_H_
#define _EDITID_H_
/// @brief List of pipette editing operation
enum EditUniqueID {
EUID_None, /// special value (default)
EUID_ToneCurve1,
EUID_ToneCurve2,
EUID_Lab_LCurve,
EUID_Lab_CCurve,
EUID_Lab_LCCurve,
EUID_Lab_CLCurve,
EUID_Lab_LHCurve,
EUID_Lab_CHCurve,
EUID_Lab_HHCurve,
EUID_Lab_aCurve,
EUID_Lab_bCurve,
EUID_RGB_R,
EUID_RGB_G,
EUID_RGB_B,
EUID_HSV_H,
EUID_HSV_S,
EUID_HSV_V,
EUID_BlackWhiteLuminance,
EUID_BlackWhiteBeforeCurve,
EUID_BlackWhiteAfterCurve,
EUID_WW_HHCurve,
};
/// @brief Editing mechanisms
// TODO: Look out if it has to be a bitfield to allow both mechanisms at a time
enum EditType {
ET_PIPETTE, /// Will trigger dedicated methods; can have a geometry list to be displayed, but without "mouse over" capabilities
ET_OBJECTS /// The objects are geometrical widgets with "mouse over" capabilities
};
/// @brief Buffer type for ET_PIPETTE type editing
enum BufferType {
BT_IMAGEFLOAT,
BT_LABIMAGE,
BT_SINGLEPLANE_FLOAT
};
/// @brief Number of object to be handled (for optimization purpose)
enum ObjectMode {
OM_255, /// less or equal than 255 objects
OM_65535 /// less or equal than 65535 objects
};
#endif

1656
rtgui/editorpanel.cc Executable file

File diff suppressed because it is too large Load Diff

207
rtgui/editorpanel.h Normal file
View File

@@ -0,0 +1,207 @@
/*
* This file is part of RawTherapee.
*
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
* Copyright (c) 2010 Oliver Duis <www.oliverduis.de>
*
* 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 _EDITORPANEL_
#define _EDITORPANEL_
#include <gtkmm.h>
#include "imageareapanel.h"
#include "toolpanelcoord.h"
#include "profilepanel.h"
#include "../rtengine/rtengine.h"
#include "history.h"
#include "histogrampanel.h"
#include "thumbnail.h"
#include "saveasdlg.h"
#include "batchqueueentry.h"
#include "thumbnaillistener.h"
#include "navigator.h"
#include "progressconnector.h"
#include "filepanel.h"
class EditorPanel;
struct EditorPanelIdleHelper {
EditorPanel* epanel;
bool destroyed;
int pending;
};
class RTWindow;
class EditorPanel : public Gtk::VBox,
public PParamsChangeListener,
public rtengine::ProgressListener,
public ThumbnailListener,
public HistoryBeforeLineListener,
public rtengine::HistogramListener {
private:
Glib::ustring lastSaveAsFileName;
bool realized;
protected:
Gtk::ProgressBar *progressLabel;
Gtk::ToggleButton* info;
Gtk::ToggleButton* hidehp;
Gtk::ToggleButton* tbShowHideSidePanels;
Gtk::ToggleButton* tbTopPanel_1;
Gtk::ToggleButton* tbRightPanel_1;
Gtk::ToggleButton* tbBeforeLock;
//bool bAllSidePanelsVisible;
Gtk::ToggleButton* beforeAfter;
Gtk::HPaned* hpanedl;
Gtk::HPaned* hpanedr;
Gtk::HBox* statusBox;
Gtk::Image *iHistoryShow, *iHistoryHide;
Gtk::Image *iTopPanel_1_Show, *iTopPanel_1_Hide;
Gtk::Image *iRightPanel_1_Show, *iRightPanel_1_Hide;
Gtk::Image *iShowHideSidePanels;
Gtk::Image *iShowHideSidePanels_exit;
Gtk::Image *iBeforeLockON, *iBeforeLockOFF;
Gtk::VBox *leftbox;
Gtk::VBox *vboxright;
Gtk::Button* queueimg;
Gtk::Button* saveimgas;
Gtk::Button* sendtogimp;
Gtk::Button* navSync;
Gtk::Button* navNext;
Gtk::Button* navPrev;
ImageAreaPanel* iareapanel;
PreviewHandler* previewHandler;
PreviewHandler* beforePreviewHandler; // for the before-after view
PreviewHandler* previewHandler2;
Navigator* navigator;
ImageAreaPanel* beforeIarea; // for the before-after view
Gtk::VBox* beforeBox;
Gtk::VBox* afterBox;
Gtk::Label* beforeLabel;
Gtk::Label* afterLabel;
Gtk::HBox* beforeAfterBox;
Gtk::HBox* beforeHeaderBox;
Gtk::HBox* afterHeaderBox;
Gtk::Frame* ppframe;
ProfilePanel* profilep;
History* history;
HistogramPanel* histogramPanel;
ToolPanelCoordinator* tpc;
RTWindow* parent;
//SaveAsDialog* saveAsDialog;
BatchToolPanelCoordinator* btpCoordinator;
FilePanel* fPanel;
bool firstProcessingDone;
Thumbnail* openThm; // may get invalid on external delete event
Glib::ustring fname; // must be saved separately
rtengine::InitialImage* isrc;
rtengine::StagedImageProcessor* ipc;
rtengine::StagedImageProcessor* beforeIpc; // for the before-after view
EditorPanelIdleHelper* epih;
void close ();
BatchQueueEntry* createBatchQueueEntry ();
bool idle_imageSaved(ProgressConnector<int> *pc,rtengine::IImage16* img,Glib::ustring fname, SaveFormat sf);
bool idle_saveImage(ProgressConnector<rtengine::IImage16*> *pc,Glib::ustring fname, SaveFormat sf);
bool idle_sendToGimp( ProgressConnector<rtengine::IImage16*> *pc, Glib::ustring fname);
bool idle_sentToGimp(ProgressConnector<int> *pc,rtengine::IImage16* img,Glib::ustring filename);
int err;
time_t processingStartedTime;
sigc::connection ShowHideSidePanelsconn;
bool isProcessing;
public:
EditorPanel (FilePanel* filePanel = NULL);
virtual ~EditorPanel ();
void open (Thumbnail* tmb, rtengine::InitialImage* isrc);
void setAspect ();
void on_realize ();
void leftPaneButtonReleased(GdkEventButton *event);
void rightPaneButtonReleased(GdkEventButton *event);
void setParent (RTWindow* p) { parent = p; }
void writeOptions();
void showTopPanel(bool show);
bool isRealized() { return realized; }
// progresslistener interface
void setProgress (double p);
void setProgressStr (Glib::ustring str);
void setProgressState (bool inProcessing);
void error (Glib::ustring title, Glib::ustring descr);
void displayError (Glib::ustring title, Glib::ustring descr); // this is called by error in the gtk thread
void refreshProcessingState (bool inProcessing); // this is called by setProcessingState in the gtk thread
// PParamsChangeListener interface
void procParamsChanged (rtengine::procparams::ProcParams* params, rtengine::ProcEvent ev, Glib::ustring descr, ParamsEdited* paramsEdited=NULL);
// thumbnaillistener interface
void procParamsChanged (Thumbnail* thm, int whoChangedIt);
// HistoryBeforeLineListener
void historyBeforeLineChanged (const rtengine::procparams::ProcParams& params);
// HistogramListener
void histogramChanged (LUTu & histRed, LUTu & histGreen, LUTu & histBlue, LUTu & histLuma, LUTu & histToneCurve, LUTu & histLCurve, LUTu & histCCurve,/* LUTu & histCLurve, LUTu & histLLCurve,*/ LUTu & histLCAM, LUTu & histCCAM,
LUTu & histRedRaw, LUTu & histGreenRaw, LUTu & histBlueRaw, LUTu & histChroma);
// event handlers
void info_toggled ();
void hideHistoryActivated ();
void tbRightPanel_1_toggled ();
void tbTopPanel_1_toggled ();
void beforeAfterToggled ();
void tbBeforeLock_toggled();
void saveAsPressed ();
void queueImgPressed ();
void sendToGimpPressed ();
void openNextEditorImage ();
void openPreviousEditorImage ();
void syncFileBrowser ();
void tbTopPanel_1_visible (bool visible);
bool CheckSidePanelsVisibility();
void tbShowHideSidePanels_managestate();
void toggleSidePanels();
void toggleSidePanelsZoomFit();
void saveProfile ();
Glib::ustring getShortName ();
Glib::ustring getFileName ();
bool handleShortcutKey (GdkEventKey* event);
bool getIsProcessing() const { return isProcessing; }
void updateTPVScrollbar (bool hide);
void updateTabsUsesIcons (bool useIcons);
void updateHistogramPosition (int oldPosition, int newPosition);
Gtk::Paned *catalogPane;
};
#endif

243
rtgui/editwindow.cc Normal file
View File

@@ -0,0 +1,243 @@
/*
* This file is part of RawTherapee.
*
* 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 "editwindow.h"
#include "options.h"
#include "preferences.h"
#include "cursormanager.h"
#include "rtwindow.h"
#include <gtk/gtk.h>
#include "rtimage.h"
#include "threadutils.h"
static EditWindow* editWnd = NULL;
// Check if the system has more than one display and option is set
bool EditWindow::isMultiDisplayEnabled() {
return options.multiDisplayMode>0 && Gdk::Screen::get_default()->get_n_monitors ()>1;
}
// Should only be created once, auto-creates window on correct display
EditWindow* EditWindow::getInstance(RTWindow* p)
{
if (editWnd == NULL) {
static MyMutex smutex_;
MyMutex::MyLock lock(smutex_);
if ( editWnd == 0 ) {
editWnd = new EditWindow(p);
// Determine the other display and maximize the window on that
const Glib::RefPtr< Gdk::Window >& wnd=p->get_window();
int monNo=p->get_screen()->get_monitor_at_window (wnd);
Gdk::Rectangle lMonitorRect;
editWnd->get_screen()->get_monitor_geometry(isMultiDisplayEnabled() ? (monNo==0 ? 1 : 0) : monNo, lMonitorRect);
editWnd->move(lMonitorRect.get_x(), lMonitorRect.get_y());
editWnd->maximize();
editWnd->show();
} else {
editWnd->show_all();
}
}
return editWnd;
}
EditWindow::EditWindow (RTWindow* p) : parent(p) , isFullscreen(false) {
Glib::ustring fName = "rt-logo.png";
Glib::ustring fullPath = RTImage::findIconAbsolutePath(fName);
#ifdef GLIBMM_EXCEPTIONS_ENABLED
try { set_default_icon_from_file (fullPath);
} catch(Glib::Exception& ex) { printf ("%s\n", ex.what().c_str()); }
#else
{ std::auto_ptr<Glib::Error> error;
set_default_icon_from_file (fullPath, error);
}
#endif //GLIBMM_EXCEPTIONS_ENABLED
set_title_decorated("");
property_allow_shrink() = true;
set_modal(false);
set_resizable(true);
property_destroy_with_parent().set_value(false);
signal_window_state_event().connect( sigc::mem_fun(*this, &EditWindow::on_window_state_event) );
mainNB = Gtk::manage (new Gtk::Notebook ());
mainNB->set_scrollable (true);
mainNB->signal_switch_page().connect_notify( sigc::mem_fun(*this, &EditWindow::on_mainNB_switch_page) );
signal_key_press_event().connect( sigc::mem_fun(*this, &EditWindow::keyPressed) );
Gtk::VBox* mainBox = Gtk::manage (new Gtk::VBox ());
mainBox->pack_start (*mainNB);
add (*mainBox);
show_all ();
}
void EditWindow::on_realize () {
Gtk::Window::on_realize ();
cursorManager.init (get_window());
}
bool EditWindow::on_window_state_event(GdkEventWindowState* event) {
if (!event->new_window_state) {
// Window mode
options.windowMaximized = false;
}
else if (event->new_window_state & (GDK_WINDOW_STATE_MAXIMIZED|GDK_WINDOW_STATE_FULLSCREEN)) {
// Fullscreen mode
options.windowMaximized = true;
}
return true;
}
void EditWindow::on_mainNB_switch_page(GtkNotebookPage* page, guint page_num) {
//if (page_num > 1) {
EditorPanel *ep = static_cast<EditorPanel*>(mainNB->get_nth_page(page_num));
if (mainNB->get_n_pages()>1 && page_num<=(filesEdited.size()-1)){
set_title_decorated(ep->getFileName());
}
ep->setAspect();
//}
}
void EditWindow::addEditorPanel (EditorPanel* ep, const std::string &name) {
ep->setParent (parent);
// construct closeable tab for the image
Gtk::HBox* hb = Gtk::manage (new Gtk::HBox ());
hb->pack_start (*Gtk::manage (new RTImage ("rtwindow.png")));
hb->pack_start (*Gtk::manage (new Gtk::Label (Glib::path_get_basename (name))));
hb->set_tooltip_markup (name);
Gtk::Button* closeb = Gtk::manage (new Gtk::Button ());
closeb->set_image (*Gtk::manage(new RTImage ("gtk-close.png")));
closeb->set_relief (Gtk::RELIEF_NONE);
closeb->set_focus_on_click (false);
// make the button as small as possible
Glib::RefPtr<Gtk::RcStyle> style = Gtk::RcStyle::create ();
style->set_xthickness (0);
style->set_ythickness (0);
closeb->modify_style (style);
closeb->signal_clicked().connect( sigc::bind (sigc::mem_fun(*this, &EditWindow::remEditorPanel) , ep));
hb->pack_end (*closeb);
hb->set_spacing (2);
hb->show_all ();
mainNB->append_page (*ep, *hb);
mainNB->set_current_page (mainNB->page_num (*ep));
mainNB->set_tab_reorderable (*ep, true);
set_title_decorated(name);
epanels[ name ] = ep;
filesEdited.insert ( name );
parent->fpanel->refreshEditedState (filesEdited);
ep->setAspect();
}
void EditWindow::remEditorPanel (EditorPanel* ep) {
if (ep->getIsProcessing())
return; // Will crash if destroyed while loading
epanels.erase (ep->getFileName());
filesEdited.erase (ep->getFileName ());
parent->fpanel->refreshEditedState (filesEdited);
mainNB->remove_page (*ep);
if (mainNB->get_n_pages()>0){
EditorPanel* ep1 = static_cast<EditorPanel*>(mainNB->get_nth_page (mainNB->get_current_page()));
set_title_decorated(ep1->getFileName());
}
else set_title_decorated("");
// TODO: save options if wanted
}
bool EditWindow::selectEditorPanel(const std::string &name) {
std::map<Glib::ustring, EditorPanel*>::iterator iep = epanels.find(name);
if (iep!=epanels.end()) {
mainNB->set_current_page (mainNB->page_num (*iep->second));
set_title_decorated(name);
return true;
}
return false;
}
bool EditWindow::keyPressed (GdkEventKey* event) {
bool ctrl = event->state & GDK_CONTROL_MASK;
if(event->keyval == GDK_F11) {
toggleFullscreen();
return true;
}
else {
if(mainNB->get_n_pages ()>0) { //pass the handling for the editor panels, if there are any
if (event->keyval == GDK_w && ctrl){ //remove editor panel
EditorPanel* ep = static_cast<EditorPanel*>(mainNB->get_nth_page (mainNB->get_current_page()));
remEditorPanel (ep);
return true;
}
else if(mainNB->get_n_pages ()>0){
EditorPanel* ep = static_cast<EditorPanel*>(mainNB->get_nth_page (mainNB->get_current_page()));
return ep->handleShortcutKey (event);
}
}
return false;
}
}
void EditWindow::toggleFullscreen () {
isFullscreen ? unfullscreen() : fullscreen();
isFullscreen = !isFullscreen;
}
bool EditWindow::on_delete_event(GdkEventAny* event) {
// Check if any editor is still processing, and do NOT quit if so. Otherwise crashes and inconsistent caches
bool isProcessing=false;
for ( std::set <Glib::ustring>::iterator iter = filesEdited.begin(); iter != filesEdited.end() && !isProcessing; iter++ ) {
if (epanels[*iter]->getIsProcessing()) isProcessing=true;
}
if (isProcessing)
return true;
for ( std::set <Glib::ustring>::iterator iter = filesEdited.begin(); iter != filesEdited.end(); iter++ )
mainNB->remove_page (*epanels[*iter]);
epanels.clear();
filesEdited.clear();
parent->fpanel->refreshEditedState (filesEdited);
hide ();
return false;
}
void EditWindow::set_title_decorated(Glib::ustring fname){
Glib::ustring subtitle;
if (!fname.empty()) subtitle= " - " + fname;
set_title("RawTherapee "+ M("EDITWINDOW_TITLE") + subtitle);
}

59
rtgui/editwindow.h Normal file
View File

@@ -0,0 +1,59 @@
/*
* This file is part of RawTherapee.
*
* 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 _EDITWINDOW_
#define _EDITWINDOW_
#include <gtkmm.h>
#include "filepanel.h"
#include "editorpanel.h"
#include <set>
class EditWindow : public Gtk::Window {
private:
RTWindow* parent;
Gtk::Notebook* mainNB;
std::set<Glib::ustring> filesEdited;
std::map<Glib::ustring, EditorPanel*> epanels;
bool isFullscreen;
void toggleFullscreen ();
public:
// Check if the system has more than one display and option is set
static bool isMultiDisplayEnabled();
// Should only be created once, auto-creates window on correct display
static EditWindow* getInstance(RTWindow* p);
EditWindow (RTWindow* p);
void addEditorPanel (EditorPanel* ep,const std::string &name);
void remEditorPanel (EditorPanel* ep);
bool selectEditorPanel(const std::string &name);
bool keyPressed (GdkEventKey* event);
bool on_delete_event(GdkEventAny* event);
bool on_window_state_event(GdkEventWindowState* event);
void on_mainNB_switch_page(GtkNotebookPage* page, guint page_num);
void set_title_decorated(Glib::ustring fname);
void on_realize ();
};
#endif

160
rtgui/epd.cc Normal file
View File

@@ -0,0 +1,160 @@
/*
* 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 "epd.h"
#include <iomanip>
#include <cmath>
using namespace rtengine;
using namespace rtengine::procparams;
EdgePreservingDecompositionUI::EdgePreservingDecompositionUI () : FoldableToolPanel(this, "epd", M("TP_EPD_LABEL"), true, true) {
setEnabledTooltipMarkup(M("TP_EPD_TOOLTIP"));
strength = Gtk::manage(new Adjuster (M("TP_EPD_STRENGTH"), -1.0, 2.0, 0.01, 0.5));
gamma = Gtk::manage(new Adjuster (M("TP_EPD_GAMMA"), 0.8, 1.5, 0.01, 1.));
edgeStopping = Gtk::manage(new Adjuster (M("TP_EPD_EDGESTOPPING"), 0.1, 4.0, 0.01, 1.4));
scale = Gtk::manage(new Adjuster (M("TP_EPD_SCALE"), 0.1, 10.0, 0.01, 0.3));
reweightingIterates = Gtk::manage(new Adjuster (M("TP_EPD_REWEIGHTINGITERATES"), 0, 9, 1, 0));
strength->setAdjusterListener(this);
gamma->setAdjusterListener(this);
edgeStopping->setAdjusterListener(this);
scale->setAdjusterListener(this);
reweightingIterates->setAdjusterListener(this);
strength->show();
gamma->show();
edgeStopping->show();
scale->show();
reweightingIterates->show();
pack_start(*strength);
pack_start(*gamma);
pack_start(*edgeStopping);
pack_start(*scale);
pack_start(*reweightingIterates);
}
void EdgePreservingDecompositionUI::read(const ProcParams *pp, const ParamsEdited *pedited){
disableListener();
if(pedited){
strength->setEditedState(pedited->epd.strength ? Edited : UnEdited);
gamma->setEditedState(pedited->epd.gamma ? Edited : UnEdited);
edgeStopping->setEditedState(pedited->epd.edgeStopping ? Edited : UnEdited);
scale->setEditedState(pedited->epd.scale ? Edited : UnEdited);
reweightingIterates->setEditedState(pedited->epd.reweightingIterates ? Edited : UnEdited);
set_inconsistent(multiImage && !pedited->epd.enabled);
}
setEnabled(pp->epd.enabled);
strength->set_sensitive (true);
if(pp->wavelet.enabled){
if(pp->wavelet.tmrs==0) {strength->set_sensitive (true);gamma->set_sensitive (true);}
else {strength->set_sensitive (false);gamma->set_sensitive (false);}
}
strength->setValue(pp->epd.strength);
gamma->setValue(pp->epd.gamma);
edgeStopping->setValue(pp->epd.edgeStopping);
scale->setValue(pp->epd.scale);
reweightingIterates->setValue(pp->epd.reweightingIterates);
enableListener();
}
void EdgePreservingDecompositionUI::write(ProcParams *pp, ParamsEdited *pedited){
pp->epd.strength = strength->getValue();
pp->epd.gamma = gamma->getValue();
pp->epd.edgeStopping = edgeStopping->getValue();
pp->epd.scale = scale->getValue();
pp->epd.reweightingIterates = reweightingIterates->getValue();
pp->epd.enabled = getEnabled();
strength->set_sensitive (true);
if(pp->wavelet.enabled){
if(pp->wavelet.tmrs==0) {strength->set_sensitive (true);gamma->set_sensitive (true);} else {strength->set_sensitive (false);gamma->set_sensitive (false);}
}
if(pedited){
pedited->epd.strength = strength->getEditedState();
pedited->epd.gamma = gamma->getEditedState();
pedited->epd.edgeStopping = edgeStopping->getEditedState();
pedited->epd.scale = scale->getEditedState();
pedited->epd.reweightingIterates = reweightingIterates->getEditedState();
pedited->epd.enabled = !get_inconsistent();
}
}
void EdgePreservingDecompositionUI::setDefaults(const ProcParams *defParams, const ParamsEdited *pedited){
strength->setDefault(defParams->epd.strength);
gamma->setDefault(defParams->epd.gamma);
edgeStopping->setDefault(defParams->epd.edgeStopping);
scale->setDefault(defParams->epd.scale);
reweightingIterates->setDefault(defParams->epd.reweightingIterates);
if(pedited){
strength->setDefaultEditedState(pedited->epd.strength ? Edited : UnEdited);
gamma->setDefaultEditedState(pedited->epd.gamma ? Edited : UnEdited);
edgeStopping->setDefaultEditedState(pedited->epd.edgeStopping ? Edited : UnEdited);
scale->setDefaultEditedState(pedited->epd.scale ? Edited : UnEdited);
reweightingIterates->setDefaultEditedState(pedited->epd.reweightingIterates ? Edited : UnEdited);
}else{
strength->setDefaultEditedState(Irrelevant);
gamma->setDefaultEditedState(Irrelevant);
edgeStopping->setDefaultEditedState(Irrelevant);
scale->setDefaultEditedState(Irrelevant);
reweightingIterates->setDefaultEditedState(Irrelevant);
}
}
void EdgePreservingDecompositionUI::adjusterChanged(Adjuster* a, double newval){
if(listener && getEnabled()){
if(a == strength)
listener->panelChanged(EvEPDStrength, Glib::ustring::format(std::setw(2), std::fixed, std::setprecision(2), a->getValue()));
else if(a == gamma)
listener->panelChanged(EvEPDgamma, Glib::ustring::format(std::setw(2), std::fixed, std::setprecision(2), a->getValue()));
else if(a == edgeStopping)
listener->panelChanged(EvEPDEdgeStopping, Glib::ustring::format(std::setw(2), std::fixed, std::setprecision(2), a->getValue()));
else if(a == scale)
listener->panelChanged(EvEPDScale, Glib::ustring::format(std::setw(2), std::fixed, std::setprecision(2), a->getValue()));
else if(a == reweightingIterates)
listener->panelChanged(EvEPDReweightingIterates, Glib::ustring::format((int)a->getValue()));
}
}
void EdgePreservingDecompositionUI::enabledChanged () {
if (listener) {
if (get_inconsistent())
listener->panelChanged (EvEPDEnabled, M("GENERAL_UNCHANGED"));
else if (getEnabled())
listener->panelChanged (EvEPDEnabled, M("GENERAL_ENABLED"));
else
listener->panelChanged (EvEPDEnabled, M("GENERAL_DISABLED"));
}
}
void EdgePreservingDecompositionUI::setBatchMode(bool batchMode){
ToolPanel::setBatchMode(batchMode);
strength->showEditedCB();
gamma->showEditedCB();
edgeStopping->showEditedCB();
scale->showEditedCB();
reweightingIterates->showEditedCB();
}

47
rtgui/epd.h Normal file
View File

@@ -0,0 +1,47 @@
/*
* 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 _EPD_H_
#define _EPD_H_
#include <gtkmm.h>
#include "adjuster.h"
#include "toolpanel.h"
class EdgePreservingDecompositionUI : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel {
protected:
Adjuster *strength;
Adjuster *gamma;
Adjuster *edgeStopping;
Adjuster *scale;
Adjuster *reweightingIterates;
public:
EdgePreservingDecompositionUI();
void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL);
void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL);
void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL);
void setBatchMode (bool batchMode);
void adjusterChanged (Adjuster* a, double newval);
void enabledChanged ();
};
#endif

View File

@@ -0,0 +1,48 @@
/*
* 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 "exiffiltersettings.h"
ExifFilterSettings::ExifFilterSettings () {
clear ();
}
void ExifFilterSettings::clear () {
fnumberFrom = 100;
fnumberTo = 0;
shutterFrom = 100;
shutterTo = 0;
isoFrom = 100000000;
isoTo = 0;
focalFrom = 1e8;
focalTo = 0;
lenses.clear ();
cameras.clear ();
expcomp.clear ();
filetypes.clear ();
filterFNumber = false;
filterShutter = false;
filterFocalLen = false;
filterISO = false;
filterExpComp = false;
filterCamera = false;
filterLens = false;
filterFiletype = false;
}

View File

@@ -0,0 +1,55 @@
/*
* 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 _EXIFFILTERSETTINGS_
#define _EXIFFILTERSETTINGS_
#include <set>
#include <string>
class ExifFilterSettings {
public:
std::set<std::string> filetypes;
std::set<std::string> cameras;
std::set<std::string> lenses;
std::set<std::string> expcomp;
double fnumberFrom;
double fnumberTo;
double shutterFrom;
double shutterTo;
double focalFrom;
double focalTo;
int isoFrom;
int isoTo;
bool filterFNumber;
bool filterShutter;
bool filterFocalLen;
bool filterISO;
bool filterExpComp;
bool filterCamera;
bool filterLens;
bool filterFiletype;
ExifFilterSettings ();
void clear ();
};
#endif

558
rtgui/exifpanel.cc Normal file
View File

@@ -0,0 +1,558 @@
/*
* 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 "exifpanel.h"
#include "../rtengine/safegtk.h"
#include "guiutils.h"
#include "rtimage.h"
using namespace rtengine;
using namespace rtengine::procparams;
using namespace rtexif;
ExifPanel::ExifPanel () : idata(NULL) {
recursiveOp = true;
exifTree = Gtk::manage(new Gtk::TreeView());
scrolledWindow = Gtk::manage(new Gtk::ScrolledWindow());
exifTree->set_headers_visible(false);
exifTree->set_rules_hint(false);
exifTree->set_reorderable(false);
exifTree->set_enable_search(true);
exifTree->get_selection()->set_mode (Gtk::SELECTION_MULTIPLE);
scrolledWindow->set_border_width(2);
scrolledWindow->set_shadow_type(Gtk::SHADOW_NONE);
scrolledWindow->set_policy(Gtk::POLICY_ALWAYS, Gtk::POLICY_ALWAYS);
scrolledWindow->property_window_placement().set_value(Gtk::CORNER_TOP_LEFT);
scrolledWindow->add(*exifTree);
exifTreeModel = Gtk::TreeStore::create(exifColumns);
exifTree->set_model (exifTreeModel);
delicon = safe_create_from_file ("gtk-close.png");
keepicon = safe_create_from_file ("gtk-apply.png");
editicon = safe_create_from_file ("gtk-add.png");
Gtk::TreeView::Column *viewcol = Gtk::manage(new Gtk::TreeView::Column ("Field Name"));
Gtk::CellRendererPixbuf* render_pb = Gtk::manage(new Gtk::CellRendererPixbuf ());
Gtk::CellRendererText *render_txt = Gtk::manage(new Gtk::CellRendererText());
viewcol->pack_start (*render_pb, false);
viewcol->pack_start (*render_txt, true);
viewcol->add_attribute (*render_pb, "pixbuf", exifColumns.icon);
viewcol->add_attribute (*render_txt, "markup", exifColumns.field);
render_pb->property_ypad() = 0;
render_txt->property_ypad() = 0;
render_pb->property_yalign() = 0;
render_txt->property_yalign() = 0;
exifTree->append_column (*viewcol);
Gtk::TreeView::Column *viewcolv = Gtk::manage(new Gtk::TreeView::Column ("Value"));
Gtk::CellRendererText *render_txtv = Gtk::manage(new Gtk::CellRendererText());
viewcolv->pack_start (*render_txtv, true);
viewcolv->add_attribute (*render_txtv, "markup", exifColumns.value);
render_txtv->property_ypad() = 0;
exifTree->append_column (*viewcolv);
pack_start (*scrolledWindow);
Gtk::HBox* buttons1 = Gtk::manage(new Gtk::HBox ());
Gtk::HBox* buttons2 = Gtk::manage(new Gtk::HBox ());
remove = Gtk::manage(new Gtk::Button (M("EXIFPANEL_REMOVE")));
remove->set_image (*Gtk::manage(new Gtk::Image (delicon)));
remove->set_tooltip_text (M("EXIFPANEL_REMOVEHINT"));
buttons1->pack_start (*remove);
keep = Gtk::manage(new Gtk::Button (M("EXIFPANEL_KEEP")));
keep->set_image (*Gtk::manage(new Gtk::Image (keepicon)));
keep->set_tooltip_text (M("EXIFPANEL_KEEPHINT"));
buttons1->pack_start (*keep);
add = Gtk::manage(new Gtk::Button (M("EXIFPANEL_ADDEDIT")));
add->set_image (*Gtk::manage(new Gtk::Image (editicon)));
add->set_tooltip_text (M("EXIFPANEL_ADDEDITHINT"));
buttons1->pack_start (*add);
reset = Gtk::manage(new Gtk::Button (M("EXIFPANEL_RESET")));
reset->set_image (*Gtk::manage(new RTImage ("gtk-undo-ltr.png", "gtk-undo-rtl.png")));
reset->set_tooltip_text (M("EXIFPANEL_RESETHINT"));
buttons2->pack_start (*reset);
resetAll = Gtk::manage(new Gtk::Button (M("EXIFPANEL_RESETALL")));
resetAll->set_image (*Gtk::manage(new RTImage ("gtk-undoall-ltr.png", "gtk-undoall-rtl.png")));
resetAll->set_tooltip_text (M("EXIFPANEL_RESETALLHINT"));
buttons2->pack_start (*resetAll);
pack_end (*buttons2, Gtk::PACK_SHRINK);
pack_end (*buttons1, Gtk::PACK_SHRINK);
exifTree->get_selection()->signal_changed().connect(sigc::mem_fun(*this, &ExifPanel::exifSelectionChanged));
exifTree->signal_row_activated().connect(sigc::mem_fun(*this, &ExifPanel::row_activated));
remove->signal_clicked().connect( sigc::mem_fun(*this, &ExifPanel::removePressed) );
keep->signal_clicked().connect( sigc::mem_fun(*this, &ExifPanel::keepPressed) );
reset->signal_clicked().connect( sigc::mem_fun(*this, &ExifPanel::resetPressed) );
resetAll->signal_clicked().connect( sigc::mem_fun(*this, &ExifPanel::resetAllPressed) );
add->signal_clicked().connect( sigc::mem_fun(*this, &ExifPanel::addPressed) );
show_all ();
}
ExifPanel::~ExifPanel () {
}
void ExifPanel::read (const ProcParams* pp, const ParamsEdited* pedited) {
disableListener ();
changeList = pp->exif;
setImageData (idata);
applyChangeList ();
exifSelectionChanged ();
enableListener ();
}
void ExifPanel::write (ProcParams* pp, ParamsEdited* pedited) {
// updateChangeList ();
pp->exif = changeList;
}
void ExifPanel::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) {
defChangeList = defParams->exif;
}
void ExifPanel::setImageData (const ImageMetaData* id) {
idata = id;
exifTreeModel->clear ();
const std::vector<Tag*>& defTags = ExifManager::getDefaultTIFFTags (NULL);
for (size_t i=0; i<defTags.size(); i++)
if (defTags[i]->nameToString() == "ImageWidth" || defTags[i]->nameToString() == "ImageHeight" || defTags[i]->nameToString() == "BitsPerSample")
addTag (exifTreeModel->children(), defTags[i]->nameToString(), "?", AC_SYSTEM, false);
else
addTag (exifTreeModel->children(), defTags[i]->nameToString(), defTags[i]->valueToString(), AC_SYSTEM, false);
if (id && id->getExifData ()) {
// id->getExifData ()->printAll ();
addDirectory (id->getExifData (), exifTreeModel->children());
}
}
Gtk::TreeModel::Children ExifPanel::addTag (const Gtk::TreeModel::Children& root, Glib::ustring field, Glib::ustring value, rtexif::ActionCode action, bool editable) {
Gtk::TreeModel::Row row = *(exifTreeModel->append(root));
row[exifColumns.action] = action;
row[exifColumns.editable] = editable;
row[exifColumns.edited] = false;
row[exifColumns.field_nopango] = field;
row[exifColumns.value_nopango] = value;
row[exifColumns.orig_value] = value;
if (action==AC_WRITE)
row[exifColumns.icon] = keepicon;
else if (action==AC_DONTWRITE)
row[exifColumns.icon] = delicon;
if (editable) {
row[exifColumns.field] = Glib::ustring("<b>") + escapeHtmlChars(field) + "</b>";
row[exifColumns.value] = Glib::ustring("<b>") + escapeHtmlChars(value) + "</b>";
}
else if (action==AC_SYSTEM) {
row[exifColumns.field] = Glib::ustring("<i>") + escapeHtmlChars(field) + "</i>";
row[exifColumns.value] = Glib::ustring("<i>") + escapeHtmlChars(value) + "</i>";
}
else {
row[exifColumns.field] = escapeHtmlChars(field);
row[exifColumns.value] = escapeHtmlChars(value);
}
return row.children();
}
void ExifPanel::addDirectory (const TagDirectory* dir, Gtk::TreeModel::Children root) {
for (int i=0; i<dir->getCount(); i++) {
Tag* t = (const_cast<TagDirectory*>(dir))->getTagByIndex (i);
if (t->getAttrib() && t->getAttrib()->action==AC_SYSTEM)
continue;
if (t->isDirectory())
for (int j=0; t->getDirectory(j); j++) {
Gtk::TreeModel::Children ch = addTag (root, t->nameToString (j), M("EXIFPANEL_SUBDIRECTORY"), t->getAttrib() ? t->getAttrib()->action : AC_DONTWRITE, t->getAttrib() && t->getAttrib()->editable);
addDirectory (t->getDirectory(j), ch);
}
else
addTag (root, t->nameToString (), t->valueToString (), t->getAttrib() ? (t->getOwnMemory()?t->getAttrib()->action:AC_SYSTEM) : AC_DONTWRITE, t->getAttrib() && t->getAttrib()->editable);
}
}
void ExifPanel::exifSelectionChanged () {
Glib::RefPtr<Gtk::TreeSelection> selection = exifTree->get_selection();
std::vector<Gtk::TreeModel::Path> sel = selection->get_selected_rows();
if (sel.size()>1) {
remove->set_sensitive (1);
keep->set_sensitive (1);
reset->set_sensitive (1);
}
else if (sel.size()==1) {
Gtk::TreeModel::iterator iter = exifTreeModel->get_iter (sel[0]);
if (iter->get_value (exifColumns.action)==AC_SYSTEM) {
remove->set_sensitive (0);
keep->set_sensitive (0);
reset->set_sensitive (0);
}
else if (!iter->children().empty()) {
remove->set_sensitive (1);
keep->set_sensitive (1);
reset->set_sensitive (1);
}
else if (iter->get_value(exifColumns.icon)==delicon) {
remove->set_sensitive (0);
keep->set_sensitive (1);
reset->set_sensitive (1);
}
else if (iter->get_value(exifColumns.icon)==keepicon || iter->get_value(exifColumns.icon)==editicon) {
keep->set_sensitive (0);
remove->set_sensitive (1);
reset->set_sensitive (1);
}
}
else {
remove->set_sensitive (0);
keep->set_sensitive (0);
reset->set_sensitive (0);
}
}
void ExifPanel::delIt (Gtk::TreeModel::iterator iter) {
if (!iter)
return;
if (iter->get_value (exifColumns.action) != AC_SYSTEM)
iter->set_value (exifColumns.icon, delicon);
if (recursiveOp)
for (Gtk::TreeModel::iterator i=iter->children().begin(); i!=iter->children().end(); i++)
delIt (i);
}
void ExifPanel::removePressed () {
std::vector<Gtk::TreeModel::Path> sel = exifTree->get_selection()->get_selected_rows();
for (size_t i=0; i<sel.size(); i++)
delIt (exifTreeModel->get_iter (sel[i]));
exifSelectionChanged ();
updateChangeList ();
notifyListener ();
}
void ExifPanel::keepIt (Gtk::TreeModel::iterator iter) {
if (!iter)
return;
if (iter->get_value (exifColumns.action) != AC_SYSTEM)
iter->set_value (exifColumns.icon, iter->get_value (exifColumns.edited) ? editicon : keepicon);
if (recursiveOp)
for (Gtk::TreeModel::iterator i=iter->children().begin(); i!=iter->children().end(); i++)
keepIt (i);
}
void ExifPanel::keepPressed () {
std::vector<Gtk::TreeModel::Path> sel = exifTree->get_selection()->get_selected_rows();
for (size_t i=0; i<sel.size(); i++)
keepIt (exifTreeModel->get_iter (sel[i]));
exifSelectionChanged ();
updateChangeList ();
notifyListener ();
}
/*void ExifPanel::resetIt (Gtk::TreeModel::iterator iter) {
if (!iter)
return;
if (iter->get_value (exifColumns.action)!=AC_SYSTEM)
iter->set_value (exifColumns.icon, iter->get_value (exifColumns.action) ? keepicon : delicon);
if (iter->get_value (exifColumns.edited)) {
iter->set_value (exifColumns.value, Glib::ustring("<b>") + iter->get_value(exifColumns.orig_value) + "</b>");
iter->set_value (exifColumns.value_nopango, iter->get_value(exifColumns.orig_value));
iter->set_value (exifColumns.edited, false);
}
if (iter->get_value (exifColumns.action)==AC_INVALID)
exifTreeModel->erase (iter);
else
if (recursiveOp)
for (Gtk::TreeModel::iterator i=iter->children().begin(); i!=iter->children().end(); i++)
resetIt (i);
}*/
Gtk::TreeModel::iterator ExifPanel::resetIt (Gtk::TreeModel::iterator iter) {
if (!iter)
return iter;
if (iter->get_value (exifColumns.action)!=AC_SYSTEM)
iter->set_value (exifColumns.icon, iter->get_value (exifColumns.action) ? keepicon : delicon);
if (iter->get_value (exifColumns.edited)) {
iter->set_value (exifColumns.value, Glib::ustring("<b>") + iter->get_value(exifColumns.orig_value) + "</b>");
iter->set_value (exifColumns.value_nopango, iter->get_value(exifColumns.orig_value));
iter->set_value (exifColumns.edited, false);
}
if (iter->get_value (exifColumns.action)==AC_INVALID) {
return exifTreeModel->erase (iter);
}
else
if (recursiveOp) {
Gtk::TreeModel::iterator i = iter->children().begin();
while (i && i != iter->children().end())
i = resetIt (i);
}
return ++iter;
}
void ExifPanel::resetPressed () {
std::vector<Gtk::TreeModel::Path> sel = exifTree->get_selection()->get_selected_rows();
for (size_t i=0; i<sel.size(); i++)
resetIt (exifTreeModel->get_iter (sel[i]));
exifSelectionChanged ();
updateChangeList ();
notifyListener ();
}
void ExifPanel::resetAllPressed () {
setImageData (idata);
changeList = defChangeList;
applyChangeList ();
exifSelectionChanged ();
notifyListener ();
}
void ExifPanel::addPressed () {
Gtk::Dialog* dialog = new Gtk::Dialog (M("EXIFPANEL_ADDTAGDLG_TITLE"), *((Gtk::Window*)get_toplevel()), true, true);
dialog->add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
dialog->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
Gtk::HBox* hb1 = new Gtk::HBox ();
Gtk::HBox* hb2 = new Gtk::HBox ();
Gtk::Label* tlabel = new Gtk::Label (M("EXIFPANEL_ADDTAGDLG_SELECTTAG")+":");
MyComboBoxText* tcombo = new MyComboBoxText ();
tcombo->append_text ("Artist");
tcombo->append_text ("Copyright");
tcombo->append_text ("ImageDescription");
tcombo->append_text ("Exif.UserComment");
hb1->pack_start (*tlabel, Gtk::PACK_SHRINK, 4);
hb1->pack_start (*tcombo);
Gtk::Label* vlabel = new Gtk::Label (M("EXIFPANEL_ADDTAGDLG_ENTERVALUE")+":");
Gtk::Entry* ventry = new Gtk::Entry ();
hb2->pack_start (*vlabel, Gtk::PACK_SHRINK, 4);
hb2->pack_start (*ventry);
Glib::ustring sel = getSelection (true);
if (sel=="")
tcombo->set_active_text ("Exif.UserComment");
else {
tcombo->set_active_text (sel);
if (tcombo->get_active ()<0) {
tcombo->append_text (sel);
tcombo->set_active_text (sel);
}
ventry->set_text (getSelectedValue ());
}
ventry->set_activates_default (true);
dialog->set_default_response (Gtk::RESPONSE_OK);
dialog->get_vbox()->pack_start (*hb1, Gtk::PACK_SHRINK);
dialog->get_vbox()->pack_start (*hb2, Gtk::PACK_SHRINK, 4);
tlabel->show ();
tcombo->show ();
vlabel->show ();
ventry->show ();
hb1->show ();
hb2->show ();
if (dialog->run ()== Gtk::RESPONSE_OK) {
editTag (exifTreeModel->children(), tcombo->get_active_text(), ventry->get_text());
updateChangeList ();
notifyListener ();
}
delete dialog;
delete tlabel;
delete tcombo;
delete vlabel;
delete ventry;
delete hb1;
delete hb2;
}
void ExifPanel::editTag (Gtk::TreeModel::Children root, Glib::ustring name, Glib::ustring value) {
Glib::ustring::size_type dp = name.find_first_of ('.');
Glib::ustring fseg = name.substr (0,dp);
// look up first segment of the path
Gtk::TreeModel::iterator iter;
for (iter = root.begin(); iter!=root.end(); iter++)
if (iter->get_value (exifColumns.field_nopango) == fseg)
break;
if (iter==root.end() && value!="#keep" && value!="#delete") {
iter = exifTreeModel->append(root);
iter->set_value (exifColumns.field_nopango, fseg);
iter->set_value (exifColumns.action, AC_INVALID);
if (dp==Glib::ustring::npos) {
iter->set_value (exifColumns.value, Glib::ustring("<b>") + value + "</b>");
iter->set_value (exifColumns.value_nopango, value);
iter->set_value (exifColumns.orig_value, value);
iter->set_value (exifColumns.field, Glib::ustring("<b>") + fseg + "</b>");
iter->set_value (exifColumns.edited, true);
iter->set_value (exifColumns.editable, true);
iter->set_value (exifColumns.icon, editicon);
}
else {
iter->set_value (exifColumns.value, Glib::ustring(M("EXIFPANEL_SUBDIRECTORY")));
iter->set_value (exifColumns.value_nopango, Glib::ustring(M("EXIFPANEL_SUBDIRECTORY")));
iter->set_value (exifColumns.field, fseg);
iter->set_value (exifColumns.icon, keepicon);
iter->set_value (exifColumns.orig_value, Glib::ustring(M("EXIFPANEL_SUBDIRECTORY")));
}
}
if (dp==Glib::ustring::npos) {
if (value=="#keep" && iter->get_value (exifColumns.action)!=AC_SYSTEM)
iter->set_value (exifColumns.icon, iter->get_value (exifColumns.edited) ? editicon : keepicon);
else if (value=="#delete" && iter->get_value (exifColumns.action)!=AC_SYSTEM)
iter->set_value (exifColumns.icon, delicon);
else {
iter->set_value (exifColumns.value, Glib::ustring("<b>") + value + "</b>");
iter->set_value (exifColumns.value_nopango, value);
iter->set_value (exifColumns.edited, true);
iter->set_value (exifColumns.icon, editicon);
}
}
else
editTag (iter->children(), name.substr (dp+1, Glib::ustring::npos), value);
}
Glib::ustring ExifPanel::getSelectedValue () {
Glib::RefPtr<Gtk::TreeSelection> selection = exifTree->get_selection();
std::vector<Gtk::TreeModel::Path> rows = selection->get_selected_rows();
if (rows.size()!=1)
return "";
Gtk::TreeModel::iterator iter = exifTreeModel->get_iter (rows[0]);
if (iter)
return iter->get_value (exifColumns.value_nopango);
return "";
}
Glib::ustring ExifPanel::getSelection (bool onlyeditable) {
Glib::RefPtr<Gtk::TreeSelection> selection = exifTree->get_selection();
std::vector<Gtk::TreeModel::Path> rows = selection->get_selected_rows();
if (rows.size()!=1)
return "";
Gtk::TreeModel::iterator iter = exifTreeModel->get_iter (rows[0]);
Glib::ustring ret = "";
bool first = true;
bool editable = false;
while (iter) {
if (first)
ret = iter->get_value (exifColumns.field_nopango);
else
ret = iter->get_value (exifColumns.field_nopango) + "." + ret;
editable = iter->get_value (exifColumns.editable);
iter = iter->parent ();
first = false;
}
if (!editable && onlyeditable)
return "";
return ret;
}
void ExifPanel::updateChangeList (Gtk::TreeModel::Children root, std::string prefix) {
if (prefix!="")
prefix = prefix + ".";
Gtk::TreeModel::iterator iter;
for (iter = root.begin(); iter!=root.end(); iter++) {
if (iter->get_value (exifColumns.edited) == true)
changeList[ prefix+iter->get_value (exifColumns.field_nopango) ] = iter->get_value (exifColumns.value_nopango);
else if (iter->get_value (exifColumns.action) == AC_WRITE && iter->get_value (exifColumns.icon) == delicon)
changeList[ prefix+iter->get_value (exifColumns.field_nopango) ] = "#delete";
else if (iter->get_value (exifColumns.action) == AC_DONTWRITE && iter->get_value (exifColumns.icon) == keepicon)
changeList[ prefix+iter->get_value (exifColumns.field_nopango) ] = "#keep";
if (iter->get_value (exifColumns.icon) == keepicon)
updateChangeList (iter->children(), prefix + iter->get_value (exifColumns.field_nopango));
}
}
void ExifPanel::updateChangeList () {
changeList.clear ();
updateChangeList (exifTreeModel->children(), "");
}
void ExifPanel::applyChangeList () {
for (rtengine::procparams::ExifPairs::iterator i=changeList.begin(); i!=changeList.end(); i++)
editTag (exifTreeModel->children(), i->first, i->second);
}
void ExifPanel::row_activated (const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column) {
Gtk::TreeModel::iterator iter = exifTreeModel->get_iter (path);
if (iter) {
if (!iter->children().empty())
if (exifTree->row_expanded (path))
exifTree->collapse_row (path);
else
exifTree->expand_row (path, false);
else if (iter->get_value (exifColumns.editable))
addPressed ();
}
}
void ExifPanel::notifyListener () {
if (listener)
listener->panelChanged (EvExif, M("HISTORY_CHANGED"));
}

97
rtgui/exifpanel.h Normal file
View File

@@ -0,0 +1,97 @@
/*
* 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 _EXIFPANEL_
#define _EXIFPANEL_
#include <gtkmm.h>
#include "toolpanel.h"
class ExifPanel : public Gtk::VBox, public ToolPanel {
private:
const rtengine::ImageMetaData* idata;
int fullw, fullh, cx, cy, cw, ch;
bool crenabled;
rtengine::procparams::ExifPairs changeList;
rtengine::procparams::ExifPairs defChangeList;
bool recursiveOp;
class ExifColumns : public Gtk::TreeModelColumnRecord {
public:
Gtk::TreeModelColumn<Glib::RefPtr<Gdk::Pixbuf> > icon;
Gtk::TreeModelColumn<Glib::ustring> field;
Gtk::TreeModelColumn<Glib::ustring> field_nopango;
Gtk::TreeModelColumn<Glib::ustring> value;
Gtk::TreeModelColumn<Glib::ustring> value_nopango;
Gtk::TreeModelColumn<Glib::ustring> orig_value;
Gtk::TreeModelColumn<rtexif::ActionCode> action;
Gtk::TreeModelColumn<bool> editable;
Gtk::TreeModelColumn<bool> edited;
ExifColumns() { add(field); add(value); add(icon); add(action); add(edited); add(field_nopango); add(value_nopango); add(editable); add(orig_value); }
};
Glib::RefPtr<Gdk::Pixbuf> delicon;
Glib::RefPtr<Gdk::Pixbuf> keepicon;
Glib::RefPtr<Gdk::Pixbuf> editicon;
ExifColumns exifColumns;
Gtk::TreeView* exifTree;
Gtk::ScrolledWindow* scrolledWindow;
Glib::RefPtr<Gtk::TreeStore> exifTreeModel;
Gtk::Button* remove;
Gtk::Button* keep;
Gtk::Button* add;
Gtk::Button* reset;
Gtk::Button* resetAll;
Gtk::TreeModel::Children addTag (const Gtk::TreeModel::Children& root, Glib::ustring field, Glib::ustring value, rtexif::ActionCode action, bool editable);
void editTag (Gtk::TreeModel::Children root, Glib::ustring name, Glib::ustring value);
void updateChangeList (Gtk::TreeModel::Children root, std::string prefix);
void addDirectory (const rtexif::TagDirectory* dir, Gtk::TreeModel::Children root);
Glib::ustring getSelection (bool onlyifeditable=false);
Glib::ustring getSelectedValue ();
void updateChangeList ();
void applyChangeList ();
void keepIt (Gtk::TreeModel::iterator iter);
void delIt (Gtk::TreeModel::iterator iter);
Gtk::TreeModel::iterator resetIt (Gtk::TreeModel::iterator iter);
public:
ExifPanel ();
virtual ~ExifPanel ();
void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL);
void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL);
void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL);
void setImageData (const rtengine::ImageMetaData* id);
void exifSelectionChanged ();
void removePressed ();
void keepPressed ();
void resetPressed ();
void resetAllPressed ();
void addPressed ();
void row_activated (const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column);
void notifyListener ();
};
#endif

422
rtgui/exportpanel.cc Normal file
View File

@@ -0,0 +1,422 @@
/*
* This file is part of RawTherapee.
*
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
* Copyright (c) 2012 Michael Ezra <michael@michaelezra.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 "exportpanel.h"
#include "multilangmgr.h"
#include "options.h"
#include "rtimage.h"
using namespace rtengine;
using namespace rtengine::procparams;
ExportPanel::ExportPanel () : listener (NULL) {
set_border_width (4);
/*enabled = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_ENABLE")) );
pack_start(*enabled, Gtk::PACK_SHRINK, 4);
pack_start (*Gtk::manage(new Gtk::HSeparator ()), Gtk::PACK_SHRINK, 2);*/
Gtk::Label* labExportTitle = Gtk::manage ( new Gtk::Label (M("EXPORT_FASTEXPORTOPTIONS")) );
labExportTitle->set_use_markup (true);
labExportTitle->set_tooltip_text (M("EXPORT_INSTRUCTIONS"));
labExportTitle->set_alignment(Gtk::ALIGN_LEFT);
pack_start(*labExportTitle, Gtk::PACK_SHRINK, 4);
bypass_ALL = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_ALL")));
bypass_sharpening = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_SHARPENING")));
bypass_sharpenEdge = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_SHARPENEDGE")));
bypass_sharpenMicro = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_SHARPENMICRO")));
//bypass_lumaDenoise = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_LUMADENOISE")));
//bypass_colorDenoise = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_COLORDENOISE")));
bypass_defringe = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_DEFRINGE")));
bypass_dirpyrDenoise = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_DIRPYRDENOISE")));
bypass_sh_hq = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_SH_HQ")));
bypass_dirpyrequalizer = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_DIRPYREQUALIZER")));
bypass_wavelet = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_EQUALIZER")));
bypass_raw_ccSteps = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_RAW_CCSTEPS")));
bypass_raw_ca = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_RAW_CA")));
bypass_raw_df = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_RAW_DF")));
bypass_raw_ff = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_RAW_FF")));
// ---------------------- Bayer sensor frame -----------------------
Gtk::Frame *bayerFrame = Gtk::manage( new Gtk::Frame(M("TP_RAW_SENSOR_BAYER")));
Gtk::VBox* bayerFrameVBox = Gtk::manage (new Gtk::VBox ());
Gtk::HBox* hb_raw_bayer_method = Gtk::manage (new Gtk::HBox ());
hb_raw_bayer_method->pack_start (*Gtk::manage (new Gtk::Label ( M("EXPORT_RAW_DMETHOD") +": ")),Gtk::PACK_SHRINK, 4);
raw_bayer_method = Gtk::manage (new MyComboBoxText ());
for( size_t i=0; i< procparams::RAWParams::BayerSensor::numMethods;i++)
raw_bayer_method->append_text(procparams::RAWParams::BayerSensor::methodstring[i]);
raw_bayer_method->set_active(0);
hb_raw_bayer_method->pack_end (*raw_bayer_method, Gtk::PACK_EXPAND_WIDGET, 4);
//bypass_raw_all_enhance = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_RAW_ALL_ENHANCE")));
bypass_raw_bayer_linenoise = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_RAW_LINENOISE")));
bypass_raw_bayer_greenthresh = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_RAW_GREENTHRESH")));
bypass_raw_bayer_dcb_iterations = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_RAW_DCB_ITERATIONS")));
bypass_raw_bayer_dcb_enhance = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_RAW_DCB_ENHANCE")));
bypass_raw_bayer_lmmse_iterations = Gtk::manage ( new Gtk::CheckButton (M("EXPORT_BYPASS_RAW_LMMSE_ITERATIONS")));
// ---------------------- Bayer sensor frame -----------------------
Gtk::Frame *xtransFrame = Gtk::manage( new Gtk::Frame(M("TP_RAW_SENSOR_XTRANS")));
Gtk::VBox* xtransFrameVBox = Gtk::manage (new Gtk::VBox ());
Gtk::HBox* hb_raw_xtrans_method = Gtk::manage (new Gtk::HBox ());
hb_raw_xtrans_method->pack_start (*Gtk::manage (new Gtk::Label ( M("EXPORT_RAW_DMETHOD") +": ")),Gtk::PACK_SHRINK, 4);
raw_xtrans_method = Gtk::manage (new MyComboBoxText ());
for( size_t i=0; i< procparams::RAWParams::XTransSensor::numMethods;i++)
raw_xtrans_method->append_text(procparams::RAWParams::XTransSensor::methodstring[i]);
raw_xtrans_method->set_active(0);
hb_raw_xtrans_method->pack_end (*raw_xtrans_method, Gtk::PACK_EXPAND_WIDGET, 4);
// ----------------------------------------------------------------
// start global packing
pack_start(*bypass_ALL , Gtk::PACK_SHRINK, 4);
pack_start(*Gtk::manage(new Gtk::HSeparator ()), Gtk::PACK_SHRINK, 4);
pack_start(*bypass_sharpening , Gtk::PACK_SHRINK, 4);
pack_start(*bypass_sharpenEdge , Gtk::PACK_SHRINK, 4);
pack_start(*bypass_sharpenMicro , Gtk::PACK_SHRINK, 4);
//pack_start(*bypass_lumaDenoise , Gtk::PACK_SHRINK, 4);
//pack_start(*bypass_colorDenoise , Gtk::PACK_SHRINK, 4);
pack_start(*bypass_defringe , Gtk::PACK_SHRINK, 4);
pack_start(*bypass_dirpyrDenoise, Gtk::PACK_SHRINK, 4);
pack_start(*bypass_sh_hq , Gtk::PACK_SHRINK, 4);
pack_start(*bypass_dirpyrequalizer , Gtk::PACK_SHRINK, 4);
pack_start(*bypass_wavelet , Gtk::PACK_SHRINK, 4);
bayerFrameVBox->pack_start(*hb_raw_bayer_method, Gtk::PACK_SHRINK, 4);
//bayerFrameVBox->pack_start(*bypass_raw_all_enhance , Gtk::PACK_SHRINK, 4);
bayerFrameVBox->pack_start(*bypass_raw_bayer_dcb_iterations, Gtk::PACK_SHRINK, 4);
bayerFrameVBox->pack_start(*bypass_raw_bayer_dcb_enhance , Gtk::PACK_SHRINK, 4);
bayerFrameVBox->pack_start(*bypass_raw_bayer_lmmse_iterations, Gtk::PACK_SHRINK, 4);
bayerFrameVBox->pack_start(*bypass_raw_bayer_linenoise , Gtk::PACK_SHRINK, 4);
bayerFrameVBox->pack_start(*bypass_raw_bayer_greenthresh , Gtk::PACK_SHRINK, 4);
bayerFrame->add(*bayerFrameVBox);
xtransFrameVBox->pack_start(*hb_raw_xtrans_method, Gtk::PACK_SHRINK, 4);
xtransFrame->add(*xtransFrameVBox);
pack_start(*bypass_raw_ccSteps , Gtk::PACK_SHRINK, 4);
pack_start(*bypass_raw_ca , Gtk::PACK_SHRINK, 4);
pack_start(*bypass_raw_df , Gtk::PACK_SHRINK, 4);
pack_start(*bypass_raw_ff , Gtk::PACK_SHRINK, 4);
pack_start (*Gtk::manage(new Gtk::HSeparator ()), Gtk::PACK_SHRINK, 2);
// Resize options
Gtk::HBox* rmbox = Gtk::manage (new Gtk::HBox ());
rmbox->pack_start (*Gtk::manage (new Gtk::Label (M("TP_RESIZE_LABEL"))), Gtk::PACK_SHRINK, 4);
pack_start (*rmbox, Gtk::PACK_SHRINK, 4);
Gtk::HBox* wbox = Gtk::manage (new Gtk::HBox ());
Gtk::HBox* hbox = Gtk::manage (new Gtk::HBox ());
MaxWidth = Gtk::manage (new MySpinButton ());
MaxHeight = Gtk::manage (new MySpinButton ());
wbox->pack_start (*Gtk::manage (new Gtk::Label (M("EXPORT_MAXWIDTH"))), Gtk::PACK_SHRINK, 4);
wbox->pack_start (*MaxWidth);
hbox->pack_start (*Gtk::manage (new Gtk::Label (M("EXPORT_MAXHEIGHT"))), Gtk::PACK_SHRINK, 4);
hbox->pack_start (*MaxHeight);
pack_start (*wbox, Gtk::PACK_SHRINK, 4);
pack_start (*hbox, Gtk::PACK_SHRINK, 4);
MaxWidth->set_digits (0);
MaxWidth->set_increments (1,100);
MaxWidth->set_value (options.fastexport_resize_width);
MaxWidth->set_range (32, 3000);
MaxHeight->set_digits (0);
MaxHeight->set_increments (1,100);
MaxHeight->set_value (options.fastexport_resize_height);
MaxHeight->set_range (32, 3000);
// Buttons
btnFastExport = Gtk::manage ( new Gtk::Button (M("EXPORT_PUTTOQUEUEFAST")) );
btnFastExport->set_image (*Gtk::manage (new RTImage ("processing.png")));
pack_start(*btnFastExport, Gtk::PACK_SHRINK, 4);
// add panel ending
Gtk::VBox* vboxpe = Gtk::manage (new Gtk::VBox ());
Gtk::HSeparator* hseptpe = Gtk::manage (new Gtk::HSeparator ());
Gtk::Image* peImg = Gtk::manage (new RTImage("PanelEnding.png"));
vboxpe->pack_start(*hseptpe, Gtk::PACK_SHRINK, 4);
vboxpe->pack_start(*peImg);
pack_start(*vboxpe, Gtk::PACK_SHRINK, 0);
btnFastExport->signal_clicked().connect( sigc::mem_fun(*this, &ExportPanel::FastExportPressed) );
//btnExportLoadSettings->signal_clicked().connect( sigc::mem_fun(*this, &ExportPanel::LoadSettings) );
//btnExportSaveSettings->signal_clicked().connect( sigc::mem_fun(*this, &ExportPanel::SaveSettings) );
bypass_ALLconn = bypass_ALL->signal_toggled().connect (sigc::mem_fun(*this, &ExportPanel::bypassALL_Toggled));
bypass_sharpeningConn = bypass_sharpening->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true));
bypass_sharpenEdgeConn = bypass_sharpenEdge->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true));
bypass_sharpenMicroConn = bypass_sharpenMicro->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true));
//bypass_lumaDenoiseConn = bypass_lumaDenoise->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true));
//bypass_colorDenoiseConn = bypass_colorDenoise->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true));
bypass_defringeConn = bypass_defringe->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true));
bypass_dirpyrDenoiseConn = bypass_dirpyrDenoise->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true));
bypass_sh_hqConn = bypass_sh_hq->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true));
bypass_dirpyrequalizerConn = bypass_dirpyrequalizer->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true));
bypass_waveletConn = bypass_wavelet->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true));
//bypass_raw_all_enhanceConn = bypass_raw_bayer_all_enhance->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true));
bypass_raw_bayer_dcb_iterationsConn = bypass_raw_bayer_dcb_iterations->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true));
bypass_raw_bayer_dcb_enhanceConn = bypass_raw_bayer_dcb_enhance->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true));
bypass_raw_bayer_lmmse_iterationsConn = bypass_raw_bayer_lmmse_iterations->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true));
bypass_raw_bayer_linenoiseConn = bypass_raw_bayer_linenoise->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true));
bypass_raw_bayer_greenthreshConn = bypass_raw_bayer_greenthresh->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true));
bypass_raw_ccStepsConn = bypass_raw_ccSteps->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true));
bypass_raw_caConn = bypass_raw_ca->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true));
bypass_raw_dfConn = bypass_raw_df->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true));
bypass_raw_ffConn = bypass_raw_ff->signal_toggled().connect (sigc::bind (sigc::mem_fun(*bypass_ALL, &Gtk::CheckButton::set_inconsistent), true));
LoadDefaultSettings();
}
/*bool ExportPanel::isEnabled () {
return enabled->get_active () && is_sensitive();
}*/
void ExportPanel::FastExportPressed (){
// options is the container for making these settings available globally.
// Therefore, settings must be saved to options before they are used further
SaveSettingsAsDefault();
if (listener)
listener->exportRequested ();
}
void ExportPanel::SaveSettingsAsDefault(){
// Save fast export settings to options
options.fastexport_bypass_sharpening = bypass_sharpening->get_active ();
options.fastexport_bypass_sharpenEdge = bypass_sharpenEdge->get_active ();
options.fastexport_bypass_sharpenMicro = bypass_sharpenMicro->get_active ();
//options.fastexport_bypass_lumaDenoise = bypass_lumaDenoise->get_active ();
//options.fastexport_bypass_colorDenoise = bypass_colorDenoise->get_active ();
options.fastexport_bypass_defringe = bypass_defringe->get_active ();
options.fastexport_bypass_dirpyrDenoise = bypass_dirpyrDenoise->get_active ();
options.fastexport_bypass_sh_hq = bypass_sh_hq->get_active ();
options.fastexport_bypass_dirpyrequalizer = bypass_dirpyrequalizer->get_active ();
options.fastexport_bypass_wavelet = bypass_wavelet->get_active ();
//options.fastexport_bypass_raw_bayer_all_enhance = bypass_raw_all_enhance->get_active ();
options.fastexport_bypass_raw_bayer_dcb_iterations = bypass_raw_bayer_dcb_iterations->get_active ();
options.fastexport_bypass_raw_bayer_dcb_enhance = bypass_raw_bayer_dcb_enhance->get_active ();
options.fastexport_bypass_raw_bayer_lmmse_iterations = bypass_raw_bayer_lmmse_iterations->get_active();
options.fastexport_bypass_raw_bayer_linenoise = bypass_raw_bayer_linenoise->get_active ();
options.fastexport_bypass_raw_bayer_greenthresh = bypass_raw_bayer_greenthresh->get_active ();
options.fastexport_bypass_raw_ccSteps = bypass_raw_ccSteps->get_active ();
options.fastexport_bypass_raw_ca = bypass_raw_ca->get_active ();
options.fastexport_bypass_raw_df = bypass_raw_df->get_active ();
options.fastexport_bypass_raw_ff = bypass_raw_ff->get_active ();
//saving Bayer demosaic_method
int currentRow = raw_bayer_method->get_active_row_number();
if( currentRow>=0 && currentRow < procparams::RAWParams::BayerSensor::numMethods)
options.fastexport_raw_bayer_method = procparams::RAWParams::BayerSensor::methodstring[currentRow];
//saving X-Trans demosaic_method
currentRow = raw_xtrans_method->get_active_row_number();
if( currentRow>=0 && currentRow < procparams::RAWParams::XTransSensor::numMethods)
options.fastexport_raw_xtrans_method = procparams::RAWParams::XTransSensor::methodstring[currentRow];
// options.fastexport_icm_input = icm_input ;
// options.fastexport_icm_working = icm_working ;
// options.fastexport_icm_output = icm_output ;
// options.fastexport_icm_gamma = icm_gamma ;
// options.fastexport_resize_enabled = resize_enabled ;
// options.fastexport_resize_scale = resize_scale ;
// options.fastexport_resize_appliesTo = resize_appliesTo;
// options.fastexport_resize_dataspec = resize_dataspec ;
options.fastexport_resize_method = "Lanczos";
options.fastexport_resize_width = MaxWidth->get_value_as_int ();
options.fastexport_resize_height = MaxHeight->get_value_as_int ();
}
void ExportPanel::LoadDefaultSettings(){
// Load fast export settings from options
bypass_sharpening->set_active (options.fastexport_bypass_sharpening );
bypass_sharpenEdge->set_active (options.fastexport_bypass_sharpenEdge );
bypass_sharpenMicro->set_active (options.fastexport_bypass_sharpenMicro );
//bypass_lumaDenoise->set_active (options.fastexport_bypass_lumaDenoise );
//bypass_colorDenoise->set_active (options.fastexport_bypass_colorDenoise );
bypass_defringe->set_active (options.fastexport_bypass_defringe );
bypass_dirpyrDenoise->set_active (options.fastexport_bypass_dirpyrDenoise );
bypass_sh_hq->set_active (options.fastexport_bypass_sh_hq );
bypass_dirpyrequalizer->set_active (options.fastexport_bypass_dirpyrequalizer );
bypass_wavelet->set_active (options.fastexport_bypass_wavelet );
//bypass_raw_bayer_all_enhance->set_active (options.fastexport_bypass_raw_bayer_all_enhance );
bypass_raw_bayer_dcb_iterations->set_active (options.fastexport_bypass_raw_bayer_dcb_iterations );
bypass_raw_bayer_dcb_enhance->set_active (options.fastexport_bypass_raw_bayer_dcb_enhance );
bypass_raw_bayer_lmmse_iterations->set_active(options.fastexport_bypass_raw_bayer_lmmse_iterations);
bypass_raw_bayer_linenoise->set_active (options.fastexport_bypass_raw_bayer_linenoise );
bypass_raw_bayer_greenthresh->set_active (options.fastexport_bypass_raw_bayer_greenthresh );
bypass_raw_ccSteps->set_active (options.fastexport_bypass_raw_ccSteps );
bypass_raw_ca->set_active (options.fastexport_bypass_raw_ca );
bypass_raw_df->set_active (options.fastexport_bypass_raw_df );
bypass_raw_ff->set_active (options.fastexport_bypass_raw_ff );
// Bayer demosaic method
raw_bayer_method->set_active(procparams::RAWParams::BayerSensor::numMethods);
for( size_t i=0; i< procparams::RAWParams::BayerSensor::numMethods;i++)
if( options.fastexport_raw_bayer_method == procparams::RAWParams::BayerSensor::methodstring[i]) {
raw_bayer_method->set_active(i);
break;
}
// X-Trans demosaic method
raw_xtrans_method->set_active(procparams::RAWParams::XTransSensor::numMethods);
for( size_t i=0; i< procparams::RAWParams::XTransSensor::numMethods;i++)
if( options.fastexport_raw_xtrans_method == procparams::RAWParams::XTransSensor::methodstring[i]) {
raw_xtrans_method->set_active(i);
break;
}
// icm_input = options.fastexport_icm_input ;
// icm_working = options.fastexport_icm_working ;
// icm_output = options.fastexport_icm_output ;
// icm_gamma = options.fastexport_icm_gamma ;
// resize_enabled = options.fastexport_resize_enabled ;
// resize_scale = options.fastexport_resize_scale ;
// resize_appliesTo = options.fastexport_resize_appliesTo;
// resize_dataspec = options.fastexport_resize_dataspec ;
MaxWidth->set_value(options.fastexport_resize_width);
MaxHeight->set_value(options.fastexport_resize_height);
}
void ExportPanel::LoadSettings(){
// load settings from file
}
void ExportPanel::SaveSettings(){
// save settings to file
}
void ExportPanel::bypassALL_Toggled(){
bypass_sharpeningConn.block (true);
bypass_sharpenEdgeConn.block (true);
bypass_sharpenMicroConn.block (true);
//bypass_lumaDenoiseConn.block (true);
//bypass_colorDenoiseConn.block (true);
bypass_defringeConn.block (true);
bypass_dirpyrDenoiseConn.block (true);
bypass_sh_hqConn.block (true);
bypass_dirpyrequalizerConn.block (true);
bypass_waveletConn.block (true);
//bypass_raw_bayer_all_enhanceConn.block (true);
bypass_raw_bayer_dcb_iterationsConn.block (true);
bypass_raw_bayer_dcb_enhanceConn.block (true);
bypass_raw_bayer_lmmse_iterationsConn.block (true);
bypass_raw_bayer_linenoiseConn.block (true);
bypass_raw_bayer_greenthreshConn.block (true);
bypass_raw_ccStepsConn.block (true);
bypass_raw_caConn.block (true);
bypass_raw_dfConn.block (true);
bypass_raw_ffConn.block (true);
bypass_ALL->set_inconsistent (false);
bypass_sharpening->set_active(bypass_ALL->get_active());
bypass_sharpenEdge->set_active(bypass_ALL->get_active());
bypass_sharpenMicro->set_active(bypass_ALL->get_active());
//bypass_lumaDenoise->set_active(bypass_ALL->get_active());
//bypass_colorDenoise->set_active(bypass_ALL->get_active());
bypass_defringe->set_active(bypass_ALL->get_active());
bypass_dirpyrDenoise->set_active(bypass_ALL->get_active());
bypass_sh_hq->set_active(bypass_ALL->get_active());
bypass_dirpyrequalizer->set_active(bypass_ALL->get_active());
bypass_wavelet->set_active(bypass_ALL->get_active());
//bypass_raw_bayer_all_enhance->set_active(bypass_ALL->get_active());
bypass_raw_bayer_dcb_iterations->set_active(bypass_ALL->get_active());
bypass_raw_bayer_dcb_enhance->set_active(bypass_ALL->get_active());
bypass_raw_bayer_lmmse_iterations->set_active(bypass_ALL->get_active());
bypass_raw_bayer_linenoise->set_active(bypass_ALL->get_active());
bypass_raw_bayer_greenthresh->set_active(bypass_ALL->get_active());
bypass_raw_ccSteps->set_active(bypass_ALL->get_active());
bypass_raw_ca->set_active(bypass_ALL->get_active());
bypass_raw_df->set_active(bypass_ALL->get_active());
bypass_raw_ff->set_active(bypass_ALL->get_active());
bypass_sharpeningConn.block (false);
bypass_sharpenEdgeConn.block (false);
bypass_sharpenMicroConn.block (false);
//bypass_lumaDenoiseConn.block (false);
//bypass_colorDenoiseConn.block (false);
bypass_defringeConn.block (false);
bypass_dirpyrDenoiseConn.block (false);
bypass_sh_hqConn.block (false);
bypass_dirpyrequalizerConn.block (false);
bypass_waveletConn.block (false);
//bypass_raw_bayer_all_enhanceConn.block (false);
bypass_raw_bayer_dcb_iterationsConn.block (false);
bypass_raw_bayer_dcb_enhanceConn.block (false);
bypass_raw_bayer_lmmse_iterationsConn.block (false);
bypass_raw_bayer_linenoiseConn.block (false);
bypass_raw_bayer_greenthreshConn.block (false);
bypass_raw_ccStepsConn.block (false);
bypass_raw_caConn.block (false);
bypass_raw_dfConn.block (false);
bypass_raw_ffConn.block (false);
}
/*
fastexport_bypass_sharpening
fastexport_bypass_sharpenEdge
fastexport_bypass_sharpenMicro
fastexport_bypass_lumaDenoise
fastexport_bypass_colorDenoise
fastexport_bypass_defringe
fastexport_bypass_dirpyrDenoise
fastexport_bypass_sh_hq
fastexport_bypass_dirpyrequalizer
fastexport_raw_bayer_method
fastexport_bypass_raw_bayer_all_enhance
fastexport_bypass_raw_bayer_dcb_iterations
fastexport_bypass_raw_bayer_dcb_enhance
fastexport_bypass_raw_bayer_linenoise
fastexport_bypass_raw_bayer_greenthresh
fastexport_raw_xtrans_method
fastexport_bypass_raw_ccSteps
fastexport_bypass_raw_ca
fastexport_bypass_raw_df
fastexport_bypass_raw_ff
fastexport_icm_input
fastexport_icm_working
fastexport_icm_output
fastexport_icm_gamma
fastexport_resize_enabled
fastexport_resize_scale
fastexport_resize_appliesTo
fastexport_resize_method
fastexport_resize_dataspec
fastexport_resize_width
fastexport_resize_height
*/

120
rtgui/exportpanel.h Normal file
View File

@@ -0,0 +1,120 @@
/*
* This file is part of RawTherapee.
*
* Copyright (c) 2004-2012 Gabor Horvath <hgabor@rawtherapee.com>
* Copyright (c) 2012 Michael Ezra <michael@michaelezra.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 _EXPORTPANEL_
#define _EXPORTPANEL_
#include <gtkmm.h>
#include "guiutils.h"
#include "adjuster.h"
class ExportPanelListener {
public:
virtual void exportRequested () {}
};
class ExportPanel : public Gtk::VBox {
protected:
//Gtk::CheckButton* enabled;
Gtk::CheckButton* bypass_ALL;
Gtk::CheckButton* bypass_sharpenEdge;
Gtk::CheckButton* bypass_sharpenMicro;
Gtk::CheckButton* bypass_sharpening;
//Gtk::CheckButton* bypass_lumaDenoise;
//Gtk::CheckButton* bypass_colorDenoise;
Gtk::CheckButton* bypass_defringe;
Gtk::CheckButton* bypass_dirpyrDenoise;
Gtk::CheckButton* bypass_sh_hq;
/* icm_input = "(camera)";
icm_working = "sRGB";
icm_output = "RT_sRGB";
icm_gamma = "default";
*/
Gtk::CheckButton* bypass_dirpyrequalizer; // also could leave untouched but disable only small radius adjustments
//Gtk::CheckButton* bypass_raw_all_enhance;
Gtk::CheckButton* bypass_wavelet; // also could leave untouched but disable only small radius adjustments
MyComboBoxText* raw_bayer_method;
Gtk::CheckButton* bypass_raw_bayer_dcb_iterations;
Gtk::CheckButton* bypass_raw_bayer_dcb_enhance;
Gtk::CheckButton* bypass_raw_bayer_lmmse_iterations;
//Gtk::CheckButton* bypass_raw_bayer_all_enhance;
Gtk::CheckButton* bypass_raw_bayer_linenoise;
Gtk::CheckButton* bypass_raw_bayer_greenthresh;
Gtk::CheckButton* bypass_raw_ccSteps;
Gtk::CheckButton* bypass_raw_ca; //wraps raw.cared, raw.cablue, raw.ca_autocorrect
Gtk::CheckButton* bypass_raw_df; //wraps raw.dark_frame, raw.df_AutoSelect
Gtk::CheckButton* bypass_raw_ff; //wraps raw.ff_file, raw.ff_AutoSelect
MyComboBoxText* raw_xtrans_method;
Gtk::Button* btnFastExport;
Gtk::Button* btnExportLoadSettings;
Gtk::Button* btnExportSaveSettings;
MySpinButton* MaxWidth;
MySpinButton* MaxHeight;
sigc::connection enabledconn, bypass_ALLconn, FastExportconn, ExportLoadSettingsconn, ExportSaveSettingsconn;
sigc::connection bypass_sharpeningConn ;
sigc::connection bypass_sharpenEdgeConn ;
sigc::connection bypass_sharpenMicroConn ;
//sigc::connection bypass_lumaDenoiseConn ;
//sigc::connection bypass_colorDenoiseConn ;
sigc::connection bypass_defringeConn ;
sigc::connection bypass_dirpyrDenoiseConn ;
sigc::connection bypass_sh_hqConn ;
sigc::connection bypass_dirpyrequalizerConn ;
sigc::connection bypass_waveletConn ;
//sigc::connection bypass_raw_bayer_all_enhanceConn ;
sigc::connection bypass_raw_bayer_dcb_iterationsConn ;
sigc::connection bypass_raw_bayer_dcb_enhanceConn ;
sigc::connection bypass_raw_bayer_lmmse_iterationsConn;
sigc::connection bypass_raw_bayer_linenoiseConn ;
sigc::connection bypass_raw_bayer_greenthreshConn ;
sigc::connection bypass_raw_ccStepsConn ;
sigc::connection bypass_raw_caConn ;
sigc::connection bypass_raw_dfConn ;
sigc::connection bypass_raw_ffConn ;
ExportPanelListener* listener;
void bypassALL_Toggled();
void SaveSettingsAsDefault();
void LoadDefaultSettings();
void LoadSettings();
void SaveSettings();
public:
ExportPanel ();
void FastExportPressed ();
//bool isEnabled ();
void setExportPanelListener (ExportPanelListener* l) { listener = l; }
};
#endif

174
rtgui/extprog.cc Normal file
View File

@@ -0,0 +1,174 @@
/*
* This file is part of RawTherapee.
*
* Copyright (c) 2012 Oliver Duis <www.oliverduis.de>
*
* 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 <cstring>
#include "extprog.h"
#include "multilangmgr.h"
#include "../rtengine/safegtk.h"
#ifdef WIN32
#include <windows.h>
// for GCC32
#ifndef _WIN32_IE
#define _WIN32_IE 0x0600
#endif
#include <shlobj.h>
#endif
using namespace std;
ExtProgAction::ExtProgAction() {}
ExtProgAction::ExtProgAction(const ExtProgAction* other, int target)
: target(target), filePathEXE(other->filePathEXE), preparams(other->preparams), name(other->name) { }
Glib::ustring ExtProgAction::GetFullName() {
return name+ " [" + M(Glib::ustring::compose("EXTPROGTARGET_%1", target)) + "]";
}
bool ExtProgAction::Execute(std::vector<Glib::ustring> fileNames) {
if (fileNames.empty()) return false;
// Check if they all exists (maybe not precessed yet)
for (int i=0;i<fileNames.size();i++) {
if (!safe_file_test(fileNames[i], Glib::FILE_TEST_EXISTS)) {
Gtk::MessageDialog msgd (M("MAIN_MSG_IMAGEUNPROCESSED"), true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
msgd.run ();
return false;
}
}
Glib::ustring cmdLine="\"" + filePathEXE + "\"";
if (preparams.length()>0) cmdLine += " " + preparams;
for (int i=0;i<fileNames.size();i++) cmdLine += " \"" + fileNames[i] + "\"";
return safe_spawn_command_line_async (cmdLine);
}
// Generates as singleton
ExtProgStore* ExtProgStore::getInstance()
{
static ExtProgStore* instance_ = 0;
if ( instance_ == 0 )
{
static MyMutex smutex_;
MyMutex::MyLock lock(smutex_);
if ( instance_ == 0 )
{
instance_ = new ExtProgStore();
}
}
return instance_;
}
ExtProgStore::~ExtProgStore() {
for (list<ExtProgAction*>::iterator it=lActions.begin();it!=lActions.end();it++) delete *it;
}
// Reads all profiles from the given profiles dir
void ExtProgStore::init () {
MyMutex::MyLock lock(mtx);
lActions.clear();
#ifdef WIN32
SearchProg("Photoshop", "Adobe\\Adobe Photoshop CS%1 (64 Bit)\\Photoshop.exe", "Adobe\\Adobe Photoshop CS%1\\Photoshop.exe", 9, false, true);
SearchProg("Photomatix Pro", "PhotomatixPro%1\\PhotomatixPro.exe", "", 9, true, true);
SearchProg("Paint.NET", "Paint.NET\\PaintDotNet.exe", "", 0, false, true);
SearchProg("MS Image Composition Editor", "Microsoft Research\\Image Composite Editor\\ICE.exe", "", 0, false, true);
SearchProg("PTGui", "PTGui\\PTGui.exe", "", 0, false, true);
SearchProg("GeoSetter", "GeoSetter\\GeoSetter.exe", "", 0, true, true);
SearchProg("FastStone Image Viewer", "FastStone Image Viewer\\FSViewer.exe", "", 0, true, true);
SearchProg("FastPictureViewer", "FastPictureViewer\\FastPictureViewer.exe", "", 0, true, true);
if (!SearchProg("Autopano Giga 3", "Kolor\\Autopano Giga 3.%1\\AutopanoGiga_x64.exe", "Kolor\\Autopano Giga 3.%1\\AutopanoGiga.exe", 15, true, true)){
if ( !SearchProg("Autopano Pro 3", "Kolor\\Autopano Pro 3.%1\\AutopanoPro_x64.exe", "Kolor\\Autopano Pro 3.%1\\AutopanoPro.exe", 15, true, true)) {
if (!SearchProg("Autopano Giga 2", "Kolor\\Autopano Giga 2.%1\\AutopanoGiga_x64.exe", "Kolor\\Autopano Giga 2.%1\\AutopanoGiga.exe", 6, true, true))
SearchProg("Autopano Pro 2", "Kolor\\Autopano Pro 2.%1\\AutopanoPro_x64.exe", "Kolor\\Autopano Pro 2.%1\\AutopanoPro.exe", 6, true, true);
}
}
// DO NOT add obscure little tools here, only widely used programs with proper setup program to have a standard path
#endif
}
bool ExtProgStore::SearchProg(Glib::ustring name, Glib::ustring exePath, Glib::ustring exePath86, int maxVer, bool allowRaw, bool allowQueueProcess) {
bool found=false;
#ifdef WIN32
// get_user_special_dir crashes on some Windows configurations.
// so we use the safe native functions here
static Glib::ustring progFilesDir,progFilesDirx86;
if (progFilesDir.empty()) {
WCHAR pathW[MAX_PATH]={0}; char pathA[MAX_PATH];
// First prio folder (64bit, otherwise 32bit)
if (SHGetSpecialFolderPathW(NULL,pathW,CSIDL_PROGRAM_FILES,false)) {
char pathA[MAX_PATH];
WideCharToMultiByte(CP_UTF8,0,pathW,-1,pathA,MAX_PATH,0,0);
progFilesDir=Glib::ustring(pathA);
}
if (SHGetSpecialFolderPathW(NULL,pathW,CSIDL_PROGRAM_FILESX86,false)) {
WideCharToMultiByte(CP_UTF8,0,pathW,-1,pathA,MAX_PATH,0,0);
progFilesDirx86=Glib::ustring(pathA);
}
}
if (exePath86.empty()) exePath86=exePath;
ExtProgAction *pAct=new ExtProgAction();
pAct->name=name;
pAct->target= (allowRaw?1:2);
if (maxVer>0) {
for (int verNo=maxVer;verNo>=0;verNo--) {
pAct->filePathEXE=progFilesDir+"\\"+Glib::ustring::compose(exePath,verNo);
if (safe_file_test(pAct->filePathEXE, Glib::FILE_TEST_EXISTS)) break;
pAct->filePathEXE=progFilesDirx86+"\\"+Glib::ustring::compose(exePath86,verNo);
if (safe_file_test(pAct->filePathEXE, Glib::FILE_TEST_EXISTS)) break;
pAct->filePathEXE="";
}
} else {
pAct->filePathEXE=progFilesDir+"\\"+exePath;
if (!safe_file_test(pAct->filePathEXE, Glib::FILE_TEST_EXISTS)) {
pAct->filePathEXE=progFilesDirx86+"\\"+exePath86;
if (!safe_file_test(pAct->filePathEXE, Glib::FILE_TEST_EXISTS)) pAct->filePathEXE="";
}
}
if (pAct->filePathEXE.length()>0){
lActions.push_back(pAct);
// Copy for second target
if (allowRaw && allowQueueProcess) lActions.push_back(new ExtProgAction(pAct,2));
found=true;
} else delete pAct;
#endif
return found;
}

59
rtgui/extprog.h Normal file
View File

@@ -0,0 +1,59 @@
/*
* This file is part of RawTherapee.
*
* Copyright (c) 2012 Oliver Duis <www.oliverduis.de>
*
* 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 _EXTPROG_
#define _EXTPROG_
#include <glibmm.h>
#include <list>
#include "threadutils.h"
class ExtProgAction {
public:
ExtProgAction();
ExtProgAction(const ExtProgAction* other, int target);
Glib::ustring filePathEXE;
Glib::ustring preparams; // after EXE and before file names
Glib::ustring name; // already localized if necessary
int target; // 1=RAW files, 2=batch converted files
Glib::ustring GetFullName(); // e.g. "Photoshop (RAW)"
virtual bool Execute(std::vector<Glib::ustring> fileNames);
};
// Stores all external programs that could be called by the user
class ExtProgStore {
MyMutex mtx; // covers actions
bool SearchProg(Glib::ustring name, Glib::ustring exePath, Glib::ustring exePath86, int maxVer, bool allowRaw, bool allowQueueProcess);
public:
~ExtProgStore();
void init(); // searches computer for installed standard programs
static ExtProgStore* getInstance();
std::list<ExtProgAction*> lActions;
};
#define extProgStore ExtProgStore::getInstance()
#endif

Some files were not shown because too many files have changed in this diff Show More