Re-add inspector tab as an option (#5867)
- add option "inspectorWindow" to switch from tab to fullscreen view - add option "zoomOnScroll" to configure scroll device for zoom or pan - add both options to preferences - filepanel creates tab if not inspectorWindow - inspector adapts to settings inspectorWindow and zoomOnScroll - filebrowser shows context menu item for inspector only if inspectorWindow
This commit is contained in:
@@ -85,39 +85,57 @@ InspectorBuffer::~InspectorBuffer() {
|
||||
Inspector::Inspector () : currImage(nullptr), scaled(false), scale(1.0), zoomScale(1.0), zoomScaleBegin(1.0), active(false), pinned(false), dirty(false)
|
||||
{
|
||||
set_name("Inspector");
|
||||
window.set_visible(false);
|
||||
window.set_title("RawTherapee Inspector");
|
||||
|
||||
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));
|
||||
if (!options.inspectorWindow) {
|
||||
window = nullptr;
|
||||
}
|
||||
else {
|
||||
window = new Gtk::Window();
|
||||
window->set_title("RawTherapee Inspector");
|
||||
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));
|
||||
window->signal_key_press_event().connect(sigc::mem_fun(*this, &Inspector::on_key_press));
|
||||
|
||||
add_events(Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_MOTION_MASK | Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK);
|
||||
gestureZoom = Gtk::GestureZoom::create(*this);
|
||||
gestureZoom->signal_begin().connect(sigc::mem_fun(*this, &Inspector::on_zoom_begin));
|
||||
gestureZoom->signal_scale_changed().connect(sigc::mem_fun(*this, &Inspector::on_zoom_scale_changed));
|
||||
add_events(Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_MOTION_MASK | Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK);
|
||||
gestureZoom = Gtk::GestureZoom::create(*this);
|
||||
gestureZoom->signal_begin().connect(sigc::mem_fun(*this, &Inspector::on_zoom_begin));
|
||||
gestureZoom->signal_scale_changed().connect(sigc::mem_fun(*this, &Inspector::on_zoom_scale_changed));
|
||||
|
||||
window.add(*this);
|
||||
window.set_size_request(400, 400);
|
||||
window.show_all();
|
||||
window.set_visible(false);
|
||||
active = true; // always track inspected thumbnails
|
||||
window->add(*this);
|
||||
window->set_size_request(500, 500);
|
||||
initialized = false; // delay init to avoid flickering on some systems
|
||||
active = true; // always track inspected thumbnails
|
||||
}
|
||||
}
|
||||
|
||||
Inspector::~Inspector()
|
||||
{
|
||||
deleteBuffers();
|
||||
if (window)
|
||||
delete window;
|
||||
}
|
||||
|
||||
void Inspector::showWindow(bool scaled, bool fullscreen)
|
||||
{
|
||||
if (!window)
|
||||
return;
|
||||
|
||||
// initialize when shown first
|
||||
if (!initialized) {
|
||||
window->show_all();
|
||||
window->set_visible(false);
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
// show inspector window
|
||||
this->scaled = scaled;
|
||||
if (fullscreen)
|
||||
window.fullscreen();
|
||||
window->fullscreen();
|
||||
else
|
||||
window.unfullscreen();
|
||||
window->unfullscreen();
|
||||
this->fullscreen = fullscreen;
|
||||
window.set_visible(true);
|
||||
window->set_visible(true);
|
||||
pinned = false;
|
||||
|
||||
// update content when becoming visible
|
||||
@@ -127,12 +145,15 @@ void Inspector::showWindow(bool scaled, bool fullscreen)
|
||||
|
||||
bool Inspector::on_key_release(GdkEventKey *event)
|
||||
{
|
||||
if (!window)
|
||||
return false;
|
||||
|
||||
if (!pinned) {
|
||||
switch (event->keyval) {
|
||||
case GDK_KEY_f:
|
||||
case GDK_KEY_F:
|
||||
zoomScale = 1.0;
|
||||
window.set_visible(false);
|
||||
window->set_visible(false);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -141,6 +162,9 @@ bool Inspector::on_key_release(GdkEventKey *event)
|
||||
|
||||
bool Inspector::on_key_press(GdkEventKey *event)
|
||||
{
|
||||
if (!window)
|
||||
return false;
|
||||
|
||||
switch (event->keyval) {
|
||||
case GDK_KEY_z:
|
||||
case GDK_KEY_F:
|
||||
@@ -160,15 +184,15 @@ bool Inspector::on_key_press(GdkEventKey *event)
|
||||
case GDK_KEY_F11:
|
||||
// toggle fullscreen
|
||||
if (fullscreen)
|
||||
window.unfullscreen();
|
||||
window->unfullscreen();
|
||||
else
|
||||
window.fullscreen();
|
||||
window->fullscreen();
|
||||
fullscreen = !fullscreen;
|
||||
return true;
|
||||
case GDK_KEY_Escape:
|
||||
// hide window
|
||||
zoomScale = 1.0;
|
||||
window.set_visible(false);
|
||||
window->set_visible(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -177,6 +201,9 @@ bool Inspector::on_key_press(GdkEventKey *event)
|
||||
|
||||
bool Inspector::on_button_press_event(GdkEventButton *event)
|
||||
{
|
||||
if (!window)
|
||||
return false;
|
||||
|
||||
if (event->type == GDK_BUTTON_PRESS) {
|
||||
button_pos.set(event->x, event->y);
|
||||
if (!pinned)
|
||||
@@ -189,7 +216,7 @@ bool Inspector::on_button_press_event(GdkEventButton *event)
|
||||
|
||||
bool Inspector::on_motion_notify_event(GdkEventMotion *event)
|
||||
{
|
||||
if (!currImage)
|
||||
if (!currImage || !window)
|
||||
return false;
|
||||
|
||||
int deviceScale = get_scale_factor();
|
||||
@@ -211,7 +238,7 @@ bool Inspector::on_motion_notify_event(GdkEventMotion *event)
|
||||
|
||||
bool Inspector::on_scroll_event(GdkEventScroll *event)
|
||||
{
|
||||
if (!currImage)
|
||||
if (!currImage || !window)
|
||||
return false;
|
||||
|
||||
bool alt = event->state & GDK_MOD1_MASK;
|
||||
@@ -244,23 +271,19 @@ bool Inspector::on_scroll_event(GdkEventScroll *event)
|
||||
break;
|
||||
case GDK_SCROLL_DOWN:
|
||||
delta_y = step_y * deviceScale * imH / 100;
|
||||
alt = true; // zoom for non smooth scroll events (scroll wheel)
|
||||
break;
|
||||
case GDK_SCROLL_UP:
|
||||
delta_y = -step_y * deviceScale * imH / 100;
|
||||
alt = true; // zoom for non smooth scroll events (scroll wheel)
|
||||
break;
|
||||
case GDK_SCROLL_LEFT:
|
||||
delta_x = step_x * deviceScale * imW / 100;
|
||||
alt = true; // zoom for non smooth scroll events (scroll wheel)
|
||||
break;
|
||||
case GDK_SCROLL_RIGHT:
|
||||
delta_x = -step_x * deviceScale * imW / 100;
|
||||
alt = true; // zoom for non smooth scroll events (scroll wheel)
|
||||
break;
|
||||
}
|
||||
|
||||
if (alt) {
|
||||
if ((options.zoomOnScroll && !alt) || (!options.zoomOnScroll && alt)) {
|
||||
// zoom
|
||||
beginZoom(event->x, event->y);
|
||||
if (std::fabs(delta_y) > std::fabs(delta_x))
|
||||
@@ -284,15 +307,15 @@ bool Inspector::on_scroll_event(GdkEventScroll *event)
|
||||
void Inspector::moveCenter(int delta_x, int delta_y, int imW, int imH, int deviceScale)
|
||||
{
|
||||
rtengine::Coord margin; // limit to image size
|
||||
margin.x = rtengine::min<int>(window.get_width() * deviceScale / scale, imW) / 2;
|
||||
margin.y = rtengine::min<int>(window.get_height() * deviceScale / scale, imH) / 2;
|
||||
margin.x = rtengine::min<int>(window->get_width() * deviceScale / scale, imW) / 2;
|
||||
margin.y = rtengine::min<int>(window->get_height() * deviceScale / scale, imH) / 2;
|
||||
center.set(rtengine::LIM<int>(center.x + delta_x, margin.x, imW - margin.x),
|
||||
rtengine::LIM<int>(center.y + delta_y, margin.y, imH - margin.y));
|
||||
}
|
||||
|
||||
void Inspector::beginZoom(double x, double y)
|
||||
{
|
||||
if (!currImage)
|
||||
if (!currImage || !window)
|
||||
return;
|
||||
|
||||
int deviceScale = get_scale_factor();
|
||||
@@ -303,8 +326,8 @@ 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;
|
||||
dcenterBegin.x = (x - window->get_width()/2) / scale * deviceScale;
|
||||
dcenterBegin.y = (y - window->get_height()/2) / scale * deviceScale;
|
||||
centerBegin = center;
|
||||
zoomScaleBegin = zoomScale;
|
||||
|
||||
@@ -319,7 +342,7 @@ void Inspector::on_zoom_begin(GdkEventSequence *s)
|
||||
|
||||
void Inspector::on_zoom_scale_changed(double zscale)
|
||||
{
|
||||
if (!currImage)
|
||||
if (!currImage || !window)
|
||||
return;
|
||||
|
||||
zoomScale = rtengine::LIM<double>(zoomScaleBegin * zscale, 0.01, 16.0);
|
||||
@@ -358,7 +381,7 @@ bool Inspector::on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr)
|
||||
rtengine::Coord availableSize;
|
||||
rtengine::Coord topLeft;
|
||||
rtengine::Coord dest(0, 0);
|
||||
int deviceScale = get_scale_factor();
|
||||
int deviceScale = window? get_scale_factor(): 1;
|
||||
availableSize.x = win->get_width() * deviceScale;
|
||||
availableSize.y = win->get_height() * deviceScale;
|
||||
int imW = rtengine::max<int>(currImage->imgBuffer.getWidth(), 1);
|
||||
@@ -417,19 +440,22 @@ bool Inspector::on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr)
|
||||
Gdk::RGBA c;
|
||||
Glib::RefPtr<Gtk::StyleContext> style = get_style_context();
|
||||
|
||||
// draw the background
|
||||
//style->render_background(cr, 0, 0, get_width(), get_height());
|
||||
|
||||
///* --- 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 ();
|
||||
//*/
|
||||
if (!window) {
|
||||
// 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 (deviceScale == 1 && !scaledImage) {
|
||||
if (!window || (deviceScale == 1 && !scaledImage)) {
|
||||
// standard drawing
|
||||
currImage->imgBuffer.copySurface(win);
|
||||
}
|
||||
@@ -454,14 +480,14 @@ bool Inspector::on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr)
|
||||
cr->paint();
|
||||
}
|
||||
|
||||
/* --- not for separate window
|
||||
// draw the frame
|
||||
c = style->get_border_color (Gtk::STATE_FLAG_NORMAL);
|
||||
cr->set_source_rgb (c.get_red(), c.get_green(), c.get_blue());
|
||||
cr->set_line_width (1);
|
||||
cr->rectangle (0.5, 0.5, availableSize.x - 1, availableSize.y - 1);
|
||||
cr->stroke ();
|
||||
*/
|
||||
if (!window) {
|
||||
// draw the frame
|
||||
c = style->get_border_color (Gtk::STATE_FLAG_NORMAL);
|
||||
cr->set_source_rgb (c.get_red(), c.get_green(), c.get_blue());
|
||||
cr->set_line_width (1);
|
||||
cr->rectangle (0.5, 0.5, availableSize.x - 1, availableSize.y - 1);
|
||||
cr->stroke ();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -476,7 +502,7 @@ void Inspector::mouseMove (rtengine::Coord2D pos, int transform)
|
||||
next_image_pos = pos;
|
||||
|
||||
// skip actual update of content when not visible
|
||||
if (!window.get_visible())
|
||||
if (window && !window->get_visible())
|
||||
return;
|
||||
|
||||
if (currImage) {
|
||||
@@ -501,7 +527,7 @@ void Inspector::switchImage (const Glib::ustring &fullPath)
|
||||
next_image_path = fullPath;
|
||||
|
||||
// skip actual update of content when not visible
|
||||
if (!window.get_visible())
|
||||
if (window && !window->get_visible())
|
||||
return;
|
||||
|
||||
if (!options.inspectorDelay) {
|
||||
@@ -601,7 +627,8 @@ void Inspector::setActive(bool state)
|
||||
flushBuffers();
|
||||
}
|
||||
|
||||
//active = state;
|
||||
if (!window)
|
||||
active = state;
|
||||
}
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user