847 lines
30 KiB
C++
847 lines
30 KiB
C++
/*
|
|
* This file is part of RawTherapee.
|
|
*
|
|
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
|
|
*
|
|
* RawTherapee is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* RawTherapee is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
#include <editorpanel.h>
|
|
#include <options.h>
|
|
#include <progressconnector.h>
|
|
#include <rtwindow.h>
|
|
#include <guiutils.h>
|
|
#include <procparamchangers.h>
|
|
#include <safegtk.h>
|
|
|
|
using namespace rtengine::procparams;
|
|
|
|
EditorPanel::EditorPanel () : parent(NULL), beforeIarea(NULL), beforePreviewHandler(NULL), beforeIpc(NULL) {
|
|
|
|
epih = new EditorPanelIdleHelper;
|
|
epih->epanel = this;
|
|
epih->destroyed = false;
|
|
epih->pending = 0;
|
|
|
|
// construct toolpanelcoordinator
|
|
tpc = new ToolPanelCoordinator ();
|
|
|
|
// build GUI
|
|
// build left side panel
|
|
leftbox = new Gtk::VBox ();
|
|
leftbox->set_border_width (4);
|
|
|
|
histogramPanel = Gtk::manage (new HistogramPanel ());
|
|
histogramPanel->set_size_request (-1, 150);
|
|
// leftbox->pack_start (*histogramPanel, Gtk::PACK_SHRINK, 4);
|
|
|
|
profilep = Gtk::manage (new ProfilePanel ());
|
|
Gtk::Frame* ppframe = Gtk::manage (new Gtk::Frame ());
|
|
ppframe->add (*profilep);
|
|
ppframe->set_label (M("PROFILEPANEL_LABEL"));
|
|
// leftbox->pack_start (*ppframe, Gtk::PACK_SHRINK, 4);
|
|
|
|
navigator = Gtk::manage (new Navigator ());
|
|
navigator->previewWindow->set_size_request (-1, 150);
|
|
leftbox->pack_start (*navigator, Gtk::PACK_SHRINK, 4);
|
|
|
|
history = Gtk::manage (new History ());
|
|
leftbox->pack_start (*history);
|
|
|
|
leftbox->show_all ();
|
|
|
|
// build the middle of the screen
|
|
Gtk::VBox* editbox = Gtk::manage (new Gtk::VBox ());
|
|
|
|
info = Gtk::manage (new Gtk::ToggleButton ());
|
|
Gtk::Image* infoimg = Gtk::manage (new Gtk::Image (argv0+"/images/info.png"));
|
|
info->add (*infoimg);
|
|
info->set_relief(Gtk::RELIEF_NONE);
|
|
info->set_tooltip_text (M("MAIN_TOOLTIP_QINFO"));
|
|
|
|
beforeAfter = Gtk::manage (new Gtk::ToggleButton (M("MAIN_TOGGLE_BEFORE_AFTER")));
|
|
beforeAfter->set_tooltip_text (M("MAIN_TOOLTIP_TOGGLE"));
|
|
|
|
|
|
Gtk::VSeparator* vsept = Gtk::manage (new Gtk::VSeparator ());
|
|
Gtk::VSeparator* vsepz = Gtk::manage (new Gtk::VSeparator ());
|
|
Gtk::VSeparator* vsepi = Gtk::manage (new Gtk::VSeparator ());
|
|
Gtk::VSeparator* vseph = Gtk::manage (new Gtk::VSeparator ());
|
|
|
|
hidehp = Gtk::manage (new Gtk::ToggleButton ());
|
|
Gtk::Label* hidehpLabel = Gtk::manage (new Gtk::Label ());
|
|
hidehpLabel->set_markup ("<b>H</b>");
|
|
Gtk::Image* hpimg = Gtk::manage (new Gtk::Image (argv0+"/images/left.png"));
|
|
Gtk::HBox* hidehpBox = Gtk::manage (new Gtk::HBox ());
|
|
hidehpBox->pack_start (*hpimg, Gtk::PACK_SHRINK, 2);
|
|
hidehpBox->pack_start (*hidehpLabel, Gtk::PACK_SHRINK, 2);
|
|
hidehp->add (*hidehpBox);
|
|
hidehp->set_relief(Gtk::RELIEF_NONE);
|
|
hidehp->set_active (options.showHistory);
|
|
hidehp->set_tooltip_text (M("MAIN_TOOLTIP_HIDEHP"));
|
|
|
|
Gtk::VSeparator* vsepcl = Gtk::manage (new Gtk::VSeparator ());
|
|
Gtk::VSeparator* vsepz2 = Gtk::manage (new Gtk::VSeparator ());
|
|
|
|
iarea = new ImageAreaPanel ();
|
|
|
|
Gtk::HBox* toolBarPanel = Gtk::manage (new Gtk::HBox ());
|
|
toolBarPanel->pack_start (*hidehp, Gtk::PACK_SHRINK, 1);
|
|
toolBarPanel->pack_start (*vseph, Gtk::PACK_SHRINK, 2);
|
|
toolBarPanel->pack_start (*info, Gtk::PACK_SHRINK, 1);
|
|
toolBarPanel->pack_start (*beforeAfter, Gtk::PACK_SHRINK, 1);
|
|
toolBarPanel->pack_start (*vsepi, Gtk::PACK_SHRINK, 2);
|
|
toolBarPanel->pack_start (*tpc->getToolBar(), Gtk::PACK_SHRINK, 1);
|
|
toolBarPanel->pack_start (*vsept, Gtk::PACK_SHRINK, 2);
|
|
toolBarPanel->pack_end (*tpc->coarse, Gtk::PACK_SHRINK, 4);
|
|
toolBarPanel->pack_end (*vsepcl, Gtk::PACK_SHRINK, 4);
|
|
toolBarPanel->pack_end (*iarea->imageArea->indClippedPanel, Gtk::PACK_SHRINK, 0);
|
|
toolBarPanel->pack_end (*vsepz, Gtk::PACK_SHRINK, 2);
|
|
|
|
afterBox = Gtk::manage (new Gtk::VBox ());
|
|
afterBox->pack_start (*iarea);
|
|
|
|
beforeAfterBox = Gtk::manage (new Gtk::HBox());
|
|
beforeAfterBox->pack_start (*afterBox);
|
|
|
|
editbox->pack_start (*toolBarPanel, Gtk::PACK_SHRINK);
|
|
editbox->pack_start (*beforeAfterBox);
|
|
|
|
// build right side panel
|
|
vboxright = new Gtk::VBox (false, 0);
|
|
vboxright->set_border_width (4);
|
|
vboxright->pack_start (*histogramPanel, Gtk::PACK_SHRINK, 4);
|
|
vboxright->pack_start (*ppframe, Gtk::PACK_SHRINK, 4);
|
|
// main notebook
|
|
vboxright->pack_start (*tpc->toolPanelNotebook);
|
|
|
|
// buttons & status
|
|
Gtk::HBox* iops = Gtk::manage (new Gtk::HBox ());
|
|
saveimgas = Gtk::manage (new Gtk::Button (M("MAIN_BUTTON_SAVE")));
|
|
saveimgas->set_image (*Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-save"), Gtk::ICON_SIZE_BUTTON)));
|
|
queueimg = Gtk::manage (new Gtk::Button (M("MAIN_BUTTON_PUTTOQUEUE")));
|
|
queueimg->set_image (*Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-execute"), Gtk::ICON_SIZE_BUTTON)));
|
|
sendtogimp = Gtk::manage (new Gtk::Button (M("MAIN_BUTTON_SENDTOEDITOR")));
|
|
sendtogimp->set_image (*Gtk::manage(new Gtk::Image (argv0+"/images/gimp.png")));
|
|
iops->pack_start (*saveimgas, Gtk::PACK_SHRINK);
|
|
iops->pack_start (*queueimg, Gtk::PACK_SHRINK);
|
|
iops->pack_start (*sendtogimp, Gtk::PACK_SHRINK);
|
|
|
|
statusBox = Gtk::manage (new Gtk::HBox ());
|
|
progressLabel = Gtk::manage (new Gtk::Label(""));
|
|
statusBox->pack_start (*progressLabel);
|
|
red = new Gtk::Image (argv0+"/images/red.png");
|
|
green = new Gtk::Image (argv0+"/images/green.png");
|
|
red->show ();
|
|
green->show ();
|
|
statusBox->pack_end (*green, Gtk::PACK_SHRINK, 4);
|
|
iops->pack_start(*statusBox, Gtk::PACK_SHRINK, 4);
|
|
|
|
iops->pack_end (*iarea->imageArea->zoomPanel, Gtk::PACK_SHRINK, 1);
|
|
iops->pack_end (*vsepz2, Gtk::PACK_SHRINK, 2);
|
|
|
|
|
|
editbox->pack_start (*Gtk::manage(new Gtk::HSeparator()), Gtk::PACK_SHRINK, 4);
|
|
editbox->pack_start (*iops, Gtk::PACK_SHRINK, 4);
|
|
editbox->show_all ();
|
|
|
|
// build screen
|
|
hpanedl = Gtk::manage (new Gtk::HPaned());
|
|
hpanedr = Gtk::manage (new Gtk::HPaned());
|
|
leftbox->reference ();
|
|
vboxright->reference ();
|
|
if (options.showHistory) {
|
|
hpanedl->pack1(*leftbox, false, true);
|
|
hpanedl->set_position (options.historyPanelWidth);
|
|
}
|
|
|
|
Gtk::Frame* vbfr = Gtk::manage (new Gtk::Frame ());
|
|
vbfr->add (*editbox);
|
|
hpanedl->pack2(*vbfr, true, true);
|
|
|
|
hpanedr->pack1(*hpanedl, true, true);
|
|
hpanedr->pack2(*vboxright, false, true);
|
|
|
|
pack_start (*hpanedr);
|
|
show_all ();
|
|
|
|
// save as dialog
|
|
if (Glib::file_test (options.lastSaveAsPath, Glib::FILE_TEST_IS_DIR))
|
|
saveAsDialog = new SaveAsDialog (options.lastSaveAsPath);
|
|
else
|
|
saveAsDialog = new SaveAsDialog (Glib::get_user_special_dir (G_USER_DIRECTORY_PICTURES));
|
|
|
|
saveAsDialog->set_default_size (options.saveAsDialogWidth, options.saveAsDialogHeight);
|
|
|
|
// connect listeners
|
|
profilep->setProfileChangeListener (tpc);
|
|
history->setProfileChangeListener (tpc);
|
|
history->setHistoryBeforeLineListener (this);
|
|
tpc->addPParamsChangeListener (profilep);
|
|
tpc->addPParamsChangeListener (history);
|
|
tpc->addPParamsChangeListener (this);
|
|
iarea->imageArea->setCropGUIListener (tpc->getCropGUIListener());
|
|
iarea->imageArea->setPointerMotionListener (navigator);
|
|
iarea->imageArea->setImageAreaToolListener (tpc);
|
|
|
|
// initialize components
|
|
info->set_active (options.showInfo);
|
|
tpc->readOptions ();
|
|
|
|
// connect event handlers
|
|
info->signal_toggled().connect( sigc::mem_fun(*this, &EditorPanel::info_toggled) );
|
|
beforeAfter->signal_toggled().connect( sigc::mem_fun(*this, &EditorPanel::beforeAfterToggled) );
|
|
hidehp->signal_toggled().connect( sigc::mem_fun(*this, &EditorPanel::hideHistoryActivated) );
|
|
saveimgas->signal_pressed().connect( sigc::mem_fun(*this, &EditorPanel::saveAsPressed) );
|
|
queueimg->signal_pressed().connect( sigc::mem_fun(*this, &EditorPanel::queueImgPressed) );
|
|
sendtogimp->signal_pressed().connect( sigc::mem_fun(*this, &EditorPanel::sendToGimpPressed) );
|
|
|
|
}
|
|
|
|
bool EditorPanel::beforeClosing () {
|
|
|
|
options.toolPanelWidth = vboxright->get_width ();
|
|
return true;
|
|
}
|
|
|
|
EditorPanel::~EditorPanel () {
|
|
|
|
history->setHistoryBeforeLineListener (NULL);
|
|
// the order is important!
|
|
delete iarea;
|
|
delete beforeIarea;
|
|
|
|
if (ipc)
|
|
ipc->setPreviewImageListener (NULL);
|
|
if (beforeIpc)
|
|
beforeIpc->setPreviewImageListener (NULL);
|
|
|
|
delete previewHandler;
|
|
delete beforePreviewHandler;
|
|
|
|
if (ipc)
|
|
close ();
|
|
|
|
if (epih->pending)
|
|
epih->destroyed = true;
|
|
else
|
|
delete epih;
|
|
|
|
delete tpc;
|
|
|
|
delete red;
|
|
delete green;
|
|
delete leftbox;
|
|
delete vboxright;
|
|
|
|
delete saveAsDialog;
|
|
}
|
|
|
|
void EditorPanel::on_realize () {
|
|
|
|
Gtk::VBox::on_realize ();
|
|
vboxright->set_size_request (options.toolPanelWidth, -1);
|
|
}
|
|
|
|
void EditorPanel::open (Thumbnail* tmb, rtengine::InitialImage* isrc) {
|
|
|
|
// initialize everything
|
|
openThm = tmb;
|
|
openThm->increaseRef ();
|
|
|
|
previewHandler = new PreviewHandler ();
|
|
|
|
this->isrc = isrc;
|
|
ipc = rtengine::StagedImageProcessor::create (isrc);
|
|
ipc->setProgressListener (this);
|
|
ipc->setPreviewImageListener (previewHandler);
|
|
ipc->setPreviewScale (10);
|
|
tpc->initImage (ipc, tmb->getType()==FT_Raw);
|
|
ipc->setHistogramListener (this);
|
|
|
|
// iarea->fitZoom (); // tell to the editorPanel that the next image has to be fitted to the screen
|
|
iarea->imageArea->setPreviewHandler (previewHandler);
|
|
iarea->imageArea->setImProcCoordinator (ipc);
|
|
navigator->previewWindow->setPreviewHandler (previewHandler);
|
|
navigator->previewWindow->setImageArea (iarea->imageArea);
|
|
|
|
// try to load the last saved parameters from the cache or from the paramfile file
|
|
ProcParams* ldprof = NULL;
|
|
if (openThm->hasProcParams()) {
|
|
ldprof = new ProcParams ();
|
|
*ldprof = openThm->getProcParams ();
|
|
}
|
|
|
|
// initialize profile
|
|
if (openThm->getType()!=FT_Raw)
|
|
profilep->initProfile (options.defProfImg, ldprof, NULL);
|
|
else
|
|
profilep->initProfile (options.defProfRaw, ldprof, NULL);
|
|
|
|
openThm->addThumbnailListener (this);
|
|
info_toggled ();
|
|
}
|
|
|
|
void EditorPanel::close () {
|
|
|
|
saveProfile ();
|
|
|
|
// close image processor and the current thumbnail
|
|
tpc->closeImage (); // this call stops image processing
|
|
tpc->writeOptions ();
|
|
|
|
if (ipc)
|
|
rtengine::StagedImageProcessor::destroy (ipc);
|
|
if (beforeIpc)
|
|
rtengine::StagedImageProcessor::destroy (beforeIpc);
|
|
|
|
openThm->removeThumbnailListener (this);
|
|
openThm->decreaseRef ();
|
|
}
|
|
|
|
void EditorPanel::saveProfile () {
|
|
|
|
ProcParams params;
|
|
ipc->getParams (¶ms);
|
|
|
|
if (options.saveParamsFile)
|
|
params.save (openThm->getFileName() + paramFileExtension);
|
|
if (openThm && options.saveParamsCache)
|
|
openThm->setProcParams (params, EDITOR);
|
|
}
|
|
|
|
Glib::ustring EditorPanel::getShortName () {
|
|
|
|
return Glib::path_get_basename (openThm->getFileName ());
|
|
}
|
|
|
|
Glib::ustring EditorPanel::getFileName () {
|
|
|
|
return openThm->getFileName ();
|
|
}
|
|
|
|
// TODO!!!
|
|
void EditorPanel::procParamsChanged (rtengine::procparams::ProcParams* params, rtengine::ProcEvent ev, Glib::ustring descr, ParamsEdited* paramsEdited) {
|
|
|
|
// if (ev!=EvPhotoLoaded)
|
|
// saveLabel->set_markup (Glib::ustring("<span foreground=\"#AA0000\" weight=\"bold\">") + M("MAIN_BUTTON_SAVE") + "</span>");
|
|
}
|
|
|
|
struct spsparams {
|
|
bool state;
|
|
EditorPanelIdleHelper* epih;
|
|
};
|
|
|
|
int setprocstate (void* data) {
|
|
|
|
gdk_threads_enter ();
|
|
spsparams* p = (spsparams*)data;
|
|
|
|
if (p->epih->destroyed) {
|
|
if (p->epih->pending == 1)
|
|
delete p->epih;
|
|
else
|
|
p->epih->pending--;
|
|
delete p;
|
|
gdk_threads_leave ();
|
|
return 0;
|
|
}
|
|
|
|
p->epih->epanel->refreshProcessingState (p->state);
|
|
p->epih->pending--;
|
|
delete p;
|
|
gdk_threads_leave ();
|
|
return 0;
|
|
}
|
|
|
|
void EditorPanel::setProgressState (int state) {
|
|
|
|
epih->pending++;
|
|
|
|
spsparams* p = new spsparams;
|
|
p->state = state;
|
|
p->epih = epih;
|
|
g_idle_add (setprocstate, p);
|
|
}
|
|
|
|
void EditorPanel::refreshProcessingState (bool state) {
|
|
|
|
// Set proc params of thumbnail. It saves it into the cache and updates the file browser.
|
|
if (ipc && openThm && !state && tpc->getChangedState()) {
|
|
rtengine::procparams::ProcParams pparams;
|
|
ipc->getParams (&pparams);
|
|
openThm->setProcParams (pparams, EDITOR, false);
|
|
}
|
|
|
|
// change state of the led
|
|
std::vector<Widget*> children = (std::vector<Widget*>) statusBox->get_children();
|
|
if (children.size()>=1) {
|
|
Gtk::Widget* wlast = children[children.size()-1];
|
|
if (wlast)
|
|
statusBox->remove (*wlast);
|
|
}
|
|
if (state)
|
|
statusBox->pack_end (*red, Gtk::PACK_SHRINK, 4);
|
|
else
|
|
statusBox->pack_end (*green, Gtk::PACK_SHRINK, 4);
|
|
}
|
|
|
|
struct errparams {
|
|
Glib::ustring descr;
|
|
EditorPanelIdleHelper* epih;
|
|
};
|
|
|
|
void EditorPanel::displayError (Glib::ustring descr) {
|
|
|
|
if (parent) {
|
|
Gtk::MessageDialog* msgd = new Gtk::MessageDialog (*parent, descr, true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
|
|
msgd->set_title (M("MAIN_MSG_CANNOTSAVE"));
|
|
msgd->run ();
|
|
delete msgd;
|
|
}
|
|
}
|
|
|
|
int disperror (void* data) {
|
|
|
|
gdk_threads_enter ();
|
|
errparams* p = (errparams*)data;
|
|
|
|
if (p->epih->destroyed) {
|
|
if (p->epih->pending == 1)
|
|
delete p->epih;
|
|
else
|
|
p->epih->pending--;
|
|
delete p;
|
|
gdk_threads_leave ();
|
|
return 0;
|
|
}
|
|
|
|
p->epih->epanel->displayError (p->descr);
|
|
p->epih->pending--;
|
|
delete p;
|
|
gdk_threads_leave ();
|
|
return 0;
|
|
}
|
|
|
|
void EditorPanel::error (Glib::ustring descr) {
|
|
|
|
epih->pending++;
|
|
errparams* p = new errparams;
|
|
p->descr = descr;
|
|
p->epih = epih;
|
|
g_idle_add (disperror, p);
|
|
}
|
|
|
|
void EditorPanel::info_toggled () {
|
|
|
|
Glib::ustring infoString;
|
|
|
|
const rtengine::ImageMetaData* idata = ipc->getInitialImage()->getMetaData();
|
|
if (idata && idata->hasExif())
|
|
infoString = Glib::ustring::compose ("%1 %2\nF/%3 %4 sec\n%5: %6\n%7: %8 mm\n",
|
|
Glib::ustring(idata->getMake()), Glib::ustring(idata->getModel()),
|
|
Glib::ustring(idata->apertureToString(idata->getFNumber())), Glib::ustring(idata->shutterToString(idata->getShutterSpeed())),
|
|
M("QINFO_ISO"), idata->getISOSpeed(),
|
|
M("QINFO_FOCALLENGTH"), idata->getFocalLen())
|
|
+ Glib::ustring::compose ("%1: %2", M("QINFO_LENS"), Glib::ustring(idata->getLens()));
|
|
else
|
|
infoString = M("QINFO_NOEXIF");
|
|
|
|
iarea->imageArea->setInfoText (infoString);
|
|
iarea->imageArea->infoEnabled (info->get_active ());
|
|
}
|
|
|
|
void EditorPanel::hideHistoryActivated () {
|
|
|
|
removeIfThere (hpanedl, leftbox, false);
|
|
if (hidehp->get_active())
|
|
hpanedl->pack1 (*leftbox, false, true);
|
|
options.showHistory = hidehp->get_active();
|
|
}
|
|
|
|
bool EditorPanel::handleShortcutKey (GdkEventKey* event) {
|
|
|
|
if (event->keyval==GDK_H || event->keyval==GDK_h) {
|
|
hidehp->set_active (!hidehp->get_active());
|
|
return true;
|
|
}
|
|
else if ((event->keyval==GDK_Z || event->keyval==GDK_z) && event->state & GDK_CONTROL_MASK && !(event->state & GDK_SHIFT_MASK)) {
|
|
history->undo ();
|
|
return true;
|
|
}
|
|
else if ((event->keyval==GDK_Z || event->keyval==GDK_z) && event->state & GDK_CONTROL_MASK && event->state & GDK_SHIFT_MASK) {
|
|
history->redo ();
|
|
return true;
|
|
}
|
|
else if (event->keyval==GDK_w || event->keyval==GDK_W) {
|
|
tpc->getToolBar()->wb_pressed ();
|
|
return true;
|
|
}
|
|
else if (event->keyval==GDK_c || event->keyval==GDK_C) {
|
|
tpc->getToolBar()->crop_pressed ();
|
|
return true;
|
|
}
|
|
else if (event->keyval==GDK_s || event->keyval==GDK_S) {
|
|
tpc->getToolBar()->stra_pressed ();
|
|
return true;
|
|
}
|
|
else if (event->keyval==GDK_n || event->keyval==GDK_N) {
|
|
tpc->getToolBar()->hand_pressed ();
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
void EditorPanel::procParamsChanged (Thumbnail* thm, int whoChangedIt) {
|
|
|
|
if (whoChangedIt!=EDITOR)
|
|
tpc->profileChange (&openThm->getProcParams(), rtengine::EvProfileChangeNotification, M("PROGRESSDLG_PROFILECHANGEDINBROWSER"));
|
|
}
|
|
|
|
bool EditorPanel::idle_saveImage (ProgressConnector<rtengine::IImage16*> *pc, Glib::ustring fname, SaveFormat sf, bool findNewNameIfNeeded){
|
|
rtengine::IImage16* img = pc->returnValue();
|
|
delete pc;
|
|
if( img )
|
|
saveImage( img, fname, sf, findNewNameIfNeeded);
|
|
else{
|
|
Glib::ustring msg_ = Glib::ustring("<b>") + fname + ": Error during image processing\n</b>";
|
|
Gtk::MessageDialog msgd (*parent, msg_, true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
|
|
msgd.run ();
|
|
|
|
saveimgas->set_sensitive(true);
|
|
sendtogimp->set_sensitive(true);
|
|
|
|
}
|
|
return false;
|
|
}
|
|
|
|
BatchQueueEntry* EditorPanel::createBatchQueueEntry () {
|
|
|
|
rtengine::procparams::ProcParams pparams;
|
|
ipc->getParams (&pparams);
|
|
rtengine::ProcessingJob* job = rtengine::ProcessingJob::create (ipc->getInitialImage(), pparams);
|
|
int prevh = options.maxThumbnailHeight;
|
|
int prevw = prevh;
|
|
guint8* prev = NULL;//(guint8*) previewHandler->getImagePreview (prevw, prevh);
|
|
double tmpscale;
|
|
rtengine::IImage8* img = openThm->processThumbImage (pparams, options.maxThumbnailHeight, tmpscale);
|
|
if (img) {
|
|
prevw = img->getWidth ();
|
|
prevh = img->getHeight ();
|
|
prev = new guint8 [prevw*prevh*3];
|
|
memcpy (prev, img->getData (), prevw*prevh*3);
|
|
img->free();
|
|
}
|
|
return new BatchQueueEntry (job, pparams, openThm->getFileName(), prev, prevw, prevh, openThm);
|
|
}
|
|
|
|
int EditorPanel::saveImage (rtengine::IImage16* img, Glib::ustring& fname, SaveFormat sf, bool findNewNameIfNeeded) {
|
|
|
|
Glib::ustring fileName = Glib::ustring::compose ("%1.%2", fname, sf.format);
|
|
if (findNewNameIfNeeded) {
|
|
int tries = 1;
|
|
while (Glib::file_test (fileName, Glib::FILE_TEST_EXISTS) && tries<1000) {
|
|
fileName = Glib::ustring::compose("%1-%2.%3", fname, tries, sf.format);
|
|
tries++;
|
|
}
|
|
if (tries==1000)
|
|
return -1000;
|
|
}
|
|
ProgressConnector<int> *ld = new ProgressConnector<int>();
|
|
img->setSaveProgressListener (parent->getProgressListener());
|
|
if (sf.format=="tif")
|
|
ld->startFunc (sigc::bind(sigc::mem_fun(img, &rtengine::IImage16::saveAsTIFF), fileName, sf.tiffBits, sf.tiffUncompressed),
|
|
sigc::bind(sigc::mem_fun(*this,&EditorPanel::idle_imageSaved), ld, img, fileName,sf));
|
|
else if (sf.format=="png")
|
|
ld->startFunc (sigc::bind(sigc::mem_fun(img, &rtengine::IImage16::saveAsPNG), fileName, sf.pngCompression, sf.pngBits),
|
|
sigc::bind(sigc::mem_fun(*this,&EditorPanel::idle_imageSaved), ld, img, fileName,sf));
|
|
else if (sf.format=="jpg")
|
|
ld->startFunc (sigc::bind(sigc::mem_fun(img, &rtengine::IImage16::saveAsJPEG), fileName, sf.jpegQuality),
|
|
sigc::bind(sigc::mem_fun(*this,&EditorPanel::idle_imageSaved), ld, img, fileName,sf));
|
|
return 0;
|
|
}
|
|
|
|
bool EditorPanel::idle_imageSaved(ProgressConnector<int> *pc,rtengine::IImage16* img,Glib::ustring fname, SaveFormat sf){
|
|
img->free ();
|
|
if (! pc->returnValue() ) {
|
|
openThm->imageDeveloped ();
|
|
// save processing parameters, if needed
|
|
if (sf.saveParams) {
|
|
rtengine::procparams::ProcParams pparams;
|
|
ipc->getParams (&pparams);
|
|
pparams.save (removeExtension (fname) + ".out" + paramFileExtension);
|
|
}
|
|
}else{
|
|
Glib::ustring msg_ = Glib::ustring("<b>") + fname + ": Error during image saving\n</b>";
|
|
Gtk::MessageDialog msgd (*parent, msg_, true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
|
|
msgd.run ();
|
|
}
|
|
saveimgas->set_sensitive(true);
|
|
sendtogimp->set_sensitive(true);
|
|
parent->setProgressStr("");
|
|
parent->setProgress(0.);
|
|
delete pc;
|
|
return false;
|
|
}
|
|
|
|
void EditorPanel::saveAsPressed () {
|
|
|
|
// obtaining short name without extension
|
|
saveAsDialog->setInitialFileName (removeExtension (Glib::path_get_basename (openThm->getFileName())));
|
|
saveAsDialog->run ();
|
|
Glib::ustring fname = saveAsDialog->getFileName ();
|
|
if (fname=="")
|
|
return;
|
|
|
|
options.lastSaveAsPath = saveAsDialog->getDirectory ();
|
|
options.saveAsDialogWidth = saveAsDialog->get_width();
|
|
options.saveAsDialogHeight = saveAsDialog->get_height();
|
|
|
|
SaveFormat sf = saveAsDialog->getFormat ();
|
|
if (getExtension (fname)!=sf.format)
|
|
fname = fname + "." + sf.format;
|
|
|
|
options.saveFormat = sf;
|
|
|
|
if (saveAsDialog->getImmediately ()) {
|
|
// check if it exists
|
|
if (Glib::file_test (fname, Glib::FILE_TEST_EXISTS)) {
|
|
Glib::ustring msg_ = Glib::ustring("<b>") + fname + ": " + M("MAIN_MSG_ALREADYEXISTS") + "\n" + M("MAIN_MSG_QOVERWRITE") + "</b>";
|
|
Gtk::MessageDialog msgd (*parent, msg_, true, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_YES_NO, true);
|
|
int response = msgd.run ();
|
|
if (response==Gtk::RESPONSE_NO)
|
|
return;
|
|
}
|
|
// save image
|
|
rtengine::procparams::ProcParams pparams;
|
|
ipc->getParams (&pparams);
|
|
rtengine::ProcessingJob* job = rtengine::ProcessingJob::create (ipc->getInitialImage(), pparams);
|
|
fname = removeExtension (fname);
|
|
ProgressConnector<rtengine::IImage16*> *ld = new ProgressConnector<rtengine::IImage16*>();
|
|
ld->startFunc(sigc::bind(sigc::ptr_fun(&rtengine::processImage), job, err, parent->getProgressListener() ),
|
|
sigc::bind(sigc::mem_fun( *this,&EditorPanel::idle_saveImage ),ld,fname,sf,false ));
|
|
saveimgas->set_sensitive(false);
|
|
sendtogimp->set_sensitive(false);
|
|
}
|
|
else {
|
|
BatchQueueEntry* bqe = createBatchQueueEntry ();
|
|
bqe->outFileName = fname;
|
|
bqe->saveFormat = saveAsDialog->getFormat ();
|
|
parent->addBatchQueueJob (bqe, saveAsDialog->getToHeadOfQueue ());
|
|
}
|
|
// ask parent to redraw file browser
|
|
// ... or does it automatically when the tab is switched to it
|
|
}
|
|
|
|
void EditorPanel::queueImgPressed () {
|
|
|
|
saveProfile ();
|
|
parent->addBatchQueueJob (createBatchQueueEntry ());
|
|
}
|
|
|
|
void EditorPanel::sendToGimpPressed () {
|
|
// develop image
|
|
rtengine::procparams::ProcParams pparams;
|
|
ipc->getParams (&pparams);
|
|
rtengine::ProcessingJob* job = rtengine::ProcessingJob::create (ipc->getInitialImage(), pparams);
|
|
ProgressConnector<rtengine::IImage16*> *ld = new ProgressConnector<rtengine::IImage16*>();
|
|
ld->startFunc(sigc::bind(sigc::ptr_fun(&rtengine::processImage), job, err, parent->getProgressListener() ),
|
|
sigc::bind(sigc::mem_fun( *this,&EditorPanel::idle_sendToGimp ),ld ));
|
|
saveimgas->set_sensitive(false);
|
|
sendtogimp->set_sensitive(false);
|
|
}
|
|
|
|
bool EditorPanel::idle_sendToGimp( ProgressConnector<rtengine::IImage16*> *pc){
|
|
|
|
rtengine::IImage16* img = pc->returnValue();
|
|
delete pc;
|
|
if (img) {
|
|
// get file name base
|
|
Glib::ustring shortname = removeExtension (Glib::path_get_basename (openThm->getFileName()));
|
|
Glib::ustring dirname = Glib::get_tmp_dir ();
|
|
Glib::ustring fname = Glib::build_filename (dirname, shortname);
|
|
|
|
SaveFormat sf;
|
|
sf.format = "tif";
|
|
sf.tiffBits = 16;
|
|
|
|
Glib::ustring fileName = Glib::ustring::compose ("%1.%2", fname, sf.format);
|
|
|
|
int tries = 1;
|
|
while (Glib::file_test (fileName, Glib::FILE_TEST_EXISTS) && tries<1000) {
|
|
fileName = Glib::ustring::compose("%1-%2.%3", fname, tries, sf.format);
|
|
tries++;
|
|
}
|
|
if (tries==1000){
|
|
img->free ();
|
|
return false;
|
|
}
|
|
|
|
ProgressConnector<int> *ld = new ProgressConnector<int>();
|
|
img->setSaveProgressListener (parent->getProgressListener());
|
|
ld->startFunc (sigc::bind(sigc::mem_fun(img, &rtengine::IImage16::saveAsTIFF), fileName, sf.tiffBits, sf.tiffUncompressed),
|
|
sigc::bind(sigc::mem_fun(*this,&EditorPanel::idle_sentToGimp), ld, img, fileName));
|
|
}else{
|
|
Glib::ustring msg_ = Glib::ustring("<b> Error during image processing\n</b>");
|
|
Gtk::MessageDialog msgd (*parent, msg_, true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
|
|
msgd.run ();
|
|
saveimgas->set_sensitive(true);
|
|
sendtogimp->set_sensitive(true);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool EditorPanel::idle_sentToGimp(ProgressConnector<int> *pc,rtengine::IImage16* img,Glib::ustring filename){
|
|
img->free ();
|
|
int errore = pc->returnValue();
|
|
delete pc;
|
|
if (!errore) {
|
|
saveimgas->set_sensitive(true);
|
|
sendtogimp->set_sensitive(true);
|
|
parent->setProgressStr("");
|
|
parent->setProgress(0.);
|
|
bool success=false;
|
|
Glib::ustring cmdLine;
|
|
// start gimp
|
|
if (options.editorToSendTo==1) {
|
|
#ifdef _WIN32
|
|
cmdLine = Glib::ustring("\"") + Glib::build_filename (Glib::build_filename(options.gimpDir,"bin"), "gimp-win-remote") + "\" gimp-2.4.exe" + " \"" + filename + "\"";
|
|
#else
|
|
cmdLine = Glib::ustring("gimp-remote ") + " \"" + filename + "\"";
|
|
#endif
|
|
success = safe_spawn_command_line_async (cmdLine);
|
|
if (!success){
|
|
#ifdef _WIN32
|
|
int ver = 12;
|
|
while (!success && ver) {
|
|
cmdLine = Glib::ustring("\"") + Glib::build_filename (Glib::build_filename(options.gimpDir,"bin"), Glib::ustring::compose("gimp-2.%1.exe",ver)) + "\" \"" + filename + "\"";
|
|
ver--;
|
|
success = safe_spawn_command_line_async (cmdLine);
|
|
}
|
|
#elif defined __APPLE__
|
|
cmdLine = Glib::ustring("gimp ") + " \"" + filename + "\"";
|
|
success = safe_spawn_command_line_async (cmdLine);
|
|
#else
|
|
cmdLine = Glib::ustring("gimp ") + " \"" + filename + "\"";
|
|
success = safe_spawn_command_line_async (cmdLine);
|
|
#endif
|
|
}
|
|
}
|
|
else if (options.editorToSendTo==2) {
|
|
#ifdef __APPLE__
|
|
cmdLine = Glib::ustring("open -a \'") + Glib::build_filename(options.psDir,"Photoshop.app\' ") + "\'" + filename + "\'";
|
|
#else
|
|
cmdLine = Glib::ustring("\"") + Glib::build_filename(options.psDir,"Photoshop.exe") + "\" \"" + filename + "\"";
|
|
#endif
|
|
success = safe_spawn_command_line_async (cmdLine);
|
|
}
|
|
else if (options.editorToSendTo==3) {
|
|
#ifdef __APPLE__
|
|
cmdLine = Glib::ustring("") + options.customEditorProg + filename;
|
|
#else
|
|
cmdLine = Glib::ustring("\"") + options.customEditorProg + "\" \"" + filename + "\"";
|
|
#endif
|
|
success = safe_spawn_command_line_async (cmdLine);
|
|
}
|
|
|
|
if (!success) {
|
|
Gtk::MessageDialog* msgd = new Gtk::MessageDialog (*parent, M("MAIN_MSG_CANNOTSTARTEDITOR"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
|
|
msgd->set_secondary_text (M("MAIN_MSG_CANNOTSTARTEDITOR_SECONDARY"));
|
|
msgd->set_title (M("MAIN_BUTTON_SENDTOEDITOR"));
|
|
msgd->run ();
|
|
delete msgd;
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void EditorPanel::saveOptions () {
|
|
|
|
options.historyPanelWidth = hpanedl->get_position ();
|
|
options.toolPanelWidth = vboxright->get_width ();
|
|
}
|
|
|
|
void EditorPanel::historyBeforeLineChanged (const rtengine::procparams::ProcParams& params) {
|
|
|
|
if (beforeIpc) {
|
|
ProcParams* pparams = beforeIpc->getParamsForUpdate (rtengine::EvProfileChanged);
|
|
*pparams = params;
|
|
beforeIpc->paramsUpdateReady ();
|
|
}
|
|
}
|
|
|
|
void EditorPanel::beforeAfterToggled () {
|
|
|
|
removeIfThere (beforeAfterBox, beforeBox, false);
|
|
removeIfThere (afterBox, afterLabel, false);
|
|
|
|
if (beforeIarea) {
|
|
if (beforeIpc)
|
|
beforeIpc->stopProcessing ();
|
|
iarea->setBeforeAfterViews (NULL, iarea);
|
|
delete beforeIarea;
|
|
beforeIarea = NULL;
|
|
if (beforeIpc)
|
|
beforeIpc->setPreviewImageListener (NULL);
|
|
delete beforePreviewHandler;
|
|
beforePreviewHandler = NULL;
|
|
if (beforeIpc)
|
|
rtengine::StagedImageProcessor::destroy (beforeIpc);
|
|
beforeIpc = NULL;
|
|
}
|
|
|
|
if (beforeAfter->get_active ()) {
|
|
|
|
beforeIarea = new ImageAreaPanel ();
|
|
|
|
beforeLabel = Gtk::manage (new Gtk::Label ());
|
|
beforeLabel->set_markup (Glib::ustring("<b>") + M("GENERAL_BEFORE") + "</b>");
|
|
beforeBox = Gtk::manage (new Gtk::VBox ());
|
|
beforeBox->pack_start (*beforeLabel, Gtk::PACK_SHRINK, 2);
|
|
beforeBox->pack_start (*beforeIarea);
|
|
|
|
afterLabel = Gtk::manage (new Gtk::Label ());
|
|
afterLabel->set_markup (Glib::ustring("<b>") + M("GENERAL_AFTER") + "</b>");
|
|
afterBox->pack_start (*afterLabel, Gtk::PACK_SHRINK, 2);
|
|
afterBox->reorder_child (*afterLabel, 0);
|
|
|
|
beforeAfterBox->pack_start (*beforeBox);
|
|
beforeAfterBox->reorder_child (*beforeBox, 0);
|
|
beforeAfterBox->show_all ();
|
|
|
|
beforePreviewHandler = new PreviewHandler ();
|
|
isrc->increaseRef ();
|
|
beforeIpc = rtengine::StagedImageProcessor::create (isrc);
|
|
beforeIpc->setPreviewScale (10);
|
|
beforeIpc->setPreviewImageListener (beforePreviewHandler);
|
|
beforeIarea->imageArea->setPreviewHandler (beforePreviewHandler);
|
|
beforeIarea->imageArea->setImProcCoordinator (beforeIpc);
|
|
|
|
iarea->setBeforeAfterViews (beforeIarea, iarea);
|
|
beforeIarea->setBeforeAfterViews (beforeIarea, iarea);
|
|
|
|
rtengine::procparams::ProcParams params;
|
|
if (history->getBeforeLineParams (params))
|
|
historyBeforeLineChanged (params);
|
|
}
|
|
}
|
|
|
|
void EditorPanel::histogramChanged (unsigned int* rh, unsigned int* gh, unsigned int* bh, unsigned int* lh, unsigned int* bcrgb, unsigned int* bcl) {
|
|
|
|
histogramPanel->histogramChanged (rh, gh, bh, lh);
|
|
tpc->updateCurveBackgroundHistogram (bcrgb, bcl);
|
|
}
|