diff --git a/.clang-tidy b/.clang-tidy
index 602e3d0c..3c98e81d 100644
--- a/.clang-tidy
+++ b/.clang-tidy
@@ -10,4 +10,6 @@ Checks:
- '-misc-include-cleaner'
- '-misc-non-private-member-variables-in-classes'
- '-modernize-use-trailing-return-type'
+ - '-bugprone-easily-swappable-parameters'
+ - '-modernize-return-braced-init-list'
FormatStyle: 'file'
diff --git a/scwx-qt/res/icons/font-awesome-6/briefcase-solid.svg b/scwx-qt/res/icons/font-awesome-6/briefcase-solid.svg
new file mode 100644
index 00000000..b16bc330
--- /dev/null
+++ b/scwx-qt/res/icons/font-awesome-6/briefcase-solid.svg
@@ -0,0 +1 @@
+
diff --git a/scwx-qt/res/icons/font-awesome-6/building-columns-solid.svg b/scwx-qt/res/icons/font-awesome-6/building-columns-solid.svg
new file mode 100644
index 00000000..cf0df19a
--- /dev/null
+++ b/scwx-qt/res/icons/font-awesome-6/building-columns-solid.svg
@@ -0,0 +1 @@
+
diff --git a/scwx-qt/res/icons/font-awesome-6/building-solid.svg b/scwx-qt/res/icons/font-awesome-6/building-solid.svg
new file mode 100644
index 00000000..6f6d3f24
--- /dev/null
+++ b/scwx-qt/res/icons/font-awesome-6/building-solid.svg
@@ -0,0 +1 @@
+
diff --git a/scwx-qt/res/icons/font-awesome-6/caravan-solid.svg b/scwx-qt/res/icons/font-awesome-6/caravan-solid.svg
new file mode 100644
index 00000000..c341214f
--- /dev/null
+++ b/scwx-qt/res/icons/font-awesome-6/caravan-solid.svg
@@ -0,0 +1 @@
+
diff --git a/scwx-qt/res/icons/font-awesome-6/house-solid-white.svg b/scwx-qt/res/icons/font-awesome-6/house-solid-white.svg
new file mode 100644
index 00000000..59f65e1e
--- /dev/null
+++ b/scwx-qt/res/icons/font-awesome-6/house-solid-white.svg
@@ -0,0 +1 @@
+
diff --git a/scwx-qt/res/icons/font-awesome-6/location-crosshairs-solid.svg b/scwx-qt/res/icons/font-awesome-6/location-crosshairs-solid.svg
new file mode 100644
index 00000000..5bb1ea5c
--- /dev/null
+++ b/scwx-qt/res/icons/font-awesome-6/location-crosshairs-solid.svg
@@ -0,0 +1 @@
+
diff --git a/scwx-qt/res/icons/font-awesome-6/location-pin.svg b/scwx-qt/res/icons/font-awesome-6/location-pin.svg
new file mode 100644
index 00000000..4b6182cd
--- /dev/null
+++ b/scwx-qt/res/icons/font-awesome-6/location-pin.svg
@@ -0,0 +1,4 @@
+
diff --git a/scwx-qt/res/icons/font-awesome-6/star-solid-white.svg b/scwx-qt/res/icons/font-awesome-6/star-solid-white.svg
new file mode 100644
index 00000000..41bcd103
--- /dev/null
+++ b/scwx-qt/res/icons/font-awesome-6/star-solid-white.svg
@@ -0,0 +1 @@
+
diff --git a/scwx-qt/res/icons/font-awesome-6/tent-solid.svg b/scwx-qt/res/icons/font-awesome-6/tent-solid.svg
new file mode 100644
index 00000000..9f159d60
--- /dev/null
+++ b/scwx-qt/res/icons/font-awesome-6/tent-solid.svg
@@ -0,0 +1 @@
+
diff --git a/scwx-qt/res/textures/images/location-marker.svg b/scwx-qt/res/textures/images/location-marker.svg
index 8ebb064f..3eef9d9e 100644
--- a/scwx-qt/res/textures/images/location-marker.svg
+++ b/scwx-qt/res/textures/images/location-marker.svg
@@ -6,6 +6,6 @@
+ stroke="#ffffff" stroke-width="20" fill="none"/>
diff --git a/scwx-qt/scwx-qt.cmake b/scwx-qt/scwx-qt.cmake
index 1c654b0e..706ac038 100644
--- a/scwx-qt/scwx-qt.cmake
+++ b/scwx-qt/scwx-qt.cmake
@@ -222,8 +222,8 @@ set(HDR_TYPES source/scwx/qt/types/alert_types.hpp
source/scwx/qt/types/layer_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/media_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
@@ -255,6 +255,7 @@ set(HDR_UI source/scwx/qt/ui/about_dialog.hpp
source/scwx/qt/ui/county_dialog.hpp
source/scwx/qt/ui/download_dialog.hpp
source/scwx/qt/ui/edit_line_dialog.hpp
+ source/scwx/qt/ui/edit_marker_dialog.hpp
source/scwx/qt/ui/flow_layout.hpp
source/scwx/qt/ui/gps_info_dialog.hpp
source/scwx/qt/ui/hotkey_edit.hpp
@@ -285,6 +286,7 @@ set(SRC_UI source/scwx/qt/ui/about_dialog.cpp
source/scwx/qt/ui/county_dialog.cpp
source/scwx/qt/ui/download_dialog.cpp
source/scwx/qt/ui/edit_line_dialog.cpp
+ source/scwx/qt/ui/edit_marker_dialog.cpp
source/scwx/qt/ui/flow_layout.cpp
source/scwx/qt/ui/gps_info_dialog.cpp
source/scwx/qt/ui/hotkey_edit.cpp
@@ -314,6 +316,7 @@ set(UI_UI source/scwx/qt/ui/about_dialog.ui
source/scwx/qt/ui/collapsible_group.ui
source/scwx/qt/ui/county_dialog.ui
source/scwx/qt/ui/edit_line_dialog.ui
+ source/scwx/qt/ui/edit_marker_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
@@ -357,6 +360,7 @@ set(HDR_UTIL source/scwx/qt/util/color.hpp
source/scwx/qt/util/network.hpp
source/scwx/qt/util/streams.hpp
source/scwx/qt/util/texture_atlas.hpp
+ source/scwx/qt/util/q_color_modulate.hpp
source/scwx/qt/util/q_file_buffer.hpp
source/scwx/qt/util/q_file_input_stream.hpp
source/scwx/qt/util/time.hpp
@@ -369,6 +373,7 @@ set(SRC_UTIL source/scwx/qt/util/color.cpp
source/scwx/qt/util/maplibre.cpp
source/scwx/qt/util/network.cpp
source/scwx/qt/util/texture_atlas.cpp
+ source/scwx/qt/util/q_color_modulate.cpp
source/scwx/qt/util/q_file_buffer.cpp
source/scwx/qt/util/q_file_input_stream.cpp
source/scwx/qt/util/time.cpp
diff --git a/scwx-qt/scwx-qt.qrc b/scwx-qt/scwx-qt.qrc
index cca0f62c..e7d8315a 100644
--- a/scwx-qt/scwx-qt.qrc
+++ b/scwx-qt/scwx-qt.qrc
@@ -32,6 +32,10 @@
res/icons/font-awesome-6/angles-up-solid.svg
res/icons/font-awesome-6/backward-step-solid.svg
res/icons/font-awesome-6/book-solid.svg
+ res/icons/font-awesome-6/briefcase-solid.svg
+ res/icons/font-awesome-6/building-columns-solid.svg
+ res/icons/font-awesome-6/building-solid.svg
+ res/icons/font-awesome-6/caravan-solid.svg
res/icons/font-awesome-6/copy-regular.svg
res/icons/font-awesome-6/discord.svg
res/icons/font-awesome-6/earth-americas-solid.svg
@@ -40,8 +44,11 @@
res/icons/font-awesome-6/gears-solid.svg
res/icons/font-awesome-6/github.svg
res/icons/font-awesome-6/house-solid.svg
+ res/icons/font-awesome-6/house-solid-white.svg
res/icons/font-awesome-6/keyboard-regular.svg
res/icons/font-awesome-6/layer-group-solid.svg
+ res/icons/font-awesome-6/location-crosshairs-solid.svg
+ res/icons/font-awesome-6/location-pin.svg
res/icons/font-awesome-6/palette-solid.svg
res/icons/font-awesome-6/pause-solid.svg
res/icons/font-awesome-6/play-solid.svg
@@ -53,7 +60,9 @@
res/icons/font-awesome-6/square-minus-regular.svg
res/icons/font-awesome-6/square-plus-regular.svg
res/icons/font-awesome-6/star-solid.svg
+ res/icons/font-awesome-6/star-solid-white.svg
res/icons/font-awesome-6/stop-solid.svg
+ res/icons/font-awesome-6/tent-solid.svg
res/icons/font-awesome-6/volume-high-solid.svg
res/palettes/wct/CC.pal
res/palettes/wct/Default16.pal
diff --git a/scwx-qt/source/scwx/qt/gl/draw/geo_icons.cpp b/scwx-qt/source/scwx/qt/gl/draw/geo_icons.cpp
index 9e2a8d17..743b0df9 100644
--- a/scwx-qt/source/scwx/qt/gl/draw/geo_icons.cpp
+++ b/scwx-qt/source/scwx/qt/gl/draw/geo_icons.cpp
@@ -38,7 +38,7 @@ static constexpr std::size_t kIntegersPerVertex_ = 4;
static constexpr std::size_t kIntegerBufferLength_ =
kNumTriangles * kVerticesPerTriangle * kIntegersPerVertex_;
-struct GeoIconDrawItem
+struct GeoIconDrawItem : types::EventHandler
{
units::length::nautical_miles threshold_ {};
std::chrono::sys_time startTime_ {};
@@ -691,7 +691,7 @@ void GeoIcons::Impl::UpdateSingleBuffer(
hoverIcons.end(),
[&di](auto& entry) { return entry.di_ == di; });
- if (di->visible_ && !di->hoverText_.empty())
+ if (di->visible_ && (!di->hoverText_.empty() || di->event_ != nullptr))
{
const units::angle::radians radians = angle;
@@ -903,7 +903,7 @@ bool GeoIcons::RunMousePicking(
const QPointF& mouseGlobalPos,
const glm::vec2& mouseCoords,
const common::Coordinate& /* mouseGeoCoords */,
- std::shared_ptr& /* eventHandler */)
+ std::shared_ptr& eventHandler)
{
std::unique_lock lock {p->iconMutex_};
@@ -993,12 +993,27 @@ bool GeoIcons::RunMousePicking(
if (it != p->currentHoverIcons_.crend())
{
itemPicked = true;
- util::tooltip::Show(it->di_->hoverText_, mouseGlobalPos);
+ if (!it->di_->hoverText_.empty())
+ {
+ // Show tooltip
+ util::tooltip::Show(it->di_->hoverText_, mouseGlobalPos);
+ }
+ if (it->di_->event_ != nullptr)
+ {
+ eventHandler = it->di_;
+ }
}
return itemPicked;
}
+void GeoIcons::RegisterEventHandler(
+ const std::shared_ptr& di,
+ const std::function& eventHandler)
+{
+ di->event_ = eventHandler;
+}
+
} // namespace draw
} // namespace gl
} // namespace qt
diff --git a/scwx-qt/source/scwx/qt/gl/draw/geo_icons.hpp b/scwx-qt/source/scwx/qt/gl/draw/geo_icons.hpp
index 4d819681..073fc118 100644
--- a/scwx-qt/source/scwx/qt/gl/draw/geo_icons.hpp
+++ b/scwx-qt/source/scwx/qt/gl/draw/geo_icons.hpp
@@ -183,6 +183,16 @@ public:
*/
void FinishIcons();
+ /**
+ * Registers an event handler for an icon.
+ *
+ * @param [in] di Icon draw item
+ * @param [in] eventHandler Event handler function
+ */
+ static void
+ RegisterEventHandler(const std::shared_ptr& di,
+ const std::function& eventHandler);
+
private:
class Impl;
diff --git a/scwx-qt/source/scwx/qt/manager/marker_manager.cpp b/scwx-qt/source/scwx/qt/manager/marker_manager.cpp
index 99208a10..fd7bee13 100644
--- a/scwx-qt/source/scwx/qt/manager/marker_manager.cpp
+++ b/scwx-qt/source/scwx/qt/manager/marker_manager.cpp
@@ -1,13 +1,17 @@
#include
#include
+#include
#include
+#include
#include
+#include
#include
#include
#include
#include
#include
+#include
#include
#include
@@ -27,6 +31,10 @@ 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";
+static const std::string kIconName_ = "icon";
+static const std::string kIconColorName_ = "icon-color";
+
+static const std::string defaultIconName = "images/location-marker";
class MarkerManager::Impl
{
@@ -36,15 +44,16 @@ public:
explicit Impl(MarkerManager* self) : self_ {self} {}
~Impl() { threadPool_.join(); }
- std::string markerSettingsPath_ {""};
- std::vector> markerRecords_ {};
+ std::string markerSettingsPath_ {""};
+ std::vector> markerRecords_ {};
std::unordered_map idToIndex_ {};
-
+ std::unordered_map markerIcons_ {};
MarkerManager* self_;
boost::asio::thread_pool threadPool_ {1u};
std::shared_mutex markerRecordLock_ {};
+ std::shared_mutex markerIconsLock_ {};
void InitializeMarkerSettings();
void ReadMarkerSettings();
@@ -53,16 +62,12 @@ public:
void InitalizeIds();
types::MarkerId NewId();
- types::MarkerId lastId_;
+ types::MarkerId lastId_ {0};
};
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}
{
@@ -81,16 +86,50 @@ public:
{
jv = {{kNameName_, record->markerInfo_.name},
{kLatitudeName_, record->markerInfo_.latitude},
- {kLongitudeName_, record->markerInfo_.longitude}};
+ {kLongitudeName_, record->markerInfo_.longitude},
+ {kIconName_, record->markerInfo_.iconName},
+ {kIconColorName_,
+ util::color::ToArgbString(record->markerInfo_.iconColor)}};
}
friend MarkerRecord tag_invoke(boost::json::value_to_tag,
const boost::json::value& jv)
{
- return MarkerRecord(
+ static const boost::gil::rgba8_pixel_t defaultIconColor =
+ util::color::ToRgba8PixelT("#ffff0000");
+
+ const boost::json::object& jo = jv.as_object();
+
+ std::string iconName = defaultIconName;
+ boost::gil::rgba8_pixel_t iconColor = defaultIconColor;
+
+ if (jo.contains(kIconName_) && jo.at(kIconName_).is_string())
+ {
+ iconName = boost::json::value_to(jv.at(kIconName_));
+ }
+
+ if (jo.contains(kIconColorName_) && jo.at(kIconName_).is_string())
+ {
+ try
+ {
+ iconColor = util::color::ToRgba8PixelT(
+ boost::json::value_to(jv.at(kIconColorName_)));
+ }
+ catch (const std::exception& ex)
+ {
+ logger_->warn(
+ "Could not parse color value in location-markers.json with the "
+ "following exception: {}",
+ ex.what());
+ }
+ }
+
+ return {types::MarkerInfo(
boost::json::value_to(jv.at(kNameName_)),
boost::json::value_to(jv.at(kLatitudeName_)),
- boost::json::value_to(jv.at(kLongitudeName_)));
+ boost::json::value_to(jv.at(kLongitudeName_)),
+ iconName,
+ iconColor)};
}
};
@@ -129,7 +168,7 @@ void MarkerManager::Impl::ReadMarkerSettings()
boost::json::value markerJson = nullptr;
{
- std::unique_lock lock(markerRecordLock_);
+ const std::unique_lock lock(markerRecordLock_);
// Determine if marker settings exists
if (std::filesystem::exists(markerSettingsPath_))
@@ -147,18 +186,16 @@ void MarkerManager::Impl::ReadMarkerSettings()
{
try
{
- MarkerRecord record =
- boost::json::value_to(markerEntry);
+ auto record = boost::json::value_to(markerEntry);
- if (!record.markerInfo_.name.empty())
- {
- types::MarkerId id = NewId();
- size_t index = markerRecords_.size();
- record.markerInfo_.id = id;
- markerRecords_.emplace_back(
- std::make_shared(record.markerInfo_));
- idToIndex_.emplace(id, index);
- }
+ const types::MarkerId id = NewId();
+ const size_t index = markerRecords_.size();
+ record.markerInfo_.id = id;
+ markerRecords_.emplace_back(
+ std::make_shared(record.markerInfo_));
+ idToIndex_.emplace(id, index);
+
+ self_->add_icon(record.markerInfo_.iconName, true);
}
catch (const std::exception& ex)
{
@@ -166,6 +203,8 @@ void MarkerManager::Impl::ReadMarkerSettings()
}
}
+ ResourceManager::BuildAtlas();
+
logger_->debug("{} location marker entries", markerRecords_.size());
}
}
@@ -177,7 +216,7 @@ void MarkerManager::Impl::WriteMarkerSettings()
{
logger_->info("Saving location marker settings");
- std::shared_lock lock(markerRecordLock_);
+ const std::shared_lock lock(markerRecordLock_);
auto markerJson = boost::json::value_from(markerRecords_);
util::json::WriteJsonFile(markerSettingsPath_, markerJson);
}
@@ -198,6 +237,20 @@ MarkerManager::Impl::GetMarkerByName(const std::string& name)
MarkerManager::MarkerManager() : p(std::make_unique(this))
{
+ static const std::vector defaultMarkerIcons_ {
+ types::MarkerIconInfo(types::ImageTexture::LocationMarker, -1, -1),
+ types::MarkerIconInfo(types::ImageTexture::LocationPin, 6, 16),
+ types::MarkerIconInfo(types::ImageTexture::LocationCrosshair, -1, -1),
+ types::MarkerIconInfo(types::ImageTexture::LocationStar, -1, -1),
+ types::MarkerIconInfo(types::ImageTexture::LocationBriefcase, -1, -1),
+ types::MarkerIconInfo(
+ types::ImageTexture::LocationBuildingColumns, -1, -1),
+ types::MarkerIconInfo(types::ImageTexture::LocationBuilding, -1, -1),
+ types::MarkerIconInfo(types::ImageTexture::LocationCaravan, -1, -1),
+ types::MarkerIconInfo(types::ImageTexture::LocationHouse, -1, -1),
+ types::MarkerIconInfo(types::ImageTexture::LocationTent, -1, -1),
+ };
+
p->InitializeMarkerSettings();
boost::asio::post(p->threadPool_,
@@ -207,8 +260,18 @@ MarkerManager::MarkerManager() : p(std::make_unique(this))
{
// Read Marker settings on startup
main::Application::WaitForInitialization();
+ {
+ const std::unique_lock lock(p->markerIconsLock_);
+ p->markerIcons_.reserve(
+ defaultMarkerIcons_.size());
+ for (auto& icon : defaultMarkerIcons_)
+ {
+ p->markerIcons_.emplace(icon.name, icon);
+ }
+ }
p->ReadMarkerSettings();
+ Q_EMIT IconsReady();
Q_EMIT MarkersInitialized(p->markerRecords_.size());
}
catch (const std::exception& ex)
@@ -230,7 +293,7 @@ size_t MarkerManager::marker_count()
std::optional MarkerManager::get_marker(types::MarkerId id)
{
- std::shared_lock lock(p->markerRecordLock_);
+ const std::shared_lock lock(p->markerRecordLock_);
if (!p->idToIndex_.contains(id))
{
return {};
@@ -248,7 +311,7 @@ std::optional MarkerManager::get_marker(types::MarkerId id)
std::optional MarkerManager::get_index(types::MarkerId id)
{
- std::shared_lock lock(p->markerRecordLock_);
+ const std::shared_lock lock(p->markerRecordLock_);
if (!p->idToIndex_.contains(id))
{
return {};
@@ -256,10 +319,11 @@ std::optional MarkerManager::get_index(types::MarkerId id)
return p->idToIndex_[id];
}
-void MarkerManager::set_marker(types::MarkerId id, const types::MarkerInfo& marker)
+void MarkerManager::set_marker(types::MarkerId id,
+ const types::MarkerInfo& marker)
{
{
- std::unique_lock lock(p->markerRecordLock_);
+ const std::unique_lock lock(p->markerRecordLock_);
if (!p->idToIndex_.contains(id))
{
return;
@@ -270,33 +334,39 @@ void MarkerManager::set_marker(types::MarkerId id, const types::MarkerInfo& mark
logger_->warn("id in idToIndex_ but out of range!");
return;
}
- std::shared_ptr& markerRecord =
+ const std::shared_ptr& markerRecord =
p->markerRecords_[index];
- markerRecord->markerInfo_ = marker;
+ markerRecord->markerInfo_ = marker;
+ markerRecord->markerInfo_.id = id;
+
+ add_icon(marker.iconName);
}
Q_EMIT MarkerChanged(id);
Q_EMIT MarkersUpdated();
}
-void MarkerManager::add_marker(const types::MarkerInfo& marker)
+types::MarkerId MarkerManager::add_marker(const types::MarkerInfo& marker)
{
types::MarkerId id;
{
- std::unique_lock lock(p->markerRecordLock_);
+ const std::unique_lock lock(p->markerRecordLock_);
id = p->NewId();
size_t index = p->markerRecords_.size();
p->idToIndex_.emplace(id, index);
p->markerRecords_.emplace_back(std::make_shared(marker));
p->markerRecords_[index]->markerInfo_.id = id;
+
+ add_icon(marker.iconName);
}
Q_EMIT MarkerAdded(id);
Q_EMIT MarkersUpdated();
+ return id;
}
void MarkerManager::remove_marker(types::MarkerId id)
{
{
- std::unique_lock lock(p->markerRecordLock_);
+ const std::unique_lock lock(p->markerRecordLock_);
if (!p->idToIndex_.contains(id))
{
return;
@@ -327,7 +397,7 @@ void MarkerManager::remove_marker(types::MarkerId id)
void MarkerManager::move_marker(size_t from, size_t to)
{
{
- std::unique_lock lock(p->markerRecordLock_);
+ const std::unique_lock lock(p->markerRecordLock_);
if (from >= p->markerRecords_.size() || to >= p->markerRecords_.size())
{
return;
@@ -358,13 +428,64 @@ void MarkerManager::move_marker(size_t from, size_t to)
void MarkerManager::for_each(std::function func)
{
- std::shared_lock lock(p->markerRecordLock_);
+ const std::shared_lock lock(p->markerRecordLock_);
for (auto marker : p->markerRecords_)
{
func(marker->markerInfo_);
}
}
+void MarkerManager::add_icon(const std::string& name, bool startup)
+{
+ {
+ const std::unique_lock lock(p->markerIconsLock_);
+ if (p->markerIcons_.contains(name))
+ {
+ return;
+ }
+ const std::shared_ptr image =
+ ResourceManager::LoadImageResource(name);
+
+ if (image)
+ {
+ auto icon = types::MarkerIconInfo(name, -1, -1, image);
+ p->markerIcons_.emplace(name, icon);
+ }
+ else
+ {
+ // defaultIconName should always be in markerIcons, so at is fine
+ auto icon = p->markerIcons_.at(defaultIconName);
+ p->markerIcons_.emplace(name, icon);
+ }
+ }
+
+ if (!startup)
+ {
+ ResourceManager::BuildAtlas();
+ Q_EMIT IconAdded(name);
+ }
+}
+
+std::optional
+MarkerManager::get_icon(const std::string& name)
+{
+ const std::shared_lock lock(p->markerIconsLock_);
+ auto it = p->markerIcons_.find(name);
+ if (it != p->markerIcons_.end())
+ {
+ return it->second;
+ }
+
+ return {};
+}
+
+const std::unordered_map
+MarkerManager::get_icons()
+{
+ const std::shared_lock lock(p->markerIconsLock_);
+ return p->markerIcons_;
+}
+
// Only use for testing
void MarkerManager::set_marker_settings_path(const std::string& path)
{
@@ -377,7 +498,7 @@ std::shared_ptr MarkerManager::Instance()
static std::weak_ptr markerManagerReference_ {};
static std::mutex instanceMutex_ {};
- std::unique_lock lock(instanceMutex_);
+ const std::unique_lock lock(instanceMutex_);
std::shared_ptr markerManager =
markerManagerReference_.lock();
@@ -391,6 +512,11 @@ std::shared_ptr MarkerManager::Instance()
return markerManager;
}
+const std::string& MarkerManager::getDefaultIconName()
+{
+ return defaultIconName;
+}
+
} // namespace manager
} // namespace qt
} // namespace scwx
diff --git a/scwx-qt/source/scwx/qt/manager/marker_manager.hpp b/scwx-qt/source/scwx/qt/manager/marker_manager.hpp
index 37ec1c31..7004e117 100644
--- a/scwx-qt/source/scwx/qt/manager/marker_manager.hpp
+++ b/scwx-qt/source/scwx/qt/manager/marker_manager.hpp
@@ -23,11 +23,15 @@ public:
size_t marker_count();
std::optional get_marker(types::MarkerId id);
- std::optional get_index(types::MarkerId id);
+ std::optional get_index(types::MarkerId id);
void set_marker(types::MarkerId id, const types::MarkerInfo& marker);
- void add_marker(const types::MarkerInfo& marker);
- void remove_marker(types::MarkerId id);
- void move_marker(size_t from, size_t to);
+ types::MarkerId add_marker(const types::MarkerInfo& marker);
+ void remove_marker(types::MarkerId id);
+ void move_marker(size_t from, size_t to);
+
+ void add_icon(const std::string& name, bool startup = false);
+ std::optional get_icon(const std::string& name);
+ const std::unordered_map get_icons();
void for_each(std::function func);
@@ -35,6 +39,7 @@ public:
void set_marker_settings_path(const std::string& path);
static std::shared_ptr Instance();
+ static const std::string& getDefaultIconName();
signals:
void MarkersInitialized(size_t count);
@@ -43,6 +48,9 @@ signals:
void MarkerAdded(types::MarkerId id);
void MarkerRemoved(types::MarkerId id);
+ void IconsReady();
+ void IconAdded(std::string name);
+
private:
class Impl;
std::unique_ptr p;
diff --git a/scwx-qt/source/scwx/qt/manager/resource_manager.cpp b/scwx-qt/source/scwx/qt/manager/resource_manager.cpp
index 443d771b..c6c40a26 100644
--- a/scwx-qt/source/scwx/qt/manager/resource_manager.cpp
+++ b/scwx-qt/source/scwx/qt/manager/resource_manager.cpp
@@ -22,6 +22,9 @@ namespace ResourceManager
static const std::string logPrefix_ = "scwx::qt::manager::resource_manager";
static const auto logger_ = scwx::util::Logger::Create(logPrefix_);
+static const size_t atlasWidth = 2048;
+static const size_t atlasHeight = 2048;
+
static void LoadFonts();
static void LoadTextures();
@@ -68,8 +71,7 @@ LoadImageResources(const std::vector& urlStrings)
if (!images.empty())
{
- util::TextureAtlas& textureAtlas = util::TextureAtlas::Instance();
- textureAtlas.BuildAtlas(2048, 2048);
+ BuildAtlas();
}
return images;
@@ -103,7 +105,13 @@ static void LoadTextures()
GetTexturePath(lineTexture));
}
- textureAtlas.BuildAtlas(2048, 2048);
+ BuildAtlas();
+}
+
+void BuildAtlas()
+{
+ util::TextureAtlas& textureAtlas = util::TextureAtlas::Instance();
+ textureAtlas.BuildAtlas(atlasWidth, atlasHeight);
}
} // namespace ResourceManager
diff --git a/scwx-qt/source/scwx/qt/manager/resource_manager.hpp b/scwx-qt/source/scwx/qt/manager/resource_manager.hpp
index 00658891..ec7cf65e 100644
--- a/scwx-qt/source/scwx/qt/manager/resource_manager.hpp
+++ b/scwx-qt/source/scwx/qt/manager/resource_manager.hpp
@@ -22,6 +22,7 @@ std::shared_ptr
LoadImageResource(const std::string& urlString);
std::vector>
LoadImageResources(const std::vector& urlStrings);
+void BuildAtlas();
} // namespace ResourceManager
} // namespace manager
diff --git a/scwx-qt/source/scwx/qt/map/map_widget.cpp b/scwx-qt/source/scwx/qt/map/map_widget.cpp
index bfe0908c..f7ba99ae 100644
--- a/scwx-qt/source/scwx/qt/map/map_widget.cpp
+++ b/scwx-qt/source/scwx/qt/map/map_widget.cpp
@@ -9,10 +9,10 @@
#include
#include
#include
+#include
#include
#include
#include
-#include
#include
#include
#include
@@ -21,6 +21,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -127,8 +128,6 @@ public:
ImGui_ImplQt_Init();
InitializeCustomStyles();
-
- ConnectSignals();
}
~MapWidgetImpl()
@@ -219,6 +218,8 @@ public:
std::shared_ptr layerModel_ {
model::LayerModel::Instance()};
+ ui::EditMarkerDialog* editMarkerDialog_ {nullptr};
+
std::shared_ptr hotkeyManager_ {
manager::HotkeyManager::Instance()};
std::shared_ptr placefileManager_ {
@@ -283,6 +284,12 @@ MapWidget::MapWidget(std::size_t id, const QMapLibre::Settings& settings) :
setFocusPolicy(Qt::StrongFocus);
ImGui_ImplQt_RegisterWidget(this);
+
+ // Qt parent deals with memory management
+ // NOLINTNEXTLINE(cppcoreguidelines-owning-memory)
+ p->editMarkerDialog_ = new ui::EditMarkerDialog(this);
+
+ p->ConnectSignals();
}
MapWidget::~MapWidget()
@@ -429,6 +436,16 @@ void MapWidgetImpl::HandleHotkeyPressed(types::Hotkey hotkey, bool isAutoRepeat)
switch (hotkey)
{
+ case types::Hotkey::AddLocationMarker:
+ if (hasMouse_)
+ {
+ auto coordinate = map_->coordinateForPixel(lastPos_);
+
+ editMarkerDialog_->setup(coordinate.first, coordinate.second);
+ editMarkerDialog_->show();
+ }
+ break;
+
case types::Hotkey::ChangeMapStyle:
if (context_->settings().isActive_)
{
diff --git a/scwx-qt/source/scwx/qt/map/marker_layer.cpp b/scwx-qt/source/scwx/qt/map/marker_layer.cpp
index 0480a63e..906ef7c1 100644
--- a/scwx-qt/source/scwx/qt/map/marker_layer.cpp
+++ b/scwx-qt/source/scwx/qt/map/marker_layer.cpp
@@ -1,9 +1,14 @@
#include
#include
#include
-#include
-#include
#include
+#include
+#include
+
+#include
+#include
+
+#include
namespace scwx
{
@@ -19,48 +24,104 @@ class MarkerLayer::Impl
{
public:
explicit Impl(MarkerLayer* self, std::shared_ptr context) :
- self_ {self}, geoIcons_ {std::make_shared(context)}
+ self_ {self},
+ geoIcons_ {std::make_shared(context)},
+ editMarkerDialog_ {std::make_shared()}
{
ConnectSignals();
}
- ~Impl() {}
+ ~Impl() = default;
void ReloadMarkers();
void ConnectSignals();
+ std::shared_ptr markerManager_ {
+ manager::MarkerManager::Instance()};
+
+ void set_icon_sheets();
+
MarkerLayer* self_;
- const std::string& markerIconName_ {
- types::GetTextureName(types::ImageTexture::LocationMarker)};
std::shared_ptr geoIcons_;
+ std::shared_ptr editMarkerDialog_;
};
void MarkerLayer::Impl::ConnectSignals()
{
- auto markerManager = manager::MarkerManager::Instance();
-
- QObject::connect(markerManager.get(),
- &manager::MarkerManager::MarkersUpdated,
- self_,
- [this]()
- {
- this->ReloadMarkers();
- });
+ QObject::connect(markerManager_.get(),
+ &manager::MarkerManager::MarkersUpdated,
+ self_,
+ [this]() { ReloadMarkers(); });
+ QObject::connect(markerManager_.get(),
+ &manager::MarkerManager::IconsReady,
+ self_,
+ [this]() { set_icon_sheets(); });
+ QObject::connect(markerManager_.get(),
+ &manager::MarkerManager::IconAdded,
+ self_,
+ [this]() { set_icon_sheets(); });
}
void MarkerLayer::Impl::ReloadMarkers()
{
logger_->debug("ReloadMarkers()");
- auto markerManager = manager::MarkerManager::Instance();
geoIcons_->StartIcons();
-
- markerManager->for_each(
+ markerManager_->for_each(
[this](const types::MarkerInfo& marker)
{
- std::shared_ptr icon = geoIcons_->AddIcon();
- geoIcons_->SetIconTexture(icon, markerIconName_, 0);
+ // must use local ID, instead of reference to marker in event handler
+ // callback.
+ const types::MarkerId id = marker.id;
+
+ const std::shared_ptr icon =
+ geoIcons_->AddIcon();
+
+ const std::string latitudeString =
+ common::GetLatitudeString(marker.latitude);
+ const std::string longitudeString =
+ common::GetLongitudeString(marker.longitude);
+
+ const std::string hoverText =
+ marker.name != "" ?
+ fmt::format(
+ "{}\n{}, {}", marker.name, latitudeString, longitudeString) :
+ fmt::format("{}, {}", latitudeString, longitudeString);
+
+ auto iconInfo = markerManager_->get_icon(marker.iconName);
+ if (iconInfo)
+ {
+ geoIcons_->SetIconTexture(icon, iconInfo->name, 0);
+ }
+ else
+ {
+ geoIcons_->SetIconTexture(icon, marker.iconName, 0);
+ }
+
geoIcons_->SetIconLocation(icon, marker.latitude, marker.longitude);
+ geoIcons_->SetIconHoverText(icon, hoverText);
+ geoIcons_->SetIconModulate(icon, marker.iconColor);
+ geoIcons_->RegisterEventHandler(
+ icon,
+ [this, id](QEvent* ev)
+ {
+ switch (ev->type())
+ {
+ case QEvent::Type::MouseButtonPress:
+ {
+ auto* mouseEvent = reinterpret_cast(ev);
+ if (mouseEvent->buttons() == Qt::MouseButton::RightButton)
+ {
+ editMarkerDialog_->setup(id);
+ editMarkerDialog_->show();
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ });
});
geoIcons_->FinishIcons();
@@ -80,17 +141,28 @@ void MarkerLayer::Initialize()
logger_->debug("Initialize()");
DrawLayer::Initialize();
- p->geoIcons_->StartIconSheets();
- p->geoIcons_->AddIconSheet(p->markerIconName_);
- p->geoIcons_->FinishIconSheets();
-
+ p->set_icon_sheets();
p->ReloadMarkers();
}
+void MarkerLayer::Impl::set_icon_sheets()
+{
+ geoIcons_->StartIconSheets();
+ for (auto& markerIcon : markerManager_->get_icons())
+ {
+ geoIcons_->AddIconSheet(markerIcon.second.name,
+ 0,
+ 0,
+ markerIcon.second.hotX,
+ markerIcon.second.hotY);
+ }
+ geoIcons_->FinishIconSheets();
+}
+
void MarkerLayer::Render(const QMapLibre::CustomLayerRenderParameters& params)
{
- // auto markerManager = manager::MarkerManager::Instance();
gl::OpenGLFunctions& gl = context()->gl();
+ context()->set_render_parameters(params);
DrawLayer::Render(params);
diff --git a/scwx-qt/source/scwx/qt/model/marker_model.cpp b/scwx-qt/source/scwx/qt/model/marker_model.cpp
index e550312e..77fb7ab7 100644
--- a/scwx-qt/source/scwx/qt/model/marker_model.cpp
+++ b/scwx-qt/source/scwx/qt/model/marker_model.cpp
@@ -3,6 +3,7 @@
#include
#include
#include
+#include
#include
#include
@@ -18,6 +19,7 @@ namespace model
static const std::string logPrefix_ = "scwx::qt::model::marker_model";
static const auto logger_ = scwx::util::Logger::Create(logPrefix_);
+static const int iconSize_ = 30;
static constexpr int kFirstColumn =
static_cast(MarkerModel::Column::Latitude);
@@ -38,7 +40,6 @@ public:
MarkerModel::MarkerModel(QObject* parent) :
QAbstractTableModel(parent), p(std::make_unique())
{
-
connect(p->markerManager_.get(),
&manager::MarkerManager::MarkersInitialized,
this,
@@ -78,26 +79,11 @@ Qt::ItemFlags MarkerModel::flags(const QModelIndex& index) const
{
Qt::ItemFlags flags = QAbstractTableModel::flags(index);
- switch (index.column())
- {
- case static_cast(Column::Name):
- case static_cast(Column::Latitude):
- case static_cast(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 ||
static_cast(index.row()) >= p->markerIds_.size())
{
@@ -118,8 +104,7 @@ QVariant MarkerModel::data(const QModelIndex& index, int role) const
{
case static_cast(Column::Name):
if (role == Qt::ItemDataRole::DisplayRole ||
- role == Qt::ItemDataRole::ToolTipRole ||
- role == Qt::ItemDataRole::EditRole)
+ role == Qt::ItemDataRole::ToolTipRole)
{
return QString::fromStdString(markerInfo->name);
}
@@ -132,11 +117,6 @@ QVariant MarkerModel::data(const QModelIndex& index, int role) const
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(Column::Longitude):
@@ -146,13 +126,41 @@ QVariant MarkerModel::data(const QModelIndex& index, int role) const
return QString::fromStdString(
common::GetLongitudeString(markerInfo->longitude));
}
- else if (role == Qt::ItemDataRole::EditRole)
- {
- return QString::number(
- markerInfo->longitude, COORDINATE_FORMAT, COORDINATE_PRECISION);
- }
break;
break;
+ case static_cast(Column::Icon):
+ if (role == Qt::ItemDataRole::DisplayRole)
+ {
+ std::optional icon =
+ p->markerManager_->get_icon(markerInfo->iconName);
+ if (icon)
+ {
+ return QString::fromStdString(icon->shortName);
+ }
+ else
+ {
+ return {};
+ }
+ }
+ else if (role == Qt::ItemDataRole::DecorationRole)
+ {
+ std::optional icon =
+ p->markerManager_->get_icon(markerInfo->iconName);
+ if (icon)
+ {
+ return util::modulateColors(icon->qIcon,
+ QSize(iconSize_, iconSize_),
+ QColor(markerInfo->iconColor[0],
+ markerInfo->iconColor[1],
+ markerInfo->iconColor[2],
+ markerInfo->iconColor[3]));
+ }
+ else
+ {
+ return {};
+ }
+ }
+ break;
default:
break;
@@ -190,6 +198,9 @@ QVariant MarkerModel::headerData(int section,
case static_cast(Column::Longitude):
return tr("Longitude");
+ case static_cast(Column::Icon):
+ return tr("Icon");
+
default:
break;
}
@@ -199,78 +210,9 @@ QVariant MarkerModel::headerData(int section,
return QVariant();
}
-bool MarkerModel::setData(const QModelIndex& index,
- const QVariant& value,
- int role)
+bool MarkerModel::setData(const QModelIndex&, const QVariant&, int)
{
-
- if (!index.isValid() || index.row() < 0 ||
- static_cast(index.row()) >= p->markerIds_.size())
- {
- return false;
- }
-
- types::MarkerId id = p->markerIds_[index.row()];
- std::optional markerInfo =
- p->markerManager_->get_marker(id);
- if (!markerInfo)
- {
- return false;
- }
- bool result = false;
-
- switch(index.column())
- {
- case static_cast(Column::Name):
- if (role == Qt::ItemDataRole::EditRole)
- {
- QString str = value.toString();
- markerInfo->name = str.toStdString();
- p->markerManager_->set_marker(id, *markerInfo);
- result = true;
- }
- break;
-
- case static_cast(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(id, *markerInfo);
- result = true;
- }
- }
- break;
-
- case static_cast(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(id, *markerInfo);
- result = true;
- }
- }
- break;
-
- default:
- break;
- }
-
- if (result)
- {
- Q_EMIT dataChanged(index, index);
- }
-
- return result;
+ return false;
}
void MarkerModel::HandleMarkersInitialized(size_t count)
diff --git a/scwx-qt/source/scwx/qt/model/marker_model.hpp b/scwx-qt/source/scwx/qt/model/marker_model.hpp
index 4fc6c95c..91c8854f 100644
--- a/scwx-qt/source/scwx/qt/model/marker_model.hpp
+++ b/scwx-qt/source/scwx/qt/model/marker_model.hpp
@@ -17,7 +17,8 @@ public:
{
Latitude = 0,
Longitude = 1,
- Name = 2,
+ Icon = 2,
+ Name = 3,
};
explicit MarkerModel(QObject* parent = nullptr);
diff --git a/scwx-qt/source/scwx/qt/settings/hotkey_settings.cpp b/scwx-qt/source/scwx/qt/settings/hotkey_settings.cpp
index 0edaf840..e9c6b007 100644
--- a/scwx-qt/source/scwx/qt/settings/hotkey_settings.cpp
+++ b/scwx-qt/source/scwx/qt/settings/hotkey_settings.cpp
@@ -12,6 +12,7 @@ namespace settings
static const std::string logPrefix_ = "scwx::qt::settings::hotkey_settings";
static const std::unordered_map kDefaultHotkeys_ {
+ {types::Hotkey::AddLocationMarker, QKeySequence {Qt::Key::Key_M}},
{types::Hotkey::ChangeMapStyle, QKeySequence {Qt::Key::Key_Z}},
{types::Hotkey::CopyCursorCoordinates,
QKeySequence {QKeyCombination {Qt::KeyboardModifier::ControlModifier,
diff --git a/scwx-qt/source/scwx/qt/types/hotkey_types.cpp b/scwx-qt/source/scwx/qt/types/hotkey_types.cpp
index 8a4d0ee5..72c77f63 100644
--- a/scwx-qt/source/scwx/qt/types/hotkey_types.cpp
+++ b/scwx-qt/source/scwx/qt/types/hotkey_types.cpp
@@ -13,6 +13,7 @@ namespace types
{
static const std::unordered_map hotkeyShortName_ {
+ {Hotkey::AddLocationMarker, "add_location_marker"},
{Hotkey::ChangeMapStyle, "change_map_style"},
{Hotkey::CopyCursorCoordinates, "copy_cursor_coordinates"},
{Hotkey::CopyMapCoordinates, "copy_map_coordinates"},
@@ -52,6 +53,7 @@ static const std::unordered_map hotkeyShortName_ {
{Hotkey::Unknown, "?"}};
static const std::unordered_map hotkeyLongName_ {
+ {Hotkey::AddLocationMarker, "Add Location Marker"},
{Hotkey::ChangeMapStyle, "Change Map Style"},
{Hotkey::CopyCursorCoordinates, "Copy Cursor Coordinates"},
{Hotkey::CopyMapCoordinates, "Copy Map Coordinates"},
diff --git a/scwx-qt/source/scwx/qt/types/hotkey_types.hpp b/scwx-qt/source/scwx/qt/types/hotkey_types.hpp
index c2118a4f..2107a009 100644
--- a/scwx-qt/source/scwx/qt/types/hotkey_types.hpp
+++ b/scwx-qt/source/scwx/qt/types/hotkey_types.hpp
@@ -13,6 +13,7 @@ namespace types
enum class Hotkey
{
+ AddLocationMarker,
ChangeMapStyle,
CopyCursorCoordinates,
CopyMapCoordinates,
@@ -52,7 +53,7 @@ enum class Hotkey
Unknown
};
typedef scwx::util::
- Iterator
+ Iterator
HotkeyIterator;
Hotkey GetHotkeyFromShortName(const std::string& name);
diff --git a/scwx-qt/source/scwx/qt/types/marker_types.hpp b/scwx-qt/source/scwx/qt/types/marker_types.hpp
index e3d28e26..661aa207 100644
--- a/scwx-qt/source/scwx/qt/types/marker_types.hpp
+++ b/scwx-qt/source/scwx/qt/types/marker_types.hpp
@@ -1,29 +1,82 @@
#pragma once
-#include
-#include
+#include
-namespace scwx
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+namespace scwx::qt::types
{
-namespace qt
-{
-namespace types
-{
-typedef std::uint64_t MarkerId;
+using MarkerId = std::uint64_t;
struct MarkerInfo
{
- MarkerInfo(const std::string& name, double latitude, double longitude) :
- name {name}, latitude {latitude}, longitude {longitude}
+ MarkerInfo(std::string name,
+ double latitude,
+ double longitude,
+ std::string iconName,
+ const boost::gil::rgba8_pixel_t& iconColor) :
+ name {std::move(name)},
+ latitude {latitude},
+ longitude {longitude},
+ iconName {std::move(iconName)},
+ iconColor {iconColor}
{
}
- MarkerId id;
- std::string name;
- double latitude;
- double longitude;
+ MarkerId id {0};
+ std::string name;
+ double latitude;
+ double longitude;
+ std::string iconName;
+ boost::gil::rgba8_pixel_t iconColor;
};
-} // namespace types
-} // namespace qt
-} // namespace scwx
+struct MarkerIconInfo
+{
+ // Initializer for default icons (which use a texture)
+ explicit MarkerIconInfo(types::ImageTexture texture,
+ std::int32_t hotX,
+ std::int32_t hotY) :
+ name {types::GetTextureName(texture)},
+ path {types::GetTexturePath(texture)},
+ hotX {hotX},
+ hotY {hotY},
+ qIcon {QIcon(QString::fromStdString(path))},
+ image {}
+ {
+ auto qName = QString::fromStdString(name);
+ QStringList parts = qName.split("location-");
+ shortName = parts.last().toStdString();
+ }
+
+ // Initializer for custom icons (which use a file path)
+ explicit MarkerIconInfo(const std::string& path,
+ std::int32_t hotX,
+ std::int32_t hotY,
+ std::shared_ptr image) :
+ name {path},
+ path {path},
+ shortName {QFileInfo(path.c_str()).fileName().toStdString()},
+ hotX {hotX},
+ hotY {hotY},
+ qIcon {QIcon(QString::fromStdString(path))},
+ image {image}
+ {
+ }
+
+ std::string name;
+ std::string path;
+ std::string shortName;
+ std::int32_t hotX;
+ std::int32_t hotY;
+ QIcon qIcon;
+ std::optional> image;
+};
+
+} // namespace scwx::qt::types
diff --git a/scwx-qt/source/scwx/qt/types/texture_types.cpp b/scwx-qt/source/scwx/qt/types/texture_types.cpp
index 7f0c7a24..18efd9b9 100644
--- a/scwx-qt/source/scwx/qt/types/texture_types.cpp
+++ b/scwx-qt/source/scwx/qt/types/texture_types.cpp
@@ -25,8 +25,33 @@ static const std::unordered_map imageTextureInfo_ {
{ImageTexture::Cursor17,
{"images/cursor-17", ":/res/textures/images/cursor-17.png"}},
{ImageTexture::Dot3, {"images/dot-3", ":/res/textures/images/dot-3.png"}},
+ {ImageTexture::LocationBriefcase,
+ {"images/location-briefcase",
+ ":/res/icons/font-awesome-6/briefcase-solid.svg"}},
+ {ImageTexture::LocationBuildingColumns,
+ {"images/location-building-columns",
+ ":/res/icons/font-awesome-6/building-columns-solid.svg"}},
+ {ImageTexture::LocationBuilding,
+ {"images/location-building",
+ ":/res/icons/font-awesome-6/building-solid.svg"}},
+ {ImageTexture::LocationCaravan,
+ {"images/location-caravan",
+ ":/res/icons/font-awesome-6/caravan-solid.svg"}},
+ {ImageTexture::LocationCrosshair,
+ {"images/location-crosshair",
+ ":/res/icons/font-awesome-6/location-crosshairs-solid.svg"}},
+ {ImageTexture::LocationHouse,
+ {"images/location-house",
+ ":/res/icons/font-awesome-6/house-solid-white.svg"}},
{ImageTexture::LocationMarker,
{"images/location-marker", ":/res/textures/images/location-marker.svg"}},
+ {ImageTexture::LocationPin,
+ {"images/location-pin", ":/res/icons/font-awesome-6/location-pin.svg"}},
+ {ImageTexture::LocationStar,
+ {"images/location-star",
+ ":/res/icons/font-awesome-6/star-solid-white.svg"}},
+ {ImageTexture::LocationTent,
+ {"images/location-tent", ":/res/icons/font-awesome-6/tent-solid.svg"}},
{ImageTexture::MapboxLogo,
{"images/mapbox-logo", ":/res/textures/images/mapbox-logo.svg"}},
{ImageTexture::MapTilerLogo,
diff --git a/scwx-qt/source/scwx/qt/types/texture_types.hpp b/scwx-qt/source/scwx/qt/types/texture_types.hpp
index 307a7638..d5eabc4a 100644
--- a/scwx-qt/source/scwx/qt/types/texture_types.hpp
+++ b/scwx-qt/source/scwx/qt/types/texture_types.hpp
@@ -18,7 +18,16 @@ enum class ImageTexture
Crosshairs24,
Cursor17,
Dot3,
+ LocationBriefcase,
+ LocationBuildingColumns,
+ LocationBuilding,
+ LocationCaravan,
+ LocationCrosshair,
+ LocationHouse,
LocationMarker,
+ LocationPin,
+ LocationStar,
+ LocationTent,
MapboxLogo,
MapTilerLogo
};
diff --git a/scwx-qt/source/scwx/qt/ui/edit_marker_dialog.cpp b/scwx-qt/source/scwx/qt/ui/edit_marker_dialog.cpp
new file mode 100644
index 00000000..a6aaa4d4
--- /dev/null
+++ b/scwx-qt/source/scwx/qt/ui/edit_marker_dialog.cpp
@@ -0,0 +1,314 @@
+#include "edit_marker_dialog.hpp"
+#include "ui_edit_marker_dialog.h"
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace scwx::qt::ui
+{
+
+static const std::string logPrefix_ = "scwx::qt::ui::edit_marker_dialog";
+static const auto logger_ = scwx::util::Logger::Create(logPrefix_);
+
+class EditMarkerDialog::Impl
+{
+public:
+ explicit Impl(EditMarkerDialog* self) : self_ {self} {}
+
+ void show_color_dialog();
+ void show_icon_file_dialog();
+
+ void set_icon_color(const std::string& color);
+
+ void connect_signals();
+
+ void handle_accepted();
+ void handle_rejected();
+
+ EditMarkerDialog* self_;
+ QPushButton* deleteButton_ {nullptr};
+ QIcon get_colored_icon(const types::MarkerIconInfo& marker,
+ const std::string& color);
+
+ std::shared_ptr markerManager_ =
+ manager::MarkerManager::Instance();
+ types::MarkerId editId_ {0};
+ bool adding_ {false};
+ std::string setIconOnAdded_ {""};
+};
+
+QIcon EditMarkerDialog::Impl::get_colored_icon(
+ const types::MarkerIconInfo& marker, const std::string& color)
+{
+ return util::modulateColors(marker.qIcon,
+ self_->ui->iconComboBox->iconSize(),
+ QColor(QString::fromStdString(color)));
+}
+
+EditMarkerDialog::EditMarkerDialog(QWidget* parent) :
+ QDialog(parent),
+ p {std::make_unique(this)},
+ ui(new Ui::EditMarkerDialog)
+{
+ ui->setupUi(this);
+
+ for (auto& markerIcon : p->markerManager_->get_icons())
+ {
+ ui->iconComboBox->addItem(
+ markerIcon.second.qIcon,
+ QString::fromStdString(markerIcon.second.shortName),
+ QString::fromStdString(markerIcon.second.name));
+ }
+ p->deleteButton_ =
+ ui->buttonBox->addButton("Delete", QDialogButtonBox::DestructiveRole);
+ p->connect_signals();
+}
+
+EditMarkerDialog::~EditMarkerDialog()
+{
+ delete ui;
+}
+
+void EditMarkerDialog::setup()
+{
+ setup(0, 0);
+}
+
+void EditMarkerDialog::setup(double latitude, double longitude)
+{
+ // By default use foreground color as marker color, mainly so the icons
+ // are vissable in the dropdown menu.
+ const QColor color = QWidget::palette().color(QWidget::foregroundRole());
+ p->editId_ = p->markerManager_->add_marker(types::MarkerInfo(
+ "",
+ latitude,
+ longitude,
+ manager::MarkerManager::getDefaultIconName(),
+ boost::gil::rgba8_pixel_t {static_cast(color.red()),
+ static_cast(color.green()),
+ static_cast(color.blue()),
+ static_cast(color.alpha())}));
+
+ setup(p->editId_);
+ p->adding_ = true;
+}
+
+void EditMarkerDialog::setup(types::MarkerId id)
+{
+ std::optional marker = p->markerManager_->get_marker(id);
+ if (!marker)
+ {
+ return;
+ }
+
+ p->editId_ = id;
+ p->adding_ = false;
+
+ const std::string iconColorStr =
+ util::color::ToArgbString(marker->iconColor);
+ p->set_icon_color(iconColorStr);
+
+ int iconIndex =
+ ui->iconComboBox->findData(QString::fromStdString(marker->iconName));
+ if (iconIndex < 0 || marker->iconName == "")
+ {
+ iconIndex = 0;
+ }
+
+ ui->nameLineEdit->setText(QString::fromStdString(marker->name));
+ ui->iconComboBox->setCurrentIndex(iconIndex);
+ ui->latitudeDoubleSpinBox->setValue(marker->latitude);
+ ui->longitudeDoubleSpinBox->setValue(marker->longitude);
+ ui->iconColorLineEdit->setText(QString::fromStdString(iconColorStr));
+}
+
+types::MarkerInfo EditMarkerDialog::get_marker_info() const
+{
+ const QString colorName = ui->iconColorLineEdit->text();
+ const boost::gil::rgba8_pixel_t color =
+ util::color::ToRgba8PixelT(colorName.toStdString());
+
+ return types::MarkerInfo(
+ ui->nameLineEdit->text().toStdString(),
+ ui->latitudeDoubleSpinBox->value(),
+ ui->longitudeDoubleSpinBox->value(),
+ ui->iconComboBox->currentData().toString().toStdString(),
+ color);
+}
+
+void EditMarkerDialog::Impl::show_color_dialog()
+{
+ // WA_DeleteOnClose manages memory
+ // NOLINTNEXTLINE(cppcoreguidelines-owning-memory)
+ auto* dialog = new QColorDialog(self_);
+
+ dialog->setAttribute(Qt::WA_DeleteOnClose);
+ dialog->setOption(QColorDialog::ColorDialogOption::ShowAlphaChannel);
+
+ const QColor initialColor(self_->ui->iconColorLineEdit->text());
+ if (initialColor.isValid())
+ {
+ dialog->setCurrentColor(initialColor);
+ }
+
+ QObject::connect(dialog,
+ &QColorDialog::colorSelected,
+ self_,
+ [this](const QColor& qColor)
+ {
+ const QString colorName =
+ qColor.name(QColor::NameFormat::HexArgb);
+ self_->ui->iconColorLineEdit->setText(colorName);
+ set_icon_color(colorName.toStdString());
+ });
+ dialog->open();
+}
+
+void EditMarkerDialog::Impl::show_icon_file_dialog()
+{
+ auto* dialog = new QFileDialog(self_);
+
+ dialog->setFileMode(QFileDialog::ExistingFile);
+ dialog->setNameFilters({"Icon (*.png *.svg)", "All Files (*)"});
+ dialog->setAttribute(Qt::WA_DeleteOnClose);
+
+ QObject::connect(dialog,
+ &QFileDialog::fileSelected,
+ self_,
+ [this](const QString& file)
+ {
+ const std::string path =
+ QDir::toNativeSeparators(file).toStdString();
+ setIconOnAdded_ = path;
+ markerManager_->add_icon(path);
+ });
+ dialog->open();
+}
+
+void EditMarkerDialog::Impl::connect_signals()
+{
+ connect(self_,
+ &EditMarkerDialog::accepted,
+ self_,
+ [this]() { handle_accepted(); });
+
+ connect(self_,
+ &EditMarkerDialog::rejected,
+ self_,
+ [this]() { handle_rejected(); });
+
+ connect(deleteButton_,
+ &QPushButton::clicked,
+ self_,
+ [this]()
+ {
+ markerManager_->remove_marker(editId_);
+ self_->done(0);
+ });
+
+ connect(self_->ui->iconColorLineEdit,
+ &QLineEdit::textEdited,
+ self_,
+ [this](const QString& text) { set_icon_color(text.toStdString()); });
+
+ connect(self_->ui->iconColorButton,
+ &QAbstractButton::clicked,
+ self_,
+ [this]() { show_color_dialog(); });
+
+ connect(self_->ui->iconFileOpenButton,
+ &QPushButton::clicked,
+ self_,
+ [this]() { show_icon_file_dialog(); });
+
+ connect(markerManager_.get(),
+ &manager::MarkerManager::IconAdded,
+ self_,
+ [this]()
+ {
+ const std::string color =
+ self_->ui->iconColorLineEdit->text().toStdString();
+ set_icon_color(color);
+
+ if (setIconOnAdded_ != "")
+ {
+ const int i = self_->ui->iconComboBox->findData(
+ QString::fromStdString(setIconOnAdded_));
+ if (i >= 0)
+ {
+ self_->ui->iconComboBox->setCurrentIndex(i);
+ setIconOnAdded_ = "";
+ }
+ }
+ });
+
+ connect(self_->ui->buttonBox->button(QDialogButtonBox::Apply),
+ &QAbstractButton::clicked,
+ self_,
+ [this]() { handle_accepted(); });
+}
+
+void EditMarkerDialog::Impl::set_icon_color(const std::string& color)
+{
+ self_->ui->iconColorFrame->setStyleSheet(
+ QString::fromStdString(fmt::format("background-color: {}", color)));
+
+ auto* iconComboBox = self_->ui->iconComboBox;
+
+ const QVariant currentIcon = iconComboBox->currentData();
+
+ self_->ui->iconComboBox->clear();
+ for (auto& markerIcon : markerManager_->get_icons())
+ {
+ const int i =
+ iconComboBox->findData(QString::fromStdString(markerIcon.second.name));
+ const QIcon icon = get_colored_icon(markerIcon.second, color);
+ if (i < 0)
+ {
+ iconComboBox->addItem(
+ icon,
+ QString::fromStdString(markerIcon.second.shortName),
+ QString::fromStdString(markerIcon.second.name));
+ }
+ else
+ {
+ self_->ui->iconComboBox->setItemIcon(i, icon);
+ }
+ }
+
+ const int i = iconComboBox->findData(currentIcon);
+ if (i < 0)
+ {
+ return;
+ }
+
+ iconComboBox->setCurrentIndex(i);
+}
+
+void EditMarkerDialog::Impl::handle_accepted()
+{
+ markerManager_->set_marker(editId_, self_->get_marker_info());
+}
+
+void EditMarkerDialog::Impl::handle_rejected()
+{
+ if (adding_)
+ {
+ markerManager_->remove_marker(editId_);
+ }
+}
+
+} // namespace scwx::qt::ui
diff --git a/scwx-qt/source/scwx/qt/ui/edit_marker_dialog.hpp b/scwx-qt/source/scwx/qt/ui/edit_marker_dialog.hpp
new file mode 100644
index 00000000..c20ebe27
--- /dev/null
+++ b/scwx-qt/source/scwx/qt/ui/edit_marker_dialog.hpp
@@ -0,0 +1,34 @@
+#pragma once
+#include
+
+#include
+
+namespace Ui
+{
+class EditMarkerDialog;
+}
+
+namespace scwx::qt::ui
+{
+class EditMarkerDialog : public QDialog
+{
+ Q_OBJECT
+ Q_DISABLE_COPY_MOVE(EditMarkerDialog)
+
+public:
+ explicit EditMarkerDialog(QWidget* parent = nullptr);
+ ~EditMarkerDialog() override;
+
+ void setup();
+ void setup(double latitude, double longitude);
+ void setup(types::MarkerId id);
+
+ [[nodiscard]] types::MarkerInfo get_marker_info() const;
+
+private:
+ class Impl;
+ std::unique_ptr p;
+ Ui::EditMarkerDialog* ui;
+};
+
+} // namespace scwx::qt::ui
diff --git a/scwx-qt/source/scwx/qt/ui/edit_marker_dialog.ui b/scwx-qt/source/scwx/qt/ui/edit_marker_dialog.ui
new file mode 100644
index 00000000..d3d47500
--- /dev/null
+++ b/scwx-qt/source/scwx/qt/ui/edit_marker_dialog.ui
@@ -0,0 +1,210 @@
+
+
+ EditMarkerDialog
+
+
+
+ 0
+ 0
+ 400
+ 249
+
+
+
+ Edit Location Marker
+
+
+ -
+
+
+ Qt::Orientation::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
-
+
+
+
+ 24
+ 24
+
+
+
+ QFrame::Shape::Box
+
+
+ QFrame::Shadow::Plain
+
+
+
+ -
+
+
+ #ffffffff
+
+
+
+ -
+
+
+ ...
+
+
+
+ :/res/icons/font-awesome-6/palette-solid.svg:/res/icons/font-awesome-6/palette-solid.svg
+
+
+
+
+
+ -
+
+
+ QAbstractSpinBox::CorrectionMode::CorrectToNearestValue
+
+
+ 5
+
+
+ -90.000000000000000
+
+
+ 90.000000000000000
+
+
+
+ -
+
+
+ Name
+
+
+
+ -
+
+
+ Icon
+
+
+
+ -
+
+
+ Qt::Orientation::Horizontal
+
+
+ QDialogButtonBox::StandardButton::Apply|QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok
+
+
+
+ -
+
+
+ Longitude
+
+
+
+ -
+
+
+ Icon Color
+
+
+
+ -
+
+
+ Latitude
+
+
+
+ -
+
+
+ Add Custom Icon
+
+
+ ...
+
+
+
+ -
+
+
+ QAbstractSpinBox::CorrectionMode::CorrectToNearestValue
+
+
+ 5
+
+
+ -180.000000000000000
+
+
+ 180.000000000000000
+
+
+
+ -
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+ buttonBox
+ accepted()
+ EditMarkerDialog
+ accept()
+
+
+ 248
+ 254
+
+
+ 157
+ 274
+
+
+
+
+ buttonBox
+ rejected()
+ EditMarkerDialog
+ reject()
+
+
+ 316
+ 260
+
+
+ 286
+ 274
+
+
+
+
+
diff --git a/scwx-qt/source/scwx/qt/ui/marker_settings_widget.cpp b/scwx-qt/source/scwx/qt/ui/marker_settings_widget.cpp
index 0c2bc614..b3ba8440 100644
--- a/scwx-qt/source/scwx/qt/ui/marker_settings_widget.cpp
+++ b/scwx-qt/source/scwx/qt/ui/marker_settings_widget.cpp
@@ -4,7 +4,7 @@
#include
#include
#include
-#include
+#include
#include
#include
@@ -23,17 +23,24 @@ class MarkerSettingsWidgetImpl
{
public:
explicit MarkerSettingsWidgetImpl(MarkerSettingsWidget* self) :
- self_ {self},
- markerModel_ {new model::MarkerModel(self_)}
+ self_ {self},
+ markerModel_ {new model::MarkerModel(self_)},
+ proxyModel_ {new QSortFilterProxyModel(self_)}
{
+ proxyModel_->setSourceModel(markerModel_);
+ proxyModel_->setSortRole(Qt::DisplayRole); // TODO types::SortRole
+ proxyModel_->setFilterCaseSensitivity(Qt::CaseInsensitive);
+ proxyModel_->setFilterKeyColumn(-1);
}
void ConnectSignals();
- MarkerSettingsWidget* self_;
- model::MarkerModel* markerModel_;
+ MarkerSettingsWidget* self_;
+ model::MarkerModel* markerModel_;
+ QSortFilterProxyModel* proxyModel_;
std::shared_ptr markerManager_ {
manager::MarkerManager::Instance()};
+ std::shared_ptr editMarkerDialog_ {nullptr};
};
@@ -45,8 +52,9 @@ MarkerSettingsWidget::MarkerSettingsWidget(QWidget* parent) :
ui->setupUi(this);
ui->removeButton->setEnabled(false);
+ ui->markerView->setModel(p->proxyModel_);
- ui->markerView->setModel(p->markerModel_);
+ p->editMarkerDialog_ = std::make_shared(this);
p->ConnectSignals();
}
@@ -63,7 +71,8 @@ void MarkerSettingsWidgetImpl::ConnectSignals()
self_,
[this]()
{
- markerManager_->add_marker(types::MarkerInfo("", 0, 0));
+ editMarkerDialog_->setup();
+ editMarkerDialog_->show();
});
QObject::connect(
self_->ui->removeButton,
@@ -99,9 +108,30 @@ void MarkerSettingsWidgetImpl::ConnectSignals()
return;
}
- bool itemSelected = selected.size() > 0;
+ const bool itemSelected = selected.size() > 0;
self_->ui->removeButton->setEnabled(itemSelected);
});
+ QObject::connect(self_->ui->markerView,
+ &QAbstractItemView::doubleClicked,
+ self_,
+ [this](const QModelIndex& index)
+ {
+ const int row = index.row();
+ if (row < 0)
+ {
+ return;
+ }
+
+ std::optional id =
+ markerModel_->getId(row);
+ if (!id)
+ {
+ return;
+ }
+
+ editMarkerDialog_->setup(*id);
+ editMarkerDialog_->show();
+ });
}
} // namespace ui
diff --git a/scwx-qt/source/scwx/qt/util/q_color_modulate.cpp b/scwx-qt/source/scwx/qt/util/q_color_modulate.cpp
new file mode 100644
index 00000000..c205ce88
--- /dev/null
+++ b/scwx-qt/source/scwx/qt/util/q_color_modulate.cpp
@@ -0,0 +1,64 @@
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+namespace scwx::qt::util
+{
+
+void modulateColors_(QImage& image, const QColor& color)
+{
+ for (int y = 0; y < image.height(); ++y)
+ {
+ QRgb* line = reinterpret_cast(image.scanLine(y));
+ for (int x = 0; x < image.width(); ++x)
+ {
+ // This is pulled from Qt Documentation
+ // https://doc.qt.io/qt-6/qimage.html#scanLine
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ QRgb& rgb = line[x];
+ /* clang-format off
+ * NOLINTBEGIN(cppcoreguidelines-narrowing-conversions, bugprone-narrowing-conversions)
+ * qRed/qGreen/qBlue/qAlpha return values 0-255, handlable by float
+ * redF/greenF/blueF/alphaF are all 0-1, so output is 0-255
+ * Rounding is fine for this.
+ * clang-format on
+ */
+ const int red = qRed(rgb) * color.redF();
+ const int green = qGreen(rgb) * color.greenF();
+ const int blue = qBlue(rgb) * color.blueF();
+ const int alpha = qAlpha(rgb) * color.alphaF();
+ /* clang-format off
+ * NOLINTEND(cppcoreguidelines-narrowing-conversions, bugprone-narrowing-conversions)
+ * clang-format on
+ */
+
+ rgb = qRgba(red, green, blue, alpha);
+ }
+ }
+}
+
+QImage modulateColors(const QImage& image, const QColor& color)
+{
+ QImage copy = image.copy();
+ modulateColors_(copy, color);
+ return copy;
+}
+
+QPixmap modulateColors(const QPixmap& pixmap, const QColor& color)
+{
+ QImage image = pixmap.toImage();
+ modulateColors_(image, color);
+ return QPixmap::fromImage(image);
+}
+
+QIcon modulateColors(const QIcon& icon, const QSize& size, const QColor& color)
+{
+ const QPixmap pixmap = modulateColors(icon.pixmap(size), color);
+ return QIcon(pixmap);
+}
+
+} // namespace scwx::qt::util
diff --git a/scwx-qt/source/scwx/qt/util/q_color_modulate.hpp b/scwx-qt/source/scwx/qt/util/q_color_modulate.hpp
new file mode 100644
index 00000000..35326293
--- /dev/null
+++ b/scwx-qt/source/scwx/qt/util/q_color_modulate.hpp
@@ -0,0 +1,16 @@
+#pragma once
+
+#include
+#include
+#include
+#include
+#include
+
+namespace scwx::qt::util
+{
+
+QImage modulateColors(const QImage& image, const QColor& color);
+QPixmap modulateColors(const QPixmap& pixmap, const QColor& color);
+QIcon modulateColors(const QIcon& icon, const QSize& size, const QColor& color);
+
+} // namespace scwx::qt::util
diff --git a/test/data b/test/data
index 4b4d9c54..0d085b1d 160000
--- a/test/data
+++ b/test/data
@@ -1 +1 @@
-Subproject commit 4b4d9c54b8218aa2297dbd457e3747091570f0d2
+Subproject commit 0d085b1df59045e14ca996982b4907b1a0da4fdb
diff --git a/test/source/scwx/qt/model/marker_model.test.cpp b/test/source/scwx/qt/model/marker_model.test.cpp
index 700ffc6e..74ad28a9 100644
--- a/test/source/scwx/qt/model/marker_model.test.cpp
+++ b/test/source/scwx/qt/model/marker_model.test.cpp
@@ -1,6 +1,7 @@
#include
#include
#include
+#include
#include
#include
@@ -9,7 +10,6 @@
#include
#include
-
namespace scwx
{
namespace qt
@@ -25,11 +25,17 @@ static const std::string ONE_MARKERS_FILE =
std::string(SCWX_TEST_DATA_DIR) + "/json/markers/markers-one.json";
static const std::string FIVE_MARKERS_FILE =
std::string(SCWX_TEST_DATA_DIR) + "/json/markers/markers-five.json";
+static const std::string PART1_MARKER_FILE =
+ std::string(SCWX_TEST_DATA_DIR) + "/json/markers/markers-part1.json";
static std::mutex initializedMutex {};
static std::condition_variable initializedCond {};
static bool initialized;
+static const boost::gil::rgba8_pixel_t defaultIconColor =
+ util::color::ToRgba8PixelT("#ffff0000");
+static const std::string defaultIconName = "images/location-marker";
+
void CompareFiles(const std::string& file1, const std::string& file2)
{
std::ifstream ifs1 {file1};
@@ -49,8 +55,8 @@ void CopyFile(const std::string& from, const std::string& to)
CompareFiles(from, to);
}
-typedef void TestFunction(std::shared_ptr manager,
- MarkerModel& model);
+using TestFunction = void(std::shared_ptr,
+ MarkerModel&);
void RunTest(const std::string& filename, TestFunction testFunction)
{
@@ -65,7 +71,7 @@ void RunTest(const std::string& filename, TestFunction testFunction)
initialized = false;
QObject::connect(manager.get(),
&manager::MarkerManager::MarkersInitialized,
- [](size_t count)
+ []()
{
std::unique_lock lock(initializedMutex);
initialized = true;
@@ -119,7 +125,10 @@ TEST(MarkerModelTest, AddRemove)
RunTest(ONE_MARKERS_FILE,
[](std::shared_ptr manager, MarkerModel&)
- { manager->add_marker(types::MarkerInfo("Null", 0, 0)); });
+ {
+ manager->add_marker(types::MarkerInfo(
+ "Null", 0, 0, defaultIconName, defaultIconColor));
+ });
RunTest(
EMPTY_MARKERS_FILE,
[](std::shared_ptr manager, MarkerModel& model)
@@ -143,11 +152,16 @@ TEST(MarkerModelTest, AddFive)
RunTest(FIVE_MARKERS_FILE,
[](std::shared_ptr manager, MarkerModel&)
{
- manager->add_marker(types::MarkerInfo("Null", 0, 0));
- manager->add_marker(types::MarkerInfo("North", 90, 0));
- manager->add_marker(types::MarkerInfo("South", -90, 0));
- manager->add_marker(types::MarkerInfo("East", 0, 90));
- manager->add_marker(types::MarkerInfo("West", 0, -90));
+ manager->add_marker(types::MarkerInfo(
+ "Null", 0, 0, defaultIconName, defaultIconColor));
+ manager->add_marker(types::MarkerInfo(
+ "North", 90, 0, defaultIconName, defaultIconColor));
+ manager->add_marker(types::MarkerInfo(
+ "South", -90, 0, defaultIconName, defaultIconColor));
+ manager->add_marker(types::MarkerInfo(
+ "East", 0, 90, defaultIconName, defaultIconColor));
+ manager->add_marker(types::MarkerInfo(
+ "West", 0, -90, defaultIconName, defaultIconColor));
});
std::filesystem::remove(TEMP_MARKERS_FILE);
@@ -161,10 +175,14 @@ TEST(MarkerModelTest, AddFour)
RunTest(FIVE_MARKERS_FILE,
[](std::shared_ptr manager, MarkerModel&)
{
- manager->add_marker(types::MarkerInfo("North", 90, 0));
- manager->add_marker(types::MarkerInfo("South", -90, 0));
- manager->add_marker(types::MarkerInfo("East", 0, 90));
- manager->add_marker(types::MarkerInfo("West", 0, -90));
+ manager->add_marker(types::MarkerInfo(
+ "North", 90, 0, defaultIconName, defaultIconColor));
+ manager->add_marker(types::MarkerInfo(
+ "South", -90, 0, defaultIconName, defaultIconColor));
+ manager->add_marker(types::MarkerInfo(
+ "East", 0, 90, defaultIconName, defaultIconColor));
+ manager->add_marker(types::MarkerInfo(
+ "West", 0, -90, defaultIconName, defaultIconColor));
});
std::filesystem::remove(TEMP_MARKERS_FILE);
@@ -235,6 +253,17 @@ TEST(MarkerModelTest, RemoveFour)
EXPECT_EQ(std::filesystem::exists(TEMP_MARKERS_FILE), false);
}
+TEST(MarkerModelTest, UpdateFromPart1)
+{
+ CopyFile(PART1_MARKER_FILE, TEMP_MARKERS_FILE);
+
+ RunTest(ONE_MARKERS_FILE,
+ [](std::shared_ptr, MarkerModel&) {});
+
+ std::filesystem::remove(TEMP_MARKERS_FILE);
+ EXPECT_EQ(std::filesystem::exists(TEMP_MARKERS_FILE), false);
+}
+
} // namespace model
} // namespace qt
} // namespace scwx