mirror of
https://github.com/ciphervance/supercell-wx.git
synced 2025-10-30 17:30:05 +00:00
Merge pull request #277 from dpaulat/feature/enhanced-alerts-3
Add Customizable Alert Lines
This commit is contained in:
commit
50cf49568d
35 changed files with 2813 additions and 427 deletions
|
|
@ -169,9 +169,11 @@ 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
|
||||
source/scwx/qt/settings/map_settings.hpp
|
||||
source/scwx/qt/settings/palette_settings.hpp
|
||||
source/scwx/qt/settings/product_settings.hpp
|
||||
|
|
@ -185,9 +187,11 @@ 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
|
||||
source/scwx/qt/settings/map_settings.cpp
|
||||
source/scwx/qt/settings/palette_settings.cpp
|
||||
source/scwx/qt/settings/product_settings.cpp
|
||||
|
|
@ -240,8 +244,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
|
||||
|
|
@ -252,6 +256,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
|
||||
|
|
@ -259,15 +264,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
|
||||
|
|
@ -278,6 +284,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
|
||||
|
|
@ -285,14 +292,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
|
||||
|
|
@ -303,11 +311,14 @@ 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)
|
||||
set(HDR_UI_SETTINGS source/scwx/qt/ui/settings/hotkey_settings_widget.hpp
|
||||
source/scwx/qt/ui/update_dialog.ui
|
||||
source/scwx/qt/ui/wfo_dialog.ui)
|
||||
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
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include <chrono>
|
||||
#include <mutex>
|
||||
#include <ranges>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
|
|
@ -40,6 +41,8 @@ struct AlertTypeHash<std::pair<awips::Phenomenon, bool>>
|
|||
size_t operator()(const std::pair<awips::Phenomenon, bool>& x) const;
|
||||
};
|
||||
|
||||
static bool IsAlertActive(const std::shared_ptr<const awips::Segment>& segment);
|
||||
|
||||
class AlertLayerHandler : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
|
@ -111,25 +114,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<MapContext> context,
|
||||
awips::Phenomenon phenomenon) :
|
||||
self_ {self},
|
||||
phenomenon_ {phenomenon},
|
||||
ibw_ {awips::ibw::GetImpactBasedWarningInfo(phenomenon)},
|
||||
geoLines_ {{false, std::make_shared<gl::draw::GeoLines>(context)},
|
||||
{true, std::make_shared<gl::draw::GeoLines>(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 +163,10 @@ public:
|
|||
const QPointF& mouseGlobalPos);
|
||||
void ScheduleRefresh();
|
||||
|
||||
LineData& GetLineData(const std::shared_ptr<const awips::Segment>& segment,
|
||||
bool alertActive);
|
||||
void UpdateLineData();
|
||||
|
||||
void AddLine(std::shared_ptr<gl::draw::GeoLines>& geoLines,
|
||||
std::shared_ptr<gl::draw::GeoLineDrawItem>& di,
|
||||
const common::Coordinate& p1,
|
||||
|
|
@ -176,6 +185,9 @@ public:
|
|||
bool enableHover,
|
||||
boost::container::stable_vector<
|
||||
std::shared_ptr<gl::draw::GeoLineDrawItem>>& drawItems);
|
||||
void UpdateLines();
|
||||
|
||||
static LineData CreateLineData(const settings::LineSettings& lineSettings);
|
||||
|
||||
boost::asio::thread_pool threadPool_ {1u};
|
||||
|
||||
|
|
@ -184,7 +196,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<QObject> receiver_ {std::make_unique<QObject>()};
|
||||
|
||||
|
|
@ -199,12 +212,18 @@ public:
|
|||
segmentsByLine_;
|
||||
std::mutex linesMutex_ {};
|
||||
|
||||
std::unordered_map<bool, boost::gil::rgba32f_pixel_t> lineColor_;
|
||||
std::unordered_map<awips::ibw::ThreatCategory, LineData>
|
||||
threatCategoryLineData_;
|
||||
LineData observedLineData_ {};
|
||||
LineData tornadoPossibleLineData_ {};
|
||||
LineData inactiveLineData_ {};
|
||||
|
||||
std::chrono::system_clock::time_point selectedTime_ {};
|
||||
|
||||
std::shared_ptr<const gl::draw::GeoLineDrawItem> lastHoverDi_ {nullptr};
|
||||
std::string tooltip_ {};
|
||||
|
||||
std::vector<boost::signals2::scoped_connection> connections_ {};
|
||||
};
|
||||
|
||||
AlertLayer::AlertLayer(std::shared_ptr<MapContext> context,
|
||||
|
|
@ -289,6 +308,15 @@ void AlertLayer::Deinitialize()
|
|||
DrawLayer::Deinitialize();
|
||||
}
|
||||
|
||||
bool IsAlertActive(const std::shared_ptr<const awips::Segment>& 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)
|
||||
{
|
||||
|
|
@ -331,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}];
|
||||
|
||||
|
|
@ -393,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(),
|
||||
|
|
@ -400,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()
|
||||
|
|
@ -439,14 +475,12 @@ 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_;
|
||||
|
||||
auto& lineColor = lineColor_.at(alertActive);
|
||||
auto& geoLines = geoLines_.at(alertActive);
|
||||
auto& lineData = GetLineData(segment, alertActive);
|
||||
auto& geoLines = geoLines_.at(alertActive);
|
||||
|
||||
const auto& coordinates = segment->codedLocation_->coordinates();
|
||||
|
||||
|
|
@ -462,30 +496,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);
|
||||
}
|
||||
}
|
||||
|
|
@ -499,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);
|
||||
|
||||
|
|
@ -590,6 +642,54 @@ void AlertLayer::Impl::AddLine(std::shared_ptr<gl::draw::GeoLines>& 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<gl::draw::GeoLineDrawItem>& di, QEvent* ev)
|
||||
{
|
||||
|
|
@ -638,6 +738,79 @@ 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<std::size_t>(lineSettings.border_width().GetValue()),
|
||||
.highlightWidth_ =
|
||||
static_cast<std::size_t>(lineSettings.highlight_width().GetValue()),
|
||||
.lineWidth_ =
|
||||
static_cast<std::size_t>(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());
|
||||
}
|
||||
|
||||
inactiveLineData_ = CreateLineData(alertPalette.inactive());
|
||||
}
|
||||
|
||||
AlertLayer::Impl::LineData& AlertLayer::Impl::GetLineData(
|
||||
const std::shared_ptr<const awips::Segment>& segment, bool alertActive)
|
||||
{
|
||||
if (!alertActive)
|
||||
{
|
||||
return inactiveLineData_;
|
||||
}
|
||||
|
||||
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_ {};
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
#include <scwx/util/strings.hpp>
|
||||
#include <scwx/util/time.hpp>
|
||||
|
||||
|
||||
#include <format>
|
||||
|
||||
#include <QApplication>
|
||||
|
|
@ -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<types::TextEventKey>>
|
||||
observedMap_;
|
||||
std::unordered_map<types::TextEventKey,
|
||||
awips::ThreatCategory,
|
||||
awips::ibw::ThreatCategory,
|
||||
types::TextEventHash<types::TextEventKey>>
|
||||
threatCategoryMap_;
|
||||
std::unordered_map<types::TextEventKey,
|
||||
|
|
@ -75,8 +74,8 @@ public:
|
|||
std::unordered_map<types::TextEventKey,
|
||||
double,
|
||||
types::TextEventHash<types::TextEventKey>>
|
||||
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<int>(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())
|
||||
|
|
|
|||
241
scwx-qt/source/scwx/qt/settings/alert_palette_settings.cpp
Normal file
241
scwx-qt/source/scwx/qt/settings/alert_palette_settings.cpp
Normal file
|
|
@ -0,0 +1,241 @@
|
|||
#include <scwx/qt/settings/alert_palette_settings.hpp>
|
||||
#include <scwx/qt/util/color.hpp>
|
||||
|
||||
#include <map>
|
||||
|
||||
#include <boost/algorithm/string/case_conv.hpp>
|
||||
#include <boost/gil.hpp>
|
||||
#include <boost/unordered/unordered_flat_map.hpp>
|
||||
|
||||
namespace scwx
|
||||
{
|
||||
namespace qt
|
||||
{
|
||||
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<awips::ibw::ThreatCategory, LineData>
|
||||
ThreatCategoryPalette;
|
||||
|
||||
static const boost::unordered_flat_map<awips::Phenomenon, ThreatCategoryPalette>
|
||||
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<awips::Phenomenon, LineData>
|
||||
kObservedPalettes_ //
|
||||
{{awips::Phenomenon::Tornado,
|
||||
{.highlightColor_ {255, 0, 0, 255},
|
||||
.lineColor_ {kColorBlack_},
|
||||
.highlightWidth_ = 1,
|
||||
.lineWidth_ = 1}}};
|
||||
|
||||
static const boost::unordered_flat_map<awips::Phenomenon, LineData>
|
||||
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<awips::Phenomenon, LineData>
|
||||
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}
|
||||
{
|
||||
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);
|
||||
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<awips::ibw::ThreatCategory, LineSettings> threatCategoryMap_ {};
|
||||
|
||||
LineSettings observed_ {"observed"};
|
||||
LineSettings tornadoPossible_ {"tornado_possible"};
|
||||
LineSettings inactive_ {"inactive"};
|
||||
};
|
||||
|
||||
AlertPaletteSettings::AlertPaletteSettings(awips::Phenomenon phenomenon) :
|
||||
SettingsCategory(awips::GetPhenomenonCode(phenomenon)),
|
||||
p(std::make_unique<Impl>(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_;
|
||||
}
|
||||
|
||||
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->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_);
|
||||
}
|
||||
|
||||
} // namespace settings
|
||||
} // namespace qt
|
||||
} // namespace scwx
|
||||
46
scwx-qt/source/scwx/qt/settings/alert_palette_settings.hpp
Normal file
46
scwx-qt/source/scwx/qt/settings/alert_palette_settings.hpp
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
#pragma once
|
||||
|
||||
#include <scwx/qt/settings/line_settings.hpp>
|
||||
#include <scwx/qt/settings/settings_category.hpp>
|
||||
#include <scwx/awips/impact_based_warnings.hpp>
|
||||
#include <scwx/awips/phenomenon.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
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<Impl> p;
|
||||
};
|
||||
|
||||
} // namespace settings
|
||||
} // namespace qt
|
||||
} // namespace scwx
|
||||
155
scwx-qt/source/scwx/qt/settings/line_settings.cpp
Normal file
155
scwx-qt/source/scwx/qt/settings/line_settings.cpp
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
#include <scwx/qt/settings/line_settings.hpp>
|
||||
#include <scwx/qt/util/color.hpp>
|
||||
|
||||
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<std::string> lineColor_ {"line_color"};
|
||||
SettingsVariable<std::string> highlightColor_ {"highlight_color"};
|
||||
SettingsVariable<std::string> borderColor_ {"border_color"};
|
||||
|
||||
SettingsVariable<std::int64_t> lineWidth_ {"line_width"};
|
||||
SettingsVariable<std::int64_t> highlightWidth_ {"highlight_width"};
|
||||
SettingsVariable<std::int64_t> borderWidth_ {"border_width"};
|
||||
};
|
||||
|
||||
LineSettings::LineSettings(const std::string& name) :
|
||||
SettingsCategory(name), p(std::make_unique<Impl>())
|
||||
{
|
||||
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<std::string>& LineSettings::border_color() const
|
||||
{
|
||||
return p->borderColor_;
|
||||
}
|
||||
|
||||
SettingsVariable<std::string>& LineSettings::highlight_color() const
|
||||
{
|
||||
return p->highlightColor_;
|
||||
}
|
||||
|
||||
SettingsVariable<std::string>& LineSettings::line_color() const
|
||||
{
|
||||
return p->lineColor_;
|
||||
}
|
||||
|
||||
SettingsVariable<std::int64_t>& LineSettings::border_width() const
|
||||
{
|
||||
return p->borderWidth_;
|
||||
}
|
||||
|
||||
SettingsVariable<std::int64_t>& LineSettings::highlight_width() const
|
||||
{
|
||||
return p->highlightWidth_;
|
||||
}
|
||||
|
||||
SettingsVariable<std::int64_t>& 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,
|
||||
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_ &&
|
||||
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
|
||||
58
scwx-qt/source/scwx/qt/settings/line_settings.hpp
Normal file
58
scwx-qt/source/scwx/qt/settings/line_settings.hpp
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
#pragma once
|
||||
|
||||
#include <scwx/qt/settings/settings_category.hpp>
|
||||
#include <scwx/qt/settings/settings_variable.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <boost/gil/typedefs.hpp>
|
||||
|
||||
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<std::string>& border_color() const;
|
||||
SettingsVariable<std::string>& highlight_color() const;
|
||||
SettingsVariable<std::string>& line_color() const;
|
||||
|
||||
SettingsVariable<std::int64_t>& border_width() const;
|
||||
SettingsVariable<std::int64_t>& highlight_width() const;
|
||||
SettingsVariable<std::int64_t>& 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,
|
||||
std::int64_t borderWidth,
|
||||
std::int64_t highlightWidth,
|
||||
std::int64_t lineWidth);
|
||||
|
||||
friend bool operator==(const LineSettings& lhs, const LineSettings& rhs);
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> p;
|
||||
};
|
||||
|
||||
} // namespace settings
|
||||
} // namespace qt
|
||||
} // namespace scwx
|
||||
|
|
@ -2,9 +2,9 @@
|
|||
#include <scwx/qt/settings/settings_variable.hpp>
|
||||
#include <scwx/qt/util/color.hpp>
|
||||
|
||||
#include <boost/algorithm/string/case_conv.hpp>
|
||||
#include <boost/gil.hpp>
|
||||
#include <fmt/format.h>
|
||||
#include <re2/re2.h>
|
||||
|
||||
namespace scwx
|
||||
{
|
||||
|
|
@ -76,59 +76,20 @@ static const awips::Phenomenon kDefaultPhenomenon_ {awips::Phenomenon::Marine};
|
|||
class PaletteSettings::Impl
|
||||
{
|
||||
public:
|
||||
explicit Impl()
|
||||
explicit Impl(PaletteSettings* self) : self_ {self}
|
||||
{
|
||||
palette_.reserve(kPaletteKeys_.size());
|
||||
|
||||
for (const auto& name : kPaletteKeys_)
|
||||
{
|
||||
const std::string& defaultValue = kDefaultPalettes_.at(name);
|
||||
|
||||
auto result =
|
||||
palette_.emplace(name, SettingsVariable<std::string> {name});
|
||||
|
||||
SettingsVariable<std::string>& 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<std::string> {activeName});
|
||||
auto inactiveResult = inactiveAlertColor_.emplace(
|
||||
alert.first, SettingsVariable<std::string> {inactiveName});
|
||||
|
||||
SettingsVariable<std::string>& activeVariable =
|
||||
activeResult.first->second;
|
||||
SettingsVariable<std::string>& 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);
|
||||
}
|
||||
InitializeColorTables();
|
||||
InitializeLegacyAlerts();
|
||||
InitializeAlerts();
|
||||
}
|
||||
|
||||
~Impl() {}
|
||||
|
||||
static bool ValidateColor(const std::string& value);
|
||||
void InitializeColorTables();
|
||||
void InitializeLegacyAlerts();
|
||||
void InitializeAlerts();
|
||||
|
||||
PaletteSettings* self_;
|
||||
|
||||
std::unordered_map<std::string, SettingsVariable<std::string>> palette_ {};
|
||||
std::unordered_map<awips::Phenomenon, SettingsVariable<std::string>>
|
||||
|
|
@ -136,16 +97,13 @@ public:
|
|||
std::unordered_map<awips::Phenomenon, SettingsVariable<std::string>>
|
||||
inactiveAlertColor_ {};
|
||||
std::vector<SettingsVariableBase*> variables_ {};
|
||||
|
||||
std::unordered_map<awips::Phenomenon, AlertPaletteSettings>
|
||||
alertPaletteMap_ {};
|
||||
};
|
||||
|
||||
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<Impl>())
|
||||
SettingsCategory("palette"), p(std::make_unique<Impl>(this))
|
||||
{
|
||||
RegisterVariables(p->variables_);
|
||||
SetDefaults();
|
||||
|
|
@ -158,6 +116,75 @@ 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<std::string> {name});
|
||||
|
||||
SettingsVariable<std::string>& 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<std::string> {activeName});
|
||||
auto inactiveResult = inactiveAlertColor_.emplace(
|
||||
alert.first, SettingsVariable<std::string> {inactiveName});
|
||||
|
||||
SettingsVariable<std::string>& activeVariable =
|
||||
activeResult.first->second;
|
||||
SettingsVariable<std::string>& inactiveVariable =
|
||||
inactiveResult.first->second;
|
||||
|
||||
activeVariable.SetDefault(util::color::ToArgbString(alert.second.first));
|
||||
inactiveVariable.SetDefault(
|
||||
util::color::ToArgbString(alert.second.second));
|
||||
|
||||
activeVariable.SetValidator(&util::color::ValidateArgbString);
|
||||
inactiveVariable.SetValidator(&util::color::ValidateArgbString);
|
||||
|
||||
variables_.push_back(&activeVariable);
|
||||
variables_.push_back(&inactiveVariable);
|
||||
}
|
||||
}
|
||||
|
||||
void PaletteSettings::Impl::InitializeAlerts()
|
||||
{
|
||||
std::vector<SettingsCategory*> alertSettings {};
|
||||
|
||||
for (auto phenomenon : PaletteSettings::alert_phenomena())
|
||||
{
|
||||
auto result = alertPaletteMap_.emplace(phenomenon, phenomenon);
|
||||
auto& it = result.first;
|
||||
AlertPaletteSettings& alertPaletteSettings = it->second;
|
||||
|
||||
// Variable registration
|
||||
alertSettings.push_back(&alertPaletteSettings);
|
||||
}
|
||||
|
||||
self_->RegisterSubcategoryArray("alerts", alertSettings);
|
||||
}
|
||||
|
||||
SettingsVariable<std::string>&
|
||||
PaletteSettings::palette(const std::string& name) const
|
||||
{
|
||||
|
|
@ -194,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<awips::Phenomenon>& PaletteSettings::alert_phenomena()
|
||||
{
|
||||
static const std::vector<awips::Phenomenon> kAlertPhenomena_ {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include <scwx/qt/settings/alert_palette_settings.hpp>
|
||||
#include <scwx/qt/settings/settings_category.hpp>
|
||||
#include <scwx/qt/settings/settings_variable.hpp>
|
||||
#include <scwx/awips/impact_based_warnings.hpp>
|
||||
#include <scwx/awips/phenomenon.hpp>
|
||||
|
||||
#include <memory>
|
||||
|
|
@ -29,6 +31,7 @@ public:
|
|||
SettingsVariable<std::string>& palette(const std::string& name) const;
|
||||
SettingsVariable<std::string>& alert_color(awips::Phenomenon phenomenon,
|
||||
bool active) const;
|
||||
AlertPaletteSettings& alert_palette(awips::Phenomenon);
|
||||
|
||||
static const std::vector<awips::Phenomenon>& alert_phenomena();
|
||||
|
||||
|
|
|
|||
|
|
@ -21,11 +21,21 @@ public:
|
|||
|
||||
~Impl() {}
|
||||
|
||||
void ConnectSubcategory(SettingsCategory& category);
|
||||
void ConnectVariable(SettingsVariableBase* variable);
|
||||
|
||||
const std::string name_;
|
||||
|
||||
std::vector<std::pair<std::string, std::vector<SettingsCategory*>>>
|
||||
subcategoryArrays_;
|
||||
std::vector<SettingsCategory*> subcategories_;
|
||||
std::vector<SettingsVariableBase*> variables_;
|
||||
|
||||
boost::signals2::signal<void()> changedSignal_ {};
|
||||
boost::signals2::signal<void()> stagedSignal_ {};
|
||||
bool blockSignals_ {false};
|
||||
|
||||
std::vector<boost::signals2::scoped_connection> connections_ {};
|
||||
};
|
||||
|
||||
SettingsCategory::SettingsCategory(const std::string& name) :
|
||||
|
|
@ -38,13 +48,88 @@ 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_;
|
||||
}
|
||||
|
||||
boost::signals2::signal<void()>& SettingsCategory::changed_signal()
|
||||
{
|
||||
return p->changedSignal_;
|
||||
}
|
||||
|
||||
boost::signals2::signal<void()>& 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_)
|
||||
{
|
||||
|
|
@ -54,11 +139,129 @@ void SettingsCategory::SetDefaults()
|
|||
}
|
||||
}
|
||||
|
||||
// Set subcategory defaults
|
||||
for (auto& subcategory : p->subcategories_)
|
||||
{
|
||||
subcategory->SetDefaults();
|
||||
}
|
||||
|
||||
// Set variable defaults
|
||||
for (auto& variable : p->variables_)
|
||||
{
|
||||
variable->SetValueToDefault();
|
||||
}
|
||||
|
||||
// Unblock signals
|
||||
p->blockSignals_ = false;
|
||||
|
||||
p->changedSignal_();
|
||||
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;
|
||||
|
||||
// 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_)
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
// 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_)
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
// Unblock signals
|
||||
p->blockSignals_ = false;
|
||||
|
||||
p->stagedSignal_();
|
||||
}
|
||||
|
||||
bool SettingsCategory::ReadJson(const boost::json::object& json)
|
||||
|
|
@ -111,6 +314,12 @@ bool SettingsCategory::ReadJson(const boost::json::object& json)
|
|||
}
|
||||
}
|
||||
|
||||
// Read subcategories
|
||||
for (auto& subcategory : p->subcategories_)
|
||||
{
|
||||
validated &= subcategory->ReadJson(object);
|
||||
}
|
||||
|
||||
// Read variables
|
||||
for (auto& variable : p->variables_)
|
||||
{
|
||||
|
|
@ -154,6 +363,12 @@ void SettingsCategory::WriteJson(boost::json::object& json) const
|
|||
object.insert_or_assign(subcategoryArray.first, arrayObject);
|
||||
}
|
||||
|
||||
// Write subcategories
|
||||
for (auto& subcategory : p->subcategories_)
|
||||
{
|
||||
subcategory->WriteJson(object);
|
||||
}
|
||||
|
||||
// Write variables
|
||||
for (auto& variable : p->variables_)
|
||||
{
|
||||
|
|
@ -163,6 +378,12 @@ void SettingsCategory::WriteJson(boost::json::object& json) const
|
|||
json.insert_or_assign(p->name_, object);
|
||||
}
|
||||
|
||||
void SettingsCategory::RegisterSubcategory(SettingsCategory& subcategory)
|
||||
{
|
||||
p->ConnectSubcategory(subcategory);
|
||||
p->subcategories_.push_back(&subcategory);
|
||||
}
|
||||
|
||||
void SettingsCategory::RegisterSubcategoryArray(
|
||||
const std::string& name, std::vector<SettingsCategory>& subcategories)
|
||||
{
|
||||
|
|
@ -172,22 +393,92 @@ 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(
|
||||
const std::string& name, std::vector<SettingsCategory*>& subcategories)
|
||||
{
|
||||
auto& newSubcategories = p->subcategoryArrays_.emplace_back(
|
||||
name, std::vector<SettingsCategory*> {});
|
||||
|
||||
std::transform(subcategories.begin(),
|
||||
subcategories.end(),
|
||||
std::back_inserter(newSubcategories.second),
|
||||
[this](SettingsCategory* subcategory)
|
||||
{
|
||||
p->ConnectSubcategory(*subcategory);
|
||||
return subcategory;
|
||||
});
|
||||
}
|
||||
|
||||
void SettingsCategory::RegisterVariables(
|
||||
std::initializer_list<SettingsVariableBase*> variables)
|
||||
{
|
||||
for (auto& variable : variables)
|
||||
{
|
||||
p->ConnectVariable(variable);
|
||||
}
|
||||
p->variables_.insert(p->variables_.end(), variables);
|
||||
}
|
||||
|
||||
void SettingsCategory::RegisterVariables(
|
||||
std::vector<SettingsVariableBase*> variables)
|
||||
{
|
||||
for (auto& variable : variables)
|
||||
{
|
||||
p->ConnectVariable(variable);
|
||||
}
|
||||
p->variables_.insert(
|
||||
p->variables_.end(), variables.cbegin(), variables.cend());
|
||||
}
|
||||
|
||||
void SettingsCategory::Impl::ConnectSubcategory(SettingsCategory& category)
|
||||
{
|
||||
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
|
||||
} // namespace qt
|
||||
} // namespace scwx
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include <string>
|
||||
|
||||
#include <boost/json/object.hpp>
|
||||
#include <boost/signals2/signal.hpp>
|
||||
|
||||
namespace scwx
|
||||
{
|
||||
|
|
@ -28,11 +29,61 @@ public:
|
|||
|
||||
std::string name() const;
|
||||
|
||||
/**
|
||||
* Gets the signal invoked when a variable within the category is changed.
|
||||
*
|
||||
* @return Changed signal
|
||||
*/
|
||||
boost::signals2::signal<void()>& changed_signal();
|
||||
|
||||
/**
|
||||
* Gets the signal invoked when a variable within the category is staged.
|
||||
*
|
||||
* @return Staged signal
|
||||
*/
|
||||
boost::signals2::signal<void()>& 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.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
|
|
@ -50,12 +101,18 @@ public:
|
|||
*/
|
||||
virtual void WriteJson(boost::json::object& json) const;
|
||||
|
||||
void RegisterSubcategory(SettingsCategory& subcategory);
|
||||
void RegisterSubcategoryArray(const std::string& name,
|
||||
std::vector<SettingsCategory>& subcategories);
|
||||
void RegisterSubcategoryArray(const std::string& name,
|
||||
std::vector<SettingsCategory*>& subcategories);
|
||||
void
|
||||
RegisterVariables(std::initializer_list<SettingsVariableBase*> variables);
|
||||
void RegisterVariables(std::vector<SettingsVariableBase*> variables);
|
||||
|
||||
protected:
|
||||
void set_block_signals(bool blockSignals);
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> p;
|
||||
|
|
|
|||
|
|
@ -65,6 +65,18 @@ inline auto FormatParameter(const T& value)
|
|||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool SettingsVariable<T>::IsDefault() const
|
||||
{
|
||||
return p->value_ == p->default_;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool SettingsVariable<T>::IsDefaultStaged() const
|
||||
{
|
||||
return p->staged_.value_or(p->value_) == p->default_;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
T SettingsVariable<T>::GetValue() const
|
||||
{
|
||||
|
|
@ -81,10 +93,13 @@ bool SettingsVariable<T>::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 +144,13 @@ bool SettingsVariable<T>::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 +164,13 @@ void SettingsVariable<T>::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 +189,7 @@ void SettingsVariable<T>::StageDefault()
|
|||
p->staged_.reset();
|
||||
}
|
||||
|
||||
staged_signal()();
|
||||
for (auto& callback : p->valueStagedCallbackFunctions_)
|
||||
{
|
||||
callback.second(p->default_);
|
||||
|
|
@ -194,6 +216,7 @@ bool SettingsVariable<T>::StageValue(const T& value)
|
|||
|
||||
validated = true;
|
||||
|
||||
staged_signal()();
|
||||
for (auto& callback : p->valueStagedCallbackFunctions_)
|
||||
{
|
||||
callback.second(transformed);
|
||||
|
|
@ -214,10 +237,13 @@ bool SettingsVariable<T>::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 +258,7 @@ void SettingsVariable<T>::Reset()
|
|||
{
|
||||
p->staged_.reset();
|
||||
|
||||
staged_signal()();
|
||||
for (auto& callback : p->valueStagedCallbackFunctions_)
|
||||
{
|
||||
callback.second(p->value_);
|
||||
|
|
@ -336,10 +363,13 @@ bool SettingsVariable<T>::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_);
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ public:
|
|||
typedef std::function<void(const T& value)> ValueCallbackFunction;
|
||||
|
||||
explicit SettingsVariable(const std::string& name);
|
||||
~SettingsVariable();
|
||||
virtual ~SettingsVariable();
|
||||
|
||||
SettingsVariable(const SettingsVariable&) = delete;
|
||||
SettingsVariable& operator=(const SettingsVariable&) = delete;
|
||||
|
|
@ -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 override;
|
||||
|
||||
/**
|
||||
* 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 override;
|
||||
|
||||
/**
|
||||
* Gets the current value of the settings variable.
|
||||
*
|
||||
|
|
@ -96,7 +114,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.
|
||||
|
|
|
|||
|
|
@ -18,6 +18,9 @@ public:
|
|||
~Impl() {}
|
||||
|
||||
const std::string name_;
|
||||
|
||||
boost::signals2::signal<void()> changedSignal_ {};
|
||||
boost::signals2::signal<void()> stagedSignal_ {};
|
||||
};
|
||||
|
||||
SettingsVariableBase::SettingsVariableBase(const std::string& name) :
|
||||
|
|
@ -38,6 +41,16 @@ std::string SettingsVariableBase::name() const
|
|||
return p->name_;
|
||||
}
|
||||
|
||||
boost::signals2::signal<void()>& SettingsVariableBase::changed_signal()
|
||||
{
|
||||
return p->changedSignal_;
|
||||
}
|
||||
|
||||
boost::signals2::signal<void()>& SettingsVariableBase::staged_signal()
|
||||
{
|
||||
return p->stagedSignal_;
|
||||
}
|
||||
|
||||
bool SettingsVariableBase::Equals(const SettingsVariableBase& o) const
|
||||
{
|
||||
return p->name_ == o.p->name_;
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#include <string>
|
||||
|
||||
#include <boost/json/object.hpp>
|
||||
#include <boost/signals2/signal.hpp>
|
||||
|
||||
namespace scwx
|
||||
{
|
||||
|
|
@ -19,7 +20,7 @@ class SettingsVariableBase
|
|||
{
|
||||
protected:
|
||||
explicit SettingsVariableBase(const std::string& name);
|
||||
~SettingsVariableBase();
|
||||
virtual ~SettingsVariableBase();
|
||||
|
||||
public:
|
||||
SettingsVariableBase(const SettingsVariableBase&) = delete;
|
||||
|
|
@ -30,6 +31,38 @@ public:
|
|||
|
||||
std::string name() const;
|
||||
|
||||
/**
|
||||
* Gets the signal invoked when the settings variable is changed.
|
||||
*
|
||||
* @return Changed signal
|
||||
*/
|
||||
boost::signals2::signal<void()>& changed_signal();
|
||||
|
||||
/**
|
||||
* Gets the signal invoked when the settings variable is staged.
|
||||
*
|
||||
* @return Staged signal
|
||||
*/
|
||||
boost::signals2::signal<void()>& 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.
|
||||
*/
|
||||
|
|
@ -48,6 +81,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
|
||||
|
|
|
|||
316
scwx-qt/source/scwx/qt/ui/edit_line_dialog.cpp
Normal file
316
scwx-qt/source/scwx/qt/ui/edit_line_dialog.cpp
Normal file
|
|
@ -0,0 +1,316 @@
|
|||
#include "edit_line_dialog.hpp"
|
||||
#include "ui_edit_line_dialog.h"
|
||||
|
||||
#include <scwx/qt/ui/line_label.hpp>
|
||||
#include <scwx/qt/util/color.hpp>
|
||||
#include <scwx/util/logger.hpp>
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <QColorDialog>
|
||||
|
||||
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, false);
|
||||
});
|
||||
|
||||
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,
|
||||
bool updateLineEdit = true);
|
||||
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<Impl>(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<QHBoxLayout*>(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,
|
||||
bool updateLineEdit)
|
||||
{
|
||||
const std::string argbString {util::color::ToArgbString(color)};
|
||||
|
||||
component.color_ = color;
|
||||
SetBackgroundColor(argbString, component.colorFrame_);
|
||||
|
||||
if (updateLineEdit)
|
||||
{
|
||||
component.colorLineEdit_->setText(QString::fromStdString(argbString));
|
||||
}
|
||||
|
||||
UpdateLineLabel();
|
||||
}
|
||||
|
||||
void EditLineDialog::Impl::set_width(EditComponent& component,
|
||||
std::size_t width)
|
||||
{
|
||||
component.width_ = width;
|
||||
component.widthSpinBox_->setValue(static_cast<int>(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
|
||||
59
scwx-qt/source/scwx/qt/ui/edit_line_dialog.hpp
Normal file
59
scwx-qt/source/scwx/qt/ui/edit_line_dialog.hpp
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
#pragma once
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
#include <boost/gil/typedefs.hpp>
|
||||
|
||||
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<Impl> p;
|
||||
Ui::EditLineDialog* ui;
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
} // namespace qt
|
||||
} // namespace scwx
|
||||
306
scwx-qt/source/scwx/qt/ui/edit_line_dialog.ui
Normal file
306
scwx-qt/source/scwx/qt/ui/edit_line_dialog.ui
Normal file
|
|
@ -0,0 +1,306 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>EditLineDialog</class>
|
||||
<widget class="QDialog" name="EditLineDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>350</width>
|
||||
<height>225</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Edit Line</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="componentLabel">
|
||||
<property name="font">
|
||||
<font>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Component</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QLineEdit" name="highlightColorLineEdit">
|
||||
<property name="text">
|
||||
<string>#ff000000</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="4">
|
||||
<widget class="QSpinBox" name="borderWidthSpinBox">
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>9</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QToolButton" name="lineColorButton">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../../scwx-qt.qrc">
|
||||
<normaloff>:/res/icons/font-awesome-6/palette-solid.svg</normaloff>:/res/icons/font-awesome-6/palette-solid.svg</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="3">
|
||||
<widget class="QToolButton" name="borderColorButton">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../../scwx-qt.qrc">
|
||||
<normaloff>:/res/icons/font-awesome-6/palette-solid.svg</normaloff>:/res/icons/font-awesome-6/palette-solid.svg</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="borderLabel">
|
||||
<property name="text">
|
||||
<string>Border</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QLineEdit" name="lineColorLineEdit">
|
||||
<property name="text">
|
||||
<string>#ff000000</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="lineLabel">
|
||||
<property name="text">
|
||||
<string>Line</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0" colspan="5">
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok|QDialogButtonBox::StandardButton::Reset</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QFrame" name="lineColorFrame">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Shape::Box</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Shadow::Plain</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="4">
|
||||
<widget class="QSpinBox" name="highlightWidthSpinBox">
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>9</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QFrame" name="highlightColorFrame">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Shape::Box</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Shadow::Plain</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" colspan="3">
|
||||
<widget class="QLabel" name="colorLabel">
|
||||
<property name="font">
|
||||
<font>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Color</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QLineEdit" name="borderColorLineEdit">
|
||||
<property name="text">
|
||||
<string>#ff000000</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QFrame" name="borderColorFrame">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Shape::Box</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Shadow::Plain</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="4">
|
||||
<widget class="QLabel" name="widthLabel">
|
||||
<property name="font">
|
||||
<font>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Width</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="4">
|
||||
<widget class="QSpinBox" name="lineWidthSpinBox">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>9</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="highlightLabel">
|
||||
<property name="text">
|
||||
<string>Highlight</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="3">
|
||||
<widget class="QToolButton" name="highlightColorButton">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../../scwx-qt.qrc">
|
||||
<normaloff>:/res/icons/font-awesome-6/palette-solid.svg</normaloff>:/res/icons/font-awesome-6/palette-solid.svg</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0" colspan="5">
|
||||
<widget class="QWidget" name="lineLabelContainer" native="true">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>45</height>
|
||||
</size>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="../../../../scwx-qt.qrc"/>
|
||||
</resources>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>EditLineDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>EditLineDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
239
scwx-qt/source/scwx/qt/ui/line_label.cpp
Normal file
239
scwx-qt/source/scwx/qt/ui/line_label.cpp
Normal file
|
|
@ -0,0 +1,239 @@
|
|||
#include <scwx/qt/ui/line_label.hpp>
|
||||
#include <scwx/qt/util/color.hpp>
|
||||
#include <scwx/util/logger.hpp>
|
||||
|
||||
#include <QEvent>
|
||||
#include <QPainter>
|
||||
|
||||
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(LineLabel* self) : self_ {self} {};
|
||||
~Impl() = default;
|
||||
|
||||
QImage GenerateImage() const;
|
||||
void UpdateLineLabel(const settings::LineSettings& lineSettings);
|
||||
|
||||
LineLabel* self_;
|
||||
|
||||
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};
|
||||
|
||||
boost::signals2::scoped_connection settingsStaged_ {};
|
||||
};
|
||||
|
||||
LineLabel::LineLabel(QWidget* parent) :
|
||||
QFrame(parent), p {std::make_unique<Impl>(this)}
|
||||
{
|
||||
}
|
||||
|
||||
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;
|
||||
p->pixmapDirty_ = true;
|
||||
updateGeometry();
|
||||
update();
|
||||
}
|
||||
|
||||
void LineLabel::set_highlight_width(std::size_t width)
|
||||
{
|
||||
p->highlightWidth_ = width;
|
||||
p->pixmapDirty_ = true;
|
||||
updateGeometry();
|
||||
update();
|
||||
}
|
||||
|
||||
void LineLabel::set_line_width(std::size_t width)
|
||||
{
|
||||
p->lineWidth_ = width;
|
||||
p->pixmapDirty_ = true;
|
||||
updateGeometry();
|
||||
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();
|
||||
}
|
||||
|
||||
void LineLabel::set_line_settings(settings::LineSettings& lineSettings)
|
||||
{
|
||||
p->settingsStaged_ = lineSettings.staged_signal().connect(
|
||||
[this, &lineSettings]() { p->UpdateLineLabel(lineSettings); });
|
||||
|
||||
p->UpdateLineLabel(lineSettings);
|
||||
}
|
||||
|
||||
void LineLabel::Impl::UpdateLineLabel(
|
||||
const settings::LineSettings& lineSettings)
|
||||
{
|
||||
self_->set_border_color(util::color::ToRgba8PixelT(
|
||||
lineSettings.border_color().GetStagedOrValue()));
|
||||
self_->set_highlight_color(util::color::ToRgba8PixelT(
|
||||
lineSettings.highlight_color().GetStagedOrValue()));
|
||||
self_->set_line_color(
|
||||
util::color::ToRgba8PixelT(lineSettings.line_color().GetStagedOrValue()));
|
||||
|
||||
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
|
||||
{
|
||||
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<int>(width) + margins.left() + margins.right(),
|
||||
static_cast<int>(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<int>(borderColor_[0]),
|
||||
static_cast<int>(borderColor_[1]),
|
||||
static_cast<int>(borderColor_[2]),
|
||||
static_cast<int>(borderColor_[3]));
|
||||
const QRgb highlightRgba = qRgba(static_cast<int>(highlightColor_[0]),
|
||||
static_cast<int>(highlightColor_[1]),
|
||||
static_cast<int>(highlightColor_[2]),
|
||||
static_cast<int>(highlightColor_[3]));
|
||||
const QRgb lineRgba = qRgba(static_cast<int>(lineColor_[0]),
|
||||
static_cast<int>(lineColor_[1]),
|
||||
static_cast<int>(lineColor_[2]),
|
||||
static_cast<int>(lineColor_[3]));
|
||||
|
||||
const std::size_t width = 1;
|
||||
const std::size_t height = (borderWidth_ + highlightWidth_) * 2 + lineWidth_;
|
||||
|
||||
QImage image(static_cast<int>(width),
|
||||
static_cast<int>(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<int>(y), borderRgba);
|
||||
image.setPixel(0, static_cast<int>(height - 1 - y), borderRgba);
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < highlightWidth_; ++i, ++y)
|
||||
{
|
||||
image.setPixel(0, static_cast<int>(y), highlightRgba);
|
||||
image.setPixel(0, static_cast<int>(height - 1 - y), highlightRgba);
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < lineWidth_; ++i, ++y)
|
||||
{
|
||||
image.setPixel(0, static_cast<int>(y), lineRgba);
|
||||
image.setPixel(0, static_cast<int>(height - 1 - y), lineRgba);
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
} // namespace ui
|
||||
} // namespace qt
|
||||
} // namespace scwx
|
||||
55
scwx-qt/source/scwx/qt/ui/line_label.hpp
Normal file
55
scwx-qt/source/scwx/qt/ui/line_label.hpp
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
#pragma once
|
||||
|
||||
#include <scwx/qt/settings/line_settings.hpp>
|
||||
|
||||
#include <QFrame>
|
||||
|
||||
#include <boost/gil/typedefs.hpp>
|
||||
|
||||
namespace scwx
|
||||
{
|
||||
namespace qt
|
||||
{
|
||||
namespace ui
|
||||
{
|
||||
|
||||
class LineLabel : public QFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY_MOVE(LineLabel)
|
||||
|
||||
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);
|
||||
|
||||
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 set_line_settings(settings::LineSettings& lineSettings);
|
||||
|
||||
protected:
|
||||
QSize minimumSizeHint() const override;
|
||||
QSize sizeHint() const override;
|
||||
void paintEvent(QPaintEvent* e) override;
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> p;
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
} // namespace qt
|
||||
} // namespace scwx
|
||||
|
|
@ -0,0 +1,292 @@
|
|||
#include <scwx/qt/ui/settings/alert_palette_settings_widget.hpp>
|
||||
#include <scwx/qt/ui/edit_line_dialog.hpp>
|
||||
#include <scwx/qt/ui/line_label.hpp>
|
||||
#include <scwx/qt/settings/palette_settings.hpp>
|
||||
#include <scwx/awips/impact_based_warnings.hpp>
|
||||
#include <scwx/awips/phenomenon.hpp>
|
||||
|
||||
#include <boost/unordered/unordered_flat_map.hpp>
|
||||
#include <QGridLayout>
|
||||
#include <QLabel>
|
||||
#include <QListWidget>
|
||||
#include <QStackedWidget>
|
||||
#include <QToolButton>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include <boost/signals2.hpp>
|
||||
|
||||
namespace scwx
|
||||
{
|
||||
namespace qt
|
||||
{
|
||||
namespace ui
|
||||
{
|
||||
|
||||
static const std::string logPrefix_ =
|
||||
"scwx::qt::ui::settings::alert_palette_settings_widget";
|
||||
|
||||
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() {};
|
||||
|
||||
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);
|
||||
void SetupUi();
|
||||
|
||||
AlertPaletteSettingsWidget* self_;
|
||||
|
||||
QStackedWidget* phenomenonPagesWidget_;
|
||||
QListWidget* phenomenonListView_;
|
||||
|
||||
EditLineDialog* editLineDialog_;
|
||||
settings::LineSettings* activeLineSettings_ {nullptr};
|
||||
|
||||
boost::unordered_flat_map<awips::Phenomenon, QWidget*> phenomenonPages_ {};
|
||||
|
||||
std::vector<boost::signals2::scoped_connection> connections_ {};
|
||||
};
|
||||
|
||||
AlertPaletteSettingsWidget::AlertPaletteSettingsWidget(QWidget* parent) :
|
||||
SettingsPageWidget(parent), p {std::make_shared<Impl>(this)}
|
||||
{
|
||||
}
|
||||
|
||||
AlertPaletteSettingsWidget::~AlertPaletteSettingsWidget() = default;
|
||||
|
||||
void AlertPaletteSettingsWidget::Impl::SetupUi()
|
||||
{
|
||||
// Setup phenomenon index pane
|
||||
QLabel* phenomenonLabel = new QLabel(tr("Phenomenon:"), self_);
|
||||
phenomenonPagesWidget_->setSizePolicy(QSizePolicy::Policy::MinimumExpanding,
|
||||
QSizePolicy::Policy::Preferred);
|
||||
|
||||
// Setup stacked widget
|
||||
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);
|
||||
|
||||
// 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()
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
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());
|
||||
|
||||
// Reset the active line settings
|
||||
activeLineSettings_ = nullptr;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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& 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",
|
||||
alertPalette.threat_category(awips::ibw::ThreatCategory::Base),
|
||||
gridLayout,
|
||||
row++);
|
||||
|
||||
if (impactBasedWarningInfo.hasObservedTag_)
|
||||
{
|
||||
AddPhenomenonLine("Observed", alertPalette.observed(), gridLayout, row++);
|
||||
}
|
||||
|
||||
if (impactBasedWarningInfo.hasTornadoPossibleTag_)
|
||||
{
|
||||
AddPhenomenonLine("Tornado Possible",
|
||||
alertPalette.tornado_possible(),
|
||||
gridLayout,
|
||||
row++);
|
||||
}
|
||||
|
||||
for (auto& category : impactBasedWarningInfo.threatCategories_)
|
||||
{
|
||||
if (category == awips::ibw::ThreatCategory::Base)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
AddPhenomenonLine(awips::ibw::GetThreatCategoryName(category),
|
||||
alertPalette.threat_category(category),
|
||||
gridLayout,
|
||||
row++);
|
||||
}
|
||||
|
||||
AddPhenomenonLine("Inactive", alertPalette.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,
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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_->Initialize(lineLabel->border_color(),
|
||||
lineLabel->highlight_color(),
|
||||
lineLabel->line_color(),
|
||||
lineLabel->border_width(),
|
||||
lineLabel->highlight_width(),
|
||||
lineLabel->line_width());
|
||||
|
||||
// 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
|
||||
} // namespace qt
|
||||
} // namespace scwx
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
#pragma once
|
||||
|
||||
#include <scwx/qt/ui/settings/settings_page_widget.hpp>
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
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<Impl> p;
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
} // namespace qt
|
||||
} // namespace scwx
|
||||
|
|
@ -19,6 +19,7 @@ public:
|
|||
explicit Impl() {}
|
||||
~Impl() = default;
|
||||
|
||||
std::vector<settings::SettingsCategory*> categories_;
|
||||
std::vector<settings::SettingsInterfaceBase*> 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();
|
||||
|
|
@ -49,6 +61,11 @@ bool SettingsPageWidget::CommitChanges()
|
|||
|
||||
void SettingsPageWidget::DiscardChanges()
|
||||
{
|
||||
for (auto& category : p->categories_)
|
||||
{
|
||||
category->Reset();
|
||||
}
|
||||
|
||||
for (auto& setting : p->settings_)
|
||||
{
|
||||
setting->Reset();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <scwx/qt/settings/settings_category.hpp>
|
||||
#include <scwx/qt/settings/settings_interface_base.hpp>
|
||||
|
||||
#include <QWidget>
|
||||
|
|
@ -61,6 +62,15 @@ public:
|
|||
protected:
|
||||
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<Impl> p;
|
||||
|
|
|
|||
|
|
@ -23,11 +23,12 @@
|
|||
#include <scwx/qt/types/time_types.hpp>
|
||||
#include <scwx/qt/types/unit_types.hpp>
|
||||
#include <scwx/qt/ui/county_dialog.hpp>
|
||||
#include <scwx/qt/ui/wfo_dialog.hpp>
|
||||
#include <scwx/qt/ui/radar_site_dialog.hpp>
|
||||
#include <scwx/qt/ui/serial_port_dialog.hpp>
|
||||
#include <scwx/qt/ui/settings/alert_palette_settings_widget.hpp>
|
||||
#include <scwx/qt/ui/settings/hotkey_settings_widget.hpp>
|
||||
#include <scwx/qt/ui/settings/unit_settings_widget.hpp>
|
||||
#include <scwx/qt/ui/wfo_dialog.hpp>
|
||||
#include <scwx/qt/util/color.hpp>
|
||||
#include <scwx/qt/util/file.hpp>
|
||||
#include <scwx/util/logger.hpp>
|
||||
|
|
@ -181,7 +182,6 @@ public:
|
|||
void SetupTextTab();
|
||||
void SetupHotkeysTab();
|
||||
|
||||
void ShowColorDialog(QLineEdit* lineEdit);
|
||||
void UpdateRadarDialogLocation(const std::string& id);
|
||||
void UpdateAlertRadarDialogLocation(const std::string& id);
|
||||
|
||||
|
|
@ -203,8 +203,7 @@ public:
|
|||
const std::string& value,
|
||||
QLabel* imageLabel);
|
||||
static std::string
|
||||
RadarSiteLabel(std::shared_ptr<config::RadarSite>& radarSite);
|
||||
static void SetBackgroundColor(const std::string& value, QFrame* frame);
|
||||
RadarSiteLabel(std::shared_ptr<config::RadarSite>& radarSite);
|
||||
|
||||
SettingsDialog* self_;
|
||||
RadarSiteDialog* radarSiteDialog_;
|
||||
|
|
@ -224,6 +223,7 @@ public:
|
|||
manager::PositionManager::Instance()};
|
||||
|
||||
std::vector<SettingsPageWidget*> settingsPages_ {};
|
||||
AlertPaletteSettingsWidget* alertPaletteSettingsWidget_ {};
|
||||
HotkeySettingsWidget* hotkeySettingsWidget_ {};
|
||||
UnitSettingsWidget* unitSettingsWidget_ {};
|
||||
|
||||
|
|
@ -252,12 +252,6 @@ public:
|
|||
|
||||
std::unordered_map<std::string, settings::SettingsInterface<std::string>>
|
||||
colorTables_ {};
|
||||
std::unordered_map<awips::Phenomenon,
|
||||
settings::SettingsInterface<std::string>>
|
||||
activeAlertColors_ {};
|
||||
std::unordered_map<awips::Phenomenon,
|
||||
settings::SettingsInterface<std::string>>
|
||||
inactiveAlertColors_ {};
|
||||
|
||||
settings::SettingsInterface<std::string> alertAudioSoundFile_ {};
|
||||
settings::SettingsInterface<std::string> alertAudioLocationMethod_ {};
|
||||
|
|
@ -358,24 +352,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<config::RadarSite> radarSite =
|
||||
config::RadarSite::Get(id);
|
||||
std::shared_ptr<config::RadarSite> 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,
|
||||
|
|
@ -803,123 +796,14 @@ void SettingsDialogImpl::SetupPalettesColorTablesTab()
|
|||
|
||||
void SettingsDialogImpl::SetupPalettesAlertsTab()
|
||||
{
|
||||
settings::PaletteSettings& paletteSettings =
|
||||
settings::PaletteSettings::Instance();
|
||||
|
||||
// Palettes > Alerts
|
||||
QGridLayout* alertsLayout =
|
||||
reinterpret_cast<QGridLayout*>(self_->ui->alertsFrame->layout());
|
||||
QVBoxLayout* layout = new QVBoxLayout(self_->ui->alertsPalette);
|
||||
|
||||
QLabel* phenomenonLabel = new QLabel(QObject::tr("Phenomenon"), self_);
|
||||
QLabel* activeLabel = new QLabel(QObject::tr("Active"), self_);
|
||||
QLabel* inactiveLabel = new QLabel(QObject::tr("Inactive"), self_);
|
||||
alertPaletteSettingsWidget_ =
|
||||
new AlertPaletteSettingsWidget(self_->ui->hotkeys);
|
||||
layout->addWidget(alertPaletteSettingsWidget_);
|
||||
|
||||
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<std::string> {});
|
||||
auto inactiveResult = inactiveAlertColors_.emplace(
|
||||
phenomenon, settings::SettingsInterface<std::string> {});
|
||||
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); });
|
||||
}
|
||||
settingsPages_.push_back(alertPaletteSettingsWidget_);
|
||||
}
|
||||
|
||||
void SettingsDialogImpl::SetupUnitsTab()
|
||||
|
|
@ -953,8 +837,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);
|
||||
|
|
@ -972,10 +855,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(
|
||||
|
|
@ -1091,8 +972,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)
|
||||
{
|
||||
|
|
@ -1206,14 +1086,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_,
|
||||
|
|
@ -1232,9 +1108,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));
|
||||
});
|
||||
|
|
@ -1242,7 +1117,6 @@ void SettingsDialogImpl::SetupAudioTab()
|
|||
alertAudioWFO_.SetSettingsVariable(audioSettings.alert_wfo());
|
||||
alertAudioWFO_.SetEditWidget(self_->ui->alertAudioWFOLineEdit);
|
||||
alertAudioWFO_.SetResetButton(self_->ui->resetAlertAudioWFOButton);
|
||||
|
||||
}
|
||||
|
||||
void SettingsDialogImpl::SetupTextTab()
|
||||
|
|
@ -1384,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<config::RadarSite> radarSite = config::RadarSite::Get(id);
|
||||
|
|
@ -1444,8 +1280,6 @@ void SettingsDialogImpl::UpdateAlertRadarDialogLocation(const std::string& id)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
QFont SettingsDialogImpl::GetSelectedFont()
|
||||
{
|
||||
std::string fontFamily = fontFamilies_.at(selectedFontCategory_)
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@
|
|||
</sizepolicy>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>3</number>
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="general">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
|
|
@ -136,8 +136,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>274</width>
|
||||
<height>691</height>
|
||||
<width>513</width>
|
||||
<height>622</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
|
|
@ -610,8 +610,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>98</width>
|
||||
<height>28</height>
|
||||
<width>506</width>
|
||||
<height>383</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
|
|
@ -634,49 +634,10 @@
|
|||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_2">
|
||||
<widget class="QWidget" name="alertsPalette">
|
||||
<attribute name="title">
|
||||
<string>Alerts</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QFrame" name="alertsFrame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Shape::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Shadow::Raised</enum>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_5">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>239</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include <scwx/qt/util/color.hpp>
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <re2/re2.h>
|
||||
#include <QColor>
|
||||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 20a1ca1752499222d33869e37148321936ca6354
|
||||
Subproject commit 40a367ca89b5b197353ca58dea547a3e3407c7f3
|
||||
|
|
@ -1,11 +1,16 @@
|
|||
#pragma once
|
||||
|
||||
#include <scwx/awips/phenomenon.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace scwx
|
||||
{
|
||||
namespace awips
|
||||
{
|
||||
namespace ibw
|
||||
{
|
||||
|
||||
enum class ThreatCategory : int
|
||||
{
|
||||
|
|
@ -17,8 +22,18 @@ enum class ThreatCategory : int
|
|||
Unknown
|
||||
};
|
||||
|
||||
struct ImpactBasedWarningInfo
|
||||
{
|
||||
bool hasObservedTag_ {false};
|
||||
bool hasTornadoPossibleTag_ {false};
|
||||
std::vector<ThreatCategory> threatCategories_ {ThreatCategory::Base};
|
||||
};
|
||||
|
||||
const ImpactBasedWarningInfo& GetImpactBasedWarningInfo(Phenomenon phenomenon);
|
||||
|
||||
ThreatCategory GetThreatCategory(const std::string& name);
|
||||
const std::string& GetThreatCategoryName(ThreatCategory threatCategory);
|
||||
|
||||
} // namespace ibw
|
||||
} // namespace awips
|
||||
} // namespace scwx
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -64,9 +64,9 @@ struct Segment
|
|||
std::optional<CodedLocation> codedLocation_ {};
|
||||
std::optional<CodedTimeMotionLocation> 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;
|
||||
|
||||
|
|
|
|||
|
|
@ -4,13 +4,40 @@
|
|||
#include <unordered_map>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/unordered/unordered_flat_map.hpp>
|
||||
|
||||
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<Phenomenon, ImpactBasedWarningInfo>
|
||||
impactBasedWarningInfo_ {
|
||||
{Phenomenon::Marine,
|
||||
ImpactBasedWarningInfo {.hasTornadoPossibleTag_ = true}},
|
||||
{Phenomenon::FlashFlood,
|
||||
ImpactBasedWarningInfo {
|
||||
.threatCategories_ {ThreatCategory::Base,
|
||||
ThreatCategory::Considerable,
|
||||
ThreatCategory::Catastrophic}}},
|
||||
{Phenomenon::SevereThunderstorm,
|
||||
ImpactBasedWarningInfo {
|
||||
.hasTornadoPossibleTag_ = true,
|
||||
.threatCategories_ {ThreatCategory::Base,
|
||||
ThreatCategory::Considerable,
|
||||
ThreatCategory::Destructive}}},
|
||||
{Phenomenon::SnowSquall, ImpactBasedWarningInfo {}},
|
||||
{Phenomenon::Tornado,
|
||||
ImpactBasedWarningInfo {
|
||||
.hasObservedTag_ = true,
|
||||
.threatCategories_ {ThreatCategory::Base,
|
||||
ThreatCategory::Considerable,
|
||||
ThreatCategory::Catastrophic}}},
|
||||
{Phenomenon::Unknown, ImpactBasedWarningInfo {}}};
|
||||
|
||||
static const std::unordered_map<ThreatCategory, std::string>
|
||||
threatCategoryName_ {{ThreatCategory::Base, "Base"},
|
||||
|
|
@ -20,6 +47,16 @@ static const std::unordered_map<ThreatCategory, std::string>
|
|||
{ThreatCategory::Catastrophic, "Catastrophic"},
|
||||
{ThreatCategory::Unknown, "?"}};
|
||||
|
||||
const ImpactBasedWarningInfo& GetImpactBasedWarningInfo(Phenomenon phenomenon)
|
||||
{
|
||||
auto it = impactBasedWarningInfo_.find(phenomenon);
|
||||
if (it != impactBasedWarningInfo_.cend())
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
return impactBasedWarningInfo_.at(Phenomenon::Unknown);
|
||||
}
|
||||
|
||||
SCWX_GET_ENUM(ThreatCategory, GetThreatCategory, threatCategoryName_)
|
||||
|
||||
const std::string& GetThreatCategoryName(ThreatCategory threatCategory)
|
||||
|
|
@ -27,5 +64,6 @@ const std::string& GetThreatCategoryName(ThreatCategory threatCategory)
|
|||
return threatCategoryName_.at(threatCategory);
|
||||
}
|
||||
|
||||
} // namespace ibw
|
||||
} // namespace awips
|
||||
} // namespace scwx
|
||||
|
|
|
|||
|
|
@ -77,64 +77,65 @@ static const PhenomenonCodesBimap phenomenonCodes_ =
|
|||
(Phenomenon::FreezingSpray, "ZY") //
|
||||
(Phenomenon::Unknown, "??");
|
||||
|
||||
static const std::unordered_map<Phenomenon, std::string> 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<PhenomenonCodesBimap::relation> //
|
||||
(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
|
||||
|
|
|
|||
|
|
@ -378,7 +378,7 @@ void ParseCodedInformation(std::shared_ptr<Segment> 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,10 +389,23 @@ void ParseCodedInformation(std::shared_ptr<Segment> segment,
|
|||
const std::string threatCategoryName =
|
||||
it->substr(threatTagIt->length());
|
||||
|
||||
ThreatCategory threatCategory = GetThreatCategory(threatCategoryName);
|
||||
if (threatCategory == ThreatCategory::Unknown)
|
||||
ibw::ThreatCategory threatCategory =
|
||||
ibw::GetThreatCategory(threatCategoryName);
|
||||
|
||||
switch (threatCategory)
|
||||
{
|
||||
threatCategory = ThreatCategory::Base;
|
||||
case ibw::ThreatCategory::Significant:
|
||||
// "Significant" is no longer an official tag, and has largely been
|
||||
// replaced with "Considerable".
|
||||
threatCategory = ibw::ThreatCategory::Considerable;
|
||||
break;
|
||||
|
||||
case ibw::ThreatCategory::Unknown:
|
||||
threatCategory = ibw::ThreatCategory::Base;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
segment->threatCategory_ = threatCategory;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue