From 7254fc71fb6dcd3ed49a6d195ecc80479690d881 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Wed, 14 Aug 2024 23:18:50 -0500 Subject: [PATCH 01/36] Custom LineLabel widget to display line preview --- scwx-qt/scwx-qt.cmake | 2 + scwx-qt/source/scwx/qt/ui/line_label.cpp | 176 +++++++++++++++++++++++ scwx-qt/source/scwx/qt/ui/line_label.hpp | 43 ++++++ 3 files changed, 221 insertions(+) create mode 100644 scwx-qt/source/scwx/qt/ui/line_label.cpp create mode 100644 scwx-qt/source/scwx/qt/ui/line_label.hpp diff --git a/scwx-qt/scwx-qt.cmake b/scwx-qt/scwx-qt.cmake index 78d45217..b300cd2a 100644 --- a/scwx-qt/scwx-qt.cmake +++ b/scwx-qt/scwx-qt.cmake @@ -252,6 +252,7 @@ set(HDR_UI source/scwx/qt/ui/about_dialog.hpp source/scwx/qt/ui/level2_products_widget.hpp source/scwx/qt/ui/level2_settings_widget.hpp source/scwx/qt/ui/level3_products_widget.hpp + source/scwx/qt/ui/line_label.hpp source/scwx/qt/ui/open_url_dialog.hpp source/scwx/qt/ui/placefile_dialog.hpp source/scwx/qt/ui/placefile_settings_widget.hpp @@ -278,6 +279,7 @@ set(SRC_UI source/scwx/qt/ui/about_dialog.cpp source/scwx/qt/ui/level2_products_widget.cpp source/scwx/qt/ui/level2_settings_widget.cpp source/scwx/qt/ui/level3_products_widget.cpp + source/scwx/qt/ui/line_label.cpp source/scwx/qt/ui/open_url_dialog.cpp source/scwx/qt/ui/placefile_dialog.cpp source/scwx/qt/ui/placefile_settings_widget.cpp diff --git a/scwx-qt/source/scwx/qt/ui/line_label.cpp b/scwx-qt/source/scwx/qt/ui/line_label.cpp new file mode 100644 index 00000000..6fd6c854 --- /dev/null +++ b/scwx-qt/source/scwx/qt/ui/line_label.cpp @@ -0,0 +1,176 @@ +#include +#include + +#include +#include + +namespace scwx +{ +namespace qt +{ +namespace ui +{ + +static const std::string logPrefix_ = "scwx::qt::ui::line_label"; +static const auto logger_ = scwx::util::Logger::Create(logPrefix_); + +class LineLabel::Impl +{ +public: + explicit Impl() {}; + ~Impl() = default; + + QImage GenerateImage() const; + + std::size_t borderWidth_ {1}; + std::size_t highlightWidth_ {1}; + std::size_t lineWidth_ {3}; + + boost::gil::rgba8_pixel_t borderColor_ {0, 0, 0, 255}; + boost::gil::rgba8_pixel_t highlightColor_ {255, 255, 0, 255}; + boost::gil::rgba8_pixel_t lineColor_ {0, 0, 255, 255}; + + QPixmap pixmap_ {}; + bool pixmapDirty_ {true}; +}; + +LineLabel::LineLabel(QWidget* parent) : + QFrame(parent), p {std::make_unique()} +{ +} + +LineLabel::~LineLabel() {} + +void LineLabel::set_border_width(std::size_t width) +{ + p->borderWidth_ = width; + p->pixmapDirty_ = true; + update(); +} + +void LineLabel::set_highlight_width(std::size_t width) +{ + p->highlightWidth_ = width; + p->pixmapDirty_ = true; + update(); +} + +void LineLabel::set_line_width(std::size_t width) +{ + p->lineWidth_ = width; + p->pixmapDirty_ = true; + update(); +} + +void LineLabel::set_border_color(boost::gil::rgba8_pixel_t color) +{ + p->borderColor_ = color; + p->pixmapDirty_ = true; + update(); +} + +void LineLabel::set_highlight_color(boost::gil::rgba8_pixel_t color) +{ + p->highlightColor_ = color; + p->pixmapDirty_ = true; + update(); +} + +void LineLabel::set_line_color(boost::gil::rgba8_pixel_t color) +{ + p->lineColor_ = color; + p->pixmapDirty_ = true; + update(); +} + +QSize LineLabel::minimumSizeHint() const +{ + return sizeHint(); +} + +QSize LineLabel::sizeHint() const +{ + QMargins margins = contentsMargins(); + + const std::size_t width = 1; + const std::size_t height = + (p->borderWidth_ + p->highlightWidth_) * 2 + p->lineWidth_; + + return QSize(static_cast(width) + margins.left() + margins.right(), + static_cast(height) + margins.top() + margins.bottom()); +} + +void LineLabel::paintEvent(QPaintEvent* e) +{ + logger_->trace("paintEvent"); + + QFrame::paintEvent(e); + + if (p->pixmapDirty_) + { + QImage image = p->GenerateImage(); + p->pixmap_ = QPixmap::fromImage(image); + p->pixmapDirty_ = false; + } + + // Don't stretch the line pixmap vertically + QRect rect = contentsRect(); + if (rect.height() > p->pixmap_.height()) + { + int dy = rect.height() - p->pixmap_.height(); + int dy1 = dy / 2; + int dy2 = dy - dy1; + rect.adjust(0, dy1, 0, -dy2); + } + + QPainter painter(this); + painter.drawPixmap(rect, p->pixmap_); +} + +QImage LineLabel::Impl::GenerateImage() const +{ + const QRgb borderRgba = qRgba(static_cast(borderColor_[0]), + static_cast(borderColor_[1]), + static_cast(borderColor_[2]), + static_cast(borderColor_[3])); + const QRgb highlightRgba = qRgba(static_cast(highlightColor_[0]), + static_cast(highlightColor_[1]), + static_cast(highlightColor_[2]), + static_cast(highlightColor_[3])); + const QRgb lineRgba = qRgba(static_cast(lineColor_[0]), + static_cast(lineColor_[1]), + static_cast(lineColor_[2]), + static_cast(lineColor_[3])); + + const std::size_t width = 1; + const std::size_t height = (borderWidth_ + highlightWidth_) * 2 + lineWidth_; + + QImage image(static_cast(width), + static_cast(height), + QImage::Format::Format_ARGB32); + + std::size_t y = 0; + for (std::size_t i = 0; i < borderWidth_; ++i, ++y) + { + image.setPixel(0, static_cast(y), borderRgba); + image.setPixel(0, static_cast(height - 1 - y), borderRgba); + } + + for (std::size_t i = 0; i < highlightWidth_; ++i, ++y) + { + image.setPixel(0, static_cast(y), highlightRgba); + image.setPixel(0, static_cast(height - 1 - y), highlightRgba); + } + + for (std::size_t i = 0; i < lineWidth_; ++i, ++y) + { + image.setPixel(0, static_cast(y), lineRgba); + image.setPixel(0, static_cast(height - 1 - y), lineRgba); + } + + return image; +} + +} // namespace ui +} // namespace qt +} // namespace scwx diff --git a/scwx-qt/source/scwx/qt/ui/line_label.hpp b/scwx-qt/source/scwx/qt/ui/line_label.hpp new file mode 100644 index 00000000..6036e92f --- /dev/null +++ b/scwx-qt/source/scwx/qt/ui/line_label.hpp @@ -0,0 +1,43 @@ +#pragma once + +#include + +#include + +namespace scwx +{ +namespace qt +{ +namespace ui +{ + +class LineLabel : public QFrame +{ + Q_OBJECT + Q_DISABLE_COPY_MOVE(LineLabel) + +public: + explicit LineLabel(QWidget* parent = nullptr); + ~LineLabel(); + + void set_border_color(boost::gil::rgba8_pixel_t color); + void set_highlight_color(boost::gil::rgba8_pixel_t color); + void set_line_color(boost::gil::rgba8_pixel_t color); + + void set_border_width(std::size_t width); + void set_highlight_width(std::size_t width); + void set_line_width(std::size_t width); + +protected: + QSize minimumSizeHint() const override; + QSize sizeHint() const override; + void paintEvent(QPaintEvent* e) override; + +private: + class Impl; + std::unique_ptr p; +}; + +} // namespace ui +} // namespace qt +} // namespace scwx From eda7751eb907be7269b94a1b4d1ba793bf644502 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Tue, 20 Aug 2024 23:58:14 -0500 Subject: [PATCH 02/36] Edit line dialog in-work --- scwx-qt/scwx-qt.cmake | 15 +- .../source/scwx/qt/ui/edit_line_dialog.cpp | 309 ++++++++++++++++++ .../source/scwx/qt/ui/edit_line_dialog.hpp | 59 ++++ scwx-qt/source/scwx/qt/ui/edit_line_dialog.ui | 306 +++++++++++++++++ 4 files changed, 683 insertions(+), 6 deletions(-) create mode 100644 scwx-qt/source/scwx/qt/ui/edit_line_dialog.cpp create mode 100644 scwx-qt/source/scwx/qt/ui/edit_line_dialog.hpp create mode 100644 scwx-qt/source/scwx/qt/ui/edit_line_dialog.ui diff --git a/scwx-qt/scwx-qt.cmake b/scwx-qt/scwx-qt.cmake index b300cd2a..a548b1f4 100644 --- a/scwx-qt/scwx-qt.cmake +++ b/scwx-qt/scwx-qt.cmake @@ -240,8 +240,8 @@ set(HDR_UI source/scwx/qt/ui/about_dialog.hpp source/scwx/qt/ui/animation_dock_widget.hpp source/scwx/qt/ui/collapsible_group.hpp source/scwx/qt/ui/county_dialog.hpp - source/scwx/qt/ui/wfo_dialog.hpp source/scwx/qt/ui/download_dialog.hpp + source/scwx/qt/ui/edit_line_dialog.hpp source/scwx/qt/ui/flow_layout.hpp source/scwx/qt/ui/gps_info_dialog.hpp source/scwx/qt/ui/hotkey_edit.hpp @@ -260,15 +260,16 @@ set(HDR_UI source/scwx/qt/ui/about_dialog.hpp source/scwx/qt/ui/radar_site_dialog.hpp source/scwx/qt/ui/serial_port_dialog.hpp source/scwx/qt/ui/settings_dialog.hpp - source/scwx/qt/ui/update_dialog.hpp) + source/scwx/qt/ui/update_dialog.hpp + source/scwx/qt/ui/wfo_dialog.hpp) set(SRC_UI source/scwx/qt/ui/about_dialog.cpp source/scwx/qt/ui/alert_dialog.cpp source/scwx/qt/ui/alert_dock_widget.cpp source/scwx/qt/ui/animation_dock_widget.cpp source/scwx/qt/ui/collapsible_group.cpp source/scwx/qt/ui/county_dialog.cpp - source/scwx/qt/ui/wfo_dialog.cpp source/scwx/qt/ui/download_dialog.cpp + source/scwx/qt/ui/edit_line_dialog.cpp source/scwx/qt/ui/flow_layout.cpp source/scwx/qt/ui/gps_info_dialog.cpp source/scwx/qt/ui/hotkey_edit.cpp @@ -287,14 +288,15 @@ set(SRC_UI source/scwx/qt/ui/about_dialog.cpp source/scwx/qt/ui/radar_site_dialog.cpp source/scwx/qt/ui/settings_dialog.cpp source/scwx/qt/ui/serial_port_dialog.cpp - source/scwx/qt/ui/update_dialog.cpp) + source/scwx/qt/ui/update_dialog.cpp + source/scwx/qt/ui/wfo_dialog.cpp) set(UI_UI source/scwx/qt/ui/about_dialog.ui source/scwx/qt/ui/alert_dialog.ui source/scwx/qt/ui/alert_dock_widget.ui source/scwx/qt/ui/animation_dock_widget.ui source/scwx/qt/ui/collapsible_group.ui source/scwx/qt/ui/county_dialog.ui - source/scwx/qt/ui/wfo_dialog.ui + source/scwx/qt/ui/edit_line_dialog.ui source/scwx/qt/ui/gps_info_dialog.ui source/scwx/qt/ui/imgui_debug_dialog.ui source/scwx/qt/ui/layer_dialog.ui @@ -305,7 +307,8 @@ set(UI_UI source/scwx/qt/ui/about_dialog.ui source/scwx/qt/ui/radar_site_dialog.ui source/scwx/qt/ui/settings_dialog.ui source/scwx/qt/ui/serial_port_dialog.ui - source/scwx/qt/ui/update_dialog.ui) + source/scwx/qt/ui/update_dialog.ui + source/scwx/qt/ui/wfo_dialog.ui) set(HDR_UI_SETTINGS source/scwx/qt/ui/settings/hotkey_settings_widget.hpp source/scwx/qt/ui/settings/settings_page_widget.hpp source/scwx/qt/ui/settings/unit_settings_widget.hpp) diff --git a/scwx-qt/source/scwx/qt/ui/edit_line_dialog.cpp b/scwx-qt/source/scwx/qt/ui/edit_line_dialog.cpp new file mode 100644 index 00000000..1aafffeb --- /dev/null +++ b/scwx-qt/source/scwx/qt/ui/edit_line_dialog.cpp @@ -0,0 +1,309 @@ +#include "edit_line_dialog.hpp" +#include "ui_edit_line_dialog.h" + +#include +#include +#include + +#include +#include + +namespace scwx +{ +namespace qt +{ +namespace ui +{ + +static const std::string logPrefix_ = "scwx::qt::ui::edit_line_dialog"; +static const auto logger_ = scwx::util::Logger::Create(logPrefix_); + +class EditLineDialog::Impl +{ +public: + struct EditComponent + { + void ConnectSignals(EditLineDialog* self) + { + QObject::connect(colorLineEdit_, + &QLineEdit::textEdited, + self, + [=, this](const QString& text) + { + boost::gil::rgba8_pixel_t color = + util::color::ToRgba8PixelT(text.toStdString()); + self->p->set_color(*this, color); + }); + + QObject::connect(colorButton_, + &QAbstractButton::clicked, + self, + [=, this]() { self->p->ShowColorDialog(*this); }); + + QObject::connect(widthSpinBox_, + &QSpinBox::valueChanged, + self, + [=, this](int width) + { self->p->set_width(*this, width); }); + } + + boost::gil::rgba8_pixel_t color_; + std::size_t width_; + QFrame* colorFrame_ {nullptr}; + QLineEdit* colorLineEdit_ {nullptr}; + QToolButton* colorButton_ {nullptr}; + QSpinBox* widthSpinBox_ {nullptr}; + }; + + explicit Impl(EditLineDialog* self) : + self_ {self}, lineLabel_ {new LineLabel(self)} + { + } + ~Impl() = default; + + void SetDefaults(); + void ShowColorDialog(EditComponent& component); + void UpdateLineLabel(); + + void set_color(EditComponent& component, boost::gil::rgba8_pixel_t color); + void set_width(EditComponent& component, std::size_t width); + + static void SetBackgroundColor(const std::string& value, QFrame* frame); + + EditLineDialog* self_; + + LineLabel* lineLabel_; + + boost::gil::rgba8_pixel_t defaultBorderColor_ {0, 0, 0, 255}; + boost::gil::rgba8_pixel_t defaultHighlightColor_ {0, 0, 0, 0}; + boost::gil::rgba8_pixel_t defaultLineColor_ {255, 255, 255, 255}; + + std::size_t defaultBorderWidth_ {1u}; + std::size_t defaultHighlightWidth_ {0u}; + std::size_t defaultLineWidth_ {3u}; + + EditComponent borderComponent_ {}; + EditComponent highlightComponent_ {}; + EditComponent lineComponent_ {}; +}; + +EditLineDialog::EditLineDialog(QWidget* parent) : + QDialog(parent), + p {std::make_unique(this)}, + ui(new Ui::EditLineDialog) +{ + ui->setupUi(this); + + p->borderComponent_.colorFrame_ = ui->borderColorFrame; + p->borderComponent_.colorLineEdit_ = ui->borderColorLineEdit; + p->borderComponent_.colorButton_ = ui->borderColorButton; + p->borderComponent_.widthSpinBox_ = ui->borderWidthSpinBox; + + p->highlightComponent_.colorFrame_ = ui->highlightColorFrame; + p->highlightComponent_.colorLineEdit_ = ui->highlightColorLineEdit; + p->highlightComponent_.colorButton_ = ui->highlightColorButton; + p->highlightComponent_.widthSpinBox_ = ui->highlightWidthSpinBox; + + p->lineComponent_.colorFrame_ = ui->lineColorFrame; + p->lineComponent_.colorLineEdit_ = ui->lineColorLineEdit; + p->lineComponent_.colorButton_ = ui->lineColorButton; + p->lineComponent_.widthSpinBox_ = ui->lineWidthSpinBox; + + p->SetDefaults(); + + p->lineLabel_->setMinimumWidth(72); + + QHBoxLayout* lineLabelContainerLayout = + static_cast(ui->lineLabelContainer->layout()); + lineLabelContainerLayout->insertWidget(1, p->lineLabel_); + + p->borderComponent_.ConnectSignals(this); + p->highlightComponent_.ConnectSignals(this); + p->lineComponent_.ConnectSignals(this); + + QObject::connect(ui->buttonBox, + &QDialogButtonBox::clicked, + this, + [this](QAbstractButton* button) + { + QDialogButtonBox::ButtonRole role = + ui->buttonBox->buttonRole(button); + + switch (role) + { + case QDialogButtonBox::ButtonRole::ResetRole: // Reset + p->SetDefaults(); + break; + + default: + break; + } + }); +} + +EditLineDialog::~EditLineDialog() +{ + delete ui; +} + +boost::gil::rgba8_pixel_t EditLineDialog::border_color() const +{ + return p->borderComponent_.color_; +} + +boost::gil::rgba8_pixel_t EditLineDialog::highlight_color() const +{ + return p->highlightComponent_.color_; +} + +boost::gil::rgba8_pixel_t EditLineDialog::line_color() const +{ + return p->lineComponent_.color_; +} + +std::size_t EditLineDialog::border_width() const +{ + return p->borderComponent_.width_; +} + +std::size_t EditLineDialog::highlight_width() const +{ + return p->highlightComponent_.width_; +} + +std::size_t EditLineDialog::line_width() const +{ + return p->lineComponent_.width_; +} + +void EditLineDialog::set_border_color(boost::gil::rgba8_pixel_t color) +{ + p->set_color(p->borderComponent_, color); +} + +void EditLineDialog::set_highlight_color(boost::gil::rgba8_pixel_t color) +{ + p->set_color(p->highlightComponent_, color); +} + +void EditLineDialog::set_line_color(boost::gil::rgba8_pixel_t color) +{ + p->set_color(p->lineComponent_, color); +} + +void EditLineDialog::set_border_width(std::size_t width) +{ + p->set_width(p->borderComponent_, width); +} + +void EditLineDialog::set_highlight_width(std::size_t width) +{ + p->set_width(p->highlightComponent_, width); +} + +void EditLineDialog::set_line_width(std::size_t width) +{ + p->set_width(p->lineComponent_, width); +} + +void EditLineDialog::Impl::set_color(EditComponent& component, + boost::gil::rgba8_pixel_t color) +{ + const std::string argbString {util::color::ToArgbString(color)}; + + component.color_ = color; + component.colorLineEdit_->setText(QString::fromStdString(argbString)); + SetBackgroundColor(argbString, component.colorFrame_); + + UpdateLineLabel(); +} + +void EditLineDialog::Impl::set_width(EditComponent& component, + std::size_t width) +{ + component.width_ = width; + component.widthSpinBox_->setValue(static_cast(width)); + + UpdateLineLabel(); +} + +void EditLineDialog::Impl::UpdateLineLabel() +{ + lineLabel_->set_border_color(borderComponent_.color_); + lineLabel_->set_highlight_color(highlightComponent_.color_); + lineLabel_->set_line_color(lineComponent_.color_); + + lineLabel_->set_border_width(borderComponent_.width_); + lineLabel_->set_highlight_width(highlightComponent_.width_); + lineLabel_->set_line_width(lineComponent_.width_); +} + +void EditLineDialog::Initialize(boost::gil::rgba8_pixel_t borderColor, + boost::gil::rgba8_pixel_t highlightColor, + boost::gil::rgba8_pixel_t lineColor, + std::size_t borderWidth, + std::size_t highlightWidth, + std::size_t lineWidth) +{ + p->defaultBorderColor_ = borderColor; + p->defaultHighlightColor_ = highlightColor; + p->defaultLineColor_ = lineColor; + + p->defaultBorderWidth_ = borderWidth; + p->defaultHighlightWidth_ = highlightWidth; + p->defaultLineWidth_ = lineWidth; + + p->SetDefaults(); +} + +void EditLineDialog::Impl::SetDefaults() +{ + self_->set_border_color(defaultBorderColor_); + self_->set_highlight_color(defaultHighlightColor_); + self_->set_line_color(defaultLineColor_); + + self_->set_border_width(defaultBorderWidth_); + self_->set_highlight_width(defaultHighlightWidth_); + self_->set_line_width(defaultLineWidth_); +} + +void EditLineDialog::Impl::ShowColorDialog(EditComponent& component) +{ + QColorDialog* dialog = new QColorDialog(self_); + + dialog->setAttribute(Qt::WA_DeleteOnClose); + dialog->setOption(QColorDialog::ColorDialogOption::ShowAlphaChannel); + + QColor initialColor(component.colorLineEdit_->text()); + if (initialColor.isValid()) + { + dialog->setCurrentColor(initialColor); + } + + QObject::connect( + dialog, + &QColorDialog::colorSelected, + self_, + [this, &component](const QColor& qColor) + { + QString colorName = qColor.name(QColor::NameFormat::HexArgb); + boost::gil::rgba8_pixel_t color = + util::color::ToRgba8PixelT(colorName.toStdString()); + + logger_->info("Selected color: {}", colorName.toStdString()); + set_color(component, color); + }); + + dialog->open(); +} + +void EditLineDialog::Impl::SetBackgroundColor(const std::string& value, + QFrame* frame) +{ + frame->setStyleSheet( + QString::fromStdString(fmt::format("background-color: {}", value))); +} + +} // namespace ui +} // namespace qt +} // namespace scwx diff --git a/scwx-qt/source/scwx/qt/ui/edit_line_dialog.hpp b/scwx-qt/source/scwx/qt/ui/edit_line_dialog.hpp new file mode 100644 index 00000000..2f8ea3ce --- /dev/null +++ b/scwx-qt/source/scwx/qt/ui/edit_line_dialog.hpp @@ -0,0 +1,59 @@ +#pragma once + +#include + +#include + +namespace Ui +{ +class EditLineDialog; +} + +namespace scwx +{ +namespace qt +{ +namespace ui +{ + +class EditLineDialog : public QDialog +{ + Q_OBJECT + Q_DISABLE_COPY_MOVE(EditLineDialog) + +public: + explicit EditLineDialog(QWidget* parent = nullptr); + ~EditLineDialog(); + + boost::gil::rgba8_pixel_t border_color() const; + boost::gil::rgba8_pixel_t highlight_color() const; + boost::gil::rgba8_pixel_t line_color() const; + + std::size_t border_width() const; + std::size_t highlight_width() const; + std::size_t line_width() const; + + void set_border_color(boost::gil::rgba8_pixel_t color); + void set_highlight_color(boost::gil::rgba8_pixel_t color); + void set_line_color(boost::gil::rgba8_pixel_t color); + + void set_border_width(std::size_t width); + void set_highlight_width(std::size_t width); + void set_line_width(std::size_t width); + + void Initialize(boost::gil::rgba8_pixel_t borderColor, + boost::gil::rgba8_pixel_t highlightColor, + boost::gil::rgba8_pixel_t lineColor, + std::size_t borderWidth, + std::size_t highlightWidth, + std::size_t lineWidth); + +private: + class Impl; + std::unique_ptr p; + Ui::EditLineDialog* ui; +}; + +} // namespace ui +} // namespace qt +} // namespace scwx diff --git a/scwx-qt/source/scwx/qt/ui/edit_line_dialog.ui b/scwx-qt/source/scwx/qt/ui/edit_line_dialog.ui new file mode 100644 index 00000000..bc133bf9 --- /dev/null +++ b/scwx-qt/source/scwx/qt/ui/edit_line_dialog.ui @@ -0,0 +1,306 @@ + + + EditLineDialog + + + + 0 + 0 + 350 + 225 + + + + Edit Line + + + + + + + true + + + + Component + + + + + + + #ff000000 + + + + + + + 0 + + + 9 + + + + + + + ... + + + + :/res/icons/font-awesome-6/palette-solid.svg:/res/icons/font-awesome-6/palette-solid.svg + + + + + + + ... + + + + :/res/icons/font-awesome-6/palette-solid.svg:/res/icons/font-awesome-6/palette-solid.svg + + + + + + + Border + + + + + + + #ff000000 + + + + + + + Line + + + + + + + Qt::Orientation::Horizontal + + + QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok|QDialogButtonBox::StandardButton::Reset + + + + + + + + 24 + 24 + + + + QFrame::Shape::Box + + + QFrame::Shadow::Plain + + + + + + + 0 + + + 9 + + + + + + + Qt::Orientation::Vertical + + + + 20 + 40 + + + + + + + + + 24 + 24 + + + + QFrame::Shape::Box + + + QFrame::Shadow::Plain + + + + + + + + true + + + + Color + + + + + + + #ff000000 + + + + + + + + 24 + 24 + + + + QFrame::Shape::Box + + + QFrame::Shadow::Plain + + + + + + + + true + + + + Width + + + + + + + 1 + + + 9 + + + + + + + Highlight + + + + + + + ... + + + + :/res/icons/font-awesome-6/palette-solid.svg:/res/icons/font-awesome-6/palette-solid.svg + + + + + + + + 0 + 45 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Orientation::Horizontal + + + + + + + Qt::Orientation::Horizontal + + + + + + + + + + + + + + buttonBox + accepted() + EditLineDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + EditLineDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + From 88b8a8001f425aa595eb10fb68bba95d57896698 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Wed, 21 Aug 2024 22:20:22 -0500 Subject: [PATCH 03/36] Line label geometry needs updated whenever a component width changes --- scwx-qt/source/scwx/qt/ui/line_label.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scwx-qt/source/scwx/qt/ui/line_label.cpp b/scwx-qt/source/scwx/qt/ui/line_label.cpp index 6fd6c854..f5c9c3e3 100644 --- a/scwx-qt/source/scwx/qt/ui/line_label.cpp +++ b/scwx-qt/source/scwx/qt/ui/line_label.cpp @@ -45,6 +45,7 @@ void LineLabel::set_border_width(std::size_t width) { p->borderWidth_ = width; p->pixmapDirty_ = true; + updateGeometry(); update(); } @@ -52,6 +53,7 @@ void LineLabel::set_highlight_width(std::size_t width) { p->highlightWidth_ = width; p->pixmapDirty_ = true; + updateGeometry(); update(); } @@ -59,6 +61,7 @@ void LineLabel::set_line_width(std::size_t width) { p->lineWidth_ = width; p->pixmapDirty_ = true; + updateGeometry(); update(); } From da79f47416c09806706d5d77e6a095448262391d Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Wed, 21 Aug 2024 22:24:07 -0500 Subject: [PATCH 04/36] Don't overwite the edit line color text boxes during text editing --- scwx-qt/source/scwx/qt/ui/edit_line_dialog.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/scwx-qt/source/scwx/qt/ui/edit_line_dialog.cpp b/scwx-qt/source/scwx/qt/ui/edit_line_dialog.cpp index 1aafffeb..5202e732 100644 --- a/scwx-qt/source/scwx/qt/ui/edit_line_dialog.cpp +++ b/scwx-qt/source/scwx/qt/ui/edit_line_dialog.cpp @@ -32,7 +32,7 @@ public: { boost::gil::rgba8_pixel_t color = util::color::ToRgba8PixelT(text.toStdString()); - self->p->set_color(*this, color); + self->p->set_color(*this, color, false); }); QObject::connect(colorButton_, @@ -65,7 +65,9 @@ public: void ShowColorDialog(EditComponent& component); void UpdateLineLabel(); - void set_color(EditComponent& component, boost::gil::rgba8_pixel_t color); + void set_color(EditComponent& component, + boost::gil::rgba8_pixel_t color, + bool updateLineEdit = true); void set_width(EditComponent& component, std::size_t width); static void SetBackgroundColor(const std::string& value, QFrame* frame); @@ -207,14 +209,19 @@ void EditLineDialog::set_line_width(std::size_t width) } void EditLineDialog::Impl::set_color(EditComponent& component, - boost::gil::rgba8_pixel_t color) + boost::gil::rgba8_pixel_t color, + bool updateLineEdit) { const std::string argbString {util::color::ToArgbString(color)}; component.color_ = color; - component.colorLineEdit_->setText(QString::fromStdString(argbString)); SetBackgroundColor(argbString, component.colorFrame_); + if (updateLineEdit) + { + component.colorLineEdit_->setText(QString::fromStdString(argbString)); + } + UpdateLineLabel(); } From f8e0ab5b564fd61db99f8cdbdab09a9271134128 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Fri, 30 Aug 2024 23:03:13 -0500 Subject: [PATCH 05/36] Add alert palette settings widget --- scwx-qt/scwx-qt.cmake | 6 +- .../alert_palette_settings_widget.cpp | 239 ++++++++++++++++++ .../alert_palette_settings_widget.hpp | 29 +++ wxdata/include/scwx/awips/phenomenon.hpp | 1 + wxdata/source/scwx/awips/phenomenon.cpp | 137 +++++----- 5 files changed, 351 insertions(+), 61 deletions(-) create mode 100644 scwx-qt/source/scwx/qt/ui/settings/alert_palette_settings_widget.cpp create mode 100644 scwx-qt/source/scwx/qt/ui/settings/alert_palette_settings_widget.hpp diff --git a/scwx-qt/scwx-qt.cmake b/scwx-qt/scwx-qt.cmake index a548b1f4..52d26ccc 100644 --- a/scwx-qt/scwx-qt.cmake +++ b/scwx-qt/scwx-qt.cmake @@ -309,10 +309,12 @@ set(UI_UI source/scwx/qt/ui/about_dialog.ui source/scwx/qt/ui/serial_port_dialog.ui source/scwx/qt/ui/update_dialog.ui source/scwx/qt/ui/wfo_dialog.ui) -set(HDR_UI_SETTINGS source/scwx/qt/ui/settings/hotkey_settings_widget.hpp +set(HDR_UI_SETTINGS source/scwx/qt/ui/settings/alert_palette_settings_widget.hpp + source/scwx/qt/ui/settings/hotkey_settings_widget.hpp source/scwx/qt/ui/settings/settings_page_widget.hpp source/scwx/qt/ui/settings/unit_settings_widget.hpp) -set(SRC_UI_SETTINGS source/scwx/qt/ui/settings/hotkey_settings_widget.cpp +set(SRC_UI_SETTINGS source/scwx/qt/ui/settings/alert_palette_settings_widget.cpp + source/scwx/qt/ui/settings/hotkey_settings_widget.cpp source/scwx/qt/ui/settings/settings_page_widget.cpp source/scwx/qt/ui/settings/unit_settings_widget.cpp) set(HDR_UI_SETUP source/scwx/qt/ui/setup/audio_codec_page.hpp diff --git a/scwx-qt/source/scwx/qt/ui/settings/alert_palette_settings_widget.cpp b/scwx-qt/source/scwx/qt/ui/settings/alert_palette_settings_widget.cpp new file mode 100644 index 00000000..f433156d --- /dev/null +++ b/scwx-qt/source/scwx/qt/ui/settings/alert_palette_settings_widget.cpp @@ -0,0 +1,239 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace scwx +{ +namespace qt +{ +namespace ui +{ + +static const std::string logPrefix_ = + "scwx::qt::ui::settings::alert_palette_settings_widget"; + +struct PhenomenonInfo +{ + bool hasObservedTag_ {false}; + bool hasTornadoPossibleTag_ {false}; + std::vector threatCategories_ { + awips::ThreatCategory::Base}; +}; + +static const boost::unordered_flat_map + phenomenaInfo_ {{awips::Phenomenon::Marine, + PhenomenonInfo {.hasTornadoPossibleTag_ {true}}}, + {awips::Phenomenon::FlashFlood, + PhenomenonInfo {.threatCategories_ { + awips::ThreatCategory::Base, + awips::ThreatCategory::Considerable, + awips::ThreatCategory::Catastrophic}}}, + {awips::Phenomenon::SevereThunderstorm, + PhenomenonInfo {.hasTornadoPossibleTag_ {true}, + .threatCategories_ { + awips::ThreatCategory::Base, + awips::ThreatCategory::Considerable, + awips::ThreatCategory::Destructive}}}, + {awips::Phenomenon::SnowSquall, PhenomenonInfo {}}, + {awips::Phenomenon::Tornado, + PhenomenonInfo {.hasObservedTag_ {true}, + .threatCategories_ { + awips::ThreatCategory::Base, + awips::ThreatCategory::Considerable, + awips::ThreatCategory::Catastrophic}}}}; + +class AlertPaletteSettingsWidget::Impl +{ +public: + explicit Impl(AlertPaletteSettingsWidget* self) : + self_ {self}, + phenomenonPagesWidget_ {new QStackedWidget(self)}, + phenomenonListView_ {new QListWidget(self)}, + editLineDialog_ {new EditLineDialog(self)} + { + SetupUi(); + ConnectSignals(); + } + ~Impl() = default; + + void + AddPhenomenonLine(const std::string& name, QGridLayout* layout, int row); + QWidget* CreateStackedWidgetPage(awips::Phenomenon phenomenon); + void ConnectSignals(); + void SelectPhenomenon(awips::Phenomenon phenomenon); + void SetupUi(); + + AlertPaletteSettingsWidget* self_; + + QStackedWidget* phenomenonPagesWidget_; + QListWidget* phenomenonListView_; + + EditLineDialog* editLineDialog_; + + boost::unordered_flat_map phenomenonPages_ {}; +}; + +AlertPaletteSettingsWidget::AlertPaletteSettingsWidget(QWidget* parent) : + SettingsPageWidget(parent), p {std::make_shared(this)} +{ +} + +AlertPaletteSettingsWidget::~AlertPaletteSettingsWidget() = default; + +void AlertPaletteSettingsWidget::Impl::SetupUi() +{ + // Setup primary widget layout + QGridLayout* gridLayout = new QGridLayout(self_); + gridLayout->setContentsMargins(0, 0, 0, 0); + self_->setLayout(gridLayout); + + QWidget* phenomenonIndexPane = new QWidget(self_); + phenomenonPagesWidget_->setSizePolicy(QSizePolicy::Policy::Expanding, + QSizePolicy::Policy::Preferred); + + gridLayout->addWidget(phenomenonIndexPane, 0, 0); + gridLayout->addWidget(phenomenonPagesWidget_, 0, 1); + + QSpacerItem* spacer = + new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding); + gridLayout->addItem(spacer, 1, 0); + + // Setup phenomenon index pane + QVBoxLayout* phenomenonIndexLayout = new QVBoxLayout(self_); + phenomenonIndexPane->setLayout(phenomenonIndexLayout); + + QLabel* phenomenonLabel = new QLabel(tr("Phenomenon:"), self_); + phenomenonListView_->setSizePolicy(QSizePolicy::Policy::Minimum, + QSizePolicy::Policy::Expanding); + + phenomenonIndexLayout->addWidget(phenomenonLabel); + phenomenonIndexLayout->addWidget(phenomenonListView_); + + // Setup stacked widget + auto& paletteSettings = settings::PaletteSettings::Instance(); + Q_UNUSED(paletteSettings); + + for (auto& phenomenon : settings::PaletteSettings::alert_phenomena()) + { + QWidget* phenomenonWidget = CreateStackedWidgetPage(phenomenon); + phenomenonPagesWidget_->addWidget(phenomenonWidget); + + phenomenonPages_.insert_or_assign(phenomenon, phenomenonWidget); + + phenomenonListView_->addItem( + QString::fromStdString(awips::GetPhenomenonText(phenomenon))); + } + + phenomenonListView_->setCurrentRow(0); +} + +void AlertPaletteSettingsWidget::Impl::ConnectSignals() +{ + QObject::connect( + phenomenonListView_->selectionModel(), + &QItemSelectionModel::selectionChanged, + self_, + [this](const QItemSelection& selected, const QItemSelection& deselected) + { + if (selected.size() == 0 && deselected.size() == 0) + { + // Items which stay selected but change their index are not + // included in selected and deselected. Thus, this signal might + // be emitted with both selected and deselected empty, if only + // the indices of selected items change. + return; + } + + if (selected.size() > 0) + { + QModelIndex selectedIndex = selected[0].indexes()[0]; + QVariant variantData = + phenomenonListView_->model()->data(selectedIndex); + if (variantData.typeId() == QMetaType::QString) + { + awips::Phenomenon phenomenon = awips::GetPhenomenonFromText( + variantData.toString().toStdString()); + SelectPhenomenon(phenomenon); + } + } + }); +} + +void AlertPaletteSettingsWidget::Impl::SelectPhenomenon( + awips::Phenomenon phenomenon) +{ + auto it = phenomenonPages_.find(phenomenon); + if (it != phenomenonPages_.cend()) + { + phenomenonPagesWidget_->setCurrentWidget(it->second); + } +} + +QWidget* AlertPaletteSettingsWidget::Impl::CreateStackedWidgetPage( + awips::Phenomenon phenomenon) +{ + QWidget* page = new QWidget(self_); + QGridLayout* gridLayout = new QGridLayout(self_); + page->setLayout(gridLayout); + + const auto& phenomenonInfo = phenomenaInfo_.at(phenomenon); + + int row = 0; + + // Add a blank label to align left and right widgets + gridLayout->addWidget(new QLabel(self_), row++, 0); + + AddPhenomenonLine("Active", gridLayout, row++); + + if (phenomenonInfo.hasObservedTag_) + { + AddPhenomenonLine("Observed", gridLayout, row++); + } + + if (phenomenonInfo.hasTornadoPossibleTag_) + { + AddPhenomenonLine("Tornado Possible", gridLayout, row++); + } + + for (auto& category : phenomenonInfo.threatCategories_) + { + if (category == awips::ThreatCategory::Base) + { + continue; + } + + AddPhenomenonLine( + awips::GetThreatCategoryName(category), gridLayout, row++); + } + + AddPhenomenonLine("Inactive", gridLayout, row++); + + QSpacerItem* spacer = + new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding); + gridLayout->addItem(spacer, row, 0); + + return page; +} + +void AlertPaletteSettingsWidget::Impl::AddPhenomenonLine( + const std::string& name, QGridLayout* layout, int row) +{ + layout->addWidget(new QLabel(tr(name.c_str()), self_), row, 0); + layout->addWidget(new LineLabel(self_), row, 1); + layout->addWidget(new QToolButton(self_), row, 2); +} + +} // namespace ui +} // namespace qt +} // namespace scwx diff --git a/scwx-qt/source/scwx/qt/ui/settings/alert_palette_settings_widget.hpp b/scwx-qt/source/scwx/qt/ui/settings/alert_palette_settings_widget.hpp new file mode 100644 index 00000000..45f03e36 --- /dev/null +++ b/scwx-qt/source/scwx/qt/ui/settings/alert_palette_settings_widget.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include + +#include + +namespace scwx +{ +namespace qt +{ +namespace ui +{ + +class AlertPaletteSettingsWidget : public SettingsPageWidget +{ + Q_OBJECT + +public: + explicit AlertPaletteSettingsWidget(QWidget* parent = nullptr); + ~AlertPaletteSettingsWidget(); + +private: + class Impl; + std::shared_ptr p; +}; + +} // namespace ui +} // namespace qt +} // namespace scwx diff --git a/wxdata/include/scwx/awips/phenomenon.hpp b/wxdata/include/scwx/awips/phenomenon.hpp index 013a9947..234e473a 100644 --- a/wxdata/include/scwx/awips/phenomenon.hpp +++ b/wxdata/include/scwx/awips/phenomenon.hpp @@ -69,6 +69,7 @@ enum class Phenomenon }; Phenomenon GetPhenomenon(const std::string& code); +Phenomenon GetPhenomenonFromText(const std::string& text); const std::string& GetPhenomenonCode(Phenomenon phenomenon); const std::string& GetPhenomenonText(Phenomenon phenomenon); diff --git a/wxdata/source/scwx/awips/phenomenon.cpp b/wxdata/source/scwx/awips/phenomenon.cpp index ee8e549d..c8154509 100644 --- a/wxdata/source/scwx/awips/phenomenon.cpp +++ b/wxdata/source/scwx/awips/phenomenon.cpp @@ -77,64 +77,65 @@ static const PhenomenonCodesBimap phenomenonCodes_ = (Phenomenon::FreezingSpray, "ZY") // (Phenomenon::Unknown, "??"); -static const std::unordered_map phenomenonText_ { - {Phenomenon::AshfallLand, "Ashfall (land)"}, // - {Phenomenon::AirStagnation, "Air Stagnation"}, // - {Phenomenon::BeachHazard, "Beach Hazard"}, // - {Phenomenon::BriskWind, "Brisk Wind"}, // - {Phenomenon::Blizzard, "Blizzard"}, // - {Phenomenon::CoastalFlood, "Coastal Flood"}, // - {Phenomenon::DebrisFlow, "Debris Flow"}, // - {Phenomenon::DustStorm, "Dust Storm"}, // - {Phenomenon::BlowingDust, "Blowing Dust"}, // - {Phenomenon::ExtremeCold, "Extreme Cold"}, // - {Phenomenon::ExcessiveHeat, "Excessive Heat"}, // - {Phenomenon::ExtremeWind, "Extreme Wind"}, // - {Phenomenon::Flood, "Flood"}, // - {Phenomenon::FlashFlood, "Flash Flood"}, // - {Phenomenon::DenseFogLand, "Dense Fog (land)"}, // - {Phenomenon::Flood, "Flood (Forecast Points)"}, // - {Phenomenon::Frost, "Frost"}, // - {Phenomenon::FireWeather, "Fire Weather"}, // - {Phenomenon::Freeze, "Freeze"}, // - {Phenomenon::Gale, "Gale"}, // - {Phenomenon::HurricaneForceWind, "Hurricane Force Wind"}, // - {Phenomenon::Heat, "Heat"}, // - {Phenomenon::Hurricane, "Hurricane"}, // - {Phenomenon::HighWind, "High Wind"}, // - {Phenomenon::Hydrologic, "Hydrologic"}, // - {Phenomenon::HardFreeze, "Hard Freeze"}, // - {Phenomenon::IceStorm, "Ice Storm"}, // - {Phenomenon::LakeEffectSnow, "Lake Effect Snow"}, // - {Phenomenon::LowWater, "Low Water"}, // - {Phenomenon::LakeshoreFlood, "Lakeshore Flood"}, // - {Phenomenon::LakeWind, "Lake Wind"}, // - {Phenomenon::Marine, "Marine"}, // - {Phenomenon::DenseFogMarine, "Dense Fog (marine)"}, // - {Phenomenon::AshfallMarine, "Ashfall (marine)"}, // - {Phenomenon::DenseSmokeMarine, "Dense Smoke (marine)"}, // - {Phenomenon::RipCurrentRisk, "Rip Current Risk"}, // - {Phenomenon::SmallCraft, "Small Craft"}, // - {Phenomenon::HazardousSeas, "Hazardous Seas"}, // - {Phenomenon::DenseSmokeLand, "Dense Smoke (land)"}, // - {Phenomenon::Storm, "Storm"}, // - {Phenomenon::StormSurge, "Storm Surge"}, // - {Phenomenon::SnowSquall, "Snow Squall"}, // - {Phenomenon::HighSurf, "High Surf"}, // - {Phenomenon::SevereThunderstorm, "Severe Thunderstorm"}, // - {Phenomenon::Tornado, "Tornado"}, // - {Phenomenon::TropicalStorm, "Tropical Storm"}, // - {Phenomenon::Tsunami, "Tsunami"}, // - {Phenomenon::Typhoon, "Typhoon"}, // - {Phenomenon::HeavyFreezingSpray, "Heavy Freezing Spray"}, // - {Phenomenon::WindChill, "Wind Chill"}, // - {Phenomenon::Wind, "Wind"}, // - {Phenomenon::WinterStorm, "Winter Storm"}, // - {Phenomenon::WinterWeather, "Winter Weather"}, // - {Phenomenon::FreezingFog, "Freezing Fog"}, // - {Phenomenon::FreezingRain, "Freezing Rain"}, // - {Phenomenon::FreezingSpray, "Freezing Spray"}, // - {Phenomenon::Unknown, "Unknown"}}; +static const PhenomenonCodesBimap phenomenonText_ = + boost::assign::list_of // + (Phenomenon::AshfallLand, "Ashfall (land)") // + (Phenomenon::AirStagnation, "Air Stagnation") // + (Phenomenon::BeachHazard, "Beach Hazard") // + (Phenomenon::BriskWind, "Brisk Wind") // + (Phenomenon::Blizzard, "Blizzard") // + (Phenomenon::CoastalFlood, "Coastal Flood") // + (Phenomenon::DebrisFlow, "Debris Flow") // + (Phenomenon::DustStorm, "Dust Storm") // + (Phenomenon::BlowingDust, "Blowing Dust") // + (Phenomenon::ExtremeCold, "Extreme Cold") // + (Phenomenon::ExcessiveHeat, "Excessive Heat") // + (Phenomenon::ExtremeWind, "Extreme Wind") // + (Phenomenon::Flood, "Flood") // + (Phenomenon::FlashFlood, "Flash Flood") // + (Phenomenon::DenseFogLand, "Dense Fog (land)") // + (Phenomenon::Flood, "Flood (Forecast Points)") // + (Phenomenon::Frost, "Frost") // + (Phenomenon::FireWeather, "Fire Weather") // + (Phenomenon::Freeze, "Freeze") // + (Phenomenon::Gale, "Gale") // + (Phenomenon::HurricaneForceWind, "Hurricane Force Wind") // + (Phenomenon::Heat, "Heat") // + (Phenomenon::Hurricane, "Hurricane") // + (Phenomenon::HighWind, "High Wind") // + (Phenomenon::Hydrologic, "Hydrologic") // + (Phenomenon::HardFreeze, "Hard Freeze") // + (Phenomenon::IceStorm, "Ice Storm") // + (Phenomenon::LakeEffectSnow, "Lake Effect Snow") // + (Phenomenon::LowWater, "Low Water") // + (Phenomenon::LakeshoreFlood, "Lakeshore Flood") // + (Phenomenon::LakeWind, "Lake Wind") // + (Phenomenon::Marine, "Marine") // + (Phenomenon::DenseFogMarine, "Dense Fog (marine)") // + (Phenomenon::AshfallMarine, "Ashfall (marine)") // + (Phenomenon::DenseSmokeMarine, "Dense Smoke (marine)") // + (Phenomenon::RipCurrentRisk, "Rip Current Risk") // + (Phenomenon::SmallCraft, "Small Craft") // + (Phenomenon::HazardousSeas, "Hazardous Seas") // + (Phenomenon::DenseSmokeLand, "Dense Smoke (land)") // + (Phenomenon::Storm, "Storm") // + (Phenomenon::StormSurge, "Storm Surge") // + (Phenomenon::SnowSquall, "Snow Squall") // + (Phenomenon::HighSurf, "High Surf") // + (Phenomenon::SevereThunderstorm, "Severe Thunderstorm") // + (Phenomenon::Tornado, "Tornado") // + (Phenomenon::TropicalStorm, "Tropical Storm") // + (Phenomenon::Tsunami, "Tsunami") // + (Phenomenon::Typhoon, "Typhoon") // + (Phenomenon::HeavyFreezingSpray, "Heavy Freezing Spray") // + (Phenomenon::WindChill, "Wind Chill") // + (Phenomenon::Wind, "Wind") // + (Phenomenon::WinterStorm, "Winter Storm") // + (Phenomenon::WinterWeather, "Winter Weather") // + (Phenomenon::FreezingFog, "Freezing Fog") // + (Phenomenon::FreezingRain, "Freezing Rain") // + (Phenomenon::FreezingSpray, "Freezing Spray") // + (Phenomenon::Unknown, "Unknown"); Phenomenon GetPhenomenon(const std::string& code) { @@ -154,6 +155,24 @@ Phenomenon GetPhenomenon(const std::string& code) return phenomenon; } +Phenomenon GetPhenomenonFromText(const std::string& text) +{ + Phenomenon phenomenon; + + if (phenomenonText_.right.find(text) != phenomenonText_.right.end()) + { + phenomenon = phenomenonText_.right.at(text); + } + else + { + phenomenon = Phenomenon::Unknown; + + logger_->debug("Unrecognized code: \"{}\"", text); + } + + return phenomenon; +} + const std::string& GetPhenomenonCode(Phenomenon phenomenon) { return phenomenonCodes_.left.at(phenomenon); @@ -161,7 +180,7 @@ const std::string& GetPhenomenonCode(Phenomenon phenomenon) const std::string& GetPhenomenonText(Phenomenon phenomenon) { - return phenomenonText_.at(phenomenon); + return phenomenonText_.left.at(phenomenon); } } // namespace awips From 0481281680a06243cad15a14c8f365029816d6ed Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Fri, 30 Aug 2024 23:04:16 -0500 Subject: [PATCH 06/36] Threat category of significant should be treated as considerable per latest NWSI --- wxdata/source/scwx/awips/text_product_message.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/wxdata/source/scwx/awips/text_product_message.cpp b/wxdata/source/scwx/awips/text_product_message.cpp index 5128aee8..541a1a1a 100644 --- a/wxdata/source/scwx/awips/text_product_message.cpp +++ b/wxdata/source/scwx/awips/text_product_message.cpp @@ -390,9 +390,21 @@ void ParseCodedInformation(std::shared_ptr segment, it->substr(threatTagIt->length()); ThreatCategory threatCategory = GetThreatCategory(threatCategoryName); - if (threatCategory == ThreatCategory::Unknown) + + switch (threatCategory) { + case ThreatCategory::Significant: + // "Significant" is no longer an official tag, and has largely been + // replaced with "Considerable". + threatCategory = ThreatCategory::Considerable; + break; + + case ThreatCategory::Unknown: threatCategory = ThreatCategory::Base; + break; + + default: + break; } segment->threatCategory_ = threatCategory; From 010879971851bfe533fdf28b4dea524e59e950d9 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sat, 31 Aug 2024 22:58:41 -0500 Subject: [PATCH 07/36] Add line label accessors --- scwx-qt/source/scwx/qt/ui/line_label.cpp | 30 ++++++++++++++++++++++++ scwx-qt/source/scwx/qt/ui/line_label.hpp | 8 +++++++ 2 files changed, 38 insertions(+) diff --git a/scwx-qt/source/scwx/qt/ui/line_label.cpp b/scwx-qt/source/scwx/qt/ui/line_label.cpp index f5c9c3e3..5248057c 100644 --- a/scwx-qt/source/scwx/qt/ui/line_label.cpp +++ b/scwx-qt/source/scwx/qt/ui/line_label.cpp @@ -41,6 +41,36 @@ LineLabel::LineLabel(QWidget* parent) : LineLabel::~LineLabel() {} +boost::gil::rgba8_pixel_t LineLabel::border_color() const +{ + return p->borderColor_; +} + +boost::gil::rgba8_pixel_t LineLabel::highlight_color() const +{ + return p->highlightColor_; +} + +boost::gil::rgba8_pixel_t LineLabel::line_color() const +{ + return p->lineColor_; +} + +std::size_t LineLabel::border_width() const +{ + return p->borderWidth_; +} + +std::size_t LineLabel::highlight_width() const +{ + return p->highlightWidth_; +} + +std::size_t LineLabel::line_width() const +{ + return p->lineWidth_; +} + void LineLabel::set_border_width(std::size_t width) { p->borderWidth_ = width; diff --git a/scwx-qt/source/scwx/qt/ui/line_label.hpp b/scwx-qt/source/scwx/qt/ui/line_label.hpp index 6036e92f..2c2d516b 100644 --- a/scwx-qt/source/scwx/qt/ui/line_label.hpp +++ b/scwx-qt/source/scwx/qt/ui/line_label.hpp @@ -20,6 +20,14 @@ public: explicit LineLabel(QWidget* parent = nullptr); ~LineLabel(); + boost::gil::rgba8_pixel_t border_color() const; + boost::gil::rgba8_pixel_t highlight_color() const; + boost::gil::rgba8_pixel_t line_color() const; + + std::size_t border_width() const; + std::size_t highlight_width() const; + std::size_t line_width() const; + void set_border_color(boost::gil::rgba8_pixel_t color); void set_highlight_color(boost::gil::rgba8_pixel_t color); void set_line_color(boost::gil::rgba8_pixel_t color); From 9182d170de582ac5a0ea509e6b80d35736cd630a Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sat, 31 Aug 2024 22:59:36 -0500 Subject: [PATCH 08/36] Update alert line labels with the edit line dialog --- .../alert_palette_settings_widget.cpp | 110 +++++++++++++----- 1 file changed, 79 insertions(+), 31 deletions(-) diff --git a/scwx-qt/source/scwx/qt/ui/settings/alert_palette_settings_widget.cpp b/scwx-qt/source/scwx/qt/ui/settings/alert_palette_settings_widget.cpp index f433156d..bf0d5970 100644 --- a/scwx-qt/source/scwx/qt/ui/settings/alert_palette_settings_widget.cpp +++ b/scwx-qt/source/scwx/qt/ui/settings/alert_palette_settings_widget.cpp @@ -80,6 +80,7 @@ public: QListWidget* phenomenonListView_; EditLineDialog* editLineDialog_; + LineLabel* activeLineLabel_ {nullptr}; boost::unordered_flat_map phenomenonPages_ {}; }; @@ -93,37 +94,12 @@ AlertPaletteSettingsWidget::~AlertPaletteSettingsWidget() = default; void AlertPaletteSettingsWidget::Impl::SetupUi() { - // Setup primary widget layout - QGridLayout* gridLayout = new QGridLayout(self_); - gridLayout->setContentsMargins(0, 0, 0, 0); - self_->setLayout(gridLayout); - - QWidget* phenomenonIndexPane = new QWidget(self_); - phenomenonPagesWidget_->setSizePolicy(QSizePolicy::Policy::Expanding, + // Setup phenomenon index pane + QLabel* phenomenonLabel = new QLabel(tr("Phenomenon:"), self_); + phenomenonPagesWidget_->setSizePolicy(QSizePolicy::Policy::MinimumExpanding, QSizePolicy::Policy::Preferred); - gridLayout->addWidget(phenomenonIndexPane, 0, 0); - gridLayout->addWidget(phenomenonPagesWidget_, 0, 1); - - QSpacerItem* spacer = - new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding); - gridLayout->addItem(spacer, 1, 0); - - // Setup phenomenon index pane - QVBoxLayout* phenomenonIndexLayout = new QVBoxLayout(self_); - phenomenonIndexPane->setLayout(phenomenonIndexLayout); - - QLabel* phenomenonLabel = new QLabel(tr("Phenomenon:"), self_); - phenomenonListView_->setSizePolicy(QSizePolicy::Policy::Minimum, - QSizePolicy::Policy::Expanding); - - phenomenonIndexLayout->addWidget(phenomenonLabel); - phenomenonIndexLayout->addWidget(phenomenonListView_); - // Setup stacked widget - auto& paletteSettings = settings::PaletteSettings::Instance(); - Q_UNUSED(paletteSettings); - for (auto& phenomenon : settings::PaletteSettings::alert_phenomena()) { QWidget* phenomenonWidget = CreateStackedWidgetPage(phenomenon); @@ -136,11 +112,31 @@ void AlertPaletteSettingsWidget::Impl::SetupUi() } phenomenonListView_->setCurrentRow(0); + + // Create phenomenon index pane layout + QVBoxLayout* phenomenonIndexLayout = new QVBoxLayout(self_); + phenomenonIndexLayout->addWidget(phenomenonLabel); + phenomenonIndexLayout->addWidget(phenomenonListView_); + + QWidget* phenomenonIndexPane = new QWidget(self_); + phenomenonIndexPane->setLayout(phenomenonIndexLayout); + + // Create primary widget layout + QGridLayout* gridLayout = new QGridLayout(self_); + gridLayout->setContentsMargins(0, 0, 0, 0); + gridLayout->addWidget(phenomenonIndexPane, 0, 0); + gridLayout->addWidget(phenomenonPagesWidget_, 0, 1); + + QSpacerItem* spacer = + new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding); + gridLayout->addItem(spacer, 1, 0); + + self_->setLayout(gridLayout); } void AlertPaletteSettingsWidget::Impl::ConnectSignals() { - QObject::connect( + connect( phenomenonListView_->selectionModel(), &QItemSelectionModel::selectionChanged, self_, @@ -168,6 +164,31 @@ void AlertPaletteSettingsWidget::Impl::ConnectSignals() } } }); + + connect( + editLineDialog_, + &EditLineDialog::accepted, + self_, + [this]() + { + // If the active line label was set + if (activeLineLabel_ != nullptr) + { + // Update the active line label with selected line settings + activeLineLabel_->set_border_color(editLineDialog_->border_color()); + activeLineLabel_->set_highlight_color( + editLineDialog_->highlight_color()); + activeLineLabel_->set_line_color(editLineDialog_->line_color()); + + activeLineLabel_->set_border_width(editLineDialog_->border_width()); + activeLineLabel_->set_highlight_width( + editLineDialog_->highlight_width()); + activeLineLabel_->set_line_width(editLineDialog_->line_width()); + + // Reset the active line label + activeLineLabel_ = nullptr; + } + }); } void AlertPaletteSettingsWidget::Impl::SelectPhenomenon( @@ -229,9 +250,36 @@ QWidget* AlertPaletteSettingsWidget::Impl::CreateStackedWidgetPage( void AlertPaletteSettingsWidget::Impl::AddPhenomenonLine( const std::string& name, QGridLayout* layout, int row) { + QToolButton* toolButton = new QToolButton(self_); + toolButton->setText(tr("...")); + + LineLabel* lineLabel = new LineLabel(self_); + layout->addWidget(new QLabel(tr(name.c_str()), self_), row, 0); - layout->addWidget(new LineLabel(self_), row, 1); - layout->addWidget(new QToolButton(self_), row, 2); + layout->addWidget(lineLabel, row, 1); + layout->addWidget(toolButton, row, 2); + + connect( + toolButton, + &QAbstractButton::clicked, + self_, + [this, lineLabel]() + { + // Set the active line label for when the dialog is finished + activeLineLabel_ = lineLabel; + + // Initialize dialog with current line settings + editLineDialog_->set_border_color(lineLabel->border_color()); + editLineDialog_->set_highlight_color(lineLabel->highlight_color()); + editLineDialog_->set_line_color(lineLabel->line_color()); + + editLineDialog_->set_border_width(lineLabel->border_width()); + editLineDialog_->set_highlight_width(lineLabel->highlight_width()); + editLineDialog_->set_line_width(lineLabel->line_width()); + + // Show the dialog + editLineDialog_->show(); + }); } } // namespace ui From 829d8a315294850de72e82039b77e2f75b2cea77 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sun, 15 Sep 2024 23:54:21 -0500 Subject: [PATCH 09/36] Refactoring phenomena info to impact based warnings header --- .../alert_palette_settings_widget.cpp | 32 +------------------ .../scwx/awips/impact_based_warnings.hpp | 12 +++++++ .../scwx/awips/impact_based_warnings.cpp | 31 ++++++++++++++++++ 3 files changed, 44 insertions(+), 31 deletions(-) diff --git a/scwx-qt/source/scwx/qt/ui/settings/alert_palette_settings_widget.cpp b/scwx-qt/source/scwx/qt/ui/settings/alert_palette_settings_widget.cpp index bf0d5970..c4680a62 100644 --- a/scwx-qt/source/scwx/qt/ui/settings/alert_palette_settings_widget.cpp +++ b/scwx-qt/source/scwx/qt/ui/settings/alert_palette_settings_widget.cpp @@ -23,36 +23,6 @@ namespace ui static const std::string logPrefix_ = "scwx::qt::ui::settings::alert_palette_settings_widget"; -struct PhenomenonInfo -{ - bool hasObservedTag_ {false}; - bool hasTornadoPossibleTag_ {false}; - std::vector threatCategories_ { - awips::ThreatCategory::Base}; -}; - -static const boost::unordered_flat_map - phenomenaInfo_ {{awips::Phenomenon::Marine, - PhenomenonInfo {.hasTornadoPossibleTag_ {true}}}, - {awips::Phenomenon::FlashFlood, - PhenomenonInfo {.threatCategories_ { - awips::ThreatCategory::Base, - awips::ThreatCategory::Considerable, - awips::ThreatCategory::Catastrophic}}}, - {awips::Phenomenon::SevereThunderstorm, - PhenomenonInfo {.hasTornadoPossibleTag_ {true}, - .threatCategories_ { - awips::ThreatCategory::Base, - awips::ThreatCategory::Considerable, - awips::ThreatCategory::Destructive}}}, - {awips::Phenomenon::SnowSquall, PhenomenonInfo {}}, - {awips::Phenomenon::Tornado, - PhenomenonInfo {.hasObservedTag_ {true}, - .threatCategories_ { - awips::ThreatCategory::Base, - awips::ThreatCategory::Considerable, - awips::ThreatCategory::Catastrophic}}}}; - class AlertPaletteSettingsWidget::Impl { public: @@ -208,7 +178,7 @@ QWidget* AlertPaletteSettingsWidget::Impl::CreateStackedWidgetPage( QGridLayout* gridLayout = new QGridLayout(self_); page->setLayout(gridLayout); - const auto& phenomenonInfo = phenomenaInfo_.at(phenomenon); + const auto& phenomenonInfo = awips::GetPhenomenonInfo(phenomenon); int row = 0; diff --git a/wxdata/include/scwx/awips/impact_based_warnings.hpp b/wxdata/include/scwx/awips/impact_based_warnings.hpp index a7b22288..7bb07f5a 100644 --- a/wxdata/include/scwx/awips/impact_based_warnings.hpp +++ b/wxdata/include/scwx/awips/impact_based_warnings.hpp @@ -1,6 +1,9 @@ #pragma once +#include + #include +#include namespace scwx { @@ -17,6 +20,15 @@ enum class ThreatCategory : int Unknown }; +struct PhenomenonInfo +{ + bool hasObservedTag_ {false}; + bool hasTornadoPossibleTag_ {false}; + std::vector threatCategories_ {ThreatCategory::Base}; +}; + +const PhenomenonInfo& GetPhenomenonInfo(Phenomenon phenomenon); + ThreatCategory GetThreatCategory(const std::string& name); const std::string& GetThreatCategoryName(ThreatCategory threatCategory); diff --git a/wxdata/source/scwx/awips/impact_based_warnings.cpp b/wxdata/source/scwx/awips/impact_based_warnings.cpp index 75f04d1e..1bf5e321 100644 --- a/wxdata/source/scwx/awips/impact_based_warnings.cpp +++ b/wxdata/source/scwx/awips/impact_based_warnings.cpp @@ -4,6 +4,7 @@ #include #include +#include namespace scwx { @@ -12,6 +13,26 @@ namespace awips static const std::string logPrefix_ = "scwx::awips::impact_based_warnings"; +static const boost::unordered_flat_map + phenomenaInfo_ { + {Phenomenon::Marine, PhenomenonInfo {.hasTornadoPossibleTag_ {true}}}, + {Phenomenon::FlashFlood, + PhenomenonInfo {.threatCategories_ {ThreatCategory::Base, + ThreatCategory::Considerable, + ThreatCategory::Catastrophic}}}, + {Phenomenon::SevereThunderstorm, + PhenomenonInfo {.hasTornadoPossibleTag_ {true}, + .threatCategories_ {ThreatCategory::Base, + ThreatCategory::Considerable, + ThreatCategory::Destructive}}}, + {Phenomenon::SnowSquall, PhenomenonInfo {}}, + {Phenomenon::Tornado, + PhenomenonInfo {.hasObservedTag_ {true}, + .threatCategories_ {ThreatCategory::Base, + ThreatCategory::Considerable, + ThreatCategory::Catastrophic}}}, + {Phenomenon::Unknown, PhenomenonInfo {}}}; + static const std::unordered_map threatCategoryName_ {{ThreatCategory::Base, "Base"}, {ThreatCategory::Significant, "Significant"}, @@ -20,6 +41,16 @@ static const std::unordered_map {ThreatCategory::Catastrophic, "Catastrophic"}, {ThreatCategory::Unknown, "?"}}; +const PhenomenonInfo& GetPhenomenonInfo(Phenomenon phenomenon) +{ + auto it = phenomenaInfo_.find(phenomenon); + if (it != phenomenaInfo_.cend()) + { + return it->second; + } + return phenomenaInfo_.at(Phenomenon::Unknown); +} + SCWX_GET_ENUM(ThreatCategory, GetThreatCategory, threatCategoryName_) const std::string& GetThreatCategoryName(ThreatCategory threatCategory) From 38a28317797f8bcd5725083513b7303397be747a Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Mon, 16 Sep 2024 21:05:07 -0500 Subject: [PATCH 10/36] Renaming PhenomenonInfo to ImpactBasedWarningInfo --- .../alert_palette_settings_widget.cpp | 9 ++-- .../scwx/awips/impact_based_warnings.hpp | 4 +- .../scwx/awips/impact_based_warnings.cpp | 44 ++++++++++--------- 3 files changed, 31 insertions(+), 26 deletions(-) diff --git a/scwx-qt/source/scwx/qt/ui/settings/alert_palette_settings_widget.cpp b/scwx-qt/source/scwx/qt/ui/settings/alert_palette_settings_widget.cpp index c4680a62..2036769f 100644 --- a/scwx-qt/source/scwx/qt/ui/settings/alert_palette_settings_widget.cpp +++ b/scwx-qt/source/scwx/qt/ui/settings/alert_palette_settings_widget.cpp @@ -178,7 +178,8 @@ QWidget* AlertPaletteSettingsWidget::Impl::CreateStackedWidgetPage( QGridLayout* gridLayout = new QGridLayout(self_); page->setLayout(gridLayout); - const auto& phenomenonInfo = awips::GetPhenomenonInfo(phenomenon); + const auto& impactBasedWarningInfo = + awips::GetImpactBasedWarningInfo(phenomenon); int row = 0; @@ -187,17 +188,17 @@ QWidget* AlertPaletteSettingsWidget::Impl::CreateStackedWidgetPage( AddPhenomenonLine("Active", gridLayout, row++); - if (phenomenonInfo.hasObservedTag_) + if (impactBasedWarningInfo.hasObservedTag_) { AddPhenomenonLine("Observed", gridLayout, row++); } - if (phenomenonInfo.hasTornadoPossibleTag_) + if (impactBasedWarningInfo.hasTornadoPossibleTag_) { AddPhenomenonLine("Tornado Possible", gridLayout, row++); } - for (auto& category : phenomenonInfo.threatCategories_) + for (auto& category : impactBasedWarningInfo.threatCategories_) { if (category == awips::ThreatCategory::Base) { diff --git a/wxdata/include/scwx/awips/impact_based_warnings.hpp b/wxdata/include/scwx/awips/impact_based_warnings.hpp index 7bb07f5a..d45ffb8f 100644 --- a/wxdata/include/scwx/awips/impact_based_warnings.hpp +++ b/wxdata/include/scwx/awips/impact_based_warnings.hpp @@ -20,14 +20,14 @@ enum class ThreatCategory : int Unknown }; -struct PhenomenonInfo +struct ImpactBasedWarningInfo { bool hasObservedTag_ {false}; bool hasTornadoPossibleTag_ {false}; std::vector threatCategories_ {ThreatCategory::Base}; }; -const PhenomenonInfo& GetPhenomenonInfo(Phenomenon phenomenon); +const ImpactBasedWarningInfo& GetImpactBasedWarningInfo(Phenomenon phenomenon); ThreatCategory GetThreatCategory(const std::string& name); const std::string& GetThreatCategoryName(ThreatCategory threatCategory); diff --git a/wxdata/source/scwx/awips/impact_based_warnings.cpp b/wxdata/source/scwx/awips/impact_based_warnings.cpp index 1bf5e321..ca26fa7b 100644 --- a/wxdata/source/scwx/awips/impact_based_warnings.cpp +++ b/wxdata/source/scwx/awips/impact_based_warnings.cpp @@ -13,25 +13,29 @@ namespace awips static const std::string logPrefix_ = "scwx::awips::impact_based_warnings"; -static const boost::unordered_flat_map - phenomenaInfo_ { - {Phenomenon::Marine, PhenomenonInfo {.hasTornadoPossibleTag_ {true}}}, +static const boost::unordered_flat_map + impactBasedWarningInfo_ { + {Phenomenon::Marine, + ImpactBasedWarningInfo {.hasTornadoPossibleTag_ {true}}}, {Phenomenon::FlashFlood, - PhenomenonInfo {.threatCategories_ {ThreatCategory::Base, - ThreatCategory::Considerable, - ThreatCategory::Catastrophic}}}, + ImpactBasedWarningInfo { + .threatCategories_ {ThreatCategory::Base, + ThreatCategory::Considerable, + ThreatCategory::Catastrophic}}}, {Phenomenon::SevereThunderstorm, - PhenomenonInfo {.hasTornadoPossibleTag_ {true}, - .threatCategories_ {ThreatCategory::Base, - ThreatCategory::Considerable, - ThreatCategory::Destructive}}}, - {Phenomenon::SnowSquall, PhenomenonInfo {}}, + ImpactBasedWarningInfo { + .hasTornadoPossibleTag_ {true}, + .threatCategories_ {ThreatCategory::Base, + ThreatCategory::Considerable, + ThreatCategory::Destructive}}}, + {Phenomenon::SnowSquall, ImpactBasedWarningInfo {}}, {Phenomenon::Tornado, - PhenomenonInfo {.hasObservedTag_ {true}, - .threatCategories_ {ThreatCategory::Base, - ThreatCategory::Considerable, - ThreatCategory::Catastrophic}}}, - {Phenomenon::Unknown, PhenomenonInfo {}}}; + ImpactBasedWarningInfo { + .hasObservedTag_ {true}, + .threatCategories_ {ThreatCategory::Base, + ThreatCategory::Considerable, + ThreatCategory::Catastrophic}}}, + {Phenomenon::Unknown, ImpactBasedWarningInfo {}}}; static const std::unordered_map threatCategoryName_ {{ThreatCategory::Base, "Base"}, @@ -41,14 +45,14 @@ static const std::unordered_map {ThreatCategory::Catastrophic, "Catastrophic"}, {ThreatCategory::Unknown, "?"}}; -const PhenomenonInfo& GetPhenomenonInfo(Phenomenon phenomenon) +const ImpactBasedWarningInfo& GetImpactBasedWarningInfo(Phenomenon phenomenon) { - auto it = phenomenaInfo_.find(phenomenon); - if (it != phenomenaInfo_.cend()) + auto it = impactBasedWarningInfo_.find(phenomenon); + if (it != impactBasedWarningInfo_.cend()) { return it->second; } - return phenomenaInfo_.at(Phenomenon::Unknown); + return impactBasedWarningInfo_.at(Phenomenon::Unknown); } SCWX_GET_ENUM(ThreatCategory, GetThreatCategory, threatCategoryName_) From 7101cdf183d65ff0ded95379b06c8c2af876c638 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Mon, 16 Sep 2024 21:13:45 -0500 Subject: [PATCH 11/36] Adding impact based warnings to ibw namespace --- scwx-qt/source/scwx/qt/model/alert_model.cpp | 19 +++++++++---------- .../alert_palette_settings_widget.cpp | 6 +++--- .../scwx/awips/impact_based_warnings.hpp | 3 +++ .../scwx/awips/text_product_message.hpp | 6 +++--- .../scwx/awips/impact_based_warnings.cpp | 5 ++++- .../scwx/awips/text_product_message.cpp | 13 +++++++------ 6 files changed, 29 insertions(+), 23 deletions(-) diff --git a/scwx-qt/source/scwx/qt/model/alert_model.cpp b/scwx-qt/source/scwx/qt/model/alert_model.cpp index d4bb1111..fed7cc17 100644 --- a/scwx-qt/source/scwx/qt/model/alert_model.cpp +++ b/scwx-qt/source/scwx/qt/model/alert_model.cpp @@ -10,7 +10,6 @@ #include #include - #include #include @@ -37,9 +36,9 @@ public: explicit AlertModelImpl(); ~AlertModelImpl() = default; - bool GetObserved(const types::TextEventKey& key); - awips::ThreatCategory GetThreatCategory(const types::TextEventKey& key); - bool GetTornadoPossible(const types::TextEventKey& key); + bool GetObserved(const types::TextEventKey& key); + awips::ibw::ThreatCategory GetThreatCategory(const types::TextEventKey& key); + bool GetTornadoPossible(const types::TextEventKey& key); static std::string GetCounties(const types::TextEventKey& key); static std::string GetState(const types::TextEventKey& key); @@ -61,7 +60,7 @@ public: types::TextEventHash> observedMap_; std::unordered_map> threatCategoryMap_; std::unordered_map> - distanceMap_; - scwx::common::Coordinate previousPosition_; + distanceMap_; + scwx::common::Coordinate previousPosition_; }; AlertModel::AlertModel(QObject* parent) : @@ -158,7 +157,7 @@ QVariant AlertModel::data(const QModelIndex& index, int role) const case static_cast(Column::ThreatCategory): if (role == Qt::DisplayRole) { - return QString::fromStdString(awips::GetThreatCategoryName( + return QString::fromStdString(awips::ibw::GetThreatCategoryName( p->GetThreatCategory(textEventKey))); } else @@ -439,10 +438,10 @@ bool AlertModelImpl::GetObserved(const types::TextEventKey& key) return observed; } -awips::ThreatCategory +awips::ibw::ThreatCategory AlertModelImpl::GetThreatCategory(const types::TextEventKey& key) { - awips::ThreatCategory threatCategory = awips::ThreatCategory::Base; + awips::ibw::ThreatCategory threatCategory = awips::ibw::ThreatCategory::Base; auto it = threatCategoryMap_.find(key); if (it != threatCategoryMap_.cend()) diff --git a/scwx-qt/source/scwx/qt/ui/settings/alert_palette_settings_widget.cpp b/scwx-qt/source/scwx/qt/ui/settings/alert_palette_settings_widget.cpp index 2036769f..0eb49807 100644 --- a/scwx-qt/source/scwx/qt/ui/settings/alert_palette_settings_widget.cpp +++ b/scwx-qt/source/scwx/qt/ui/settings/alert_palette_settings_widget.cpp @@ -179,7 +179,7 @@ QWidget* AlertPaletteSettingsWidget::Impl::CreateStackedWidgetPage( page->setLayout(gridLayout); const auto& impactBasedWarningInfo = - awips::GetImpactBasedWarningInfo(phenomenon); + awips::ibw::GetImpactBasedWarningInfo(phenomenon); int row = 0; @@ -200,13 +200,13 @@ QWidget* AlertPaletteSettingsWidget::Impl::CreateStackedWidgetPage( for (auto& category : impactBasedWarningInfo.threatCategories_) { - if (category == awips::ThreatCategory::Base) + if (category == awips::ibw::ThreatCategory::Base) { continue; } AddPhenomenonLine( - awips::GetThreatCategoryName(category), gridLayout, row++); + awips::ibw::GetThreatCategoryName(category), gridLayout, row++); } AddPhenomenonLine("Inactive", gridLayout, row++); diff --git a/wxdata/include/scwx/awips/impact_based_warnings.hpp b/wxdata/include/scwx/awips/impact_based_warnings.hpp index d45ffb8f..3d956893 100644 --- a/wxdata/include/scwx/awips/impact_based_warnings.hpp +++ b/wxdata/include/scwx/awips/impact_based_warnings.hpp @@ -9,6 +9,8 @@ namespace scwx { namespace awips { +namespace ibw +{ enum class ThreatCategory : int { @@ -32,5 +34,6 @@ const ImpactBasedWarningInfo& GetImpactBasedWarningInfo(Phenomenon phenomenon); ThreatCategory GetThreatCategory(const std::string& name); const std::string& GetThreatCategoryName(ThreatCategory threatCategory); +} // namespace ibw } // namespace awips } // namespace scwx diff --git a/wxdata/include/scwx/awips/text_product_message.hpp b/wxdata/include/scwx/awips/text_product_message.hpp index dec4af09..b043494f 100644 --- a/wxdata/include/scwx/awips/text_product_message.hpp +++ b/wxdata/include/scwx/awips/text_product_message.hpp @@ -64,9 +64,9 @@ struct Segment std::optional codedLocation_ {}; std::optional codedMotion_ {}; - bool observed_ {false}; - ThreatCategory threatCategory_ {ThreatCategory::Base}; - bool tornadoPossible_ {false}; + bool observed_ {false}; + ibw::ThreatCategory threatCategory_ {ibw::ThreatCategory::Base}; + bool tornadoPossible_ {false}; Segment() = default; diff --git a/wxdata/source/scwx/awips/impact_based_warnings.cpp b/wxdata/source/scwx/awips/impact_based_warnings.cpp index ca26fa7b..a5e63a76 100644 --- a/wxdata/source/scwx/awips/impact_based_warnings.cpp +++ b/wxdata/source/scwx/awips/impact_based_warnings.cpp @@ -10,8 +10,10 @@ namespace scwx { namespace awips { +namespace ibw +{ -static const std::string logPrefix_ = "scwx::awips::impact_based_warnings"; +static const std::string logPrefix_ = "scwx::awips::ibw::impact_based_warnings"; static const boost::unordered_flat_map impactBasedWarningInfo_ { @@ -62,5 +64,6 @@ const std::string& GetThreatCategoryName(ThreatCategory threatCategory) return threatCategoryName_.at(threatCategory); } +} // namespace ibw } // namespace awips } // namespace scwx diff --git a/wxdata/source/scwx/awips/text_product_message.cpp b/wxdata/source/scwx/awips/text_product_message.cpp index 541a1a1a..54ce7e25 100644 --- a/wxdata/source/scwx/awips/text_product_message.cpp +++ b/wxdata/source/scwx/awips/text_product_message.cpp @@ -378,7 +378,7 @@ void ParseCodedInformation(std::shared_ptr segment, segment->tornadoPossible_ = true; } - else if (segment->threatCategory_ == ThreatCategory::Base && + else if (segment->threatCategory_ == ibw::ThreatCategory::Base && (threatTagIt = std::find_if(kThreatCategoryTags.cbegin(), kThreatCategoryTags.cend(), [&it](const std::string& tag) { @@ -389,18 +389,19 @@ void ParseCodedInformation(std::shared_ptr segment, const std::string threatCategoryName = it->substr(threatTagIt->length()); - ThreatCategory threatCategory = GetThreatCategory(threatCategoryName); + ibw::ThreatCategory threatCategory = + ibw::GetThreatCategory(threatCategoryName); switch (threatCategory) { - case ThreatCategory::Significant: + case ibw::ThreatCategory::Significant: // "Significant" is no longer an official tag, and has largely been // replaced with "Considerable". - threatCategory = ThreatCategory::Considerable; + threatCategory = ibw::ThreatCategory::Considerable; break; - case ThreatCategory::Unknown: - threatCategory = ThreatCategory::Base; + case ibw::ThreatCategory::Unknown: + threatCategory = ibw::ThreatCategory::Base; break; default: From 8fc392681a6a0885be55492eead969d7cd3476f5 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Mon, 16 Sep 2024 22:02:41 -0500 Subject: [PATCH 12/36] Initial impact based warning palette settings TODO: - Update settings to use line component data - Add interface to data --- .../scwx/qt/settings/palette_settings.cpp | 179 +++++++++++++----- .../scwx/qt/settings/palette_settings.hpp | 1 + 2 files changed, 134 insertions(+), 46 deletions(-) diff --git a/scwx-qt/source/scwx/qt/settings/palette_settings.cpp b/scwx-qt/source/scwx/qt/settings/palette_settings.cpp index 9d9c93fa..4c61a916 100644 --- a/scwx-qt/source/scwx/qt/settings/palette_settings.cpp +++ b/scwx-qt/source/scwx/qt/settings/palette_settings.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -76,66 +77,59 @@ static const awips::Phenomenon kDefaultPhenomenon_ {awips::Phenomenon::Marine}; class PaletteSettings::Impl { public: - explicit Impl() + struct AlertData { - palette_.reserve(kPaletteKeys_.size()); - - for (const auto& name : kPaletteKeys_) + AlertData(awips::Phenomenon phenomenon) : phenomenon_ {phenomenon} { - const std::string& defaultValue = kDefaultPalettes_.at(name); - - auto result = - palette_.emplace(name, SettingsVariable {name}); - - SettingsVariable& settingsVariable = result.first->second; - - settingsVariable.SetDefault(defaultValue); - - variables_.push_back(&settingsVariable); - }; - - activeAlertColor_.reserve(kAlertColors_.size()); - inactiveAlertColor_.reserve(kAlertColors_.size()); - - for (auto& alert : kAlertColors_) - { - std::string phenomenonCode = awips::GetPhenomenonCode(alert.first); - std::string activeName = fmt::format("{}-active", phenomenonCode); - std::string inactiveName = fmt::format("{}-inactive", phenomenonCode); - - auto activeResult = activeAlertColor_.emplace( - alert.first, SettingsVariable {activeName}); - auto inactiveResult = inactiveAlertColor_.emplace( - alert.first, SettingsVariable {inactiveName}); - - SettingsVariable& activeVariable = - activeResult.first->second; - SettingsVariable& inactiveVariable = - inactiveResult.first->second; - - activeVariable.SetDefault( - util::color::ToArgbString(alert.second.first)); - inactiveVariable.SetDefault( - util::color::ToArgbString(alert.second.second)); - - activeVariable.SetValidator(&ValidateColor); - inactiveVariable.SetValidator(&ValidateColor); - - variables_.push_back(&activeVariable); - variables_.push_back(&inactiveVariable); + auto& info = awips::ibw::GetImpactBasedWarningInfo(phenomenon); + for (auto& threatCategory : info.threatCategories_) + { + std::string threatCategoryName = + awips::ibw::GetThreatCategoryName(threatCategory); + boost::algorithm::to_lower(threatCategoryName); + threatCategoryMap_.emplace(threatCategory, threatCategoryName); + } } + + void RegisterVariables(SettingsCategory& settings); + + awips::Phenomenon phenomenon_; + + std::map> + threatCategoryMap_ {}; + + SettingsVariable observed_ {"observed"}; + SettingsVariable tornadoPossible_ {"tornado_possible"}; + SettingsVariable inactive_ {"inactive"}; + }; + + explicit Impl(PaletteSettings* self) : self_ {self} + { + InitializeColorTables(); + InitializeLegacyAlerts(); + InitializeAlerts(); } ~Impl() {} + void InitializeColorTables(); + void InitializeLegacyAlerts(); + void InitializeAlerts(); + static bool ValidateColor(const std::string& value); + PaletteSettings* self_; + std::unordered_map> palette_ {}; std::unordered_map> activeAlertColor_ {}; std::unordered_map> inactiveAlertColor_ {}; std::vector variables_ {}; + + std::unordered_map alertDataMap_ {}; + + std::vector alertSettings_ {}; }; bool PaletteSettings::Impl::ValidateColor(const std::string& value) @@ -145,7 +139,7 @@ bool PaletteSettings::Impl::ValidateColor(const std::string& value) } PaletteSettings::PaletteSettings() : - SettingsCategory("palette"), p(std::make_unique()) + SettingsCategory("palette"), p(std::make_unique(this)) { RegisterVariables(p->variables_); SetDefaults(); @@ -158,6 +152,99 @@ PaletteSettings::PaletteSettings(PaletteSettings&&) noexcept = default; PaletteSettings& PaletteSettings::operator=(PaletteSettings&&) noexcept = default; +void PaletteSettings::Impl::InitializeColorTables() +{ + palette_.reserve(kPaletteKeys_.size()); + + for (const auto& name : kPaletteKeys_) + { + const std::string& defaultValue = kDefaultPalettes_.at(name); + + auto result = + palette_.emplace(name, SettingsVariable {name}); + + SettingsVariable& settingsVariable = result.first->second; + + settingsVariable.SetDefault(defaultValue); + + variables_.push_back(&settingsVariable); + }; +} + +void PaletteSettings::Impl::InitializeLegacyAlerts() +{ + activeAlertColor_.reserve(kAlertColors_.size()); + inactiveAlertColor_.reserve(kAlertColors_.size()); + + for (auto& alert : kAlertColors_) + { + std::string phenomenonCode = awips::GetPhenomenonCode(alert.first); + std::string activeName = fmt::format("{}-active", phenomenonCode); + std::string inactiveName = fmt::format("{}-inactive", phenomenonCode); + + auto activeResult = activeAlertColor_.emplace( + alert.first, SettingsVariable {activeName}); + auto inactiveResult = inactiveAlertColor_.emplace( + alert.first, SettingsVariable {inactiveName}); + + SettingsVariable& activeVariable = + activeResult.first->second; + SettingsVariable& inactiveVariable = + inactiveResult.first->second; + + activeVariable.SetDefault(util::color::ToArgbString(alert.second.first)); + inactiveVariable.SetDefault( + util::color::ToArgbString(alert.second.second)); + + activeVariable.SetValidator(&ValidateColor); + inactiveVariable.SetValidator(&ValidateColor); + + variables_.push_back(&activeVariable); + variables_.push_back(&inactiveVariable); + } +} + +void PaletteSettings::Impl::InitializeAlerts() +{ + for (auto phenomenon : PaletteSettings::alert_phenomena()) + { + auto pair = alertDataMap_.emplace( + std::make_pair(phenomenon, AlertData {phenomenon})); + auto& alertData = pair.first->second; + + // Variable registration + auto& settings = alertSettings_.emplace_back( + SettingsCategory {awips::GetPhenomenonCode(phenomenon)}); + + alertData.RegisterVariables(settings); + } + + self_->RegisterSubcategoryArray("alerts", alertSettings_); +} + +void PaletteSettings::Impl::AlertData::RegisterVariables( + SettingsCategory& settings) +{ + auto& info = awips::ibw::GetImpactBasedWarningInfo(phenomenon_); + + for (auto& threatCategory : threatCategoryMap_) + { + settings.RegisterVariables({&threatCategory.second}); + } + + if (info.hasObservedTag_) + { + settings.RegisterVariables({&observed_}); + } + + if (info.hasTornadoPossibleTag_) + { + settings.RegisterVariables({&tornadoPossible_}); + } + + settings.RegisterVariables({&inactive_}); +} + SettingsVariable& PaletteSettings::palette(const std::string& name) const { diff --git a/scwx-qt/source/scwx/qt/settings/palette_settings.hpp b/scwx-qt/source/scwx/qt/settings/palette_settings.hpp index c0f7985a..bf21e119 100644 --- a/scwx-qt/source/scwx/qt/settings/palette_settings.hpp +++ b/scwx-qt/source/scwx/qt/settings/palette_settings.hpp @@ -2,6 +2,7 @@ #include #include +#include #include #include From c8dc8ed6303c39c294e56cafb461390d530fa05a Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Thu, 19 Sep 2024 23:15:41 -0500 Subject: [PATCH 13/36] Refactor color validator from settings to utility source --- .../source/scwx/qt/settings/palette_settings.cpp | 13 ++----------- scwx-qt/source/scwx/qt/util/color.cpp | 7 +++++++ scwx-qt/source/scwx/qt/util/color.hpp | 9 +++++++++ 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/scwx-qt/source/scwx/qt/settings/palette_settings.cpp b/scwx-qt/source/scwx/qt/settings/palette_settings.cpp index 4c61a916..12e3fe99 100644 --- a/scwx-qt/source/scwx/qt/settings/palette_settings.cpp +++ b/scwx-qt/source/scwx/qt/settings/palette_settings.cpp @@ -5,7 +5,6 @@ #include #include #include -#include namespace scwx { @@ -116,8 +115,6 @@ public: void InitializeLegacyAlerts(); void InitializeAlerts(); - static bool ValidateColor(const std::string& value); - PaletteSettings* self_; std::unordered_map> palette_ {}; @@ -132,12 +129,6 @@ public: std::vector alertSettings_ {}; }; -bool PaletteSettings::Impl::ValidateColor(const std::string& value) -{ - static constexpr LazyRE2 re = {"#[0-9A-Fa-f]{8}"}; - return RE2::FullMatch(value, *re); -} - PaletteSettings::PaletteSettings() : SettingsCategory("palette"), p(std::make_unique(this)) { @@ -196,8 +187,8 @@ void PaletteSettings::Impl::InitializeLegacyAlerts() inactiveVariable.SetDefault( util::color::ToArgbString(alert.second.second)); - activeVariable.SetValidator(&ValidateColor); - inactiveVariable.SetValidator(&ValidateColor); + activeVariable.SetValidator(&util::color::ValidateArgbString); + inactiveVariable.SetValidator(&util::color::ValidateArgbString); variables_.push_back(&activeVariable); variables_.push_back(&inactiveVariable); diff --git a/scwx-qt/source/scwx/qt/util/color.cpp b/scwx-qt/source/scwx/qt/util/color.cpp index 6e193dc9..16060bb9 100644 --- a/scwx-qt/source/scwx/qt/util/color.cpp +++ b/scwx-qt/source/scwx/qt/util/color.cpp @@ -1,6 +1,7 @@ #include #include +#include #include namespace scwx @@ -38,6 +39,12 @@ boost::gil::rgba32f_pixel_t ToRgba32fPixelT(const std::string& argbString) rgba8Pixel[3] / 255.0f}; } +bool ValidateArgbString(const std::string& argbString) +{ + static constexpr LazyRE2 re = {"#[0-9A-Fa-f]{8}"}; + return RE2::FullMatch(argbString, *re); +} + } // namespace color } // namespace util } // namespace qt diff --git a/scwx-qt/source/scwx/qt/util/color.hpp b/scwx-qt/source/scwx/qt/util/color.hpp index 73ca07f1..6d90fe56 100644 --- a/scwx-qt/source/scwx/qt/util/color.hpp +++ b/scwx-qt/source/scwx/qt/util/color.hpp @@ -39,6 +39,15 @@ boost::gil::rgba8_pixel_t ToRgba8PixelT(const std::string& argbString); */ boost::gil::rgba32f_pixel_t ToRgba32fPixelT(const std::string& argbString); +/** + * Validates an ARGB string used by Qt libraries. + * + * @param argbString + * + * @return Validity of ARGB string + */ +bool ValidateArgbString(const std::string& argbString); + } // namespace color } // namespace util } // namespace qt From cea299366506029219be9f8ff4cf35fa8fe28f9a Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Thu, 19 Sep 2024 23:16:54 -0500 Subject: [PATCH 14/36] Add LineSettings class to use as subcategory --- scwx-qt/scwx-qt.cmake | 2 + .../source/scwx/qt/settings/line_settings.cpp | 121 ++++++++++++++++++ .../source/scwx/qt/settings/line_settings.hpp | 45 +++++++ 3 files changed, 168 insertions(+) create mode 100644 scwx-qt/source/scwx/qt/settings/line_settings.cpp create mode 100644 scwx-qt/source/scwx/qt/settings/line_settings.hpp diff --git a/scwx-qt/scwx-qt.cmake b/scwx-qt/scwx-qt.cmake index 52d26ccc..530f93a1 100644 --- a/scwx-qt/scwx-qt.cmake +++ b/scwx-qt/scwx-qt.cmake @@ -172,6 +172,7 @@ set(SRC_REQUEST source/scwx/qt/request/download_request.cpp set(HDR_SETTINGS source/scwx/qt/settings/audio_settings.hpp source/scwx/qt/settings/general_settings.hpp source/scwx/qt/settings/hotkey_settings.hpp + source/scwx/qt/settings/line_settings.hpp source/scwx/qt/settings/map_settings.hpp source/scwx/qt/settings/palette_settings.hpp source/scwx/qt/settings/product_settings.hpp @@ -188,6 +189,7 @@ set(HDR_SETTINGS source/scwx/qt/settings/audio_settings.hpp set(SRC_SETTINGS source/scwx/qt/settings/audio_settings.cpp source/scwx/qt/settings/general_settings.cpp source/scwx/qt/settings/hotkey_settings.cpp + source/scwx/qt/settings/line_settings.cpp source/scwx/qt/settings/map_settings.cpp source/scwx/qt/settings/palette_settings.cpp source/scwx/qt/settings/product_settings.cpp diff --git a/scwx-qt/source/scwx/qt/settings/line_settings.cpp b/scwx-qt/source/scwx/qt/settings/line_settings.cpp new file mode 100644 index 00000000..bc467186 --- /dev/null +++ b/scwx-qt/source/scwx/qt/settings/line_settings.cpp @@ -0,0 +1,121 @@ +#include +#include + +#include + +namespace scwx +{ +namespace qt +{ +namespace settings +{ + +static const std::string logPrefix_ = "scwx::qt::settings::line_settings"; + +static const boost::gil::rgba8_pixel_t kTransparentColor_ {0, 0, 0, 0}; +static const std::string kTransparentColorString_ { + util::color::ToArgbString(kTransparentColor_)}; + +static const boost::gil::rgba8_pixel_t kBlackColor_ {0, 0, 0, 255}; +static const std::string kBlackColorString_ { + util::color::ToArgbString(kBlackColor_)}; + +static const boost::gil::rgba8_pixel_t kWhiteColor_ {255, 255, 255, 255}; +static const std::string kWhiteColorString_ { + util::color::ToArgbString(kWhiteColor_)}; + +class LineSettings::Impl +{ +public: + explicit Impl() + { + lineColor_.SetDefault(kWhiteColorString_); + highlightColor_.SetDefault(kTransparentColorString_); + borderColor_.SetDefault(kBlackColorString_); + + lineWidth_.SetDefault(3); + highlightWidth_.SetDefault(0); + borderWidth_.SetDefault(1); + + lineWidth_.SetMinimum(1); + highlightWidth_.SetMinimum(0); + borderWidth_.SetMinimum(0); + + lineWidth_.SetMaximum(9); + highlightWidth_.SetMaximum(9); + borderWidth_.SetMaximum(9); + + lineColor_.SetValidator(&util::color::ValidateArgbString); + highlightColor_.SetValidator(&util::color::ValidateArgbString); + borderColor_.SetValidator(&util::color::ValidateArgbString); + } + ~Impl() {} + + SettingsVariable lineColor_ {"line_color"}; + SettingsVariable highlightColor_ {"highlight_color"}; + SettingsVariable borderColor_ {"border_color"}; + + SettingsVariable lineWidth_ {"line_width"}; + SettingsVariable highlightWidth_ {"highlight_width"}; + SettingsVariable borderWidth_ {"border_width"}; +}; + +LineSettings::LineSettings(const std::string& name) : + SettingsCategory(name), p(std::make_unique()) +{ + RegisterVariables({&p->lineColor_, + &p->highlightColor_, + &p->borderColor_, + &p->lineWidth_, + &p->highlightWidth_, + &p->borderWidth_}); + SetDefaults(); +} +LineSettings::~LineSettings() = default; + +LineSettings::LineSettings(LineSettings&&) noexcept = default; +LineSettings& LineSettings::operator=(LineSettings&&) noexcept = default; + +SettingsVariable& LineSettings::border_color() const +{ + return p->borderColor_; +} + +SettingsVariable& LineSettings::highlight_color() const +{ + return p->highlightColor_; +} + +SettingsVariable& LineSettings::line_color() const +{ + return p->lineColor_; +} + +SettingsVariable& LineSettings::border_width() const +{ + return p->borderWidth_; +} + +SettingsVariable& LineSettings::highlight_width() const +{ + return p->highlightWidth_; +} + +SettingsVariable& LineSettings::line_width() const +{ + return p->lineWidth_; +} + +bool operator==(const LineSettings& lhs, const LineSettings& rhs) +{ + return (lhs.p->borderColor_ == rhs.p->borderColor_ && + lhs.p->highlightColor_ == rhs.p->highlightColor_ && + lhs.p->lineColor_ == rhs.p->lineColor_ && + lhs.p->borderWidth_ == rhs.p->borderWidth_ && + lhs.p->highlightWidth_ == rhs.p->highlightWidth_ && + lhs.p->lineWidth_ == rhs.p->lineWidth_); +} + +} // namespace settings +} // namespace qt +} // namespace scwx diff --git a/scwx-qt/source/scwx/qt/settings/line_settings.hpp b/scwx-qt/source/scwx/qt/settings/line_settings.hpp new file mode 100644 index 00000000..e99d9b3e --- /dev/null +++ b/scwx-qt/source/scwx/qt/settings/line_settings.hpp @@ -0,0 +1,45 @@ +#pragma once + +#include +#include + +#include +#include + +namespace scwx +{ +namespace qt +{ +namespace settings +{ + +class LineSettings : public SettingsCategory +{ +public: + explicit LineSettings(const std::string& name); + ~LineSettings(); + + LineSettings(const LineSettings&) = delete; + LineSettings& operator=(const LineSettings&) = delete; + + LineSettings(LineSettings&&) noexcept; + LineSettings& operator=(LineSettings&&) noexcept; + + SettingsVariable& border_color() const; + SettingsVariable& highlight_color() const; + SettingsVariable& line_color() const; + + SettingsVariable& border_width() const; + SettingsVariable& highlight_width() const; + SettingsVariable& line_width() const; + + friend bool operator==(const LineSettings& lhs, const LineSettings& rhs); + +private: + class Impl; + std::unique_ptr p; +}; + +} // namespace settings +} // namespace qt +} // namespace scwx From 1a30743c0a0b6ca11793f529aaa3655e5a90603c Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sat, 21 Sep 2024 08:28:09 -0500 Subject: [PATCH 15/36] Add subcategory functionality to settings, still need to read/write JSON --- .../scwx/qt/settings/settings_category.cpp | 40 +++++++++++++++++++ .../scwx/qt/settings/settings_category.hpp | 3 ++ 2 files changed, 43 insertions(+) diff --git a/scwx-qt/source/scwx/qt/settings/settings_category.cpp b/scwx-qt/source/scwx/qt/settings/settings_category.cpp index e6c929f8..a346c50d 100644 --- a/scwx-qt/source/scwx/qt/settings/settings_category.cpp +++ b/scwx-qt/source/scwx/qt/settings/settings_category.cpp @@ -25,6 +25,7 @@ public: std::vector>> subcategoryArrays_; + std::vector subcategories_; std::vector variables_; }; @@ -54,6 +55,12 @@ void SettingsCategory::SetDefaults() } } + // Set subcategory defaults + for (auto& subcategory : p->subcategories_) + { + subcategory->SetDefaults(); + } + // Set variable defaults for (auto& variable : p->variables_) { @@ -111,6 +118,14 @@ bool SettingsCategory::ReadJson(const boost::json::object& json) } } + // Read subcategories + for (auto& subcategory : p->subcategories_) + { + (void) subcategory; + // TODO: + // subcategory->ReadJson(object); + } + // Read variables for (auto& variable : p->variables_) { @@ -154,6 +169,14 @@ void SettingsCategory::WriteJson(boost::json::object& json) const object.insert_or_assign(subcategoryArray.first, arrayObject); } + // Write subcategories + for (auto& subcategory : p->subcategories_) + { + (void) subcategory; + // TODO: + // subcategory->WriteJson(); + } + // Write variables for (auto& variable : p->variables_) { @@ -163,6 +186,11 @@ void SettingsCategory::WriteJson(boost::json::object& json) const json.insert_or_assign(p->name_, object); } +void SettingsCategory::RegisterSubcategory(SettingsCategory& subcategory) +{ + p->subcategories_.push_back(&subcategory); +} + void SettingsCategory::RegisterSubcategoryArray( const std::string& name, std::vector& subcategories) { @@ -175,6 +203,18 @@ void SettingsCategory::RegisterSubcategoryArray( [](SettingsCategory& subcategory) { return &subcategory; }); } +void SettingsCategory::RegisterSubcategoryArray( + const std::string& name, std::vector& subcategories) +{ + auto& newSubcategories = p->subcategoryArrays_.emplace_back( + name, std::vector {}); + + std::transform(subcategories.begin(), + subcategories.end(), + std::back_inserter(newSubcategories.second), + [](SettingsCategory* subcategory) { return subcategory; }); +} + void SettingsCategory::RegisterVariables( std::initializer_list variables) { diff --git a/scwx-qt/source/scwx/qt/settings/settings_category.hpp b/scwx-qt/source/scwx/qt/settings/settings_category.hpp index 2da7b9ab..bea48659 100644 --- a/scwx-qt/source/scwx/qt/settings/settings_category.hpp +++ b/scwx-qt/source/scwx/qt/settings/settings_category.hpp @@ -50,8 +50,11 @@ public: */ virtual void WriteJson(boost::json::object& json) const; + void RegisterSubcategory(SettingsCategory& subcategory); void RegisterSubcategoryArray(const std::string& name, std::vector& subcategories); + void RegisterSubcategoryArray(const std::string& name, + std::vector& subcategories); void RegisterVariables(std::initializer_list variables); void RegisterVariables(std::vector variables); From efee1653e1589d32bc34e78ee53a9663a66ae8a1 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sat, 21 Sep 2024 08:29:13 -0500 Subject: [PATCH 16/36] Add alert palette settings --- scwx-qt/scwx-qt.cmake | 6 +- .../qt/settings/alert_palette_settings.cpp | 112 ++++++++++++++++++ .../qt/settings/alert_palette_settings.hpp | 46 +++++++ 3 files changed, 162 insertions(+), 2 deletions(-) create mode 100644 scwx-qt/source/scwx/qt/settings/alert_palette_settings.cpp create mode 100644 scwx-qt/source/scwx/qt/settings/alert_palette_settings.hpp diff --git a/scwx-qt/scwx-qt.cmake b/scwx-qt/scwx-qt.cmake index 530f93a1..06646bbe 100644 --- a/scwx-qt/scwx-qt.cmake +++ b/scwx-qt/scwx-qt.cmake @@ -169,7 +169,8 @@ set(HDR_REQUEST source/scwx/qt/request/download_request.hpp source/scwx/qt/request/nexrad_file_request.hpp) set(SRC_REQUEST source/scwx/qt/request/download_request.cpp source/scwx/qt/request/nexrad_file_request.cpp) -set(HDR_SETTINGS source/scwx/qt/settings/audio_settings.hpp +set(HDR_SETTINGS source/scwx/qt/settings/alert_palette_settings.hpp + source/scwx/qt/settings/audio_settings.hpp source/scwx/qt/settings/general_settings.hpp source/scwx/qt/settings/hotkey_settings.hpp source/scwx/qt/settings/line_settings.hpp @@ -186,7 +187,8 @@ set(HDR_SETTINGS source/scwx/qt/settings/audio_settings.hpp source/scwx/qt/settings/text_settings.hpp source/scwx/qt/settings/ui_settings.hpp source/scwx/qt/settings/unit_settings.hpp) -set(SRC_SETTINGS source/scwx/qt/settings/audio_settings.cpp +set(SRC_SETTINGS source/scwx/qt/settings/alert_palette_settings.cpp + source/scwx/qt/settings/audio_settings.cpp source/scwx/qt/settings/general_settings.cpp source/scwx/qt/settings/hotkey_settings.cpp source/scwx/qt/settings/line_settings.cpp diff --git a/scwx-qt/source/scwx/qt/settings/alert_palette_settings.cpp b/scwx-qt/source/scwx/qt/settings/alert_palette_settings.cpp new file mode 100644 index 00000000..ed82ef7e --- /dev/null +++ b/scwx-qt/source/scwx/qt/settings/alert_palette_settings.cpp @@ -0,0 +1,112 @@ +#include +#include + +#include + +#include +#include + +namespace scwx +{ +namespace qt +{ +namespace settings +{ + +static const std::string logPrefix_ = + "scwx::qt::settings::alert_palette_settings"; + +class AlertPaletteSettings::Impl +{ +public: + explicit Impl(awips::Phenomenon phenomenon) : phenomenon_ {phenomenon} + { + auto& info = awips::ibw::GetImpactBasedWarningInfo(phenomenon); + for (auto& threatCategory : info.threatCategories_) + { + std::string threatCategoryName = + awips::ibw::GetThreatCategoryName(threatCategory); + boost::algorithm::to_lower(threatCategoryName); + threatCategoryMap_.emplace(threatCategory, threatCategoryName); + } + } + ~Impl() {} + + awips::Phenomenon phenomenon_; + + std::map threatCategoryMap_ {}; + + LineSettings observed_ {"observed"}; + LineSettings tornadoPossible_ {"tornado_possible"}; + LineSettings inactive_ {"inactive"}; +}; + +AlertPaletteSettings::AlertPaletteSettings(awips::Phenomenon phenomenon) : + SettingsCategory(awips::GetPhenomenonCode(phenomenon)), + p(std::make_unique(phenomenon)) +{ + auto& info = awips::ibw::GetImpactBasedWarningInfo(p->phenomenon_); + for (auto& threatCategory : p->threatCategoryMap_) + { + RegisterSubcategory(threatCategory.second); + } + + if (info.hasObservedTag_) + { + RegisterSubcategory(p->observed_); + } + + if (info.hasTornadoPossibleTag_) + { + RegisterSubcategory(p->tornadoPossible_); + } + + RegisterSubcategory(p->inactive_); + + SetDefaults(); +} +AlertPaletteSettings::~AlertPaletteSettings() = default; + +AlertPaletteSettings::AlertPaletteSettings(AlertPaletteSettings&&) noexcept = + default; +AlertPaletteSettings& +AlertPaletteSettings::operator=(AlertPaletteSettings&&) noexcept = default; + +LineSettings& AlertPaletteSettings::threat_category( + awips::ibw::ThreatCategory threatCategory) const +{ + auto it = p->threatCategoryMap_.find(threatCategory); + if (it != p->threatCategoryMap_.cend()) + { + return it->second; + } + return p->threatCategoryMap_.at(awips::ibw::ThreatCategory::Base); +} + +LineSettings& AlertPaletteSettings::inactive() const +{ + return p->inactive_; +} + +LineSettings& AlertPaletteSettings::observed() const +{ + return p->observed_; +} + +LineSettings& AlertPaletteSettings::tornado_possible() const +{ + return p->tornadoPossible_; +} + +bool operator==(const AlertPaletteSettings& lhs, + const AlertPaletteSettings& rhs) +{ + return (lhs.p->threatCategoryMap_ == rhs.p->threatCategoryMap_ && + lhs.p->inactive_ == rhs.p->inactive_ && + lhs.p->observed_ == rhs.p->observed_ && + lhs.p->tornadoPossible_ == rhs.p->tornadoPossible_); +} + +} // namespace settings +} // namespace qt +} // namespace scwx diff --git a/scwx-qt/source/scwx/qt/settings/alert_palette_settings.hpp b/scwx-qt/source/scwx/qt/settings/alert_palette_settings.hpp new file mode 100644 index 00000000..152a6351 --- /dev/null +++ b/scwx-qt/source/scwx/qt/settings/alert_palette_settings.hpp @@ -0,0 +1,46 @@ +#pragma once + +#include +#include +#include +#include + +#include +#include + +namespace scwx +{ +namespace qt +{ +namespace settings +{ + +class AlertPaletteSettings : public SettingsCategory +{ +public: + explicit AlertPaletteSettings(awips::Phenomenon phenomenon); + ~AlertPaletteSettings(); + + AlertPaletteSettings(const AlertPaletteSettings&) = delete; + AlertPaletteSettings& operator=(const AlertPaletteSettings&) = delete; + + AlertPaletteSettings(AlertPaletteSettings&&) noexcept; + AlertPaletteSettings& operator=(AlertPaletteSettings&&) noexcept; + + LineSettings& + threat_category(awips::ibw::ThreatCategory threatCategory) const; + LineSettings& inactive() const; + LineSettings& observed() const; + LineSettings& tornado_possible() const; + + friend bool operator==(const AlertPaletteSettings& lhs, + const AlertPaletteSettings& rhs); + +private: + class Impl; + std::unique_ptr p; +}; + +} // namespace settings +} // namespace qt +} // namespace scwx From 47b7d475c8d9d068e06f07fb4171704e5f95c5d9 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sat, 21 Sep 2024 08:30:17 -0500 Subject: [PATCH 17/36] Use new alert palette settings in parent palette settings --- .../scwx/qt/settings/palette_settings.cpp | 75 ++++--------------- .../scwx/qt/settings/palette_settings.hpp | 2 + 2 files changed, 17 insertions(+), 60 deletions(-) diff --git a/scwx-qt/source/scwx/qt/settings/palette_settings.cpp b/scwx-qt/source/scwx/qt/settings/palette_settings.cpp index 12e3fe99..c5902fb3 100644 --- a/scwx-qt/source/scwx/qt/settings/palette_settings.cpp +++ b/scwx-qt/source/scwx/qt/settings/palette_settings.cpp @@ -76,32 +76,6 @@ static const awips::Phenomenon kDefaultPhenomenon_ {awips::Phenomenon::Marine}; class PaletteSettings::Impl { public: - struct AlertData - { - AlertData(awips::Phenomenon phenomenon) : phenomenon_ {phenomenon} - { - auto& info = awips::ibw::GetImpactBasedWarningInfo(phenomenon); - for (auto& threatCategory : info.threatCategories_) - { - std::string threatCategoryName = - awips::ibw::GetThreatCategoryName(threatCategory); - boost::algorithm::to_lower(threatCategoryName); - threatCategoryMap_.emplace(threatCategory, threatCategoryName); - } - } - - void RegisterVariables(SettingsCategory& settings); - - awips::Phenomenon phenomenon_; - - std::map> - threatCategoryMap_ {}; - - SettingsVariable observed_ {"observed"}; - SettingsVariable tornadoPossible_ {"tornado_possible"}; - SettingsVariable inactive_ {"inactive"}; - }; - explicit Impl(PaletteSettings* self) : self_ {self} { InitializeColorTables(); @@ -124,9 +98,8 @@ public: inactiveAlertColor_ {}; std::vector variables_ {}; - std::unordered_map alertDataMap_ {}; - - std::vector alertSettings_ {}; + std::unordered_map + alertPaletteMap_ {}; }; PaletteSettings::PaletteSettings() : @@ -197,43 +170,19 @@ void PaletteSettings::Impl::InitializeLegacyAlerts() void PaletteSettings::Impl::InitializeAlerts() { + std::vector alertSettings {}; + for (auto phenomenon : PaletteSettings::alert_phenomena()) { - auto pair = alertDataMap_.emplace( - std::make_pair(phenomenon, AlertData {phenomenon})); - auto& alertData = pair.first->second; + auto result = alertPaletteMap_.emplace(phenomenon, phenomenon); + auto& it = result.first; + AlertPaletteSettings& alertPaletteSettings = it->second; // Variable registration - auto& settings = alertSettings_.emplace_back( - SettingsCategory {awips::GetPhenomenonCode(phenomenon)}); - - alertData.RegisterVariables(settings); + alertSettings.push_back(&alertPaletteSettings); } - self_->RegisterSubcategoryArray("alerts", alertSettings_); -} - -void PaletteSettings::Impl::AlertData::RegisterVariables( - SettingsCategory& settings) -{ - auto& info = awips::ibw::GetImpactBasedWarningInfo(phenomenon_); - - for (auto& threatCategory : threatCategoryMap_) - { - settings.RegisterVariables({&threatCategory.second}); - } - - if (info.hasObservedTag_) - { - settings.RegisterVariables({&observed_}); - } - - if (info.hasTornadoPossibleTag_) - { - settings.RegisterVariables({&tornadoPossible_}); - } - - settings.RegisterVariables({&inactive_}); + self_->RegisterSubcategoryArray("alerts", alertSettings); } SettingsVariable& @@ -272,6 +221,12 @@ PaletteSettings::alert_color(awips::Phenomenon phenomenon, bool active) const } } +AlertPaletteSettings& +PaletteSettings::alert_palette(awips::Phenomenon phenomenon) +{ + return p->alertPaletteMap_.at(phenomenon); +} + const std::vector& PaletteSettings::alert_phenomena() { static const std::vector kAlertPhenomena_ { diff --git a/scwx-qt/source/scwx/qt/settings/palette_settings.hpp b/scwx-qt/source/scwx/qt/settings/palette_settings.hpp index bf21e119..eb52e600 100644 --- a/scwx-qt/source/scwx/qt/settings/palette_settings.hpp +++ b/scwx-qt/source/scwx/qt/settings/palette_settings.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -30,6 +31,7 @@ public: SettingsVariable& palette(const std::string& name) const; SettingsVariable& alert_color(awips::Phenomenon phenomenon, bool active) const; + AlertPaletteSettings& alert_palette(awips::Phenomenon); static const std::vector& alert_phenomena(); From 9f4a798d673d2026f4d82dabebdf88949d864d0c Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sat, 21 Sep 2024 17:15:22 -0500 Subject: [PATCH 18/36] Read and write settings subcategories --- scwx-qt/source/scwx/qt/settings/settings_category.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/scwx-qt/source/scwx/qt/settings/settings_category.cpp b/scwx-qt/source/scwx/qt/settings/settings_category.cpp index a346c50d..2258baeb 100644 --- a/scwx-qt/source/scwx/qt/settings/settings_category.cpp +++ b/scwx-qt/source/scwx/qt/settings/settings_category.cpp @@ -121,9 +121,7 @@ bool SettingsCategory::ReadJson(const boost::json::object& json) // Read subcategories for (auto& subcategory : p->subcategories_) { - (void) subcategory; - // TODO: - // subcategory->ReadJson(object); + validated &= subcategory->ReadJson(object); } // Read variables @@ -172,9 +170,7 @@ void SettingsCategory::WriteJson(boost::json::object& json) const // Write subcategories for (auto& subcategory : p->subcategories_) { - (void) subcategory; - // TODO: - // subcategory->WriteJson(); + subcategory->WriteJson(object); } // Write variables From 8212d24d345200b6576277aa1862f4ea8fe49588 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sat, 21 Sep 2024 23:11:26 -0500 Subject: [PATCH 19/36] Connect line label to alert palette settings - Line label will initialize to settings value - Changes to the line label will stage settings --- scwx-qt/source/scwx/qt/ui/line_label.cpp | 66 ++++++++++++++++++- scwx-qt/source/scwx/qt/ui/line_label.hpp | 4 ++ .../alert_palette_settings_widget.cpp | 36 +++++++--- 3 files changed, 96 insertions(+), 10 deletions(-) diff --git a/scwx-qt/source/scwx/qt/ui/line_label.cpp b/scwx-qt/source/scwx/qt/ui/line_label.cpp index 5248057c..a8be0507 100644 --- a/scwx-qt/source/scwx/qt/ui/line_label.cpp +++ b/scwx-qt/source/scwx/qt/ui/line_label.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -20,6 +21,8 @@ public: explicit Impl() {}; ~Impl() = default; + void ResetLineSettings(); + QImage GenerateImage() const; std::size_t borderWidth_ {1}; @@ -30,6 +33,8 @@ public: boost::gil::rgba8_pixel_t highlightColor_ {255, 255, 0, 255}; boost::gil::rgba8_pixel_t lineColor_ {0, 0, 255, 255}; + settings::LineSettings* lineSettings_ {nullptr}; + QPixmap pixmap_ {}; bool pixmapDirty_ {true}; }; @@ -39,7 +44,15 @@ LineLabel::LineLabel(QWidget* parent) : { } -LineLabel::~LineLabel() {} +LineLabel::~LineLabel() +{ + p->ResetLineSettings(); +} + +void LineLabel::Impl::ResetLineSettings() +{ + lineSettings_ = nullptr; +} boost::gil::rgba8_pixel_t LineLabel::border_color() const { @@ -77,6 +90,11 @@ void LineLabel::set_border_width(std::size_t width) p->pixmapDirty_ = true; updateGeometry(); update(); + + if (p->lineSettings_ != nullptr) + { + p->lineSettings_->border_width().StageValue(width); + } } void LineLabel::set_highlight_width(std::size_t width) @@ -85,6 +103,11 @@ void LineLabel::set_highlight_width(std::size_t width) p->pixmapDirty_ = true; updateGeometry(); update(); + + if (p->lineSettings_ != nullptr) + { + p->lineSettings_->highlight_width().StageValue(width); + } } void LineLabel::set_line_width(std::size_t width) @@ -93,6 +116,11 @@ void LineLabel::set_line_width(std::size_t width) p->pixmapDirty_ = true; updateGeometry(); update(); + + if (p->lineSettings_ != nullptr) + { + p->lineSettings_->line_width().StageValue(width); + } } void LineLabel::set_border_color(boost::gil::rgba8_pixel_t color) @@ -100,6 +128,12 @@ void LineLabel::set_border_color(boost::gil::rgba8_pixel_t color) p->borderColor_ = color; p->pixmapDirty_ = true; update(); + + if (p->lineSettings_ != nullptr) + { + p->lineSettings_->border_color().StageValue( + util::color::ToArgbString(color)); + } } void LineLabel::set_highlight_color(boost::gil::rgba8_pixel_t color) @@ -107,6 +141,12 @@ void LineLabel::set_highlight_color(boost::gil::rgba8_pixel_t color) p->highlightColor_ = color; p->pixmapDirty_ = true; update(); + + if (p->lineSettings_ != nullptr) + { + p->lineSettings_->highlight_color().StageValue( + util::color::ToArgbString(color)); + } } void LineLabel::set_line_color(boost::gil::rgba8_pixel_t color) @@ -114,6 +154,30 @@ void LineLabel::set_line_color(boost::gil::rgba8_pixel_t color) p->lineColor_ = color; p->pixmapDirty_ = true; update(); + + if (p->lineSettings_ != nullptr) + { + p->lineSettings_->line_color().StageValue( + util::color::ToArgbString(color)); + } +} + +void LineLabel::set_line_settings(settings::LineSettings& lineSettings) +{ + p->ResetLineSettings(); + + set_border_color(util::color::ToRgba8PixelT( + lineSettings.border_color().GetStagedOrValue())); + set_highlight_color(util::color::ToRgba8PixelT( + lineSettings.highlight_color().GetStagedOrValue())); + set_line_color( + util::color::ToRgba8PixelT(lineSettings.line_color().GetStagedOrValue())); + + set_border_width(lineSettings.border_width().GetStagedOrValue()); + set_highlight_width(lineSettings.highlight_width().GetStagedOrValue()); + set_line_width(lineSettings.line_width().GetStagedOrValue()); + + p->lineSettings_ = &lineSettings; } QSize LineLabel::minimumSizeHint() const diff --git a/scwx-qt/source/scwx/qt/ui/line_label.hpp b/scwx-qt/source/scwx/qt/ui/line_label.hpp index 2c2d516b..b746a98e 100644 --- a/scwx-qt/source/scwx/qt/ui/line_label.hpp +++ b/scwx-qt/source/scwx/qt/ui/line_label.hpp @@ -1,5 +1,7 @@ #pragma once +#include + #include #include @@ -36,6 +38,8 @@ public: void set_highlight_width(std::size_t width); void set_line_width(std::size_t width); + void set_line_settings(settings::LineSettings& lineSettings); + protected: QSize minimumSizeHint() const override; QSize sizeHint() const override; diff --git a/scwx-qt/source/scwx/qt/ui/settings/alert_palette_settings_widget.cpp b/scwx-qt/source/scwx/qt/ui/settings/alert_palette_settings_widget.cpp index 0eb49807..0a63add4 100644 --- a/scwx-qt/source/scwx/qt/ui/settings/alert_palette_settings_widget.cpp +++ b/scwx-qt/source/scwx/qt/ui/settings/alert_palette_settings_widget.cpp @@ -37,8 +37,10 @@ public: } ~Impl() = default; - void - AddPhenomenonLine(const std::string& name, QGridLayout* layout, int row); + void AddPhenomenonLine(const std::string& name, + settings::LineSettings& lineSettings, + QGridLayout* layout, + int row); QWidget* CreateStackedWidgetPage(awips::Phenomenon phenomenon); void ConnectSignals(); void SelectPhenomenon(awips::Phenomenon phenomenon); @@ -181,21 +183,31 @@ QWidget* AlertPaletteSettingsWidget::Impl::CreateStackedWidgetPage( const auto& impactBasedWarningInfo = awips::ibw::GetImpactBasedWarningInfo(phenomenon); + auto& alertPalette = + settings::PaletteSettings::Instance().alert_palette(phenomenon); + int row = 0; // Add a blank label to align left and right widgets gridLayout->addWidget(new QLabel(self_), row++, 0); - AddPhenomenonLine("Active", gridLayout, row++); + AddPhenomenonLine( + "Active", + alertPalette.threat_category(awips::ibw::ThreatCategory::Base), + gridLayout, + row++); if (impactBasedWarningInfo.hasObservedTag_) { - AddPhenomenonLine("Observed", gridLayout, row++); + AddPhenomenonLine("Observed", alertPalette.observed(), gridLayout, row++); } if (impactBasedWarningInfo.hasTornadoPossibleTag_) { - AddPhenomenonLine("Tornado Possible", gridLayout, row++); + AddPhenomenonLine("Tornado Possible", + alertPalette.tornado_possible(), + gridLayout, + row++); } for (auto& category : impactBasedWarningInfo.threatCategories_) @@ -205,11 +217,13 @@ QWidget* AlertPaletteSettingsWidget::Impl::CreateStackedWidgetPage( continue; } - AddPhenomenonLine( - awips::ibw::GetThreatCategoryName(category), gridLayout, row++); + AddPhenomenonLine(awips::ibw::GetThreatCategoryName(category), + alertPalette.threat_category(category), + gridLayout, + row++); } - AddPhenomenonLine("Inactive", gridLayout, row++); + AddPhenomenonLine("Inactive", alertPalette.inactive(), gridLayout, row++); QSpacerItem* spacer = new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding); @@ -219,12 +233,16 @@ QWidget* AlertPaletteSettingsWidget::Impl::CreateStackedWidgetPage( } void AlertPaletteSettingsWidget::Impl::AddPhenomenonLine( - const std::string& name, QGridLayout* layout, int row) + const std::string& name, + settings::LineSettings& lineSettings, + QGridLayout* layout, + int row) { QToolButton* toolButton = new QToolButton(self_); toolButton->setText(tr("...")); LineLabel* lineLabel = new LineLabel(self_); + lineLabel->set_line_settings(lineSettings); layout->addWidget(new QLabel(tr(name.c_str()), self_), row, 0); layout->addWidget(lineLabel, row, 1); From 6b0aaea7738588a303357c94d54c78f29ba339f1 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sat, 21 Sep 2024 23:31:47 -0500 Subject: [PATCH 20/36] Commit line settings changes on apply --- .../scwx/qt/settings/settings_category.cpp | 28 +++++++++++++++++++ .../scwx/qt/settings/settings_category.hpp | 9 ++++++ .../alert_palette_settings_widget.cpp | 2 ++ .../qt/ui/settings/settings_page_widget.cpp | 12 ++++++++ .../qt/ui/settings/settings_page_widget.hpp | 2 ++ 5 files changed, 53 insertions(+) diff --git a/scwx-qt/source/scwx/qt/settings/settings_category.cpp b/scwx-qt/source/scwx/qt/settings/settings_category.cpp index 2258baeb..34859ae2 100644 --- a/scwx-qt/source/scwx/qt/settings/settings_category.cpp +++ b/scwx-qt/source/scwx/qt/settings/settings_category.cpp @@ -68,6 +68,34 @@ void SettingsCategory::SetDefaults() } } +bool SettingsCategory::Commit() +{ + bool committed = false; + + // Commit subcategory arrays + for (auto& subcategoryArray : p->subcategoryArrays_) + { + for (auto& subcategory : subcategoryArray.second) + { + committed |= subcategory->Commit(); + } + } + + // Commit subcategories + for (auto& subcategory : p->subcategories_) + { + committed |= subcategory->Commit(); + } + + // Commit variables + for (auto& variable : p->variables_) + { + committed |= variable->Commit(); + } + + return committed; +} + bool SettingsCategory::ReadJson(const boost::json::object& json) { bool validated = true; diff --git a/scwx-qt/source/scwx/qt/settings/settings_category.hpp b/scwx-qt/source/scwx/qt/settings/settings_category.hpp index bea48659..9ccf7458 100644 --- a/scwx-qt/source/scwx/qt/settings/settings_category.hpp +++ b/scwx-qt/source/scwx/qt/settings/settings_category.hpp @@ -33,6 +33,15 @@ public: */ void SetDefaults(); + /** + * Sets the current value of all variables to the staged + * value. + * + * @return true if any staged value was committed, false if no staged values + * are present. + */ + bool Commit(); + /** * Reads the variables from the JSON object. * diff --git a/scwx-qt/source/scwx/qt/ui/settings/alert_palette_settings_widget.cpp b/scwx-qt/source/scwx/qt/ui/settings/alert_palette_settings_widget.cpp index 0a63add4..2de6f283 100644 --- a/scwx-qt/source/scwx/qt/ui/settings/alert_palette_settings_widget.cpp +++ b/scwx-qt/source/scwx/qt/ui/settings/alert_palette_settings_widget.cpp @@ -248,6 +248,8 @@ void AlertPaletteSettingsWidget::Impl::AddPhenomenonLine( layout->addWidget(lineLabel, row, 1); layout->addWidget(toolButton, row, 2); + self_->AddSettingsCategory(&lineSettings); + connect( toolButton, &QAbstractButton::clicked, diff --git a/scwx-qt/source/scwx/qt/ui/settings/settings_page_widget.cpp b/scwx-qt/source/scwx/qt/ui/settings/settings_page_widget.cpp index d174fbbd..a7c77380 100644 --- a/scwx-qt/source/scwx/qt/ui/settings/settings_page_widget.cpp +++ b/scwx-qt/source/scwx/qt/ui/settings/settings_page_widget.cpp @@ -19,6 +19,7 @@ public: explicit Impl() {} ~Impl() = default; + std::vector categories_; std::vector settings_; }; @@ -29,6 +30,12 @@ SettingsPageWidget::SettingsPageWidget(QWidget* parent) : SettingsPageWidget::~SettingsPageWidget() = default; +void SettingsPageWidget::AddSettingsCategory( + settings::SettingsCategory* category) +{ + p->categories_.push_back(category); +} + void SettingsPageWidget::AddSettingsInterface( settings::SettingsInterfaceBase* setting) { @@ -39,6 +46,11 @@ bool SettingsPageWidget::CommitChanges() { bool committed = false; + for (auto& category : p->categories_) + { + committed |= category->Commit(); + } + for (auto& setting : p->settings_) { committed |= setting->Commit(); diff --git a/scwx-qt/source/scwx/qt/ui/settings/settings_page_widget.hpp b/scwx-qt/source/scwx/qt/ui/settings/settings_page_widget.hpp index 228badd6..2fbdfc9e 100644 --- a/scwx-qt/source/scwx/qt/ui/settings/settings_page_widget.hpp +++ b/scwx-qt/source/scwx/qt/ui/settings/settings_page_widget.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -59,6 +60,7 @@ public: void ResetToDefault(); protected: + void AddSettingsCategory(settings::SettingsCategory* category); void AddSettingsInterface(settings::SettingsInterfaceBase* setting); private: From 928b3397d2b6630644260069670675162cbae1bf Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sat, 21 Sep 2024 23:39:32 -0500 Subject: [PATCH 21/36] Add alert palette settings widget to settings dialog --- scwx-qt/source/scwx/qt/ui/settings_dialog.cpp | 11 +++++++++++ scwx-qt/source/scwx/qt/ui/settings_dialog.ui | 17 +++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/scwx-qt/source/scwx/qt/ui/settings_dialog.cpp b/scwx-qt/source/scwx/qt/ui/settings_dialog.cpp index cd72b4ee..dde77454 100644 --- a/scwx-qt/source/scwx/qt/ui/settings_dialog.cpp +++ b/scwx-qt/source/scwx/qt/ui/settings_dialog.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -224,6 +225,7 @@ public: manager::PositionManager::Instance()}; std::vector settingsPages_ {}; + AlertPaletteSettingsWidget* alertPaletteSettingsWidget_ {}; HotkeySettingsWidget* hotkeySettingsWidget_ {}; UnitSettingsWidget* unitSettingsWidget_ {}; @@ -807,6 +809,15 @@ void SettingsDialogImpl::SetupPalettesAlertsTab() settings::PaletteSettings::Instance(); // Palettes > Alerts + QVBoxLayout* layout = new QVBoxLayout(self_->ui->alertsPalette); + + alertPaletteSettingsWidget_ = + new AlertPaletteSettingsWidget(self_->ui->hotkeys); + layout->addWidget(alertPaletteSettingsWidget_); + + settingsPages_.push_back(alertPaletteSettingsWidget_); + + // Palettes > Old Alerts QGridLayout* alertsLayout = reinterpret_cast(self_->ui->alertsFrame->layout()); diff --git a/scwx-qt/source/scwx/qt/ui/settings_dialog.ui b/scwx-qt/source/scwx/qt/ui/settings_dialog.ui index 88dacbbc..0237462a 100644 --- a/scwx-qt/source/scwx/qt/ui/settings_dialog.ui +++ b/scwx-qt/source/scwx/qt/ui/settings_dialog.ui @@ -122,7 +122,7 @@ - 3 + 0 @@ -136,8 +136,8 @@ 0 0 - 274 - 691 + 513 + 622 @@ -610,8 +610,8 @@ 0 0 - 98 - 28 + 506 + 383 @@ -634,10 +634,15 @@ - + Alerts + + + + Old Alerts + From 6063de2095252ca4000c02142afab2042baf1802 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sat, 21 Sep 2024 23:39:51 -0500 Subject: [PATCH 22/36] Settings dialog formatting --- scwx-qt/source/scwx/qt/ui/settings_dialog.cpp | 71 ++++++++----------- 1 file changed, 28 insertions(+), 43 deletions(-) diff --git a/scwx-qt/source/scwx/qt/ui/settings_dialog.cpp b/scwx-qt/source/scwx/qt/ui/settings_dialog.cpp index dde77454..f7e22c09 100644 --- a/scwx-qt/source/scwx/qt/ui/settings_dialog.cpp +++ b/scwx-qt/source/scwx/qt/ui/settings_dialog.cpp @@ -23,12 +23,12 @@ #include #include #include -#include #include #include #include #include #include +#include #include #include #include @@ -360,24 +360,23 @@ void SettingsDialogImpl::ConnectSignals() self_, [this]() { alertAudioRadarSiteDialog_->show(); }); - QObject::connect(alertAudioRadarSiteDialog_, - &RadarSiteDialog::accepted, - self_, - [this]() - { - std::string id = - alertAudioRadarSiteDialog_->radar_site(); + QObject::connect( + alertAudioRadarSiteDialog_, + &RadarSiteDialog::accepted, + self_, + [this]() + { + std::string id = alertAudioRadarSiteDialog_->radar_site(); - std::shared_ptr radarSite = - config::RadarSite::Get(id); + std::shared_ptr radarSite = + config::RadarSite::Get(id); - if (radarSite != nullptr) - { - self_->ui->alertAudioRadarSiteComboBox - ->setCurrentText(QString::fromStdString( - RadarSiteLabel(radarSite))); - } - }); + if (radarSite != nullptr) + { + self_->ui->alertAudioRadarSiteComboBox->setCurrentText( + QString::fromStdString(RadarSiteLabel(radarSite))); + } + }); QObject::connect(self_->ui->gpsSourceSelectButton, &QAbstractButton::clicked, @@ -923,13 +922,11 @@ void SettingsDialogImpl::SetupPalettesAlertsTab() QObject::connect(activeButton, &QAbstractButton::clicked, self_, - [=, this]() - { ShowColorDialog(activeEdit); }); + [=, this]() { ShowColorDialog(activeEdit); }); QObject::connect(inactiveButton, &QAbstractButton::clicked, self_, - [=, this]() - { ShowColorDialog(inactiveEdit); }); + [=, this]() { ShowColorDialog(inactiveEdit); }); } } @@ -964,8 +961,7 @@ void SettingsDialogImpl::SetupAudioTab() locationMethod == types::LocationMethod::RadarSite; bool countyEntryEnabled = locationMethod == types::LocationMethod::County; - bool wfoEntryEnabled = - locationMethod == types::LocationMethod::WFO; + bool wfoEntryEnabled = locationMethod == types::LocationMethod::WFO; self_->ui->alertAudioLatitudeSpinBox->setEnabled( coordinateEntryEnabled); @@ -983,10 +979,8 @@ void SettingsDialogImpl::SetupAudioTab() self_->ui->resetAlertAudioRadarSiteButton->setEnabled( radarSiteEntryEnable); - self_->ui->alertAudioRadiusSpinBox->setEnabled( - radiusEntryEnable); - self_->ui->resetAlertAudioRadiusButton->setEnabled( - radiusEntryEnable); + self_->ui->alertAudioRadiusSpinBox->setEnabled(radiusEntryEnable); + self_->ui->resetAlertAudioRadiusButton->setEnabled(radiusEntryEnable); self_->ui->alertAudioCountyLineEdit->setEnabled(countyEntryEnabled); self_->ui->alertAudioCountySelectButton->setEnabled( @@ -1102,8 +1096,7 @@ void SettingsDialogImpl::SetupAudioTab() alertAudioRadius_.SetSettingsVariable(audioSettings.alert_radius()); alertAudioRadius_.SetEditWidget(self_->ui->alertAudioRadiusSpinBox); - alertAudioRadius_.SetResetButton( - self_->ui->resetAlertAudioRadiusButton); + alertAudioRadius_.SetResetButton(self_->ui->resetAlertAudioRadiusButton); alertAudioRadius_.SetUnitLabel(self_->ui->alertAudioRadiusUnitsLabel); auto alertAudioRadiusUpdateUnits = [this](const std::string& newValue) { @@ -1217,14 +1210,10 @@ void SettingsDialogImpl::SetupAudioTab() alertAudioCounty_.SetEditWidget(self_->ui->alertAudioCountyLineEdit); alertAudioCounty_.SetResetButton(self_->ui->resetAlertAudioCountyButton); - QObject::connect( - self_->ui->alertAudioWFOSelectButton, - &QAbstractButton::clicked, - self_, - [this]() - { - wfoDialog_->show(); - }); + QObject::connect(self_->ui->alertAudioWFOSelectButton, + &QAbstractButton::clicked, + self_, + [this]() { wfoDialog_->show(); }); QObject::connect(wfoDialog_, &WFODialog::accepted, self_, @@ -1243,9 +1232,8 @@ void SettingsDialogImpl::SetupAudioTab() self_, [this](const QString& text) { - std::string wfoName = - config::CountyDatabase::GetWFOName( - text.toStdString()); + std::string wfoName = config::CountyDatabase::GetWFOName( + text.toStdString()); self_->ui->alertAudioWFOLabel->setText( QString::fromStdString(wfoName)); }); @@ -1253,7 +1241,6 @@ void SettingsDialogImpl::SetupAudioTab() alertAudioWFO_.SetSettingsVariable(audioSettings.alert_wfo()); alertAudioWFO_.SetEditWidget(self_->ui->alertAudioWFOLineEdit); alertAudioWFO_.SetResetButton(self_->ui->resetAlertAudioWFOButton); - } void SettingsDialogImpl::SetupTextTab() @@ -1455,8 +1442,6 @@ void SettingsDialogImpl::UpdateAlertRadarDialogLocation(const std::string& id) } } - - QFont SettingsDialogImpl::GetSelectedFont() { std::string fontFamily = fontFamilies_.at(selectedFontCategory_) From 76809de2df678ca713d03d6574d6578f4e6de768 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sun, 22 Sep 2024 09:54:32 -0500 Subject: [PATCH 23/36] Implement discard functionality for line settings --- .../scwx/qt/settings/settings_category.cpp | 36 +++++++++++++++++++ .../scwx/qt/settings/settings_category.hpp | 17 +++++++-- .../scwx/qt/settings/settings_variable.hpp | 4 +-- .../qt/settings/settings_variable_base.hpp | 7 +++- .../alert_palette_settings_widget.cpp | 17 ++++++++- .../qt/ui/settings/settings_page_widget.cpp | 5 +++ .../qt/ui/settings/settings_page_widget.hpp | 10 +++++- 7 files changed, 89 insertions(+), 7 deletions(-) diff --git a/scwx-qt/source/scwx/qt/settings/settings_category.cpp b/scwx-qt/source/scwx/qt/settings/settings_category.cpp index 34859ae2..29b3a022 100644 --- a/scwx-qt/source/scwx/qt/settings/settings_category.cpp +++ b/scwx-qt/source/scwx/qt/settings/settings_category.cpp @@ -4,6 +4,8 @@ #include +#include + namespace scwx { namespace qt @@ -27,6 +29,8 @@ public: subcategoryArrays_; std::vector subcategories_; std::vector variables_; + + boost::signals2::signal resetSignal_; }; SettingsCategory::SettingsCategory(const std::string& name) : @@ -96,6 +100,32 @@ bool SettingsCategory::Commit() return committed; } +void SettingsCategory::Reset() +{ + // Reset subcategory arrays + for (auto& subcategoryArray : p->subcategoryArrays_) + { + for (auto& subcategory : subcategoryArray.second) + { + subcategory->Reset(); + } + } + + // Reset subcategories + for (auto& subcategory : p->subcategories_) + { + subcategory->Reset(); + } + + // Reset variables + for (auto& variable : p->variables_) + { + variable->Reset(); + } + + p->resetSignal_(); +} + bool SettingsCategory::ReadJson(const boost::json::object& json) { bool validated = true; @@ -252,6 +282,12 @@ void SettingsCategory::RegisterVariables( p->variables_.end(), variables.cbegin(), variables.cend()); } +boost::signals2::connection +SettingsCategory::RegisterResetCallback(std::function callback) +{ + return p->resetSignal_.connect(callback); +} + } // namespace settings } // namespace qt } // namespace scwx diff --git a/scwx-qt/source/scwx/qt/settings/settings_category.hpp b/scwx-qt/source/scwx/qt/settings/settings_category.hpp index 9ccf7458..9b5613be 100644 --- a/scwx-qt/source/scwx/qt/settings/settings_category.hpp +++ b/scwx-qt/source/scwx/qt/settings/settings_category.hpp @@ -6,6 +6,7 @@ #include #include +#include namespace scwx { @@ -34,14 +35,18 @@ public: void SetDefaults(); /** - * Sets the current value of all variables to the staged - * value. + * Sets the current value of all variables to the staged value. * * @return true if any staged value was committed, false if no staged values * are present. */ bool Commit(); + /** + * Clears the staged value of all variables. + */ + void Reset(); + /** * Reads the variables from the JSON object. * @@ -68,6 +73,14 @@ public: RegisterVariables(std::initializer_list variables); void RegisterVariables(std::vector variables); + /** + * Registers a function to be called when the category is reset. + * + * @param callback Function to be called + */ + boost::signals2::connection + RegisterResetCallback(std::function callback); + private: class Impl; std::unique_ptr p; diff --git a/scwx-qt/source/scwx/qt/settings/settings_variable.hpp b/scwx-qt/source/scwx/qt/settings/settings_variable.hpp index 72d61dde..d2e6c949 100644 --- a/scwx-qt/source/scwx/qt/settings/settings_variable.hpp +++ b/scwx-qt/source/scwx/qt/settings/settings_variable.hpp @@ -29,7 +29,7 @@ public: typedef std::function ValueCallbackFunction; explicit SettingsVariable(const std::string& name); - ~SettingsVariable(); + virtual ~SettingsVariable(); SettingsVariable(const SettingsVariable&) = delete; SettingsVariable& operator=(const SettingsVariable&) = delete; @@ -96,7 +96,7 @@ public: /** * Clears the staged value of the settings variable. */ - void Reset(); + void Reset() override; /** * Gets the staged value of the settings variable, if defined. diff --git a/scwx-qt/source/scwx/qt/settings/settings_variable_base.hpp b/scwx-qt/source/scwx/qt/settings/settings_variable_base.hpp index f0444f45..d7211197 100644 --- a/scwx-qt/source/scwx/qt/settings/settings_variable_base.hpp +++ b/scwx-qt/source/scwx/qt/settings/settings_variable_base.hpp @@ -19,7 +19,7 @@ class SettingsVariableBase { protected: explicit SettingsVariableBase(const std::string& name); - ~SettingsVariableBase(); + virtual ~SettingsVariableBase(); public: SettingsVariableBase(const SettingsVariableBase&) = delete; @@ -48,6 +48,11 @@ public: */ virtual bool Commit() = 0; + /** + * Clears the staged value of the settings variable. + */ + virtual void Reset() = 0; + /** * Reads the value from the JSON object. If the read value is out of range, * the value is set to the minimum or maximum. If the read value fails diff --git a/scwx-qt/source/scwx/qt/ui/settings/alert_palette_settings_widget.cpp b/scwx-qt/source/scwx/qt/ui/settings/alert_palette_settings_widget.cpp index 2de6f283..8e77bdb6 100644 --- a/scwx-qt/source/scwx/qt/ui/settings/alert_palette_settings_widget.cpp +++ b/scwx-qt/source/scwx/qt/ui/settings/alert_palette_settings_widget.cpp @@ -13,6 +13,8 @@ #include #include +#include + namespace scwx { namespace qt @@ -35,7 +37,13 @@ public: SetupUi(); ConnectSignals(); } - ~Impl() = default; + ~Impl() + { + for (auto& c : bs2Connections_) + { + c.disconnect(); + } + }; void AddPhenomenonLine(const std::string& name, settings::LineSettings& lineSettings, @@ -54,6 +62,8 @@ public: EditLineDialog* editLineDialog_; LineLabel* activeLineLabel_ {nullptr}; + std::vector bs2Connections_ {}; + boost::unordered_flat_map phenomenonPages_ {}; }; @@ -250,6 +260,11 @@ void AlertPaletteSettingsWidget::Impl::AddPhenomenonLine( self_->AddSettingsCategory(&lineSettings); + boost::signals2::connection c = lineSettings.RegisterResetCallback( + [lineLabel, &lineSettings]() + { lineLabel->set_line_settings(lineSettings); }); + bs2Connections_.push_back(c); + connect( toolButton, &QAbstractButton::clicked, diff --git a/scwx-qt/source/scwx/qt/ui/settings/settings_page_widget.cpp b/scwx-qt/source/scwx/qt/ui/settings/settings_page_widget.cpp index a7c77380..41c43817 100644 --- a/scwx-qt/source/scwx/qt/ui/settings/settings_page_widget.cpp +++ b/scwx-qt/source/scwx/qt/ui/settings/settings_page_widget.cpp @@ -61,6 +61,11 @@ bool SettingsPageWidget::CommitChanges() void SettingsPageWidget::DiscardChanges() { + for (auto& category : p->categories_) + { + category->Reset(); + } + for (auto& setting : p->settings_) { setting->Reset(); diff --git a/scwx-qt/source/scwx/qt/ui/settings/settings_page_widget.hpp b/scwx-qt/source/scwx/qt/ui/settings/settings_page_widget.hpp index 2fbdfc9e..39d8647a 100644 --- a/scwx-qt/source/scwx/qt/ui/settings/settings_page_widget.hpp +++ b/scwx-qt/source/scwx/qt/ui/settings/settings_page_widget.hpp @@ -60,9 +60,17 @@ public: void ResetToDefault(); protected: - void AddSettingsCategory(settings::SettingsCategory* category); void AddSettingsInterface(settings::SettingsInterfaceBase* setting); + /** + * Commits and resets all settings within a category upon page commit or + * reset. The use of SettingsInterface is preferred, as it allows the binding + * of widgets to these actions. + * + * @param [in] category Settings category + */ + void AddSettingsCategory(settings::SettingsCategory* category); + private: class Impl; std::shared_ptr p; From 20dbc7f5b759410cc36d4fe9c2a2011e0432d61f Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sun, 22 Sep 2024 22:53:45 -0500 Subject: [PATCH 24/36] Default alert palettes --- .../qt/settings/alert_palette_settings.cpp | 135 +++++++++++++++++- 1 file changed, 132 insertions(+), 3 deletions(-) diff --git a/scwx-qt/source/scwx/qt/settings/alert_palette_settings.cpp b/scwx-qt/source/scwx/qt/settings/alert_palette_settings.cpp index ed82ef7e..96bed7f9 100644 --- a/scwx-qt/source/scwx/qt/settings/alert_palette_settings.cpp +++ b/scwx-qt/source/scwx/qt/settings/alert_palette_settings.cpp @@ -5,6 +5,7 @@ #include #include +#include namespace scwx { @@ -16,22 +17,133 @@ namespace settings static const std::string logPrefix_ = "scwx::qt::settings::alert_palette_settings"; +static const boost::gil::rgba8_pixel_t kColorBlack_ {0, 0, 0, 255}; + +struct LineData +{ + boost::gil::rgba8_pixel_t borderColor_ {kColorBlack_}; + boost::gil::rgba8_pixel_t highlightColor_ {kColorBlack_}; + boost::gil::rgba8_pixel_t lineColor_; + std::int64_t borderWidth_ {1}; + std::int64_t highlightWidth_ {0}; + std::int64_t lineWidth_ {3}; +}; + +typedef boost::unordered_flat_map + ThreatCategoryPalette; + +static const boost::unordered_flat_map + kThreatCategoryPalettes_ // + {{awips::Phenomenon::Marine, + {{awips::ibw::ThreatCategory::Base, {.lineColor_ {255, 127, 0, 255}}}}}, + {awips::Phenomenon::FlashFlood, + {{awips::ibw::ThreatCategory::Base, {.lineColor_ {0, 255, 0, 255}}}, + {awips::ibw::ThreatCategory::Considerable, + {.highlightColor_ {0, 255, 0, 255}, + .lineColor_ {kColorBlack_}, + .highlightWidth_ {1}, + .lineWidth_ {1}}}, + {awips::ibw::ThreatCategory::Catastrophic, + {.highlightColor_ {0, 255, 0, 255}, + .lineColor_ {255, 0, 0, 255}, + .highlightWidth_ {1}, + .lineWidth_ {1}}}}}, + {awips::Phenomenon::SevereThunderstorm, + {{awips::ibw::ThreatCategory::Base, {.lineColor_ {255, 255, 0, 255}}}, + {awips::ibw::ThreatCategory::Considerable, + {.highlightColor_ {255, 255, 0, 255}, + .lineColor_ {255, 0, 0, 255}, + .highlightWidth_ {1}, + .lineWidth_ {1}}}, + {awips::ibw::ThreatCategory::Destructive, + {.highlightColor_ {255, 255, 0, 255}, + .lineColor_ {255, 0, 0, 255}, + .highlightWidth_ {1}, + .lineWidth_ {2}}}}}, + {awips::Phenomenon::SnowSquall, + {{awips::ibw::ThreatCategory::Base, {.lineColor_ {0, 255, 255, 255}}}}}, + {awips::Phenomenon::Tornado, + {{awips::ibw::ThreatCategory::Base, {.lineColor_ {255, 0, 0, 255}}}, + {awips::ibw::ThreatCategory::Considerable, + {.lineColor_ {255, 0, 255, 255}}}, + {awips::ibw::ThreatCategory::Catastrophic, + {.highlightColor_ {255, 0, 255, 255}, + .lineColor_ {kColorBlack_}, + .highlightWidth_ {1}, + .lineWidth_ {1}}}}}}; + +static const boost::unordered_flat_map + kObservedPalettes_ // + {{awips::Phenomenon::Tornado, + {.highlightColor_ {255, 0, 0, 255}, + .lineColor_ {kColorBlack_}, + .highlightWidth_ {1}, + .lineWidth_ {1}}}}; + +static const boost::unordered_flat_map + kTornadoPossiblePalettes_ // + {{awips::Phenomenon::Marine, + {.highlightColor_ {255, 127, 0, 255}, + .lineColor_ {kColorBlack_}, + .highlightWidth_ {1}, + .lineWidth_ {1}}}, + {awips::Phenomenon::SevereThunderstorm, + {.highlightColor_ {255, 255, 0, 255}, + .lineColor_ {kColorBlack_}, + .highlightWidth_ {1}, + .lineWidth_ {1}}}}; + +static const boost::unordered_flat_map + kInactivePalettes_ // + { + {awips::Phenomenon::Marine, {.lineColor_ {127, 63, 0, 255}}}, + {awips::Phenomenon::FlashFlood, {.lineColor_ {0, 127, 0, 255}}}, + {awips::Phenomenon::SevereThunderstorm, {.lineColor_ {127, 127, 0, 255}}}, + {awips::Phenomenon::SnowSquall, {.lineColor_ {0, 127, 127, 255}}}, + {awips::Phenomenon::Tornado, {.lineColor_ {127, 0, 0, 255}}}, + }; + class AlertPaletteSettings::Impl { public: explicit Impl(awips::Phenomenon phenomenon) : phenomenon_ {phenomenon} { - auto& info = awips::ibw::GetImpactBasedWarningInfo(phenomenon); + const auto& info = awips::ibw::GetImpactBasedWarningInfo(phenomenon); + + const auto& threatCategoryPalettes = + kThreatCategoryPalettes_.at(phenomenon); + for (auto& threatCategory : info.threatCategories_) { std::string threatCategoryName = awips::ibw::GetThreatCategoryName(threatCategory); boost::algorithm::to_lower(threatCategoryName); - threatCategoryMap_.emplace(threatCategory, threatCategoryName); + auto result = + threatCategoryMap_.emplace(threatCategory, threatCategoryName); + auto& lineSettings = result.first->second; + + SetDefaultLineData(lineSettings, + threatCategoryPalettes.at(threatCategory)); } + + if (info.hasObservedTag_) + { + SetDefaultLineData(observed_, kObservedPalettes_.at(phenomenon)); + } + + if (info.hasTornadoPossibleTag_) + { + SetDefaultLineData(tornadoPossible_, + kTornadoPossiblePalettes_.at(phenomenon)); + } + + SetDefaultLineData(inactive_, kInactivePalettes_.at(phenomenon)); } ~Impl() {} + static void SetDefaultLineData(LineSettings& lineSettings, + const LineData& lineData); + awips::Phenomenon phenomenon_; std::map threatCategoryMap_ {}; @@ -65,6 +177,7 @@ AlertPaletteSettings::AlertPaletteSettings(awips::Phenomenon phenomenon) : SetDefaults(); } + AlertPaletteSettings::~AlertPaletteSettings() = default; AlertPaletteSettings::AlertPaletteSettings(AlertPaletteSettings&&) noexcept = @@ -98,10 +211,26 @@ LineSettings& AlertPaletteSettings::tornado_possible() const return p->tornadoPossible_; } +void AlertPaletteSettings::Impl::SetDefaultLineData(LineSettings& lineSettings, + const LineData& lineData) +{ + lineSettings.border_color().SetDefault( + util::color::ToArgbString(lineData.borderColor_)); + lineSettings.highlight_color().SetDefault( + util::color::ToArgbString(lineData.highlightColor_)); + lineSettings.line_color().SetDefault( + util::color::ToArgbString(lineData.lineColor_)); + + lineSettings.border_width().SetDefault(lineData.borderWidth_); + lineSettings.highlight_width().SetDefault(lineData.highlightWidth_); + lineSettings.line_width().SetDefault(lineData.lineWidth_); +} + bool operator==(const AlertPaletteSettings& lhs, const AlertPaletteSettings& rhs) { - return (lhs.p->threatCategoryMap_ == rhs.p->threatCategoryMap_ && + return (lhs.p->phenomenon_ == rhs.p->phenomenon_ && + lhs.p->threatCategoryMap_ == rhs.p->threatCategoryMap_ && lhs.p->inactive_ == rhs.p->inactive_ && lhs.p->observed_ == rhs.p->observed_ && lhs.p->tornadoPossible_ == rhs.p->tornadoPossible_); From 70cb3ab6d21f0cbea1be0311577f7e1247872e09 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Thu, 26 Sep 2024 04:41:56 -0500 Subject: [PATCH 25/36] Update settings category signals to be in line with variables and only fire once Properly connect line labels to the category signals --- .../source/scwx/qt/settings/line_settings.cpp | 23 +++- .../source/scwx/qt/settings/line_settings.hpp | 9 ++ .../scwx/qt/settings/settings_category.cpp | 120 ++++++++++++++++-- .../scwx/qt/settings/settings_category.hpp | 25 ++-- .../scwx/qt/settings/settings_variable.cpp | 18 +++ .../qt/settings/settings_variable_base.cpp | 13 ++ .../qt/settings/settings_variable_base.hpp | 15 +++ scwx-qt/source/scwx/qt/ui/line_label.cpp | 80 ++++-------- .../alert_palette_settings_widget.cpp | 66 ++++------ 9 files changed, 252 insertions(+), 117 deletions(-) diff --git a/scwx-qt/source/scwx/qt/settings/line_settings.cpp b/scwx-qt/source/scwx/qt/settings/line_settings.cpp index bc467186..105be812 100644 --- a/scwx-qt/source/scwx/qt/settings/line_settings.cpp +++ b/scwx-qt/source/scwx/qt/settings/line_settings.cpp @@ -1,8 +1,6 @@ #include #include -#include - namespace scwx { namespace qt @@ -106,6 +104,27 @@ SettingsVariable& LineSettings::line_width() const return p->lineWidth_; } +void LineSettings::StageValues(boost::gil::rgba8_pixel_t borderColor, + boost::gil::rgba8_pixel_t highlightColor, + boost::gil::rgba8_pixel_t lineColor, + std::int64_t borderWidth, + std::int64_t highlightWidth, + std::int64_t lineWidth) +{ + set_block_signals(true); + + p->borderColor_.StageValue(util::color::ToArgbString(borderColor)); + p->highlightColor_.StageValue(util::color::ToArgbString(highlightColor)); + p->lineColor_.StageValue(util::color::ToArgbString(lineColor)); + p->borderWidth_.StageValue(borderWidth); + p->highlightWidth_.StageValue(highlightWidth); + p->lineWidth_.StageValue(lineWidth); + + set_block_signals(false); + + staged_signal()(); +} + bool operator==(const LineSettings& lhs, const LineSettings& rhs) { return (lhs.p->borderColor_ == rhs.p->borderColor_ && diff --git a/scwx-qt/source/scwx/qt/settings/line_settings.hpp b/scwx-qt/source/scwx/qt/settings/line_settings.hpp index e99d9b3e..bc9a9cb8 100644 --- a/scwx-qt/source/scwx/qt/settings/line_settings.hpp +++ b/scwx-qt/source/scwx/qt/settings/line_settings.hpp @@ -6,6 +6,8 @@ #include #include +#include + namespace scwx { namespace qt @@ -33,6 +35,13 @@ public: SettingsVariable& highlight_width() const; SettingsVariable& line_width() const; + void StageValues(boost::gil::rgba8_pixel_t borderColor, + boost::gil::rgba8_pixel_t highlightColor, + boost::gil::rgba8_pixel_t lineColor, + std::int64_t borderWidth, + std::int64_t highlightWidth, + std::int64_t lineWidth); + friend bool operator==(const LineSettings& lhs, const LineSettings& rhs); private: diff --git a/scwx-qt/source/scwx/qt/settings/settings_category.cpp b/scwx-qt/source/scwx/qt/settings/settings_category.cpp index 29b3a022..3714c4ca 100644 --- a/scwx-qt/source/scwx/qt/settings/settings_category.cpp +++ b/scwx-qt/source/scwx/qt/settings/settings_category.cpp @@ -4,8 +4,6 @@ #include -#include - namespace scwx { namespace qt @@ -23,6 +21,9 @@ public: ~Impl() {} + void ConnectSubcategory(SettingsCategory& category); + void ConnectVariable(SettingsVariableBase* variable); + const std::string name_; std::vector>> @@ -30,7 +31,11 @@ public: std::vector subcategories_; std::vector variables_; - boost::signals2::signal resetSignal_; + boost::signals2::signal changedSignal_ {}; + boost::signals2::signal stagedSignal_ {}; + bool blockSignals_ {false}; + + std::vector connections_ {}; }; SettingsCategory::SettingsCategory(const std::string& name) : @@ -48,8 +53,27 @@ std::string SettingsCategory::name() const return p->name_; } +boost::signals2::signal& SettingsCategory::changed_signal() +{ + return p->changedSignal_; +} + +boost::signals2::signal& SettingsCategory::staged_signal() +{ + return p->stagedSignal_; +} + +void SettingsCategory::set_block_signals(bool blockSignals) +{ + p->blockSignals_ = blockSignals; +} + void SettingsCategory::SetDefaults() { + // Don't allow individual variables to invoke the signal when operating over + // the entire category + p->blockSignals_ = true; + // Set subcategory array defaults for (auto& subcategoryArray : p->subcategoryArrays_) { @@ -70,12 +94,22 @@ void SettingsCategory::SetDefaults() { variable->SetValueToDefault(); } + + // Unblock signals + p->blockSignals_ = false; + + p->changedSignal_(); + p->stagedSignal_(); } bool SettingsCategory::Commit() { bool committed = false; + // Don't allow individual variables to invoke the signal when operating over + // the entire category + p->blockSignals_ = true; + // Commit subcategory arrays for (auto& subcategoryArray : p->subcategoryArrays_) { @@ -97,11 +131,23 @@ bool SettingsCategory::Commit() committed |= variable->Commit(); } + // Unblock signals + p->blockSignals_ = false; + + if (committed) + { + p->changedSignal_(); + } + return committed; } void SettingsCategory::Reset() { + // Don't allow individual variables to invoke the signal when operating over + // the entire category + p->blockSignals_ = true; + // Reset subcategory arrays for (auto& subcategoryArray : p->subcategoryArrays_) { @@ -123,7 +169,10 @@ void SettingsCategory::Reset() variable->Reset(); } - p->resetSignal_(); + // Unblock signals + p->blockSignals_ = false; + + p->stagedSignal_(); } bool SettingsCategory::ReadJson(const boost::json::object& json) @@ -242,6 +291,7 @@ void SettingsCategory::WriteJson(boost::json::object& json) const void SettingsCategory::RegisterSubcategory(SettingsCategory& subcategory) { + p->ConnectSubcategory(subcategory); p->subcategories_.push_back(&subcategory); } @@ -254,7 +304,11 @@ void SettingsCategory::RegisterSubcategoryArray( std::transform(subcategories.begin(), subcategories.end(), std::back_inserter(newSubcategories.second), - [](SettingsCategory& subcategory) { return &subcategory; }); + [this](SettingsCategory& subcategory) + { + p->ConnectSubcategory(subcategory); + return &subcategory; + }); } void SettingsCategory::RegisterSubcategoryArray( @@ -266,26 +320,74 @@ void SettingsCategory::RegisterSubcategoryArray( std::transform(subcategories.begin(), subcategories.end(), std::back_inserter(newSubcategories.second), - [](SettingsCategory* subcategory) { return subcategory; }); + [this](SettingsCategory* subcategory) + { + p->ConnectSubcategory(*subcategory); + return subcategory; + }); } void SettingsCategory::RegisterVariables( std::initializer_list variables) { + for (auto& variable : variables) + { + p->ConnectVariable(variable); + } p->variables_.insert(p->variables_.end(), variables); } void SettingsCategory::RegisterVariables( std::vector variables) { + for (auto& variable : variables) + { + p->ConnectVariable(variable); + } p->variables_.insert( p->variables_.end(), variables.cbegin(), variables.cend()); } -boost::signals2::connection -SettingsCategory::RegisterResetCallback(std::function callback) +void SettingsCategory::Impl::ConnectSubcategory(SettingsCategory& category) { - return p->resetSignal_.connect(callback); + connections_.emplace_back(category.changed_signal().connect( + [this]() + { + if (!blockSignals_) + { + changedSignal_(); + } + })); + + connections_.emplace_back(category.staged_signal().connect( + [this]() + { + if (!blockSignals_) + { + stagedSignal_(); + } + })); +} + +void SettingsCategory::Impl::ConnectVariable(SettingsVariableBase* variable) +{ + connections_.emplace_back(variable->changed_signal().connect( + [this]() + { + if (!blockSignals_) + { + changedSignal_(); + } + })); + + connections_.emplace_back(variable->staged_signal().connect( + [this]() + { + if (!blockSignals_) + { + stagedSignal_(); + } + })); } } // namespace settings diff --git a/scwx-qt/source/scwx/qt/settings/settings_category.hpp b/scwx-qt/source/scwx/qt/settings/settings_category.hpp index 9b5613be..ee80ba46 100644 --- a/scwx-qt/source/scwx/qt/settings/settings_category.hpp +++ b/scwx-qt/source/scwx/qt/settings/settings_category.hpp @@ -6,7 +6,7 @@ #include #include -#include +#include namespace scwx { @@ -29,6 +29,20 @@ public: std::string name() const; + /** + * Gets the signal invoked when a variable within the category is changed. + * + * @return Changed signal + */ + boost::signals2::signal& changed_signal(); + + /** + * Gets the signal invoked when a variable within the category is staged. + * + * @return Staged signal + */ + boost::signals2::signal& staged_signal(); + /** * Set all variables to their defaults. */ @@ -73,13 +87,8 @@ public: RegisterVariables(std::initializer_list variables); void RegisterVariables(std::vector variables); - /** - * Registers a function to be called when the category is reset. - * - * @param callback Function to be called - */ - boost::signals2::connection - RegisterResetCallback(std::function callback); +protected: + void set_block_signals(bool blockSignals); private: class Impl; diff --git a/scwx-qt/source/scwx/qt/settings/settings_variable.cpp b/scwx-qt/source/scwx/qt/settings/settings_variable.cpp index 71db421e..c4a5f6c9 100644 --- a/scwx-qt/source/scwx/qt/settings/settings_variable.cpp +++ b/scwx-qt/source/scwx/qt/settings/settings_variable.cpp @@ -81,10 +81,13 @@ bool SettingsVariable::SetValue(const T& value) p->value_ = (p->transform_ != nullptr) ? p->transform_(value) : value; validated = true; + changed_signal()(); for (auto& callback : p->valueChangedCallbackFunctions_) { callback.second(p->value_); } + + staged_signal()(); for (auto& callback : p->valueStagedCallbackFunctions_) { callback.second(p->value_); @@ -129,10 +132,13 @@ bool SettingsVariable::SetValueOrDefault(const T& value) p->value_ = p->default_; } + changed_signal()(); for (auto& callback : p->valueChangedCallbackFunctions_) { callback.second(p->value_); } + + staged_signal()(); for (auto& callback : p->valueStagedCallbackFunctions_) { callback.second(p->value_); @@ -146,10 +152,13 @@ void SettingsVariable::SetValueToDefault() { p->value_ = p->default_; + changed_signal()(); for (auto& callback : p->valueChangedCallbackFunctions_) { callback.second(p->value_); } + + staged_signal()(); for (auto& callback : p->valueStagedCallbackFunctions_) { callback.second(p->value_); @@ -168,6 +177,7 @@ void SettingsVariable::StageDefault() p->staged_.reset(); } + staged_signal()(); for (auto& callback : p->valueStagedCallbackFunctions_) { callback.second(p->default_); @@ -194,6 +204,7 @@ bool SettingsVariable::StageValue(const T& value) validated = true; + staged_signal()(); for (auto& callback : p->valueStagedCallbackFunctions_) { callback.second(transformed); @@ -214,10 +225,13 @@ bool SettingsVariable::Commit() p->staged_.reset(); committed = true; + changed_signal()(); for (auto& callback : p->valueChangedCallbackFunctions_) { callback.second(p->value_); } + + staged_signal()(); for (auto& callback : p->valueStagedCallbackFunctions_) { callback.second(p->value_); @@ -232,6 +246,7 @@ void SettingsVariable::Reset() { p->staged_.reset(); + staged_signal()(); for (auto& callback : p->valueStagedCallbackFunctions_) { callback.second(p->value_); @@ -336,10 +351,13 @@ bool SettingsVariable::ReadValue(const boost::json::object& json) p->value_ = p->default_; } + changed_signal()(); for (auto& callback : p->valueChangedCallbackFunctions_) { callback.second(p->value_); } + + staged_signal()(); for (auto& callback : p->valueStagedCallbackFunctions_) { callback.second(p->value_); diff --git a/scwx-qt/source/scwx/qt/settings/settings_variable_base.cpp b/scwx-qt/source/scwx/qt/settings/settings_variable_base.cpp index 55ce72ea..7e31fb5f 100644 --- a/scwx-qt/source/scwx/qt/settings/settings_variable_base.cpp +++ b/scwx-qt/source/scwx/qt/settings/settings_variable_base.cpp @@ -18,6 +18,9 @@ public: ~Impl() {} const std::string name_; + + boost::signals2::signal changedSignal_ {}; + boost::signals2::signal stagedSignal_ {}; }; SettingsVariableBase::SettingsVariableBase(const std::string& name) : @@ -38,6 +41,16 @@ std::string SettingsVariableBase::name() const return p->name_; } +boost::signals2::signal& SettingsVariableBase::changed_signal() +{ + return p->changedSignal_; +} + +boost::signals2::signal& SettingsVariableBase::staged_signal() +{ + return p->stagedSignal_; +} + bool SettingsVariableBase::Equals(const SettingsVariableBase& o) const { return p->name_ == o.p->name_; diff --git a/scwx-qt/source/scwx/qt/settings/settings_variable_base.hpp b/scwx-qt/source/scwx/qt/settings/settings_variable_base.hpp index d7211197..fba1eff9 100644 --- a/scwx-qt/source/scwx/qt/settings/settings_variable_base.hpp +++ b/scwx-qt/source/scwx/qt/settings/settings_variable_base.hpp @@ -4,6 +4,7 @@ #include #include +#include namespace scwx { @@ -30,6 +31,20 @@ public: std::string name() const; + /** + * Gets the signal invoked when the settings variable is changed. + * + * @return Changed signal + */ + boost::signals2::signal& changed_signal(); + + /** + * Gets the signal invoked when the settings variable is staged. + * + * @return Staged signal + */ + boost::signals2::signal& staged_signal(); + /** * Sets the current value of the settings variable to default. */ diff --git a/scwx-qt/source/scwx/qt/ui/line_label.cpp b/scwx-qt/source/scwx/qt/ui/line_label.cpp index a8be0507..0b2f8f75 100644 --- a/scwx-qt/source/scwx/qt/ui/line_label.cpp +++ b/scwx-qt/source/scwx/qt/ui/line_label.cpp @@ -18,12 +18,13 @@ static const auto logger_ = scwx::util::Logger::Create(logPrefix_); class LineLabel::Impl { public: - explicit Impl() {}; + explicit Impl(LineLabel* self) : self_ {self} {}; ~Impl() = default; - void ResetLineSettings(); - QImage GenerateImage() const; + void UpdateLineLabel(const settings::LineSettings& lineSettings); + + LineLabel* self_; std::size_t borderWidth_ {1}; std::size_t highlightWidth_ {1}; @@ -33,26 +34,18 @@ public: boost::gil::rgba8_pixel_t highlightColor_ {255, 255, 0, 255}; boost::gil::rgba8_pixel_t lineColor_ {0, 0, 255, 255}; - settings::LineSettings* lineSettings_ {nullptr}; - QPixmap pixmap_ {}; bool pixmapDirty_ {true}; + + boost::signals2::scoped_connection settingsStaged_ {}; }; LineLabel::LineLabel(QWidget* parent) : - QFrame(parent), p {std::make_unique()} + QFrame(parent), p {std::make_unique(this)} { } -LineLabel::~LineLabel() -{ - p->ResetLineSettings(); -} - -void LineLabel::Impl::ResetLineSettings() -{ - lineSettings_ = nullptr; -} +LineLabel::~LineLabel() {} boost::gil::rgba8_pixel_t LineLabel::border_color() const { @@ -90,11 +83,6 @@ void LineLabel::set_border_width(std::size_t width) p->pixmapDirty_ = true; updateGeometry(); update(); - - if (p->lineSettings_ != nullptr) - { - p->lineSettings_->border_width().StageValue(width); - } } void LineLabel::set_highlight_width(std::size_t width) @@ -103,11 +91,6 @@ void LineLabel::set_highlight_width(std::size_t width) p->pixmapDirty_ = true; updateGeometry(); update(); - - if (p->lineSettings_ != nullptr) - { - p->lineSettings_->highlight_width().StageValue(width); - } } void LineLabel::set_line_width(std::size_t width) @@ -116,11 +99,6 @@ void LineLabel::set_line_width(std::size_t width) p->pixmapDirty_ = true; updateGeometry(); update(); - - if (p->lineSettings_ != nullptr) - { - p->lineSettings_->line_width().StageValue(width); - } } void LineLabel::set_border_color(boost::gil::rgba8_pixel_t color) @@ -128,12 +106,6 @@ void LineLabel::set_border_color(boost::gil::rgba8_pixel_t color) p->borderColor_ = color; p->pixmapDirty_ = true; update(); - - if (p->lineSettings_ != nullptr) - { - p->lineSettings_->border_color().StageValue( - util::color::ToArgbString(color)); - } } void LineLabel::set_highlight_color(boost::gil::rgba8_pixel_t color) @@ -141,12 +113,6 @@ void LineLabel::set_highlight_color(boost::gil::rgba8_pixel_t color) p->highlightColor_ = color; p->pixmapDirty_ = true; update(); - - if (p->lineSettings_ != nullptr) - { - p->lineSettings_->highlight_color().StageValue( - util::color::ToArgbString(color)); - } } void LineLabel::set_line_color(boost::gil::rgba8_pixel_t color) @@ -154,30 +120,30 @@ void LineLabel::set_line_color(boost::gil::rgba8_pixel_t color) p->lineColor_ = color; p->pixmapDirty_ = true; update(); - - if (p->lineSettings_ != nullptr) - { - p->lineSettings_->line_color().StageValue( - util::color::ToArgbString(color)); - } } void LineLabel::set_line_settings(settings::LineSettings& lineSettings) { - p->ResetLineSettings(); + p->settingsStaged_ = lineSettings.staged_signal().connect( + [this, &lineSettings]() { p->UpdateLineLabel(lineSettings); }); - set_border_color(util::color::ToRgba8PixelT( + p->UpdateLineLabel(lineSettings); +} + +void LineLabel::Impl::UpdateLineLabel( + const settings::LineSettings& lineSettings) +{ + self_->set_border_color(util::color::ToRgba8PixelT( lineSettings.border_color().GetStagedOrValue())); - set_highlight_color(util::color::ToRgba8PixelT( + self_->set_highlight_color(util::color::ToRgba8PixelT( lineSettings.highlight_color().GetStagedOrValue())); - set_line_color( + self_->set_line_color( util::color::ToRgba8PixelT(lineSettings.line_color().GetStagedOrValue())); - set_border_width(lineSettings.border_width().GetStagedOrValue()); - set_highlight_width(lineSettings.highlight_width().GetStagedOrValue()); - set_line_width(lineSettings.line_width().GetStagedOrValue()); - - p->lineSettings_ = &lineSettings; + self_->set_border_width(lineSettings.border_width().GetStagedOrValue()); + self_->set_highlight_width( + lineSettings.highlight_width().GetStagedOrValue()); + self_->set_line_width(lineSettings.line_width().GetStagedOrValue()); } QSize LineLabel::minimumSizeHint() const diff --git a/scwx-qt/source/scwx/qt/ui/settings/alert_palette_settings_widget.cpp b/scwx-qt/source/scwx/qt/ui/settings/alert_palette_settings_widget.cpp index 8e77bdb6..9775b9c8 100644 --- a/scwx-qt/source/scwx/qt/ui/settings/alert_palette_settings_widget.cpp +++ b/scwx-qt/source/scwx/qt/ui/settings/alert_palette_settings_widget.cpp @@ -37,13 +37,7 @@ public: SetupUi(); ConnectSignals(); } - ~Impl() - { - for (auto& c : bs2Connections_) - { - c.disconnect(); - } - }; + ~Impl() {}; void AddPhenomenonLine(const std::string& name, settings::LineSettings& lineSettings, @@ -59,10 +53,8 @@ public: QStackedWidget* phenomenonPagesWidget_; QListWidget* phenomenonListView_; - EditLineDialog* editLineDialog_; - LineLabel* activeLineLabel_ {nullptr}; - - std::vector bs2Connections_ {}; + EditLineDialog* editLineDialog_; + settings::LineSettings* activeLineSettings_ {nullptr}; boost::unordered_flat_map phenomenonPages_ {}; }; @@ -147,30 +139,27 @@ void AlertPaletteSettingsWidget::Impl::ConnectSignals() } }); - connect( - editLineDialog_, - &EditLineDialog::accepted, - self_, - [this]() - { - // If the active line label was set - if (activeLineLabel_ != nullptr) - { - // Update the active line label with selected line settings - activeLineLabel_->set_border_color(editLineDialog_->border_color()); - activeLineLabel_->set_highlight_color( - editLineDialog_->highlight_color()); - activeLineLabel_->set_line_color(editLineDialog_->line_color()); + connect(editLineDialog_, + &EditLineDialog::accepted, + self_, + [this]() + { + // If the active line label was set + if (activeLineSettings_ != nullptr) + { + // Update the active line settings with selected line settings + activeLineSettings_->StageValues( + editLineDialog_->border_color(), + editLineDialog_->highlight_color(), + editLineDialog_->line_color(), + editLineDialog_->border_width(), + editLineDialog_->highlight_width(), + editLineDialog_->line_width()); - activeLineLabel_->set_border_width(editLineDialog_->border_width()); - activeLineLabel_->set_highlight_width( - editLineDialog_->highlight_width()); - activeLineLabel_->set_line_width(editLineDialog_->line_width()); - - // Reset the active line label - activeLineLabel_ = nullptr; - } - }); + // Reset the active line settings + activeLineSettings_ = nullptr; + } + }); } void AlertPaletteSettingsWidget::Impl::SelectPhenomenon( @@ -260,19 +249,14 @@ void AlertPaletteSettingsWidget::Impl::AddPhenomenonLine( self_->AddSettingsCategory(&lineSettings); - boost::signals2::connection c = lineSettings.RegisterResetCallback( - [lineLabel, &lineSettings]() - { lineLabel->set_line_settings(lineSettings); }); - bs2Connections_.push_back(c); - connect( toolButton, &QAbstractButton::clicked, self_, - [this, lineLabel]() + [this, lineLabel, &lineSettings]() { // Set the active line label for when the dialog is finished - activeLineLabel_ = lineLabel; + activeLineSettings_ = &lineSettings; // Initialize dialog with current line settings editLineDialog_->set_border_color(lineLabel->border_color()); From dafb71e75c021aacdd3d955f99bbaf04c1ecdd3b Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Fri, 27 Sep 2024 07:28:18 -0500 Subject: [PATCH 26/36] Use new alert palettes in AlertLayer --- scwx-qt/source/scwx/qt/map/alert_layer.cpp | 141 +++++++++++++++--- .../source/scwx/qt/settings/line_settings.cpp | 15 ++ .../source/scwx/qt/settings/line_settings.hpp | 4 + 3 files changed, 138 insertions(+), 22 deletions(-) diff --git a/scwx-qt/source/scwx/qt/map/alert_layer.cpp b/scwx-qt/source/scwx/qt/map/alert_layer.cpp index cc8bc29b..c0842758 100644 --- a/scwx-qt/source/scwx/qt/map/alert_layer.cpp +++ b/scwx-qt/source/scwx/qt/map/alert_layer.cpp @@ -111,25 +111,27 @@ signals: class AlertLayer::Impl { public: + struct LineData + { + boost::gil::rgba32f_pixel_t borderColor_ {}; + boost::gil::rgba32f_pixel_t highlightColor_ {}; + boost::gil::rgba32f_pixel_t lineColor_ {}; + + std::size_t borderWidth_ {}; + std::size_t highlightWidth_ {}; + std::size_t lineWidth_ {}; + }; + explicit Impl(AlertLayer* self, std::shared_ptr context, awips::Phenomenon phenomenon) : self_ {self}, phenomenon_ {phenomenon}, + ibw_ {awips::ibw::GetImpactBasedWarningInfo(phenomenon)}, geoLines_ {{false, std::make_shared(context)}, {true, std::make_shared(context)}} { - auto& paletteSettings = settings::PaletteSettings::Instance(); - - for (auto alertActive : {false, true}) - { - lineColor_.emplace( - alertActive, - util::color::ToRgba32fPixelT( - paletteSettings.alert_color(phenomenon_, alertActive) - .GetValue())); - } - + UpdateLineData(); ConnectSignals(); ScheduleRefresh(); } @@ -158,6 +160,9 @@ public: const QPointF& mouseGlobalPos); void ScheduleRefresh(); + LineData& GetLineData(std::shared_ptr& segment); + void UpdateLineData(); + void AddLine(std::shared_ptr& geoLines, std::shared_ptr& di, const common::Coordinate& p1, @@ -177,6 +182,8 @@ public: boost::container::stable_vector< std::shared_ptr>& drawItems); + static LineData CreateLineData(const settings::LineSettings& lineSettings); + boost::asio::thread_pool threadPool_ {1u}; AlertLayer* self_; @@ -184,7 +191,8 @@ public: boost::asio::system_timer refreshTimer_ {threadPool_}; std::mutex refreshMutex_; - const awips::Phenomenon phenomenon_; + const awips::Phenomenon phenomenon_; + const awips::ibw::ImpactBasedWarningInfo& ibw_; std::unique_ptr receiver_ {std::make_unique()}; @@ -199,7 +207,10 @@ public: segmentsByLine_; std::mutex linesMutex_ {}; - std::unordered_map lineColor_; + std::unordered_map + threatCategoryLineData_; + LineData observedLineData_ {}; + LineData tornadoPossibleLineData_ {}; std::chrono::system_clock::time_point selectedTime_ {}; @@ -445,8 +456,8 @@ void AlertLayer::Impl::AddAlert( auto& startTime = segmentRecord->segmentBegin_; auto& endTime = segmentRecord->segmentEnd_; - auto& lineColor = lineColor_.at(alertActive); - auto& geoLines = geoLines_.at(alertActive); + auto& lineData = GetLineData(segment); + auto& geoLines = geoLines_.at(alertActive); const auto& coordinates = segment->codedLocation_->coordinates(); @@ -462,30 +473,51 @@ void AlertLayer::Impl::AddAlert( // If draw items were added if (drawItems.second) { + const float borderWidth = lineData.borderWidth_; + const float highlightWidth = lineData.highlightWidth_; + const float lineWidth = lineData.lineWidth_; + + const float totalHighlightWidth = lineWidth + (highlightWidth * 2.0f); + const float totalBorderWidth = totalHighlightWidth + (borderWidth * 2.0f); + + constexpr bool borderHover = true; + constexpr bool highlightHover = false; + constexpr bool lineHover = false; + // Add border AddLines(geoLines, coordinates, - kBlack_, - 5.0f, + lineData.borderColor_, + totalBorderWidth, startTime, endTime, - true, + borderHover, drawItems.first->second); - // Add only border to segmentsByLine_ + // Add border to segmentsByLine_ for (auto& di : drawItems.first->second) { segmentsByLine_.insert({di, segmentRecord}); } + // Add highlight + AddLines(geoLines, + coordinates, + lineData.highlightColor_, + totalHighlightWidth, + startTime, + endTime, + highlightHover, + drawItems.first->second); + // Add line AddLines(geoLines, coordinates, - lineColor, - 3.0f, + lineData.lineColor_, + lineWidth, startTime, endTime, - false, + lineHover, drawItems.first->second); } } @@ -638,6 +670,71 @@ void AlertLayer::Impl::HandleGeoLinesHover( } } +AlertLayer::Impl::LineData +AlertLayer::Impl::CreateLineData(const settings::LineSettings& lineSettings) +{ + return LineData {.borderColor_ {lineSettings.GetBorderColorRgba32f()}, + .highlightColor_ {lineSettings.GetHighlightColorRgba32f()}, + .lineColor_ {lineSettings.GetLineColorRgba32f()}, + .borderWidth_ {static_cast( + lineSettings.border_width().GetValue())}, + .highlightWidth_ {static_cast( + lineSettings.highlight_width().GetValue())}, + .lineWidth_ {static_cast( + lineSettings.line_width().GetValue())}}; +} + +void AlertLayer::Impl::UpdateLineData() +{ + auto& alertPalette = + settings::PaletteSettings().Instance().alert_palette(phenomenon_); + + for (auto threatCategory : ibw_.threatCategories_) + { + auto& palette = alertPalette.threat_category(threatCategory); + threatCategoryLineData_.insert_or_assign(threatCategory, + CreateLineData(palette)); + } + + if (ibw_.hasObservedTag_) + { + observedLineData_ = CreateLineData(alertPalette.observed()); + } + + if (ibw_.hasTornadoPossibleTag_) + { + tornadoPossibleLineData_ = + CreateLineData(alertPalette.tornado_possible()); + } +} + +AlertLayer::Impl::LineData& +AlertLayer::Impl::GetLineData(std::shared_ptr& segment) +{ + for (auto& threatCategory : ibw_.threatCategories_) + { + if (segment->threatCategory_ == threatCategory) + { + if (threatCategory == awips::ibw::ThreatCategory::Base) + { + if (ibw_.hasObservedTag_ && segment->observed_) + { + return observedLineData_; + } + + if (ibw_.hasTornadoPossibleTag_ && segment->tornadoPossible_) + { + return tornadoPossibleLineData_; + } + } + + return threatCategoryLineData_.at(threatCategory); + } + } + + return threatCategoryLineData_.at(awips::ibw::ThreatCategory::Base); +}; + AlertLayerHandler& AlertLayerHandler::Instance() { static AlertLayerHandler alertLayerHandler_ {}; diff --git a/scwx-qt/source/scwx/qt/settings/line_settings.cpp b/scwx-qt/source/scwx/qt/settings/line_settings.cpp index 105be812..45337fa2 100644 --- a/scwx-qt/source/scwx/qt/settings/line_settings.cpp +++ b/scwx-qt/source/scwx/qt/settings/line_settings.cpp @@ -104,6 +104,21 @@ SettingsVariable& LineSettings::line_width() const return p->lineWidth_; } +boost::gil::rgba32f_pixel_t LineSettings::GetBorderColorRgba32f() const +{ + return util::color::ToRgba32fPixelT(p->borderColor_.GetValue()); +} + +boost::gil::rgba32f_pixel_t LineSettings::GetHighlightColorRgba32f() const +{ + return util::color::ToRgba32fPixelT(p->highlightColor_.GetValue()); +} + +boost::gil::rgba32f_pixel_t LineSettings::GetLineColorRgba32f() const +{ + return util::color::ToRgba32fPixelT(p->lineColor_.GetValue()); +} + void LineSettings::StageValues(boost::gil::rgba8_pixel_t borderColor, boost::gil::rgba8_pixel_t highlightColor, boost::gil::rgba8_pixel_t lineColor, diff --git a/scwx-qt/source/scwx/qt/settings/line_settings.hpp b/scwx-qt/source/scwx/qt/settings/line_settings.hpp index bc9a9cb8..6f6988a2 100644 --- a/scwx-qt/source/scwx/qt/settings/line_settings.hpp +++ b/scwx-qt/source/scwx/qt/settings/line_settings.hpp @@ -35,6 +35,10 @@ public: SettingsVariable& highlight_width() const; SettingsVariable& line_width() const; + boost::gil::rgba32f_pixel_t GetBorderColorRgba32f() const; + boost::gil::rgba32f_pixel_t GetHighlightColorRgba32f() const; + boost::gil::rgba32f_pixel_t GetLineColorRgba32f() const; + void StageValues(boost::gil::rgba8_pixel_t borderColor, boost::gil::rgba8_pixel_t highlightColor, boost::gil::rgba8_pixel_t lineColor, From 584f5943b6fcaf7b0885fb0beeb55eaf35319f41 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Fri, 27 Sep 2024 07:48:48 -0500 Subject: [PATCH 27/36] Re-add inactive alert palette display --- scwx-qt/source/scwx/qt/map/alert_layer.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/scwx-qt/source/scwx/qt/map/alert_layer.cpp b/scwx-qt/source/scwx/qt/map/alert_layer.cpp index c0842758..69ebddb9 100644 --- a/scwx-qt/source/scwx/qt/map/alert_layer.cpp +++ b/scwx-qt/source/scwx/qt/map/alert_layer.cpp @@ -160,7 +160,8 @@ public: const QPointF& mouseGlobalPos); void ScheduleRefresh(); - LineData& GetLineData(std::shared_ptr& segment); + LineData& GetLineData(std::shared_ptr& segment, + bool alertActive); void UpdateLineData(); void AddLine(std::shared_ptr& geoLines, @@ -211,6 +212,7 @@ public: threatCategoryLineData_; LineData observedLineData_ {}; LineData tornadoPossibleLineData_ {}; + LineData inactiveLineData_ {}; std::chrono::system_clock::time_point selectedTime_ {}; @@ -456,7 +458,7 @@ void AlertLayer::Impl::AddAlert( auto& startTime = segmentRecord->segmentBegin_; auto& endTime = segmentRecord->segmentEnd_; - auto& lineData = GetLineData(segment); + auto& lineData = GetLineData(segment, alertActive); auto& geoLines = geoLines_.at(alertActive); const auto& coordinates = segment->codedLocation_->coordinates(); @@ -706,11 +708,19 @@ void AlertLayer::Impl::UpdateLineData() tornadoPossibleLineData_ = CreateLineData(alertPalette.tornado_possible()); } + + inactiveLineData_ = CreateLineData(alertPalette.inactive()); } AlertLayer::Impl::LineData& -AlertLayer::Impl::GetLineData(std::shared_ptr& segment) +AlertLayer::Impl::GetLineData(std::shared_ptr& segment, + bool alertActive) { + if (!alertActive) + { + return inactiveLineData_; + } + for (auto& threatCategory : ibw_.threatCategories_) { if (segment->threatCategory_ == threatCategory) From 40d70b0a13eb8d3f2799ae14fca23f60a71c8264 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Fri, 27 Sep 2024 09:13:45 -0500 Subject: [PATCH 28/36] Don't use braces around scalar initializers --- .../qt/settings/alert_palette_settings.cpp | 32 +++++++++---------- .../scwx/awips/impact_based_warnings.cpp | 6 ++-- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/scwx-qt/source/scwx/qt/settings/alert_palette_settings.cpp b/scwx-qt/source/scwx/qt/settings/alert_palette_settings.cpp index 96bed7f9..c684e1ed 100644 --- a/scwx-qt/source/scwx/qt/settings/alert_palette_settings.cpp +++ b/scwx-qt/source/scwx/qt/settings/alert_palette_settings.cpp @@ -41,25 +41,25 @@ static const boost::unordered_flat_map {awips::ibw::ThreatCategory::Considerable, {.highlightColor_ {0, 255, 0, 255}, .lineColor_ {kColorBlack_}, - .highlightWidth_ {1}, - .lineWidth_ {1}}}, + .highlightWidth_ = 1, + .lineWidth_ = 1}}, {awips::ibw::ThreatCategory::Catastrophic, {.highlightColor_ {0, 255, 0, 255}, .lineColor_ {255, 0, 0, 255}, - .highlightWidth_ {1}, - .lineWidth_ {1}}}}}, + .highlightWidth_ = 1, + .lineWidth_ = 1}}}}, {awips::Phenomenon::SevereThunderstorm, {{awips::ibw::ThreatCategory::Base, {.lineColor_ {255, 255, 0, 255}}}, {awips::ibw::ThreatCategory::Considerable, {.highlightColor_ {255, 255, 0, 255}, .lineColor_ {255, 0, 0, 255}, - .highlightWidth_ {1}, - .lineWidth_ {1}}}, + .highlightWidth_ = 1, + .lineWidth_ = 1}}, {awips::ibw::ThreatCategory::Destructive, {.highlightColor_ {255, 255, 0, 255}, .lineColor_ {255, 0, 0, 255}, - .highlightWidth_ {1}, - .lineWidth_ {2}}}}}, + .highlightWidth_ = 1, + .lineWidth_ = 2}}}}, {awips::Phenomenon::SnowSquall, {{awips::ibw::ThreatCategory::Base, {.lineColor_ {0, 255, 255, 255}}}}}, {awips::Phenomenon::Tornado, @@ -69,29 +69,29 @@ static const boost::unordered_flat_map {awips::ibw::ThreatCategory::Catastrophic, {.highlightColor_ {255, 0, 255, 255}, .lineColor_ {kColorBlack_}, - .highlightWidth_ {1}, - .lineWidth_ {1}}}}}}; + .highlightWidth_ = 1, + .lineWidth_ = 1}}}}}; static const boost::unordered_flat_map kObservedPalettes_ // {{awips::Phenomenon::Tornado, {.highlightColor_ {255, 0, 0, 255}, .lineColor_ {kColorBlack_}, - .highlightWidth_ {1}, - .lineWidth_ {1}}}}; + .highlightWidth_ = 1, + .lineWidth_ = 1}}}; static const boost::unordered_flat_map kTornadoPossiblePalettes_ // {{awips::Phenomenon::Marine, {.highlightColor_ {255, 127, 0, 255}, .lineColor_ {kColorBlack_}, - .highlightWidth_ {1}, - .lineWidth_ {1}}}, + .highlightWidth_ = 1, + .lineWidth_ = 1}}, {awips::Phenomenon::SevereThunderstorm, {.highlightColor_ {255, 255, 0, 255}, .lineColor_ {kColorBlack_}, - .highlightWidth_ {1}, - .lineWidth_ {1}}}}; + .highlightWidth_ = 1, + .lineWidth_ = 1}}}; static const boost::unordered_flat_map kInactivePalettes_ // diff --git a/wxdata/source/scwx/awips/impact_based_warnings.cpp b/wxdata/source/scwx/awips/impact_based_warnings.cpp index a5e63a76..40a20051 100644 --- a/wxdata/source/scwx/awips/impact_based_warnings.cpp +++ b/wxdata/source/scwx/awips/impact_based_warnings.cpp @@ -18,7 +18,7 @@ static const std::string logPrefix_ = "scwx::awips::ibw::impact_based_warnings"; static const boost::unordered_flat_map impactBasedWarningInfo_ { {Phenomenon::Marine, - ImpactBasedWarningInfo {.hasTornadoPossibleTag_ {true}}}, + ImpactBasedWarningInfo {.hasTornadoPossibleTag_ = true}}, {Phenomenon::FlashFlood, ImpactBasedWarningInfo { .threatCategories_ {ThreatCategory::Base, @@ -26,14 +26,14 @@ static const boost::unordered_flat_map ThreatCategory::Catastrophic}}}, {Phenomenon::SevereThunderstorm, ImpactBasedWarningInfo { - .hasTornadoPossibleTag_ {true}, + .hasTornadoPossibleTag_ = true, .threatCategories_ {ThreatCategory::Base, ThreatCategory::Considerable, ThreatCategory::Destructive}}}, {Phenomenon::SnowSquall, ImpactBasedWarningInfo {}}, {Phenomenon::Tornado, ImpactBasedWarningInfo { - .hasObservedTag_ {true}, + .hasObservedTag_ = true, .threatCategories_ {ThreatCategory::Base, ThreatCategory::Considerable, ThreatCategory::Catastrophic}}}, From 94edeefee0ea1275dfb16fba45dbb72d7c381b9b Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Fri, 27 Sep 2024 09:32:50 -0500 Subject: [PATCH 29/36] Update test data for alert settings --- test/data | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/data b/test/data index 20a1ca17..8a9e6bc2 160000 --- a/test/data +++ b/test/data @@ -1 +1 @@ -Subproject commit 20a1ca1752499222d33869e37148321936ca6354 +Subproject commit 8a9e6bc2e457e9ef69cbff575819228849b9c982 From 3434db279eabf8d94a61beb0373d9569c190e10f Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Fri, 27 Sep 2024 12:01:38 -0500 Subject: [PATCH 30/36] More removing braces around scalar initializers --- scwx-qt/source/scwx/qt/map/alert_layer.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/scwx-qt/source/scwx/qt/map/alert_layer.cpp b/scwx-qt/source/scwx/qt/map/alert_layer.cpp index 69ebddb9..d0e4d686 100644 --- a/scwx-qt/source/scwx/qt/map/alert_layer.cpp +++ b/scwx-qt/source/scwx/qt/map/alert_layer.cpp @@ -675,15 +675,16 @@ void AlertLayer::Impl::HandleGeoLinesHover( AlertLayer::Impl::LineData AlertLayer::Impl::CreateLineData(const settings::LineSettings& lineSettings) { - return LineData {.borderColor_ {lineSettings.GetBorderColorRgba32f()}, - .highlightColor_ {lineSettings.GetHighlightColorRgba32f()}, - .lineColor_ {lineSettings.GetLineColorRgba32f()}, - .borderWidth_ {static_cast( - lineSettings.border_width().GetValue())}, - .highlightWidth_ {static_cast( - lineSettings.highlight_width().GetValue())}, - .lineWidth_ {static_cast( - lineSettings.line_width().GetValue())}}; + return LineData { + .borderColor_ {lineSettings.GetBorderColorRgba32f()}, + .highlightColor_ {lineSettings.GetHighlightColorRgba32f()}, + .lineColor_ {lineSettings.GetLineColorRgba32f()}, + .borderWidth_ = + static_cast(lineSettings.border_width().GetValue()), + .highlightWidth_ = + static_cast(lineSettings.highlight_width().GetValue()), + .lineWidth_ = + static_cast(lineSettings.line_width().GetValue())}; } void AlertLayer::Impl::UpdateLineData() From d039fef4f13b90babe86fe82e6d013dfcc183ce3 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sun, 29 Sep 2024 07:35:20 -0500 Subject: [PATCH 31/36] Ensure edit line dialog reset button resets dialog to proper defaults --- .../alert_palette_settings_widget.cpp | 36 +++++++++---------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/scwx-qt/source/scwx/qt/ui/settings/alert_palette_settings_widget.cpp b/scwx-qt/source/scwx/qt/ui/settings/alert_palette_settings_widget.cpp index 9775b9c8..5d974225 100644 --- a/scwx-qt/source/scwx/qt/ui/settings/alert_palette_settings_widget.cpp +++ b/scwx-qt/source/scwx/qt/ui/settings/alert_palette_settings_widget.cpp @@ -249,27 +249,25 @@ void AlertPaletteSettingsWidget::Impl::AddPhenomenonLine( self_->AddSettingsCategory(&lineSettings); - connect( - toolButton, - &QAbstractButton::clicked, - self_, - [this, lineLabel, &lineSettings]() - { - // Set the active line label for when the dialog is finished - activeLineSettings_ = &lineSettings; + connect(toolButton, + &QAbstractButton::clicked, + self_, + [this, lineLabel, &lineSettings]() + { + // Set the active line label for when the dialog is finished + activeLineSettings_ = &lineSettings; - // Initialize dialog with current line settings - editLineDialog_->set_border_color(lineLabel->border_color()); - editLineDialog_->set_highlight_color(lineLabel->highlight_color()); - editLineDialog_->set_line_color(lineLabel->line_color()); + // Initialize dialog with current line settings + editLineDialog_->Initialize(lineLabel->border_color(), + lineLabel->highlight_color(), + lineLabel->line_color(), + lineLabel->border_width(), + lineLabel->highlight_width(), + lineLabel->line_width()); - editLineDialog_->set_border_width(lineLabel->border_width()); - editLineDialog_->set_highlight_width(lineLabel->highlight_width()); - editLineDialog_->set_line_width(lineLabel->line_width()); - - // Show the dialog - editLineDialog_->show(); - }); + // Show the dialog + editLineDialog_->show(); + }); } } // namespace ui From 2d8c3c8175fa6a59cde8cfb5aaea30d8529cde5c Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sun, 29 Sep 2024 07:41:46 -0500 Subject: [PATCH 32/36] Removing old alert palette configuration from settings dialog --- scwx-qt/source/scwx/qt/ui/settings_dialog.cpp | 164 +----------------- scwx-qt/source/scwx/qt/ui/settings_dialog.ui | 44 ----- 2 files changed, 1 insertion(+), 207 deletions(-) diff --git a/scwx-qt/source/scwx/qt/ui/settings_dialog.cpp b/scwx-qt/source/scwx/qt/ui/settings_dialog.cpp index f7e22c09..c35607a9 100644 --- a/scwx-qt/source/scwx/qt/ui/settings_dialog.cpp +++ b/scwx-qt/source/scwx/qt/ui/settings_dialog.cpp @@ -182,7 +182,6 @@ public: void SetupTextTab(); void SetupHotkeysTab(); - void ShowColorDialog(QLineEdit* lineEdit); void UpdateRadarDialogLocation(const std::string& id); void UpdateAlertRadarDialogLocation(const std::string& id); @@ -204,8 +203,7 @@ public: const std::string& value, QLabel* imageLabel); static std::string - RadarSiteLabel(std::shared_ptr& radarSite); - static void SetBackgroundColor(const std::string& value, QFrame* frame); + RadarSiteLabel(std::shared_ptr& radarSite); SettingsDialog* self_; RadarSiteDialog* radarSiteDialog_; @@ -254,12 +252,6 @@ public: std::unordered_map> colorTables_ {}; - std::unordered_map> - activeAlertColors_ {}; - std::unordered_map> - inactiveAlertColors_ {}; settings::SettingsInterface alertAudioSoundFile_ {}; settings::SettingsInterface alertAudioLocationMethod_ {}; @@ -804,9 +796,6 @@ void SettingsDialogImpl::SetupPalettesColorTablesTab() void SettingsDialogImpl::SetupPalettesAlertsTab() { - settings::PaletteSettings& paletteSettings = - settings::PaletteSettings::Instance(); - // Palettes > Alerts QVBoxLayout* layout = new QVBoxLayout(self_->ui->alertsPalette); @@ -815,119 +804,6 @@ void SettingsDialogImpl::SetupPalettesAlertsTab() layout->addWidget(alertPaletteSettingsWidget_); settingsPages_.push_back(alertPaletteSettingsWidget_); - - // Palettes > Old Alerts - QGridLayout* alertsLayout = - reinterpret_cast(self_->ui->alertsFrame->layout()); - - QLabel* phenomenonLabel = new QLabel(QObject::tr("Phenomenon"), self_); - QLabel* activeLabel = new QLabel(QObject::tr("Active"), self_); - QLabel* inactiveLabel = new QLabel(QObject::tr("Inactive"), self_); - - QFont boldFont; - boldFont.setBold(true); - phenomenonLabel->setFont(boldFont); - activeLabel->setFont(boldFont); - inactiveLabel->setFont(boldFont); - - alertsLayout->addWidget(phenomenonLabel, 0, 0); - alertsLayout->addWidget(activeLabel, 0, 1, 1, 4); - alertsLayout->addWidget(inactiveLabel, 0, 5, 1, 4); - - auto& alertPhenomena = settings::PaletteSettings::alert_phenomena(); - - activeAlertColors_.reserve(alertPhenomena.size()); - inactiveAlertColors_.reserve(alertPhenomena.size()); - - int alertsRow = 1; - for (auto& phenomenon : alertPhenomena) - { - QFrame* activeFrame = new QFrame(self_); - QFrame* inactiveFrame = new QFrame(self_); - - QLineEdit* activeEdit = new QLineEdit(self_); - QLineEdit* inactiveEdit = new QLineEdit(self_); - - QToolButton* activeButton = new QToolButton(self_); - QToolButton* inactiveButton = new QToolButton(self_); - QToolButton* activeResetButton = new QToolButton(self_); - QToolButton* inactiveResetButton = new QToolButton(self_); - - activeFrame->setMinimumHeight(24); - activeFrame->setMinimumWidth(24); - activeFrame->setFrameShape(QFrame::Shape::Box); - activeFrame->setFrameShadow(QFrame::Shadow::Plain); - inactiveFrame->setMinimumHeight(24); - inactiveFrame->setMinimumWidth(24); - inactiveFrame->setFrameShape(QFrame::Shape::Box); - inactiveFrame->setFrameShadow(QFrame::Shadow::Plain); - - activeButton->setIcon( - QIcon {":/res/icons/font-awesome-6/palette-solid.svg"}); - inactiveButton->setIcon( - QIcon {":/res/icons/font-awesome-6/palette-solid.svg"}); - activeResetButton->setIcon( - QIcon {":/res/icons/font-awesome-6/rotate-left-solid.svg"}); - inactiveResetButton->setIcon( - QIcon {":/res/icons/font-awesome-6/rotate-left-solid.svg"}); - - alertsLayout->addWidget( - new QLabel(QObject::tr(awips::GetPhenomenonText(phenomenon).c_str()), - self_), - alertsRow, - 0); - alertsLayout->addWidget(activeFrame, alertsRow, 1); - alertsLayout->addWidget(activeEdit, alertsRow, 2); - alertsLayout->addWidget(activeButton, alertsRow, 3); - alertsLayout->addWidget(activeResetButton, alertsRow, 4); - alertsLayout->addWidget(inactiveFrame, alertsRow, 5); - alertsLayout->addWidget(inactiveEdit, alertsRow, 6); - alertsLayout->addWidget(inactiveButton, alertsRow, 7); - alertsLayout->addWidget(inactiveResetButton, alertsRow, 8); - ++alertsRow; - - // Create settings interface - auto activeResult = activeAlertColors_.emplace( - phenomenon, settings::SettingsInterface {}); - auto inactiveResult = inactiveAlertColors_.emplace( - phenomenon, settings::SettingsInterface {}); - auto& activeColor = activeResult.first->second; - auto& inactiveColor = inactiveResult.first->second; - - // Add to settings list - settings_.push_back(&activeColor); - settings_.push_back(&inactiveColor); - - auto& activeSetting = paletteSettings.alert_color(phenomenon, true); - auto& inactiveSetting = paletteSettings.alert_color(phenomenon, false); - - activeColor.SetSettingsVariable(activeSetting); - activeColor.SetEditWidget(activeEdit); - activeColor.SetResetButton(activeResetButton); - - inactiveColor.SetSettingsVariable(inactiveSetting); - inactiveColor.SetEditWidget(inactiveEdit); - inactiveColor.SetResetButton(inactiveResetButton); - - SetBackgroundColor(activeSetting.GetValue(), activeFrame); - SetBackgroundColor(inactiveSetting.GetValue(), inactiveFrame); - - activeSetting.RegisterValueStagedCallback( - [activeFrame](const std::string& value) - { SetBackgroundColor(value, activeFrame); }); - inactiveSetting.RegisterValueStagedCallback( - [inactiveFrame](const std::string& value) - { SetBackgroundColor(value, inactiveFrame); }); - - QObject::connect(activeButton, - &QAbstractButton::clicked, - self_, - [=, this]() { ShowColorDialog(activeEdit); }); - QObject::connect(inactiveButton, - &QAbstractButton::clicked, - self_, - [=, this]() { ShowColorDialog(inactiveEdit); }); - } } void SettingsDialogImpl::SetupUnitsTab() @@ -1382,44 +1258,6 @@ void SettingsDialogImpl::LoadColorTablePreview(const std::string& key, }); } -void SettingsDialogImpl::ShowColorDialog(QLineEdit* lineEdit) -{ - QColorDialog* dialog = new QColorDialog(self_); - - dialog->setAttribute(Qt::WA_DeleteOnClose); - dialog->setOption(QColorDialog::ColorDialogOption::ShowAlphaChannel); - - QColor initialColor(lineEdit->text()); - if (initialColor.isValid()) - { - dialog->setCurrentColor(initialColor); - } - - QObject::connect( - dialog, - &QColorDialog::colorSelected, - self_, - [lineEdit](const QColor& color) - { - QString colorName = color.name(QColor::NameFormat::HexArgb); - - logger_->info("Selected color: {}", colorName.toStdString()); - lineEdit->setText(colorName); - - // setText does not emit the textEdited signal - Q_EMIT lineEdit->textEdited(colorName); - }); - - dialog->open(); -} - -void SettingsDialogImpl::SetBackgroundColor(const std::string& value, - QFrame* frame) -{ - frame->setStyleSheet( - QString::fromStdString(fmt::format("background-color: {}", value))); -} - void SettingsDialogImpl::UpdateRadarDialogLocation(const std::string& id) { std::shared_ptr radarSite = config::RadarSite::Get(id); diff --git a/scwx-qt/source/scwx/qt/ui/settings_dialog.ui b/scwx-qt/source/scwx/qt/ui/settings_dialog.ui index 0237462a..444e6705 100644 --- a/scwx-qt/source/scwx/qt/ui/settings_dialog.ui +++ b/scwx-qt/source/scwx/qt/ui/settings_dialog.ui @@ -639,50 +639,6 @@ Alerts - - - Old Alerts - - - - - - QFrame::Shape::StyledPanel - - - QFrame::Shadow::Raised - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - Qt::Orientation::Vertical - - - - 20 - 239 - - - - - - From a1d9b25f0bbc0b517188801c5a20fcf8a97d4a40 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sun, 29 Sep 2024 08:19:51 -0500 Subject: [PATCH 33/36] Add alert palette reset buttons --- .../scwx/qt/settings/settings_category.cpp | 89 +++++++++++++++++++ .../scwx/qt/settings/settings_category.hpp | 23 +++++ .../scwx/qt/settings/settings_variable.cpp | 12 +++ .../scwx/qt/settings/settings_variable.hpp | 18 ++++ .../qt/settings/settings_variable_base.hpp | 18 ++++ .../alert_palette_settings_widget.cpp | 17 ++++ 6 files changed, 177 insertions(+) diff --git a/scwx-qt/source/scwx/qt/settings/settings_category.cpp b/scwx-qt/source/scwx/qt/settings/settings_category.cpp index 3714c4ca..75a46bf8 100644 --- a/scwx-qt/source/scwx/qt/settings/settings_category.cpp +++ b/scwx-qt/source/scwx/qt/settings/settings_category.cpp @@ -48,6 +48,62 @@ SettingsCategory::SettingsCategory(SettingsCategory&&) noexcept = default; SettingsCategory& SettingsCategory::operator=(SettingsCategory&&) noexcept = default; +bool SettingsCategory::IsDefault() const +{ + bool isDefault = true; + + // Get subcategory array defaults + for (auto& subcategoryArray : p->subcategoryArrays_) + { + for (auto& subcategory : subcategoryArray.second) + { + isDefault = isDefault && subcategory->IsDefault(); + } + } + + // Get subcategory defaults + for (auto& subcategory : p->subcategories_) + { + isDefault = isDefault && subcategory->IsDefault(); + } + + // Get variable defaults + for (auto& variable : p->variables_) + { + isDefault = isDefault && variable->IsDefault(); + } + + return isDefault; +} + +bool SettingsCategory::IsDefaultStaged() const +{ + bool isDefaultStaged = true; + + // Get subcategory array defaults + for (auto& subcategoryArray : p->subcategoryArrays_) + { + for (auto& subcategory : subcategoryArray.second) + { + isDefaultStaged = isDefaultStaged && subcategory->IsDefaultStaged(); + } + } + + // Get subcategory defaults + for (auto& subcategory : p->subcategories_) + { + isDefaultStaged = isDefaultStaged && subcategory->IsDefaultStaged(); + } + + // Get variable defaults + for (auto& variable : p->variables_) + { + isDefaultStaged = isDefaultStaged && variable->IsDefaultStaged(); + } + + return isDefaultStaged; +} + std::string SettingsCategory::name() const { return p->name_; @@ -102,6 +158,39 @@ void SettingsCategory::SetDefaults() p->stagedSignal_(); } +void SettingsCategory::StageDefaults() +{ + // Don't allow individual variables to invoke the signal when operating over + // the entire category + p->blockSignals_ = true; + + // Stage subcategory array defaults + for (auto& subcategoryArray : p->subcategoryArrays_) + { + for (auto& subcategory : subcategoryArray.second) + { + subcategory->StageDefaults(); + } + } + + // Stage subcategory defaults + for (auto& subcategory : p->subcategories_) + { + subcategory->StageDefaults(); + } + + // Stage variable defaults + for (auto& variable : p->variables_) + { + variable->StageDefault(); + } + + // Unblock signals + p->blockSignals_ = false; + + p->stagedSignal_(); +} + bool SettingsCategory::Commit() { bool committed = false; diff --git a/scwx-qt/source/scwx/qt/settings/settings_category.hpp b/scwx-qt/source/scwx/qt/settings/settings_category.hpp index ee80ba46..167af06a 100644 --- a/scwx-qt/source/scwx/qt/settings/settings_category.hpp +++ b/scwx-qt/source/scwx/qt/settings/settings_category.hpp @@ -43,11 +43,34 @@ public: */ boost::signals2::signal& staged_signal(); + /** + * Gets whether or not all settings variables are currently set to default + * values. + * + * @return true if all settings variables are currently set to default + * values, otherwise false. + */ + bool IsDefault() const; + + /** + * Gets whether or not all settings variables currently have staged values + * set to default. + * + * @return true if all settings variables currently have staged values set + * to default, otherwise false. + */ + bool IsDefaultStaged() const; + /** * Set all variables to their defaults. */ void SetDefaults(); + /** + * Stage all variables to their defaults. + */ + void StageDefaults(); + /** * Sets the current value of all variables to the staged value. * diff --git a/scwx-qt/source/scwx/qt/settings/settings_variable.cpp b/scwx-qt/source/scwx/qt/settings/settings_variable.cpp index c4a5f6c9..a5387937 100644 --- a/scwx-qt/source/scwx/qt/settings/settings_variable.cpp +++ b/scwx-qt/source/scwx/qt/settings/settings_variable.cpp @@ -65,6 +65,18 @@ inline auto FormatParameter(const T& value) } } +template +bool SettingsVariable::IsDefault() const +{ + return p->value_ == p->default_; +} + +template +bool SettingsVariable::IsDefaultStaged() const +{ + return p->staged_.value_or(p->value_) == p->default_; +} + template T SettingsVariable::GetValue() const { diff --git a/scwx-qt/source/scwx/qt/settings/settings_variable.hpp b/scwx-qt/source/scwx/qt/settings/settings_variable.hpp index d2e6c949..df9184a1 100644 --- a/scwx-qt/source/scwx/qt/settings/settings_variable.hpp +++ b/scwx-qt/source/scwx/qt/settings/settings_variable.hpp @@ -37,6 +37,24 @@ public: SettingsVariable(SettingsVariable&&) noexcept; SettingsVariable& operator=(SettingsVariable&&) noexcept; + /** + * Gets whether or not the settings variable is currently set to its default + * value. + * + * @return true if the settings variable is currently set to its default + * value, otherwise false. + */ + bool IsDefault() const; + + /** + * Gets whether or not the settings variable currently has its staged value + * set to default. + * + * @return true if the settings variable currently has its staged value set + * to default, otherwise false. + */ + bool IsDefaultStaged() const; + /** * Gets the current value of the settings variable. * diff --git a/scwx-qt/source/scwx/qt/settings/settings_variable_base.hpp b/scwx-qt/source/scwx/qt/settings/settings_variable_base.hpp index fba1eff9..f4e48934 100644 --- a/scwx-qt/source/scwx/qt/settings/settings_variable_base.hpp +++ b/scwx-qt/source/scwx/qt/settings/settings_variable_base.hpp @@ -45,6 +45,24 @@ public: */ boost::signals2::signal& staged_signal(); + /** + * Gets whether or not the settings variable is currently set to its default + * value. + * + * @return true if the settings variable is currently set to its default + * value, otherwise false. + */ + virtual bool IsDefault() const = 0; + + /** + * Gets whether or not the settings variable currently has its staged value + * set to default. + * + * @return true if the settings variable currently has its staged value set + * to default, otherwise false. + */ + virtual bool IsDefaultStaged() const = 0; + /** * Sets the current value of the settings variable to default. */ diff --git a/scwx-qt/source/scwx/qt/ui/settings/alert_palette_settings_widget.cpp b/scwx-qt/source/scwx/qt/ui/settings/alert_palette_settings_widget.cpp index 5d974225..a3ae4642 100644 --- a/scwx-qt/source/scwx/qt/ui/settings/alert_palette_settings_widget.cpp +++ b/scwx-qt/source/scwx/qt/ui/settings/alert_palette_settings_widget.cpp @@ -57,6 +57,8 @@ public: settings::LineSettings* activeLineSettings_ {nullptr}; boost::unordered_flat_map phenomenonPages_ {}; + + std::vector connections_ {}; }; AlertPaletteSettingsWidget::AlertPaletteSettingsWidget(QWidget* parent) : @@ -243,9 +245,15 @@ void AlertPaletteSettingsWidget::Impl::AddPhenomenonLine( LineLabel* lineLabel = new LineLabel(self_); lineLabel->set_line_settings(lineSettings); + QToolButton* resetButton = new QToolButton(self_); + resetButton->setIcon( + QIcon {":/res/icons/font-awesome-6/rotate-left-solid.svg"}); + resetButton->setVisible(!lineSettings.IsDefaultStaged()); + layout->addWidget(new QLabel(tr(name.c_str()), self_), row, 0); layout->addWidget(lineLabel, row, 1); layout->addWidget(toolButton, row, 2); + layout->addWidget(resetButton, row, 3); self_->AddSettingsCategory(&lineSettings); @@ -268,6 +276,15 @@ void AlertPaletteSettingsWidget::Impl::AddPhenomenonLine( // Show the dialog editLineDialog_->show(); }); + + connect(resetButton, + &QAbstractButton::clicked, + self_, + [&lineSettings]() { lineSettings.StageDefaults(); }); + + connections_.emplace_back(lineSettings.staged_signal().connect( + [resetButton, &lineSettings]() + { resetButton->setVisible(!lineSettings.IsDefaultStaged()); })); } } // namespace ui From 295bbda921f591d622be11aa03713ef244ac06ca Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sun, 29 Sep 2024 21:39:44 -0500 Subject: [PATCH 34/36] Properly mark settings variable functions as override --- scwx-qt/source/scwx/qt/settings/settings_variable.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scwx-qt/source/scwx/qt/settings/settings_variable.hpp b/scwx-qt/source/scwx/qt/settings/settings_variable.hpp index df9184a1..2c3b2a07 100644 --- a/scwx-qt/source/scwx/qt/settings/settings_variable.hpp +++ b/scwx-qt/source/scwx/qt/settings/settings_variable.hpp @@ -44,7 +44,7 @@ public: * @return true if the settings variable is currently set to its default * value, otherwise false. */ - bool IsDefault() const; + bool IsDefault() const override; /** * Gets whether or not the settings variable currently has its staged value @@ -53,7 +53,7 @@ public: * @return true if the settings variable currently has its staged value set * to default, otherwise false. */ - bool IsDefaultStaged() const; + bool IsDefaultStaged() const override; /** * Gets the current value of the settings variable. From f672ff553a1765629f8043d1151a75a0f115acaf Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Mon, 30 Sep 2024 06:14:17 -0500 Subject: [PATCH 35/36] Update alert lines on settings update --- scwx-qt/source/scwx/qt/map/alert_layer.cpp | 99 ++++++++++++++++++---- 1 file changed, 82 insertions(+), 17 deletions(-) diff --git a/scwx-qt/source/scwx/qt/map/alert_layer.cpp b/scwx-qt/source/scwx/qt/map/alert_layer.cpp index d0e4d686..5ed4e458 100644 --- a/scwx-qt/source/scwx/qt/map/alert_layer.cpp +++ b/scwx-qt/source/scwx/qt/map/alert_layer.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -40,6 +41,8 @@ struct AlertTypeHash> size_t operator()(const std::pair& x) const; }; +static bool IsAlertActive(const std::shared_ptr& segment); + class AlertLayerHandler : public QObject { Q_OBJECT @@ -160,8 +163,8 @@ public: const QPointF& mouseGlobalPos); void ScheduleRefresh(); - LineData& GetLineData(std::shared_ptr& segment, - bool alertActive); + LineData& GetLineData(const std::shared_ptr& segment, + bool alertActive); void UpdateLineData(); void AddLine(std::shared_ptr& geoLines, @@ -182,6 +185,7 @@ public: bool enableHover, boost::container::stable_vector< std::shared_ptr>& drawItems); + void UpdateLines(); static LineData CreateLineData(const settings::LineSettings& lineSettings); @@ -218,6 +222,8 @@ public: std::shared_ptr lastHoverDi_ {nullptr}; std::string tooltip_ {}; + + std::vector connections_ {}; }; AlertLayer::AlertLayer(std::shared_ptr context, @@ -302,6 +308,15 @@ void AlertLayer::Deinitialize() DrawLayer::Deinitialize(); } +bool IsAlertActive(const std::shared_ptr& segment) +{ + auto& vtec = segment->header_->vtecString_.front(); + auto action = vtec.pVtec_.action(); + bool alertActive = (action != awips::PVtec::Action::Canceled); + + return alertActive; +} + void AlertLayerHandler::HandleAlert(const types::TextEventKey& key, size_t messageIndex) { @@ -344,10 +359,9 @@ void AlertLayerHandler::HandleAlert(const types::TextEventKey& key, continue; } - auto& vtec = segment->header_->vtecString_.front(); - auto action = vtec.pVtec_.action(); - awips::Phenomenon phenomenon = vtec.pVtec_.phenomenon(); - bool alertActive = (action != awips::PVtec::Action::Canceled); + auto& vtec = segment->header_->vtecString_.front(); + awips::Phenomenon phenomenon = vtec.pVtec_.phenomenon(); + bool alertActive = IsAlertActive(segment); auto& segmentsForType = segmentsByType_[{key.phenomenon_, alertActive}]; @@ -406,6 +420,8 @@ void AlertLayer::Impl::ConnectAlertHandlerSignals() void AlertLayer::Impl::ConnectSignals() { + auto& alertPaletteSettings = + settings::PaletteSettings::Instance().alert_palette(phenomenon_); auto timelineManager = manager::TimelineManager::Instance(); QObject::connect(timelineManager.get(), @@ -413,6 +429,13 @@ void AlertLayer::Impl::ConnectSignals() receiver_.get(), [this](std::chrono::system_clock::time_point dateTime) { selectedTime_ = dateTime; }); + + connections_.push_back(alertPaletteSettings.changed_signal().connect( + [this]() + { + UpdateLineData(); + UpdateLines(); + })); } void AlertLayer::Impl::ScheduleRefresh() @@ -452,9 +475,7 @@ void AlertLayer::Impl::AddAlert( { auto& segment = segmentRecord->segment_; - auto& vtec = segment->header_->vtecString_.front(); - auto action = vtec.pVtec_.action(); - bool alertActive = (action != awips::PVtec::Action::Canceled); + bool alertActive = IsAlertActive(segment); auto& startTime = segmentRecord->segmentBegin_; auto& endTime = segmentRecord->segmentEnd_; @@ -533,11 +554,8 @@ void AlertLayer::Impl::UpdateAlert( auto it = linesBySegment_.find(segmentRecord); if (it != linesBySegment_.cend()) { - auto& segment = segmentRecord->segment_; - - auto& vtec = segment->header_->vtecString_.front(); - auto action = vtec.pVtec_.action(); - bool alertActive = (action != awips::PVtec::Action::Canceled); + auto& segment = segmentRecord->segment_; + bool alertActive = IsAlertActive(segment); auto& geoLines = geoLines_.at(alertActive); @@ -624,6 +642,54 @@ void AlertLayer::Impl::AddLine(std::shared_ptr& geoLines, } } +void AlertLayer::Impl::UpdateLines() +{ + std::unique_lock lock {linesMutex_}; + + for (auto& segmentLine : linesBySegment_) + { + auto& segmentRecord = segmentLine.first; + auto& geoLineDrawItems = segmentLine.second; + auto& segment = segmentRecord->segment_; + bool alertActive = IsAlertActive(segment); + auto& lineData = GetLineData(segment, alertActive); + auto& geoLines = geoLines_.at(alertActive); + + const float borderWidth = lineData.borderWidth_; + const float highlightWidth = lineData.highlightWidth_; + const float lineWidth = lineData.lineWidth_; + + const float totalHighlightWidth = lineWidth + (highlightWidth * 2.0f); + const float totalBorderWidth = totalHighlightWidth + (borderWidth * 2.0f); + + // Border, highlight and line + std::size_t linesPerType = geoLineDrawItems.size() / 3; + + // Border + for (auto& borderLine : geoLineDrawItems | std::views::take(linesPerType)) + { + geoLines->SetLineModulate(borderLine, lineData.borderColor_); + geoLines->SetLineWidth(borderLine, totalBorderWidth); + } + + // Highlight + for (auto& highlightLine : geoLineDrawItems | + std::views::drop(linesPerType) | + std::views::take(linesPerType)) + { + geoLines->SetLineModulate(highlightLine, lineData.highlightColor_); + geoLines->SetLineWidth(highlightLine, totalHighlightWidth); + } + + // Line + for (auto& line : geoLineDrawItems | std::views::drop(linesPerType * 2)) + { + geoLines->SetLineModulate(line, lineData.lineColor_); + geoLines->SetLineWidth(line, lineWidth); + } + } +} + void AlertLayer::Impl::HandleGeoLinesEvent( std::shared_ptr& di, QEvent* ev) { @@ -713,9 +779,8 @@ void AlertLayer::Impl::UpdateLineData() inactiveLineData_ = CreateLineData(alertPalette.inactive()); } -AlertLayer::Impl::LineData& -AlertLayer::Impl::GetLineData(std::shared_ptr& segment, - bool alertActive) +AlertLayer::Impl::LineData& AlertLayer::Impl::GetLineData( + const std::shared_ptr& segment, bool alertActive) { if (!alertActive) { From c811b95129cdf709d40793203770883c07feeeb9 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Mon, 30 Sep 2024 06:22:24 -0500 Subject: [PATCH 36/36] Update test data to merged revision --- test/data | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/data b/test/data index 8a9e6bc2..40a367ca 160000 --- a/test/data +++ b/test/data @@ -1 +1 @@ -Subproject commit 8a9e6bc2e457e9ef69cbff575819228849b9c982 +Subproject commit 40a367ca89b5b197353ca58dea547a3e3407c7f3