Skip to content

Add radar and overlay layer opacity control - #682

Draft
dpaulat wants to merge 2 commits into
developfrom
cursor/radar-layer-opacity-a385
Draft

Add radar and overlay layer opacity control#682
dpaulat wants to merge 2 commits into
developfrom
cursor/radar-layer-opacity-a385

Conversation

@dpaulat

@dpaulat dpaulat commented Aug 14, 2026

Copy link
Copy Markdown
Owner

Fixes SCWX-168 / #168.

Radar products (BR, BV, CC, and the rest) can now be faded on the fly so satellite imagery and streets show through. Overlay layers in Layer Manager get the same control; MapLibre map styles stay fully opaque.

What changed

  • Each overlay layer stores opacity (0–100%) in layers.json. Map Underlay and Map Symbology are locked at 100%.
  • Radar Toolbox → Map Settings has a Radar Opacity slider and percent field for live radar fading.
  • Layer Manager adds an Opacity column plus a slider/spin box for the selected overlay layer(s).
  • Fragment shaders multiply output alpha by the current layer opacity so radar, alerts, placefiles, markers, overlay products, and the color table respect the setting. Radar range uses MapLibre line-opacity.

Testing

Unit tests (LayerTypes.* and LayerModelOpacityTest.*) all passed:

100% tests passed, 0 tests failed out of 10

Manual GUI check on KLSX reflectivity over a satellite style: Radar Opacity 100% → 40% → 15% → 100%, streets visible through faded radar. Layer Manager shows an Opacity column, with map style layers labeled Opaque.

Radar opacity at 100%
Radar opacity at 40% with streets visible through radar
Radar opacity at 15%
Layer Manager Opacity column and slider

radar_opacity_slider_and_layer_manager.mp4

To show artifacts inline, enable in settings.

Linear Issue: SCWX-168

Open in Web Open in Cursor 

cursoragent and others added 2 commits August 14, 2026 19:43
Radar products and other overlay layers can be faded with a slider or
percent field so streets and satellite imagery show through. Map style
layers stay fully opaque. Opacity is stored per layer and applied in
the fragment shaders at render time.

Co-authored-by: Dan Paulat <dpaulat@users.noreply.github.com>
Call Application::FinishInitialization so PlacefileManager does not
block the test destructor, and compare serialized opacity as float.

Co-authored-by: Dan Paulat <dpaulat@users.noreply.github.com>

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clang-tidy made some suggestions

There were too many comments to post at once. Showing the first 25 out of 30. Check the log or trigger a new build to see more.


void MainWindowImpl::ConfigureRadarOpacityControls()
{
auto* opacityWidget = new QWidget(mapSettingsGroup_);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: initializing non-owner 'QWidget *' with a newly created 'gsl::owner<>' [cppcoreguidelines-owning-memory]

)
       ^

void MainWindowImpl::ConfigureRadarOpacityControls()
{
auto* opacityWidget = new QWidget(mapSettingsGroup_);
auto* opacityLayout = new QHBoxLayout(opacityWidget);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: initializing non-owner 'QHBoxLayout *' with a newly created 'gsl::owner<>' [cppcoreguidelines-owning-memory]

_);
       ^

opacityLayout->setContentsMargins(0, 0, 0, 0);

auto* opacityLabel = new QLabel(QObject::tr("Radar Opacity"), opacityWidget);
radarOpacitySlider_ =

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: assigning newly created 'gsl::owner<>' to non-owner 'QSlider *' [cppcoreguidelines-owning-memory]

t);
       ^

auto* opacityLabel = new QLabel(QObject::tr("Radar Opacity"), opacityWidget);
radarOpacitySlider_ =
new QSlider(Qt::Orientation::Horizontal, opacityWidget);
radarOpacitySlider_->setRange(0, 100);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: 100 is a magic number; consider replacing it with a named constant [cppcoreguidelines-avoid-magic-numbers]

t);
                                        ^

new QSlider(Qt::Orientation::Horizontal, opacityWidget);
radarOpacitySlider_->setRange(0, 100);
radarOpacitySlider_->setTickPosition(QSlider::TickPosition::TicksBelow);
radarOpacitySlider_->setTickInterval(25);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: 25 is a magic number; consider replacing it with a named constant [cppcoreguidelines-avoid-magic-numbers]

w);
                                            ^

tr("Layer opacity. Map style layers stay opaque."));
opacityLayout->addWidget(p->opacitySlider_);
p->opacitySpinBox_ = new QFocusedSpinBox(opacityFrame);
p->opacitySpinBox_->setRange(0, 100);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: 100 is a magic number; consider replacing it with a named constant [cppcoreguidelines-avoid-magic-numbers]

   p->opacitySpinBox_->setRange(0, 100);
                                   ^

updatingOpacityControls_ = true;

const auto selectedRows = GetSelectedRows();
int opacityPercent = 100;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: 100 is a magic number; consider replacing it with a named constant [cppcoreguidelines-avoid-magic-numbers]

   int        opacityPercent = 100;
                               ^

int opacityPercent = 100;
bool anyEditable = false;

for (int row : selectedRows)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: variable 'row' of type 'int' can be declared 'const' [misc-const-correctness]

Suggested change
for (int row : selectedRows)
for (int const row : selectedRows)

opacitySpinBox_->setValue(percent);
updatingOpacityControls_ = false;

for (int row : GetSelectedRows())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: variable 'row' of type 'int' can be declared 'const' [misc-const-correctness]

Suggested change
for (int row : GetSelectedRows())
for (int const row : GetSelectedRows())

const QStyleOptionViewItem& /* option */,
const QModelIndex& /* index */) const
{
auto* spinBox = new QFocusedSpinBox(parent);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: initializing non-owner 'QFocusedSpinBox *' with a newly created 'gsl::owner<>' [cppcoreguidelines-owning-memory]

   auto* spinBox = new QFocusedSpinBox(parent);
   ^

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants