Big update: 1) implemented scalable histogram (TooWaBoo's CSS untested but probably unnecessary now); 2) reverted graphical changes; 3) gridlines now multiply based on height and width; 4) removed cube-scaling; 5) implementend double-log scaling as the third alternative based on suggestion by @iliasg

This commit is contained in:
Thanatomanic
2018-06-17 10:01:16 +02:00
parent c8bddca09b
commit 9e735b2640
4 changed files with 121 additions and 162 deletions

View File

@@ -497,8 +497,11 @@ EditorPanel::EditorPanel (FilePanel* filePanel)
// build GUI
// build left side panel
leftbox = new Gtk::VBox ();
leftbox->set_size_request (230, 250);
leftbox = new Gtk::Paned (Gtk::ORIENTATION_VERTICAL);
// make a subbox to allow resizing of the histogram (if it's on the left)
leftsubbox = new Gtk::Box (Gtk::ORIENTATION_VERTICAL);
leftsubbox->set_size_request (230, 250);
histogramPanel = nullptr;
@@ -507,19 +510,21 @@ EditorPanel::EditorPanel (FilePanel* filePanel)
ppframe->set_name ("ProfilePanel");
ppframe->add (*profilep);
ppframe->set_label (M ("PROFILEPANEL_LABEL"));
//leftbox->pack_start (*ppframe, Gtk::PACK_SHRINK, 4);
//leftsubbox->pack_start (*ppframe, Gtk::PACK_SHRINK, 4);
navigator = Gtk::manage (new Navigator ());
navigator->previewWindow->set_size_request (-1, 150);
leftbox->pack_start (*navigator, Gtk::PACK_SHRINK, 2);
leftsubbox->pack_start (*navigator, Gtk::PACK_SHRINK, 2);
history = Gtk::manage (new History ());
leftbox->pack_start (*history);
leftsubbox->pack_start (*history);
leftbox->show_all ();
leftsubbox->show_all ();
leftbox->pack2 (*leftsubbox, true, true);
// build the middle of the screen
Gtk::VBox* editbox = Gtk::manage (new Gtk::VBox ());
Gtk::Box* editbox = Gtk::manage (new Gtk::Box (Gtk::ORIENTATION_VERTICAL));
info = Gtk::manage (new Gtk::ToggleButton ());
Gtk::Image* infoimg = Gtk::manage (new RTImage ("info.png"));
@@ -590,7 +595,7 @@ EditorPanel::EditorPanel (FilePanel* filePanel)
tpc->setEditProvider (iareapanel->imageArea);
tpc->getToolBar()->setLockablePickerToolListener (iareapanel->imageArea);
Gtk::HBox* toolBarPanel = Gtk::manage (new Gtk::HBox ());
Gtk::Box* toolBarPanel = Gtk::manage (new Gtk::Box (Gtk::ORIENTATION_HORIZONTAL));
toolBarPanel->set_name ("EditorTopPanel");
toolBarPanel->pack_start (*hidehp, Gtk::PACK_SHRINK, 1);
toolBarPanel->pack_start (*vseph, Gtk::PACK_SHRINK, 2);
@@ -617,10 +622,10 @@ EditorPanel::EditorPanel (FilePanel* filePanel)
toolBarPanel->pack_end (*iareapanel->imageArea->previewModePanel, Gtk::PACK_SHRINK, 0);
toolBarPanel->pack_end (*vsepz4, Gtk::PACK_SHRINK, 2);
afterBox = Gtk::manage (new Gtk::VBox ());
afterBox = Gtk::manage (new Gtk::Box (Gtk::ORIENTATION_VERTICAL));
afterBox->pack_start (*iareapanel);
beforeAfterBox = Gtk::manage (new Gtk::HBox());
beforeAfterBox = Gtk::manage (new Gtk::Box (Gtk::ORIENTATION_HORIZONTAL));
beforeAfterBox->set_name ("BeforeAfterContainer");
beforeAfterBox->pack_start (*afterBox);
@@ -628,12 +633,16 @@ EditorPanel::EditorPanel (FilePanel* filePanel)
editbox->pack_start (*beforeAfterBox);
// build right side panel
vboxright = new Gtk::VBox (false, 0);
vboxright->set_size_request (300, 250);
vboxright = new Gtk::Paned (Gtk::ORIENTATION_VERTICAL);
vsubboxright = new Gtk::Box (Gtk::ORIENTATION_VERTICAL, 0);
vsubboxright->set_size_request (300, 250);
vboxright->pack_start (*ppframe, Gtk::PACK_SHRINK, 2);
vsubboxright->pack_start (*ppframe, Gtk::PACK_SHRINK, 2);
// main notebook
vboxright->pack_start (*tpc->toolPanelNotebook);
vsubboxright->pack_start (*tpc->toolPanelNotebook);
vboxright->pack2 (*vsubboxright, true, true);
// Save buttons
Gtk::Grid *iops = new Gtk::Grid ();
@@ -769,8 +778,7 @@ EditorPanel::EditorPanel (FilePanel* filePanel)
hpanedl->set_position (options.historyPanelWidth);
}
Gtk::VPaned * viewpaned = Gtk::manage (new Gtk::VPaned());
Gtk::Paned *viewpaned = Gtk::manage (new Gtk::Paned (Gtk::ORIENTATION_VERTICAL));
fPanel = filePanel;
if (filePanel) {
@@ -886,7 +894,9 @@ EditorPanel::~EditorPanel ()
delete tpc;
delete ppframe;
delete leftsubbox;
delete leftbox;
delete vsubboxright;
delete vboxright;
//delete saveAsDialog;
@@ -2165,7 +2175,7 @@ void EditorPanel::beforeAfterToggled ()
tbBeforeLock = Gtk::manage (new Gtk::ToggleButton ());
tbBeforeLock->set_tooltip_markup (M ("MAIN_TOOLTIP_BEFOREAFTERLOCK"));
tbBeforeLock->signal_toggled().connect ( sigc::mem_fun (*this, &EditorPanel::tbBeforeLock_toggled) );
beforeHeaderBox = Gtk::manage (new Gtk::HBox ());
beforeHeaderBox = Gtk::manage (new Gtk::Box (Gtk::ORIENTATION_HORIZONTAL));
beforeHeaderBox->pack_end (*tbBeforeLock, Gtk::PACK_SHRINK, 2);
beforeHeaderBox->pack_end (*beforeLabel, Gtk::PACK_SHRINK, 2);
beforeHeaderBox->set_size_request (0, HeaderBoxHeight);
@@ -2179,7 +2189,7 @@ void EditorPanel::beforeAfterToggled ()
afterLabel = Gtk::manage (new Gtk::Label ());
afterLabel->set_markup (Glib::ustring ("<b>") + M ("GENERAL_AFTER") + "</b>");
afterHeaderBox = Gtk::manage (new Gtk::HBox ());
afterHeaderBox = Gtk::manage (new Gtk::Box (Gtk::ORIENTATION_HORIZONTAL));
afterHeaderBox->set_size_request (0, HeaderBoxHeight);
afterHeaderBox->pack_end (*afterLabel, Gtk::PACK_SHRINK, 2);
afterBox->pack_start (*afterHeaderBox, Gtk::PACK_SHRINK, 2);
@@ -2321,17 +2331,16 @@ void EditorPanel::updateHistogramPosition (int oldPosition, int newPosition)
if (oldPosition == 0) {
// There was no Histogram before, so we create it
histogramPanel = Gtk::manage (new HistogramPanel ());
leftbox->pack_start (*histogramPanel, Gtk::PACK_SHRINK, 2);
leftbox->pack1(*histogramPanel, true, false);
} else if (oldPosition == 2) {
// The histogram was on the right side, so we move it to the left
histogramPanel->reference();
removeIfThere (vboxright, histogramPanel, false);
leftbox->pack_start (*histogramPanel, Gtk::PACK_SHRINK, 2);
leftbox->pack1(*histogramPanel, true, false);
histogramPanel->unreference();
}
histogramPanel->reorder (Gtk::POS_LEFT);
leftbox->reorder_child (*histogramPanel, 0);
break;
case 2:
@@ -2341,17 +2350,16 @@ void EditorPanel::updateHistogramPosition (int oldPosition, int newPosition)
if (oldPosition == 0) {
// There was no Histogram before, so we create it
histogramPanel = Gtk::manage (new HistogramPanel ());
vboxright->pack_start (*histogramPanel, Gtk::PACK_SHRINK, 2);
vboxright->pack1 (*histogramPanel, true, false);
} else if (oldPosition == 1) {
// The histogram was on the left side, so we move it to the right
histogramPanel->reference();
removeIfThere (leftbox, histogramPanel, false);
vboxright->pack_start (*histogramPanel, Gtk::PACK_SHRINK, 2);
vboxright->pack1 (*histogramPanel, true, false);
histogramPanel->unreference();
}
histogramPanel->reorder (Gtk::POS_RIGHT);
vboxright->reorder_child (*histogramPanel, 0);
break;
}

View File

@@ -173,8 +173,10 @@ private:
Gtk::Image *iShowHideSidePanels;
Gtk::Image *iShowHideSidePanels_exit;
Gtk::Image *iBeforeLockON, *iBeforeLockOFF;
Gtk::VBox *leftbox;
Gtk::VBox *vboxright;
Gtk::Paned *leftbox;
Gtk::Box *leftsubbox;
Gtk::Paned *vboxright;
Gtk::Box *vsubboxright;
Gtk::Button* queueimg;
Gtk::Button* saveimgas;
@@ -191,13 +193,13 @@ private:
PreviewHandler* beforePreviewHandler; // for the before-after view
Navigator* navigator;
ImageAreaPanel* beforeIarea; // for the before-after view
Gtk::VBox* beforeBox;
Gtk::VBox* afterBox;
Gtk::Box* beforeBox;
Gtk::Box* afterBox;
Gtk::Label* beforeLabel;
Gtk::Label* afterLabel;
Gtk::HBox* beforeAfterBox;
Gtk::HBox* beforeHeaderBox;
Gtk::HBox* afterHeaderBox;
Gtk::Box* beforeAfterBox;
Gtk::Box* beforeHeaderBox;
Gtk::Box* afterHeaderBox;
Gtk::ToggleButton* toggleHistogramProfile;
Gtk::Frame* ppframe;

View File

@@ -39,9 +39,9 @@ extern Options options;
HistogramPanel::HistogramPanel ()
{
set_vexpand(false);
set_vexpand(true);
set_hexpand(true);
set_valign(Gtk::ALIGN_START);
set_valign(Gtk::ALIGN_FILL);
set_halign(Gtk::ALIGN_FILL);
set_name("HistogramPanel");
@@ -464,10 +464,10 @@ void HistogramRGBArea::get_preferred_height_for_width_vfunc (int width, int &min
{
int bHeight = width / 30;
if (bHeight > 10) {
bHeight = 10; // it would be useful to scale this based on display dpi
} else if (bHeight < 5 ) {
bHeight = 5;
if (bHeight > 15) {
bHeight = 15;
} else if (bHeight < 10 ) {
bHeight = 10;
}
minimum_height = bHeight;
@@ -721,19 +721,15 @@ HistogramArea::~HistogramArea ()
}
}
/* Note: best case scenario would be to have the histogram size really flexible
by being able to resize the panel vertically, and the side-bar horizontally.
We would only need to enforce some lower limits then. */
Gtk::SizeRequestMode HistogramArea::get_request_mode_vfunc () const
{
return Gtk::SIZE_REQUEST_HEIGHT_FOR_WIDTH;
return Gtk::SIZE_REQUEST_CONSTANT_SIZE;
}
void HistogramArea::get_preferred_height_vfunc (int &minimum_height, int &natural_height) const
{
int minimumWidth = 0;
int naturalWidth = 0; // unused?
int naturalWidth = 0;
get_preferred_width_vfunc (minimumWidth, naturalWidth);
get_preferred_height_for_width_vfunc (minimumWidth, minimum_height, natural_height);
}
@@ -745,16 +741,8 @@ void HistogramArea::get_preferred_width_vfunc (int &minimum_width, int &natural_
}
void HistogramArea::get_preferred_height_for_width_vfunc (int width, int &minimum_height, int &natural_height) const
{
/*int gHeight = width / 2;
if (gHeight > 150) {
gHeight = 150;
} else if (gHeight < 100) {
gHeight = 100;
}*/
int gHeight = width; // aspect ratio 1:1 should fit on most monitors
{
int gHeight = width * 0.618;
if (gHeight < 100) {
gHeight = 100;
}
@@ -763,7 +751,6 @@ void HistogramArea::get_preferred_height_for_width_vfunc (int width, int &minimu
natural_height = gHeight;
}
//unused?
void HistogramArea::get_preferred_width_for_height_vfunc (int height, int &minimum_width, int &natural_width) const
{
get_preferred_width_vfunc (minimum_width, natural_width);
@@ -918,67 +905,53 @@ void HistogramArea::updateBackBuffer ()
cr->set_antialias (Cairo::ANTIALIAS_SUBPIXEL);
cr->set_line_width (1.0);
cr->set_operator(Cairo::OPERATOR_ADD);
cr->set_operator(Cairo::OPERATOR_SOURCE);
int ui = 0, oi = 0;
if (needBlue) {
drawCurve(cr, bhchanged, realhistheight, w, h);
cr->set_source_rgba (0.0, 0.0, 1.0, 0.4);
if (needLuma && !rawMode) {
drawCurve(cr, lhist, realhistheight, w, h);
cr->set_source_rgb (0.65, 0.65, 0.65);
cr->fill ();
drawCurve(cr, bhchanged, realhistheight, w, h);
cr->set_source_rgba (0.0, 0.0, 1.0, 0.9);
drawMarks(cr, lhist, realhistheight, w, ui, oi);
}
if (needChroma && !rawMode) {
drawCurve(cr, chist, realhistheight, w, h);
cr->set_source_rgb (0., 0., 0.);
cr->stroke ();
drawMarks(cr, bhchanged, realhistheight, w, ui, oi);
drawMarks(cr, chist, realhistheight, w, ui, oi);
}
if (needGreen) {
drawCurve(cr, ghchanged, realhistheight, w, h);
cr->set_source_rgba (0.0, 1.0, 0.0, 0.4);
cr->fill ();
drawCurve(cr, ghchanged, realhistheight, w, h);
cr->set_source_rgba (0.0, 1.0, 0.0, 0.9);
cr->stroke ();
drawMarks(cr, ghchanged, realhistheight, w, ui, oi);
}
if (needRed) {
drawCurve(cr, rhchanged, realhistheight, w, h);
cr->set_source_rgba (1.0, 0.0, 0.0, 0.4);
cr->fill ();
drawCurve(cr, rhchanged, realhistheight, w, h);
cr->set_source_rgba (1.0, 0.0, 0.0, 0.9);
cr->set_source_rgb (1.0, 0.0, 0.0);
cr->stroke ();
drawMarks(cr, rhchanged, realhistheight, w, ui, oi);
}
cr->set_operator(Cairo::OPERATOR_SOURCE);
if (needLuma && !rawMode) {
drawCurve(cr, lhist, realhistheight, w, h);
cr->set_source_rgb (0.9, 0.9, 0.9);
if (needGreen) {
drawCurve(cr, ghchanged, realhistheight, w, h);
cr->set_source_rgb (0.0, 1.0, 0.0);
cr->stroke ();
drawMarks(cr, lhist, realhistheight, w, ui, oi);
drawMarks(cr, ghchanged, realhistheight, w, ui, oi);
}
if (needChroma && !rawMode) {
drawCurve(cr, chist, realhistheight, w, h);
cr->set_source_rgb (0.4, 0.4, 0.4);
if (needBlue) {
drawCurve(cr, bhchanged, realhistheight, w, h);
cr->set_source_rgb (0.0, 0.0, 1.0);
cr->stroke ();
drawMarks(cr, chist, realhistheight, w, ui, oi);
drawMarks(cr, bhchanged, realhistheight, w, ui, oi);
}
}
cr->set_source_rgba (1., 1., 1., 0.35);
cr->set_source_rgba (1., 1., 1., 0.25);
cr->set_line_width (1.0);
cr->set_antialias(Cairo::ANTIALIAS_NONE);
@@ -988,51 +961,38 @@ void HistogramArea::updateBackBuffer ()
ch_ds[0] = 4;
cr->set_dash (ch_ds, 0);
cr->move_to(w / 4 + 0.5, 1.5);
cr->line_to(w / 4 + 0.5, h - 2);
cr->stroke();
cr->move_to(2 * w / 4 + 0.5, 1.5);
cr->line_to(2 * w / 4 + 0.5, h - 2);
cr->stroke();
cr->move_to(3 * w / 4 + 0.5, 1.5);
cr->line_to(3 * w / 4 + 0.5, h - 2);
cr->stroke();
// determine the number of gridlines based on current h/w
int nrOfHGridPartitions = (int)rtengine::min (16.0, pow (2.0, floor ((h - 100) / 250) + 2));
int nrOfVGridPartitions = (int)rtengine::min (16.0, pow (2.0, floor ((w - 100) / 250) + 2));
if (options.histogramDrawMode == 0)
{
cr->move_to(1.5, h / 4 + 0.5);
cr->line_to(w - 2, h / 4 + 0.5);
cr->stroke();
cr->move_to(1.5, 2 * h / 4 + 0.5);
cr->line_to(w - 2, 2 * h / 4 + 0.5);
cr->stroke();
cr->move_to(1.5, 3 * h / 4 + 0.5);
cr->line_to(w - 2, 3 * h / 4 + 0.5);
cr->stroke();
// draw vertical gridlines
if (options.histogramDrawMode < 2) {
for (int i = 1; i < nrOfVGridPartitions; i++) {
cr->move_to (i * w / nrOfVGridPartitions + 0.5, 1.5);
cr->line_to (i * w / nrOfVGridPartitions + 0.5, h - 2);
cr->stroke ();
}
} else {
for (int i = 1; i < nrOfVGridPartitions; i++) {
cr->move_to (scalingFunctionLog (w, i * w / nrOfVGridPartitions) + 0.5, 1.5);
cr->line_to (scalingFunctionLog (w, i * w / nrOfVGridPartitions) + 0.5, h - 2);
cr->stroke ();
}
}
if (options.histogramDrawMode == 1)
{
cr->move_to(1.5, h - scalingFunctionLog(h,h / 4 + 0.5));
cr->line_to(w - 2, h - scalingFunctionLog(h,h / 4 + 0.5));
cr->stroke();
cr->move_to(1.5, h - scalingFunctionLog(h,2 * h / 4 + 0.5));
cr->line_to(w - 2, h - scalingFunctionLog(h,2 * h / 4 + 0.5));
cr->stroke();
cr->move_to(1.5, h - scalingFunctionLog(h,3 * h / 4 + 0.5));
cr->line_to(w - 2, h - scalingFunctionLog(h,3 * h / 4 + 0.5));
cr->stroke();
}
if (options.histogramDrawMode == 2)
{
cr->move_to(1.5, scalingFunctionCube(h,h / 4 + 0.5));
cr->line_to(w - 2, scalingFunctionCube(h,h / 4 + 0.5));
cr->stroke();
cr->move_to(1.5, scalingFunctionCube(h,2 * h / 4 + 0.5));
cr->line_to(w - 2, scalingFunctionCube(h,2 * h / 4 + 0.5));
cr->stroke();
cr->move_to(1.5, scalingFunctionCube(h,3 * h / 4 + 0.5));
cr->line_to(w - 2, scalingFunctionCube(h,3 * h / 4 + 0.5));
cr->stroke();
// draw horizontal gridlines
if (options.histogramDrawMode == 0) {
for (int i = 1; i < nrOfHGridPartitions; i++) {
cr->move_to (1.5, i * h / nrOfHGridPartitions + 0.5);
cr->line_to (w - 2, i * h / nrOfHGridPartitions + 0.5);
cr->stroke ();
}
} else {
for (int i = 1; i < nrOfHGridPartitions; i++) {
cr->move_to (1.5, h - scalingFunctionLog(h, i * h / nrOfHGridPartitions) + 0.5);
cr->line_to (w - 2, h - scalingFunctionLog(h, i * h / nrOfHGridPartitions) + 0.5);
cr->stroke ();
}
}
cr->unset_dash();
@@ -1056,14 +1016,8 @@ void HistogramArea::on_realize ()
double HistogramArea::scalingFunctionLog(double vsize, double val)
{
double factor = 1.0; // can be tuned if necessary - makes the log 'steeper'
return vsize * log(factor / (factor + val)) / log(factor / vsize);
}
double HistogramArea::scalingFunctionCube(double vsize, double val)
{
double factor = 3.0; // can be tuned; higher values compress the middel part of the scale
return (val * (4 * (-1.0 + factor) * val * val - 6.0 * (-1.0 + factor) * val * vsize + (-2.0 + 3.0 * factor) * vsize *vsize))/(factor * vsize * vsize);
double factor = 20.0; // can be tuned if necessary - higher is flatter curve
return vsize * log(factor / (factor + val)) / log(factor / (factor + vsize));
}
void HistogramArea::drawCurve(Cairo::RefPtr<Cairo::Context> &cr,
@@ -1075,16 +1029,20 @@ void HistogramArea::drawCurve(Cairo::RefPtr<Cairo::Context> &cr,
for (int i = 0; i < 256; i++) {
double val = data[i] * (double)(vsize - 2) / scale;
if (drawMode == 1)
val = scalingFunctionLog((double)vsize,val);
if (drawMode == 2)
val = scalingFunctionCube((double)vsize,val);
if (drawMode > 0) { // scale y for single and double log-scale
val = scalingFunctionLog ((double)vsize, val);
}
if (val > vsize - 1) {
val = vsize - 1;
}
double iscaled = i;
if (drawMode == 2) { // scale x for double log-scale
iscaled = scalingFunctionLog (256.0, (double)i);
}
double posX = (i / 255.0) * (hsize - 1);
double posX = (iscaled / 255.0) * (hsize - 1);
double posY = vsize - 1 - val;
cr->line_to (posX, posY);
}

View File

@@ -100,14 +100,6 @@ private:
// Some ...
};
/*class FullModeListener
{
public:
virtual ~FullModeListener() {}
virtual void toggle_button_full () {}
};*/
class DrawModeListener
{
public:
@@ -125,12 +117,12 @@ protected:
LUTu lhistRaw, rhistRaw, ghistRaw, bhistRaw;
bool valid;
int drawMode;
DrawModeListener *myDrawModeListener;
int drawMode;
DrawModeListener *myDrawModeListener;
int oldwidth, oldheight;
bool needLuma, needRed, needGreen, needBlue, rawMode, needChroma;
HistogramAreaIdleHelper* haih;
@@ -154,8 +146,7 @@ private:
void get_preferred_width_vfunc (int &minimum_width, int &natural_width) const;
void get_preferred_height_for_width_vfunc (int width, int &minimum_height, int &natural_height) const;
void get_preferred_width_for_height_vfunc (int height, int &minimum_width, int &natural_width) const;
double scalingFunctionLog(double vsize, double val);
double scalingFunctionCube(double vsize, double val);
double scalingFunctionLog (double vsize, double val);
};
class HistogramPanel : public Gtk::Grid, public PointerMotionListener, public DrawModeListener