From 58995a052db23009db3c8341a0f189163d0f3f7a Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 25 Apr 2021 15:44:49 -0700 Subject: [PATCH 01/27] Properly enable inspector window for film strip --- rtgui/filebrowserentry.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtgui/filebrowserentry.cc b/rtgui/filebrowserentry.cc index 432296f38..5e8c730aa 100644 --- a/rtgui/filebrowserentry.cc +++ b/rtgui/filebrowserentry.cc @@ -294,7 +294,7 @@ bool FileBrowserEntry::motionNotify (int x, int y) Inspector* inspector = parent->getInspector(); - if (inspector && inspector->isActive() && !parent->isInTabMode()) { + if (inspector && inspector->isActive() && (!parent->isInTabMode() || options.inspectorWindow)) { const rtengine::Coord2D coord(getPosInImgSpace(x, y)); if (coord.x != -1.) { From 61aba8ad08f17f7fe3091725ca8c790518266c61 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 25 Apr 2021 15:48:29 -0700 Subject: [PATCH 02/27] Set inspector window title from language files --- rtdata/languages/default | 1 + rtgui/inspector.cc | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 595f03e7e..abc5f1609 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1462,6 +1462,7 @@ ICCPROFCREATOR_PROF_V4;ICC v4 ICCPROFCREATOR_SAVEDIALOG_TITLE;Save ICC profile as... ICCPROFCREATOR_SLOPE;Slope ICCPROFCREATOR_TRC_PRESET;Tone response curve +INSPECTOR_WINDOW_TITLE;Inspector IPTCPANEL_CATEGORY;Category IPTCPANEL_CATEGORYHINT;Identifies the subject of the image in the opinion of the provider. IPTCPANEL_CITY;City diff --git a/rtgui/inspector.cc b/rtgui/inspector.cc index 37ed20207..711a96615 100644 --- a/rtgui/inspector.cc +++ b/rtgui/inspector.cc @@ -21,6 +21,7 @@ #include #include "cursormanager.h" #include "guiutils.h" +#include "multilangmgr.h" #include "options.h" #include "pathutils.h" #include "rtscalable.h" @@ -91,7 +92,7 @@ Inspector::Inspector () : currImage(nullptr), scaled(false), scale(1.0), zoomSca } else { window = new Gtk::Window(); - window->set_title("RawTherapee Inspector"); + window->set_title("RawTherapee " + M("INSPECTOR_WINDOW_TITLE")); window->set_visible(false); window->add_events(Gdk::KEY_PRESS_MASK); window->signal_key_release_event().connect(sigc::mem_fun(*this, &Inspector::on_key_release)); From 67e18b5c53fc24de2fec155d59623937f80328e1 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 25 Apr 2021 17:05:02 -0700 Subject: [PATCH 03/27] Fix inspector window sometimes not hiding When the f shortcut is quickly pressed, the inspector window will sometimes open and remain open even though it should automatically close. This commit ensures the window closes by capturing the f key release event from the main window in addition to the inspector window. --- rtgui/filecatalog.cc | 15 +++++++++++++++ rtgui/filecatalog.h | 1 + rtgui/filepanel.cc | 9 +++++++++ rtgui/filepanel.h | 1 + rtgui/inspector.cc | 5 +++++ rtgui/inspector.h | 5 +++++ rtgui/rtwindow.cc | 9 +++++++++ rtgui/rtwindow.h | 1 + 8 files changed, 46 insertions(+) diff --git a/rtgui/filecatalog.cc b/rtgui/filecatalog.cc index dbea4ade9..cdcb00195 100644 --- a/rtgui/filecatalog.cc +++ b/rtgui/filecatalog.cc @@ -2524,6 +2524,21 @@ bool FileCatalog::handleShortcutKey (GdkEventKey* event) return fileBrowser->keyPressed(event); } +bool FileCatalog::handleShortcutKeyRelease(GdkEventKey* event) +{ + bool ctrl = event->state & GDK_CONTROL_MASK; + bool alt = event->state & GDK_MOD1_MASK; + + if (!ctrl && !alt) { + switch (event->keyval) { + case GDK_KEY_f: + case GDK_KEY_F: + fileBrowser->getInspector()->hideWindow(); + return true; + } + } +} + void FileCatalog::showToolBar() { if (hbToolBar1STB) { diff --git a/rtgui/filecatalog.h b/rtgui/filecatalog.h index c7c4f3155..23d56af73 100644 --- a/rtgui/filecatalog.h +++ b/rtgui/filecatalog.h @@ -276,6 +276,7 @@ public: void openNextPreviousEditorImage (Glib::ustring fname, bool clearFilters, eRTNav nextPrevious); bool handleShortcutKey (GdkEventKey* event); + bool handleShortcutKeyRelease(GdkEventKey *event); bool CheckSidePanelsVisibility(); void toggleSidePanels(); diff --git a/rtgui/filepanel.cc b/rtgui/filepanel.cc index a09a82597..974482f41 100644 --- a/rtgui/filepanel.cc +++ b/rtgui/filepanel.cc @@ -412,6 +412,15 @@ bool FilePanel::handleShortcutKey (GdkEventKey* event) return false; } +bool FilePanel::handleShortcutKeyRelease(GdkEventKey *event) +{ + if(fileCatalog->handleShortcutKeyRelease(event)) { + return true; + } + + return false; +} + void FilePanel::loadingThumbs(Glib::ustring str, double rate) { GThreadLock lock; // All GUI access from idle_add callbacks or separate thread HAVE to be protected diff --git a/rtgui/filepanel.h b/rtgui/filepanel.h index 65e1ea548..ba5dfa7c9 100644 --- a/rtgui/filepanel.h +++ b/rtgui/filepanel.h @@ -81,6 +81,7 @@ public: bool imageLoaded( Thumbnail* thm, ProgressConnector * ); bool handleShortcutKey (GdkEventKey* event); + bool handleShortcutKeyRelease(GdkEventKey *event); void updateTPVScrollbar (bool hide); private: diff --git a/rtgui/inspector.cc b/rtgui/inspector.cc index 711a96615..7ca0b92d0 100644 --- a/rtgui/inspector.cc +++ b/rtgui/inspector.cc @@ -144,6 +144,11 @@ void Inspector::showWindow(bool scaled, bool fullscreen) mouseMove(next_image_pos, 0); } +void Inspector::hideWindow() +{ + window->set_visible(false); +} + bool Inspector::on_key_release(GdkEventKey *event) { if (!window) diff --git a/rtgui/inspector.h b/rtgui/inspector.h index 726bc947c..52c95d14c 100644 --- a/rtgui/inspector.h +++ b/rtgui/inspector.h @@ -91,6 +91,11 @@ public: */ void showWindow(bool scaled, bool fullscreen = true); + /** + * Hide the window. + */ + void hideWindow(); + /** @brief Mouse movement to a new position * @param pos Location of the mouse, in percentage (i.e. [0;1] range) relative to the full size image ; -1,-1 == out of the image * @param transform H/V flip and coarse rotation transformation diff --git a/rtgui/rtwindow.cc b/rtgui/rtwindow.cc index c0042f949..cf77374ce 100644 --- a/rtgui/rtwindow.cc +++ b/rtgui/rtwindow.cc @@ -285,6 +285,7 @@ RTWindow::RTWindow () property_destroy_with_parent().set_value (false); signal_window_state_event().connect ( sigc::mem_fun (*this, &RTWindow::on_window_state_event) ); signal_key_press_event().connect ( sigc::mem_fun (*this, &RTWindow::keyPressed) ); + signal_key_release_event().connect(sigc::mem_fun(*this, &RTWindow::keyReleased)); if (simpleEditor) { epanel = Gtk::manage ( new EditorPanel (nullptr) ); @@ -756,6 +757,14 @@ bool RTWindow::keyPressed (GdkEventKey* event) return false; } +bool RTWindow::keyReleased(GdkEventKey *event) +{ + if (mainNB->get_current_page() == mainNB->page_num(*fpanel)) { + return fpanel->handleShortcutKeyRelease(event); + } + return false; +} + void RTWindow::addBatchQueueJob (BatchQueueEntry* bqe, bool head) { diff --git a/rtgui/rtwindow.h b/rtgui/rtwindow.h index e5e180747..aa1830d89 100644 --- a/rtgui/rtwindow.h +++ b/rtgui/rtwindow.h @@ -85,6 +85,7 @@ public: void addBatchQueueJobs (const std::vector& entries); bool keyPressed (GdkEventKey* event); + bool keyReleased(GdkEventKey *event); bool on_configure_event (GdkEventConfigure* event) override; bool on_delete_event (GdkEventAny* event) override; bool on_window_state_event (GdkEventWindowState* event) override; From d4bceb5c06b256debf76051a5e2da4108bc253ca Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 25 Apr 2021 17:27:57 -0700 Subject: [PATCH 04/27] Pin inspector window if opened with context menu --- rtgui/filebrowser.cc | 2 +- rtgui/inspector.cc | 4 ++-- rtgui/inspector.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rtgui/filebrowser.cc b/rtgui/filebrowser.cc index 0d2451b59..0246520ee 100644 --- a/rtgui/filebrowser.cc +++ b/rtgui/filebrowser.cc @@ -2100,5 +2100,5 @@ void FileBrowser::openRequested( std::vector mselected) void FileBrowser::inspectRequested(std::vector mselected) { - getInspector()->showWindow(false, false); + getInspector()->showWindow(false, false, true); } diff --git a/rtgui/inspector.cc b/rtgui/inspector.cc index 7ca0b92d0..242ebac24 100644 --- a/rtgui/inspector.cc +++ b/rtgui/inspector.cc @@ -117,7 +117,7 @@ Inspector::~Inspector() delete window; } -void Inspector::showWindow(bool scaled, bool fullscreen) +void Inspector::showWindow(bool scaled, bool fullscreen, bool pinned) { if (!window) return; @@ -137,7 +137,7 @@ void Inspector::showWindow(bool scaled, bool fullscreen) window->unfullscreen(); this->fullscreen = fullscreen; window->set_visible(true); - pinned = false; + this->pinned = pinned; // update content when becoming visible switchImage(next_image_path); diff --git a/rtgui/inspector.h b/rtgui/inspector.h index 52c95d14c..62bcef471 100644 --- a/rtgui/inspector.h +++ b/rtgui/inspector.h @@ -89,7 +89,7 @@ public: /** @brief Show or hide window * @param scaled fit image into window */ - void showWindow(bool scaled, bool fullscreen = true); + void showWindow(bool scaled, bool fullscreen = true, bool pinned = false); /** * Hide the window. From 900af7aeb7c9e9ba71c0a2e4d489f7b853790cd3 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 25 Apr 2021 18:11:47 -0700 Subject: [PATCH 05/27] Remove drawn background in inspector window Add "InspectorWindow" CSS ID so that the background color can be changed through CSS. --- rtgui/inspector.cc | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/rtgui/inspector.cc b/rtgui/inspector.cc index 242ebac24..c43e3863e 100644 --- a/rtgui/inspector.cc +++ b/rtgui/inspector.cc @@ -92,6 +92,7 @@ Inspector::Inspector () : currImage(nullptr), scaled(false), scale(1.0), zoomSca } else { window = new Gtk::Window(); + window->set_name("InspectorWindow"); window->set_title("RawTherapee " + M("INSPECTOR_WINDOW_TITLE")); window->set_visible(false); window->add_events(Gdk::KEY_PRESS_MASK); @@ -450,15 +451,6 @@ bool Inspector::on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr) // draw the background style->render_background(cr, 0, 0, get_width(), get_height()); } - else { - ///* --- old method (the new method does not seem to work) - c = style->get_background_color (Gtk::STATE_FLAG_NORMAL); - cr->set_source_rgb (c.get_red(), c.get_green(), c.get_blue()); - cr->set_line_width (0); - cr->rectangle (0, 0, availableSize.x, availableSize.y); - cr->fill (); - //*/ - } bool scaledImage = scale != 1.0; if (!window || (deviceScale == 1 && !scaledImage)) { From 5decec540542a9769f410a6ab50265a59a771b81 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sat, 1 May 2021 15:48:50 -0700 Subject: [PATCH 06/27] Fix inspector window zoom centering Use floating point coordinates instead of integers to avoid rounding errors. --- rtgui/inspector.cc | 59 +++++++++++++++++++++++++++++----------------- rtgui/inspector.h | 5 ++-- 2 files changed, 39 insertions(+), 25 deletions(-) diff --git a/rtgui/inspector.cc b/rtgui/inspector.cc index c43e3863e..d212787df 100644 --- a/rtgui/inspector.cc +++ b/rtgui/inspector.cc @@ -333,8 +333,17 @@ void Inspector::beginZoom(double x, double y) moveCenter(0, 0, imW, imH, deviceScale); // store center and current position for zooming - dcenterBegin.x = (x - window->get_width()/2) / scale * deviceScale; - dcenterBegin.y = (y - window->get_height()/2) / scale * deviceScale; + double cur_scale = zoomScale; + if (scaled) { + Glib::RefPtr win = get_window(); + double winW = win->get_width() * deviceScale; + double winH = win->get_height() * deviceScale; + int imW = rtengine::max(currImage->imgBuffer.getWidth(), 1); + int imH = rtengine::max(currImage->imgBuffer.getHeight(), 1); + cur_scale *= rtengine::min(winW / imW, winH / imH); + } + dcenterBegin.x = (x - window->get_width() / 2.) / cur_scale * deviceScale; + dcenterBegin.y = (y - window->get_height() / 2.) / cur_scale * deviceScale; centerBegin = center; zoomScaleBegin = zoomScale; @@ -385,15 +394,16 @@ bool Inspector::on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr) // this will eventually create/update the off-screen pixmap // compute the displayed area - rtengine::Coord availableSize; - rtengine::Coord topLeft; - rtengine::Coord dest(0, 0); + rtengine::Coord2D availableSize; + rtengine::Coord2D topLeft; + rtengine::Coord topLeftInt; + rtengine::Coord2D dest(0, 0); int deviceScale = window? get_scale_factor(): 1; availableSize.x = win->get_width() * deviceScale; availableSize.y = win->get_height() * deviceScale; int imW = rtengine::max(currImage->imgBuffer.getWidth(), 1); int imH = rtengine::max(currImage->imgBuffer.getHeight(), 1); - scale = rtengine::min((double)availableSize.x / imW, (double)availableSize.y / imH); + scale = rtengine::min(availableSize.x / imW, availableSize.y / imH); if (scaled) { // reduce size of image to fit into window, no further zoom down zoomScale = rtengine::max(zoomScale, 1.0); @@ -410,33 +420,36 @@ bool Inspector::on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr) if (imW < availableSize.x) { // center the image in the available space along X topLeft.x = 0; - dest.x = (availableSize.x - imW) / 2; + dest.x = (availableSize.x - imW) / 2.; } else { // partial image display // double clamp - topLeft.x = center.x + availableSize.x / 2; - topLeft.x = rtengine::min(topLeft.x, imW); + topLeft.x = center.x + availableSize.x / 2.; + topLeft.x = rtengine::min(topLeft.x, imW); topLeft.x -= availableSize.x; - topLeft.x = rtengine::max(topLeft.x, 0); + topLeft.x = rtengine::max(topLeft.x, 0); } if (imH < availableSize.y) { // center the image in the available space along Y topLeft.y = 0; - dest.y = (availableSize.y - imH) / 2; + dest.y = (availableSize.y - imH) / 2.; } else { // partial image display // double clamp - topLeft.y = center.y + availableSize.y / 2; - topLeft.y = rtengine::min(topLeft.y, imH); + topLeft.y = center.y + availableSize.y / 2.; + topLeft.y = rtengine::min(topLeft.y, imH); topLeft.y -= availableSize.y; - topLeft.y = rtengine::max(topLeft.y, 0); + topLeft.y = rtengine::max(topLeft.y, 0); } //printf("center: %d, %d (img: %d, %d) (availableSize: %d, %d) (topLeft: %d, %d)\n", center.x, center.y, imW, imH, availableSize.x, availableSize.y, topLeft.x, topLeft.y); + topLeftInt.x = floor(topLeft.x); + topLeftInt.y = floor(topLeft.y); + // define the destination area - currImage->imgBuffer.setDrawRectangle(win, dest.x, dest.y, rtengine::min(availableSize.x - dest.x, imW), rtengine::min(availableSize.y - dest.y, imH), false); - currImage->imgBuffer.setSrcOffset(topLeft.x, topLeft.y); + currImage->imgBuffer.setDrawRectangle(win, dest.x, dest.y, rtengine::min(ceil(availableSize.x + (topLeft.x - topLeftInt.x) - 2 * dest.x), imW), rtengine::min(ceil(availableSize.y + (topLeft.y - topLeftInt.y) - 2 * dest.y), imH), false); + currImage->imgBuffer.setSrcOffset(topLeftInt.x, topLeftInt.y); if (!currImage->imgBuffer.surfaceCreated()) { return false; @@ -464,16 +477,18 @@ bool Inspector::on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr) cairo_surface_set_device_scale(cr->get_target()->cobj(), scale, scale); scaledImage = false; } - int viewW = rtengine::min(imW, availableSize.x); - int viewH = rtengine::min(imH, availableSize.y); - Glib::RefPtr crop = Gdk::Pixbuf::create(currImage->imgBuffer.getSurface(), topLeft.x, topLeft.y, viewW, viewH); + int viewW = rtengine::min(imW, ceil(availableSize.x + (topLeft.x - topLeftInt.x))); + int viewH = rtengine::min(imH, ceil(availableSize.y + (topLeft.y - topLeftInt.y))); + Glib::RefPtr crop = Gdk::Pixbuf::create(currImage->imgBuffer.getSurface(), topLeftInt.x, topLeftInt.y, viewW, viewH); if (!scaledImage) { Gdk::Cairo::set_source_pixbuf(cr, crop, dest.x, dest.y); } else { + double dx = scale * (dest.x + topLeftInt.x - topLeft.x); + double dy = scale * (dest.y + topLeftInt.y - topLeft.y); // scale crop as the device does not seem to support it (Linux) - crop = crop->scale_simple(viewW*scale, viewH*scale, Gdk::INTERP_BILINEAR); - Gdk::Cairo::set_source_pixbuf(cr, crop, dest.x*scale, dest.y*scale); + crop = crop->scale_simple(round(viewW*scale), round(viewH*scale), Gdk::INTERP_BILINEAR); + Gdk::Cairo::set_source_pixbuf(cr, crop, dx, dy); } cr->paint(); } @@ -504,7 +519,7 @@ void Inspector::mouseMove (rtengine::Coord2D pos, int transform) return; if (currImage) { - center.set(int(rtengine::LIM01(pos.x)*double(currImage->imgBuffer.getWidth())), int(rtengine::LIM01(pos.y)*double(currImage->imgBuffer.getHeight()))); + center.set(rtengine::LIM01(pos.x)*double(currImage->imgBuffer.getWidth()), rtengine::LIM01(pos.y)*double(currImage->imgBuffer.getHeight())); } else { center.set(0, 0); } diff --git a/rtgui/inspector.h b/rtgui/inspector.h index 62bcef471..b17d199bf 100644 --- a/rtgui/inspector.h +++ b/rtgui/inspector.h @@ -22,7 +22,6 @@ #include "guiutils.h" -#include "../rtengine/coord.h" #include "../rtengine/coord2d.h" class InspectorBuffer @@ -44,13 +43,13 @@ class Inspector final : public Gtk::DrawingArea { private: - rtengine::Coord center; + rtengine::Coord2D center; std::vector images; InspectorBuffer* currImage; bool scaled; // fit image into window double scale; // current scale double zoomScale, zoomScaleBegin; // scale during zoom - rtengine::Coord centerBegin, dcenterBegin; // center during zoom + rtengine::Coord2D centerBegin, dcenterBegin; // center during zoom bool active; bool pinned; bool dirty; From e25cb3fde0665f1060e9fa6d8dba2414671002d3 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sat, 1 May 2021 15:52:45 -0700 Subject: [PATCH 07/27] Fix inspector window panning speed Consistently use integers for mouse movement and compensate for image scale. --- rtgui/inspector.cc | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/rtgui/inspector.cc b/rtgui/inspector.cc index d212787df..59378b9d2 100644 --- a/rtgui/inspector.cc +++ b/rtgui/inspector.cc @@ -227,13 +227,15 @@ bool Inspector::on_motion_notify_event(GdkEventMotion *event) return false; int deviceScale = get_scale_factor(); - int delta_x = (button_pos.x - event->x)*deviceScale; - int delta_y = (button_pos.y - event->y)*deviceScale; + int event_x = round(event->x); + int event_y = round(event->y); + int delta_x = (button_pos.x - event_x) * deviceScale; + int delta_y = (button_pos.y - event_y) * deviceScale; int imW = currImage->imgBuffer.getWidth(); int imH = currImage->imgBuffer.getHeight(); moveCenter(delta_x, delta_y, imW, imH, deviceScale); - button_pos.set(event->x, event->y); + button_pos.set(event_x, event_y); if (!dirty) { dirty = true; @@ -316,8 +318,8 @@ void Inspector::moveCenter(int delta_x, int delta_y, int imW, int imH, int devic rtengine::Coord margin; // limit to image size margin.x = rtengine::min(window->get_width() * deviceScale / scale, imW) / 2; margin.y = rtengine::min(window->get_height() * deviceScale / scale, imH) / 2; - center.set(rtengine::LIM(center.x + delta_x, margin.x, imW - margin.x), - rtengine::LIM(center.y + delta_y, margin.y, imH - margin.y)); + center.set(rtengine::LIM(center.x + delta_x / scale, margin.x, imW - margin.x), + rtengine::LIM(center.y + delta_y / scale, margin.y, imH - margin.y)); } void Inspector::beginZoom(double x, double y) From b99b9302cce5a8e175fc7faf87edc6c745f22fd3 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 2 May 2021 12:31:33 -0700 Subject: [PATCH 08/27] Fix inspector window scaling with caps lock When launched with the accelerator key, the inspector window initially scales the image without respecting the state of the caps lock. This commit fixes the bug. --- rtgui/filecatalog.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/rtgui/filecatalog.cc b/rtgui/filecatalog.cc index cdcb00195..d0316a2d4 100644 --- a/rtgui/filecatalog.cc +++ b/rtgui/filecatalog.cc @@ -2515,8 +2515,10 @@ bool FileCatalog::handleShortcutKey (GdkEventKey* event) if (!ctrl && !alt) { switch (event->keyval) { case GDK_KEY_f: + fileBrowser->getInspector()->showWindow(true); + return true; case GDK_KEY_F: - fileBrowser->getInspector()->showWindow(!shift); + fileBrowser->getInspector()->showWindow(false); return true; } } From 4811f92c399a5941175591c578f30baffe9cb8ec Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 2 May 2021 12:35:05 -0700 Subject: [PATCH 09/27] Add missing return statement --- rtgui/filecatalog.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rtgui/filecatalog.cc b/rtgui/filecatalog.cc index d0316a2d4..a685bebe9 100644 --- a/rtgui/filecatalog.cc +++ b/rtgui/filecatalog.cc @@ -2539,6 +2539,8 @@ bool FileCatalog::handleShortcutKeyRelease(GdkEventKey* event) return true; } } + + return false; } void FileCatalog::showToolBar() From de9403f9fe27c9d36cb48cbac4663952301e581c Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 2 May 2021 12:52:15 -0700 Subject: [PATCH 10/27] Ignore key down repeat events in inspector window Ignore key press events that happen when a key is held down. --- rtgui/inspector.cc | 12 +++++++++++- rtgui/inspector.h | 1 + 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/rtgui/inspector.cc b/rtgui/inspector.cc index 59378b9d2..e0da8378e 100644 --- a/rtgui/inspector.cc +++ b/rtgui/inspector.cc @@ -83,7 +83,7 @@ InspectorBuffer::~InspectorBuffer() { // return deg; //} -Inspector::Inspector () : currImage(nullptr), scaled(false), scale(1.0), zoomScale(1.0), zoomScaleBegin(1.0), active(false), pinned(false), dirty(false) +Inspector::Inspector () : currImage(nullptr), scaled(false), scale(1.0), zoomScale(1.0), zoomScaleBegin(1.0), active(false), pinned(false), dirty(false), keyDown(false) { set_name("Inspector"); @@ -152,6 +152,8 @@ void Inspector::hideWindow() bool Inspector::on_key_release(GdkEventKey *event) { + keyDown = false; + if (!window) return false; @@ -172,6 +174,12 @@ bool Inspector::on_key_press(GdkEventKey *event) if (!window) return false; + if (keyDown) { + return true; + } + + keyDown = true; + switch (event->keyval) { case GDK_KEY_z: case GDK_KEY_F: @@ -203,6 +211,8 @@ bool Inspector::on_key_press(GdkEventKey *event) return true; } + keyDown = false; + return false; } diff --git a/rtgui/inspector.h b/rtgui/inspector.h index b17d199bf..4d5e5e835 100644 --- a/rtgui/inspector.h +++ b/rtgui/inspector.h @@ -55,6 +55,7 @@ private: bool dirty; bool initialized; bool fullscreen; // window is shown in fullscreen mode + bool keyDown; sigc::connection delayconn; Glib::ustring next_image_path; From bce88478c47731eca702d65fc0baaf88d44855ce Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 2 May 2021 15:50:55 -0700 Subject: [PATCH 11/27] Fix inspector window rendering with device scaling --- rtgui/inspector.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rtgui/inspector.cc b/rtgui/inspector.cc index e0da8378e..c8d9c8bd2 100644 --- a/rtgui/inspector.cc +++ b/rtgui/inspector.cc @@ -485,9 +485,13 @@ bool Inspector::on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr) else { // consider device scale and image scale if (deviceScale > 1) { +#ifdef __APPLE__ // use full device resolution and let it scale the image (macOS) cairo_surface_set_device_scale(cr->get_target()->cobj(), scale, scale); scaledImage = false; +#else + cr->scale(1. / deviceScale, 1. / deviceScale); +#endif } int viewW = rtengine::min(imW, ceil(availableSize.x + (topLeft.x - topLeftInt.x))); int viewH = rtengine::min(imH, ceil(availableSize.y + (topLeft.y - topLeftInt.y))); From 70d30a5050e6784f8b118eb088704df068fc30ea Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 2 May 2021 15:57:34 -0700 Subject: [PATCH 12/27] Fix crash after pressing `f` key in file browser Check that the inspector window exists before trying to close it. --- rtgui/inspector.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/rtgui/inspector.cc b/rtgui/inspector.cc index c8d9c8bd2..2de324b29 100644 --- a/rtgui/inspector.cc +++ b/rtgui/inspector.cc @@ -147,6 +147,9 @@ void Inspector::showWindow(bool scaled, bool fullscreen, bool pinned) void Inspector::hideWindow() { + if (!window) { + return; + } window->set_visible(false); } From 9495c049c49b73b129ee329546af84db173753c7 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Thu, 6 May 2021 21:39:01 -0700 Subject: [PATCH 13/27] Fix inspector not opening full-screen at first --- rtgui/inspector.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/rtgui/inspector.cc b/rtgui/inspector.cc index 2de324b29..cf4ae3207 100644 --- a/rtgui/inspector.cc +++ b/rtgui/inspector.cc @@ -126,7 +126,6 @@ void Inspector::showWindow(bool scaled, bool fullscreen, bool pinned) // initialize when shown first if (!initialized) { window->show_all(); - window->set_visible(false); initialized = true; } From b2988ddbb32e0bd77805daa4f3e36284cfb91fea Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Fri, 7 May 2021 22:26:28 -0700 Subject: [PATCH 14/27] Avoid reopening inspector window when being opened --- rtgui/inspector.cc | 11 +++++++++-- rtgui/inspector.h | 3 +++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/rtgui/inspector.cc b/rtgui/inspector.cc index cf4ae3207..1534618e4 100644 --- a/rtgui/inspector.cc +++ b/rtgui/inspector.cc @@ -83,7 +83,7 @@ InspectorBuffer::~InspectorBuffer() { // return deg; //} -Inspector::Inspector () : currImage(nullptr), scaled(false), scale(1.0), zoomScale(1.0), zoomScaleBegin(1.0), active(false), pinned(false), dirty(false), keyDown(false) +Inspector::Inspector () : currImage(nullptr), scaled(false), scale(1.0), zoomScale(1.0), zoomScaleBegin(1.0), active(false), pinned(false), dirty(false), keyDown(false), windowShowing(false) { set_name("Inspector"); @@ -98,6 +98,7 @@ Inspector::Inspector () : currImage(nullptr), scaled(false), scale(1.0), zoomSca window->add_events(Gdk::KEY_PRESS_MASK); window->signal_key_release_event().connect(sigc::mem_fun(*this, &Inspector::on_key_release)); window->signal_key_press_event().connect(sigc::mem_fun(*this, &Inspector::on_key_press)); + window->signal_hide().connect(sigc::mem_fun(*this, &Inspector::on_window_hide)); add_events(Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_MOTION_MASK | Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK); gestureZoom = Gtk::GestureZoom::create(*this); @@ -120,7 +121,7 @@ Inspector::~Inspector() void Inspector::showWindow(bool scaled, bool fullscreen, bool pinned) { - if (!window) + if (!window || windowShowing) return; // initialize when shown first @@ -138,6 +139,7 @@ void Inspector::showWindow(bool scaled, bool fullscreen, bool pinned) this->fullscreen = fullscreen; window->set_visible(true); this->pinned = pinned; + windowShowing = true; // update content when becoming visible switchImage(next_image_path); @@ -218,6 +220,11 @@ bool Inspector::on_key_press(GdkEventKey *event) return false; } +void Inspector::on_window_hide() +{ + windowShowing = false; +} + bool Inspector::on_button_press_event(GdkEventButton *event) { if (!window) diff --git a/rtgui/inspector.h b/rtgui/inspector.h index 4d5e5e835..9ff03f96e 100644 --- a/rtgui/inspector.h +++ b/rtgui/inspector.h @@ -56,6 +56,7 @@ private: bool initialized; bool fullscreen; // window is shown in fullscreen mode bool keyDown; + bool windowShowing; sigc::connection delayconn; Glib::ustring next_image_path; @@ -65,6 +66,8 @@ private: bool on_key_release(GdkEventKey *event); bool on_key_press(GdkEventKey *event); + void on_window_hide(); + rtengine::Coord button_pos; bool on_button_press_event(GdkEventButton *event) override; bool on_motion_notify_event(GdkEventMotion *event) override; From 36cb32b31be5702574bcc32e97a82296e465a2be Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sat, 8 May 2021 11:15:41 -0700 Subject: [PATCH 15/27] Make inspector window size consistent --- rtgui/filebrowser.cc | 2 +- rtgui/filecatalog.cc | 4 ++-- rtgui/inspector.cc | 22 +++++++++++++++------- rtgui/inspector.h | 4 +++- 4 files changed, 21 insertions(+), 11 deletions(-) diff --git a/rtgui/filebrowser.cc b/rtgui/filebrowser.cc index 0246520ee..304e75a5c 100644 --- a/rtgui/filebrowser.cc +++ b/rtgui/filebrowser.cc @@ -2100,5 +2100,5 @@ void FileBrowser::openRequested( std::vector mselected) void FileBrowser::inspectRequested(std::vector mselected) { - getInspector()->showWindow(false, false, true); + getInspector()->showWindow(true); } diff --git a/rtgui/filecatalog.cc b/rtgui/filecatalog.cc index a685bebe9..c45fc154f 100644 --- a/rtgui/filecatalog.cc +++ b/rtgui/filecatalog.cc @@ -2515,10 +2515,10 @@ bool FileCatalog::handleShortcutKey (GdkEventKey* event) if (!ctrl && !alt) { switch (event->keyval) { case GDK_KEY_f: - fileBrowser->getInspector()->showWindow(true); + fileBrowser->getInspector()->showWindow(false, true); return true; case GDK_KEY_F: - fileBrowser->getInspector()->showWindow(false); + fileBrowser->getInspector()->showWindow(false, false); return true; } } diff --git a/rtgui/inspector.cc b/rtgui/inspector.cc index 1534618e4..9fa1b8773 100644 --- a/rtgui/inspector.cc +++ b/rtgui/inspector.cc @@ -83,7 +83,7 @@ InspectorBuffer::~InspectorBuffer() { // return deg; //} -Inspector::Inspector () : currImage(nullptr), scaled(false), scale(1.0), zoomScale(1.0), zoomScaleBegin(1.0), active(false), pinned(false), dirty(false), keyDown(false), windowShowing(false) +Inspector::Inspector () : currImage(nullptr), scaled(false), scale(1.0), zoomScale(1.0), zoomScaleBegin(1.0), active(false), pinned(false), dirty(false), fullscreen(true), keyDown(false), windowShowing(false) { set_name("Inspector"); @@ -99,6 +99,7 @@ Inspector::Inspector () : currImage(nullptr), scaled(false), scale(1.0), zoomSca window->signal_key_release_event().connect(sigc::mem_fun(*this, &Inspector::on_key_release)); window->signal_key_press_event().connect(sigc::mem_fun(*this, &Inspector::on_key_press)); window->signal_hide().connect(sigc::mem_fun(*this, &Inspector::on_window_hide)); + window->signal_window_state_event().connect(sigc::mem_fun(*this, &Inspector::on_inspector_window_state_event)); add_events(Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_MOTION_MASK | Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK); gestureZoom = Gtk::GestureZoom::create(*this); @@ -107,6 +108,7 @@ Inspector::Inspector () : currImage(nullptr), scaled(false), scale(1.0), zoomSca window->add(*this); window->set_size_request(500, 500); + window->fullscreen(); initialized = false; // delay init to avoid flickering on some systems active = true; // always track inspected thumbnails } @@ -119,7 +121,7 @@ Inspector::~Inspector() delete window; } -void Inspector::showWindow(bool scaled, bool fullscreen, bool pinned) +void Inspector::showWindow(bool pinned, bool scaled) { if (!window || windowShowing) return; @@ -132,11 +134,6 @@ void Inspector::showWindow(bool scaled, bool fullscreen, bool pinned) // show inspector window this->scaled = scaled; - if (fullscreen) - window->fullscreen(); - else - window->unfullscreen(); - this->fullscreen = fullscreen; window->set_visible(true); this->pinned = pinned; windowShowing = true; @@ -225,6 +222,17 @@ void Inspector::on_window_hide() windowShowing = false; } +bool Inspector::on_inspector_window_state_event(GdkEventWindowState *event) +{ + if (!window->get_window() || window->get_window()->gobj() != event->window) { + return false; + } + + fullscreen = event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN; + + return true; +} + bool Inspector::on_button_press_event(GdkEventButton *event) { if (!window) diff --git a/rtgui/inspector.h b/rtgui/inspector.h index 9ff03f96e..5577bfb45 100644 --- a/rtgui/inspector.h +++ b/rtgui/inspector.h @@ -67,6 +67,7 @@ private: bool on_key_press(GdkEventKey *event); void on_window_hide(); + bool on_inspector_window_state_event(GdkEventWindowState *event); rtengine::Coord button_pos; bool on_button_press_event(GdkEventButton *event) override; @@ -90,9 +91,10 @@ public: ~Inspector() override; /** @brief Show or hide window + * @param pinned pin window * @param scaled fit image into window */ - void showWindow(bool scaled, bool fullscreen = true, bool pinned = false); + void showWindow(bool pinned, bool scaled = true); /** * Hide the window. From 9df34be6cbf5ed791aa78f3f1761c719208aea09 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sat, 8 May 2021 12:15:58 -0700 Subject: [PATCH 16/27] Hide inspector accelerator in film strip Only show the accelerator key in the context menu when opening the menu from the full file browser but not the film strip. --- rtgui/filebrowser.cc | 15 ++++++++++++++- rtgui/filebrowser.h | 2 ++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/rtgui/filebrowser.cc b/rtgui/filebrowser.cc index 304e75a5c..37ff6da62 100644 --- a/rtgui/filebrowser.cc +++ b/rtgui/filebrowser.cc @@ -411,7 +411,7 @@ FileBrowser::FileBrowser () : untrash->add_accelerator ("activate", pmenu->get_accel_group(), GDK_KEY_Delete, Gdk::SHIFT_MASK, Gtk::ACCEL_VISIBLE); open->add_accelerator ("activate", pmenu->get_accel_group(), GDK_KEY_Return, (Gdk::ModifierType)0, Gtk::ACCEL_VISIBLE); if (options.inspectorWindow) - inspect->add_accelerator ("activate", pmenu->get_accel_group(), GDK_KEY_F, (Gdk::ModifierType)0, Gtk::ACCEL_VISIBLE); + inspect->add_accelerator ("activate", pmenu->get_accel_group(), GDK_KEY_f, (Gdk::ModifierType)0, Gtk::ACCEL_VISIBLE); develop->add_accelerator ("activate", pmenu->get_accel_group(), GDK_KEY_B, Gdk::CONTROL_MASK, Gtk::ACCEL_VISIBLE); developfast->add_accelerator ("activate", pmenu->get_accel_group(), GDK_KEY_B, Gdk::CONTROL_MASK | Gdk::SHIFT_MASK, Gtk::ACCEL_VISIBLE); copyprof->add_accelerator ("activate", pmenu->get_accel_group(), GDK_KEY_C, Gdk::CONTROL_MASK, Gtk::ACCEL_VISIBLE); @@ -1374,6 +1374,19 @@ int FileBrowser::getThumbnailHeight () } } +void FileBrowser::enableTabMode(bool enable) +{ + ThumbBrowserBase::enableTabMode(enable); + if (options.inspectorWindow) { + if (enable) { + inspect->remove_accelerator(pmenu->get_accel_group(), GDK_KEY_f, (Gdk::ModifierType)0); + } + else { + inspect->add_accelerator ("activate", pmenu->get_accel_group(), GDK_KEY_f, (Gdk::ModifierType)0, Gtk::ACCEL_VISIBLE); + } + } +} + void FileBrowser::applyMenuItemActivated (ProfileStoreLabel *label) { MYREADERLOCK(l, entryRW); diff --git a/rtgui/filebrowser.h b/rtgui/filebrowser.h index 03a8636e5..4602ba9bb 100644 --- a/rtgui/filebrowser.h +++ b/rtgui/filebrowser.h @@ -182,6 +182,8 @@ public: void saveThumbnailHeight (int height) override; int getThumbnailHeight () override; + + void enableTabMode(bool enable); bool isInTabMode() override { return tbl ? tbl->isInTabMode() : false; From 6535cb4a9454b86164f0017df958b691965ae4d1 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 9 May 2021 12:18:06 -0700 Subject: [PATCH 17/27] Make inspector never upscale in fit-to-window mode When zoomed completely out, don't upscale images. --- rtgui/inspector.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtgui/inspector.cc b/rtgui/inspector.cc index 9fa1b8773..0453564f9 100644 --- a/rtgui/inspector.cc +++ b/rtgui/inspector.cc @@ -432,7 +432,7 @@ bool Inspector::on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr) availableSize.y = win->get_height() * deviceScale; int imW = rtengine::max(currImage->imgBuffer.getWidth(), 1); int imH = rtengine::max(currImage->imgBuffer.getHeight(), 1); - scale = rtengine::min(availableSize.x / imW, availableSize.y / imH); + scale = rtengine::min(1., rtengine::min(availableSize.x / imW, availableSize.y / imH)); if (scaled) { // reduce size of image to fit into window, no further zoom down zoomScale = rtengine::max(zoomScale, 1.0); From 77ea6d92cbfadc1a1c90cee5064dc78501c4d031 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 9 May 2021 12:31:26 -0700 Subject: [PATCH 18/27] Pin inspector whenever scrolling or zooming --- rtgui/inspector.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/rtgui/inspector.cc b/rtgui/inspector.cc index 0453564f9..675da51c6 100644 --- a/rtgui/inspector.cc +++ b/rtgui/inspector.cc @@ -277,6 +277,8 @@ bool Inspector::on_scroll_event(GdkEventScroll *event) if (!currImage || !window) return false; + pinned = true; + bool alt = event->state & GDK_MOD1_MASK; int deviceScale = get_scale_factor(); int imW = currImage->imgBuffer.getWidth(); @@ -381,6 +383,7 @@ void Inspector::beginZoom(double x, double y) void Inspector::on_zoom_begin(GdkEventSequence *s) { double x, y; + pinned = true; if (gestureZoom->get_point(s, x, y)) beginZoom(x, y); } From 76706ac2766d926d0df56d35c7ed400525f1917d Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sat, 22 May 2021 17:35:22 -0700 Subject: [PATCH 19/27] Leave spot removal widgets in good state on commit Set the correct geometry states if edit mode is toggled off while a spot is being dragged. --- rtgui/spot.cc | 20 ++++++++++++++++++++ rtgui/spot.h | 1 + 2 files changed, 21 insertions(+) diff --git a/rtgui/spot.cc b/rtgui/spot.cc index 322ffe106..7facb8f93 100644 --- a/rtgui/spot.cc +++ b/rtgui/spot.cc @@ -185,6 +185,25 @@ void Spot::resetPressed() } } +/** + * Release anything that's currently being dragged. + */ +void Spot::releaseEdit() +{ + Geometry *loGeom = getVisibleGeometryFromMO (lastObject); + + if (!loGeom) { + EditSubscriber::action = EditSubscriber::Action::NONE; + return; + } + + loGeom->state = Geometry::ACTIVE; + sourceIcon.state = Geometry::ACTIVE; + EditSubscriber::action = EditSubscriber::Action::NONE; + draggedSide = DraggedSide::NONE; + updateGeometry(); +} + void Spot::setBatchMode (bool batchMode) { ToolPanel::setBatchMode (batchMode); @@ -237,6 +256,7 @@ void Spot::editToggled () listener->refreshPreview(EvSpotEnabledOPA); // reprocess the preview w/o creating History entry subscribe(); } else { + releaseEdit(); unsubscribe(); listener->unsetTweakOperator(this); listener->refreshPreview(EvSpotEnabled); // reprocess the preview w/o creating History entry diff --git a/rtgui/spot.h b/rtgui/spot.h index db1fdac05..85cefa4c2 100644 --- a/rtgui/spot.h +++ b/rtgui/spot.h @@ -82,6 +82,7 @@ private: void addNewEntry (); void deleteSelectedEntry (); void resetPressed (); + void releaseEdit(); protected: Gtk::Box* labelBox; From a5de8920fba653ffc66919e9c2b46933a510e12a Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sat, 22 May 2021 17:51:54 -0700 Subject: [PATCH 20/27] Fix crash when resetting spot removal with drag Do not attempt to update non-existent spots immediately after resetting the spot removal tool. --- rtgui/spot.cc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/rtgui/spot.cc b/rtgui/spot.cc index 7facb8f93..9911a9595 100644 --- a/rtgui/spot.cc +++ b/rtgui/spot.cc @@ -172,6 +172,7 @@ void Spot::resetPressed() } } else { if (!spots.empty()) { + EditSubscriber::action = EditSubscriber::Action::NONE; spots.clear(); activeSpot = -1; lastObject = -1; @@ -657,6 +658,10 @@ bool Spot::button3Released() bool Spot::drag1 (int modifierKey) { + if (EditSubscriber::action != EditSubscriber::Action::DRAGGING) { + return false; + } + EditDataProvider *editProvider = getEditProvider(); int imW, imH; editProvider->getImageSize (imW, imH); @@ -738,6 +743,10 @@ bool Spot::drag1 (int modifierKey) bool Spot::drag3 (int modifierKey) { + if (EditSubscriber::action != EditSubscriber::Action::DRAGGING) { + return false; + } + EditDataProvider *editProvider = getEditProvider(); int imW, imH; editProvider->getImageSize (imW, imH); From 3ade11c970a48dcb0be4955c6fba7e2a8fd0869b Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sat, 22 May 2021 18:17:30 -0700 Subject: [PATCH 21/27] Leave control lines in good state on commit When exiting perspective control line editing mode while dragging a control line, set the geometry and control line state to the appropriate state corresponding to when lines are not being dragged. --- rtgui/controllines.cc | 18 ++++++++++++++++++ rtgui/controllines.h | 2 ++ rtgui/perspective.cc | 1 + 3 files changed, 21 insertions(+) diff --git a/rtgui/controllines.cc b/rtgui/controllines.cc index c078b4322..5918a75cb 100644 --- a/rtgui/controllines.cc +++ b/rtgui/controllines.cc @@ -199,6 +199,10 @@ bool ControlLineManager::pick3(bool picked) bool ControlLineManager::drag1(int modifierKey) { + if (action != Action::DRAGGING) { + return false; + } + EditDataProvider* provider = getEditProvider(); if (!provider || selected_object < 1) { @@ -263,6 +267,20 @@ bool ControlLineManager::drag1(int modifierKey) return false; } +void ControlLineManager::releaseEdit(void) +{ + action = Action::NONE; + + if (selected_object > 0) { + mouseOverGeometry[selected_object]->state = Geometry::NORMAL; + } + + edited = true; + callbacks->lineChanged(); + drawing_line = false; + selected_object = -1; +} + bool ControlLineManager::getEdited(void) const { return edited; diff --git a/rtgui/controllines.h b/rtgui/controllines.h index 2b2d179a4..a045eedd7 100644 --- a/rtgui/controllines.h +++ b/rtgui/controllines.h @@ -87,6 +87,8 @@ public: ~ControlLineManager(); bool getEdited(void) const; + /** Release anything that is currently being dragged. */ + void releaseEdit(void); void removeAll(void); /** Sets whether or not the lines are visible and interact-able. */ void setActive(bool active); diff --git a/rtgui/perspective.cc b/rtgui/perspective.cc index 8db91ee2e..fb4797ae4 100644 --- a/rtgui/perspective.cc +++ b/rtgui/perspective.cc @@ -778,6 +778,7 @@ void PerspCorrection::linesEditButtonPressed(void) listener->unsetTweakOperator(this); listener->refreshPreview(EvPerspRender); } + lines->releaseEdit(); lines->setDrawMode(false); lines->setActive(false); if (panel_listener) { From 4bc69dc30c2ae91394d281e65bda1d82d1b18c1a Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 23 May 2021 12:00:30 -0700 Subject: [PATCH 22/27] Leave gradient widget in good state on commit Stop highlighting the hovered or dragged geometry when disabling the widget. --- rtgui/gradient.cc | 14 ++++++++++++++ rtgui/gradient.h | 1 + 2 files changed, 15 insertions(+) diff --git a/rtgui/gradient.cc b/rtgui/gradient.cc index 972105dd0..cfe626ca7 100644 --- a/rtgui/gradient.cc +++ b/rtgui/gradient.cc @@ -325,6 +325,7 @@ void Gradient::editToggled () if (edit->get_active()) { subscribe(); } else { + releaseEdit(); unsubscribe(); } } @@ -579,6 +580,19 @@ bool Gradient::drag1(int modifierKey) return false; } +void Gradient::releaseEdit() +{ + if (lastObject >= 0) { + if (lastObject == 2 || lastObject == 3) { + EditSubscriber::visibleGeometry.at(2)->state = Geometry::NORMAL; + EditSubscriber::visibleGeometry.at(3)->state = Geometry::NORMAL; + } else { + EditSubscriber::visibleGeometry.at(lastObject)->state = Geometry::NORMAL; + } + } + action = Action::NONE; +} + void Gradient::switchOffEditMode () { if (edit->get_active()) { diff --git a/rtgui/gradient.h b/rtgui/gradient.h index 139b281a8..dc0371932 100644 --- a/rtgui/gradient.h +++ b/rtgui/gradient.h @@ -35,6 +35,7 @@ protected: sigc::connection editConn; void editToggled (); + void releaseEdit(); public: From 051d69331f1582e039f6cec2be298e7c209a9423 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 23 May 2021 12:10:40 -0700 Subject: [PATCH 23/27] Fix control line and spot removal spot highlight Return the geometry color to normal (white) when exiting edit mode. --- rtgui/controllines.cc | 3 +++ rtgui/spot.cc | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/rtgui/controllines.cc b/rtgui/controllines.cc index 5918a75cb..c08fbd1d2 100644 --- a/rtgui/controllines.cc +++ b/rtgui/controllines.cc @@ -274,6 +274,9 @@ void ControlLineManager::releaseEdit(void) if (selected_object > 0) { mouseOverGeometry[selected_object]->state = Geometry::NORMAL; } + if (prev_obj > 0) { + visibleGeometry[prev_obj - 1]->state = Geometry::NORMAL; + } edited = true; callbacks->lineChanged(); diff --git a/rtgui/spot.cc b/rtgui/spot.cc index 9911a9595..45fc3eec8 100644 --- a/rtgui/spot.cc +++ b/rtgui/spot.cc @@ -198,8 +198,8 @@ void Spot::releaseEdit() return; } - loGeom->state = Geometry::ACTIVE; - sourceIcon.state = Geometry::ACTIVE; + loGeom->state = Geometry::NORMAL; + sourceIcon.state = Geometry::NORMAL; EditSubscriber::action = EditSubscriber::Action::NONE; draggedSide = DraggedSide::NONE; updateGeometry(); From 56e634da81880e65ab9c8ff1605c717b9a2a1b32 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 23 May 2021 21:45:23 -0700 Subject: [PATCH 24/27] Improve control lines dragging behavior Fix control line not updating when dragging and allow dragging when starting with the mouse cursor outside the preview image area. --- rtgui/controllines.cc | 11 +++++++---- rtgui/cropwindow.cc | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/rtgui/controllines.cc b/rtgui/controllines.cc index c08fbd1d2..d321abd07 100644 --- a/rtgui/controllines.cc +++ b/rtgui/controllines.cc @@ -104,6 +104,9 @@ bool ControlLineManager::button1Pressed(int modifierKey) action = Action::DRAGGING; } } else if (draw_mode && (modifierKey & GDK_CONTROL_MASK)) { // Add new line. + if (object < 0) { + return false; + } addLine(dataProvider->posImage, dataProvider->posImage); drawing_line = true; selected_object = mouseOverGeometry.size() - 1; // Select endpoint. @@ -125,7 +128,7 @@ bool ControlLineManager::button1Released(void) callbacks->lineChanged(); drawing_line = false; selected_object = -1; - return false; + return true; } bool ControlLineManager::button3Pressed(int modifierKey) @@ -139,7 +142,7 @@ bool ControlLineManager::button3Pressed(int modifierKey) } action = Action::PICKING; - return false; + return true; } bool ControlLineManager::pick1(bool picked) @@ -194,7 +197,7 @@ bool ControlLineManager::pick3(bool picked) removeLine((provider->getObject() - 1) / ::ControlLine::OBJ_COUNT); prev_obj = -1; selected_object = -1; - return false; + return true; } bool ControlLineManager::drag1(int modifierKey) @@ -264,7 +267,7 @@ bool ControlLineManager::drag1(int modifierKey) autoSetLineType(selected_object); } - return false; + return true; } void ControlLineManager::releaseEdit(void) diff --git a/rtgui/cropwindow.cc b/rtgui/cropwindow.cc index 5a1debb23..b612de2e7 100644 --- a/rtgui/cropwindow.cc +++ b/rtgui/cropwindow.cc @@ -540,7 +540,7 @@ void CropWindow::buttonPress (int button, int type, int bstate, int x, int y) action_y = 0; } - } else if (iarea->getToolMode () == TMHand) { // events outside of the image domain + } else if (iarea->getToolMode () == TMHand || iarea->getToolMode() == TMPerspective) { // events outside of the image domain EditSubscriber *editSubscriber = iarea->getCurrSubscriber(); if (editSubscriber && editSubscriber->getEditingType() == ET_OBJECTS) { From 3441854a19e6776b19f62781b0c01f32edd67101 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 23 May 2021 22:01:01 -0700 Subject: [PATCH 25/27] Prevent making spot removal spots outside image --- rtgui/spot.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/rtgui/spot.cc b/rtgui/spot.cc index 45fc3eec8..16e8cf391 100644 --- a/rtgui/spot.cc +++ b/rtgui/spot.cc @@ -567,6 +567,12 @@ bool Spot::button1Pressed (int modifierKey) if (editProvider) { if (lastObject == -1 && (modifierKey & GDK_CONTROL_MASK)) { + int imW, imH; + const auto startPos = editProvider->posImage; + editProvider->getImageSize(imW, imH); + if (startPos.x < 0 || startPos.y < 0 || startPos.x > imW || startPos.y > imH) { + return false; // Outside of image area. + } draggedSide = DraggedSide::SOURCE; addNewEntry(); EditSubscriber::action = EditSubscriber::Action::DRAGGING; From 5f88cf240e6412e8f1c1b1817867d2761c1070ad Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 30 May 2021 11:51:49 -0700 Subject: [PATCH 26/27] Use enums for on-preview geometry --- rtgui/controllines.cc | 130 +++++++++++++++++++++++++++++++----------- rtgui/controllines.h | 9 ++- rtgui/gradient.cc | 76 +++++++++++++----------- rtgui/spot.cc | 104 +++++++++++++++++++++------------ 4 files changed, 212 insertions(+), 107 deletions(-) diff --git a/rtgui/controllines.cc b/rtgui/controllines.cc index d321abd07..14454e2ef 100644 --- a/rtgui/controllines.cc +++ b/rtgui/controllines.cc @@ -16,6 +16,7 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ +#include #include #include "controllines.h" @@ -27,6 +28,53 @@ using namespace rtengine; +enum GeometryIndex { + MO_CANVAS, + MO_OBJECT_COUNT, + + VISIBLE_OBJECT_COUNT = 0 +}; + +/** + * Offsets for mouse-over geometry that can be compared to the mouse-over object + * ID modded with the control line object count. + */ +enum GeometryOffset { + OFFSET_LINE = (MO_OBJECT_COUNT + ::ControlLine::LINE) % ::ControlLine::OBJECT_COUNT, + OFFSET_ICON = (MO_OBJECT_COUNT + ::ControlLine::ICON) % ::ControlLine::OBJECT_COUNT, + OFFSET_BEGIN = (MO_OBJECT_COUNT + ::ControlLine::BEGIN) % ::ControlLine::OBJECT_COUNT, + OFFSET_END = (MO_OBJECT_COUNT + ::ControlLine::END) % ::ControlLine::OBJECT_COUNT, +}; + +namespace +{ + +/** + * Returns true if the object matches the offset. + */ +constexpr bool checkOffset(int object_id, enum GeometryOffset offset) +{ + return object_id % ::ControlLine::OBJECT_COUNT == offset; +} + +/** + * Converts a control line mouse-over geometry ID to the visible geometry ID. + */ +constexpr int mouseOverIdToVisibleId(int mouse_over_id) +{ + return mouse_over_id - MO_OBJECT_COUNT + VISIBLE_OBJECT_COUNT; +} + +/** + * Converts a control line mouse-over geometry ID to the control line ID. + */ +constexpr int mouseOverIdToLineId(int mouse_over_id) +{ + return (mouse_over_id - MO_OBJECT_COUNT) / ::ControlLine::OBJECT_COUNT; +} + +} + ::ControlLine::~ControlLine() = default; ControlLineManager::ControlLineManager(): @@ -96,8 +144,8 @@ bool ControlLineManager::button1Pressed(int modifierKey) const int object = dataProvider->getObject(); - if (object > 0) { // A control line. - if (object % ::ControlLine::OBJ_COUNT == 2) { // Icon. + if (object >= MO_OBJECT_COUNT) { // A control line. + if (checkOffset(object, OFFSET_ICON)) { // Icon. action = Action::PICKING; } else { selected_object = object; @@ -109,7 +157,7 @@ bool ControlLineManager::button1Pressed(int modifierKey) } addLine(dataProvider->posImage, dataProvider->posImage); drawing_line = true; - selected_object = mouseOverGeometry.size() - 1; // Select endpoint. + selected_object = mouseOverGeometry.size() - ::ControlLine::OBJECT_COUNT + ::ControlLine::END; // Select endpoint. action = Action::DRAGGING; } @@ -120,7 +168,7 @@ bool ControlLineManager::button1Released(void) { action = Action::NONE; - if (selected_object > 0) { + if (selected_object >= MO_OBJECT_COUNT) { mouseOverGeometry[selected_object]->state = Geometry::NORMAL; } @@ -137,7 +185,7 @@ bool ControlLineManager::button3Pressed(int modifierKey) action = Action::NONE; - if (!provider || provider->getObject() < 1) { + if (!provider || provider->getObject() < MO_OBJECT_COUNT) { return false; } @@ -155,14 +203,13 @@ bool ControlLineManager::pick1(bool picked) EditDataProvider* provider = getEditProvider(); - if (!provider || provider->getObject() % ::ControlLine::OBJ_COUNT != 2) { + if (!provider || !checkOffset(provider->getObject(), OFFSET_ICON)) { return false; } // Change line type. int object_id = provider->getObject(); - ::ControlLine& line = - *control_lines[(object_id - 1) / ::ControlLine::OBJ_COUNT]; + ::ControlLine& line = *control_lines[mouseOverIdToLineId(object_id)]; if (line.type == rtengine::ControlLine::HORIZONTAL) { line.icon = line.icon_v; @@ -172,7 +219,7 @@ bool ControlLineManager::pick1(bool picked) line.type = rtengine::ControlLine::HORIZONTAL; } - visibleGeometry[object_id - 1] = line.icon.get(); + visibleGeometry[mouseOverIdToVisibleId(object_id)] = line.icon.get(); edited = true; callbacks->lineChanged(); @@ -194,7 +241,7 @@ bool ControlLineManager::pick3(bool picked) return false; } - removeLine((provider->getObject() - 1) / ::ControlLine::OBJ_COUNT); + removeLine(mouseOverIdToLineId(provider->getObject())); prev_obj = -1; selected_object = -1; return true; @@ -208,28 +255,28 @@ bool ControlLineManager::drag1(int modifierKey) EditDataProvider* provider = getEditProvider(); - if (!provider || selected_object < 1) { + if (!provider || selected_object < MO_OBJECT_COUNT) { return false; } ::ControlLine& control_line = - *control_lines[(selected_object - 1) / ::ControlLine::OBJ_COUNT]; + *control_lines[mouseOverIdToLineId(selected_object)]; // 0 == end, 1 == line, 2 == icon, 3 == begin - int component = selected_object % ::ControlLine::OBJ_COUNT; + int component = selected_object % ::ControlLine::OBJECT_COUNT; Coord mouse = provider->posImage + provider->deltaImage; Coord delta = provider->deltaImage - drag_delta; int ih, iw; provider->getImageSize(iw, ih); switch (component) { - case (0): // end + case (OFFSET_END): // end control_line.end->center = mouse; control_line.end->center.clip(iw, ih); control_line.line->end = control_line.end->center; control_line.end->state = Geometry::DRAGGED; break; - case (1): { // line + case (OFFSET_LINE): { // line // Constrain delta so the end stays above the image. Coord new_delta = control_line.end->center + delta; new_delta.clip(iw, ih); @@ -248,7 +295,7 @@ bool ControlLineManager::drag1(int modifierKey) break; } - case (3): // begin + case (OFFSET_BEGIN): // begin control_line.begin->center = mouse; control_line.begin->center.clip(iw, ih); control_line.line->begin = control_line.begin->center; @@ -274,11 +321,11 @@ void ControlLineManager::releaseEdit(void) { action = Action::NONE; - if (selected_object > 0) { + if (selected_object >= MO_OBJECT_COUNT) { mouseOverGeometry[selected_object]->state = Geometry::NORMAL; } - if (prev_obj > 0) { - visibleGeometry[prev_obj - 1]->state = Geometry::NORMAL; + if (prev_obj >= MO_OBJECT_COUNT) { + visibleGeometry[mouseOverIdToVisibleId(prev_obj)]->state = Geometry::NORMAL; } edited = true; @@ -307,7 +354,7 @@ bool ControlLineManager::mouseOver(int modifierKey) int cur_obj = provider->getObject(); - if (cur_obj == 0) { // Canvas + if (cur_obj == MO_CANVAS) { // Canvas if (draw_mode && modifierKey & GDK_CONTROL_MASK) { cursor = CSCrosshair; } else { @@ -315,16 +362,16 @@ bool ControlLineManager::mouseOver(int modifierKey) } } else if (cur_obj < 0) { // Nothing cursor = CSArrow; - } else if (cur_obj % ::ControlLine::OBJ_COUNT == 2) { // Icon - visibleGeometry[cur_obj - 1]->state = Geometry::PRELIGHT; + } else if (checkOffset(cur_obj, OFFSET_ICON)) { // Icon + visibleGeometry[mouseOverIdToVisibleId(cur_obj)]->state = Geometry::PRELIGHT; cursor = CSArrow; } else { // Object - visibleGeometry[cur_obj - 1]->state = Geometry::PRELIGHT; + visibleGeometry[mouseOverIdToVisibleId(cur_obj)]->state = Geometry::PRELIGHT; cursor = CSMove2D; } - if (prev_obj != cur_obj && prev_obj > 0) { - visibleGeometry[prev_obj - 1]->state = Geometry::NORMAL; + if (prev_obj != cur_obj && prev_obj >= MO_OBJECT_COUNT) { + visibleGeometry[mouseOverIdToVisibleId(prev_obj)]->state = Geometry::NORMAL; } prev_obj = cur_obj; @@ -418,14 +465,29 @@ void ControlLineManager::addLine(Coord begin, Coord end, control_line->line = std::move(line); control_line->type = type; + auto assertEqual = [](size_t a, int b) { + assert(b >= 0); + assert(a == static_cast(b)); + }; + + const int base_visible_offset = VISIBLE_OBJECT_COUNT + ::ControlLine::OBJECT_COUNT * control_lines.size(); + assertEqual(visibleGeometry.size(), base_visible_offset + ::ControlLine::LINE); EditSubscriber::visibleGeometry.push_back(control_line->line.get()); + assertEqual(visibleGeometry.size(), base_visible_offset + ::ControlLine::ICON); EditSubscriber::visibleGeometry.push_back(control_line->icon.get()); + assertEqual(visibleGeometry.size(), base_visible_offset + ::ControlLine::BEGIN); EditSubscriber::visibleGeometry.push_back(control_line->begin.get()); + assertEqual(visibleGeometry.size(), base_visible_offset + ::ControlLine::END); EditSubscriber::visibleGeometry.push_back(control_line->end.get()); + const int base_mo_count = MO_OBJECT_COUNT + ::ControlLine::OBJECT_COUNT * control_lines.size(); + assertEqual(mouseOverGeometry.size(), base_mo_count + ::ControlLine::LINE); EditSubscriber::mouseOverGeometry.push_back(control_line->line.get()); + assertEqual(mouseOverGeometry.size(), base_mo_count + ::ControlLine::ICON); EditSubscriber::mouseOverGeometry.push_back(control_line->icon.get()); + assertEqual(mouseOverGeometry.size(), base_mo_count + ::ControlLine::BEGIN); EditSubscriber::mouseOverGeometry.push_back(control_line->begin.get()); + assertEqual(mouseOverGeometry.size(), base_mo_count + ::ControlLine::END); EditSubscriber::mouseOverGeometry.push_back(control_line->end.get()); control_lines.push_back(std::move(control_line)); @@ -433,7 +495,7 @@ void ControlLineManager::addLine(Coord begin, Coord end, void ControlLineManager::autoSetLineType(int object_id) { - int line_id = (object_id - 1) / ::ControlLine::OBJ_COUNT; + int line_id = mouseOverIdToLineId(object_id); ::ControlLine& line = *control_lines[line_id]; int dx = line.begin->center.x - line.end->center.x; @@ -461,7 +523,8 @@ void ControlLineManager::autoSetLineType(int object_id) if (type != line.type) { // Need to update line type. line.type = type; line.icon = icon; - visibleGeometry[line_id * ::ControlLine::OBJ_COUNT + 1] = + visibleGeometry[line_id * ::ControlLine::OBJECT_COUNT ++ VISIBLE_OBJECT_COUNT + ::ControlLine::ICON] = line.icon.get(); } } @@ -469,7 +532,7 @@ void ControlLineManager::autoSetLineType(int object_id) void ControlLineManager::removeAll(void) { visibleGeometry.clear(); - mouseOverGeometry.erase(mouseOverGeometry.begin() + 1, + mouseOverGeometry.erase(mouseOverGeometry.begin() + MO_OBJECT_COUNT, mouseOverGeometry.end()); control_lines.clear(); prev_obj = -1; @@ -485,14 +548,13 @@ void ControlLineManager::removeLine(size_t line_id) } visibleGeometry.erase( - visibleGeometry.begin() + ::ControlLine::OBJ_COUNT * line_id, - visibleGeometry.begin() + ::ControlLine::OBJ_COUNT * line_id - + ::ControlLine::OBJ_COUNT + visibleGeometry.begin() + ::ControlLine::OBJECT_COUNT * line_id + VISIBLE_OBJECT_COUNT, + visibleGeometry.begin() + ::ControlLine::OBJECT_COUNT * line_id + VISIBLE_OBJECT_COUNT + + ::ControlLine::OBJECT_COUNT ); mouseOverGeometry.erase( - mouseOverGeometry.begin() + ::ControlLine::OBJ_COUNT * line_id + 1, - mouseOverGeometry.begin() + ::ControlLine::OBJ_COUNT * line_id - + ::ControlLine::OBJ_COUNT + 1 + mouseOverGeometry.begin() + ::ControlLine::OBJECT_COUNT * line_id + MO_OBJECT_COUNT, + mouseOverGeometry.begin() + ::ControlLine::OBJECT_COUNT * line_id + MO_OBJECT_COUNT + ::ControlLine::OBJECT_COUNT ); control_lines.erase(control_lines.begin() + line_id); diff --git a/rtgui/controllines.h b/rtgui/controllines.h index a045eedd7..a05fb8b00 100644 --- a/rtgui/controllines.h +++ b/rtgui/controllines.h @@ -30,7 +30,14 @@ class Rectangle; class RTSurface; struct ControlLine { - static constexpr int OBJ_COUNT = 4; + enum ObjectIndex { + LINE, + ICON, + BEGIN, + END, + OBJECT_COUNT + }; + std::unique_ptr line; std::shared_ptr icon; std::shared_ptr icon_h, icon_v; diff --git a/rtgui/gradient.cc b/rtgui/gradient.cc index cfe626ca7..af6503b45 100644 --- a/rtgui/gradient.cc +++ b/rtgui/gradient.cc @@ -12,6 +12,14 @@ using namespace rtengine; using namespace rtengine::procparams; +enum GeometryIndex { + H_LINE, + V_LINE, + FEATHER_LINE_1, + FEATHER_LINE_2, + CENTER_CIRCLE, +}; + Gradient::Gradient () : FoldableToolPanel(this, "gradient", M("TP_GRADIENT_LABEL"), false, true), EditSubscriber(ET_OBJECTS), lastObject(-1), draggedPointOldAngle(-1000.) { @@ -191,24 +199,24 @@ void Gradient::updateGeometry(const int centerX, const int centerY, const double }; // update horizontal line - updateLine (visibleGeometry.at(0), 1500., 0., 180.); - updateLine (mouseOverGeometry.at(0), 1500., 0., 180.); + updateLine (visibleGeometry.at(H_LINE), 1500., 0., 180.); + updateLine (mouseOverGeometry.at(H_LINE), 1500., 0., 180.); // update vertical line - updateLine (visibleGeometry.at(1), 700., 90., 270.); - updateLine (mouseOverGeometry.at(1), 700., 90., 270.); + updateLine (visibleGeometry.at(V_LINE), 700., 90., 270.); + updateLine (mouseOverGeometry.at(V_LINE), 700., 90., 270.); // update upper feather line - updateLineWithDecay (visibleGeometry.at(2), 350., 270.); - updateLineWithDecay (mouseOverGeometry.at(2), 350., 270.); + updateLineWithDecay (visibleGeometry.at(FEATHER_LINE_1), 350., 270.); + updateLineWithDecay (mouseOverGeometry.at(FEATHER_LINE_1), 350., 270.); // update lower feather line - updateLineWithDecay (visibleGeometry.at(3), 350., 90.); - updateLineWithDecay (mouseOverGeometry.at(3), 350., 90.); + updateLineWithDecay (visibleGeometry.at(FEATHER_LINE_2), 350., 90.); + updateLineWithDecay (mouseOverGeometry.at(FEATHER_LINE_2), 350., 90.); // update circle's position - updateCircle (visibleGeometry.at(4)); - updateCircle (mouseOverGeometry.at(4)); + updateCircle (visibleGeometry.at(CENTER_CIRCLE)); + updateCircle (mouseOverGeometry.at(CENTER_CIRCLE)); } void Gradient::write (ProcParams* pp, ParamsEdited* pedited) @@ -333,12 +341,12 @@ void Gradient::editToggled () CursorShape Gradient::getCursor(int objectID, int xPos, int yPos) const { switch (objectID) { - case (0): - case (1): + case (H_LINE): + case (V_LINE): return CSMoveRotate; - case (2): - case (3): { + case (FEATHER_LINE_1): + case (FEATHER_LINE_2): { int angle = degree->getIntValue(); if (angle < -135 || (angle >= -45 && angle <= 45) || angle > 135) { @@ -348,7 +356,7 @@ CursorShape Gradient::getCursor(int objectID, int xPos, int yPos) const return CSMove1DH; } - case (4): + case (CENTER_CIRCLE): return CSMove2D; default: @@ -362,18 +370,18 @@ bool Gradient::mouseOver(int modifierKey) if (editProvider && editProvider->getObject() != lastObject) { if (lastObject > -1) { - if (lastObject == 2 || lastObject == 3) { - EditSubscriber::visibleGeometry.at(2)->state = Geometry::NORMAL; - EditSubscriber::visibleGeometry.at(3)->state = Geometry::NORMAL; + if (lastObject == FEATHER_LINE_1 || lastObject == FEATHER_LINE_2) { + EditSubscriber::visibleGeometry.at(FEATHER_LINE_1)->state = Geometry::NORMAL; + EditSubscriber::visibleGeometry.at(FEATHER_LINE_2)->state = Geometry::NORMAL; } else { EditSubscriber::visibleGeometry.at(lastObject)->state = Geometry::NORMAL; } } if (editProvider->getObject() > -1) { - if (editProvider->getObject() == 2 || editProvider->getObject() == 3) { - EditSubscriber::visibleGeometry.at(2)->state = Geometry::PRELIGHT; - EditSubscriber::visibleGeometry.at(3)->state = Geometry::PRELIGHT; + if (editProvider->getObject() == FEATHER_LINE_1 || editProvider->getObject() == FEATHER_LINE_2) { + EditSubscriber::visibleGeometry.at(FEATHER_LINE_1)->state = Geometry::PRELIGHT; + EditSubscriber::visibleGeometry.at(FEATHER_LINE_2)->state = Geometry::PRELIGHT; } else { EditSubscriber::visibleGeometry.at(editProvider->getObject())->state = Geometry::PRELIGHT; } @@ -415,7 +423,7 @@ bool Gradient::button1Pressed(int modifierKey) //printf("\ndraggedPointOldAngle=%.3f\n\n", draggedPointOldAngle); draggedPointAdjusterAngle = degree->getValue(); - if (lastObject == 2 || lastObject == 3) { + if (lastObject == FEATHER_LINE_1 || lastObject == FEATHER_LINE_2) { // Dragging a line to change the angle PolarCoord draggedPoint; rtengine::Coord currPos; @@ -431,7 +439,7 @@ bool Gradient::button1Pressed(int modifierKey) // compute the projected value of the dragged point draggedFeatherOffset = draggedPoint.radius * sin((draggedPoint.angle - degree->getValue()) / 180.*rtengine::RT_PI); - if (lastObject == 3) { + if (lastObject == FEATHER_LINE_2) { draggedFeatherOffset = -draggedFeatherOffset; } @@ -442,9 +450,9 @@ bool Gradient::button1Pressed(int modifierKey) return false; } else { // should theoretically always be true // this will let this class ignore further drag events - if (lastObject == 2 || lastObject == 3) { - EditSubscriber::visibleGeometry.at(2)->state = Geometry::NORMAL; - EditSubscriber::visibleGeometry.at(3)->state = Geometry::NORMAL; + if (lastObject == FEATHER_LINE_1 || lastObject == FEATHER_LINE_2) { + EditSubscriber::visibleGeometry.at(FEATHER_LINE_1)->state = Geometry::NORMAL; + EditSubscriber::visibleGeometry.at(FEATHER_LINE_2)->state = Geometry::NORMAL; } else { EditSubscriber::visibleGeometry.at(lastObject)->state = Geometry::NORMAL; } @@ -472,7 +480,7 @@ bool Gradient::drag1(int modifierKey) double halfSizeW = imW / 2.; double halfSizeH = imH / 2.; - if (lastObject == 0 || lastObject == 1) { + if (lastObject == H_LINE || lastObject == V_LINE) { // Dragging a line to change the angle PolarCoord draggedPoint; @@ -516,7 +524,7 @@ bool Gradient::drag1(int modifierKey) return true; } - } else if (lastObject == 2 || lastObject == 3) { + } else if (lastObject == FEATHER_LINE_1 || lastObject == FEATHER_LINE_2) { // Dragging the upper or lower feather bar PolarCoord draggedPoint; rtengine::Coord currPos; @@ -533,11 +541,11 @@ bool Gradient::drag1(int modifierKey) draggedPoint = currPos - centerPos; double currDraggedFeatherOffset = draggedPoint.radius * sin((draggedPoint.angle - degree->getValue()) / 180.*rtengine::RT_PI); - if (lastObject == 2) + if (lastObject == FEATHER_LINE_1) // Dragging the upper feather bar { currDraggedFeatherOffset -= draggedFeatherOffset; - } else if (lastObject == 3) + } else if (lastObject == FEATHER_LINE_2) // Dragging the lower feather bar { currDraggedFeatherOffset = -currDraggedFeatherOffset + draggedFeatherOffset; @@ -555,7 +563,7 @@ bool Gradient::drag1(int modifierKey) return true; } - } else if (lastObject == 4) { + } else if (lastObject == CENTER_CIRCLE) { // Dragging the circle to change the center rtengine::Coord currPos; draggedCenter += provider->deltaPrevImage; @@ -583,9 +591,9 @@ bool Gradient::drag1(int modifierKey) void Gradient::releaseEdit() { if (lastObject >= 0) { - if (lastObject == 2 || lastObject == 3) { - EditSubscriber::visibleGeometry.at(2)->state = Geometry::NORMAL; - EditSubscriber::visibleGeometry.at(3)->state = Geometry::NORMAL; + if (lastObject == FEATHER_LINE_1 || lastObject == FEATHER_LINE_2) { + EditSubscriber::visibleGeometry.at(FEATHER_LINE_1)->state = Geometry::NORMAL; + EditSubscriber::visibleGeometry.at(FEATHER_LINE_2)->state = Geometry::NORMAL; } else { EditSubscriber::visibleGeometry.at(lastObject)->state = Geometry::NORMAL; } diff --git a/rtgui/spot.cc b/rtgui/spot.cc index 16e8cf391..3845751c9 100644 --- a/rtgui/spot.cc +++ b/rtgui/spot.cc @@ -29,8 +29,23 @@ using namespace rtengine; using namespace rtengine::procparams; -#define STATIC_VISIBLE_OBJ_NBR 6 -#define STATIC_MO_OBJ_NBR 6 +enum GeometryIndex { + MO_TARGET_DISK, + MO_SOURCE_DISC, + MO_TARGET_CIRCLE, + MO_SOURCE_CIRCLE, + MO_TARGET_FEATHER_CIRCLE, + MO_SOURCE_FEATHER_CIRCLE, + MO_OBJECT_COUNT, + + VISIBLE_SOURCE_ICON = 0, + VISIBLE_SOURCE_FEATHER_CIRCLE, + VISIBLE_LINK, + VISIBLE_SOURCE_CIRCLE, + VISIBLE_TARGET_FEATHER_CIRCLE, + VISIBLE_TARGET_CIRCLE, + VISIBLE_OBJECT_COUNT +}; Spot::Spot() : FoldableToolPanel(this, "spot", M ("TP_SPOT_LABEL"), true, true), @@ -106,7 +121,7 @@ Spot::~Spot() { // delete all dynamically allocated geometry if (EditSubscriber::visibleGeometry.size()) { - for (size_t i = 0; i < EditSubscriber::visibleGeometry.size() - STATIC_VISIBLE_OBJ_NBR; ++i) { // static visible geometry at the end if the list + for (size_t i = 0; i < EditSubscriber::visibleGeometry.size() - VISIBLE_OBJECT_COUNT; ++i) { // static visible geometry at the end of the list delete EditSubscriber::visibleGeometry.at (i); } } @@ -271,16 +286,16 @@ Geometry* Spot::getVisibleGeometryFromMO (int MOID) return nullptr; } - if (MOID == 0) { + if (MOID == MO_TARGET_DISK) { return getActiveSpotIcon(); } - if (MOID == 1) { // sourceMODisc + if (MOID == MO_SOURCE_DISC) { return &sourceIcon; } - if (MOID > STATIC_MO_OBJ_NBR) { - return EditSubscriber::visibleGeometry.at(MOID - STATIC_MO_OBJ_NBR); + if (MOID > MO_OBJECT_COUNT) { + return EditSubscriber::visibleGeometry.at(MOID - MO_OBJECT_COUNT); } return EditSubscriber::mouseOverGeometry.at (MOID); @@ -296,30 +311,36 @@ void Spot::createGeometry () //printf("CreateGeometry(%d)\n", nbrEntry); // delete all dynamically allocated geometry - if (EditSubscriber::visibleGeometry.size() > STATIC_VISIBLE_OBJ_NBR) - for (size_t i = 0; i < EditSubscriber::visibleGeometry.size() - STATIC_VISIBLE_OBJ_NBR; ++i) { // static visible geometry at the end if the list + if (EditSubscriber::visibleGeometry.size() > VISIBLE_OBJECT_COUNT) + for (size_t i = 0; i < EditSubscriber::visibleGeometry.size() - VISIBLE_OBJECT_COUNT; ++i) { // static visible geometry at the end of the list delete EditSubscriber::visibleGeometry.at (i); } // mouse over geometry starts with the static geometry, then the spot's icon geometry - EditSubscriber::mouseOverGeometry.resize (STATIC_MO_OBJ_NBR + nbrEntry); + EditSubscriber::mouseOverGeometry.resize (MO_OBJECT_COUNT + nbrEntry); // visible geometry starts with the spot's icon geometry, then the static geometry - EditSubscriber::visibleGeometry.resize (nbrEntry + STATIC_VISIBLE_OBJ_NBR); + EditSubscriber::visibleGeometry.resize (nbrEntry + VISIBLE_OBJECT_COUNT); size_t i = 0, j = 0; - EditSubscriber::mouseOverGeometry.at (i++) = &targetMODisc; // STATIC_MO_OBJ_NBR + 0 - EditSubscriber::mouseOverGeometry.at (i++) = &sourceMODisc; // STATIC_MO_OBJ_NBR + 1 - EditSubscriber::mouseOverGeometry.at (i++) = &targetCircle; // STATIC_MO_OBJ_NBR + 2 - EditSubscriber::mouseOverGeometry.at (i++) = &sourceCircle; // STATIC_MO_OBJ_NBR + 3 - EditSubscriber::mouseOverGeometry.at (i++) = &targetFeatherCircle; // STATIC_MO_OBJ_NBR + 4 - EditSubscriber::mouseOverGeometry.at (i++) = &sourceFeatherCircle; // STATIC_MO_OBJ_NBR + 5 + assert(i == MO_TARGET_DISK); + EditSubscriber::mouseOverGeometry.at (i++) = &targetMODisc; // MO_OBJECT_COUNT + 0 + assert(i == MO_SOURCE_DISC); + EditSubscriber::mouseOverGeometry.at (i++) = &sourceMODisc; // MO_OBJECT_COUNT + 1 + assert(i == MO_TARGET_CIRCLE); + EditSubscriber::mouseOverGeometry.at (i++) = &targetCircle; // MO_OBJECT_COUNT + 2 + assert(i == MO_SOURCE_CIRCLE); + EditSubscriber::mouseOverGeometry.at (i++) = &sourceCircle; // MO_OBJECT_COUNT + 3 + assert(i == MO_TARGET_FEATHER_CIRCLE); + EditSubscriber::mouseOverGeometry.at (i++) = &targetFeatherCircle; // MO_OBJECT_COUNT + 4 + assert(i == MO_SOURCE_FEATHER_CIRCLE); + EditSubscriber::mouseOverGeometry.at (i++) = &sourceFeatherCircle; // MO_OBJECT_COUNT + 5 // recreate all spots geometry Cairo::RefPtr normalImg = sourceIcon.getNormalImg(); Cairo::RefPtr prelightImg = sourceIcon.getPrelightImg(); Cairo::RefPtr activeImg = sourceIcon.getActiveImg(); - for (; j < EditSubscriber::visibleGeometry.size() - STATIC_VISIBLE_OBJ_NBR; ++i, ++j) { + for (; j < EditSubscriber::visibleGeometry.size() - VISIBLE_OBJECT_COUNT; ++i, ++j) { EditSubscriber::mouseOverGeometry.at (i) = EditSubscriber::visibleGeometry.at (j) = new OPIcon (normalImg, activeImg, prelightImg, Cairo::RefPtr (nullptr), Cairo::RefPtr (nullptr), Geometry::DP_CENTERCENTER); EditSubscriber::visibleGeometry.at (j)->setActive (true); EditSubscriber::visibleGeometry.at (j)->datum = Geometry::IMAGE; @@ -327,12 +348,19 @@ void Spot::createGeometry () //printf("mouseOverGeometry.at(%d) = %p\n", (unsigned int)i, (void*)EditSubscriber::mouseOverGeometry.at(i)); } - EditSubscriber::visibleGeometry.at (j++) = &sourceIcon; // STATIC_VISIBLE_OBJ_NBR + 0 - EditSubscriber::visibleGeometry.at (j++) = &sourceFeatherCircle; // STATIC_VISIBLE_OBJ_NBR + 1 - EditSubscriber::visibleGeometry.at (j++) = &link; // STATIC_VISIBLE_OBJ_NBR + 2 - EditSubscriber::visibleGeometry.at (j++) = &sourceCircle; // STATIC_VISIBLE_OBJ_NBR + 3 - EditSubscriber::visibleGeometry.at (j++) = &targetFeatherCircle; // STATIC_VISIBLE_OBJ_NBR + 4 - EditSubscriber::visibleGeometry.at (j++) = &targetCircle; // STATIC_VISIBLE_OBJ_NBR + 5 + int visibleOffset = j; + assert(j - visibleOffset == VISIBLE_SOURCE_ICON); + EditSubscriber::visibleGeometry.at (j++) = &sourceIcon; // VISIBLE_OBJECT_COUNT + 0 + assert(j - visibleOffset == VISIBLE_SOURCE_FEATHER_CIRCLE); + EditSubscriber::visibleGeometry.at (j++) = &sourceFeatherCircle; // VISIBLE_OBJECT_COUNT + 1 + assert(j - visibleOffset == VISIBLE_LINK); + EditSubscriber::visibleGeometry.at (j++) = &link; // VISIBLE_OBJECT_COUNT + 2 + assert(j - visibleOffset == VISIBLE_SOURCE_CIRCLE); + EditSubscriber::visibleGeometry.at (j++) = &sourceCircle; // VISIBLE_OBJECT_COUNT + 3 + assert(j - visibleOffset == VISIBLE_TARGET_FEATHER_CIRCLE); + EditSubscriber::visibleGeometry.at (j++) = &targetFeatherCircle; // VISIBLE_OBJECT_COUNT + 4 + assert(j - visibleOffset == VISIBLE_TARGET_CIRCLE); + EditSubscriber::visibleGeometry.at (j++) = &targetCircle; // VISIBLE_OBJECT_COUNT + 5 } void Spot::updateGeometry() @@ -440,7 +468,7 @@ void Spot::addNewEntry() se.sourcePos = se.targetPos; spots.push_back (se); // this make a copy of se ... activeSpot = spots.size() - 1; - lastObject = 1; + lastObject = MO_SOURCE_DISC; //printf("ActiveSpot = %d\n", activeSpot); @@ -487,11 +515,11 @@ CursorShape Spot::getCursor (int objectID, int xPos, int yPos) const return CSEmpty; } - if (objectID == 0 || objectID == 1) { + if (objectID == MO_TARGET_DISK || objectID == MO_SOURCE_DISC) { return CSMove2D; } - if (objectID >= 2 && objectID <= 5) { - Coord delta(Coord(xPos, yPos) - ((objectID == 3 || objectID == 5) ? spots.at(activeSpot).sourcePos : spots.at(activeSpot).targetPos)); + if (objectID >= MO_TARGET_CIRCLE && objectID <= MO_SOURCE_FEATHER_CIRCLE) { + Coord delta(Coord(xPos, yPos) - ((objectID == MO_SOURCE_CIRCLE || objectID == MO_SOURCE_FEATHER_CIRCLE) ? spots.at(activeSpot).sourcePos : spots.at(activeSpot).targetPos)); PolarCoord polarPos(delta); if (polarPos.angle < 0.) { polarPos.angle += 180.; @@ -529,19 +557,19 @@ bool Spot::mouseOver (int modifierKey) if (editProvider->getObject() > -1) { getVisibleGeometryFromMO (editProvider->getObject())->state = Geometry::PRELIGHT; - if (editProvider->getObject() >= STATIC_MO_OBJ_NBR) { + if (editProvider->getObject() >= MO_OBJECT_COUNT) { // a Spot is being edited int oldActiveSpot = activeSpot; - activeSpot = editProvider->getObject() - STATIC_MO_OBJ_NBR; + activeSpot = editProvider->getObject() - MO_OBJECT_COUNT; if (activeSpot != oldActiveSpot) { if (oldActiveSpot > -1) { EditSubscriber::visibleGeometry.at (oldActiveSpot)->state = Geometry::NORMAL; - EditSubscriber::mouseOverGeometry.at (oldActiveSpot + STATIC_MO_OBJ_NBR)->state = Geometry::NORMAL; + EditSubscriber::mouseOverGeometry.at (oldActiveSpot + MO_OBJECT_COUNT)->state = Geometry::NORMAL; } EditSubscriber::visibleGeometry.at (activeSpot)->state = Geometry::PRELIGHT; - EditSubscriber::mouseOverGeometry.at (activeSpot + STATIC_MO_OBJ_NBR)->state = Geometry::PRELIGHT; + EditSubscriber::mouseOverGeometry.at (activeSpot + MO_OBJECT_COUNT)->state = Geometry::PRELIGHT; //printf("ActiveSpot = %d (was %d before)\n", activeSpot, oldActiveSpot); } } @@ -550,7 +578,7 @@ bool Spot::mouseOver (int modifierKey) lastObject = editProvider->getObject(); if (lastObject > -1 && EditSubscriber::mouseOverGeometry.at (lastObject) == getActiveSpotIcon()) { - lastObject = 0; // targetMODisc + lastObject = MO_TARGET_DISK; } updateGeometry(); @@ -578,7 +606,7 @@ bool Spot::button1Pressed (int modifierKey) EditSubscriber::action = EditSubscriber::Action::DRAGGING; return true; } else if (lastObject > -1) { - draggedSide = lastObject == 0 ? DraggedSide::TARGET : lastObject == 1 ? DraggedSide::SOURCE : DraggedSide::NONE; + draggedSide = lastObject == MO_TARGET_DISK ? DraggedSide::TARGET : lastObject == MO_SOURCE_DISC ? DraggedSide::SOURCE : DraggedSide::NONE; getVisibleGeometryFromMO (lastObject)->state = Geometry::DRAGGED; EditSubscriber::action = EditSubscriber::Action::DRAGGING; return true; @@ -630,8 +658,8 @@ bool Spot::button3Pressed (int modifierKey) return false; } - if ((modifierKey & GDK_CONTROL_MASK) && (EditSubscriber::mouseOverGeometry.at (lastObject) == &targetMODisc || lastObject >= STATIC_MO_OBJ_NBR)) { - lastObject = 1; // sourceMODisc + if ((modifierKey & GDK_CONTROL_MASK) && (EditSubscriber::mouseOverGeometry.at (lastObject) == &targetMODisc || lastObject >= MO_OBJECT_COUNT)) { + lastObject = MO_SOURCE_DISC; sourceIcon.state = Geometry::DRAGGED; EditSubscriber::action = EditSubscriber::Action::DRAGGING; draggedSide = DraggedSide::SOURCE; @@ -687,8 +715,8 @@ bool Spot::drag1 (int modifierKey) modified = true; } - EditSubscriber::mouseOverGeometry.at (activeSpot + STATIC_MO_OBJ_NBR)->state = Geometry::DRAGGED; - } else if (loGeom == &targetMODisc || lastObject >= STATIC_MO_OBJ_NBR) { + EditSubscriber::mouseOverGeometry.at (activeSpot + MO_OBJECT_COUNT)->state = Geometry::DRAGGED; + } else if (loGeom == &targetMODisc || lastObject >= MO_OBJECT_COUNT) { //printf("targetMODisc / deltaPrevImage = %d / %d\n", editProvider->deltaPrevImage.x, editProvider->deltaPrevImage.y); rtengine::Coord currPos = spots.at (activeSpot).targetPos; spots.at (activeSpot).targetPos += editProvider->deltaPrevImage; From 3c7e20b6897baffc3c88e16a2bcccf07e3974521 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 30 May 2021 12:05:51 -0700 Subject: [PATCH 27/27] Refactor rtgui/spot.cc --- rtgui/spot.cc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/rtgui/spot.cc b/rtgui/spot.cc index 3845751c9..d9a6be6b7 100644 --- a/rtgui/spot.cc +++ b/rtgui/spot.cc @@ -208,14 +208,14 @@ void Spot::releaseEdit() { Geometry *loGeom = getVisibleGeometryFromMO (lastObject); + EditSubscriber::action = EditSubscriber::Action::NONE; + if (!loGeom) { - EditSubscriber::action = EditSubscriber::Action::NONE; return; } loGeom->state = Geometry::NORMAL; sourceIcon.state = Geometry::NORMAL; - EditSubscriber::action = EditSubscriber::Action::NONE; draggedSide = DraggedSide::NONE; updateGeometry(); } @@ -686,8 +686,6 @@ bool Spot::button3Released() updateGeometry(); EditSubscriber::action = EditSubscriber::Action::NONE; return true; - - return false; } bool Spot::drag1 (int modifierKey)