diff --git a/src/img/img/ImagePropertiesPage.ui b/src/img/img/ImagePropertiesPage.ui index d0453605b..2ea522bdd 100644 --- a/src/img/img/ImagePropertiesPage.ui +++ b/src/img/img/ImagePropertiesPage.ui @@ -1058,16 +1058,6 @@ p, li { white-space: pre-wrap; } 0 - - - - Preview (Auto apply) - - - true - - - @@ -1141,7 +1131,6 @@ p, li { white-space: pre-wrap; } g_sb b_slider b_sb - preview_cbx reset_pb contrast_sb gamma_sb diff --git a/src/img/img/imgPropertiesPage.cc b/src/img/img/imgPropertiesPage.cc index f53c0a100..ddd9298e7 100644 --- a/src/img/img/imgPropertiesPage.cc +++ b/src/img/img/imgPropertiesPage.cc @@ -35,6 +35,27 @@ namespace img const double min_gamma = 0.3; const double max_gamma = 3.0; +// ------------------------------------------------------------------------- + +void +indicate_error (QWidget *le, const tl::Exception *ex) +{ + // by the way, update the foreground color of the cell edit box as well (red, if not valid) + QPalette pl = le->palette (); + if (ex) { + pl.setColor (QPalette::Active, QPalette::Text, Qt::red); + pl.setColor (QPalette::Active, QPalette::Base, QColor (Qt::red).lighter (180)); + le->setToolTip (tl::to_qstring (ex->msg ())); + } else { + QWidget *pw = dynamic_cast (le->parent ()); + tl_assert (pw != 0); + pl.setColor (QPalette::Active, QPalette::Text, pw->palette ().color (QPalette::Text)); + pl.setColor (QPalette::Active, QPalette::Base, pw->palette ().color (QPalette::Base)); + le->setToolTip (QString ()); + } + le->setPalette (pl); +} + // ------------------------------------------------------------------------- // PropertiesPage implementation @@ -73,6 +94,7 @@ void PropertiesPage::init () { m_no_signals = false; + m_in_color_mapping_signal = false; setupUi (this); @@ -108,6 +130,7 @@ PropertiesPage::init () connect (browse_pb, SIGNAL (clicked ()), this, SLOT (browse ())); connect (colors, SIGNAL (color_changed (std::pair)), false_color_control, SLOT (set_current_color (std::pair))); connect (false_color_control, SIGNAL (selection_changed (std::pair)), colors, SLOT (set_color (std::pair))); + connect (false_color_control, SIGNAL (color_mapping_changed ()), this, SLOT (color_mapping_changed ())); connect (brightness_slider, SIGNAL (valueChanged (int)), this, SLOT (brightness_slider_changed (int))); connect (brightness_sb, SIGNAL (valueChanged (int)), this, SLOT (brightness_spinbox_changed (int))); @@ -122,15 +145,22 @@ PropertiesPage::init () connect (b_slider, SIGNAL (valueChanged (int)), this, SLOT (blue_slider_changed (int))); connect (b_sb, SIGNAL (valueChanged (double)), this, SLOT (blue_spinbox_changed (double))); - connect (false_color_control, SIGNAL (color_mapping_changed ()), this, SLOT (color_mapping_changed ())); - connect (false_color_control, SIGNAL (selection_changed ()), this, SLOT (color_mapping_changed ())); - connect (from_le, SIGNAL (returnPressed ()), this, SLOT (min_max_return_pressed ())); - connect (to_le, SIGNAL (returnPressed ()), this, SLOT (min_max_return_pressed ())); - connect (value_le, SIGNAL (returnPressed ()), this, SLOT (value_return_pressed ())); + connect (from_le, SIGNAL (editingFinished ()), this, SLOT (min_max_value_changed ())); + connect (to_le, SIGNAL (editingFinished ()), this, SLOT (min_max_value_changed ())); + connect (value_le, SIGNAL (editingFinished ()), this, SLOT (value_changed ())); + connect (width_le, SIGNAL (editingFinished ()), this, SIGNAL (edited ())); + connect (height_le, SIGNAL (editingFinished ()), this, SIGNAL (edited ())); + connect (x_offset_le, SIGNAL (editingFinished ()), this, SIGNAL (edited ())); + connect (y_offset_le, SIGNAL (editingFinished ()), this, SIGNAL (edited ())); + connect (angle_le, SIGNAL (editingFinished ()), this, SIGNAL (edited ())); + connect (shear_le, SIGNAL (editingFinished ()), this, SIGNAL (edited ())); + connect (persp_tx_le, SIGNAL (editingFinished ()), this, SIGNAL (edited ())); + connect (persp_ty_le, SIGNAL (editingFinished ()), this, SIGNAL (edited ())); + + connect (mirror_cbx, SIGNAL (clicked ()), this, SIGNAL (edited ())); connect (reset_pb, SIGNAL (clicked ()), this, SLOT (reset_pressed ())); connect (save_pb, SIGNAL (clicked ()), this, SLOT (save_pressed ())); - connect (preview_cbx, SIGNAL (clicked ()), this, SLOT (preview_checked ())); connect (define_landmarks_pb, SIGNAL (clicked ()), this, SLOT (define_landmarks_pressed ())); } @@ -202,11 +232,42 @@ PropertiesPage::readonly () return false; } -void -PropertiesPage::min_max_return_pressed () +void +PropertiesPage::get_xmin_xmax (double &xmin, double &xmax, bool &has_error_out) { -BEGIN_PROTECTED + bool has_error = false; + try { + tl::from_string (tl::to_string (from_le->text ()), xmin); + indicate_error (from_le, 0); + } catch (tl::Exception &ex) { + indicate_error (from_le, &ex); + has_error = true; + } + + try { + tl::from_string (tl::to_string (to_le->text ()), xmax); + indicate_error (to_le, 0); + } catch (tl::Exception &ex) { + indicate_error (to_le, &ex); + has_error = true; + } + + if (! has_error && xmin >= xmax) { + tl::Exception ex (tl::to_string (QObject::tr ("Invalid data value range (min. value must be less than max. value)"))); + indicate_error (from_le, &ex); + indicate_error (to_le, &ex); + has_error = true; + } + + if (has_error) { + has_error_out = true; + } +} + +void +PropertiesPage::min_max_value_changed () +{ value_le->setText (QString ()); value_le->setEnabled (false); @@ -214,10 +275,11 @@ BEGIN_PROTECTED colors->set_single_mode (false); double xmin, xmax; - tl::from_string (tl::to_string (from_le->text ()), xmin); - tl::from_string (tl::to_string (to_le->text ()), xmax); - if (xmin >= xmax) { - throw tl::Exception (tl::to_string (QObject::tr ("Invalid data value range (min. value must be less than max. value)"))); + bool has_error = false; + get_xmin_xmax (xmin, xmax, has_error); + + if (has_error) { + return; } if (false_color_control->has_selection () && false_color_control->selected_node () > 0 && false_color_control->selected_node () < int (false_color_control->nodes ().size ()) - 1) { @@ -236,9 +298,7 @@ BEGIN_PROTECTED recompute_histogram (); - preview (); - -END_PROTECTED + emit edited (); } void @@ -246,22 +306,20 @@ PropertiesPage::color_mapping_changed () { if (! m_no_signals) { + bool has_error = false; + value_le->setText (QString ()); value_le->setEnabled (false); colors->setEnabled (false_color_control->has_selection ()); colors->set_single_mode (false); - try { + if (false_color_control->has_selection () && false_color_control->selected_node () > 0 && false_color_control->selected_node () < int (false_color_control->nodes ().size ()) - 1) { - if (false_color_control->has_selection () && false_color_control->selected_node () > 0 && false_color_control->selected_node () < int (false_color_control->nodes ().size ()) - 1) { + double xmin, xmax; + get_xmin_xmax (xmin, xmax, has_error); - double xmin, xmax; - tl::from_string (tl::to_string (from_le->text ()), xmin); - tl::from_string (tl::to_string (to_le->text ()), xmax); - if (xmin >= xmax) { - throw tl::Exception (""); - } + if (! has_error) { double x = false_color_control->nodes () [false_color_control->selected_node ()].first; double xx = x * (xmax - xmin) + xmin; @@ -269,46 +327,57 @@ PropertiesPage::color_mapping_changed () value_le->setText (tl::to_qstring (tl::sprintf ("%.4g", xx))); value_le->setEnabled (true); - } else if (false_color_control->has_selection ()) { - - colors->set_single_mode (true); - } - } catch (...) { } + } else if (false_color_control->has_selection ()) { - preview (); + colors->set_single_mode (true); + + } + + if (! has_error) { + m_in_color_mapping_signal = true; + emit edited (); + m_in_color_mapping_signal = false; + } } } void -PropertiesPage::value_return_pressed () +PropertiesPage::value_changed () { -BEGIN_PROTECTED + double xx = 0; + bool has_error = false; double xmin, xmax; - tl::from_string (tl::to_string (from_le->text ()), xmin); - tl::from_string (tl::to_string (to_le->text ()), xmax); - if (xmin >= xmax) { - throw tl::Exception (tl::to_string (QObject::tr ("Invalid data value range (min. value must be less than max. value)"))); - } + get_xmin_xmax (xmin, xmax, has_error); double x = 0.0; - tl::from_string (tl::to_string (value_le->text ()), x); - - double xx = (x - xmin) / (xmax - xmin); - if (xx < 0 || xx > 1.0) { - throw tl::Exception (tl::to_string (QObject::tr ("The position entered (%g) must be between the minimum (%g) and maximum (%g) value")), x, xmin, xmax); + try { + tl::from_string (tl::to_string (value_le->text ()), x); + indicate_error (value_le, 0); + } catch (tl::Exception &ex) { + indicate_error (value_le, &ex); + has_error = true; } - m_no_signals = true; - false_color_control->set_current_position (xx); - m_no_signals = false; + xx = (x - xmin) / (xmax - xmin); + if (! has_error && (xx < 0 || xx > 1.0)) { + tl::Exception ex (tl::to_string (QObject::tr ("The position entered (%g) must be between the minimum (%g) and maximum (%g) value")), x, xmin, xmax); + indicate_error (value_le, &ex); + has_error = true; + } - preview (); + if (! has_error) { -END_PROTECTED + m_no_signals = true; + false_color_control->set_current_position (xx); + m_no_signals = false; + + emit edited (); + + } } inline double @@ -320,6 +389,10 @@ round_to_zero (double x) void PropertiesPage::update () { + if (m_in_color_mapping_signal) { + return; + } + m_no_signals = true; if (mp_service) { @@ -498,7 +571,7 @@ PropertiesPage::brightness_slider_changed (int value) m_no_signals = true; brightness_sb->setValue (value); - preview (); + emit edited (); m_no_signals = false; } @@ -511,7 +584,7 @@ PropertiesPage::brightness_spinbox_changed (int value) m_no_signals = true; brightness_slider->setValue (value); - preview (); + emit edited (); m_no_signals = false; } @@ -524,7 +597,7 @@ PropertiesPage::contrast_slider_changed (int value) m_no_signals = true; contrast_sb->setValue (value); - preview (); + emit edited (); m_no_signals = false; } @@ -537,7 +610,7 @@ PropertiesPage::contrast_spinbox_changed (int value) m_no_signals = true; contrast_slider->setValue (value); - preview (); + emit edited (); m_no_signals = false; } @@ -556,7 +629,7 @@ PropertiesPage::gamma_spinbox_changed (double value) gamma_slider->setValue (50 + int (0.5 + (value - 1.0) / (max_gamma - 1.0) * 50.0)); } - preview (); + emit edited (); m_no_signals = false; } @@ -578,7 +651,7 @@ PropertiesPage::gamma_slider_changed (int value) } gamma_sb->setValue (gamma); - preview (); + emit edited (); m_no_signals = false; } @@ -595,7 +668,7 @@ PropertiesPage::red_slider_changed (int value) double gain = value * 0.02; r_sb->setValue (gain); - preview (); + emit edited (); m_no_signals = false; } @@ -610,7 +683,7 @@ PropertiesPage::red_spinbox_changed (double value) m_no_signals = true; r_slider->setValue (int (0.5 + value * 50.0)); - preview (); + emit edited (); m_no_signals = false; } @@ -627,7 +700,7 @@ PropertiesPage::green_slider_changed (int value) double gain = value * 0.02; g_sb->setValue (gain); - preview (); + emit edited (); m_no_signals = false; } @@ -642,7 +715,7 @@ PropertiesPage::green_spinbox_changed (double value) m_no_signals = true; g_slider->setValue (int (0.5 + value * 50.0)); - preview (); + emit edited (); m_no_signals = false; } @@ -659,7 +732,7 @@ PropertiesPage::blue_slider_changed (int value) double gain = value * 0.02; b_sb->setValue (gain); - preview (); + emit edited (); m_no_signals = false; } @@ -674,9 +747,9 @@ PropertiesPage::blue_spinbox_changed (double value) m_no_signals = true; b_slider->setValue (int (0.5 + value * 50.0)); - preview (); + emit edited (); - m_no_signals = false; + m_no_signals = false; } void @@ -686,6 +759,7 @@ PropertiesPage::black_to_white () nodes.push_back (std::make_pair (0.0, std::make_pair (QColor (0, 0, 0), QColor (0, 0, 0)))); nodes.push_back (std::make_pair (1.0, std::make_pair (QColor (255, 255, 255), QColor (255, 255, 255)))); false_color_control->set_nodes (nodes); + emit edited (); } void @@ -695,6 +769,7 @@ PropertiesPage::white_to_black () nodes.push_back (std::make_pair (0.0, std::make_pair (QColor (255, 255, 255), QColor (255, 255, 255)))); nodes.push_back (std::make_pair (1.0, std::make_pair (QColor (0, 0, 0), QColor (0, 0, 0)))); false_color_control->set_nodes (nodes); + emit edited (); } void @@ -704,7 +779,7 @@ PropertiesPage::red_to_blue () nodes.push_back (std::make_pair (0.0, std::make_pair (QColor (255, 0, 0), QColor (255, 0, 0)))); nodes.push_back (std::make_pair (1.0, std::make_pair (QColor (0, 0, 255), QColor (0, 0, 255)))); false_color_control->set_nodes (nodes); - + emit edited (); } void @@ -714,6 +789,7 @@ PropertiesPage::blue_to_red () nodes.push_back (std::make_pair (0.0, std::make_pair (QColor (0, 0, 255), QColor (0, 0, 255)))); nodes.push_back (std::make_pair (1.0, std::make_pair (QColor (255, 0, 0), QColor (255, 0, 0)))); false_color_control->set_nodes (nodes); + emit edited (); } void @@ -725,11 +801,14 @@ PropertiesPage::reverse_color_order () std::swap (nodes [i].second.first, nodes [nodes.size () - 1 - i].second.second); } false_color_control->set_nodes (nodes); + emit edited (); } void PropertiesPage::apply () { + bool has_error = false; + db::Matrix3d matrix = mp_direct_image->matrix (); // The observer distance for perspective distortion is the average of the images width and height. @@ -741,45 +820,89 @@ PropertiesPage::apply () double w = matrix.mag_x (), h = matrix.mag_y (), x = matrix.disp ().x (), y = matrix.disp ().y (), a = matrix.angle (), sa = matrix.shear_angle (), tx = matrix.perspective_tilt_x (z), ty = matrix.perspective_tilt_y (z); - bool mirror; - - if (width_le->text () != tl::to_qstring (tl::micron_to_string (matrix.mag_x ()))) { + try { tl::from_string (tl::to_string (width_le->text ()), w); + if (w <= 0.0 || h <= 0.0) { + throw tl::Exception (tl::to_string (QObject::tr ("Pixel width or height must be positive, non-null values"))); + } + indicate_error (width_le, 0); + } catch (tl::Exception &ex) { + indicate_error (width_le, &ex); + has_error = true; } - if (height_le->text () != tl::to_qstring (tl::micron_to_string (matrix.mag_y ()))) { + + try { tl::from_string (tl::to_string (height_le->text ()), h); + indicate_error (height_le, 0); + } catch (tl::Exception &ex) { + indicate_error (height_le, &ex); + has_error = true; } - if (x_offset_le->text () != tl::to_qstring (tl::micron_to_string (round_to_zero (matrix.disp ().x ())))) { + + try { tl::from_string (tl::to_string (x_offset_le->text ()), x); + indicate_error (x_offset_le, 0); + } catch (tl::Exception &ex) { + indicate_error (x_offset_le, &ex); + has_error = true; } - if (y_offset_le->text () != tl::to_qstring (tl::micron_to_string (round_to_zero (matrix.disp ().y ())))) { + + try { tl::from_string (tl::to_string (y_offset_le->text ()), y); + indicate_error (y_offset_le, 0); + } catch (tl::Exception &ex) { + indicate_error (y_offset_le, &ex); + has_error = true; } - if (angle_le->text () != tl::to_qstring (tl::to_string (round_to_zero (matrix.angle ())))) { + + try { tl::from_string (tl::to_string (angle_le->text ()), a); + indicate_error (angle_le, 0); + } catch (tl::Exception &ex) { + indicate_error (angle_le, &ex); + has_error = true; } - if (shear_le->text () != tl::to_qstring (tl::to_string (round_to_zero (matrix.shear_angle ())))) { + + try { tl::from_string (tl::to_string (shear_le->text ()), sa); + if (sa <= -45 || sa >= 45) { + throw tl::Exception (tl::to_string (QObject::tr ("The shear angle must be larger than -45 and less than 45 degree"))); + } + indicate_error (shear_le, 0); + } catch (tl::Exception &ex) { + indicate_error (shear_le, &ex); + has_error = true; } - if (persp_tx_le->text () != tl::to_qstring (tl::to_string (round_to_zero (matrix.perspective_tilt_x (z))))) { + + try { tl::from_string (tl::to_string (persp_tx_le->text ()), tx); + if (tx <= -90 || tx >= 90) { + throw tl::Exception (tl::to_string (QObject::tr ("The perspective tilt angles must be larger than -90 and less than 90 degree"))); + } + indicate_error (persp_tx_le, 0); + } catch (tl::Exception &ex) { + indicate_error (persp_tx_le, &ex); + has_error = true; } - if (persp_ty_le->text () != tl::to_qstring (tl::to_string (round_to_zero (matrix.perspective_tilt_y (z))))) { + + try { tl::from_string (tl::to_string (persp_ty_le->text ()), ty); + if (ty <= -90 || ty >= 90) { + throw tl::Exception (tl::to_string (QObject::tr ("The perspective tilt angles must be larger than -90 and less than 90 degree"))); + } + indicate_error (persp_ty_le, 0); + } catch (tl::Exception &ex) { + indicate_error (persp_ty_le, &ex); + has_error = true; } - mirror = mirror_cbx->isChecked (); + bool mirror = mirror_cbx->isChecked (); - if (w <= 0.0 || h <= 0.0) { - throw tl::Exception (tl::to_string (QObject::tr ("Pixel width or height must be positive, non-null values"))); - } + double xmin, xmax; + get_xmin_xmax (xmin, xmax, has_error); - if (sa <= -45 || sa >= 45) { - throw tl::Exception (tl::to_string (QObject::tr ("The shear angle must be larger than -45 and less than 45 degree"))); - } - - if (tx <= -90 || tx >= 90 || ty <= -90 || ty >= 90) { - throw tl::Exception (tl::to_string (QObject::tr ("The perspective tilt angles must be larger than -90 and less than 90 degree"))); + if (has_error) { + throw tl::Exception (tl::to_string (tr ("At least one value is invalid - see highlighted entry fields"))); } // Compute the new observer distance @@ -790,13 +913,6 @@ PropertiesPage::apply () matrix = db::Matrix3d::disp (db::DVector (x, y)) * db::Matrix3d::perspective (tx, ty, z) * db::Matrix3d::rotation (a) * db::Matrix3d::shear (sa) * db::Matrix3d::mag (w, h) * db::Matrix3d::mirror (mirror); mp_direct_image->set_matrix (matrix); - double xmin, xmax; - tl::from_string (tl::to_string (from_le->text ()), xmin); - tl::from_string (tl::to_string (to_le->text ()), xmax); - if (xmin >= xmax) { - throw tl::Exception (tl::to_string (QObject::tr ("Invalid data value range (min. value must be less than max. value)"))); - } - mp_direct_image->set_min_value (xmin); mp_direct_image->set_max_value (xmax); @@ -891,30 +1007,7 @@ PropertiesPage::reset_pressed () m_no_signals = false; - preview (); -} - -void -PropertiesPage::preview_checked () -{ - preview (); -} - -void -PropertiesPage::preview () -{ - if (preview_cbx->isChecked ()) { - - BEGIN_PROTECTED_CLEANUP - - apply (); // this is a HACK, because it changes the current object - - END_PROTECTED_CLEANUP - { - preview_cbx->setChecked (false); - } - - } + emit edited (); } void @@ -922,7 +1015,9 @@ PropertiesPage::define_landmarks_pressed () { if (mp_direct_image) { img::LandmarksDialog dialog (this, *mp_direct_image); - dialog.exec (); + if (dialog.exec ()) { + emit edited (); + } } } diff --git a/src/img/img/imgPropertiesPage.h b/src/img/img/imgPropertiesPage.h index 1de6a3f88..8a45bd186 100644 --- a/src/img/img/imgPropertiesPage.h +++ b/src/img/img/imgPropertiesPage.h @@ -64,7 +64,7 @@ public: private slots: void browse (); - void value_return_pressed (); + void value_changed (); void color_mapping_changed (); void brightness_slider_changed (int value); void brightness_spinbox_changed (int value); @@ -83,8 +83,7 @@ private slots: void red_to_blue (); void blue_to_red (); void reverse_color_order (); - void min_max_return_pressed (); - void preview_checked (); + void min_max_value_changed (); void reset_pressed (); void save_pressed (); void define_landmarks_pressed (); @@ -95,11 +94,12 @@ private: img::Service *mp_service; img::Object *mp_direct_image; bool m_no_signals; + bool m_in_color_mapping_signal; void recompute_histogram (); void invalidate (); void init (); - void preview (); + void get_xmin_xmax (double &xmin, double &xmax, bool &has_error_out); }; }