Merge pull request #6299 from Beep6581/multi-external-editor
Multiple External Editors
This commit is contained in:
commit
f449a726e8
@ -210,6 +210,7 @@ FILEBROWSER_ZOOMOUTHINT;Decrease thumbnail size.\n\nShortcuts:\n<b>-</b> - Multi
|
|||||||
FILECHOOSER_FILTER_ANY;All files
|
FILECHOOSER_FILTER_ANY;All files
|
||||||
FILECHOOSER_FILTER_COLPROF;Color profiles (*.icc)
|
FILECHOOSER_FILTER_COLPROF;Color profiles (*.icc)
|
||||||
FILECHOOSER_FILTER_CURVE;Curve files
|
FILECHOOSER_FILTER_CURVE;Curve files
|
||||||
|
FILECHOOSER_FILTER_EXECUTABLE;Executable files
|
||||||
FILECHOOSER_FILTER_LCP;Lens correction profiles
|
FILECHOOSER_FILTER_LCP;Lens correction profiles
|
||||||
FILECHOOSER_FILTER_PP;Processing profiles
|
FILECHOOSER_FILTER_PP;Processing profiles
|
||||||
FILECHOOSER_FILTER_SAME;Same format as current photo
|
FILECHOOSER_FILTER_SAME;Same format as current photo
|
||||||
@ -237,6 +238,7 @@ GENERAL_NO;No
|
|||||||
GENERAL_NONE;None
|
GENERAL_NONE;None
|
||||||
GENERAL_OK;OK
|
GENERAL_OK;OK
|
||||||
GENERAL_OPEN;Open
|
GENERAL_OPEN;Open
|
||||||
|
GENERAL_OTHER;Other
|
||||||
GENERAL_PORTRAIT;Portrait
|
GENERAL_PORTRAIT;Portrait
|
||||||
GENERAL_RESET;Reset
|
GENERAL_RESET;Reset
|
||||||
GENERAL_SAVE;Save
|
GENERAL_SAVE;Save
|
||||||
@ -1621,7 +1623,7 @@ MAIN_BUTTON_PREFERENCES;Preferences
|
|||||||
MAIN_BUTTON_PUTTOQUEUE_TOOLTIP;Put current image to processing queue.\nShortcut: <b>Ctrl+b</b>
|
MAIN_BUTTON_PUTTOQUEUE_TOOLTIP;Put current image to processing queue.\nShortcut: <b>Ctrl+b</b>
|
||||||
MAIN_BUTTON_SAVE_TOOLTIP;Save current image.\nShortcut: <b>Ctrl+s</b>\nSave current profile (.pp3).\nShortcut: <b>Ctrl+Shift+s</b>
|
MAIN_BUTTON_SAVE_TOOLTIP;Save current image.\nShortcut: <b>Ctrl+s</b>\nSave current profile (.pp3).\nShortcut: <b>Ctrl+Shift+s</b>
|
||||||
MAIN_BUTTON_SENDTOEDITOR;Edit image in external editor
|
MAIN_BUTTON_SENDTOEDITOR;Edit image in external editor
|
||||||
MAIN_BUTTON_SENDTOEDITOR_TOOLTIP;Edit current image in external editor.\nShortcut: <b>Ctrl+e</b>
|
MAIN_BUTTON_SENDTOEDITOR_TOOLTIP;Edit current image in external editor.\nShortcut: <b>Ctrl+e</b>\nCurrent editor:
|
||||||
MAIN_BUTTON_SHOWHIDESIDEPANELS_TOOLTIP;Show/hide all side panels.\nShortcut: <b>m</b>
|
MAIN_BUTTON_SHOWHIDESIDEPANELS_TOOLTIP;Show/hide all side panels.\nShortcut: <b>m</b>
|
||||||
MAIN_BUTTON_UNFULLSCREEN;Exit fullscreen
|
MAIN_BUTTON_UNFULLSCREEN;Exit fullscreen
|
||||||
MAIN_FRAME_EDITOR;Editor
|
MAIN_FRAME_EDITOR;Editor
|
||||||
@ -1872,6 +1874,10 @@ PREFERENCES_EXTEDITOR_DIR_CUSTOM;Custom
|
|||||||
PREFERENCES_EXTEDITOR_DIR_TEMP;OS temp dir
|
PREFERENCES_EXTEDITOR_DIR_TEMP;OS temp dir
|
||||||
PREFERENCES_EXTEDITOR_FLOAT32;32-bit float TIFF output
|
PREFERENCES_EXTEDITOR_FLOAT32;32-bit float TIFF output
|
||||||
PREFERENCES_EXTERNALEDITOR;External Editor
|
PREFERENCES_EXTERNALEDITOR;External Editor
|
||||||
|
PREFERENCES_EXTERNALEDITOR_CHANGE;Change Application
|
||||||
|
PREFERENCES_EXTERNALEDITOR_CHANGE_FILE;Change Executable
|
||||||
|
PREFERENCES_EXTERNALEDITOR_COLUMN_NAME;Name
|
||||||
|
PREFERENCES_EXTERNALEDITOR_COLUMN_COMMAND;Command
|
||||||
PREFERENCES_FBROWSEROPTS;File Browser / Thumbnail Options
|
PREFERENCES_FBROWSEROPTS;File Browser / Thumbnail Options
|
||||||
PREFERENCES_FILEBROWSERTOOLBARSINGLEROW;Compact toolbars in File Browser
|
PREFERENCES_FILEBROWSERTOOLBARSINGLEROW;Compact toolbars in File Browser
|
||||||
PREFERENCES_FLATFIELDFOUND;Found
|
PREFERENCES_FLATFIELDFOUND;Found
|
||||||
|
@ -62,6 +62,7 @@ set(NONCLISOURCEFILES
|
|||||||
exiffiltersettings.cc
|
exiffiltersettings.cc
|
||||||
exifpanel.cc
|
exifpanel.cc
|
||||||
exportpanel.cc
|
exportpanel.cc
|
||||||
|
externaleditorpreferences.cc
|
||||||
extprog.cc
|
extprog.cc
|
||||||
fattaltonemap.cc
|
fattaltonemap.cc
|
||||||
filebrowser.cc
|
filebrowser.cc
|
||||||
@ -134,6 +135,7 @@ set(NONCLISOURCEFILES
|
|||||||
retinex.cc
|
retinex.cc
|
||||||
rgbcurves.cc
|
rgbcurves.cc
|
||||||
rotate.cc
|
rotate.cc
|
||||||
|
rtappchooserdialog.cc
|
||||||
rtimage.cc
|
rtimage.cc
|
||||||
rtscalable.cc
|
rtscalable.cc
|
||||||
rtsurface.cc
|
rtsurface.cc
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
#include "procparamchangers.h"
|
#include "procparamchangers.h"
|
||||||
#include "placesbrowser.h"
|
#include "placesbrowser.h"
|
||||||
#include "pathutils.h"
|
#include "pathutils.h"
|
||||||
|
#include "rtappchooserdialog.h"
|
||||||
#include "thumbnail.h"
|
#include "thumbnail.h"
|
||||||
#include "toolpanelcoord.h"
|
#include "toolpanelcoord.h"
|
||||||
|
|
||||||
@ -701,7 +702,9 @@ public:
|
|||||||
EditorPanel::EditorPanel (FilePanel* filePanel)
|
EditorPanel::EditorPanel (FilePanel* filePanel)
|
||||||
: catalogPane (nullptr), realized (false), tbBeforeLock (nullptr), iHistoryShow (nullptr), iHistoryHide (nullptr),
|
: catalogPane (nullptr), realized (false), tbBeforeLock (nullptr), iHistoryShow (nullptr), iHistoryHide (nullptr),
|
||||||
iTopPanel_1_Show (nullptr), iTopPanel_1_Hide (nullptr), iRightPanel_1_Show (nullptr), iRightPanel_1_Hide (nullptr),
|
iTopPanel_1_Show (nullptr), iTopPanel_1_Hide (nullptr), iRightPanel_1_Show (nullptr), iRightPanel_1_Hide (nullptr),
|
||||||
iBeforeLockON (nullptr), iBeforeLockOFF (nullptr), previewHandler (nullptr), beforePreviewHandler (nullptr),
|
iBeforeLockON (nullptr), iBeforeLockOFF (nullptr),
|
||||||
|
externalEditorChangedSignal (nullptr),
|
||||||
|
previewHandler (nullptr), beforePreviewHandler (nullptr),
|
||||||
beforeIarea (nullptr), beforeBox (nullptr), afterBox (nullptr), beforeLabel (nullptr), afterLabel (nullptr),
|
beforeIarea (nullptr), beforeBox (nullptr), afterBox (nullptr), beforeLabel (nullptr), afterLabel (nullptr),
|
||||||
beforeHeaderBox (nullptr), afterHeaderBox (nullptr), parent (nullptr), parentWindow (nullptr), openThm (nullptr),
|
beforeHeaderBox (nullptr), afterHeaderBox (nullptr), parent (nullptr), parentWindow (nullptr), openThm (nullptr),
|
||||||
selectedFrame(0), isrc (nullptr), ipc (nullptr), beforeIpc (nullptr), err (0), isProcessing (false),
|
selectedFrame(0), isrc (nullptr), ipc (nullptr), beforeIpc (nullptr), err (0), isProcessing (false),
|
||||||
@ -899,12 +902,15 @@ EditorPanel::EditorPanel (FilePanel* filePanel)
|
|||||||
queueimg->set_tooltip_markup (M ("MAIN_BUTTON_PUTTOQUEUE_TOOLTIP"));
|
queueimg->set_tooltip_markup (M ("MAIN_BUTTON_PUTTOQUEUE_TOOLTIP"));
|
||||||
setExpandAlignProperties (queueimg, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_FILL);
|
setExpandAlignProperties (queueimg, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_FILL);
|
||||||
|
|
||||||
Gtk::Image *sendToEditorButtonImage = Gtk::manage (new RTImage ("palette-brush.png"));
|
send_to_external = Gtk::manage(new PopUpButton("", false));
|
||||||
sendtogimp = Gtk::manage (new Gtk::Button ());
|
send_to_external->set_tooltip_text(M("MAIN_BUTTON_SENDTOEDITOR_TOOLTIP"));
|
||||||
sendtogimp->set_relief(Gtk::RELIEF_NONE);
|
setExpandAlignProperties(send_to_external->buttonGroup, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_FILL);
|
||||||
sendtogimp->add (*sendToEditorButtonImage);
|
send_to_external->addEntry("palette-brush.png", M("GENERAL_OTHER"));
|
||||||
sendtogimp->set_tooltip_markup (M ("MAIN_BUTTON_SENDTOEDITOR_TOOLTIP"));
|
updateExternalEditorWidget(
|
||||||
setExpandAlignProperties (sendtogimp, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_FILL);
|
options.externalEditorIndex >= 0 ? options.externalEditorIndex : options.externalEditors.size(),
|
||||||
|
options.externalEditors
|
||||||
|
);
|
||||||
|
send_to_external->show();
|
||||||
|
|
||||||
// Status box
|
// Status box
|
||||||
progressLabel = Gtk::manage (new MyProgressBar (300));
|
progressLabel = Gtk::manage (new MyProgressBar (300));
|
||||||
@ -969,7 +975,7 @@ EditorPanel::EditorPanel (FilePanel* filePanel)
|
|||||||
iops->attach_next_to (*vsep1, Gtk::POS_LEFT, 1, 1);
|
iops->attach_next_to (*vsep1, Gtk::POS_LEFT, 1, 1);
|
||||||
|
|
||||||
if (!gimpPlugin) {
|
if (!gimpPlugin) {
|
||||||
iops->attach_next_to (*sendtogimp, Gtk::POS_LEFT, 1, 1);
|
iops->attach_next_to(*send_to_external->buttonGroup, Gtk::POS_LEFT, 1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!gimpPlugin && !simpleEditor) {
|
if (!gimpPlugin && !simpleEditor) {
|
||||||
@ -1073,7 +1079,8 @@ EditorPanel::EditorPanel (FilePanel* filePanel)
|
|||||||
tbRightPanel_1->signal_toggled().connect ( sigc::mem_fun (*this, &EditorPanel::tbRightPanel_1_toggled) );
|
tbRightPanel_1->signal_toggled().connect ( sigc::mem_fun (*this, &EditorPanel::tbRightPanel_1_toggled) );
|
||||||
saveimgas->signal_pressed().connect ( sigc::mem_fun (*this, &EditorPanel::saveAsPressed) );
|
saveimgas->signal_pressed().connect ( sigc::mem_fun (*this, &EditorPanel::saveAsPressed) );
|
||||||
queueimg->signal_pressed().connect ( sigc::mem_fun (*this, &EditorPanel::queueImgPressed) );
|
queueimg->signal_pressed().connect ( sigc::mem_fun (*this, &EditorPanel::queueImgPressed) );
|
||||||
sendtogimp->signal_pressed().connect ( sigc::mem_fun (*this, &EditorPanel::sendToGimpPressed) );
|
send_to_external->signal_changed().connect(sigc::mem_fun(*this, &EditorPanel::sendToExternalChanged));
|
||||||
|
send_to_external->signal_pressed().connect(sigc::mem_fun(*this, &EditorPanel::sendToExternalPressed));
|
||||||
toggleHistogramProfile->signal_toggled().connect( sigc::mem_fun (*this, &EditorPanel::histogramProfile_toggled) );
|
toggleHistogramProfile->signal_toggled().connect( sigc::mem_fun (*this, &EditorPanel::histogramProfile_toggled) );
|
||||||
|
|
||||||
if (navPrev) {
|
if (navPrev) {
|
||||||
@ -1906,7 +1913,7 @@ bool EditorPanel::handleShortcutKey (GdkEventKey* event)
|
|||||||
|
|
||||||
case GDK_KEY_e:
|
case GDK_KEY_e:
|
||||||
if (!gimpPlugin) {
|
if (!gimpPlugin) {
|
||||||
sendToGimpPressed();
|
sendToExternalPressed();
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -2024,7 +2031,7 @@ bool EditorPanel::idle_saveImage (ProgressConnector<rtengine::IImagefloat*> *pc,
|
|||||||
msgd.run ();
|
msgd.run ();
|
||||||
|
|
||||||
saveimgas->set_sensitive (true);
|
saveimgas->set_sensitive (true);
|
||||||
sendtogimp->set_sensitive (true);
|
send_to_external->set_sensitive(true);
|
||||||
isProcessing = false;
|
isProcessing = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -2052,7 +2059,7 @@ bool EditorPanel::idle_imageSaved (ProgressConnector<int> *pc, rtengine::IImagef
|
|||||||
}
|
}
|
||||||
|
|
||||||
saveimgas->set_sensitive (true);
|
saveimgas->set_sensitive (true);
|
||||||
sendtogimp->set_sensitive (true);
|
send_to_external->set_sensitive(true);
|
||||||
|
|
||||||
parent->setProgressStr ("");
|
parent->setProgressStr ("");
|
||||||
parent->setProgress (0.);
|
parent->setProgress (0.);
|
||||||
@ -2163,7 +2170,7 @@ void EditorPanel::saveAsPressed ()
|
|||||||
ld->startFunc (sigc::bind (sigc::ptr_fun (&rtengine::processImage), job, err, parent->getProgressListener(), false ),
|
ld->startFunc (sigc::bind (sigc::ptr_fun (&rtengine::processImage), job, err, parent->getProgressListener(), false ),
|
||||||
sigc::bind (sigc::mem_fun ( *this, &EditorPanel::idle_saveImage ), ld, fnameOut, sf, pparams));
|
sigc::bind (sigc::mem_fun ( *this, &EditorPanel::idle_saveImage ), ld, fnameOut, sf, pparams));
|
||||||
saveimgas->set_sensitive (false);
|
saveimgas->set_sensitive (false);
|
||||||
sendtogimp->set_sensitive (false);
|
send_to_external->set_sensitive(false);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
BatchQueueEntry* bqe = createBatchQueueEntry ();
|
BatchQueueEntry* bqe = createBatchQueueEntry ();
|
||||||
@ -2194,7 +2201,7 @@ void EditorPanel::queueImgPressed ()
|
|||||||
parent->addBatchQueueJob (createBatchQueueEntry ());
|
parent->addBatchQueueJob (createBatchQueueEntry ());
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorPanel::sendToGimpPressed ()
|
void EditorPanel::sendToExternal()
|
||||||
{
|
{
|
||||||
if (!ipc || !openThm) {
|
if (!ipc || !openThm) {
|
||||||
return;
|
return;
|
||||||
@ -2206,12 +2213,46 @@ void EditorPanel::sendToGimpPressed ()
|
|||||||
if (options.editor_bypass_output_profile) {
|
if (options.editor_bypass_output_profile) {
|
||||||
pparams.icm.outputProfile = rtengine::procparams::ColorManagementParams::NoProfileString;
|
pparams.icm.outputProfile = rtengine::procparams::ColorManagementParams::NoProfileString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!cached_exported_filename.empty() && cached_exported_image == ipc->getInitialImage() && pparams == cached_exported_pparams && Glib::file_test(cached_exported_filename, Glib::FILE_TEST_IS_REGULAR)) {
|
||||||
|
idle_sentToGimp(nullptr, nullptr, cached_exported_filename);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cached_exported_image = ipc->getInitialImage();
|
||||||
|
cached_exported_pparams = pparams;
|
||||||
|
cached_exported_filename.clear();
|
||||||
rtengine::ProcessingJob* job = rtengine::ProcessingJob::create (ipc->getInitialImage(), pparams);
|
rtengine::ProcessingJob* job = rtengine::ProcessingJob::create (ipc->getInitialImage(), pparams);
|
||||||
ProgressConnector<rtengine::IImagefloat*> *ld = new ProgressConnector<rtengine::IImagefloat*>();
|
ProgressConnector<rtengine::IImagefloat*> *ld = new ProgressConnector<rtengine::IImagefloat*>();
|
||||||
ld->startFunc (sigc::bind (sigc::ptr_fun (&rtengine::processImage), job, err, parent->getProgressListener(), false ),
|
ld->startFunc (sigc::bind (sigc::ptr_fun (&rtengine::processImage), job, err, parent->getProgressListener(), false ),
|
||||||
sigc::bind (sigc::mem_fun ( *this, &EditorPanel::idle_sendToGimp ), ld, openThm->getFileName() ));
|
sigc::bind (sigc::mem_fun ( *this, &EditorPanel::idle_sendToGimp ), ld, openThm->getFileName() ));
|
||||||
saveimgas->set_sensitive (false);
|
saveimgas->set_sensitive (false);
|
||||||
sendtogimp->set_sensitive (false);
|
send_to_external->set_sensitive(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorPanel::sendToExternalChanged(int)
|
||||||
|
{
|
||||||
|
int index = send_to_external->getSelected();
|
||||||
|
if (index >= 0 && static_cast<unsigned>(index) == options.externalEditors.size()) {
|
||||||
|
index = -1;
|
||||||
|
}
|
||||||
|
options.externalEditorIndex = index;
|
||||||
|
if (externalEditorChangedSignal) {
|
||||||
|
externalEditorChangedSignal->emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorPanel::sendToExternalPressed()
|
||||||
|
{
|
||||||
|
if (options.externalEditorIndex == -1) {
|
||||||
|
// "Other" external editor. Show app chooser dialog to let user pick.
|
||||||
|
RTAppChooserDialog *dialog = getAppChooserDialog();
|
||||||
|
dialog->show();
|
||||||
|
} else {
|
||||||
|
struct ExternalEditor editor = options.externalEditors.at(options.externalEditorIndex);
|
||||||
|
external_editor_info = Gio::AppInfo::create_from_commandline(editor.command, editor.name, Gio::APP_INFO_CREATE_NONE);
|
||||||
|
sendToExternal();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2265,6 +2306,23 @@ void EditorPanel::syncFileBrowser() // synchronize filebrowser with image in E
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ExternalEditorChangedSignal * EditorPanel::getExternalEditorChangedSignal()
|
||||||
|
{
|
||||||
|
return externalEditorChangedSignal;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorPanel::setExternalEditorChangedSignal(ExternalEditorChangedSignal *signal)
|
||||||
|
{
|
||||||
|
if (externalEditorChangedSignal) {
|
||||||
|
externalEditorChangedSignalConnection.disconnect();
|
||||||
|
}
|
||||||
|
externalEditorChangedSignal = signal;
|
||||||
|
if (signal) {
|
||||||
|
externalEditorChangedSignalConnection = signal->connect(
|
||||||
|
sigc::mem_fun(*this, &EditorPanel::updateExternalEditorSelection));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void EditorPanel::histogramProfile_toggled()
|
void EditorPanel::histogramProfile_toggled()
|
||||||
{
|
{
|
||||||
options.rtSettings.HistogramWorking = toggleHistogramProfile->get_active();
|
options.rtSettings.HistogramWorking = toggleHistogramProfile->get_active();
|
||||||
@ -2330,7 +2388,7 @@ bool EditorPanel::idle_sendToGimp ( ProgressConnector<rtengine::IImagefloat*> *p
|
|||||||
Gtk::MessageDialog msgd (*parent, msg_, true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
|
Gtk::MessageDialog msgd (*parent, msg_, true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
|
||||||
msgd.run ();
|
msgd.run ();
|
||||||
saveimgas->set_sensitive (true);
|
saveimgas->set_sensitive (true);
|
||||||
sendtogimp->set_sensitive (true);
|
send_to_external->set_sensitive(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -2338,27 +2396,27 @@ bool EditorPanel::idle_sendToGimp ( ProgressConnector<rtengine::IImagefloat*> *p
|
|||||||
|
|
||||||
bool EditorPanel::idle_sentToGimp (ProgressConnector<int> *pc, rtengine::IImagefloat* img, Glib::ustring filename)
|
bool EditorPanel::idle_sentToGimp (ProgressConnector<int> *pc, rtengine::IImagefloat* img, Glib::ustring filename)
|
||||||
{
|
{
|
||||||
delete img;
|
if (img) {
|
||||||
int errore = pc->returnValue();
|
delete img;
|
||||||
|
cached_exported_filename = filename;
|
||||||
|
}
|
||||||
|
int errore = 0;
|
||||||
setProgressState(false);
|
setProgressState(false);
|
||||||
delete pc;
|
if (pc) {
|
||||||
|
errore = pc->returnValue();
|
||||||
|
delete pc;
|
||||||
|
}
|
||||||
|
|
||||||
if (!errore) {
|
if ((!img && Glib::file_test(filename, Glib::FILE_TEST_IS_REGULAR)) || (img && !errore)) {
|
||||||
saveimgas->set_sensitive (true);
|
saveimgas->set_sensitive (true);
|
||||||
sendtogimp->set_sensitive (true);
|
send_to_external->set_sensitive(true);
|
||||||
parent->setProgressStr ("");
|
parent->setProgressStr ("");
|
||||||
parent->setProgress (0.);
|
parent->setProgress (0.);
|
||||||
bool success = false;
|
bool success = false;
|
||||||
|
|
||||||
setUserOnlyPermission(Gio::File::create_for_path(filename), false);
|
setUserOnlyPermission(Gio::File::create_for_path(filename), false);
|
||||||
|
|
||||||
if (options.editorToSendTo == 1) {
|
success = ExtProgStore::openInExternalEditor(filename, external_editor_info);
|
||||||
success = ExtProgStore::openInGimp (filename);
|
|
||||||
} else if (options.editorToSendTo == 2) {
|
|
||||||
success = ExtProgStore::openInPhotoshop (filename);
|
|
||||||
} else if (options.editorToSendTo == 3) {
|
|
||||||
success = ExtProgStore::openInCustomEditor (filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
Gtk::MessageDialog msgd (*parent, M ("MAIN_MSG_CANNOTSTARTEDITOR"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
|
Gtk::MessageDialog msgd (*parent, M ("MAIN_MSG_CANNOTSTARTEDITOR"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
|
||||||
@ -2371,6 +2429,48 @@ bool EditorPanel::idle_sentToGimp (ProgressConnector<int> *pc, rtengine::IImagef
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RTAppChooserDialog *EditorPanel::getAppChooserDialog()
|
||||||
|
{
|
||||||
|
if (!app_chooser_dialog.get()) {
|
||||||
|
app_chooser_dialog.reset(new RTAppChooserDialog("image/tiff"));
|
||||||
|
app_chooser_dialog->signal_response().connect(
|
||||||
|
sigc::mem_fun(*this, &EditorPanel::onAppChooserDialogResponse)
|
||||||
|
);
|
||||||
|
app_chooser_dialog->set_modal();
|
||||||
|
}
|
||||||
|
|
||||||
|
return app_chooser_dialog.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorPanel::onAppChooserDialogResponse(int responseId)
|
||||||
|
{
|
||||||
|
switch (responseId) {
|
||||||
|
case Gtk::RESPONSE_OK:
|
||||||
|
getAppChooserDialog()->close();
|
||||||
|
external_editor_info = getAppChooserDialog()->get_app_info();
|
||||||
|
sendToExternal();
|
||||||
|
break;
|
||||||
|
case Gtk::RESPONSE_CANCEL:
|
||||||
|
case Gtk::RESPONSE_CLOSE:
|
||||||
|
getAppChooserDialog()->close();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorPanel::updateExternalEditorSelection()
|
||||||
|
{
|
||||||
|
int index = send_to_external->getSelected();
|
||||||
|
if (index >= 0 && static_cast<unsigned>(index) == options.externalEditors.size()) {
|
||||||
|
index = -1;
|
||||||
|
}
|
||||||
|
if (options.externalEditorIndex != index) {
|
||||||
|
send_to_external->setSelected(
|
||||||
|
options.externalEditorIndex >= 0 ? options.externalEditorIndex : options.externalEditors.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void EditorPanel::historyBeforeLineChanged (const rtengine::procparams::ProcParams& params)
|
void EditorPanel::historyBeforeLineChanged (const rtengine::procparams::ProcParams& params)
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -2646,6 +2746,40 @@ void EditorPanel::tbShowHideSidePanels_managestate()
|
|||||||
ShowHideSidePanelsconn.block (false);
|
ShowHideSidePanelsconn.block (false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EditorPanel::updateExternalEditorWidget(int selectedIndex, const std::vector<ExternalEditor> &editors)
|
||||||
|
{
|
||||||
|
// Remove the editors and leave the "Other" entry.
|
||||||
|
while (send_to_external->getEntryCount() > 1) {
|
||||||
|
send_to_external->removeEntry(0);
|
||||||
|
}
|
||||||
|
// Add the editors.
|
||||||
|
for (unsigned i = 0; i < editors.size(); i++) {
|
||||||
|
const auto & name = editors[i].name.empty() ? Glib::ustring(" ") : editors[i].name;
|
||||||
|
if (!editors[i].icon_serialized.empty()) {
|
||||||
|
Glib::RefPtr<Gio::Icon> gioIcon;
|
||||||
|
GError *e = nullptr;
|
||||||
|
GVariant *icon_variant = g_variant_parse(
|
||||||
|
nullptr, editors[i].icon_serialized.c_str(), nullptr, nullptr, &e);
|
||||||
|
|
||||||
|
if (e) {
|
||||||
|
std::cerr
|
||||||
|
<< "Error loading external editor icon from \""
|
||||||
|
<< editors[i].icon_serialized << "\": " << e->message
|
||||||
|
<< std::endl;
|
||||||
|
gioIcon = Glib::RefPtr<Gio::Icon>();
|
||||||
|
} else {
|
||||||
|
gioIcon = Gio::Icon::deserialize(Glib::VariantBase(icon_variant));
|
||||||
|
}
|
||||||
|
|
||||||
|
send_to_external->insertEntry(i, gioIcon, name);
|
||||||
|
} else {
|
||||||
|
send_to_external->insertEntry(i, "palette-brush.png", name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
send_to_external->setSelected(selectedIndex);
|
||||||
|
send_to_external->show();
|
||||||
|
}
|
||||||
|
|
||||||
void EditorPanel::updateProfiles (const Glib::ustring &printerProfile, rtengine::RenderingIntent printerIntent, bool printerBPC)
|
void EditorPanel::updateProfiles (const Glib::ustring &printerProfile, rtengine::RenderingIntent printerIntent, bool printerBPC)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -38,11 +38,15 @@ template<typename T>
|
|||||||
class array2D;
|
class array2D;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using ExternalEditorChangedSignal = sigc::signal<void>;
|
||||||
|
|
||||||
class BatchQueueEntry;
|
class BatchQueueEntry;
|
||||||
class EditorPanel;
|
class EditorPanel;
|
||||||
class FilePanel;
|
class FilePanel;
|
||||||
class MyProgressBar;
|
class MyProgressBar;
|
||||||
class Navigator;
|
class Navigator;
|
||||||
|
class PopUpButton;
|
||||||
|
class RTAppChooserDialog;
|
||||||
class Thumbnail;
|
class Thumbnail;
|
||||||
class ToolPanelCoordinator;
|
class ToolPanelCoordinator;
|
||||||
|
|
||||||
@ -65,6 +69,7 @@ class EditorPanel final :
|
|||||||
public rtengine::NonCopyable
|
public rtengine::NonCopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
explicit EditorPanel (FilePanel* filePanel = nullptr);
|
explicit EditorPanel (FilePanel* filePanel = nullptr);
|
||||||
~EditorPanel () override;
|
~EditorPanel () override;
|
||||||
|
|
||||||
@ -162,11 +167,17 @@ public:
|
|||||||
void tbBeforeLock_toggled();
|
void tbBeforeLock_toggled();
|
||||||
void saveAsPressed ();
|
void saveAsPressed ();
|
||||||
void queueImgPressed ();
|
void queueImgPressed ();
|
||||||
void sendToGimpPressed ();
|
void sendToExternal();
|
||||||
|
void sendToExternalChanged(int);
|
||||||
|
void sendToExternalPressed();
|
||||||
void openNextEditorImage ();
|
void openNextEditorImage ();
|
||||||
void openPreviousEditorImage ();
|
void openPreviousEditorImage ();
|
||||||
void syncFileBrowser ();
|
void syncFileBrowser ();
|
||||||
|
|
||||||
|
// Signals.
|
||||||
|
ExternalEditorChangedSignal * getExternalEditorChangedSignal();
|
||||||
|
void setExternalEditorChangedSignal(ExternalEditorChangedSignal *signal);
|
||||||
|
|
||||||
void tbTopPanel_1_visible (bool visible);
|
void tbTopPanel_1_visible (bool visible);
|
||||||
bool CheckSidePanelsVisibility();
|
bool CheckSidePanelsVisibility();
|
||||||
void tbShowHideSidePanels_managestate();
|
void tbShowHideSidePanels_managestate();
|
||||||
@ -182,6 +193,7 @@ public:
|
|||||||
{
|
{
|
||||||
return isProcessing;
|
return isProcessing;
|
||||||
}
|
}
|
||||||
|
void updateExternalEditorWidget(int selectedIndex, const std::vector<ExternalEditor> &editors);
|
||||||
void updateProfiles (const Glib::ustring &printerProfile, rtengine::RenderingIntent printerIntent, bool printerBPC);
|
void updateProfiles (const Glib::ustring &printerProfile, rtengine::RenderingIntent printerIntent, bool printerBPC);
|
||||||
void updateTPVScrollbar (bool hide);
|
void updateTPVScrollbar (bool hide);
|
||||||
void updateHistogramPosition (int oldPosition, int newPosition);
|
void updateHistogramPosition (int oldPosition, int newPosition);
|
||||||
@ -201,6 +213,9 @@ private:
|
|||||||
bool idle_sendToGimp ( ProgressConnector<rtengine::IImagefloat*> *pc, Glib::ustring fname);
|
bool idle_sendToGimp ( ProgressConnector<rtengine::IImagefloat*> *pc, Glib::ustring fname);
|
||||||
bool idle_sentToGimp (ProgressConnector<int> *pc, rtengine::IImagefloat* img, Glib::ustring filename);
|
bool idle_sentToGimp (ProgressConnector<int> *pc, rtengine::IImagefloat* img, Glib::ustring filename);
|
||||||
void histogramProfile_toggled ();
|
void histogramProfile_toggled ();
|
||||||
|
RTAppChooserDialog *getAppChooserDialog();
|
||||||
|
void onAppChooserDialogResponse(int resposneId);
|
||||||
|
void updateExternalEditorSelection();
|
||||||
|
|
||||||
|
|
||||||
Glib::ustring lastSaveAsFileName;
|
Glib::ustring lastSaveAsFileName;
|
||||||
@ -230,10 +245,18 @@ private:
|
|||||||
|
|
||||||
Gtk::Button* queueimg;
|
Gtk::Button* queueimg;
|
||||||
Gtk::Button* saveimgas;
|
Gtk::Button* saveimgas;
|
||||||
Gtk::Button* sendtogimp;
|
PopUpButton* send_to_external;
|
||||||
Gtk::Button* navSync;
|
Gtk::Button* navSync;
|
||||||
Gtk::Button* navNext;
|
Gtk::Button* navNext;
|
||||||
Gtk::Button* navPrev;
|
Gtk::Button* navPrev;
|
||||||
|
Glib::RefPtr<Gio::AppInfo> external_editor_info;
|
||||||
|
std::unique_ptr<RTAppChooserDialog> app_chooser_dialog;
|
||||||
|
ExternalEditorChangedSignal *externalEditorChangedSignal;
|
||||||
|
sigc::connection externalEditorChangedSignalConnection;
|
||||||
|
|
||||||
|
rtengine::InitialImage *cached_exported_image;
|
||||||
|
rtengine::procparams::ProcParams cached_exported_pparams;
|
||||||
|
Glib::ustring cached_exported_filename;
|
||||||
|
|
||||||
class ColorManagementToolbar;
|
class ColorManagementToolbar;
|
||||||
std::unique_ptr<ColorManagementToolbar> colorMgmtToolBar;
|
std::unique_ptr<ColorManagementToolbar> colorMgmtToolBar;
|
||||||
|
@ -250,6 +250,7 @@ void EditWindow::addEditorPanel (EditorPanel* ep, const std::string &name)
|
|||||||
{
|
{
|
||||||
ep->setParent (parent);
|
ep->setParent (parent);
|
||||||
ep->setParentWindow(this);
|
ep->setParentWindow(this);
|
||||||
|
ep->setExternalEditorChangedSignal(&externalEditorChangedSignal);
|
||||||
|
|
||||||
// construct closeable tab for the image
|
// construct closeable tab for the image
|
||||||
Gtk::Box* hb = Gtk::manage (new Gtk::Box ());
|
Gtk::Box* hb = Gtk::manage (new Gtk::Box ());
|
||||||
@ -288,6 +289,7 @@ void EditWindow::remEditorPanel (EditorPanel* ep)
|
|||||||
return; // Will crash if destroyed while loading
|
return; // Will crash if destroyed while loading
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ep->setExternalEditorChangedSignal(nullptr);
|
||||||
epanels.erase (ep->getFileName());
|
epanels.erase (ep->getFileName());
|
||||||
filesEdited.erase (ep->getFileName ());
|
filesEdited.erase (ep->getFileName ());
|
||||||
parent->fpanel->refreshEditedState (filesEdited);
|
parent->fpanel->refreshEditedState (filesEdited);
|
||||||
|
@ -39,6 +39,8 @@ private:
|
|||||||
std::set<Glib::ustring> filesEdited;
|
std::set<Glib::ustring> filesEdited;
|
||||||
std::map<Glib::ustring, EditorPanel*> epanels;
|
std::map<Glib::ustring, EditorPanel*> epanels;
|
||||||
|
|
||||||
|
sigc::signal<void> externalEditorChangedSignal;
|
||||||
|
|
||||||
bool isFullscreen;
|
bool isFullscreen;
|
||||||
bool isClosed;
|
bool isClosed;
|
||||||
bool isMinimized;
|
bool isMinimized;
|
||||||
|
354
rtgui/externaleditorpreferences.cc
Normal file
354
rtgui/externaleditorpreferences.cc
Normal file
@ -0,0 +1,354 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of RawTherapee.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021 Lawrence Lee <billee@ucdavis.edu>
|
||||||
|
*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <giomm/contenttype.h>
|
||||||
|
#include <glibmm/shell.h>
|
||||||
|
#include <gtkmm/filechooserdialog.h>
|
||||||
|
#include <gtkmm/stock.h>
|
||||||
|
|
||||||
|
#include "externaleditorpreferences.h"
|
||||||
|
#include "multilangmgr.h"
|
||||||
|
#include "rtimage.h"
|
||||||
|
|
||||||
|
|
||||||
|
ExternalEditorPreferences::ExternalEditorPreferences():
|
||||||
|
Box(Gtk::Orientation::ORIENTATION_VERTICAL),
|
||||||
|
list_model(Gtk::ListStore::create(model_columns)),
|
||||||
|
toolbar(Gtk::Orientation::ORIENTATION_HORIZONTAL)
|
||||||
|
{
|
||||||
|
// List view.
|
||||||
|
list_view = Gtk::manage(new Gtk::TreeView());
|
||||||
|
list_view->set_model(list_model);
|
||||||
|
list_view->append_column(*Gtk::manage(makeAppColumn()));
|
||||||
|
list_view->append_column(*Gtk::manage(makeCommandColumn()));
|
||||||
|
|
||||||
|
for (auto &&column : list_view->get_columns()) {
|
||||||
|
column->set_sizing(Gtk::TreeViewColumnSizing::TREE_VIEW_COLUMN_FIXED);
|
||||||
|
}
|
||||||
|
|
||||||
|
list_view->set_grid_lines(Gtk::TREE_VIEW_GRID_LINES_VERTICAL);
|
||||||
|
list_view->set_reorderable();
|
||||||
|
|
||||||
|
// List scroll area.
|
||||||
|
list_scroll_area.set_hexpand();
|
||||||
|
list_scroll_area.set_vexpand();
|
||||||
|
list_scroll_area.add(*list_view);
|
||||||
|
|
||||||
|
// Toolbar buttons.
|
||||||
|
auto add_image = Gtk::manage(new RTImage("add-small.png"));
|
||||||
|
auto remove_image = Gtk::manage(new RTImage("remove-small.png"));
|
||||||
|
button_add = Gtk::manage(new Gtk::Button());
|
||||||
|
button_remove = Gtk::manage(new Gtk::Button());
|
||||||
|
button_add->set_image(*add_image);
|
||||||
|
button_remove->set_image(*remove_image);
|
||||||
|
button_app_chooser = Gtk::manage(new Gtk::Button(M("PREFERENCES_EXTERNALEDITOR_CHANGE")));
|
||||||
|
button_file_chooser = Gtk::manage(new Gtk::Button(M("PREFERENCES_EXTERNALEDITOR_CHANGE_FILE")));
|
||||||
|
|
||||||
|
button_app_chooser->signal_pressed().connect(sigc::mem_fun(
|
||||||
|
*this, &ExternalEditorPreferences::openAppChooserDialog));
|
||||||
|
button_add->signal_pressed().connect(sigc::mem_fun(
|
||||||
|
*this, &ExternalEditorPreferences::addEditor));
|
||||||
|
button_file_chooser->signal_pressed().connect(sigc::mem_fun(
|
||||||
|
*this, &ExternalEditorPreferences::openFileChooserDialog));
|
||||||
|
button_remove->signal_pressed().connect(sigc::mem_fun(
|
||||||
|
*this, &ExternalEditorPreferences::removeSelectedEditors));
|
||||||
|
|
||||||
|
list_view->get_selection()->signal_changed().connect(sigc::mem_fun(
|
||||||
|
*this, &ExternalEditorPreferences::updateToolbarSensitivity));
|
||||||
|
updateToolbarSensitivity();
|
||||||
|
|
||||||
|
// Toolbar.
|
||||||
|
toolbar.set_halign(Gtk::Align::ALIGN_END);
|
||||||
|
toolbar.add(*button_app_chooser);
|
||||||
|
toolbar.add(*button_file_chooser);
|
||||||
|
toolbar.add(*button_add);
|
||||||
|
toolbar.add(*button_remove);
|
||||||
|
|
||||||
|
// This widget's children.
|
||||||
|
add(list_scroll_area);
|
||||||
|
add(toolbar);
|
||||||
|
show_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<ExternalEditorPreferences::EditorInfo>
|
||||||
|
ExternalEditorPreferences::getEditors() const
|
||||||
|
{
|
||||||
|
std::vector<ExternalEditorPreferences::EditorInfo> editors;
|
||||||
|
|
||||||
|
auto children = list_model->children();
|
||||||
|
|
||||||
|
for (auto rowIter = children.begin(); rowIter != children.end(); rowIter++) {
|
||||||
|
const Gio::Icon *const icon = rowIter->get_value(model_columns.icon).get();
|
||||||
|
const auto &icon_serialized = icon == nullptr ? "" : icon->serialize().print();
|
||||||
|
editors.push_back(ExternalEditorPreferences::EditorInfo(
|
||||||
|
rowIter->get_value(model_columns.name),
|
||||||
|
rowIter->get_value(model_columns.command),
|
||||||
|
icon_serialized,
|
||||||
|
rowIter->get_value(model_columns.other_data)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
return editors;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExternalEditorPreferences::setEditors(
|
||||||
|
const std::vector<ExternalEditorPreferences::EditorInfo> &editors)
|
||||||
|
{
|
||||||
|
list_model->clear();
|
||||||
|
|
||||||
|
for (const ExternalEditorPreferences::EditorInfo & editor : editors) {
|
||||||
|
auto row = *list_model->append();
|
||||||
|
Glib::RefPtr<Gio::Icon> icon;
|
||||||
|
|
||||||
|
// Get icon.
|
||||||
|
if (editor.icon_serialized.empty()) {
|
||||||
|
icon = Glib::RefPtr<Gio::Icon>();
|
||||||
|
} else {
|
||||||
|
GError *e = nullptr;
|
||||||
|
GVariant *icon_variant = g_variant_parse(
|
||||||
|
nullptr, editor.icon_serialized.c_str(), nullptr, nullptr, &e);
|
||||||
|
if (e) {
|
||||||
|
std::cerr
|
||||||
|
<< "Error loading external editor icon from \""
|
||||||
|
<< editor.icon_serialized << "\": " << e->message
|
||||||
|
<< std::endl;
|
||||||
|
icon = Glib::RefPtr<Gio::Icon>();
|
||||||
|
} else {
|
||||||
|
icon = Gio::Icon::deserialize(Glib::VariantBase(icon_variant));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
row[model_columns.name] = editor.name;
|
||||||
|
row[model_columns.icon] = icon;
|
||||||
|
row[model_columns.command] = editor.command;
|
||||||
|
row[model_columns.other_data] = editor.other_data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExternalEditorPreferences::addEditor()
|
||||||
|
{
|
||||||
|
Gtk::TreeModel::Row row;
|
||||||
|
auto selected = list_view->get_selection()->get_selected_rows();
|
||||||
|
|
||||||
|
if (selected.size()) {
|
||||||
|
row = *list_model->insert_after(list_model->get_iter(selected.back()));
|
||||||
|
} else {
|
||||||
|
row = *list_model->append();
|
||||||
|
}
|
||||||
|
|
||||||
|
row[model_columns.name] = "-";
|
||||||
|
list_view->get_selection()->select(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
Gtk::TreeViewColumn *ExternalEditorPreferences::makeAppColumn()
|
||||||
|
{
|
||||||
|
auto name_renderer = Gtk::manage(new Gtk::CellRendererText());
|
||||||
|
auto icon_renderer = Gtk::manage(new Gtk::CellRendererPixbuf());
|
||||||
|
auto col = Gtk::manage(new Gtk::TreeViewColumn());
|
||||||
|
|
||||||
|
col->set_title(M("PREFERENCES_EXTERNALEDITOR_COLUMN_NAME"));
|
||||||
|
col->set_resizable();
|
||||||
|
col->pack_start(*icon_renderer, false);
|
||||||
|
col->pack_start(*name_renderer);
|
||||||
|
col->add_attribute(*icon_renderer, "gicon", model_columns.icon);
|
||||||
|
col->add_attribute(*name_renderer, "text", model_columns.name);
|
||||||
|
col->set_min_width(20);
|
||||||
|
|
||||||
|
name_renderer->property_editable() = true;
|
||||||
|
name_renderer->signal_edited().connect(
|
||||||
|
sigc::mem_fun(*this, &ExternalEditorPreferences::setAppName));
|
||||||
|
|
||||||
|
return col;
|
||||||
|
}
|
||||||
|
|
||||||
|
Gtk::TreeViewColumn *ExternalEditorPreferences::makeCommandColumn()
|
||||||
|
{
|
||||||
|
auto command_renderer = Gtk::manage(new Gtk::CellRendererText());
|
||||||
|
auto col = Gtk::manage(new Gtk::TreeViewColumn());
|
||||||
|
|
||||||
|
col->set_title(M("PREFERENCES_EXTERNALEDITOR_COLUMN_COMMAND"));
|
||||||
|
col->pack_start(*command_renderer);
|
||||||
|
col->add_attribute(*command_renderer, "text", model_columns.command);
|
||||||
|
|
||||||
|
command_renderer->property_editable() = true;
|
||||||
|
command_renderer->signal_edited().connect(
|
||||||
|
sigc::mem_fun(*this, &ExternalEditorPreferences::setAppCommand));
|
||||||
|
|
||||||
|
return col;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExternalEditorPreferences::onAppChooserDialogResponse(
|
||||||
|
int response_id, RTAppChooserDialog *dialog)
|
||||||
|
{
|
||||||
|
switch (response_id) {
|
||||||
|
case Gtk::RESPONSE_OK:
|
||||||
|
dialog->close();
|
||||||
|
setApp(dialog->get_app_info());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Gtk::RESPONSE_CANCEL:
|
||||||
|
case Gtk::RESPONSE_CLOSE:
|
||||||
|
dialog->close();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExternalEditorPreferences::onFileChooserDialogResponse(
|
||||||
|
int response_id, Gtk::FileChooserDialog *dialog)
|
||||||
|
{
|
||||||
|
switch (response_id) {
|
||||||
|
case Gtk::RESPONSE_OK: {
|
||||||
|
dialog->close();
|
||||||
|
|
||||||
|
auto selection = list_view->get_selection()->get_selected_rows();
|
||||||
|
for (const auto &selected : selection) {
|
||||||
|
auto row = *list_model->get_iter(selected);
|
||||||
|
row[model_columns.icon] = Glib::RefPtr<Gio::Icon>(nullptr);
|
||||||
|
row[model_columns.command] =
|
||||||
|
#ifdef WIN32
|
||||||
|
'"' + dialog->get_filename() + '"';
|
||||||
|
#else
|
||||||
|
Glib::shell_quote(dialog->get_filename());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Gtk::RESPONSE_CANCEL:
|
||||||
|
case Gtk::RESPONSE_CLOSE:
|
||||||
|
dialog->close();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExternalEditorPreferences::openAppChooserDialog()
|
||||||
|
{
|
||||||
|
if (app_chooser_dialog.get()) {
|
||||||
|
app_chooser_dialog->refresh();
|
||||||
|
app_chooser_dialog->show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
app_chooser_dialog.reset(new RTAppChooserDialog("image/tiff"));
|
||||||
|
app_chooser_dialog->signal_response().connect(sigc::bind(
|
||||||
|
sigc::mem_fun(*this, &ExternalEditorPreferences::onAppChooserDialogResponse),
|
||||||
|
app_chooser_dialog.get()
|
||||||
|
));
|
||||||
|
app_chooser_dialog->set_modal();
|
||||||
|
app_chooser_dialog->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExternalEditorPreferences::openFileChooserDialog()
|
||||||
|
{
|
||||||
|
if (file_chooser_dialog.get()) {
|
||||||
|
file_chooser_dialog->show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
file_chooser_dialog.reset(new Gtk::FileChooserDialog(M("PREFERENCES_EXTERNALEDITOR_CHANGE_FILE")));
|
||||||
|
|
||||||
|
const auto exe_filter = Gtk::FileFilter::create();
|
||||||
|
exe_filter->set_name(M("FILECHOOSER_FILTER_EXECUTABLE"));
|
||||||
|
exe_filter->add_custom(Gtk::FILE_FILTER_MIME_TYPE, [](const Gtk::FileFilter::Info &info) {
|
||||||
|
return Gio::content_type_can_be_executable(info.mime_type);
|
||||||
|
});
|
||||||
|
const auto all_filter = Gtk::FileFilter::create();
|
||||||
|
all_filter->set_name(M("FILECHOOSER_FILTER_ANY"));
|
||||||
|
all_filter->add_pattern("*");
|
||||||
|
file_chooser_dialog->add_filter(exe_filter);
|
||||||
|
file_chooser_dialog->add_filter(all_filter);
|
||||||
|
|
||||||
|
file_chooser_dialog->signal_response().connect(sigc::bind(
|
||||||
|
sigc::mem_fun(*this, &ExternalEditorPreferences::onFileChooserDialogResponse),
|
||||||
|
file_chooser_dialog.get()));
|
||||||
|
file_chooser_dialog->set_modal();
|
||||||
|
file_chooser_dialog->add_button(M("GENERAL_CANCEL"), Gtk::RESPONSE_CANCEL);
|
||||||
|
file_chooser_dialog->add_button(M("GENERAL_OPEN"), Gtk::RESPONSE_OK);
|
||||||
|
file_chooser_dialog->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExternalEditorPreferences::removeSelectedEditors()
|
||||||
|
{
|
||||||
|
auto selection = list_view->get_selection()->get_selected_rows();
|
||||||
|
|
||||||
|
for (const auto &selected : selection) {
|
||||||
|
list_model->erase(list_model->get_iter(selected));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExternalEditorPreferences::setApp(const Glib::RefPtr<Gio::AppInfo> app_info)
|
||||||
|
{
|
||||||
|
auto selection = list_view->get_selection()->get_selected_rows();
|
||||||
|
|
||||||
|
for (const auto &selected : selection) {
|
||||||
|
auto row = *list_model->get_iter(selected);
|
||||||
|
row[model_columns.icon] = app_info->get_icon();
|
||||||
|
row[model_columns.name] = app_info->get_name();
|
||||||
|
row[model_columns.command] = app_info->get_commandline();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExternalEditorPreferences::setAppCommand(
|
||||||
|
const Glib::ustring & path, const Glib::ustring & new_text)
|
||||||
|
{
|
||||||
|
auto row_iter = list_model->get_iter(path);
|
||||||
|
|
||||||
|
if (!row_iter->get_value(model_columns.command).compare(new_text)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
row_iter->set_value(model_columns.command, new_text);
|
||||||
|
row_iter->set_value(model_columns.icon, Glib::RefPtr<Gio::Icon>(nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExternalEditorPreferences::setAppName(
|
||||||
|
const Glib::ustring & path, const Glib::ustring & new_text)
|
||||||
|
{
|
||||||
|
list_model->get_iter(path)->set_value(model_columns.name, new_text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExternalEditorPreferences::updateToolbarSensitivity()
|
||||||
|
{
|
||||||
|
bool selected = list_view->get_selection()->count_selected_rows();
|
||||||
|
button_app_chooser->set_sensitive(selected);
|
||||||
|
button_file_chooser->set_sensitive(selected);
|
||||||
|
button_remove->set_sensitive(selected);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExternalEditorPreferences::EditorInfo::EditorInfo(
|
||||||
|
Glib::ustring name, Glib::ustring command, Glib::ustring icon_serialized, void *other_data
|
||||||
|
) : name(name), icon_serialized(icon_serialized), command(command), other_data(other_data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ExternalEditorPreferences::ModelColumns::ModelColumns()
|
||||||
|
{
|
||||||
|
add(name);
|
||||||
|
add(icon);
|
||||||
|
add(command);
|
||||||
|
add(other_data);
|
||||||
|
}
|
167
rtgui/externaleditorpreferences.h
Normal file
167
rtgui/externaleditorpreferences.h
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of RawTherapee.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021 Lawrence Lee <billee@ucdavis.edu>
|
||||||
|
*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <gtkmm/button.h>
|
||||||
|
#include <gtkmm/box.h>
|
||||||
|
#include <gtkmm/liststore.h>
|
||||||
|
#include <gtkmm/scrolledwindow.h>
|
||||||
|
#include <gtkmm/treemodelcolumn.h>
|
||||||
|
#include <gtkmm/treeview.h>
|
||||||
|
|
||||||
|
#include "rtappchooserdialog.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Gtk
|
||||||
|
{
|
||||||
|
|
||||||
|
class FileChooserDialog;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Widget for editing the external editors options.
|
||||||
|
*/
|
||||||
|
class ExternalEditorPreferences : public Gtk::Box
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Data struct containing information about an external editor.
|
||||||
|
*/
|
||||||
|
struct EditorInfo {
|
||||||
|
explicit EditorInfo(
|
||||||
|
Glib::ustring name = Glib::ustring(),
|
||||||
|
Glib::ustring command = Glib::ustring(),
|
||||||
|
Glib::ustring icon_serialized = Glib::ustring(),
|
||||||
|
void *other_data = nullptr
|
||||||
|
);
|
||||||
|
/**
|
||||||
|
* Name of the external editor.
|
||||||
|
*/
|
||||||
|
Glib::ustring name;
|
||||||
|
/**
|
||||||
|
* The string representation of the icon. See Gio::Icon::serialize().
|
||||||
|
*/
|
||||||
|
Glib::ustring icon_serialized;
|
||||||
|
/**
|
||||||
|
* The commandline for running the program. See
|
||||||
|
* Gio::AppInfo::get_commandline()
|
||||||
|
*/
|
||||||
|
Glib::ustring command;
|
||||||
|
/**
|
||||||
|
* Holds any other data associated with the editor. For example, it can
|
||||||
|
* be used as a tag to uniquely identify the editor.
|
||||||
|
*/
|
||||||
|
void *other_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
ExternalEditorPreferences();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates and returns a vector representing the external editors shown in
|
||||||
|
* this widget.
|
||||||
|
*/
|
||||||
|
std::vector<EditorInfo> getEditors() const;
|
||||||
|
/**
|
||||||
|
* Populates this widget with the external editors described in the
|
||||||
|
* argument.
|
||||||
|
*/
|
||||||
|
void setEditors(const std::vector<EditorInfo> &editors);
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* Model representing the data fields each external editor entry has.
|
||||||
|
*/
|
||||||
|
class ModelColumns : public Gtk::TreeModelColumnRecord
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ModelColumns();
|
||||||
|
Gtk::TreeModelColumn<Glib::ustring> name;
|
||||||
|
Gtk::TreeModelColumn<Glib::RefPtr<Gio::Icon>> icon;
|
||||||
|
Gtk::TreeModelColumn<Glib::ustring> command;
|
||||||
|
Gtk::TreeModelColumn<void *> other_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
ModelColumns model_columns;
|
||||||
|
Glib::RefPtr<Gtk::ListStore> list_model; // The list of editors.
|
||||||
|
Gtk::ScrolledWindow list_scroll_area; // Allows the list to be scrolled.
|
||||||
|
Gtk::TreeView *list_view; // Widget for displaying the list.
|
||||||
|
Gtk::Box toolbar; // Contains buttons for editing the list.
|
||||||
|
Gtk::Button *button_app_chooser;
|
||||||
|
Gtk::Button *button_add;
|
||||||
|
Gtk::Button *button_file_chooser;
|
||||||
|
Gtk::Button *button_remove;
|
||||||
|
std::unique_ptr<RTAppChooserDialog> app_chooser_dialog;
|
||||||
|
std::unique_ptr<Gtk::FileChooserDialog> file_chooser_dialog;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts a new editor entry after the current selection, or at the end if
|
||||||
|
* no editor is selected.
|
||||||
|
*/
|
||||||
|
void addEditor();
|
||||||
|
/**
|
||||||
|
* Constructs the column for displaying the external editor name (and icon).
|
||||||
|
*/
|
||||||
|
Gtk::TreeViewColumn *makeAppColumn();
|
||||||
|
/**
|
||||||
|
* Constructs the column for displaying an editable commandline.
|
||||||
|
*/
|
||||||
|
Gtk::TreeViewColumn *makeCommandColumn();
|
||||||
|
/**
|
||||||
|
* Called when the user is done interacting with the app chooser dialog.
|
||||||
|
* Closes the dialog and updates the selected entry if an app was chosen.
|
||||||
|
*/
|
||||||
|
void onAppChooserDialogResponse(int responseId, RTAppChooserDialog *dialog);
|
||||||
|
/**
|
||||||
|
* Called when the user is done interacting with the file chooser dialog.
|
||||||
|
* Closes the dialog and updates the selected entry if a file was chosen.
|
||||||
|
*/
|
||||||
|
void onFileChooserDialogResponse(int responseId, Gtk::FileChooserDialog *dialog);
|
||||||
|
/**
|
||||||
|
* Shows the app chooser dialog.
|
||||||
|
*/
|
||||||
|
void openAppChooserDialog();
|
||||||
|
/**
|
||||||
|
* Shows the file chooser dialog for picking an executable.
|
||||||
|
*/
|
||||||
|
void openFileChooserDialog();
|
||||||
|
/**
|
||||||
|
* Removes all selected editors.
|
||||||
|
*/
|
||||||
|
void removeSelectedEditors();
|
||||||
|
/**
|
||||||
|
* Sets the selected entries with the provided information.
|
||||||
|
*/
|
||||||
|
void setApp(const Glib::RefPtr<Gio::AppInfo> app_info);
|
||||||
|
/**
|
||||||
|
* Updates the application command and removes the icon for the given row.
|
||||||
|
*/
|
||||||
|
void setAppCommand(const Glib::ustring & path, const Glib::ustring & new_text);
|
||||||
|
/**
|
||||||
|
* Updates the application name for the given row.
|
||||||
|
*/
|
||||||
|
void setAppName(const Glib::ustring & path, const Glib::ustring & new_text);
|
||||||
|
/**
|
||||||
|
* Sets the sensitivity of the widgets in the toolbar to reflect the current
|
||||||
|
* state of the list. For example, makes the remove button insensitive if no
|
||||||
|
* entries are selected.
|
||||||
|
*/
|
||||||
|
void updateToolbarSensitivity();
|
||||||
|
};
|
@ -339,3 +339,16 @@ bool ExtProgStore::openInCustomEditor (const Glib::ustring& fileName)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ExtProgStore::openInExternalEditor(const Glib::ustring &fileName, const Glib::RefPtr<Gio::AppInfo> &editorInfo)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
return editorInfo->launch(Gio::File::create_for_path(fileName));
|
||||||
|
} catch (const Glib::Error &e) {
|
||||||
|
std::cerr
|
||||||
|
<< "Error launching external editor.\n"
|
||||||
|
<< "Error code #" << e.code() << ": " << e.what()
|
||||||
|
<< std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -20,10 +20,16 @@
|
|||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <glibmm/refptr.h>
|
||||||
#include <glibmm/ustring.h>
|
#include <glibmm/ustring.h>
|
||||||
|
|
||||||
#include "threadutils.h"
|
#include "threadutils.h"
|
||||||
|
|
||||||
|
namespace Gio
|
||||||
|
{
|
||||||
|
class AppInfo;
|
||||||
|
}
|
||||||
|
|
||||||
struct ExtProgAction
|
struct ExtProgAction
|
||||||
{
|
{
|
||||||
Glib::ustring filePathEXE;
|
Glib::ustring filePathEXE;
|
||||||
@ -64,6 +70,7 @@ public:
|
|||||||
static bool openInGimp (const Glib::ustring& fileName);
|
static bool openInGimp (const Glib::ustring& fileName);
|
||||||
static bool openInPhotoshop (const Glib::ustring& fileName);
|
static bool openInPhotoshop (const Glib::ustring& fileName);
|
||||||
static bool openInCustomEditor (const Glib::ustring& fileName);
|
static bool openInCustomEditor (const Glib::ustring& fileName);
|
||||||
|
static bool openInExternalEditor(const Glib::ustring &fileName, const Glib::RefPtr<Gio::AppInfo> &editorInfo);
|
||||||
};
|
};
|
||||||
|
|
||||||
#define extProgStore ExtProgStore::getInstance()
|
#define extProgStore ExtProgStore::getInstance()
|
||||||
|
@ -1507,13 +1507,28 @@ TextOrIcon::TextOrIcon (const Glib::ustring &fname, const Glib::ustring &labelTx
|
|||||||
}
|
}
|
||||||
|
|
||||||
MyImageMenuItem::MyImageMenuItem(Glib::ustring label, Glib::ustring imageFileName)
|
MyImageMenuItem::MyImageMenuItem(Glib::ustring label, Glib::ustring imageFileName)
|
||||||
|
{
|
||||||
|
RTImage* itemImage = nullptr;
|
||||||
|
|
||||||
|
if (!imageFileName.empty()) {
|
||||||
|
itemImage = Gtk::manage(new RTImage(imageFileName));
|
||||||
|
}
|
||||||
|
|
||||||
|
construct(label, itemImage);
|
||||||
|
}
|
||||||
|
|
||||||
|
MyImageMenuItem::MyImageMenuItem(Glib::ustring label, RTImage* itemImage) {
|
||||||
|
construct(label, itemImage);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MyImageMenuItem::construct(Glib::ustring label, RTImage* itemImage)
|
||||||
{
|
{
|
||||||
box = Gtk::manage (new Gtk::Grid());
|
box = Gtk::manage (new Gtk::Grid());
|
||||||
this->label = Gtk::manage( new Gtk::Label(label));
|
this->label = Gtk::manage( new Gtk::Label(label));
|
||||||
box->set_orientation(Gtk::ORIENTATION_HORIZONTAL);
|
box->set_orientation(Gtk::ORIENTATION_HORIZONTAL);
|
||||||
|
|
||||||
if (!imageFileName.empty()) {
|
if (itemImage) {
|
||||||
image = Gtk::manage( new RTImage(imageFileName) );
|
image = itemImage;
|
||||||
box->attach_next_to(*image, Gtk::POS_LEFT, 1, 1);
|
box->attach_next_to(*image, Gtk::POS_LEFT, 1, 1);
|
||||||
} else {
|
} else {
|
||||||
image = nullptr;
|
image = nullptr;
|
||||||
|
@ -489,8 +489,11 @@ private:
|
|||||||
RTImage *image;
|
RTImage *image;
|
||||||
Gtk::Label *label;
|
Gtk::Label *label;
|
||||||
|
|
||||||
|
void construct(Glib::ustring label, RTImage* image);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MyImageMenuItem (Glib::ustring label, Glib::ustring imageFileName);
|
MyImageMenuItem (Glib::ustring label, Glib::ustring imageFileName);
|
||||||
|
MyImageMenuItem (Glib::ustring label, RTImage* image);
|
||||||
const RTImage *getImage () const;
|
const RTImage *getImage () const;
|
||||||
const Gtk::Label* getLabel () const;
|
const Gtk::Label* getLabel () const;
|
||||||
};
|
};
|
||||||
|
188
rtgui/options.cc
188
rtgui/options.cc
@ -412,6 +412,8 @@ void Options::setDefaults()
|
|||||||
gimpDir = "";
|
gimpDir = "";
|
||||||
psDir = "";
|
psDir = "";
|
||||||
customEditorProg = "";
|
customEditorProg = "";
|
||||||
|
externalEditors.clear();
|
||||||
|
externalEditorIndex = -1;
|
||||||
CPBKeys = CPBKT_TID;
|
CPBKeys = CPBKT_TID;
|
||||||
editorToSendTo = 1;
|
editorToSendTo = 1;
|
||||||
editor_out_dir = EDITOR_OUT_DIR_TEMP;
|
editor_out_dir = EDITOR_OUT_DIR_TEMP;
|
||||||
@ -821,6 +823,7 @@ void Options::readFromFile(Glib::ustring fname)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Remove.
|
||||||
if (keyFile.has_group("External Editor")) {
|
if (keyFile.has_group("External Editor")) {
|
||||||
if (keyFile.has_key("External Editor", "EditorKind")) {
|
if (keyFile.has_key("External Editor", "EditorKind")) {
|
||||||
editorToSendTo = keyFile.get_integer("External Editor", "EditorKind");
|
editorToSendTo = keyFile.get_integer("External Editor", "EditorKind");
|
||||||
@ -861,6 +864,156 @@ void Options::readFromFile(Glib::ustring fname)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (keyFile.has_group("External Editor")) {
|
||||||
|
if (keyFile.has_key("External Editor", "Names")
|
||||||
|
|| keyFile.has_key("External Editor", "Commands")
|
||||||
|
|| keyFile.has_key("External Editor", "IconsSerialized")) {
|
||||||
|
// Multiple external editors.
|
||||||
|
|
||||||
|
const auto & names =
|
||||||
|
!keyFile.has_key("External Editor", "Names") ?
|
||||||
|
std::vector<Glib::ustring>() :
|
||||||
|
static_cast<std::vector<Glib::ustring>>(
|
||||||
|
keyFile.get_string_list("External Editor", "Names"));
|
||||||
|
const auto & commands =
|
||||||
|
!keyFile.has_key("External Editor", "Commands") ?
|
||||||
|
std::vector<Glib::ustring>() :
|
||||||
|
static_cast<std::vector<Glib::ustring>>(
|
||||||
|
keyFile.get_string_list("External Editor", "Commands"));
|
||||||
|
const auto & icons_serialized =
|
||||||
|
!keyFile.has_key("External Editor", "IconsSerialized") ?
|
||||||
|
std::vector<Glib::ustring>() :
|
||||||
|
static_cast<std::vector<Glib::ustring>>(
|
||||||
|
keyFile.get_string_list("External Editor", "IconsSerialized"));
|
||||||
|
externalEditors = std::vector<ExternalEditor>(std::max(std::max(
|
||||||
|
names.size(), commands.size()), icons_serialized.size()));
|
||||||
|
for (unsigned i = 0; i < names.size(); i++) {
|
||||||
|
externalEditors[i].name = names[i];
|
||||||
|
}
|
||||||
|
for (unsigned i = 0; i < commands.size(); i++) {
|
||||||
|
externalEditors[i].command = commands[i];
|
||||||
|
}
|
||||||
|
for (unsigned i = 0; i < icons_serialized.size(); i++) {
|
||||||
|
externalEditors[i].icon_serialized = icons_serialized[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyFile.has_key("External Editor", "EditorIndex")) {
|
||||||
|
int index = keyFile.get_integer("External Editor", "EditorIndex");
|
||||||
|
externalEditorIndex = std::min(
|
||||||
|
std::max(-1, index),
|
||||||
|
static_cast<int>(externalEditors.size())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else if (keyFile.has_key("External Editor", "EditorKind")) {
|
||||||
|
// Legacy fixed external editors. Convert to flexible.
|
||||||
|
|
||||||
|
// GIMP == 1, Photoshop == 2, Custom == 3.
|
||||||
|
editorToSendTo = keyFile.get_integer("External Editor", "EditorKind");
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
auto getIconSerialized = [](const Glib::ustring &executable) {
|
||||||
|
// Backslashes and quotes must be escaped in the text representation of GVariant strings.
|
||||||
|
// See https://www.freedesktop.org/software/gstreamer-sdk/data/docs/2012.5/glib/gvariant-text.html#gvariant-text-strings
|
||||||
|
Glib::ustring exec_escaped = "";
|
||||||
|
for (const auto character : executable) {
|
||||||
|
if (character == '\\' || character == '\'') {
|
||||||
|
exec_escaped += '\\';
|
||||||
|
}
|
||||||
|
exec_escaped += character;
|
||||||
|
}
|
||||||
|
return Glib::ustring::compose("('themed', <['%1,0', '%1,0-symbolic']>)", exec_escaped);
|
||||||
|
};
|
||||||
|
Glib::ustring gimpDir = "";
|
||||||
|
if (keyFile.has_key("External Editor", "GimpDir")) {
|
||||||
|
gimpDir = keyFile.get_string("External Editor", "GimpDir");
|
||||||
|
}
|
||||||
|
auto executable = Glib::build_filename(options.gimpDir, "bin", "gimp-win-remote");
|
||||||
|
if (Glib::file_test(executable, Glib::FILE_TEST_IS_EXECUTABLE)) {
|
||||||
|
if (editorToSendTo == 1) {
|
||||||
|
externalEditorIndex = externalEditors.size();
|
||||||
|
}
|
||||||
|
externalEditors.push_back(ExternalEditor("GIMP", "\"" + executable + "\"", getIconSerialized(executable)));
|
||||||
|
} else {
|
||||||
|
for (auto ver = 12; ver >= 0; --ver) {
|
||||||
|
executable = Glib::build_filename(gimpDir, "bin", Glib::ustring::compose(Glib::ustring("gimp-2.%1.exe"), ver));
|
||||||
|
if (Glib::file_test(executable, Glib::FILE_TEST_IS_EXECUTABLE)) {
|
||||||
|
if (editorToSendTo == 1) {
|
||||||
|
externalEditorIndex = externalEditors.size();
|
||||||
|
}
|
||||||
|
externalEditors.push_back(ExternalEditor("GIMP", "\"" + executable + "\"", getIconSerialized(executable)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Glib::ustring psDir = "";
|
||||||
|
if (keyFile.has_key("External Editor", "PhotoshopDir")) {
|
||||||
|
psDir = keyFile.get_string("External Editor", "PhotoshopDir");
|
||||||
|
}
|
||||||
|
executable = Glib::build_filename(psDir, "Photoshop.exe");
|
||||||
|
if (Glib::file_test(executable, Glib::FILE_TEST_IS_EXECUTABLE)) {
|
||||||
|
if (editorToSendTo == 2) {
|
||||||
|
externalEditorIndex = externalEditors.size();
|
||||||
|
}
|
||||||
|
externalEditors.push_back(ExternalEditor("Photoshop", "\"" + executable + "\"", getIconSerialized(executable)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyFile.has_key("External Editor", "CustomEditor")) {
|
||||||
|
executable = keyFile.get_string("External Editor", "CustomEditor");
|
||||||
|
if (!executable.empty()) {
|
||||||
|
if (editorToSendTo == 3) {
|
||||||
|
externalEditorIndex = externalEditors.size();
|
||||||
|
}
|
||||||
|
externalEditors.push_back(ExternalEditor("-", "\"" + executable + "\"", ""));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#elif defined __APPLE__
|
||||||
|
if (editorToSendTo == 1) {
|
||||||
|
externalEditorIndex = externalEditors.size();
|
||||||
|
}
|
||||||
|
externalEditors.push_back(ExternalEditor("GIMP", "open -a GIMP", "gimp"));
|
||||||
|
externalEditors.push_back(ExternalEditor("GIMP-dev", "open -a GIMP-dev", "gimp"));
|
||||||
|
|
||||||
|
if (editorToSendTo == 2) {
|
||||||
|
externalEditorIndex = externalEditors.size();
|
||||||
|
}
|
||||||
|
externalEditors.push_back(ExternalEditor("Photoshop", "open -a Photoshop", ""));
|
||||||
|
|
||||||
|
if (keyFile.has_key("External Editor", "CustomEditor")) {
|
||||||
|
auto executable = keyFile.get_string("External Editor", "CustomEditor");
|
||||||
|
if (!executable.empty()) {
|
||||||
|
if (editorToSendTo == 3) {
|
||||||
|
externalEditorIndex = externalEditors.size();
|
||||||
|
}
|
||||||
|
externalEditors.push_back(ExternalEditor("-", executable, ""));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (Glib::find_program_in_path("gimp").compare("")) {
|
||||||
|
if (editorToSendTo == 1) {
|
||||||
|
externalEditorIndex = externalEditors.size();
|
||||||
|
}
|
||||||
|
externalEditors.push_back(ExternalEditor("GIMP", "gimp", "gimp"));
|
||||||
|
} else if (Glib::find_program_in_path("gimp-remote").compare("")) {
|
||||||
|
if (editorToSendTo == 1) {
|
||||||
|
externalEditorIndex = externalEditors.size();
|
||||||
|
}
|
||||||
|
externalEditors.push_back(ExternalEditor("GIMP", "gimp-remote", "gimp"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyFile.has_key("External Editor", "CustomEditor")) {
|
||||||
|
auto executable = keyFile.get_string("External Editor", "CustomEditor");
|
||||||
|
if (!executable.empty()) {
|
||||||
|
if (editorToSendTo == 3) {
|
||||||
|
externalEditorIndex = externalEditors.size();
|
||||||
|
}
|
||||||
|
externalEditors.push_back(ExternalEditor("-", executable, ""));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (keyFile.has_group("Output")) {
|
if (keyFile.has_group("Output")) {
|
||||||
if (keyFile.has_key("Output", "Format")) {
|
if (keyFile.has_key("Output", "Format")) {
|
||||||
saveFormat.format = keyFile.get_string("Output", "Format");
|
saveFormat.format = keyFile.get_string("Output", "Format");
|
||||||
@ -2175,6 +2328,7 @@ void Options::saveToFile(Glib::ustring fname)
|
|||||||
keyFile.set_boolean("General", "Detectshape", rtSettings.detectshape);
|
keyFile.set_boolean("General", "Detectshape", rtSettings.detectshape);
|
||||||
keyFile.set_boolean("General", "Fftwsigma", rtSettings.fftwsigma);
|
keyFile.set_boolean("General", "Fftwsigma", rtSettings.fftwsigma);
|
||||||
|
|
||||||
|
// TODO: Remove.
|
||||||
keyFile.set_integer("External Editor", "EditorKind", editorToSendTo);
|
keyFile.set_integer("External Editor", "EditorKind", editorToSendTo);
|
||||||
keyFile.set_string("External Editor", "GimpDir", gimpDir);
|
keyFile.set_string("External Editor", "GimpDir", gimpDir);
|
||||||
keyFile.set_string("External Editor", "PhotoshopDir", psDir);
|
keyFile.set_string("External Editor", "PhotoshopDir", psDir);
|
||||||
@ -2184,6 +2338,24 @@ void Options::saveToFile(Glib::ustring fname)
|
|||||||
keyFile.set_boolean("External Editor", "Float32", editor_float32);
|
keyFile.set_boolean("External Editor", "Float32", editor_float32);
|
||||||
keyFile.set_boolean("External Editor", "BypassOutputProfile", editor_bypass_output_profile);
|
keyFile.set_boolean("External Editor", "BypassOutputProfile", editor_bypass_output_profile);
|
||||||
|
|
||||||
|
{
|
||||||
|
std::vector<Glib::ustring> names;
|
||||||
|
std::vector<Glib::ustring> commands;
|
||||||
|
std::vector<Glib::ustring> icons_serialized;
|
||||||
|
|
||||||
|
for (const auto & editor : externalEditors) {
|
||||||
|
names.push_back(editor.name);
|
||||||
|
commands.push_back(editor.command);
|
||||||
|
icons_serialized.push_back(editor.icon_serialized);
|
||||||
|
}
|
||||||
|
|
||||||
|
keyFile.set_string_list("External Editor", "Names", names);
|
||||||
|
keyFile.set_string_list("External Editor", "Commands", commands);
|
||||||
|
keyFile.set_string_list("External Editor", "IconsSerialized", icons_serialized);
|
||||||
|
|
||||||
|
keyFile.set_integer("External Editor", "EditorIndex", externalEditorIndex);
|
||||||
|
}
|
||||||
|
|
||||||
keyFile.set_boolean("File Browser", "BrowseOnlyRaw", fbOnlyRaw);
|
keyFile.set_boolean("File Browser", "BrowseOnlyRaw", fbOnlyRaw);
|
||||||
keyFile.set_boolean("File Browser", "BrowserShowsDate", fbShowDateTime);
|
keyFile.set_boolean("File Browser", "BrowserShowsDate", fbShowDateTime);
|
||||||
keyFile.set_boolean("File Browser", "BrowserShowsExif", fbShowBasicExif);
|
keyFile.set_boolean("File Browser", "BrowserShowsExif", fbShowBasicExif);
|
||||||
@ -2853,3 +3025,19 @@ Glib::ustring Options::getICCProfileCopyright()
|
|||||||
now.set_time_current();
|
now.set_time_current();
|
||||||
return Glib::ustring::compose("Copyright RawTherapee %1, CC0", now.get_year());
|
return Glib::ustring::compose("Copyright RawTherapee %1, CC0", now.get_year());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ExternalEditor::ExternalEditor() {}
|
||||||
|
|
||||||
|
ExternalEditor::ExternalEditor(
|
||||||
|
const Glib::ustring &name, const Glib::ustring &command, const Glib::ustring &icon_serialized
|
||||||
|
): name(name), command(command), icon_serialized(icon_serialized) {}
|
||||||
|
|
||||||
|
bool ExternalEditor::operator==(const ExternalEditor &other) const
|
||||||
|
{
|
||||||
|
return this->name == other.name && this->command == other.command && this->icon_serialized == other.icon_serialized;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ExternalEditor::operator!=(const ExternalEditor &other) const
|
||||||
|
{
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
@ -52,6 +52,17 @@
|
|||||||
// Special name for the Dynamic profile
|
// Special name for the Dynamic profile
|
||||||
#define DEFPROFILE_DYNAMIC "Dynamic"
|
#define DEFPROFILE_DYNAMIC "Dynamic"
|
||||||
|
|
||||||
|
struct ExternalEditor {
|
||||||
|
ExternalEditor();
|
||||||
|
ExternalEditor(const Glib::ustring &name, const Glib::ustring &command, const Glib::ustring &icon_serialized);
|
||||||
|
Glib::ustring name;
|
||||||
|
Glib::ustring command;
|
||||||
|
Glib::ustring icon_serialized;
|
||||||
|
|
||||||
|
bool operator==(const ExternalEditor & other) const;
|
||||||
|
bool operator!=(const ExternalEditor & other) const;
|
||||||
|
};
|
||||||
|
|
||||||
struct SaveFormat {
|
struct SaveFormat {
|
||||||
SaveFormat(
|
SaveFormat(
|
||||||
const Glib::ustring& _format,
|
const Glib::ustring& _format,
|
||||||
@ -276,6 +287,8 @@ public:
|
|||||||
Glib::ustring gimpDir;
|
Glib::ustring gimpDir;
|
||||||
Glib::ustring psDir;
|
Glib::ustring psDir;
|
||||||
Glib::ustring customEditorProg;
|
Glib::ustring customEditorProg;
|
||||||
|
std::vector<ExternalEditor> externalEditors;
|
||||||
|
int externalEditorIndex;
|
||||||
Glib::ustring CPBPath; // Custom Profile Builder's path
|
Glib::ustring CPBPath; // Custom Profile Builder's path
|
||||||
CPBKeyType CPBKeys; // Custom Profile Builder's key type
|
CPBKeyType CPBKeys; // Custom Profile Builder's key type
|
||||||
int editorToSendTo;
|
int editorToSendTo;
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
PopUpCommon::PopUpCommon (Gtk::Button* thisButton, const Glib::ustring& label)
|
PopUpCommon::PopUpCommon (Gtk::Button* thisButton, const Glib::ustring& label)
|
||||||
: buttonImage (nullptr)
|
: buttonImage (nullptr)
|
||||||
, menu (nullptr)
|
, menu(new Gtk::Menu())
|
||||||
, selected (-1) // -1 means that the button is invalid
|
, selected (-1) // -1 means that the button is invalid
|
||||||
{
|
{
|
||||||
button = thisButton;
|
button = thisButton;
|
||||||
@ -48,59 +48,148 @@ PopUpCommon::PopUpCommon (Gtk::Button* thisButton, const Glib::ustring& label)
|
|||||||
setExpandAlignProperties(buttonGroup, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER);
|
setExpandAlignProperties(buttonGroup, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER);
|
||||||
buttonGroup->attach(*button, 0, 0, 1, 1);
|
buttonGroup->attach(*button, 0, 0, 1, 1);
|
||||||
buttonGroup->get_style_context()->add_class("image-combo");
|
buttonGroup->get_style_context()->add_class("image-combo");
|
||||||
|
|
||||||
|
// Create the image for the button
|
||||||
|
buttonImage = Gtk::manage(new RTImage());
|
||||||
|
setExpandAlignProperties(buttonImage, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER);
|
||||||
|
imageContainer->attach_next_to(*buttonImage, Gtk::POS_RIGHT, 1, 1);
|
||||||
|
buttonImage->set_no_show_all();
|
||||||
|
|
||||||
|
// Create the button for showing the pop-up.
|
||||||
|
arrowButton = Gtk::manage(new Gtk::Button());
|
||||||
|
Gtk::Image *arrowImage = Gtk::manage(new Gtk::Image());
|
||||||
|
arrowImage->set_from_icon_name("pan-down-symbolic", Gtk::ICON_SIZE_BUTTON);
|
||||||
|
setExpandAlignProperties(arrowButton, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_FILL);
|
||||||
|
arrowButton->add(*arrowImage); //menuSymbol);
|
||||||
|
arrowImage->show();
|
||||||
|
buttonGroup->attach_next_to(*arrowButton, *button, Gtk::POS_RIGHT, 1, 1);
|
||||||
|
arrowButton->signal_button_release_event().connect_notify(sigc::mem_fun(*this, &PopUpCommon::showMenu));
|
||||||
|
arrowButton->get_style_context()->add_class("Right");
|
||||||
|
arrowButton->get_style_context()->add_class("popupbutton-arrow");
|
||||||
|
arrowButton->set_no_show_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
PopUpCommon::~PopUpCommon ()
|
PopUpCommon::~PopUpCommon ()
|
||||||
{
|
{
|
||||||
delete menu;
|
|
||||||
delete buttonImage;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PopUpCommon::addEntry (const Glib::ustring& fileName, const Glib::ustring& label)
|
bool PopUpCommon::addEntry (const Glib::ustring& fileName, const Glib::ustring& label)
|
||||||
{
|
{
|
||||||
if (label.empty ())
|
return insertEntry(getEntryCount(), fileName, label);
|
||||||
return false;
|
}
|
||||||
|
|
||||||
|
bool PopUpCommon::insertEntry(int position, const Glib::ustring& fileName, const Glib::ustring& label)
|
||||||
|
{
|
||||||
|
RTImage* image = nullptr;
|
||||||
|
if (!fileName.empty()) {
|
||||||
|
image = Gtk::manage(new RTImage(fileName));
|
||||||
|
}
|
||||||
|
bool success = insertEntryImpl(position, fileName, Glib::RefPtr<const Gio::Icon>(), image, label);
|
||||||
|
if (!success && image) {
|
||||||
|
delete image;
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PopUpCommon::insertEntry(int position, const Glib::RefPtr<const Gio::Icon>& gIcon, const Glib::ustring& label)
|
||||||
|
{
|
||||||
|
RTImage* image = Gtk::manage(new RTImage(gIcon, Gtk::ICON_SIZE_BUTTON));
|
||||||
|
bool success = insertEntryImpl(position, "", gIcon, image, label);
|
||||||
|
if (!success) {
|
||||||
|
delete image;
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PopUpCommon::insertEntryImpl(int position, const Glib::ustring& fileName, const Glib::RefPtr<const Gio::Icon>& gIcon, RTImage* image, const Glib::ustring& label)
|
||||||
|
{
|
||||||
|
if (label.empty() || position < 0 || position > getEntryCount())
|
||||||
|
return false;
|
||||||
|
|
||||||
// Create the menu item and image
|
// Create the menu item and image
|
||||||
MyImageMenuItem* newItem = Gtk::manage (new MyImageMenuItem (label, fileName));
|
MyImageMenuItem *newItem = Gtk::manage(new MyImageMenuItem(label, image));
|
||||||
imageFilenames.push_back (fileName);
|
imageIcons.insert(imageIcons.begin() + position, gIcon);
|
||||||
images.push_back (newItem->getImage ());
|
imageFilenames.insert(imageFilenames.begin() + position, fileName);
|
||||||
|
images.insert(images.begin() + position, newItem->getImage());
|
||||||
if (selected == -1) {
|
|
||||||
// Create the menu on the first item
|
|
||||||
menu = new Gtk::Menu ();
|
|
||||||
// Create the image for the button
|
|
||||||
buttonImage = new RTImage(fileName);
|
|
||||||
setExpandAlignProperties(buttonImage, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER);
|
|
||||||
// Use the first image by default
|
|
||||||
imageContainer->attach_next_to(*buttonImage, Gtk::POS_RIGHT, 1, 1);
|
|
||||||
selected = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// When there is at least 1 choice, we add the arrow button
|
// When there is at least 1 choice, we add the arrow button
|
||||||
if (images.size() == 1) {
|
if (images.size() == 1) {
|
||||||
Gtk::Button* arrowButton = Gtk::manage( new Gtk::Button() );
|
changeImage(fileName, gIcon);
|
||||||
Gtk::Image *arrowImage = Gtk::manage(new Gtk::Image());
|
buttonImage->show();
|
||||||
arrowImage->set_from_icon_name("pan-down-symbolic", Gtk::ICON_SIZE_BUTTON);
|
selected = 0;
|
||||||
setExpandAlignProperties(arrowButton, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_FILL);
|
|
||||||
arrowButton->add(*arrowImage); //menuSymbol);
|
|
||||||
buttonGroup->attach_next_to(*arrowButton, *button, Gtk::POS_RIGHT, 1, 1);
|
|
||||||
arrowButton->signal_button_release_event().connect_notify( sigc::mem_fun(*this, &PopUpCommon::showMenu) );
|
|
||||||
button->get_style_context()->add_class("Left");
|
button->get_style_context()->add_class("Left");
|
||||||
arrowButton->get_style_context()->add_class("Right");
|
arrowButton->show();
|
||||||
arrowButton->get_style_context()->add_class("popupbutton-arrow");
|
|
||||||
hasMenu = true;
|
hasMenu = true;
|
||||||
|
} else if (position <= selected) {
|
||||||
|
selected++;
|
||||||
}
|
}
|
||||||
|
|
||||||
newItem->signal_activate ().connect (sigc::bind (sigc::mem_fun (*this, &PopUpCommon::entrySelected), images.size () - 1));
|
void (PopUpCommon::*entrySelectedFunc)(Gtk::Widget *) = &PopUpCommon::entrySelected;
|
||||||
menu->append (*newItem);
|
newItem->signal_activate ().connect (sigc::bind (sigc::mem_fun (*this, entrySelectedFunc), newItem));
|
||||||
|
menu->insert(*newItem, position);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: 'PopUpCommon::removeEntry' method to be created...
|
void PopUpCommon::removeEntry(int position)
|
||||||
|
{
|
||||||
|
if (position < 0 || position >= getEntryCount()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
void PopUpCommon::entrySelected (int i)
|
if (getEntryCount() == 1) { // Last of the entries.
|
||||||
|
// Hide the arrow button.
|
||||||
|
button->get_style_context()->remove_class("Left");
|
||||||
|
arrowButton->hide();
|
||||||
|
hasMenu = false;
|
||||||
|
// Remove the button image.
|
||||||
|
buttonImage->hide();
|
||||||
|
selected = -1;
|
||||||
|
}
|
||||||
|
else if (position < selected) {
|
||||||
|
selected--;
|
||||||
|
}
|
||||||
|
else if (position == selected) { // Select a different entry before removing.
|
||||||
|
int nextSelection = position + (position == getEntryCount() - 1 ? -1 : 1);
|
||||||
|
changeImage(nextSelection);
|
||||||
|
setButtonHint();
|
||||||
|
}
|
||||||
|
|
||||||
|
MyImageMenuItem *menuItem = dynamic_cast<MyImageMenuItem *>(menu->get_children()[position]);
|
||||||
|
menu->remove(*menuItem);
|
||||||
|
delete menuItem;
|
||||||
|
imageIcons.erase(imageIcons.begin() + position);
|
||||||
|
imageFilenames.erase(imageFilenames.begin() + position);
|
||||||
|
images.erase(images.begin() + position);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PopUpCommon::changeImage(int position)
|
||||||
|
{
|
||||||
|
changeImage(imageFilenames.at(position), imageIcons.at(position));
|
||||||
|
}
|
||||||
|
|
||||||
|
void PopUpCommon::changeImage(const Glib::ustring& fileName, const Glib::RefPtr<const Gio::Icon>& gIcon)
|
||||||
|
{
|
||||||
|
if (!fileName.empty()) {
|
||||||
|
buttonImage->changeImage(fileName);
|
||||||
|
} else {
|
||||||
|
buttonImage->changeImage(gIcon, static_cast<Gtk::IconSize>(Gtk::ICON_SIZE_BUTTON));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PopUpCommon::entrySelected(Gtk::Widget* widget)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
for (const auto & child : menu->get_children()) {
|
||||||
|
if (widget == child) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
entrySelected(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PopUpCommon::entrySelected(int i)
|
||||||
{
|
{
|
||||||
// Emit a signal if the selected item has changed
|
// Emit a signal if the selected item has changed
|
||||||
if (setSelected (posToIndex(i)))
|
if (setSelected (posToIndex(i)))
|
||||||
@ -130,7 +219,7 @@ bool PopUpCommon::setSelected (int entryNum)
|
|||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
// Maybe we could do something better than loading the image file each time the selection is changed !?
|
// Maybe we could do something better than loading the image file each time the selection is changed !?
|
||||||
buttonImage->changeImage(imageFilenames.at(entryNum));
|
changeImage(entryNum);
|
||||||
selected = entryNum;
|
selected = entryNum;
|
||||||
setButtonHint();
|
setButtonHint();
|
||||||
return true;
|
return true;
|
||||||
@ -162,7 +251,7 @@ void PopUpCommon::setButtonHint()
|
|||||||
auto item = dynamic_cast<MyImageMenuItem*>(widget);
|
auto item = dynamic_cast<MyImageMenuItem*>(widget);
|
||||||
|
|
||||||
if (item) {
|
if (item) {
|
||||||
hint += item->getLabel ()->get_text ();
|
hint += escapeHtmlChars(item->getLabel()->get_text());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,12 +20,19 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "glibmm/refptr.h"
|
||||||
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <glibmm/ustring.h>
|
#include <glibmm/ustring.h>
|
||||||
|
|
||||||
#include <sigc++/signal.h>
|
#include <sigc++/signal.h>
|
||||||
|
|
||||||
|
namespace Gio
|
||||||
|
{
|
||||||
|
class Icon;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Gtk
|
namespace Gtk
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -33,6 +40,7 @@ class Grid;
|
|||||||
class Menu;
|
class Menu;
|
||||||
class Button;
|
class Button;
|
||||||
class ImageMenuItem;
|
class ImageMenuItem;
|
||||||
|
class Widget;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,9 +61,12 @@ public:
|
|||||||
explicit PopUpCommon (Gtk::Button* button, const Glib::ustring& label = "");
|
explicit PopUpCommon (Gtk::Button* button, const Glib::ustring& label = "");
|
||||||
virtual ~PopUpCommon ();
|
virtual ~PopUpCommon ();
|
||||||
bool addEntry (const Glib::ustring& fileName, const Glib::ustring& label);
|
bool addEntry (const Glib::ustring& fileName, const Glib::ustring& label);
|
||||||
|
bool insertEntry(int position, const Glib::ustring& fileName, const Glib::ustring& label);
|
||||||
|
bool insertEntry(int position, const Glib::RefPtr<const Gio::Icon>& gIcon, const Glib::ustring& label);
|
||||||
int getEntryCount () const;
|
int getEntryCount () const;
|
||||||
bool setSelected (int entryNum);
|
bool setSelected (int entryNum);
|
||||||
int getSelected () const;
|
int getSelected () const;
|
||||||
|
void removeEntry(int position);
|
||||||
void setButtonHint();
|
void setButtonHint();
|
||||||
void show ();
|
void show ();
|
||||||
void set_tooltip_text (const Glib::ustring &text);
|
void set_tooltip_text (const Glib::ustring &text);
|
||||||
@ -65,16 +76,22 @@ private:
|
|||||||
type_signal_changed messageChanged;
|
type_signal_changed messageChanged;
|
||||||
type_signal_item_selected messageItemSelected;
|
type_signal_item_selected messageItemSelected;
|
||||||
|
|
||||||
|
std::vector<Glib::RefPtr<const Gio::Icon>> imageIcons;
|
||||||
std::vector<Glib::ustring> imageFilenames;
|
std::vector<Glib::ustring> imageFilenames;
|
||||||
std::vector<const RTImage*> images;
|
std::vector<const RTImage*> images;
|
||||||
Glib::ustring buttonHint;
|
Glib::ustring buttonHint;
|
||||||
RTImage* buttonImage;
|
RTImage* buttonImage;
|
||||||
Gtk::Grid* imageContainer;
|
Gtk::Grid* imageContainer;
|
||||||
Gtk::Menu* menu;
|
std::unique_ptr<Gtk::Menu> menu;
|
||||||
Gtk::Button* button;
|
Gtk::Button* button;
|
||||||
|
Gtk::Button* arrowButton;
|
||||||
int selected;
|
int selected;
|
||||||
bool hasMenu;
|
bool hasMenu;
|
||||||
|
|
||||||
|
void changeImage(int position);
|
||||||
|
void changeImage(const Glib::ustring& fileName, const Glib::RefPtr<const Gio::Icon>& gIcon);
|
||||||
|
void entrySelected(Gtk::Widget* menuItem);
|
||||||
|
bool insertEntryImpl(int position, const Glib::ustring& fileName, const Glib::RefPtr<const Gio::Icon>& gIcon, RTImage* image, const Glib::ustring& label);
|
||||||
void showMenu(GdkEventButton* event);
|
void showMenu(GdkEventButton* event);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
* along with RawTherapee. If not, see <https://www.gnu.org/licenses/>.
|
* along with RawTherapee. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#include <sigc++/slot.h>
|
#include <sigc++/slot.h>
|
||||||
|
#include "externaleditorpreferences.h"
|
||||||
#include "preferences.h"
|
#include "preferences.h"
|
||||||
#include "multilangmgr.h"
|
#include "multilangmgr.h"
|
||||||
#include "splash.h"
|
#include "splash.h"
|
||||||
@ -1202,68 +1203,16 @@ Gtk::Widget* Preferences::getGeneralPanel()
|
|||||||
|
|
||||||
Gtk::Frame* fdg = Gtk::manage(new Gtk::Frame(M("PREFERENCES_EXTERNALEDITOR")));
|
Gtk::Frame* fdg = Gtk::manage(new Gtk::Frame(M("PREFERENCES_EXTERNALEDITOR")));
|
||||||
setExpandAlignProperties(fdg, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL);
|
setExpandAlignProperties(fdg, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL);
|
||||||
Gtk::Grid* externaleditorGrid = Gtk::manage(new Gtk::Grid());
|
|
||||||
externaleditorGrid->set_column_spacing(4);
|
|
||||||
externaleditorGrid->set_row_spacing(4);
|
|
||||||
setExpandAlignProperties(externaleditorGrid, false, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL);
|
|
||||||
|
|
||||||
edOther = Gtk::manage(new Gtk::RadioButton(M("PREFERENCES_EDITORCMDLINE") + ":"));
|
|
||||||
setExpandAlignProperties(edOther, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER);
|
|
||||||
editorToSendTo = Gtk::manage(new Gtk::Entry());
|
|
||||||
setExpandAlignProperties(editorToSendTo, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_BASELINE);
|
|
||||||
Gtk::RadioButton::Group ge = edOther->get_group();
|
|
||||||
|
|
||||||
#ifdef __APPLE__
|
|
||||||
edGimp = Gtk::manage(new Gtk::RadioButton("GIMP"));
|
|
||||||
setExpandAlignProperties(edGimp, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER);
|
|
||||||
edGimp->set_group(ge);
|
|
||||||
externaleditorGrid->attach_next_to(*edGimp, Gtk::POS_TOP, 2, 1);
|
|
||||||
|
|
||||||
edPS = Gtk::manage(new Gtk::RadioButton(M("PREFERENCES_PSPATH") + ":"));
|
|
||||||
setExpandAlignProperties(edPS, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER);
|
|
||||||
psDir = Gtk::manage(new MyFileChooserButton(M("PREFERENCES_PSPATH"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER));
|
|
||||||
setExpandAlignProperties(psDir, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER);
|
|
||||||
externaleditorGrid->attach_next_to(*edPS, *edGimp, Gtk::POS_BOTTOM, 1, 1);
|
|
||||||
externaleditorGrid->attach_next_to(*psDir, *edPS, Gtk::POS_RIGHT, 1, 1);
|
|
||||||
edPS->set_group(ge);
|
|
||||||
|
|
||||||
externaleditorGrid->attach_next_to(*edOther, *edPS, Gtk::POS_BOTTOM, 1, 1);
|
|
||||||
externaleditorGrid->attach_next_to(*editorToSendTo, *edOther, Gtk::POS_RIGHT, 1, 1);
|
|
||||||
#elif defined WIN32
|
|
||||||
edGimp = Gtk::manage(new Gtk::RadioButton(M("PREFERENCES_GIMPPATH") + ":"));
|
|
||||||
setExpandAlignProperties(edGimp, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER);
|
|
||||||
gimpDir = Gtk::manage(new MyFileChooserButton(M("PREFERENCES_GIMPPATH"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER));
|
|
||||||
setExpandAlignProperties(gimpDir, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER);
|
|
||||||
externaleditorGrid->attach_next_to(*edGimp, Gtk::POS_TOP, 1, 1);
|
|
||||||
externaleditorGrid->attach_next_to(*gimpDir, *edGimp, Gtk::POS_RIGHT, 1, 1);
|
|
||||||
edGimp->set_group(ge);
|
|
||||||
|
|
||||||
edPS = Gtk::manage(new Gtk::RadioButton(M("PREFERENCES_PSPATH") + ":"));
|
|
||||||
setExpandAlignProperties(edPS, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER);
|
|
||||||
psDir = Gtk::manage(new MyFileChooserButton(M("PREFERENCES_PSPATH"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER));
|
|
||||||
setExpandAlignProperties(psDir, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER);
|
|
||||||
externaleditorGrid->attach_next_to(*edPS, *edGimp, Gtk::POS_BOTTOM, 1, 1);
|
|
||||||
externaleditorGrid->attach_next_to(*psDir, *edPS, Gtk::POS_RIGHT, 1, 1);
|
|
||||||
edPS->set_group(ge);
|
|
||||||
|
|
||||||
externaleditorGrid->attach_next_to(*edOther, *edPS, Gtk::POS_BOTTOM, 1, 1);
|
|
||||||
externaleditorGrid->attach_next_to(*editorToSendTo, *edOther, Gtk::POS_RIGHT, 1, 1);
|
|
||||||
#else
|
|
||||||
edGimp = Gtk::manage(new Gtk::RadioButton("GIMP"));
|
|
||||||
setExpandAlignProperties(edGimp, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER);
|
|
||||||
externaleditorGrid->attach_next_to(*edGimp, Gtk::POS_TOP, 2, 1);
|
|
||||||
edGimp->set_group(ge);
|
|
||||||
|
|
||||||
externaleditorGrid->attach_next_to(*edOther, *edGimp, Gtk::POS_BOTTOM, 1, 1);
|
|
||||||
externaleditorGrid->attach_next_to(*editorToSendTo, *edOther, Gtk::POS_RIGHT, 1, 1);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
externalEditors = Gtk::manage(new ExternalEditorPreferences());
|
||||||
|
externalEditors->set_size_request(-1, 200);
|
||||||
|
|
||||||
// fdg->add(*externaleditorGrid);
|
// fdg->add(*externaleditorGrid);
|
||||||
editor_dir_temp = Gtk::manage(new Gtk::RadioButton(M("PREFERENCES_EXTEDITOR_DIR_TEMP")));
|
editor_dir_temp = Gtk::manage(new Gtk::RadioButton(M("PREFERENCES_EXTEDITOR_DIR_TEMP")));
|
||||||
editor_dir_current = Gtk::manage(new Gtk::RadioButton(M("PREFERENCES_EXTEDITOR_DIR_CURRENT")));
|
editor_dir_current = Gtk::manage(new Gtk::RadioButton(M("PREFERENCES_EXTEDITOR_DIR_CURRENT")));
|
||||||
editor_dir_custom = Gtk::manage(new Gtk::RadioButton(M("PREFERENCES_EXTEDITOR_DIR_CUSTOM") + ": "));
|
editor_dir_custom = Gtk::manage(new Gtk::RadioButton(M("PREFERENCES_EXTEDITOR_DIR_CUSTOM") + ": "));
|
||||||
editor_dir_custom_path = Gtk::manage(new MyFileChooserButton("", Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER));
|
editor_dir_custom_path = Gtk::manage(new MyFileChooserButton("", Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER));
|
||||||
|
Gtk::RadioButton::Group ge;
|
||||||
ge = editor_dir_temp->get_group();
|
ge = editor_dir_temp->get_group();
|
||||||
editor_dir_current->set_group(ge);
|
editor_dir_current->set_group(ge);
|
||||||
editor_dir_custom->set_group(ge);
|
editor_dir_custom->set_group(ge);
|
||||||
@ -1272,7 +1221,7 @@ Gtk::Widget* Preferences::getGeneralPanel()
|
|||||||
editor_bypass_output_profile = Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_EXTEDITOR_BYPASS_OUTPUT_PROFILE")));
|
editor_bypass_output_profile = Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_EXTEDITOR_BYPASS_OUTPUT_PROFILE")));
|
||||||
{
|
{
|
||||||
Gtk::Frame *f = Gtk::manage(new Gtk::Frame(M("PREFERENCES_EXTEDITOR_DIR")));
|
Gtk::Frame *f = Gtk::manage(new Gtk::Frame(M("PREFERENCES_EXTEDITOR_DIR")));
|
||||||
setExpandAlignProperties(f, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL);
|
setExpandAlignProperties(f, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START);
|
||||||
Gtk::Box *vb = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_VERTICAL));
|
Gtk::Box *vb = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_VERTICAL));
|
||||||
vb->pack_start(*editor_dir_temp);
|
vb->pack_start(*editor_dir_temp);
|
||||||
vb->pack_start(*editor_dir_current);
|
vb->pack_start(*editor_dir_current);
|
||||||
@ -1283,7 +1232,7 @@ Gtk::Widget* Preferences::getGeneralPanel()
|
|||||||
f->add(*vb);
|
f->add(*vb);
|
||||||
|
|
||||||
hb = Gtk::manage(new Gtk::Box());
|
hb = Gtk::manage(new Gtk::Box());
|
||||||
hb->pack_start(*externaleditorGrid);
|
hb->pack_start(*externalEditors);
|
||||||
hb->pack_start(*f, Gtk::PACK_EXPAND_WIDGET, 4);
|
hb->pack_start(*f, Gtk::PACK_EXPAND_WIDGET, 4);
|
||||||
|
|
||||||
vb = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_VERTICAL));
|
vb = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_VERTICAL));
|
||||||
@ -1755,31 +1704,17 @@ void Preferences::storePreferences()
|
|||||||
|
|
||||||
moptions.pseudoHiDPISupport = pseudoHiDPI->get_active();
|
moptions.pseudoHiDPISupport = pseudoHiDPI->get_active();
|
||||||
|
|
||||||
#ifdef WIN32
|
const std::vector<ExternalEditorPreferences::EditorInfo> &editors = externalEditors->getEditors();
|
||||||
moptions.gimpDir = gimpDir->get_filename();
|
moptions.externalEditors.resize(editors.size());
|
||||||
moptions.psDir = psDir->get_filename();
|
moptions.externalEditorIndex = -1;
|
||||||
#elif defined __APPLE__
|
for (unsigned i = 0; i < editors.size(); i++) {
|
||||||
moptions.psDir = psDir->get_filename();
|
moptions.externalEditors[i] = (ExternalEditor(
|
||||||
#endif
|
editors[i].name, editors[i].command, editors[i].icon_serialized));
|
||||||
moptions.customEditorProg = editorToSendTo->get_text();
|
if (editors[i].other_data) {
|
||||||
|
// The current editor was marked before the list was edited. We
|
||||||
if (edGimp->get_active()) {
|
// found the mark, so this is the editor that was active.
|
||||||
moptions.editorToSendTo = 1;
|
moptions.externalEditorIndex = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
else if (edPS->get_active()) {
|
|
||||||
moptions.editorToSendTo = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
#elif defined __APPLE__
|
|
||||||
else if (edPS->get_active()) {
|
|
||||||
moptions.editorToSendTo = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
else if (edOther->get_active()) {
|
|
||||||
moptions.editorToSendTo = 3;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (editor_dir_temp->get_active()) {
|
if (editor_dir_temp->get_active()) {
|
||||||
@ -2050,34 +1985,16 @@ void Preferences::fillPreferences()
|
|||||||
hlThresh->set_value(moptions.highlightThreshold);
|
hlThresh->set_value(moptions.highlightThreshold);
|
||||||
shThresh->set_value(moptions.shadowThreshold);
|
shThresh->set_value(moptions.shadowThreshold);
|
||||||
|
|
||||||
edGimp->set_active(moptions.editorToSendTo == 1);
|
std::vector<ExternalEditorPreferences::EditorInfo> editorInfos;
|
||||||
edOther->set_active(moptions.editorToSendTo == 3);
|
for (const auto &editor : moptions.externalEditors) {
|
||||||
#ifdef WIN32
|
editorInfos.push_back(ExternalEditorPreferences::EditorInfo(
|
||||||
edPS->set_active(moptions.editorToSendTo == 2);
|
editor.name, editor.command, editor.icon_serialized));
|
||||||
|
|
||||||
if (Glib::file_test(moptions.gimpDir, Glib::FILE_TEST_IS_DIR)) {
|
|
||||||
gimpDir->set_current_folder(moptions.gimpDir);
|
|
||||||
} else {
|
|
||||||
gimpDir->set_current_folder(Glib::get_home_dir());
|
|
||||||
}
|
}
|
||||||
|
if (moptions.externalEditorIndex >= 0) {
|
||||||
if (Glib::file_test(moptions.psDir, Glib::FILE_TEST_IS_DIR)) {
|
// Mark the current editor so we can track it.
|
||||||
psDir->set_current_folder(moptions.psDir);
|
editorInfos[moptions.externalEditorIndex].other_data = (void *)1;
|
||||||
} else {
|
|
||||||
psDir->set_current_folder(Glib::get_home_dir());
|
|
||||||
}
|
}
|
||||||
|
externalEditors->setEditors(editorInfos);
|
||||||
#elif defined __APPLE__
|
|
||||||
edPS->set_active(moptions.editorToSendTo == 2);
|
|
||||||
|
|
||||||
if (Glib::file_test(moptions.psDir, Glib::FILE_TEST_IS_DIR)) {
|
|
||||||
psDir->set_current_folder(moptions.psDir);
|
|
||||||
} else {
|
|
||||||
psDir->set_current_folder(Glib::get_home_dir());
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
editorToSendTo->set_text(moptions.customEditorProg);
|
|
||||||
|
|
||||||
editor_dir_temp->set_active(moptions.editor_out_dir == Options::EDITOR_OUT_DIR_TEMP);
|
editor_dir_temp->set_active(moptions.editor_out_dir == Options::EDITOR_OUT_DIR_TEMP);
|
||||||
editor_dir_current->set_active(moptions.editor_out_dir == Options::EDITOR_OUT_DIR_CURRENT);
|
editor_dir_current->set_active(moptions.editor_out_dir == Options::EDITOR_OUT_DIR_CURRENT);
|
||||||
@ -2554,6 +2471,23 @@ void Preferences::workflowUpdate()
|
|||||||
parent->updateProfiles (moptions.rtSettings.printerProfile, rtengine::RenderingIntent(moptions.rtSettings.printerIntent), moptions.rtSettings.printerBPC);
|
parent->updateProfiles (moptions.rtSettings.printerProfile, rtengine::RenderingIntent(moptions.rtSettings.printerIntent), moptions.rtSettings.printerBPC);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool changed = moptions.externalEditorIndex != options.externalEditorIndex
|
||||||
|
|| moptions.externalEditors.size() != options.externalEditors.size();
|
||||||
|
if (!changed) {
|
||||||
|
auto &editors = options.externalEditors;
|
||||||
|
auto &meditors = moptions.externalEditors;
|
||||||
|
for (unsigned i = 0; i < editors.size(); i++) {
|
||||||
|
if (editors[i] != meditors[i]) {
|
||||||
|
changed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (changed) {
|
||||||
|
// Update the send to external editor widget.
|
||||||
|
parent->updateExternalEditorWidget(moptions.externalEditorIndex, moptions.externalEditors);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Preferences::addExtPressed()
|
void Preferences::addExtPressed()
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include "options.h"
|
#include "options.h"
|
||||||
#include "../rtengine/profilestore.h"
|
#include "../rtengine/profilestore.h"
|
||||||
|
|
||||||
|
class ExternalEditorPreferences;
|
||||||
class RTWindow;
|
class RTWindow;
|
||||||
class Splash;
|
class Splash;
|
||||||
|
|
||||||
@ -101,6 +102,7 @@ class Preferences final :
|
|||||||
Gtk::RadioButton* edGimp;
|
Gtk::RadioButton* edGimp;
|
||||||
Gtk::RadioButton* edPS;
|
Gtk::RadioButton* edPS;
|
||||||
Gtk::RadioButton* edOther;
|
Gtk::RadioButton* edOther;
|
||||||
|
ExternalEditorPreferences *externalEditors;
|
||||||
|
|
||||||
Gtk::RadioButton *editor_dir_temp;
|
Gtk::RadioButton *editor_dir_temp;
|
||||||
Gtk::RadioButton *editor_dir_current;
|
Gtk::RadioButton *editor_dir_current;
|
||||||
|
77
rtgui/rtappchooserdialog.cc
Normal file
77
rtgui/rtappchooserdialog.cc
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of RawTherapee.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021 Lawrence Lee <billee@ucdavis.edu>
|
||||||
|
*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include "rtappchooserdialog.h"
|
||||||
|
|
||||||
|
#if !(defined WIN32 || defined __APPLE__)
|
||||||
|
#define GTKMM_APPCHOOSERDIALOG
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RTAppChooserDialog::~RTAppChooserDialog() {}
|
||||||
|
|
||||||
|
#ifdef GTKMM_APPCHOOSERDIALOG // Use Gtk::AppChooserDialog directly.
|
||||||
|
|
||||||
|
RTAppChooserDialog::RTAppChooserDialog(const Glib::ustring &content_type) :
|
||||||
|
Gtk::AppChooserDialog(content_type)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Glib::RefPtr<Gio::AppInfo> RTAppChooserDialog::get_app_info()
|
||||||
|
{
|
||||||
|
return Gtk::AppChooserDialog::get_app_info();
|
||||||
|
}
|
||||||
|
|
||||||
|
Glib::RefPtr<const Gio::AppInfo> RTAppChooserDialog::get_app_info() const
|
||||||
|
{
|
||||||
|
return Gtk::AppChooserDialog::get_app_info();
|
||||||
|
}
|
||||||
|
|
||||||
|
#else // Work around bugs with GLib and glibmm.
|
||||||
|
|
||||||
|
RTAppChooserDialog::RTAppChooserDialog(const Glib::ustring &content_type) :
|
||||||
|
Gtk::AppChooserDialog(content_type)
|
||||||
|
{
|
||||||
|
// GTK calls a faulty GLib function to update the most recently selected
|
||||||
|
// application after an application is selected. This removes all signal
|
||||||
|
// handlers to prevent the function call.
|
||||||
|
auto signal_id = g_signal_lookup("response", GTK_TYPE_APP_CHOOSER_DIALOG);
|
||||||
|
while (true) {
|
||||||
|
auto handler_id = g_signal_handler_find(gobj(), G_SIGNAL_MATCH_ID, signal_id, GQuark(), nullptr, nullptr, nullptr);
|
||||||
|
if (!handler_id) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
g_signal_handler_disconnect(gobj(), handler_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Glib::RefPtr<Gio::AppInfo> RTAppChooserDialog::get_app_info()
|
||||||
|
{
|
||||||
|
// glibmm wrapping of GAppInfo does not work on some platforms. Manually
|
||||||
|
// wrap it here.
|
||||||
|
GAppInfo *gAppInfo = gtk_app_chooser_get_app_info(GTK_APP_CHOOSER(gobj()));
|
||||||
|
return Glib::wrap(gAppInfo, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
Glib::RefPtr<const Gio::AppInfo> RTAppChooserDialog::get_app_info() const
|
||||||
|
{
|
||||||
|
GAppInfo *gAppInfo = gtk_app_chooser_get_app_info(GTK_APP_CHOOSER(
|
||||||
|
const_cast<GtkAppChooserDialog *>(gobj())));
|
||||||
|
return Glib::wrap(gAppInfo, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
39
rtgui/rtappchooserdialog.h
Normal file
39
rtgui/rtappchooserdialog.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of RawTherapee.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021 Lawrence Lee <billee@ucdavis.edu>
|
||||||
|
*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <giomm/appinfo.h>
|
||||||
|
#include <glibmm/refptr.h>
|
||||||
|
#include <glibmm/ustring.h>
|
||||||
|
#include <gtkmm/appchooserdialog.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom version of gtkmm's Gtk::AppChooserDialog to work around crashes
|
||||||
|
* (https://gitlab.gnome.org/GNOME/glib/-/issues/1104 and
|
||||||
|
* https://gitlab.gnome.org/GNOME/glibmm/-/issues/94).
|
||||||
|
*/
|
||||||
|
class RTAppChooserDialog : public Gtk::AppChooserDialog
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RTAppChooserDialog(const Glib::ustring &content_type);
|
||||||
|
~RTAppChooserDialog();
|
||||||
|
|
||||||
|
Glib::RefPtr<Gio::AppInfo> get_app_info();
|
||||||
|
Glib::RefPtr<const Gio::AppInfo> get_app_info() const;
|
||||||
|
};
|
107
rtgui/rtimage.cc
107
rtgui/rtimage.cc
@ -22,12 +22,40 @@
|
|||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <gtkmm/icontheme.h>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
#include "../rtengine/settings.h"
|
#include "../rtengine/settings.h"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
|
struct GIconKey {
|
||||||
|
Glib::RefPtr<const Gio::Icon> icon;
|
||||||
|
/**
|
||||||
|
* Icon size in pixels.
|
||||||
|
*/
|
||||||
|
int icon_size;
|
||||||
|
|
||||||
|
GIconKey() {}
|
||||||
|
GIconKey(const Glib::RefPtr<const Gio::Icon> &icon, int icon_size): icon(icon), icon_size(icon_size) {}
|
||||||
|
|
||||||
|
bool operator==(const GIconKey &other) const
|
||||||
|
{
|
||||||
|
bool icons_match = (icon.get() == nullptr && other.icon.get() == nullptr) || (icon.get() != nullptr && icon->equal(Glib::RefPtr<Gio::Icon>::cast_const(other.icon)));
|
||||||
|
return icons_match && icon_size == other.icon_size;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GIconKeyHash {
|
||||||
|
size_t operator()(const GIconKey &key) const
|
||||||
|
{
|
||||||
|
const size_t icon_hash = key.icon ? key.icon->hash() : 0;
|
||||||
|
return icon_hash ^ std::hash<int>()(key.icon_size);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unordered_map<GIconKey, Glib::RefPtr<Gdk::Pixbuf>, GIconKeyHash> gIconPixbufCache;
|
||||||
std::map<std::string, Glib::RefPtr<Gdk::Pixbuf> > pixbufCache;
|
std::map<std::string, Glib::RefPtr<Gdk::Pixbuf> > pixbufCache;
|
||||||
std::map<std::string, Cairo::RefPtr<Cairo::ImageSurface> > surfaceCache;
|
std::map<std::string, Cairo::RefPtr<Cairo::ImageSurface> > surfaceCache;
|
||||||
|
|
||||||
@ -44,6 +72,8 @@ RTImage::RTImage (RTImage &other) : surface(other.surface), pixbuf(other.pixbuf)
|
|||||||
set(pixbuf);
|
set(pixbuf);
|
||||||
} else if (surface) {
|
} else if (surface) {
|
||||||
set(surface);
|
set(surface);
|
||||||
|
} else if (other.gIcon) {
|
||||||
|
changeImage(other.gIcon, other.gIconSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,13 +110,27 @@ RTImage::RTImage (Glib::RefPtr<RTImage> &other)
|
|||||||
if (other->get_surface()) {
|
if (other->get_surface()) {
|
||||||
surface = other->get_surface();
|
surface = other->get_surface();
|
||||||
set(surface);
|
set(surface);
|
||||||
} else {
|
} else if (other->pixbuf) {
|
||||||
pixbuf = other->get_pixbuf();
|
pixbuf = other->get_pixbuf();
|
||||||
set(pixbuf);
|
set(pixbuf);
|
||||||
|
} else if (other->gIcon) {
|
||||||
|
changeImage(other->gIcon, other->gIconSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RTImage::RTImage(const Glib::RefPtr<const Gio::Icon> &gIcon, Gtk::IconSize size)
|
||||||
|
{
|
||||||
|
changeImage(gIcon, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
int RTImage::iconSizeToPixels(Gtk::IconSize size) const
|
||||||
|
{
|
||||||
|
int width, height;
|
||||||
|
Gtk::IconSize::lookup(size, width, height);
|
||||||
|
return std::round(getTweakedDPI() / baseDPI * std::max(width, height));
|
||||||
|
}
|
||||||
|
|
||||||
void RTImage::setImage (const Glib::ustring& fileName, const Glib::ustring& rtlFileName)
|
void RTImage::setImage (const Glib::ustring& fileName, const Glib::ustring& rtlFileName)
|
||||||
{
|
{
|
||||||
Glib::ustring imageName;
|
Glib::ustring imageName;
|
||||||
@ -113,10 +157,41 @@ void RTImage::setDPInScale (const double newDPI, const int newScale)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RTImage::changeImage(const Glib::RefPtr<const Gio::Icon> &gIcon, int size)
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
|
||||||
|
pixbuf.reset();
|
||||||
|
surface.clear();
|
||||||
|
this->gIcon = gIcon;
|
||||||
|
|
||||||
|
if (!gIcon) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
gIconSize = size;
|
||||||
|
GIconKey key(gIcon, gIconSize);
|
||||||
|
auto iterator = gIconPixbufCache.find(key);
|
||||||
|
|
||||||
|
if (iterator == gIconPixbufCache.end()) {
|
||||||
|
auto icon_pixbuf = createPixbufFromGIcon(gIcon, gIconSize);
|
||||||
|
iterator = gIconPixbufCache.emplace(key, icon_pixbuf).first;
|
||||||
|
}
|
||||||
|
|
||||||
|
set(iterator->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RTImage::changeImage(const Glib::RefPtr<const Gio::Icon> &gIcon, Gtk::IconSize size)
|
||||||
|
{
|
||||||
|
changeImage(gIcon, iconSizeToPixels(size));
|
||||||
|
}
|
||||||
|
|
||||||
void RTImage::changeImage (const Glib::ustring& imageName)
|
void RTImage::changeImage (const Glib::ustring& imageName)
|
||||||
{
|
{
|
||||||
clear ();
|
clear ();
|
||||||
|
|
||||||
|
gIcon.reset();
|
||||||
|
|
||||||
if (imageName.empty()) {
|
if (imageName.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -150,6 +225,11 @@ int RTImage::get_width()
|
|||||||
if (pixbuf) {
|
if (pixbuf) {
|
||||||
return pixbuf->get_width();
|
return pixbuf->get_width();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (gIcon) {
|
||||||
|
return this->get_pixbuf()->get_width();
|
||||||
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,6 +241,11 @@ int RTImage::get_height()
|
|||||||
if (pixbuf) {
|
if (pixbuf) {
|
||||||
return pixbuf->get_height();
|
return pixbuf->get_height();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (gIcon) {
|
||||||
|
return this->get_pixbuf()->get_height();
|
||||||
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,6 +263,11 @@ void RTImage::cleanup(bool all)
|
|||||||
for (auto& entry : surfaceCache) {
|
for (auto& entry : surfaceCache) {
|
||||||
entry.second.clear();
|
entry.second.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto& entry : gIconPixbufCache) {
|
||||||
|
entry.second.reset();
|
||||||
|
}
|
||||||
|
|
||||||
RTScalable::cleanup(all);
|
RTScalable::cleanup(all);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,6 +279,10 @@ void RTImage::updateImages()
|
|||||||
for (auto& entry : surfaceCache) {
|
for (auto& entry : surfaceCache) {
|
||||||
entry.second = createImgSurfFromFile(entry.first);
|
entry.second = createImgSurfFromFile(entry.first);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto& entry : gIconPixbufCache) {
|
||||||
|
entry.second = createPixbufFromGIcon(entry.first.icon, entry.first.icon_size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Glib::RefPtr<Gdk::Pixbuf> RTImage::createPixbufFromFile (const Glib::ustring& fileName)
|
Glib::RefPtr<Gdk::Pixbuf> RTImage::createPixbufFromFile (const Glib::ustring& fileName)
|
||||||
@ -197,6 +291,17 @@ Glib::RefPtr<Gdk::Pixbuf> RTImage::createPixbufFromFile (const Glib::ustring& fi
|
|||||||
return Gdk::Pixbuf::create(imgSurf, 0, 0, imgSurf->get_width(), imgSurf->get_height());
|
return Gdk::Pixbuf::create(imgSurf, 0, 0, imgSurf->get_width(), imgSurf->get_height());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Glib::RefPtr<Gdk::Pixbuf> RTImage::createPixbufFromGIcon(const Glib::RefPtr<const Gio::Icon> &icon, int size)
|
||||||
|
{
|
||||||
|
// TODO: Listen for theme changes and update icon, remove from cache.
|
||||||
|
Gtk::IconInfo iconInfo = Gtk::IconTheme::get_default()->lookup_icon(icon, size, Gtk::ICON_LOOKUP_FORCE_SIZE);
|
||||||
|
try {
|
||||||
|
return iconInfo.load_icon();
|
||||||
|
} catch (Glib::Exception &e) {
|
||||||
|
return Glib::RefPtr<Gdk::Pixbuf>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Cairo::RefPtr<Cairo::ImageSurface> RTImage::createImgSurfFromFile (const Glib::ustring& fileName)
|
Cairo::RefPtr<Cairo::ImageSurface> RTImage::createImgSurfFromFile (const Glib::ustring& fileName)
|
||||||
{
|
{
|
||||||
Cairo::RefPtr<Cairo::ImageSurface> surf;
|
Cairo::RefPtr<Cairo::ImageSurface> surf;
|
||||||
|
@ -34,6 +34,11 @@ class RTImage final : public Gtk::Image, public RTScalable
|
|||||||
protected:
|
protected:
|
||||||
Cairo::RefPtr<Cairo::ImageSurface> surface;
|
Cairo::RefPtr<Cairo::ImageSurface> surface;
|
||||||
Glib::RefPtr<Gdk::Pixbuf> pixbuf;
|
Glib::RefPtr<Gdk::Pixbuf> pixbuf;
|
||||||
|
Glib::RefPtr<const Gio::Icon> gIcon;
|
||||||
|
int gIconSize;
|
||||||
|
|
||||||
|
void changeImage(const Glib::RefPtr<const Gio::Icon> &gIcon, int size);
|
||||||
|
int iconSizeToPixels(Gtk::IconSize size) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
RTImage ();
|
RTImage ();
|
||||||
@ -42,9 +47,11 @@ public:
|
|||||||
explicit RTImage (Cairo::RefPtr<Cairo::ImageSurface> &surf);
|
explicit RTImage (Cairo::RefPtr<Cairo::ImageSurface> &surf);
|
||||||
explicit RTImage(Cairo::RefPtr<Cairo::ImageSurface> other);
|
explicit RTImage(Cairo::RefPtr<Cairo::ImageSurface> other);
|
||||||
explicit RTImage (Glib::RefPtr<RTImage> &other);
|
explicit RTImage (Glib::RefPtr<RTImage> &other);
|
||||||
|
explicit RTImage(const Glib::RefPtr<const Gio::Icon> &gIcon, Gtk::IconSize size);
|
||||||
explicit RTImage (const Glib::ustring& fileName, const Glib::ustring& rtlFileName = Glib::ustring());
|
explicit RTImage (const Glib::ustring& fileName, const Glib::ustring& rtlFileName = Glib::ustring());
|
||||||
|
|
||||||
void setImage (const Glib::ustring& fileName, const Glib::ustring& rtlFileName = Glib::ustring());
|
void setImage (const Glib::ustring& fileName, const Glib::ustring& rtlFileName = Glib::ustring());
|
||||||
|
void changeImage(const Glib::RefPtr<const Gio::Icon> &gIcon, Gtk::IconSize size);
|
||||||
void changeImage (const Glib::ustring& imageName);
|
void changeImage (const Glib::ustring& imageName);
|
||||||
Cairo::RefPtr<Cairo::ImageSurface> get_surface();
|
Cairo::RefPtr<Cairo::ImageSurface> get_surface();
|
||||||
int get_width();
|
int get_width();
|
||||||
@ -58,6 +65,7 @@ public:
|
|||||||
static void setScale (const int newScale);
|
static void setScale (const int newScale);
|
||||||
|
|
||||||
static Glib::RefPtr<Gdk::Pixbuf> createPixbufFromFile (const Glib::ustring& fileName);
|
static Glib::RefPtr<Gdk::Pixbuf> createPixbufFromFile (const Glib::ustring& fileName);
|
||||||
|
static Glib::RefPtr<Gdk::Pixbuf> createPixbufFromGIcon(const Glib::RefPtr<const Gio::Icon> &icon, int size);
|
||||||
static Cairo::RefPtr<Cairo::ImageSurface> createImgSurfFromFile (const Glib::ustring& fileName);
|
static Cairo::RefPtr<Cairo::ImageSurface> createImgSurfFromFile (const Glib::ustring& fileName);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -1054,6 +1054,13 @@ void RTWindow::MoveFileBrowserToEditor()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RTWindow::updateExternalEditorWidget(int selectedIndex, const std::vector<ExternalEditor> & editors)
|
||||||
|
{
|
||||||
|
if (epanel) {
|
||||||
|
epanel->updateExternalEditorWidget(selectedIndex, editors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void RTWindow::updateProfiles (const Glib::ustring &printerProfile, rtengine::RenderingIntent printerIntent, bool printerBPC)
|
void RTWindow::updateProfiles (const Glib::ustring &printerProfile, rtengine::RenderingIntent printerIntent, bool printerBPC)
|
||||||
{
|
{
|
||||||
if (epanel) {
|
if (epanel) {
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
class BatchQueueEntry;
|
class BatchQueueEntry;
|
||||||
class BatchQueuePanel;
|
class BatchQueuePanel;
|
||||||
class EditorPanel;
|
class EditorPanel;
|
||||||
|
class ExternalEditor;
|
||||||
class FilePanel;
|
class FilePanel;
|
||||||
class PLDBridge;
|
class PLDBridge;
|
||||||
class RTWindow final :
|
class RTWindow final :
|
||||||
@ -118,6 +119,7 @@ public:
|
|||||||
void MoveFileBrowserToEditor();
|
void MoveFileBrowserToEditor();
|
||||||
void MoveFileBrowserToMain();
|
void MoveFileBrowserToMain();
|
||||||
|
|
||||||
|
void updateExternalEditorWidget(int selectedIndex, const std::vector<ExternalEditor> &editors);
|
||||||
void updateProfiles (const Glib::ustring &printerProfile, rtengine::RenderingIntent printerIntent, bool printerBPC);
|
void updateProfiles (const Glib::ustring &printerProfile, rtengine::RenderingIntent printerIntent, bool printerBPC);
|
||||||
void updateTPVScrollbar (bool hide);
|
void updateTPVScrollbar (bool hide);
|
||||||
void updateHistogramPosition (int oldPosition, int newPosition);
|
void updateHistogramPosition (int oldPosition, int newPosition);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user