merge with dev

This commit is contained in:
Desmis 2020-07-28 20:46:56 +02:00
commit e07d142749
5 changed files with 281 additions and 16 deletions

View File

@ -15,6 +15,7 @@ Development contributors, in last name alphabetical order:
Maciek Dworak
Michael Ezra
Flössie
Rüdiger Franke
Jean-Christophe Frisch
Ilias Giarimis
Alberto Griggio

View File

@ -42,6 +42,7 @@
#include "pathutils.h"
#include "thumbnail.h"
#include "toolbar.h"
#include "inspector.h"
using namespace std;
@ -2508,6 +2509,15 @@ bool FileCatalog::handleShortcutKey (GdkEventKey* event)
}
}
if (!ctrl && !alt) {
switch (event->keyval) {
case GDK_KEY_f:
case GDK_KEY_F:
fileBrowser->getInspector()->showWindow(!shift);
return true;
}
}
return fileBrowser->keyPressed(event);
}

View File

@ -115,9 +115,9 @@ FilePanel::FilePanel () : parent(nullptr), error(0)
Gtk::Label* devLab = Gtk::manage ( new Gtk::Label (M("MAIN_TAB_DEVELOP")) );
devLab->set_name ("LabelRightNotebook");
devLab->set_angle (90);
Gtk::Label* inspectLab = Gtk::manage ( new Gtk::Label (M("MAIN_TAB_INSPECT")) );
inspectLab->set_name ("LabelRightNotebook");
inspectLab->set_angle (90);
//Gtk::Label* inspectLab = Gtk::manage ( new Gtk::Label (M("MAIN_TAB_INSPECT")) );
//inspectLab->set_name ("LabelRightNotebook");
//inspectLab->set_angle (90);
Gtk::Label* filtLab = Gtk::manage ( new Gtk::Label (M("MAIN_TAB_FILTER")) );
filtLab->set_name ("LabelRightNotebook");
filtLab->set_angle (90);
@ -132,7 +132,7 @@ FilePanel::FilePanel () : parent(nullptr), error(0)
tpcPaned->pack2 (*history, true, false);
rightNotebook->append_page (*sFilterPanel, *filtLab);
rightNotebook->append_page (*inspectorPanel, *inspectLab);
//rightNotebook->append_page (*inspectorPanel, *inspectLab);
rightNotebook->append_page (*tpcPaned, *devLab);
//rightNotebook->append_page (*taggingBox, *tagLab); commented out: currently the tab is empty ...
rightNotebook->append_page (*sExportPanel, *exportLab);

View File

@ -82,9 +82,25 @@ InspectorBuffer::~InspectorBuffer() {
// return deg;
//}
Inspector::Inspector () : currImage(nullptr), zoom(0.0), active(false)
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));
add_events(Gdk::BUTTON_PRESS_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.show_all();
window.set_visible(false);
active = true; // always track inspected thumbnails
}
Inspector::~Inspector()
@ -92,8 +108,184 @@ Inspector::~Inspector()
deleteBuffers();
}
void Inspector::showWindow(bool scaled)
{
this->scaled = scaled;
window.fullscreen();
window.set_visible(true);
pinned = false;
}
bool Inspector::on_key_release(GdkEventKey *event)
{
if (!pinned) {
switch (event->keyval) {
case GDK_KEY_f:
case GDK_KEY_F:
zoomScale = 1.0;
window.set_visible(false);
return true;
}
}
return false;
}
bool Inspector::on_key_press(GdkEventKey *event)
{
switch (event->keyval) {
case GDK_KEY_z:
case GDK_KEY_F:
if (pinned || scaled)
zoomScale = 1.0; // reset if not key hold
scaled = false;
queue_draw();
return true;
case GDK_KEY_f:
if (pinned || !scaled)
zoomScale = 1.0; // reset if not key hold
scaled = true;
queue_draw();
return true;
case GDK_KEY_Escape:
zoomScale = 1.0;
window.set_visible(false);
return true;
}
return false;
}
bool Inspector::on_button_press_event(GdkEventButton *event)
{
if (event->type == GDK_BUTTON_PRESS) {
if (!pinned)
// pin window with mouse click
pinned = true;
return true;
}
return false;
}
bool Inspector::on_scroll_event(GdkEventScroll *event)
{
if (!currImage)
return false;
bool alt = event->state & GDK_MOD1_MASK;
int deviceScale = get_scale_factor();
int imW = currImage->imgBuffer.getWidth();
int imH = currImage->imgBuffer.getHeight();
#ifdef GDK_WINDOWING_QUARTZ
// event reports speed of scroll wheel
double step_x = -event->delta_x;
double step_y = event->delta_y;
#else
// assume fixed step of 5%
double step_x = 5;
double step_y = 5;
#endif
int delta_x = 0;
int delta_y = 0;
switch (event->direction) {
case GDK_SCROLL_SMOOTH:
#ifdef GDK_WINDOWING_QUARTZ
// no additional step for smooth scrolling
delta_x = event->delta_x * deviceScale;
delta_y = event->delta_y * deviceScale;
#else
// apply step to smooth scrolling as well
delta_x = event->delta_x * deviceScale * step_x * imW / 100;
delta_y = event->delta_y * deviceScale * step_y * imH / 100;
#endif
break;
case GDK_SCROLL_DOWN:
delta_y = step_y * deviceScale * imH / 100;
break;
case GDK_SCROLL_UP:
delta_y = -step_y * deviceScale * imH / 100;
break;
case GDK_SCROLL_LEFT:
delta_x = step_x * deviceScale * imW / 100;
break;
case GDK_SCROLL_RIGHT:
delta_x = -step_x * deviceScale * imW / 100;
break;
}
if (alt) {
// zoom
beginZoom(event->x, event->y);
if (std::fabs(delta_y) > std::fabs(delta_x))
on_zoom_scale_changed(1.0 - (double)delta_y / imH / deviceScale);
else
on_zoom_scale_changed(1.0 - (double)delta_x / imW / deviceScale);
return true;
}
// scroll
moveCenter(delta_x, delta_y, imW, imH, deviceScale);
if (!dirty) {
dirty = true;
queue_draw();
}
return true;
}
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;
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)
{
int deviceScale = get_scale_factor();
int imW = currImage->imgBuffer.getWidth();
int imH = currImage->imgBuffer.getHeight();
// limit center to image size
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;
centerBegin = center;
zoomScaleBegin = zoomScale;
}
void Inspector::on_zoom_begin(GdkEventSequence *s)
{
double x, y;
if (gestureZoom->get_point(s, x, y))
beginZoom(x, y);
}
void Inspector::on_zoom_scale_changed(double zscale)
{
if (!currImage)
return;
zoomScale = rtengine::LIM<double>(zoomScaleBegin * zscale, 0.01, 16.0);
double dcenterRatio = 1.0 - zoomScaleBegin / zoomScale;
center.x = centerBegin.x + dcenterBegin.x * dcenterRatio;
center.y = centerBegin.y + dcenterBegin.y * dcenterRatio;
if (!dirty) {
dirty = true;
queue_draw();
}
}
bool Inspector::on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr)
{
dirty = false;
Glib::RefPtr<Gdk::Window> win = get_window();
@ -116,10 +308,24 @@ bool Inspector::on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr)
rtengine::Coord availableSize;
rtengine::Coord topLeft;
rtengine::Coord dest(0, 0);
availableSize.x = win->get_width();
availableSize.y = win->get_height();
int imW = currImage->imgBuffer.getWidth();
int imH = currImage->imgBuffer.getHeight();
int deviceScale = get_scale_factor();
availableSize.x = win->get_width() * deviceScale;
availableSize.y = win->get_height() * deviceScale;
int imW = rtengine::max<int>(currImage->imgBuffer.getWidth(), 1);
int imH = rtengine::max<int>(currImage->imgBuffer.getHeight(), 1);
scale = rtengine::min<double>((double)availableSize.x / imW, (double)availableSize.y / imH);
if (scaled) {
// reduce size of image to fit into window, no further zoom down
zoomScale = rtengine::max<double>(zoomScale, 1.0);
scale *= zoomScale;
}
else {
// limit zoom to fill at least complete window or 1:1
zoomScale = rtengine::max<double>(zoomScale, rtengine::min<double>(1.0, scale));
scale = zoomScale;
}
availableSize.x /= scale;
availableSize.y /= scale;
if (imW < availableSize.x) {
// center the image in the available space along X
@ -146,7 +352,6 @@ bool Inspector::on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr)
topLeft.y -= availableSize.y;
topLeft.y = rtengine::max<int>(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);
// define the destination area
@ -163,24 +368,50 @@ bool Inspector::on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr)
Glib::RefPtr<Gtk::StyleContext> style = get_style_context();
// draw the background
style->render_background(cr, 0, 0, get_width(), get_height());
//style->render_background(cr, 0, 0, get_width(), get_height());
/* --- old method
///* --- 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 ();
*/
//*/
currImage->imgBuffer.copySurface(win);
bool scaledImage = scale != 1.0;
if (deviceScale == 1 && !scaledImage) {
// standard drawing
currImage->imgBuffer.copySurface(win);
}
else {
// consider device scale and image scale
if (deviceScale > 1) {
// use full device resolution and let it scale the image (macOS)
cairo_surface_set_device_scale(cr->get_target()->cobj(), scale, scale);
scaledImage = false;
}
int viewW = rtengine::min<int>(imW, availableSize.x);
int viewH = rtengine::min<int>(imH, availableSize.y);
Glib::RefPtr<Gdk::Pixbuf> crop = Gdk::Pixbuf::create(currImage->imgBuffer.getSurface(), topLeft.x, topLeft.y, viewW, viewH);
if (!scaledImage) {
Gdk::Cairo::set_source_pixbuf(cr, crop, dest.x, dest.y);
}
else {
// 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);
}
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 ();
*/
}
return true;
@ -309,7 +540,7 @@ void Inspector::setActive(bool state)
flushBuffers();
}
active = state;
//active = state;
}

View File

@ -47,12 +47,30 @@ private:
rtengine::Coord center;
std::vector<InspectorBuffer*> images;
InspectorBuffer* currImage;
double zoom;
bool scaled; // fit image into window
double scale; // current scale
double zoomScale, zoomScaleBegin; // scale during zoom
rtengine::Coord centerBegin, dcenterBegin; // center during zoom
bool active;
bool pinned;
bool dirty;
sigc::connection delayconn;
Glib::ustring next_image_path;
Gtk::Window window;
bool on_key_release(GdkEventKey *event);
bool on_key_press(GdkEventKey *event);
bool on_button_press_event(GdkEventButton *event) override;
bool on_scroll_event(GdkEventScroll *event) override;
void moveCenter(int delta_x, int delta_y, int imW, int imH, int deviceScale);
Glib::RefPtr<Gtk::GestureZoom> gestureZoom;
void beginZoom(double x, double y);
void on_zoom_begin(GdkEventSequence *);
void on_zoom_scale_changed(double zscale);
bool on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr) override;
void deleteBuffers();
@ -62,6 +80,11 @@ public:
Inspector();
~Inspector() override;
/** @brief Show or hide window
* @param scaled fit image into window
*/
void showWindow(bool scaled);
/** @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