diff --git a/agave_app/AppearanceDockWidget.cpp b/agave_app/AppearanceDockWidget.cpp index f909b54e..e2d7b59a 100644 --- a/agave_app/AppearanceDockWidget.cpp +++ b/agave_app/AppearanceDockWidget.cpp @@ -17,6 +17,9 @@ QAppearanceWidget::QAppearanceWidget(QWidget* pParent, QScrollArea* scrollArea = new QScrollArea(); scrollArea->setWidgetResizable(true); + // Make the inner appearance widget always shrink to the viewport's width; + // this prevents an expanded section from forcing a horizontal scrollbar. + m_AppearanceSettingsWidget.setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Preferred); scrollArea->setWidget(&m_AppearanceSettingsWidget); m_MainLayout.addWidget(scrollArea, 1, 0); diff --git a/agave_app/AppearanceSettingsWidget.cpp b/agave_app/AppearanceSettingsWidget.cpp index 2f4529a6..e2a5b63e 100644 --- a/agave_app/AppearanceSettingsWidget.cpp +++ b/agave_app/AppearanceSettingsWidget.cpp @@ -1,21 +1,27 @@ #include "AppearanceSettingsWidget.h" + +#include "Controls.h" #include "ObjectTransformMode.h" #include "QRenderSettings.h" #include "RangeWidget.h" #include "Section.h" -#include "ImageXYZC.h" +#include "tfeditor/gradients.h" + +#include "renderlib/ImageXYZC.h" #include "renderlib/AppScene.h" #include "renderlib/Colormap.h" #include "renderlib/Light.h" #include "renderlib/Logging.h" #include "renderlib/RenderSettings.h" -#include "tfeditor/gradients.h" #include #include +#include #include #include +#include +#include #include static QGradientStops @@ -40,6 +46,68 @@ swatchStopsForColorRamp(const ColorRamp& cr) return colormapToGradient(cr.m_stops); } +// Item delegate for the colormap dropdown. Paints each item's BackgroundRole +// brush (the colormap gradient) edge-to-edge with no inner border. The hover +// / selected state is rendered as a translucent overlay plus a focus outline, +// so the underlying colormap remains visible. +class GradientItemDelegate : public QAbstractItemDelegate +{ +public: + explicit GradientItemDelegate(QComboBox* combo) + : QAbstractItemDelegate(combo) + , m_combo(combo) + { + } + + void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override + { + painter->save(); + painter->setPen(Qt::NoPen); + QVariant bg = index.data(Qt::BackgroundRole); + if (bg.canConvert()) { + painter->setBrush(bg.value()); + } else { + painter->setBrush(option.palette.base()); + } + painter->drawRect(option.rect); + + QString text = index.data(Qt::DisplayRole).toString(); + if (!text.isEmpty()) { + painter->setPen(option.palette.color(QPalette::Text)); + painter->drawText(option.rect, Qt::AlignCenter, text); + } + + // Hover / selected state: translucent overlay + 1px outline so the + // colormap underneath remains visible. + if (option.state & (QStyle::State_Selected | QStyle::State_MouseOver)) { + QColor highlight = option.palette.color(QPalette::Highlight); + QColor overlay = highlight; + overlay.setAlpha(64); + painter->setPen(Qt::NoPen); + painter->setBrush(overlay); + painter->drawRect(option.rect); + + painter->setPen(QPen(highlight, 1)); + painter->setBrush(Qt::NoBrush); + painter->drawRect(option.rect.adjusted(0, 0, -1, -1)); + } + painter->restore(); + } + + QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override + { + Q_UNUSED(index); + int height = option.fontMetrics.height() + 4; + if (m_combo) { + height = std::max(height, m_combo->sizeHint().height()); + } + return { option.fontMetrics.averageCharWidth() * 10, height }; + } + +private: + QPointer m_combo; +}; + class GradientCombo : public QComboBox { public: @@ -63,14 +131,25 @@ class GradientCombo : public QComboBox QComboBox::paintEvent(e); QPainter painter(this); - painter.setPen(Qt::black); + painter.setPen(Qt::NoPen); painter.setBrush(itemData(currentIndex(), Qt::BackgroundRole).value()); QStyleOptionComboBox option; + option.initFrom(this); option.rect = rect(); - QRect r = style()->subControlRect(QStyle::CC_ComboBox, &option, QStyle::SC_ComboBoxEditField); - - painter.drawRect(r.adjusted(0, 0, -1, -1)); - painter.drawText(QRectF(0, 0, width(), height()), Qt::AlignCenter, itemText(currentIndex())); + QRect arrowRect = style()->subControlRect(QStyle::CC_ComboBox, &option, QStyle::SC_ComboBoxArrow, this); + + // Fill the entire widget area to the left of the dropdown arrow. + QRect fillRect = rect(); + fillRect.setRight(arrowRect.left() - 1); + painter.drawRect(fillRect); + painter.setPen(palette().color(QPalette::Text)); + painter.drawText(fillRect, Qt::AlignCenter, itemText(currentIndex())); + + // Draw a standard 1px border around the swatch using the palette's + // mid color (matches other framed widgets in the theme). + painter.setBrush(Qt::NoBrush); + painter.setPen(palette().color(QPalette::Mid)); + painter.drawRect(fillRect.adjusted(0, 0, -1, -1)); } }; @@ -78,6 +157,7 @@ static QComboBox* makeGradientCombo() { QComboBox* cb = new GradientCombo(); + cb->setItemDelegate(new GradientItemDelegate(cb)); const QStringList colorNames = QColor::colorNames(); int index = 0; for (auto& gspec : getBuiltInGradients()) { @@ -113,7 +193,7 @@ QAppearanceSettingsWidget::QAppearanceSettingsWidget(QWidget* pParent, QAction* pToggleRotateAction, QAction* pToggleTranslateAction) : QGroupBox(pParent) - , m_MainLayout() + , m_MainLayout(new QFormLayout()) , m_DensityScaleSlider() , m_RendererType() , m_ShadingType() @@ -123,76 +203,81 @@ QAppearanceSettingsWidget::QAppearanceSettingsWidget(QWidget* pParent, , m_qrendersettings(qrs) , m_transformMode(new ObjectTransformMode([this]() { return m_scene; }, qrs, this)) { - Controls::initFormLayout(m_MainLayout); - setLayout(&m_MainLayout); - - m_RendererType.setStatusTip(tr("Select volume rendering type")); - m_RendererType.setToolTip(tr("Select volume rendering type")); + Controls::initFormLayout(*m_MainLayout); + setLayout(m_MainLayout); m_RendererType.addItem("Ray march blending", 0); m_RendererType.addItem("Path Traced", 1); m_RendererType.setCurrentIndex(1); - m_MainLayout.addRow("Renderer", &m_RendererType); + Controls::addFormRow( + m_MainLayout, "Renderer", &m_RendererType, tr("Select volume rendering type"), tr("Select volume rendering type")); - m_DensityScaleSlider.setStatusTip(tr("Set scattering density for volume")); - m_DensityScaleSlider.setToolTip(tr("Set scattering density for volume")); m_DensityScaleSlider.setRange(0.001, 100.0); m_DensityScaleSlider.setDecimals(3); m_DensityScaleSlider.setValue(rs->m_RenderSettings.m_DensityScale); - m_MainLayout.addRow("Scattering Density", &m_DensityScaleSlider); + Controls::addFormRow(m_MainLayout, + "Scattering Density", + &m_DensityScaleSlider, + tr("Set scattering density for volume"), + tr("Set scattering density for volume")); - m_ShadingType.setStatusTip(tr("Select volume shading style")); - m_ShadingType.setToolTip(tr("Select volume shading style")); m_ShadingType.addItem("BRDF Only", 0); m_ShadingType.addItem("Phase Function Only", 1); m_ShadingType.addItem("Mixed", 2); m_ShadingType.setCurrentIndex(rs->m_RenderSettings.m_ShadingType); - m_MainLayout.addRow("Shading Type", &m_ShadingType); + Controls::addFormRow( + m_MainLayout, "Shading Type", &m_ShadingType, tr("Select volume shading style"), tr("Select volume shading style")); - m_GradientFactorSlider.setStatusTip(tr("Mix between BRDF and Phase shading")); - m_GradientFactorSlider.setToolTip(tr("Mix between BRDF and Phase shading")); m_GradientFactorSlider.setRange(0.0, 1.0); m_GradientFactorSlider.setDecimals(3); m_GradientFactorSlider.setValue(rs->m_RenderSettings.m_GradientFactor); - m_MainLayout.addRow("Shading Type Mixture", &m_GradientFactorSlider); + Controls::addFormRow(m_MainLayout, + "Shading Type Mixture", + &m_GradientFactorSlider, + tr("Mix between BRDF and Phase shading"), + tr("Mix between BRDF and Phase shading")); QObject::connect(&m_DensityScaleSlider, SIGNAL(valueChanged(double)), this, SLOT(OnSetDensityScale(double))); QObject::connect(&m_GradientFactorSlider, SIGNAL(valueChanged(double)), this, SLOT(OnSetGradientFactor(double))); - m_StepSizePrimaryRaySlider.setStatusTip(tr("Set volume ray march step size for camera rays")); - m_StepSizePrimaryRaySlider.setToolTip(tr("Set volume ray march step size for camera rays")); - // step size is in voxels and step sizes of less than 1 voxel are not very useful, while slowing down performance m_StepSizePrimaryRaySlider.setRange(1.0, 100.0); m_StepSizePrimaryRaySlider.setValue(rs->m_RenderSettings.m_StepSizeFactor); m_StepSizePrimaryRaySlider.setDecimals(3); - m_MainLayout.addRow("Primary Ray Step Size", &m_StepSizePrimaryRaySlider); + Controls::addFormRow(m_MainLayout, + "Primary Ray Step Size", + &m_StepSizePrimaryRaySlider, + tr("Set volume ray march step size for camera rays"), + tr("Set volume ray march step size for camera rays")); QObject::connect( &m_StepSizePrimaryRaySlider, SIGNAL(valueChanged(double)), this, SLOT(OnSetStepSizePrimaryRay(double))); - m_StepSizeSecondaryRaySlider.setStatusTip(tr("Set volume ray march step size for scattered rays")); - m_StepSizeSecondaryRaySlider.setToolTip(tr("Set volume ray march step size for scattered rays")); m_StepSizeSecondaryRaySlider.setRange(1.0, 100.0); m_StepSizeSecondaryRaySlider.setValue(rs->m_RenderSettings.m_StepSizeFactorShadow); m_StepSizeSecondaryRaySlider.setDecimals(3); - m_MainLayout.addRow("Secondary Ray Step Size", &m_StepSizeSecondaryRaySlider); + Controls::addFormRow(m_MainLayout, + "Secondary Ray Step Size", + &m_StepSizeSecondaryRaySlider, + tr("Set volume ray march step size for scattered rays"), + tr("Set volume ray march step size for scattered rays")); QObject::connect( &m_StepSizeSecondaryRaySlider, SIGNAL(valueChanged(double)), this, SLOT(OnSetStepSizeSecondaryRay(double))); m_interpolateCheckBox.setChecked(true); - m_interpolateCheckBox.setStatusTip(tr("Interpolated volume sampling")); - m_interpolateCheckBox.setToolTip(tr("Interpolated volume sampling")); - m_MainLayout.addRow("Interpolate", &m_interpolateCheckBox); + Controls::addFormRow(m_MainLayout, + "Interpolate", + &m_interpolateCheckBox, + tr("Interpolated volume sampling"), + tr("Interpolated volume sampling")); QObject::connect(&m_interpolateCheckBox, &QCheckBox::clicked, [this](const bool is_checked) { this->OnInterpolateChecked(is_checked); }); - m_backgroundColorButton.setStatusTip(tr("Set background color")); - m_backgroundColorButton.setToolTip(tr("Set background color")); m_backgroundColorButton.SetColor(QColor(0, 0, 0), true); - m_MainLayout.addRow("Background Color", &m_backgroundColorButton); + Controls::addFormRow( + m_MainLayout, "Background Color", &m_backgroundColorButton, tr("Set background color"), tr("Set background color")); QObject::connect(&m_backgroundColorButton, &QColorPushButton::currentColorChanged, [this](const QColor& c) { this->OnBackgroundColorChanged(c); @@ -209,7 +294,8 @@ QAppearanceSettingsWidget::QAppearanceSettingsWidget(QWidget* pParent, m_boundingBoxColorButton.SetColor(QColor(255, 255, 255), true); bboxLayout->addWidget(&m_boundingBoxColorButton, 1); - m_MainLayout.addRow("Bounding Box", bboxLayout); + Controls::addFormRow( + m_MainLayout, "Bounding Box", bboxLayout, tr("Show/hide bounding box"), tr("Show/hide bounding box")); QObject::connect(&m_showBoundingBoxCheckBox, &QCheckBox::clicked, [this](const bool is_checked) { this->OnShowBoundsChecked(is_checked); @@ -219,17 +305,15 @@ QAppearanceSettingsWidget::QAppearanceSettingsWidget(QWidget* pParent, }); m_showScaleBarCheckBox.setChecked(false); - m_showScaleBarCheckBox.setStatusTip(tr("Show/hide scale bar")); - m_showScaleBarCheckBox.setToolTip(tr("Show/hide scale bar")); - m_MainLayout.addRow("Scale Bar", &m_showScaleBarCheckBox); + Controls::addFormRow( + m_MainLayout, "Scale Bar", &m_showScaleBarCheckBox, tr("Show/hide scale bar"), tr("Show/hide scale bar")); QObject::connect(&m_showScaleBarCheckBox, &QCheckBox::clicked, [this](const bool is_checked) { this->OnShowScaleBarChecked(is_checked); }); m_showTimeStampCheckBox.setChecked(false); - m_showTimeStampCheckBox.setStatusTip(tr("Show/hide timestamps")); - m_showTimeStampCheckBox.setToolTip(tr("Show/hide timestamps")); - m_MainLayout.addRow("Timestamps", &m_showTimeStampCheckBox); + Controls::addFormRow( + m_MainLayout, "Timestamps", &m_showTimeStampCheckBox, tr("Show/hide timestamps"), tr("Show/hide timestamps")); QObject::connect(&m_showTimeStampCheckBox, &QCheckBox::clicked, [this](const bool is_checked) { this->OnShowTimeStampChecked(is_checked); }); @@ -237,9 +321,11 @@ QAppearanceSettingsWidget::QAppearanceSettingsWidget(QWidget* pParent, m_timeStampFormatComboBox.addItem(tr("HH:MM:SS")); m_timeStampFormatComboBox.addItem(tr("Time Units")); m_timeStampFormatComboBox.setCurrentIndex(1); - m_timeStampFormatComboBox.setStatusTip(tr("Choose timestamp display format")); - m_timeStampFormatComboBox.setToolTip(tr("Choose timestamp display format")); - m_MainLayout.addRow("Timestamp Format", &m_timeStampFormatComboBox); + Controls::addFormRow(m_MainLayout, + "Timestamp Format", + &m_timeStampFormatComboBox, + tr("Choose timestamp display format"), + tr("Choose timestamp display format")); QObject::connect(&m_timeStampFormatComboBox, QOverload::of(&QComboBox::currentIndexChanged), [this](int index) { this->OnTimeStampFormatChanged(index); }); @@ -302,7 +388,7 @@ QAppearanceSettingsWidget::QAppearanceSettingsWidget(QWidget* pParent, m_zFlipCheckBox, &QCheckBox::clicked, [this](bool flipValue) { this->OnFlipAxis(Axis::Z, flipValue); }); m_scaleSection->setContentLayout(*scaleSectionLayout); - m_MainLayout.addRow(m_scaleSection); + m_MainLayout->addRow(m_scaleSection); m_clipRoiSection = new Section("ROI", 0); auto* roiSectionLayout = new QGridLayout(); @@ -341,23 +427,23 @@ QAppearanceSettingsWidget::QAppearanceSettingsWidget(QWidget* pParent, roiSectionLayout->setColumnStretch(1, 3); m_clipRoiSection->setContentLayout(*roiSectionLayout); - m_MainLayout.addRow(m_clipRoiSection); + m_MainLayout->addRow(m_clipRoiSection); Section* sectionCP = createClipPlaneSection(pToggleRotateAction, pToggleTranslateAction); - m_MainLayout.addRow(sectionCP); + m_MainLayout->addRow(sectionCP); QFrame* lineB = new QFrame(); lineB->setFrameShape(QFrame::HLine); lineB->setFrameShadow(QFrame::Sunken); - m_MainLayout.addRow(lineB); + m_MainLayout->addRow(lineB); // create a "lock lights to camera" checkbox m_lockLightsToCameraCheckBox = new QCheckBox("Lock Lights to Camera"); m_lockLightsToCameraCheckBox->setStatusTip(tr("When checked, interactive volume rotation will not rotate lights")); m_lockLightsToCameraCheckBox->setToolTip(tr("When checked, interactive volume rotation will not rotate lights")); - m_lockLightsToCameraCheckBox->setChecked(m_scene ? m_scene->m_lighting.lockToCamera : false); - m_MainLayout.addRow(m_lockLightsToCameraCheckBox); + m_lockLightsToCameraCheckBox->setChecked(m_scene ? m_scene->m_lighting.lockToCamera : true); + m_MainLayout->addRow(m_lockLightsToCameraCheckBox); QObject::connect(m_lockLightsToCameraCheckBox, &QCheckBox::clicked, [this](bool is_checked) { if (m_scene) { m_scene->setLockLightsToCamera(is_checked); @@ -365,14 +451,14 @@ QAppearanceSettingsWidget::QAppearanceSettingsWidget(QWidget* pParent, }); Section* section = createAreaLightingControls(pToggleRotateAction); - m_MainLayout.addRow(section); + m_MainLayout->addRow(section); Section* section2 = createSkyLightingControls(pToggleRotateAction); - m_MainLayout.addRow(section2); + m_MainLayout->addRow(section2); QFrame* lineA = new QFrame(); lineA->setFrameShape(QFrame::HLine); lineA->setFrameShadow(QFrame::Sunken); - m_MainLayout.addRow(lineA); + m_MainLayout->addRow(lineA); QObject::connect(&m_RendererType, SIGNAL(currentIndexChanged(int)), this, SLOT(OnSetRendererType(int))); QObject::connect(&m_ShadingType, SIGNAL(currentIndexChanged(int)), this, SLOT(OnSetShadingType(int))); @@ -420,8 +506,6 @@ QAppearanceSettingsWidget::createClipPlaneSection(QAction* pToggleRotateAction, m_hideUserClipPlane = new QCheckBox(); m_hideUserClipPlane->setChecked(false); - m_hideUserClipPlane->setStatusTip(tr("Hide clip plane grid in viewport")); - m_hideUserClipPlane->setToolTip(tr("Hide clip plane grid in viewport")); QObject::connect( m_hideUserClipPlane, &QCheckBox::clicked, [this, pToggleRotateAction, pToggleTranslateAction](bool toggled) { if (!this->m_scene) { @@ -432,7 +516,11 @@ QAppearanceSettingsWidget::createClipPlaneSection(QAction* pToggleRotateAction, p->setVisible(!toggled); }); - sectionLayout->addRow("Hide", m_hideUserClipPlane); + Controls::addFormRow(sectionLayout, + "Hide", + m_hideUserClipPlane, + tr("Hide clip plane grid in viewport"), + tr("Hide clip plane grid in viewport")); // Add the Reset button m_clipPlaneResetButton = new QPushButton("Reset"); @@ -488,42 +576,44 @@ QAppearanceSettingsWidget::createAreaLightingControls(QAction* pRotationAction) sectionLayout->addLayout(btnLayout, sectionLayout->rowCount(), 0, 1, 2); m_lt0gui.m_thetaSlider = new QNumericSlider(); - m_lt0gui.m_thetaSlider->setStatusTip(tr("Set angle theta for area light")); - m_lt0gui.m_thetaSlider->setToolTip(tr("Set angle theta for area light")); m_lt0gui.m_thetaSlider->setRange(0.0, TWO_PI_F); m_lt0gui.m_thetaSlider->setSingleStep(TWO_PI_F / 100.0); m_lt0gui.m_thetaSlider->setValue(0.0); - sectionLayout->addRow("Theta", m_lt0gui.m_thetaSlider); + Controls::addFormRow(sectionLayout, + "Theta", + m_lt0gui.m_thetaSlider, + tr("Set angle theta for area light"), + tr("Set angle theta for area light")); QObject::connect( m_lt0gui.m_thetaSlider, &QNumericSlider::valueChanged, this, &QAppearanceSettingsWidget::OnSetAreaLightTheta); m_lt0gui.m_phiSlider = new QNumericSlider(); - m_lt0gui.m_phiSlider->setStatusTip(tr("Set angle phi for area light")); - m_lt0gui.m_phiSlider->setToolTip(tr("Set angle phi for area light")); m_lt0gui.m_phiSlider->setRange(0.0, PI_F); m_lt0gui.m_phiSlider->setSingleStep(PI_F / 100.0); m_lt0gui.m_phiSlider->setValue(HALF_PI_F); - sectionLayout->addRow("Phi", m_lt0gui.m_phiSlider); + Controls::addFormRow( + sectionLayout, "Phi", m_lt0gui.m_phiSlider, tr("Set angle phi for area light"), tr("Set angle phi for area light")); QObject::connect( m_lt0gui.m_phiSlider, &QNumericSlider::valueChanged, this, &QAppearanceSettingsWidget::OnSetAreaLightPhi); m_lt0gui.m_sizeSlider = new QNumericSlider(); - m_lt0gui.m_sizeSlider->setStatusTip(tr("Set size for area light")); - m_lt0gui.m_sizeSlider->setToolTip(tr("Set size for area light")); m_lt0gui.m_sizeSlider->setRange(0.1, 5.0); m_lt0gui.m_sizeSlider->setSingleStep(5.0 / 100.0); m_lt0gui.m_sizeSlider->setValue(1.0); - sectionLayout->addRow("Size", m_lt0gui.m_sizeSlider); + Controls::addFormRow( + sectionLayout, "Size", m_lt0gui.m_sizeSlider, tr("Set size for area light"), tr("Set size for area light")); QObject::connect( m_lt0gui.m_sizeSlider, &QNumericSlider::valueChanged, this, &QAppearanceSettingsWidget::OnSetAreaLightSize); m_lt0gui.m_distSlider = new QNumericSlider(); - m_lt0gui.m_distSlider->setStatusTip(tr("Set distance for area light")); - m_lt0gui.m_distSlider->setToolTip(tr("Set distance for area light")); m_lt0gui.m_distSlider->setRange(0.1, 10.0); m_lt0gui.m_distSlider->setSingleStep(1.0); m_lt0gui.m_distSlider->setValue(10.0); - sectionLayout->addRow("Distance", m_lt0gui.m_distSlider); + Controls::addFormRow(sectionLayout, + "Distance", + m_lt0gui.m_distSlider, + tr("Set distance for area light"), + tr("Set distance for area light")); QObject::connect( m_lt0gui.m_distSlider, &QNumericSlider::valueChanged, this, &QAppearanceSettingsWidget::OnSetAreaLightDistance); @@ -541,7 +631,11 @@ QAppearanceSettingsWidget::createAreaLightingControls(QAction* pRotationAction) m_lt0gui.m_areaLightColorButton->setToolTip(tr("Set color for area light")); arealightLayout->addWidget(m_lt0gui.m_areaLightColorButton, 0); arealightLayout->setContentsMargins(0, 0, 0, 0); - sectionLayout->addRow("Intensity", arealightLayout); + Controls::addFormRow(sectionLayout, + "Intensity", + arealightLayout, + tr("Set intensity for area light"), + tr("Set intensity for area light")); QObject::connect(m_lt0gui.m_areaLightColorButton, &QColorPushButton::currentColorChanged, [this](const QColor& c) { this->OnSetAreaLightColor(this->m_lt0gui.m_intensitySlider->value(), c); }); @@ -604,7 +698,11 @@ QAppearanceSettingsWidget::createSkyLightingControls(QAction* pRotationAction) m_lt1gui.m_stColorButton->setStatusTip(tr("Set color for top of skylight sphere")); m_lt1gui.m_stColorButton->setToolTip(tr("Set color for top of skylight sphere")); skylightTopLayout->addWidget(m_lt1gui.m_stColorButton); - sectionLayout->addRow("Top", skylightTopLayout); + Controls::addFormRow(sectionLayout, + "Top", + skylightTopLayout, + tr("Set intensity/color for top of skylight sphere"), + tr("Set intensity/color for top of skylight sphere")); QObject::connect(m_lt1gui.m_stColorButton, &QColorPushButton::currentColorChanged, [this](const QColor& c) { this->OnSetSkyLightTopColor(this->m_lt1gui.m_stintensitySlider->value(), c); }); @@ -623,7 +721,11 @@ QAppearanceSettingsWidget::createSkyLightingControls(QAction* pRotationAction) m_lt1gui.m_smColorButton->setStatusTip(tr("Set color for middle of skylight sphere")); m_lt1gui.m_smColorButton->setToolTip(tr("Set color for middle of skylight sphere")); skylightMidLayout->addWidget(m_lt1gui.m_smColorButton); - sectionLayout->addRow("Mid", skylightMidLayout); + Controls::addFormRow(sectionLayout, + "Mid", + skylightMidLayout, + tr("Set intensity/color for middle of skylight sphere"), + tr("Set intensity/color for middle of skylight sphere")); QObject::connect(m_lt1gui.m_smColorButton, &QColorPushButton::currentColorChanged, [this](const QColor& c) { this->OnSetSkyLightMidColor(this->m_lt1gui.m_smintensitySlider->value(), c); }); @@ -642,7 +744,11 @@ QAppearanceSettingsWidget::createSkyLightingControls(QAction* pRotationAction) m_lt1gui.m_sbColorButton->setStatusTip(tr("Set color for bottom of skylight sphere")); m_lt1gui.m_sbColorButton->setToolTip(tr("Set color for bottom of skylight sphere")); skylightBotLayout->addWidget(m_lt1gui.m_sbColorButton); - sectionLayout->addRow("Bot", skylightBotLayout); + Controls::addFormRow(sectionLayout, + "Bot", + skylightBotLayout, + tr("Set intensity/color for bottom of skylight sphere"), + tr("Set intensity/color for bottom of skylight sphere")); QObject::connect(m_lt1gui.m_sbColorButton, &QColorPushButton::currentColorChanged, [this](const QColor& c) { this->OnSetSkyLightBotColor(this->m_lt1gui.m_sbintensitySlider->value(), c); }); @@ -1263,12 +1369,11 @@ QAppearanceSettingsWidget::onNewImage(Scene* scene) this->OnUpdateLut(i, std::vector()); QNumericSlider* opacitySlider = new QNumericSlider(); - opacitySlider->setStatusTip(tr("Set opacity for channel")); - opacitySlider->setToolTip(tr("Set opacity for channel")); opacitySlider->setRange(0.0, 1.0); opacitySlider->setSingleStep(0.01); opacitySlider->setValue(scene->m_material.m_opacity[i], true); - sectionLayout->addRow("Opacity", opacitySlider); + Controls::addFormRow( + sectionLayout, "Opacity", opacitySlider, tr("Set opacity for channel"), tr("Set opacity for channel")); QObject::connect( opacitySlider, &QNumericSlider::valueChanged, [i, this](double d) { this->OnOpacityChanged(i, d); }); @@ -1283,10 +1388,6 @@ QAppearanceSettingsWidget::onNewImage(Scene* scene) // get color ramp from scene const ColorRamp& cr = scene->m_material.m_colormap[i]; QComboBox* gradients = makeGradientCombo(); - gradients->setToolTip(tr( - "Set colormap for channel. ColorMap will be multiplied with Color. To use ColorMap only, set Color to white.")); - gradients->setStatusTip(tr( - "Set colormap for channel. ColorMap will be multiplied with Color. To use ColorMap only, set Color to white.")); int idx = gradients->findData(QVariant(cr.m_name.c_str()), Qt::UserRole); // Reflect the current colormap in the section's swatch. The combo's @@ -1294,7 +1395,13 @@ QAppearanceSettingsWidget::onNewImage(Scene* scene) // user interaction. section->setColormapStops(swatchStopsForColorRamp(cr)); - sectionLayout->addRow("ColorMap", gradients); + Controls::addFormRow( + sectionLayout, + "ColorMap", + gradients, + tr("Set colormap for channel. ColorMap will be multiplied with Color. To use ColorMap only, set Color to white."), + tr("Set colormap for channel. ColorMap will be multiplied with Color. To use ColorMap only, set Color to " + "white.")); QObject::connect(gradients, &QComboBox::currentIndexChanged, [i, gradients, section, this](int index) { // get string from userdata std::string name = gradients->itemData(index).toString().toStdString(); @@ -1318,10 +1425,9 @@ QAppearanceSettingsWidget::onNewImage(Scene* scene) gradients->setCurrentIndex(idx); QColorPushButton* diffuseColorButton = new QColorPushButton(); - diffuseColorButton->setStatusTip(tr("Set color for channel")); - diffuseColorButton->setToolTip(tr("Set color for channel")); diffuseColorButton->SetColor(cdiff, true); - sectionLayout->addRow("Color", diffuseColorButton); + Controls::addFormRow( + sectionLayout, "Color", diffuseColorButton, tr("Set color for channel"), tr("Set color for channel")); QObject::connect(diffuseColorButton, &QColorPushButton::currentColorChanged, [i, this, section](const QColor& c) { this->OnDiffuseColorChanged(i, c); section->setColor(c); @@ -1340,13 +1446,15 @@ QAppearanceSettingsWidget::onNewImage(Scene* scene) sectionLayout->addWidget(separator2, sectionLayout->rowCount(), 0, 1, 2); QColorPushButton* specularColorButton = new QColorPushButton(); - specularColorButton->setStatusTip(tr("Set specular color for channel")); - specularColorButton->setToolTip(tr("Set specular color for channel")); QColor cspec = QColor::fromRgbF(scene->m_material.m_specular[i * 3 + 0], scene->m_material.m_specular[i * 3 + 1], scene->m_material.m_specular[i * 3 + 2]); specularColorButton->SetColor(cspec, true); - sectionLayout->addRow("SpecularColor", specularColorButton); + Controls::addFormRow(sectionLayout, + "SpecularColor", + specularColorButton, + tr("Set specular color for channel"), + tr("Set specular color for channel")); QObject::connect(specularColorButton, &QColorPushButton::currentColorChanged, [i, this](const QColor& c) { this->OnSpecularColorChanged(i, c); }); @@ -1354,13 +1462,15 @@ QAppearanceSettingsWidget::onNewImage(Scene* scene) this->OnSpecularColorChanged(i, cspec); QColorPushButton* emissiveColorButton = new QColorPushButton(); - emissiveColorButton->setStatusTip(tr("Set emissive color for channel")); - emissiveColorButton->setToolTip(tr("Set emissive color for channel")); QColor cemis = QColor::fromRgbF(scene->m_material.m_emissive[i * 3 + 0], scene->m_material.m_emissive[i * 3 + 1], scene->m_material.m_emissive[i * 3 + 2]); emissiveColorButton->SetColor(cemis, true); - sectionLayout->addRow("EmissiveColor", emissiveColorButton); + Controls::addFormRow(sectionLayout, + "EmissiveColor", + emissiveColorButton, + tr("Set emissive color for channel"), + tr("Set emissive color for channel")); QObject::connect(emissiveColorButton, &QColorPushButton::currentColorChanged, [i, this](const QColor& c) { this->OnEmissiveColorChanged(i, c); }); @@ -1368,12 +1478,14 @@ QAppearanceSettingsWidget::onNewImage(Scene* scene) this->OnEmissiveColorChanged(i, cemis); QNumericSlider* roughnessSlider = new QNumericSlider(); - roughnessSlider->setStatusTip(tr("Set specular glossiness for channel")); - roughnessSlider->setToolTip(tr("Set specular glossiness for channel")); roughnessSlider->setRange(0.0, 100.0); roughnessSlider->setSingleStep(0.01); roughnessSlider->setValue(scene->m_material.m_roughness[i]); - sectionLayout->addRow("Glossiness", roughnessSlider); + Controls::addFormRow(sectionLayout, + "Glossiness", + roughnessSlider, + tr("Set specular glossiness for channel"), + tr("Set specular glossiness for channel")); QObject::connect( roughnessSlider, &QNumericSlider::valueChanged, [i, this](double d) { this->OnRoughnessChanged(i, d); }); this->OnRoughnessChanged(i, scene->m_material.m_roughness[i]); @@ -1383,7 +1495,7 @@ QAppearanceSettingsWidget::onNewImage(Scene* scene) section->setContentLayout(*fullLayout); // assumes per-channel sections are at the very end of the m_MainLayout - m_MainLayout.addRow(section); + m_MainLayout->addRow(section); m_channelSections.push_back(section); } } diff --git a/agave_app/AppearanceSettingsWidget.h b/agave_app/AppearanceSettingsWidget.h index 9420eb68..a6a83693 100644 --- a/agave_app/AppearanceSettingsWidget.h +++ b/agave_app/AppearanceSettingsWidget.h @@ -93,7 +93,7 @@ public slots: private: Scene* m_scene{ nullptr }; - QFormLayout m_MainLayout; + QFormLayout* m_MainLayout; QNumericSlider m_DensityScaleSlider; QComboBox m_RendererType; QComboBox m_ShadingType; diff --git a/agave_app/CameraWidget.cpp b/agave_app/CameraWidget.cpp index c273aaf5..60447c23 100644 --- a/agave_app/CameraWidget.cpp +++ b/agave_app/CameraWidget.cpp @@ -11,66 +11,68 @@ QCameraWidget::QCameraWidget(QWidget* pParent, QCamera* cam, RenderSettings* rs) setLayout(&m_MainLayout); // Exposure, controls how bright or dim overall scene is - m_ExposureSlider.setStatusTip(tr("Set Exposure")); - m_ExposureSlider.setToolTip(tr("Set camera exposure")); m_ExposureSlider.setRange(0.0f, 1.0f); m_ExposureSlider.setValue(cam->GetFilm().GetExposure()); m_ExposureSlider.setDecimals(2); m_ExposureSlider.setSingleStep(0.01); - m_MainLayout.addRow("Exposure", &m_ExposureSlider); + Controls::addFormRow(&m_MainLayout, "Exposure", &m_ExposureSlider, tr("Set camera exposure"), tr("Set Exposure")); connect(&m_ExposureSlider, &QNumericSlider::valueChanged, this, &QCameraWidget::SetExposure); // Number of render iterations per viewport update - m_ExposureIterationsSpinner.setStatusTip(tr("Set Exposure Time")); - m_ExposureIterationsSpinner.setToolTip(tr("Set number of samples to accumulate per viewport update")); m_ExposureIterationsSpinner.addItem("1", 1); m_ExposureIterationsSpinner.addItem("2", 2); m_ExposureIterationsSpinner.addItem("4", 4); m_ExposureIterationsSpinner.addItem("8", 8); m_ExposureIterationsSpinner.setCurrentIndex( m_ExposureIterationsSpinner.findData(cam->GetFilm().GetExposureIterations())); - m_MainLayout.addRow("Exposure Time", &m_ExposureIterationsSpinner); + Controls::addFormRow(&m_MainLayout, + "Exposure Time", + &m_ExposureIterationsSpinner, + tr("Set number of samples to accumulate per viewport update"), + tr("Set Exposure Time")); connect(&m_ExposureIterationsSpinner, &QComboBox::currentIndexChanged, this, &QCameraWidget::SetExposureIterations); - m_NoiseReduction.setStatusTip(tr("Enable denoising pass")); - m_NoiseReduction.setToolTip(tr("Enable denoising pass")); m_NoiseReduction.setCheckState(rs->m_DenoiseParams.m_Enabled ? Qt::CheckState::Checked : Qt::CheckState::Unchecked); - m_MainLayout.addRow("Noise Reduction", &m_NoiseReduction); + Controls::addFormRow( + &m_MainLayout, "Noise Reduction", &m_NoiseReduction, tr("Enable denoising pass"), tr("Enable denoising pass")); connect(&m_NoiseReduction, &QCheckBox::stateChanged, this, &QCameraWidget::OnNoiseReduction); - m_ApertureSizeSlider.setStatusTip(tr("Set camera aperture size")); - m_ApertureSizeSlider.setToolTip(tr("Set camera aperture size")); m_ApertureSizeSlider.setRange(0.0, 0.1); m_ApertureSizeSlider.setSuffix(" mm"); m_ApertureSizeSlider.setDecimals(2); m_ApertureSizeSlider.setValue(0.0); m_ApertureSizeSlider.setSingleStep(0.01); - m_MainLayout.addRow("Aperture Size", &m_ApertureSizeSlider); + Controls::addFormRow(&m_MainLayout, + "Aperture Size", + &m_ApertureSizeSlider, + tr("Set camera aperture size"), + tr("Set camera aperture size")); connect(&m_ApertureSizeSlider, &QNumericSlider::valueChanged, this, &QCameraWidget::SetAperture); - m_FieldOfViewSlider.setStatusTip(tr("Set camera field of view angle")); - m_FieldOfViewSlider.setToolTip(tr("Set camera field of view angle")); m_FieldOfViewSlider.setRange(10.0, 150.0); m_FieldOfViewSlider.setDecimals(2); m_FieldOfViewSlider.setValue(cam->GetProjection().GetFieldOfView()); m_FieldOfViewSlider.setSuffix(" deg."); - m_MainLayout.addRow("Field of view", &m_FieldOfViewSlider); + Controls::addFormRow(&m_MainLayout, + "Field of view", + &m_FieldOfViewSlider, + tr("Set camera field of view angle"), + tr("Set camera field of view angle")); connect(&m_FieldOfViewSlider, &QNumericSlider::valueChanged, this, &QCameraWidget::SetFieldOfView); // Focal distance - m_FocalDistanceSlider.setStatusTip(tr("Set focal distance")); - m_FocalDistanceSlider.setToolTip(tr("Set focal distance")); m_FocalDistanceSlider.setRange(0.0, 15.0); m_FocalDistanceSlider.setDecimals(2); m_FocalDistanceSlider.setValue(0.0); m_FocalDistanceSlider.setSuffix(" m"); - m_MainLayout.addRow("Focal distance", &m_FocalDistanceSlider); + Controls::addFormRow( + &m_MainLayout, "Focal distance", &m_FocalDistanceSlider, tr("Set focal distance"), tr("Set focal distance")); connect(&m_FocalDistanceSlider, &QNumericSlider::valueChanged, this, &QCameraWidget::SetFocalDistance); diff --git a/agave_app/Controls.cpp b/agave_app/Controls.cpp index a06d081b..2af3c62f 100644 --- a/agave_app/Controls.cpp +++ b/agave_app/Controls.cpp @@ -557,6 +557,8 @@ AgaveFormLayout::addRow(const QString& label, QWidget* widget) int row = rowCount(); auto* labelWidget = new QLabel(label); labelWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + labelWidget->setToolTip(widget->toolTip()); + labelWidget->setStatusTip(widget->statusTip()); addWidget(labelWidget, row, 0, Qt::AlignLeft); addWidget(widget, row, 1); } @@ -571,6 +573,13 @@ AgaveFormLayout::addRow(const QString& label, QLayout* layout) addLayout(layout, row, 1); } +void +AgaveFormLayout::addRow(QWidget* section) +{ + int row = rowCount(); + addWidget(section, row, 0, 1, 2); +} + QFormLayout* Controls::createFormLayout(QWidget* parent) { @@ -597,3 +606,67 @@ Controls::createAgaveFormLayout(QWidget* parent) layout->setColumnStretch(1, 100); return layout; } + +static void +applyTipsToWidget(QWidget* w, const QString& toolTip, const QString& statusTip) +{ + if (!w) { + return; + } + if (!toolTip.isEmpty()) { + w->setToolTip(toolTip); + } + if (!statusTip.isEmpty()) { + w->setStatusTip(statusTip); + } +} + +void +Controls::addFormRow(QFormLayout* layout, + const QString& labelText, + QWidget* field, + const QString& toolTip, + const QString& statusTip) +{ + layout->addRow(labelText, field); + applyTipsToWidget(field, toolTip, statusTip); + applyTipsToWidget(layout->labelForField(field), toolTip, statusTip); +} + +void +Controls::addFormRow(QFormLayout* layout, + const QString& labelText, + QLayout* fieldLayout, + const QString& toolTip, + const QString& statusTip) +{ + layout->addRow(labelText, fieldLayout); + applyTipsToWidget(layout->labelForField(fieldLayout), toolTip, statusTip); +} + +void +Controls::addFormRow(AgaveFormLayout* layout, + const QString& labelText, + QWidget* field, + const QString& toolTip, + const QString& statusTip) +{ + // Apply to the field first so AgaveFormLayout::addRow's existing tooltip-copy + // logic also picks it up, then explicitly apply to the label as well. + applyTipsToWidget(field, toolTip, statusTip); + layout->addRow(labelText, field); + QLayoutItem* item = layout->itemAtPosition(layout->rowCount() - 1, 0); + applyTipsToWidget(item ? item->widget() : nullptr, toolTip, statusTip); +} + +void +Controls::addFormRow(AgaveFormLayout* layout, + const QString& labelText, + QLayout* fieldLayout, + const QString& toolTip, + const QString& statusTip) +{ + layout->addRow(labelText, fieldLayout); + QLayoutItem* item = layout->itemAtPosition(layout->rowCount() - 1, 0); + applyTipsToWidget(item ? item->widget() : nullptr, toolTip, statusTip); +} diff --git a/agave_app/Controls.h b/agave_app/Controls.h index 980380b9..dc7522d4 100644 --- a/agave_app/Controls.h +++ b/agave_app/Controls.h @@ -256,6 +256,7 @@ class AgaveFormLayout : public QGridLayout } void addRow(const QString& label, QWidget* widget); void addRow(const QString& label, QLayout* layout); + void addRow(QWidget* section); }; class Controls @@ -265,6 +266,33 @@ class Controls static void initFormLayout(QFormLayout& layout); static AgaveFormLayout* createAgaveFormLayout(QWidget* parent = nullptr); + + // Add a row to a QFormLayout and apply the given toolTip/statusTip to BOTH the + // field widget and the auto-created label. Empty strings are skipped so existing + // tooltips/statusTips on the widget are not erased. + static void addFormRow(QFormLayout* layout, + const QString& labelText, + QWidget* field, + const QString& toolTip, + const QString& statusTip = QString()); + static void addFormRow(QFormLayout* layout, + const QString& labelText, + QLayout* fieldLayout, + const QString& toolTip, + const QString& statusTip = QString()); + + // Same as above but for AgaveFormLayout. The label is located at column 0 of + // the just-added row. + static void addFormRow(AgaveFormLayout* layout, + const QString& labelText, + QWidget* field, + const QString& toolTip, + const QString& statusTip = QString()); + static void addFormRow(AgaveFormLayout* layout, + const QString& labelText, + QLayout* fieldLayout, + const QString& toolTip, + const QString& statusTip = QString()); }; /** diff --git a/agave_app/tfeditor/gradients.cpp b/agave_app/tfeditor/gradients.cpp index 1c24a233..f5b8a6ad 100644 --- a/agave_app/tfeditor/gradients.cpp +++ b/agave_app/tfeditor/gradients.cpp @@ -892,6 +892,7 @@ GradientWidget::GradientWidget(const Histogram& histogram, GradientData* dataObj btnGroup->addButton(customButton, CUSTOM_BTNID); QHBoxLayout* hbox = new QHBoxLayout(); hbox->setSpacing(0); + hbox->setContentsMargins(0, 0, 0, 0); int initialButtonId = WINDOW_LEVEL_BTNID; GradientEditMode m = m_gradientData->m_activeMode; @@ -910,22 +911,27 @@ GradientWidget::GradientWidget(const Histogram& histogram, GradientData* dataObj QWidget* firstPageWidget = new QWidget; auto* section0Layout = Controls::createAgaveFormLayout(); + section0Layout->setContentsMargins(0, 0, 0, 0); firstPageWidget->setLayout(section0Layout); QWidget* secondPageWidget = new QWidget; auto* section1Layout = Controls::createAgaveFormLayout(); + section1Layout->setContentsMargins(0, 0, 0, 0); secondPageWidget->setLayout(section1Layout); QWidget* thirdPageWidget = new QWidget; auto* section2Layout = Controls::createAgaveFormLayout(); + section2Layout->setContentsMargins(0, 0, 0, 0); thirdPageWidget->setLayout(section2Layout); QWidget* fourthPageWidget = new QWidget; auto* section3Layout = Controls::createAgaveFormLayout(); + section3Layout->setContentsMargins(0, 0, 0, 0); fourthPageWidget->setLayout(section3Layout); QWidget* fifthPageWidget = new QWidget; auto* section4Layout = Controls::createAgaveFormLayout(); + section4Layout->setContentsMargins(0, 0, 0, 0); fifthPageWidget->setLayout(section4Layout); QStackedLayout* stackedLayout = new QStackedLayout(mainGroupLayout); @@ -963,19 +969,23 @@ GradientWidget::GradientWidget(const Histogram& histogram, GradientData* dataObj }); minu16Slider = new QIntSlider(); - minu16Slider->setStatusTip(tr("Minimum u16 value")); - minu16Slider->setToolTip(tr("Set minimum u16 value")); minu16Slider->setRange(m_histogram.getDataMin(), m_histogram.getDataMax()); minu16Slider->setSingleStep(1); minu16Slider->setValue(m_gradientData->m_minu16); - section0Layout->addRow("Min u16", minu16Slider); + Controls::addFormRow(section0Layout, + "Min u16", + minu16Slider, + tr("Set minimum 16-bit intensity value"), + tr("Minimum 16-bit intensity value")); maxu16Slider = new QIntSlider(); - maxu16Slider->setStatusTip(tr("Maximum u16 value")); - maxu16Slider->setToolTip(tr("Set maximum u16 value")); maxu16Slider->setRange(m_histogram.getDataMin(), m_histogram.getDataMax()); maxu16Slider->setSingleStep(1); maxu16Slider->setValue(m_gradientData->m_maxu16); - section0Layout->addRow("Max u16", maxu16Slider); + Controls::addFormRow(section0Layout, + "Max u16", + maxu16Slider, + tr("Set maximum 16-bit intensity value"), + tr("Maximum 16-bit intensity value")); connect(minu16Slider, &QIntSlider::valueChanged, [this](int i) { this->m_gradientData->m_minu16 = i; this->onSetMinMax(i, this->m_gradientData->m_maxu16); @@ -986,21 +996,17 @@ GradientWidget::GradientWidget(const Histogram& histogram, GradientData* dataObj }); windowSlider = new QNumericSlider(); - windowSlider->setStatusTip(tr("Window")); - windowSlider->setToolTip(tr("Set size of range of intensities")); windowSlider->setRange(0.0, 1.0); windowSlider->setSingleStep(0.01); windowSlider->setDecimals(3); windowSlider->setValue(m_gradientData->m_window); - section1Layout->addRow("Window", windowSlider); + Controls::addFormRow(section1Layout, "Window", windowSlider, tr("Set size of range of intensities"), tr("Window")); levelSlider = new QNumericSlider(); - levelSlider->setStatusTip(tr("Level")); - levelSlider->setToolTip(tr("Set level of mid intensity")); levelSlider->setRange(0.0, 1.0); levelSlider->setSingleStep(0.01); levelSlider->setDecimals(3); levelSlider->setValue(m_gradientData->m_level); - section1Layout->addRow("Level", levelSlider); + Controls::addFormRow(section1Layout, "Level", levelSlider, tr("Set level of mid intensity"), tr("Level")); connect(windowSlider, &QNumericSlider::valueChanged, [this](double d) { this->m_gradientData->m_window = d; this->onSetWindowLevel(d, levelSlider->value()); @@ -1011,21 +1017,18 @@ GradientWidget::GradientWidget(const Histogram& histogram, GradientData* dataObj }); isovalueSlider = new QNumericSlider(); - isovalueSlider->setStatusTip(tr("Isovalue")); - isovalueSlider->setToolTip(tr("Set Isovalue")); isovalueSlider->setRange(0.0, 1.0); isovalueSlider->setSingleStep(0.01); isovalueSlider->setDecimals(3); isovalueSlider->setValue(m_gradientData->m_isovalue); - section2Layout->addRow("Isovalue", isovalueSlider); + Controls::addFormRow(section2Layout, "Isovalue", isovalueSlider, tr("Set Isovalue"), tr("Isovalue")); isorangeSlider = new QNumericSlider(); - isorangeSlider->setStatusTip(tr("Isovalue range")); - isorangeSlider->setToolTip(tr("Set range above and below isovalue")); isorangeSlider->setRange(0.0, 1.0); isorangeSlider->setSingleStep(0.01); isorangeSlider->setDecimals(3); isorangeSlider->setValue(m_gradientData->m_isorange); - section2Layout->addRow("Iso-range", isorangeSlider); + Controls::addFormRow( + section2Layout, "Iso-range", isorangeSlider, tr("Set range above and below isovalue"), tr("Isovalue range")); connect(isovalueSlider, &QNumericSlider::valueChanged, [this](double d) { this->m_gradientData->m_isovalue = d; this->onSetIsovalue(d, isorangeSlider->value()); @@ -1036,21 +1039,17 @@ GradientWidget::GradientWidget(const Histogram& histogram, GradientData* dataObj }); pctLowSlider = new QNumericSlider(); - pctLowSlider->setStatusTip(tr("Low percentile")); - pctLowSlider->setToolTip(tr("Set bottom percentile")); pctLowSlider->setRange(0.0, 1.0); pctLowSlider->setSingleStep(0.01); pctLowSlider->setDecimals(4); pctLowSlider->setValue(m_gradientData->m_pctLow); - section3Layout->addRow("Pct Min", pctLowSlider); + Controls::addFormRow(section3Layout, "Pct Min", pctLowSlider, tr("Set bottom percentile"), tr("Low percentile")); pctHighSlider = new QNumericSlider(); - pctHighSlider->setStatusTip(tr("High percentile")); - pctHighSlider->setToolTip(tr("Set top percentile")); pctHighSlider->setRange(0.0, 1.0); pctHighSlider->setSingleStep(0.01); pctHighSlider->setDecimals(4); pctHighSlider->setValue(m_gradientData->m_pctHigh); - section3Layout->addRow("Pct Max", pctHighSlider); + Controls::addFormRow(section3Layout, "Pct Max", pctHighSlider, tr("Set top percentile"), tr("High percentile")); connect(pctLowSlider, &QNumericSlider::valueChanged, [this](double d) { this->m_gradientData->m_pctLow = d; this->onSetHistogramPercentiles(d, pctHighSlider->value()); diff --git a/renderlib/Lighting.h b/renderlib/Lighting.h index e3b4e250..12d09ca9 100644 --- a/renderlib/Lighting.h +++ b/renderlib/Lighting.h @@ -61,7 +61,7 @@ class Lighting size_t m_NoLights{ 0 }; SceneLight* m_sceneLights[MAX_NO_LIGHTS]{ nullptr, nullptr, nullptr, nullptr }; - bool lockToCamera = false; + bool lockToCamera = true; glm::mat3 m_capturedRelativeBasis[MAX_NO_LIGHTS] = { glm::mat3(1.0f), glm::mat3(1.0f), glm::mat3(1.0f),