mirror of
https://github.com/ciphervance/supercell-wx.git
synced 2025-10-30 08:00:06 +00:00
Merge pull request #281 from AdenKoperczak/location_markers
Add Location Markers (Part 1)
This commit is contained in:
commit
1843f387ff
25 changed files with 1343 additions and 3 deletions
11
scwx-qt/res/textures/images/location-marker.svg
Normal file
11
scwx-qt/res/textures/images/location-marker.svg
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<svg version="1.1"
|
||||
viewBox="0 0 170 150"
|
||||
width="17" height="15"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
|
||||
<path d="M 40,118 L 85,40 L 130,118 L 40,118 L 85,40 Z"
|
||||
stroke="black" stroke-width="40" fill="none"/>
|
||||
<path d="M 40,118 L 85,40 L 130,118 L 40,118 L 85,40 Z"
|
||||
stroke="red" stroke-width="20" fill="none"/>
|
||||
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 355 B |
|
|
@ -95,6 +95,7 @@ set(HDR_MANAGER source/scwx/qt/manager/alert_manager.hpp
|
|||
source/scwx/qt/manager/log_manager.hpp
|
||||
source/scwx/qt/manager/media_manager.hpp
|
||||
source/scwx/qt/manager/placefile_manager.hpp
|
||||
source/scwx/qt/manager/marker_manager.hpp
|
||||
source/scwx/qt/manager/position_manager.hpp
|
||||
source/scwx/qt/manager/radar_product_manager.hpp
|
||||
source/scwx/qt/manager/radar_product_manager_notifier.hpp
|
||||
|
|
@ -111,6 +112,7 @@ set(SRC_MANAGER source/scwx/qt/manager/alert_manager.cpp
|
|||
source/scwx/qt/manager/log_manager.cpp
|
||||
source/scwx/qt/manager/media_manager.cpp
|
||||
source/scwx/qt/manager/placefile_manager.cpp
|
||||
source/scwx/qt/manager/marker_manager.cpp
|
||||
source/scwx/qt/manager/position_manager.cpp
|
||||
source/scwx/qt/manager/radar_product_manager.cpp
|
||||
source/scwx/qt/manager/radar_product_manager_notifier.cpp
|
||||
|
|
@ -132,6 +134,7 @@ set(HDR_MAP source/scwx/qt/map/alert_layer.hpp
|
|||
source/scwx/qt/map/overlay_layer.hpp
|
||||
source/scwx/qt/map/overlay_product_layer.hpp
|
||||
source/scwx/qt/map/placefile_layer.hpp
|
||||
source/scwx/qt/map/marker_layer.hpp
|
||||
source/scwx/qt/map/radar_product_layer.hpp
|
||||
source/scwx/qt/map/radar_range_layer.hpp
|
||||
source/scwx/qt/map/radar_site_layer.hpp)
|
||||
|
|
@ -146,6 +149,7 @@ set(SRC_MAP source/scwx/qt/map/alert_layer.cpp
|
|||
source/scwx/qt/map/overlay_layer.cpp
|
||||
source/scwx/qt/map/overlay_product_layer.cpp
|
||||
source/scwx/qt/map/placefile_layer.cpp
|
||||
source/scwx/qt/map/marker_layer.cpp
|
||||
source/scwx/qt/map/radar_product_layer.cpp
|
||||
source/scwx/qt/map/radar_range_layer.cpp
|
||||
source/scwx/qt/map/radar_site_layer.cpp)
|
||||
|
|
@ -154,6 +158,7 @@ set(HDR_MODEL source/scwx/qt/model/alert_model.hpp
|
|||
source/scwx/qt/model/imgui_context_model.hpp
|
||||
source/scwx/qt/model/layer_model.hpp
|
||||
source/scwx/qt/model/placefile_model.hpp
|
||||
source/scwx/qt/model/marker_model.hpp
|
||||
source/scwx/qt/model/radar_site_model.hpp
|
||||
source/scwx/qt/model/tree_item.hpp
|
||||
source/scwx/qt/model/tree_model.hpp)
|
||||
|
|
@ -162,6 +167,7 @@ set(SRC_MODEL source/scwx/qt/model/alert_model.cpp
|
|||
source/scwx/qt/model/imgui_context_model.cpp
|
||||
source/scwx/qt/model/layer_model.cpp
|
||||
source/scwx/qt/model/placefile_model.cpp
|
||||
source/scwx/qt/model/marker_model.cpp
|
||||
source/scwx/qt/model/radar_site_model.cpp
|
||||
source/scwx/qt/model/tree_item.cpp
|
||||
source/scwx/qt/model/tree_model.cpp)
|
||||
|
|
@ -215,6 +221,7 @@ set(HDR_TYPES source/scwx/qt/types/alert_types.hpp
|
|||
source/scwx/qt/types/location_types.hpp
|
||||
source/scwx/qt/types/map_types.hpp
|
||||
source/scwx/qt/types/media_types.hpp
|
||||
source/scwx/qt/types/marker_types.hpp
|
||||
source/scwx/qt/types/qt_types.hpp
|
||||
source/scwx/qt/types/radar_product_record.hpp
|
||||
source/scwx/qt/types/text_event_key.hpp
|
||||
|
|
@ -260,6 +267,8 @@ set(HDR_UI source/scwx/qt/ui/about_dialog.hpp
|
|||
source/scwx/qt/ui/open_url_dialog.hpp
|
||||
source/scwx/qt/ui/placefile_dialog.hpp
|
||||
source/scwx/qt/ui/placefile_settings_widget.hpp
|
||||
source/scwx/qt/ui/marker_dialog.hpp
|
||||
source/scwx/qt/ui/marker_settings_widget.hpp
|
||||
source/scwx/qt/ui/progress_dialog.hpp
|
||||
source/scwx/qt/ui/radar_site_dialog.hpp
|
||||
source/scwx/qt/ui/serial_port_dialog.hpp
|
||||
|
|
@ -288,6 +297,8 @@ set(SRC_UI source/scwx/qt/ui/about_dialog.cpp
|
|||
source/scwx/qt/ui/open_url_dialog.cpp
|
||||
source/scwx/qt/ui/placefile_dialog.cpp
|
||||
source/scwx/qt/ui/placefile_settings_widget.cpp
|
||||
source/scwx/qt/ui/marker_dialog.cpp
|
||||
source/scwx/qt/ui/marker_settings_widget.cpp
|
||||
source/scwx/qt/ui/progress_dialog.cpp
|
||||
source/scwx/qt/ui/radar_site_dialog.cpp
|
||||
source/scwx/qt/ui/settings_dialog.cpp
|
||||
|
|
@ -307,6 +318,8 @@ set(UI_UI source/scwx/qt/ui/about_dialog.ui
|
|||
source/scwx/qt/ui/open_url_dialog.ui
|
||||
source/scwx/qt/ui/placefile_dialog.ui
|
||||
source/scwx/qt/ui/placefile_settings_widget.ui
|
||||
source/scwx/qt/ui/marker_dialog.ui
|
||||
source/scwx/qt/ui/marker_settings_widget.ui
|
||||
source/scwx/qt/ui/progress_dialog.ui
|
||||
source/scwx/qt/ui/radar_site_dialog.ui
|
||||
source/scwx/qt/ui/settings_dialog.ui
|
||||
|
|
|
|||
|
|
@ -75,6 +75,7 @@
|
|||
<file>res/textures/images/cursor-17.png</file>
|
||||
<file>res/textures/images/crosshairs-24.png</file>
|
||||
<file>res/textures/images/dot-3.png</file>
|
||||
<file>res/textures/images/location-marker.svg</file>
|
||||
<file>res/textures/images/mapbox-logo.svg</file>
|
||||
<file>res/textures/images/maptiler-logo.svg</file>
|
||||
</qresource>
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include <scwx/qt/manager/alert_manager.hpp>
|
||||
#include <scwx/qt/manager/hotkey_manager.hpp>
|
||||
#include <scwx/qt/manager/placefile_manager.hpp>
|
||||
#include <scwx/qt/manager/marker_manager.hpp>
|
||||
#include <scwx/qt/manager/position_manager.hpp>
|
||||
#include <scwx/qt/manager/radar_product_manager.hpp>
|
||||
#include <scwx/qt/manager/text_event_manager.hpp>
|
||||
|
|
@ -30,6 +31,7 @@
|
|||
#include <scwx/qt/ui/level2_settings_widget.hpp>
|
||||
#include <scwx/qt/ui/level3_products_widget.hpp>
|
||||
#include <scwx/qt/ui/placefile_dialog.hpp>
|
||||
#include <scwx/qt/ui/marker_dialog.hpp>
|
||||
#include <scwx/qt/ui/radar_site_dialog.hpp>
|
||||
#include <scwx/qt/ui/settings_dialog.hpp>
|
||||
#include <scwx/qt/ui/update_dialog.hpp>
|
||||
|
|
@ -86,11 +88,13 @@ public:
|
|||
imGuiDebugDialog_ {nullptr},
|
||||
layerDialog_ {nullptr},
|
||||
placefileDialog_ {nullptr},
|
||||
markerDialog_ {nullptr},
|
||||
radarSiteDialog_ {nullptr},
|
||||
settingsDialog_ {nullptr},
|
||||
updateDialog_ {nullptr},
|
||||
alertManager_ {manager::AlertManager::Instance()},
|
||||
placefileManager_ {manager::PlacefileManager::Instance()},
|
||||
markerManager_ {manager::MarkerManager::Instance()},
|
||||
positionManager_ {manager::PositionManager::Instance()},
|
||||
textEventManager_ {manager::TextEventManager::Instance()},
|
||||
timelineManager_ {manager::TimelineManager::Instance()},
|
||||
|
|
@ -203,6 +207,7 @@ public:
|
|||
ui::ImGuiDebugDialog* imGuiDebugDialog_;
|
||||
ui::LayerDialog* layerDialog_;
|
||||
ui::PlacefileDialog* placefileDialog_;
|
||||
ui::MarkerDialog* markerDialog_;
|
||||
ui::RadarSiteDialog* radarSiteDialog_;
|
||||
ui::SettingsDialog* settingsDialog_;
|
||||
ui::UpdateDialog* updateDialog_;
|
||||
|
|
@ -217,6 +222,7 @@ public:
|
|||
std::shared_ptr<manager::HotkeyManager> hotkeyManager_ {
|
||||
manager::HotkeyManager::Instance()};
|
||||
std::shared_ptr<manager::PlacefileManager> placefileManager_;
|
||||
std::shared_ptr<manager::MarkerManager> markerManager_;
|
||||
std::shared_ptr<manager::PositionManager> positionManager_;
|
||||
std::shared_ptr<manager::TextEventManager> textEventManager_;
|
||||
std::shared_ptr<manager::TimelineManager> timelineManager_;
|
||||
|
|
@ -303,6 +309,9 @@ MainWindow::MainWindow(QWidget* parent) :
|
|||
// Placefile Manager Dialog
|
||||
p->placefileDialog_ = new ui::PlacefileDialog(this);
|
||||
|
||||
// Marker Manager Dialog
|
||||
p->markerDialog_ = new ui::MarkerDialog(this);
|
||||
|
||||
// Layer Dialog
|
||||
p->layerDialog_ = new ui::LayerDialog(this);
|
||||
|
||||
|
|
@ -610,6 +619,11 @@ void MainWindow::on_actionPlacefileManager_triggered()
|
|||
p->placefileDialog_->show();
|
||||
}
|
||||
|
||||
void MainWindow::on_actionMarkerManager_triggered()
|
||||
{
|
||||
p->markerDialog_->show();
|
||||
}
|
||||
|
||||
void MainWindow::on_actionLayerManager_triggered()
|
||||
{
|
||||
p->layerDialog_->show();
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ private slots:
|
|||
void on_actionRadarRange_triggered(bool checked);
|
||||
void on_actionRadarSites_triggered(bool checked);
|
||||
void on_actionPlacefileManager_triggered();
|
||||
void on_actionMarkerManager_triggered();
|
||||
void on_actionLayerManager_triggered();
|
||||
void on_actionImGuiDebug_triggered();
|
||||
void on_actionDumpLayerList_triggered();
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1024</width>
|
||||
<height>33</height>
|
||||
<height>22</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuFile">
|
||||
|
|
@ -104,6 +104,7 @@
|
|||
</property>
|
||||
<addaction name="actionPlacefileManager"/>
|
||||
<addaction name="actionLayerManager"/>
|
||||
<addaction name="actionMarkerManager"/>
|
||||
</widget>
|
||||
<addaction name="menuFile"/>
|
||||
<addaction name="menuView"/>
|
||||
|
|
@ -152,8 +153,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>190</width>
|
||||
<height>686</height>
|
||||
<width>205</width>
|
||||
<height>701</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||
|
|
@ -487,6 +488,15 @@
|
|||
<string>&GPS Info</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionMarkerManager">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../../scwx-qt.qrc">
|
||||
<normaloff>:/res/icons/font-awesome-6/house-solid.svg</normaloff>:/res/icons/font-awesome-6/house-solid.svg</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Location &Marker Manager</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="../../../../scwx-qt.qrc"/>
|
||||
|
|
|
|||
317
scwx-qt/source/scwx/qt/manager/marker_manager.cpp
Normal file
317
scwx-qt/source/scwx/qt/manager/marker_manager.cpp
Normal file
|
|
@ -0,0 +1,317 @@
|
|||
#include <scwx/qt/manager/marker_manager.hpp>
|
||||
#include <scwx/qt/types/marker_types.hpp>
|
||||
#include <scwx/qt/util/json.hpp>
|
||||
#include <scwx/qt/main/application.hpp>
|
||||
#include <scwx/util/logger.hpp>
|
||||
|
||||
#include <filesystem>
|
||||
#include <shared_mutex>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include <QStandardPaths>
|
||||
#include <boost/json.hpp>
|
||||
#include <boost/asio/post.hpp>
|
||||
#include <boost/asio/thread_pool.hpp>
|
||||
|
||||
namespace scwx
|
||||
{
|
||||
namespace qt
|
||||
{
|
||||
namespace manager
|
||||
{
|
||||
|
||||
static const std::string logPrefix_ = "scwx::qt::manager::marker_manager";
|
||||
static const auto logger_ = scwx::util::Logger::Create(logPrefix_);
|
||||
|
||||
static const std::string kNameName_ = "name";
|
||||
static const std::string kLatitudeName_ = "latitude";
|
||||
static const std::string kLongitudeName_ = "longitude";
|
||||
|
||||
class MarkerManager::Impl
|
||||
{
|
||||
public:
|
||||
class MarkerRecord;
|
||||
|
||||
explicit Impl(MarkerManager* self) : self_ {self} {}
|
||||
~Impl() { threadPool_.join(); }
|
||||
|
||||
std::string markerSettingsPath_ {};
|
||||
std::vector<std::shared_ptr<MarkerRecord>> markerRecords_ {};
|
||||
|
||||
MarkerManager* self_;
|
||||
|
||||
boost::asio::thread_pool threadPool_ {1u};
|
||||
std::shared_mutex markerRecordLock_ {};
|
||||
|
||||
void InitializeMarkerSettings();
|
||||
void ReadMarkerSettings();
|
||||
void WriteMarkerSettings();
|
||||
std::shared_ptr<MarkerRecord> GetMarkerByName(const std::string& name);
|
||||
};
|
||||
|
||||
class MarkerManager::Impl::MarkerRecord
|
||||
{
|
||||
public:
|
||||
MarkerRecord(const std::string& name, double latitude, double longitude) :
|
||||
markerInfo_ {types::MarkerInfo(name, latitude, longitude)}
|
||||
{
|
||||
}
|
||||
MarkerRecord(const types::MarkerInfo& info) :
|
||||
markerInfo_ {info}
|
||||
{
|
||||
}
|
||||
|
||||
const types::MarkerInfo& toMarkerInfo()
|
||||
{
|
||||
return markerInfo_;
|
||||
}
|
||||
|
||||
types::MarkerInfo markerInfo_;
|
||||
|
||||
friend void tag_invoke(boost::json::value_from_tag,
|
||||
boost::json::value& jv,
|
||||
const std::shared_ptr<MarkerRecord>& record)
|
||||
{
|
||||
jv = {{kNameName_, record->markerInfo_.name},
|
||||
{kLatitudeName_, record->markerInfo_.latitude},
|
||||
{kLongitudeName_, record->markerInfo_.longitude}};
|
||||
}
|
||||
|
||||
friend MarkerRecord tag_invoke(boost::json::value_to_tag<MarkerRecord>,
|
||||
const boost::json::value& jv)
|
||||
{
|
||||
return MarkerRecord(
|
||||
boost::json::value_to<std::string>(jv.at(kNameName_)),
|
||||
boost::json::value_to<double>(jv.at(kLatitudeName_)),
|
||||
boost::json::value_to<double>(jv.at(kLongitudeName_)));
|
||||
}
|
||||
};
|
||||
|
||||
void MarkerManager::Impl::InitializeMarkerSettings()
|
||||
{
|
||||
std::string appDataPath {
|
||||
QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)
|
||||
.toStdString()};
|
||||
|
||||
if (!std::filesystem::exists(appDataPath))
|
||||
{
|
||||
if (!std::filesystem::create_directories(appDataPath))
|
||||
{
|
||||
logger_->error("Unable to create application data directory: \"{}\"",
|
||||
appDataPath);
|
||||
}
|
||||
}
|
||||
|
||||
markerSettingsPath_ = appDataPath + "/location-markers.json";
|
||||
}
|
||||
|
||||
void MarkerManager::Impl::ReadMarkerSettings()
|
||||
{
|
||||
logger_->info("Reading location marker settings");
|
||||
|
||||
boost::json::value markerJson = nullptr;
|
||||
{
|
||||
std::unique_lock lock(markerRecordLock_);
|
||||
|
||||
// Determine if marker settings exists
|
||||
if (std::filesystem::exists(markerSettingsPath_))
|
||||
{
|
||||
markerJson = util::json::ReadJsonFile(markerSettingsPath_);
|
||||
}
|
||||
|
||||
if (markerJson != nullptr && markerJson.is_array())
|
||||
{
|
||||
// For each marker entry
|
||||
auto& markerArray = markerJson.as_array();
|
||||
markerRecords_.reserve(markerArray.size());
|
||||
for (auto& markerEntry : markerArray)
|
||||
{
|
||||
try
|
||||
{
|
||||
MarkerRecord record =
|
||||
boost::json::value_to<MarkerRecord>(markerEntry);
|
||||
|
||||
if (!record.markerInfo_.name.empty())
|
||||
{
|
||||
markerRecords_.emplace_back(
|
||||
std::make_shared<MarkerRecord>(record.markerInfo_));
|
||||
}
|
||||
}
|
||||
catch (const std::exception& ex)
|
||||
{
|
||||
logger_->warn("Invalid location marker entry: {}", ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
logger_->debug("{} location marker entries", markerRecords_.size());
|
||||
}
|
||||
}
|
||||
|
||||
Q_EMIT self_->MarkersUpdated();
|
||||
}
|
||||
|
||||
void MarkerManager::Impl::WriteMarkerSettings()
|
||||
{
|
||||
logger_->info("Saving location marker settings");
|
||||
|
||||
std::shared_lock lock(markerRecordLock_);
|
||||
auto markerJson = boost::json::value_from(markerRecords_);
|
||||
util::json::WriteJsonFile(markerSettingsPath_, markerJson);
|
||||
}
|
||||
|
||||
std::shared_ptr<MarkerManager::Impl::MarkerRecord>
|
||||
MarkerManager::Impl::GetMarkerByName(const std::string& name)
|
||||
{
|
||||
for (auto& markerRecord : markerRecords_)
|
||||
{
|
||||
if (markerRecord->markerInfo_.name == name)
|
||||
{
|
||||
return markerRecord;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MarkerManager::MarkerManager() : p(std::make_unique<Impl>(this))
|
||||
{
|
||||
|
||||
boost::asio::post(p->threadPool_,
|
||||
[this]()
|
||||
{
|
||||
try
|
||||
{
|
||||
p->InitializeMarkerSettings();
|
||||
|
||||
// Read Marker settings on startup
|
||||
main::Application::WaitForInitialization();
|
||||
p->ReadMarkerSettings();
|
||||
|
||||
Q_EMIT MarkersInitialized(p->markerRecords_.size());
|
||||
}
|
||||
catch (const std::exception& ex)
|
||||
{
|
||||
logger_->error(ex.what());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
MarkerManager::~MarkerManager()
|
||||
{
|
||||
p->WriteMarkerSettings();
|
||||
}
|
||||
|
||||
size_t MarkerManager::marker_count()
|
||||
{
|
||||
return p->markerRecords_.size();
|
||||
}
|
||||
|
||||
std::optional<types::MarkerInfo> MarkerManager::get_marker(size_t index)
|
||||
{
|
||||
std::shared_lock lock(p->markerRecordLock_);
|
||||
if (index >= p->markerRecords_.size())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
std::shared_ptr<MarkerManager::Impl::MarkerRecord>& markerRecord =
|
||||
p->markerRecords_[index];
|
||||
return markerRecord->toMarkerInfo();
|
||||
}
|
||||
|
||||
void MarkerManager::set_marker(size_t index, const types::MarkerInfo& marker)
|
||||
{
|
||||
{
|
||||
std::unique_lock lock(p->markerRecordLock_);
|
||||
if (index >= p->markerRecords_.size())
|
||||
{
|
||||
return;
|
||||
}
|
||||
std::shared_ptr<MarkerManager::Impl::MarkerRecord>& markerRecord =
|
||||
p->markerRecords_[index];
|
||||
markerRecord->markerInfo_ = marker;
|
||||
}
|
||||
Q_EMIT MarkerChanged(index);
|
||||
Q_EMIT MarkersUpdated();
|
||||
}
|
||||
|
||||
void MarkerManager::add_marker(const types::MarkerInfo& marker)
|
||||
{
|
||||
{
|
||||
std::unique_lock lock(p->markerRecordLock_);
|
||||
p->markerRecords_.emplace_back(std::make_shared<Impl::MarkerRecord>(marker));
|
||||
}
|
||||
Q_EMIT MarkerAdded();
|
||||
Q_EMIT MarkersUpdated();
|
||||
}
|
||||
|
||||
void MarkerManager::remove_marker(size_t index)
|
||||
{
|
||||
{
|
||||
std::unique_lock lock(p->markerRecordLock_);
|
||||
if (index >= p->markerRecords_.size())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
p->markerRecords_.erase(std::next(p->markerRecords_.begin(), index));
|
||||
}
|
||||
|
||||
Q_EMIT MarkerRemoved(index);
|
||||
Q_EMIT MarkersUpdated();
|
||||
}
|
||||
|
||||
void MarkerManager::move_marker(size_t from, size_t to)
|
||||
{
|
||||
{
|
||||
std::unique_lock lock(p->markerRecordLock_);
|
||||
if (from >= p->markerRecords_.size() || to >= p->markerRecords_.size())
|
||||
{
|
||||
return;
|
||||
}
|
||||
std::shared_ptr<MarkerManager::Impl::MarkerRecord>& markerRecord =
|
||||
p->markerRecords_[from];
|
||||
|
||||
if (from == to) {}
|
||||
else if (from < to)
|
||||
{
|
||||
for (size_t i = from; i < to; i++)
|
||||
{
|
||||
p->markerRecords_[i] = p->markerRecords_[i + 1];
|
||||
}
|
||||
p->markerRecords_[to] = markerRecord;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t i = from; i > to; i--)
|
||||
{
|
||||
p->markerRecords_[i] = p->markerRecords_[i - 1];
|
||||
}
|
||||
p->markerRecords_[to] = markerRecord;
|
||||
}
|
||||
}
|
||||
Q_EMIT MarkersUpdated();
|
||||
}
|
||||
|
||||
std::shared_ptr<MarkerManager> MarkerManager::Instance()
|
||||
{
|
||||
static std::weak_ptr<MarkerManager> markerManagerReference_ {};
|
||||
static std::mutex instanceMutex_ {};
|
||||
|
||||
std::unique_lock lock(instanceMutex_);
|
||||
|
||||
std::shared_ptr<MarkerManager> markerManager =
|
||||
markerManagerReference_.lock();
|
||||
|
||||
if (markerManager == nullptr)
|
||||
{
|
||||
markerManager = std::make_shared<MarkerManager>();
|
||||
markerManagerReference_ = markerManager;
|
||||
}
|
||||
|
||||
return markerManager;
|
||||
}
|
||||
|
||||
} // namespace manager
|
||||
} // namespace qt
|
||||
} // namespace scwx
|
||||
46
scwx-qt/source/scwx/qt/manager/marker_manager.hpp
Normal file
46
scwx-qt/source/scwx/qt/manager/marker_manager.hpp
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
#pragma once
|
||||
|
||||
#include <scwx/qt/types/marker_types.hpp>
|
||||
|
||||
#include <QObject>
|
||||
#include <optional>
|
||||
|
||||
namespace scwx
|
||||
{
|
||||
namespace qt
|
||||
{
|
||||
namespace manager
|
||||
{
|
||||
|
||||
class MarkerManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MarkerManager();
|
||||
~MarkerManager();
|
||||
|
||||
size_t marker_count();
|
||||
std::optional<types::MarkerInfo> get_marker(size_t index);
|
||||
void set_marker(size_t index, const types::MarkerInfo& marker);
|
||||
void add_marker(const types::MarkerInfo& marker);
|
||||
void remove_marker(size_t index);
|
||||
void move_marker(size_t from, size_t to);
|
||||
|
||||
static std::shared_ptr<MarkerManager> Instance();
|
||||
|
||||
signals:
|
||||
void MarkersInitialized(size_t count);
|
||||
void MarkersUpdated();
|
||||
void MarkerChanged(size_t index);
|
||||
void MarkerAdded();
|
||||
void MarkerRemoved(size_t index);
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> p;
|
||||
};
|
||||
|
||||
} // namespace manager
|
||||
} // namespace qt
|
||||
} // namespace scwx
|
||||
|
|
@ -12,6 +12,7 @@
|
|||
#include <scwx/qt/map/overlay_layer.hpp>
|
||||
#include <scwx/qt/map/overlay_product_layer.hpp>
|
||||
#include <scwx/qt/map/placefile_layer.hpp>
|
||||
#include <scwx/qt/map/marker_layer.hpp>
|
||||
#include <scwx/qt/map/radar_product_layer.hpp>
|
||||
#include <scwx/qt/map/radar_range_layer.hpp>
|
||||
#include <scwx/qt/map/radar_site_layer.hpp>
|
||||
|
|
@ -81,6 +82,7 @@ public:
|
|||
radarProductLayer_ {nullptr},
|
||||
overlayLayer_ {nullptr},
|
||||
placefileLayer_ {nullptr},
|
||||
markerLayer_ {nullptr},
|
||||
colorTableLayer_ {nullptr},
|
||||
autoRefreshEnabled_ {true},
|
||||
autoUpdateEnabled_ {true},
|
||||
|
|
@ -223,6 +225,7 @@ public:
|
|||
std::shared_ptr<OverlayLayer> overlayLayer_;
|
||||
std::shared_ptr<OverlayProductLayer> overlayProductLayer_ {nullptr};
|
||||
std::shared_ptr<PlacefileLayer> placefileLayer_;
|
||||
std::shared_ptr<MarkerLayer> markerLayer_;
|
||||
std::shared_ptr<ColorTableLayer> colorTableLayer_;
|
||||
std::shared_ptr<RadarSiteLayer> radarSiteLayer_ {nullptr};
|
||||
|
||||
|
|
@ -1232,6 +1235,12 @@ void MapWidgetImpl::AddLayer(types::LayerType type,
|
|||
{ widget_->RadarSiteRequested(id); });
|
||||
break;
|
||||
|
||||
// Create the location marker layer
|
||||
case types::InformationLayer::Markers:
|
||||
markerLayer_ = std::make_shared<MarkerLayer>(context_);
|
||||
AddLayer(layerName, markerLayer_, before);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
113
scwx-qt/source/scwx/qt/map/marker_layer.cpp
Normal file
113
scwx-qt/source/scwx/qt/map/marker_layer.cpp
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
#include <scwx/qt/map/marker_layer.hpp>
|
||||
#include <scwx/qt/manager/marker_manager.hpp>
|
||||
#include <scwx/util/logger.hpp>
|
||||
#include <scwx/qt/types/marker_types.hpp>
|
||||
#include <scwx/qt/types/texture_types.hpp>
|
||||
#include <scwx/qt/gl/draw/geo_icons.hpp>
|
||||
|
||||
namespace scwx
|
||||
{
|
||||
namespace qt
|
||||
{
|
||||
namespace map
|
||||
{
|
||||
|
||||
static const std::string logPrefix_ = "scwx::qt::map::marker_layer";
|
||||
static const auto logger_ = scwx::util::Logger::Create(logPrefix_);
|
||||
|
||||
class MarkerLayer::Impl
|
||||
{
|
||||
public:
|
||||
explicit Impl(MarkerLayer* self, std::shared_ptr<MapContext> context) :
|
||||
self_ {self}, geoIcons_ {std::make_shared<gl::draw::GeoIcons>(context)}
|
||||
{
|
||||
ConnectSignals();
|
||||
}
|
||||
~Impl() {}
|
||||
|
||||
void ReloadMarkers();
|
||||
void ConnectSignals();
|
||||
|
||||
MarkerLayer* self_;
|
||||
const std::string& markerIconName_ {
|
||||
types::GetTextureName(types::ImageTexture::LocationMarker)};
|
||||
|
||||
std::shared_ptr<gl::draw::GeoIcons> geoIcons_;
|
||||
};
|
||||
|
||||
void MarkerLayer::Impl::ConnectSignals()
|
||||
{
|
||||
auto markerManager = manager::MarkerManager::Instance();
|
||||
|
||||
QObject::connect(markerManager.get(),
|
||||
&manager::MarkerManager::MarkersUpdated,
|
||||
self_,
|
||||
[this]()
|
||||
{
|
||||
this->ReloadMarkers();
|
||||
});
|
||||
}
|
||||
|
||||
void MarkerLayer::Impl::ReloadMarkers()
|
||||
{
|
||||
logger_->debug("ReloadMarkers()");
|
||||
auto markerManager = manager::MarkerManager::Instance();
|
||||
|
||||
geoIcons_->StartIcons();
|
||||
|
||||
for (size_t i = 0; i < markerManager->marker_count(); i++)
|
||||
{
|
||||
std::optional<types::MarkerInfo> marker = markerManager->get_marker(i);
|
||||
if (!marker)
|
||||
{
|
||||
break;
|
||||
}
|
||||
std::shared_ptr<gl::draw::GeoIconDrawItem> icon = geoIcons_->AddIcon();
|
||||
geoIcons_->SetIconTexture(icon, markerIconName_, 0);
|
||||
geoIcons_->SetIconLocation(icon, marker->latitude, marker->longitude);
|
||||
}
|
||||
|
||||
geoIcons_->FinishIcons();
|
||||
Q_EMIT self_->NeedsRendering();
|
||||
}
|
||||
|
||||
MarkerLayer::MarkerLayer(const std::shared_ptr<MapContext>& context) :
|
||||
DrawLayer(context), p(std::make_unique<MarkerLayer::Impl>(this, context))
|
||||
{
|
||||
AddDrawItem(p->geoIcons_);
|
||||
}
|
||||
|
||||
MarkerLayer::~MarkerLayer() = default;
|
||||
|
||||
void MarkerLayer::Initialize()
|
||||
{
|
||||
logger_->debug("Initialize()");
|
||||
DrawLayer::Initialize();
|
||||
|
||||
p->geoIcons_->StartIconSheets();
|
||||
p->geoIcons_->AddIconSheet(p->markerIconName_);
|
||||
p->geoIcons_->FinishIconSheets();
|
||||
|
||||
p->ReloadMarkers();
|
||||
}
|
||||
|
||||
void MarkerLayer::Render(const QMapLibre::CustomLayerRenderParameters& params)
|
||||
{
|
||||
// auto markerManager = manager::MarkerManager::Instance();
|
||||
gl::OpenGLFunctions& gl = context()->gl();
|
||||
|
||||
DrawLayer::Render(params);
|
||||
|
||||
SCWX_GL_CHECK_ERROR();
|
||||
}
|
||||
|
||||
void MarkerLayer::Deinitialize()
|
||||
{
|
||||
logger_->debug("Deinitialize()");
|
||||
|
||||
DrawLayer::Deinitialize();
|
||||
}
|
||||
|
||||
} // namespace map
|
||||
} // namespace qt
|
||||
} // namespace scwx
|
||||
33
scwx-qt/source/scwx/qt/map/marker_layer.hpp
Normal file
33
scwx-qt/source/scwx/qt/map/marker_layer.hpp
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#pragma once
|
||||
|
||||
#include <scwx/qt/map/draw_layer.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace scwx
|
||||
{
|
||||
namespace qt
|
||||
{
|
||||
namespace map
|
||||
{
|
||||
|
||||
class MarkerLayer : public DrawLayer
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MarkerLayer(const std::shared_ptr<MapContext>& context);
|
||||
~MarkerLayer();
|
||||
|
||||
void Initialize() override final;
|
||||
void Render(const QMapLibre::CustomLayerRenderParameters&) override final;
|
||||
void Deinitialize() override final;
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> p;
|
||||
};
|
||||
|
||||
} // namespace map
|
||||
} // namespace qt
|
||||
} // namespace scwx
|
||||
|
|
@ -43,6 +43,7 @@ static const std::vector<types::LayerInfo> kDefaultLayers_ {
|
|||
types::InformationLayer::RadarSite,
|
||||
false,
|
||||
{false, false, false, false}},
|
||||
{types::LayerType::Information, types::InformationLayer::Markers, true},
|
||||
{types::LayerType::Data, types::DataLayer::RadarRange, true},
|
||||
{types::LayerType::Alert, awips::Phenomenon::Tornado, true},
|
||||
{types::LayerType::Alert, awips::Phenomenon::SnowSquall, true},
|
||||
|
|
|
|||
290
scwx-qt/source/scwx/qt/model/marker_model.cpp
Normal file
290
scwx-qt/source/scwx/qt/model/marker_model.cpp
Normal file
|
|
@ -0,0 +1,290 @@
|
|||
#include <scwx/common/geographic.hpp>
|
||||
#include <scwx/qt/model/marker_model.hpp>
|
||||
#include <scwx/qt/manager/marker_manager.hpp>
|
||||
#include <scwx/qt/types/marker_types.hpp>
|
||||
#include <scwx/qt/types/qt_types.hpp>
|
||||
#include <scwx/util/logger.hpp>
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
namespace scwx
|
||||
{
|
||||
namespace qt
|
||||
{
|
||||
namespace model
|
||||
{
|
||||
|
||||
static const std::string logPrefix_ = "scwx::qt::model::marker_model";
|
||||
static const auto logger_ = scwx::util::Logger::Create(logPrefix_);
|
||||
|
||||
static constexpr int kFirstColumn =
|
||||
static_cast<int>(MarkerModel::Column::Latitude);
|
||||
static constexpr int kLastColumn =
|
||||
static_cast<int>(MarkerModel::Column::Name);
|
||||
static constexpr int kNumColumns = kLastColumn - kFirstColumn + 1;
|
||||
|
||||
class MarkerModel::Impl
|
||||
{
|
||||
public:
|
||||
explicit Impl() {}
|
||||
~Impl() = default;
|
||||
std::shared_ptr<manager::MarkerManager> markerManager_ {
|
||||
manager::MarkerManager::Instance()};
|
||||
};
|
||||
|
||||
MarkerModel::MarkerModel(QObject* parent) :
|
||||
QAbstractTableModel(parent), p(std::make_unique<Impl>())
|
||||
{
|
||||
|
||||
connect(p->markerManager_.get(),
|
||||
&manager::MarkerManager::MarkersInitialized,
|
||||
this,
|
||||
&MarkerModel::HandleMarkersInitialized);
|
||||
|
||||
connect(p->markerManager_.get(),
|
||||
&manager::MarkerManager::MarkerAdded,
|
||||
this,
|
||||
&MarkerModel::HandleMarkerAdded);
|
||||
|
||||
connect(p->markerManager_.get(),
|
||||
&manager::MarkerManager::MarkerChanged,
|
||||
this,
|
||||
&MarkerModel::HandleMarkerChanged);
|
||||
|
||||
connect(p->markerManager_.get(),
|
||||
&manager::MarkerManager::MarkerRemoved,
|
||||
this,
|
||||
&MarkerModel::HandleMarkerRemoved);
|
||||
}
|
||||
|
||||
MarkerModel::~MarkerModel() = default;
|
||||
|
||||
int MarkerModel::rowCount(const QModelIndex& parent) const
|
||||
{
|
||||
return parent.isValid() ?
|
||||
0 :
|
||||
static_cast<int>(p->markerManager_->marker_count());
|
||||
}
|
||||
|
||||
int MarkerModel::columnCount(const QModelIndex& parent) const
|
||||
{
|
||||
return parent.isValid() ? 0 : kNumColumns;
|
||||
}
|
||||
|
||||
Qt::ItemFlags MarkerModel::flags(const QModelIndex& index) const
|
||||
{
|
||||
Qt::ItemFlags flags = QAbstractTableModel::flags(index);
|
||||
|
||||
switch (index.column())
|
||||
{
|
||||
case static_cast<int>(Column::Name):
|
||||
case static_cast<int>(Column::Latitude):
|
||||
case static_cast<int>(Column::Longitude):
|
||||
flags |= Qt::ItemFlag::ItemIsEditable;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
QVariant MarkerModel::data(const QModelIndex& index, int role) const
|
||||
{
|
||||
|
||||
static const char COORDINATE_FORMAT = 'g';
|
||||
static const int COORDINATE_PRECISION = 10;
|
||||
|
||||
if (!index.isValid() || index.row() < 0)
|
||||
{
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
std::optional<types::MarkerInfo> markerInfo =
|
||||
p->markerManager_->get_marker(index.row());
|
||||
if (!markerInfo)
|
||||
{
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
switch(index.column())
|
||||
{
|
||||
case static_cast<int>(Column::Name):
|
||||
if (role == Qt::ItemDataRole::DisplayRole ||
|
||||
role == Qt::ItemDataRole::ToolTipRole ||
|
||||
role == Qt::ItemDataRole::EditRole)
|
||||
{
|
||||
return QString::fromStdString(markerInfo->name);
|
||||
}
|
||||
break;
|
||||
|
||||
case static_cast<int>(Column::Latitude):
|
||||
if (role == Qt::ItemDataRole::DisplayRole ||
|
||||
role == Qt::ItemDataRole::ToolTipRole)
|
||||
{
|
||||
return QString::fromStdString(
|
||||
common::GetLatitudeString(markerInfo->latitude));
|
||||
}
|
||||
else if (role == Qt::ItemDataRole::EditRole)
|
||||
{
|
||||
return QString::number(
|
||||
markerInfo->latitude, COORDINATE_FORMAT, COORDINATE_PRECISION);
|
||||
}
|
||||
break;
|
||||
|
||||
case static_cast<int>(Column::Longitude):
|
||||
if (role == Qt::ItemDataRole::DisplayRole ||
|
||||
role == Qt::ItemDataRole::ToolTipRole)
|
||||
{
|
||||
return QString::fromStdString(
|
||||
common::GetLongitudeString(markerInfo->longitude));
|
||||
}
|
||||
else if (role == Qt::ItemDataRole::EditRole)
|
||||
{
|
||||
return QString::number(
|
||||
markerInfo->longitude, COORDINATE_FORMAT, COORDINATE_PRECISION);
|
||||
}
|
||||
break;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant MarkerModel::headerData(int section,
|
||||
Qt::Orientation orientation,
|
||||
int role) const
|
||||
{
|
||||
if (role == Qt::ItemDataRole::DisplayRole)
|
||||
{
|
||||
if (orientation == Qt::Horizontal)
|
||||
{
|
||||
switch (section)
|
||||
{
|
||||
case static_cast<int>(Column::Name):
|
||||
return tr("Name");
|
||||
|
||||
case static_cast<int>(Column::Latitude):
|
||||
return tr("Latitude");
|
||||
|
||||
case static_cast<int>(Column::Longitude):
|
||||
return tr("Longitude");
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
bool MarkerModel::setData(const QModelIndex& index,
|
||||
const QVariant& value,
|
||||
int role)
|
||||
{
|
||||
if (!index.isValid() || index.row() < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
std::optional<types::MarkerInfo> markerInfo =
|
||||
p->markerManager_->get_marker(index.row());
|
||||
if (!markerInfo)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bool result = false;
|
||||
|
||||
switch(index.column())
|
||||
{
|
||||
case static_cast<int>(Column::Name):
|
||||
if (role == Qt::ItemDataRole::EditRole)
|
||||
{
|
||||
QString str = value.toString();
|
||||
markerInfo->name = str.toStdString();
|
||||
p->markerManager_->set_marker(index.row(), *markerInfo);
|
||||
result = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case static_cast<int>(Column::Latitude):
|
||||
if (role == Qt::ItemDataRole::EditRole)
|
||||
{
|
||||
QString str = value.toString();
|
||||
bool ok;
|
||||
double latitude = str.toDouble(&ok);
|
||||
if (!str.isEmpty() && ok && -90 <= latitude && latitude <= 90)
|
||||
{
|
||||
markerInfo->latitude = latitude;
|
||||
p->markerManager_->set_marker(index.row(), *markerInfo);
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case static_cast<int>(Column::Longitude):
|
||||
if (role == Qt::ItemDataRole::EditRole)
|
||||
{
|
||||
QString str = value.toString();
|
||||
bool ok;
|
||||
double longitude = str.toDouble(&ok);
|
||||
if (!str.isEmpty() && ok && -180 <= longitude && longitude <= 180)
|
||||
{
|
||||
markerInfo->longitude = longitude;
|
||||
p->markerManager_->set_marker(index.row(), *markerInfo);
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
Q_EMIT dataChanged(index, index);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void MarkerModel::HandleMarkersInitialized(size_t count)
|
||||
{
|
||||
const int index = static_cast<int>(count - 1);
|
||||
|
||||
beginInsertRows(QModelIndex(), 0, index);
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
void MarkerModel::HandleMarkerAdded()
|
||||
{
|
||||
const int newIndex = static_cast<int>(p->markerManager_->marker_count() - 1);
|
||||
|
||||
beginInsertRows(QModelIndex(), newIndex, newIndex);
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
void MarkerModel::HandleMarkerChanged(size_t index)
|
||||
{
|
||||
const int changedIndex = static_cast<int>(index);
|
||||
QModelIndex topLeft = createIndex(changedIndex, kFirstColumn);
|
||||
QModelIndex bottomRight = createIndex(changedIndex, kLastColumn);
|
||||
|
||||
Q_EMIT dataChanged(topLeft, bottomRight);
|
||||
}
|
||||
|
||||
void MarkerModel::HandleMarkerRemoved(size_t index)
|
||||
{
|
||||
const int removedIndex = static_cast<int>(index);
|
||||
|
||||
beginRemoveRows(QModelIndex(), removedIndex, removedIndex);
|
||||
endRemoveRows();
|
||||
}
|
||||
|
||||
} // namespace model
|
||||
} // namespace qt
|
||||
} // namespace scwx
|
||||
54
scwx-qt/source/scwx/qt/model/marker_model.hpp
Normal file
54
scwx-qt/source/scwx/qt/model/marker_model.hpp
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
#pragma once
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
|
||||
namespace scwx
|
||||
{
|
||||
namespace qt
|
||||
{
|
||||
namespace model
|
||||
{
|
||||
|
||||
class MarkerModel : public QAbstractTableModel
|
||||
{
|
||||
public:
|
||||
enum class Column : int
|
||||
{
|
||||
Latitude = 0,
|
||||
Longitude = 1,
|
||||
Name = 2,
|
||||
};
|
||||
|
||||
explicit MarkerModel(QObject* parent = nullptr);
|
||||
~MarkerModel();
|
||||
|
||||
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||
int columnCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||
|
||||
Qt::ItemFlags flags(const QModelIndex& index) const override;
|
||||
|
||||
QVariant data(const QModelIndex& index,
|
||||
int role = Qt::DisplayRole) const override;
|
||||
QVariant headerData(int section,
|
||||
Qt::Orientation orientation,
|
||||
int role = Qt::DisplayRole) const override;
|
||||
|
||||
bool setData(const QModelIndex& index,
|
||||
const QVariant& value,
|
||||
int role = Qt::EditRole) override;
|
||||
|
||||
|
||||
public slots:
|
||||
void HandleMarkersInitialized(size_t count);
|
||||
void HandleMarkerAdded();
|
||||
void HandleMarkerChanged(size_t index);
|
||||
void HandleMarkerRemoved(size_t index);
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> p;
|
||||
};
|
||||
|
||||
} // namespace model
|
||||
} // namespace qt
|
||||
} // namespace scwx
|
||||
|
|
@ -31,6 +31,7 @@ static const std::unordered_map<InformationLayer, std::string>
|
|||
informationLayerName_ {{InformationLayer::MapOverlay, "Map Overlay"},
|
||||
{InformationLayer::RadarSite, "Radar Sites"},
|
||||
{InformationLayer::ColorTable, "Color Table"},
|
||||
{InformationLayer::Markers, "Location Markers"},
|
||||
{InformationLayer::Unknown, "?"}};
|
||||
|
||||
static const std::unordered_map<MapLayer, std::string> mapLayerName_ {
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ enum class InformationLayer
|
|||
MapOverlay,
|
||||
RadarSite,
|
||||
ColorTable,
|
||||
Markers,
|
||||
Unknown
|
||||
};
|
||||
|
||||
|
|
|
|||
26
scwx-qt/source/scwx/qt/types/marker_types.hpp
Normal file
26
scwx-qt/source/scwx/qt/types/marker_types.hpp
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace scwx
|
||||
{
|
||||
namespace qt
|
||||
{
|
||||
namespace types
|
||||
{
|
||||
|
||||
struct MarkerInfo
|
||||
{
|
||||
MarkerInfo(const std::string& name, double latitude, double longitude) :
|
||||
name {name}, latitude {latitude}, longitude {longitude}
|
||||
{
|
||||
}
|
||||
|
||||
std::string name;
|
||||
double latitude;
|
||||
double longitude;
|
||||
};
|
||||
|
||||
} // namespace types
|
||||
} // namespace qt
|
||||
} // namespace scwx
|
||||
|
|
@ -25,6 +25,8 @@ static const std::unordered_map<ImageTexture, TextureInfo> imageTextureInfo_ {
|
|||
{ImageTexture::Cursor17,
|
||||
{"images/cursor-17", ":/res/textures/images/cursor-17.png"}},
|
||||
{ImageTexture::Dot3, {"images/dot-3", ":/res/textures/images/dot-3.png"}},
|
||||
{ImageTexture::LocationMarker,
|
||||
{"images/location-marker", ":/res/textures/images/location-marker.svg"}},
|
||||
{ImageTexture::MapboxLogo,
|
||||
{"images/mapbox-logo", ":/res/textures/images/mapbox-logo.svg"}},
|
||||
{ImageTexture::MapTilerLogo,
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ enum class ImageTexture
|
|||
Crosshairs24,
|
||||
Cursor17,
|
||||
Dot3,
|
||||
LocationMarker,
|
||||
MapboxLogo,
|
||||
MapTilerLogo
|
||||
};
|
||||
|
|
|
|||
45
scwx-qt/source/scwx/qt/ui/marker_dialog.cpp
Normal file
45
scwx-qt/source/scwx/qt/ui/marker_dialog.cpp
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#include "marker_dialog.hpp"
|
||||
#include "ui_marker_dialog.h"
|
||||
|
||||
#include <scwx/qt/ui/marker_settings_widget.hpp>
|
||||
#include <scwx/util/logger.hpp>
|
||||
|
||||
namespace scwx
|
||||
{
|
||||
namespace qt
|
||||
{
|
||||
namespace ui
|
||||
{
|
||||
|
||||
static const std::string logPrefix_ = "scwx::qt::ui::marker_dialog";
|
||||
static const auto logger_ = scwx::util::Logger::Create(logPrefix_);
|
||||
|
||||
class MarkerDialogImpl
|
||||
{
|
||||
public:
|
||||
explicit MarkerDialogImpl() {}
|
||||
~MarkerDialogImpl() = default;
|
||||
|
||||
MarkerSettingsWidget* markerSettingsWidget_ {nullptr};
|
||||
};
|
||||
|
||||
MarkerDialog::MarkerDialog(QWidget* parent) :
|
||||
QDialog(parent),
|
||||
p {std::make_unique<MarkerDialogImpl>()},
|
||||
ui(new Ui::MarkerDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
p->markerSettingsWidget_ = new MarkerSettingsWidget(this);
|
||||
p->markerSettingsWidget_->layout()->setContentsMargins(0, 0, 0, 0);
|
||||
ui->contentsFrame->layout()->addWidget(p->markerSettingsWidget_);
|
||||
}
|
||||
|
||||
MarkerDialog::~MarkerDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
} // namespace ui
|
||||
} // namespace qt
|
||||
} // namespace scwx
|
||||
35
scwx-qt/source/scwx/qt/ui/marker_dialog.hpp
Normal file
35
scwx-qt/source/scwx/qt/ui/marker_dialog.hpp
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
#pragma once
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class MarkerDialog;
|
||||
}
|
||||
|
||||
namespace scwx
|
||||
{
|
||||
namespace qt
|
||||
{
|
||||
namespace ui
|
||||
{
|
||||
|
||||
class MarkerDialogImpl;
|
||||
|
||||
class MarkerDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MarkerDialog(QWidget* parent = nullptr);
|
||||
~MarkerDialog();
|
||||
|
||||
private:
|
||||
friend class MarkerDialogImpl;
|
||||
std::unique_ptr<MarkerDialogImpl> p;
|
||||
Ui::MarkerDialog* ui;
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
} // namespace qt
|
||||
} // namespace scwx
|
||||
88
scwx-qt/source/scwx/qt/ui/marker_dialog.ui
Normal file
88
scwx-qt/source/scwx/qt/ui/marker_dialog.ui
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MarkerDialog</class>
|
||||
<widget class="QDialog" name="MarkerDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>700</width>
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Marker Manager</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QFrame" name="contentsFrame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<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>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Close</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>MarkerDialog</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>MarkerDialog</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>
|
||||
105
scwx-qt/source/scwx/qt/ui/marker_settings_widget.cpp
Normal file
105
scwx-qt/source/scwx/qt/ui/marker_settings_widget.cpp
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
#include "marker_settings_widget.hpp"
|
||||
#include "ui_marker_settings_widget.h"
|
||||
|
||||
#include <scwx/qt/manager/marker_manager.hpp>
|
||||
#include <scwx/qt/model/marker_model.hpp>
|
||||
#include <scwx/qt/types/qt_types.hpp>
|
||||
#include <scwx/qt/ui/open_url_dialog.hpp>
|
||||
#include <scwx/util/logger.hpp>
|
||||
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
namespace scwx
|
||||
{
|
||||
namespace qt
|
||||
{
|
||||
namespace ui
|
||||
{
|
||||
|
||||
static const std::string logPrefix_ = "scwx::qt::ui::marker_settings_widget";
|
||||
static const auto logger_ = scwx::util::Logger::Create(logPrefix_);
|
||||
|
||||
class MarkerSettingsWidgetImpl
|
||||
{
|
||||
public:
|
||||
explicit MarkerSettingsWidgetImpl(MarkerSettingsWidget* self) :
|
||||
self_ {self},
|
||||
markerModel_ {new model::MarkerModel(self_)}
|
||||
{
|
||||
}
|
||||
|
||||
void ConnectSignals();
|
||||
|
||||
MarkerSettingsWidget* self_;
|
||||
model::MarkerModel* markerModel_;
|
||||
std::shared_ptr<manager::MarkerManager> markerManager_ {
|
||||
manager::MarkerManager::Instance()};
|
||||
};
|
||||
|
||||
|
||||
MarkerSettingsWidget::MarkerSettingsWidget(QWidget* parent) :
|
||||
QFrame(parent),
|
||||
p {std::make_unique<MarkerSettingsWidgetImpl>(this)},
|
||||
ui(new Ui::MarkerSettingsWidget)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
ui->removeButton->setEnabled(false);
|
||||
|
||||
ui->markerView->setModel(p->markerModel_);
|
||||
|
||||
p->ConnectSignals();
|
||||
}
|
||||
|
||||
MarkerSettingsWidget::~MarkerSettingsWidget()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void MarkerSettingsWidgetImpl::ConnectSignals()
|
||||
{
|
||||
QObject::connect(self_->ui->addButton,
|
||||
&QPushButton::clicked,
|
||||
self_,
|
||||
[this]()
|
||||
{
|
||||
markerManager_->add_marker(types::MarkerInfo("", 0, 0));
|
||||
});
|
||||
QObject::connect(self_->ui->removeButton,
|
||||
&QPushButton::clicked,
|
||||
self_,
|
||||
[this]()
|
||||
{
|
||||
auto selectionModel =
|
||||
self_->ui->markerView->selectionModel();
|
||||
QModelIndex selected =
|
||||
selectionModel
|
||||
->selectedRows(static_cast<int>(
|
||||
model::MarkerModel::Column::Name))
|
||||
.first();
|
||||
|
||||
markerManager_->remove_marker(selected.row());
|
||||
});
|
||||
QObject::connect(
|
||||
self_->ui->markerView->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;
|
||||
}
|
||||
|
||||
bool itemSelected = selected.size() > 0;
|
||||
self_->ui->removeButton->setEnabled(itemSelected);
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace ui
|
||||
} // namespace qt
|
||||
} // namespace scwx
|
||||
35
scwx-qt/source/scwx/qt/ui/marker_settings_widget.hpp
Normal file
35
scwx-qt/source/scwx/qt/ui/marker_settings_widget.hpp
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
#pragma once
|
||||
|
||||
#include <QFrame>
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class MarkerSettingsWidget;
|
||||
}
|
||||
|
||||
namespace scwx
|
||||
{
|
||||
namespace qt
|
||||
{
|
||||
namespace ui
|
||||
{
|
||||
|
||||
class MarkerSettingsWidgetImpl;
|
||||
|
||||
class MarkerSettingsWidget : public QFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MarkerSettingsWidget(QWidget* parent = nullptr);
|
||||
~MarkerSettingsWidget();
|
||||
|
||||
private:
|
||||
friend class MarkerSettingsWidgetImpl;
|
||||
std::unique_ptr<MarkerSettingsWidgetImpl> p;
|
||||
Ui::MarkerSettingsWidget* ui;
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
} // namespace qt
|
||||
} // namespace scwx
|
||||
88
scwx-qt/source/scwx/qt/ui/marker_settings_widget.ui
Normal file
88
scwx-qt/source/scwx/qt/ui/marker_settings_widget.ui
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MarkerSettingsWidget</class>
|
||||
<widget class="QFrame" name="MarkerSettingsWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Frame</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QTreeView" name="markerView">
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="indentation">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="sortingEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="buttonFrame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Shape::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Shadow::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<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>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="addButton">
|
||||
<property name="text">
|
||||
<string>&Add</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="removeButton">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>R&emove</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
Loading…
Add table
Add a link
Reference in a new issue