mirror of
https://github.com/ciphervance/supercell-wx.git
synced 2025-10-30 19:50:05 +00:00
Merge pull request #321 from AdenKoperczak/location_markers_part2
Location Markers Part 2
This commit is contained in:
commit
60b4833eb2
37 changed files with 1234 additions and 218 deletions
|
|
@ -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<double> threshold_ {};
|
||||
std::chrono::sys_time<std::chrono::seconds> 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<double> radians = angle;
|
||||
|
||||
|
|
@ -903,7 +903,7 @@ bool GeoIcons::RunMousePicking(
|
|||
const QPointF& mouseGlobalPos,
|
||||
const glm::vec2& mouseCoords,
|
||||
const common::Coordinate& /* mouseGeoCoords */,
|
||||
std::shared_ptr<types::EventHandler>& /* eventHandler */)
|
||||
std::shared_ptr<types::EventHandler>& 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<GeoIconDrawItem>& di,
|
||||
const std::function<void(QEvent*)>& eventHandler)
|
||||
{
|
||||
di->event_ = eventHandler;
|
||||
}
|
||||
|
||||
} // namespace draw
|
||||
} // namespace gl
|
||||
} // namespace qt
|
||||
|
|
|
|||
|
|
@ -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<GeoIconDrawItem>& di,
|
||||
const std::function<void(QEvent*)>& eventHandler);
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,17 @@
|
|||
#include <scwx/qt/manager/marker_manager.hpp>
|
||||
#include <scwx/qt/types/marker_types.hpp>
|
||||
#include <scwx/qt/util/color.hpp>
|
||||
#include <scwx/qt/util/json.hpp>
|
||||
#include <scwx/qt/util/texture_atlas.hpp>
|
||||
#include <scwx/qt/main/application.hpp>
|
||||
#include <scwx/qt/manager/resource_manager.hpp>
|
||||
#include <scwx/util/logger.hpp>
|
||||
|
||||
#include <filesystem>
|
||||
#include <shared_mutex>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <QStandardPaths>
|
||||
#include <boost/json.hpp>
|
||||
|
|
@ -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<std::shared_ptr<MarkerRecord>> markerRecords_ {};
|
||||
std::string markerSettingsPath_ {""};
|
||||
std::vector<std::shared_ptr<MarkerRecord>> markerRecords_ {};
|
||||
std::unordered_map<types::MarkerId, size_t> idToIndex_ {};
|
||||
|
||||
std::unordered_map<std::string, types::MarkerIconInfo> 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<MarkerRecord>,
|
||||
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<std::string>(jv.at(kIconName_));
|
||||
}
|
||||
|
||||
if (jo.contains(kIconColorName_) && jo.at(kIconName_).is_string())
|
||||
{
|
||||
try
|
||||
{
|
||||
iconColor = util::color::ToRgba8PixelT(
|
||||
boost::json::value_to<std::string>(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<std::string>(jv.at(kNameName_)),
|
||||
boost::json::value_to<double>(jv.at(kLatitudeName_)),
|
||||
boost::json::value_to<double>(jv.at(kLongitudeName_)));
|
||||
boost::json::value_to<double>(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<MarkerRecord>(markerEntry);
|
||||
auto record = boost::json::value_to<MarkerRecord>(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<MarkerRecord>(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<MarkerRecord>(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<Impl>(this))
|
||||
{
|
||||
static const std::vector<types::MarkerIconInfo> 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<Impl>(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<types::MarkerInfo> 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<types::MarkerInfo> MarkerManager::get_marker(types::MarkerId id)
|
|||
|
||||
std::optional<size_t> 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<size_t> 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<MarkerManager::Impl::MarkerRecord>& markerRecord =
|
||||
const std::shared_ptr<MarkerManager::Impl::MarkerRecord>& 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<Impl::MarkerRecord>(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<MarkerForEachFunc> 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<boost::gil::rgba8_image_t> 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<types::MarkerIconInfo>
|
||||
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<std::string, types::MarkerIconInfo>
|
||||
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> MarkerManager::Instance()
|
|||
static std::weak_ptr<MarkerManager> markerManagerReference_ {};
|
||||
static std::mutex instanceMutex_ {};
|
||||
|
||||
std::unique_lock lock(instanceMutex_);
|
||||
const std::unique_lock lock(instanceMutex_);
|
||||
|
||||
std::shared_ptr<MarkerManager> markerManager =
|
||||
markerManagerReference_.lock();
|
||||
|
|
@ -391,6 +512,11 @@ std::shared_ptr<MarkerManager> MarkerManager::Instance()
|
|||
return markerManager;
|
||||
}
|
||||
|
||||
const std::string& MarkerManager::getDefaultIconName()
|
||||
{
|
||||
return defaultIconName;
|
||||
}
|
||||
|
||||
} // namespace manager
|
||||
} // namespace qt
|
||||
} // namespace scwx
|
||||
|
|
|
|||
|
|
@ -23,11 +23,15 @@ public:
|
|||
|
||||
size_t marker_count();
|
||||
std::optional<types::MarkerInfo> get_marker(types::MarkerId id);
|
||||
std::optional<size_t> get_index(types::MarkerId id);
|
||||
std::optional<size_t> 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<types::MarkerIconInfo> get_icon(const std::string& name);
|
||||
const std::unordered_map<std::string, types::MarkerIconInfo> get_icons();
|
||||
|
||||
void for_each(std::function<MarkerForEachFunc> func);
|
||||
|
||||
|
|
@ -35,6 +39,7 @@ public:
|
|||
void set_marker_settings_path(const std::string& path);
|
||||
|
||||
static std::shared_ptr<MarkerManager> 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<Impl> p;
|
||||
|
|
|
|||
|
|
@ -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<std::string>& 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
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ std::shared_ptr<boost::gil::rgba8_image_t>
|
|||
LoadImageResource(const std::string& urlString);
|
||||
std::vector<std::shared_ptr<boost::gil::rgba8_image_t>>
|
||||
LoadImageResources(const std::vector<std::string>& urlStrings);
|
||||
void BuildAtlas();
|
||||
|
||||
} // namespace ResourceManager
|
||||
} // namespace manager
|
||||
|
|
|
|||
|
|
@ -9,10 +9,10 @@
|
|||
#include <scwx/qt/map/layer_wrapper.hpp>
|
||||
#include <scwx/qt/map/map_provider.hpp>
|
||||
#include <scwx/qt/map/map_settings.hpp>
|
||||
#include <scwx/qt/map/marker_layer.hpp>
|
||||
#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>
|
||||
|
|
@ -21,6 +21,7 @@
|
|||
#include <scwx/qt/settings/general_settings.hpp>
|
||||
#include <scwx/qt/settings/map_settings.hpp>
|
||||
#include <scwx/qt/settings/palette_settings.hpp>
|
||||
#include <scwx/qt/ui/edit_marker_dialog.hpp>
|
||||
#include <scwx/qt/util/file.hpp>
|
||||
#include <scwx/qt/util/maplibre.hpp>
|
||||
#include <scwx/qt/util/tooltip.hpp>
|
||||
|
|
@ -127,8 +128,6 @@ public:
|
|||
ImGui_ImplQt_Init();
|
||||
|
||||
InitializeCustomStyles();
|
||||
|
||||
ConnectSignals();
|
||||
}
|
||||
|
||||
~MapWidgetImpl()
|
||||
|
|
@ -219,6 +218,8 @@ public:
|
|||
std::shared_ptr<model::LayerModel> layerModel_ {
|
||||
model::LayerModel::Instance()};
|
||||
|
||||
ui::EditMarkerDialog* editMarkerDialog_ {nullptr};
|
||||
|
||||
std::shared_ptr<manager::HotkeyManager> hotkeyManager_ {
|
||||
manager::HotkeyManager::Instance()};
|
||||
std::shared_ptr<manager::PlacefileManager> 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_)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,9 +1,14 @@
|
|||
#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>
|
||||
#include <scwx/qt/types/marker_types.hpp>
|
||||
#include <scwx/qt/ui/edit_marker_dialog.hpp>
|
||||
|
||||
#include <QGeoPositionInfo>
|
||||
#include <QMouseEvent>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace scwx
|
||||
{
|
||||
|
|
@ -19,48 +24,104 @@ class MarkerLayer::Impl
|
|||
{
|
||||
public:
|
||||
explicit Impl(MarkerLayer* self, std::shared_ptr<MapContext> context) :
|
||||
self_ {self}, geoIcons_ {std::make_shared<gl::draw::GeoIcons>(context)}
|
||||
self_ {self},
|
||||
geoIcons_ {std::make_shared<gl::draw::GeoIcons>(context)},
|
||||
editMarkerDialog_ {std::make_shared<ui::EditMarkerDialog>()}
|
||||
{
|
||||
ConnectSignals();
|
||||
}
|
||||
~Impl() {}
|
||||
~Impl() = default;
|
||||
|
||||
void ReloadMarkers();
|
||||
void ConnectSignals();
|
||||
|
||||
std::shared_ptr<manager::MarkerManager> markerManager_ {
|
||||
manager::MarkerManager::Instance()};
|
||||
|
||||
void set_icon_sheets();
|
||||
|
||||
MarkerLayer* self_;
|
||||
const std::string& markerIconName_ {
|
||||
types::GetTextureName(types::ImageTexture::LocationMarker)};
|
||||
|
||||
std::shared_ptr<gl::draw::GeoIcons> geoIcons_;
|
||||
std::shared_ptr<ui::EditMarkerDialog> 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<gl::draw::GeoIconDrawItem> 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<gl::draw::GeoIconDrawItem> 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<QMouseEvent*>(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);
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include <scwx/qt/manager/marker_manager.hpp>
|
||||
#include <scwx/qt/types/marker_types.hpp>
|
||||
#include <scwx/qt/types/qt_types.hpp>
|
||||
#include <scwx/qt/util/q_color_modulate.hpp>
|
||||
#include <scwx/util/logger.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
|
@ -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<int>(MarkerModel::Column::Latitude);
|
||||
|
|
@ -38,7 +40,6 @@ public:
|
|||
MarkerModel::MarkerModel(QObject* parent) :
|
||||
QAbstractTableModel(parent), p(std::make_unique<Impl>())
|
||||
{
|
||||
|
||||
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<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 ||
|
||||
static_cast<size_t>(index.row()) >= p->markerIds_.size())
|
||||
{
|
||||
|
|
@ -118,8 +104,7 @@ QVariant MarkerModel::data(const QModelIndex& index, int role) const
|
|||
{
|
||||
case static_cast<int>(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<int>(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<int>(Column::Icon):
|
||||
if (role == Qt::ItemDataRole::DisplayRole)
|
||||
{
|
||||
std::optional<types::MarkerIconInfo> icon =
|
||||
p->markerManager_->get_icon(markerInfo->iconName);
|
||||
if (icon)
|
||||
{
|
||||
return QString::fromStdString(icon->shortName);
|
||||
}
|
||||
else
|
||||
{
|
||||
return {};
|
||||
}
|
||||
}
|
||||
else if (role == Qt::ItemDataRole::DecorationRole)
|
||||
{
|
||||
std::optional<types::MarkerIconInfo> 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<int>(Column::Longitude):
|
||||
return tr("Longitude");
|
||||
|
||||
case static_cast<int>(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<size_t>(index.row()) >= p->markerIds_.size())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
types::MarkerId id = p->markerIds_[index.row()];
|
||||
std::optional<types::MarkerInfo> markerInfo =
|
||||
p->markerManager_->get_marker(id);
|
||||
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(id, *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(id, *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(id, *markerInfo);
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
Q_EMIT dataChanged(index, index);
|
||||
}
|
||||
|
||||
return result;
|
||||
return false;
|
||||
}
|
||||
|
||||
void MarkerModel::HandleMarkersInitialized(size_t count)
|
||||
|
|
|
|||
|
|
@ -17,7 +17,8 @@ public:
|
|||
{
|
||||
Latitude = 0,
|
||||
Longitude = 1,
|
||||
Name = 2,
|
||||
Icon = 2,
|
||||
Name = 3,
|
||||
};
|
||||
|
||||
explicit MarkerModel(QObject* parent = nullptr);
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ namespace settings
|
|||
static const std::string logPrefix_ = "scwx::qt::settings::hotkey_settings";
|
||||
|
||||
static const std::unordered_map<types::Hotkey, QKeySequence> 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,
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ namespace types
|
|||
{
|
||||
|
||||
static const std::unordered_map<Hotkey, std::string> 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<Hotkey, std::string> hotkeyShortName_ {
|
|||
{Hotkey::Unknown, "?"}};
|
||||
|
||||
static const std::unordered_map<Hotkey, std::string> hotkeyLongName_ {
|
||||
{Hotkey::AddLocationMarker, "Add Location Marker"},
|
||||
{Hotkey::ChangeMapStyle, "Change Map Style"},
|
||||
{Hotkey::CopyCursorCoordinates, "Copy Cursor Coordinates"},
|
||||
{Hotkey::CopyMapCoordinates, "Copy Map Coordinates"},
|
||||
|
|
|
|||
|
|
@ -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<Hotkey, Hotkey::ChangeMapStyle, Hotkey::TimelineStepEnd>
|
||||
Iterator<Hotkey, Hotkey::AddLocationMarker, Hotkey::TimelineStepEnd>
|
||||
HotkeyIterator;
|
||||
|
||||
Hotkey GetHotkeyFromShortName(const std::string& name);
|
||||
|
|
|
|||
|
|
@ -1,29 +1,82 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include <scwx/qt/types/texture_types.hpp>
|
||||
|
||||
namespace scwx
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include <boost/gil.hpp>
|
||||
#include <QFileInfo>
|
||||
#include <QIcon>
|
||||
|
||||
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<boost::gil::rgba8_image_t> 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<std::shared_ptr<boost::gil::rgba8_image_t>> image;
|
||||
};
|
||||
|
||||
} // namespace scwx::qt::types
|
||||
|
|
|
|||
|
|
@ -25,8 +25,33 @@ 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::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,
|
||||
|
|
|
|||
|
|
@ -18,7 +18,16 @@ enum class ImageTexture
|
|||
Crosshairs24,
|
||||
Cursor17,
|
||||
Dot3,
|
||||
LocationBriefcase,
|
||||
LocationBuildingColumns,
|
||||
LocationBuilding,
|
||||
LocationCaravan,
|
||||
LocationCrosshair,
|
||||
LocationHouse,
|
||||
LocationMarker,
|
||||
LocationPin,
|
||||
LocationStar,
|
||||
LocationTent,
|
||||
MapboxLogo,
|
||||
MapTilerLogo
|
||||
};
|
||||
|
|
|
|||
314
scwx-qt/source/scwx/qt/ui/edit_marker_dialog.cpp
Normal file
314
scwx-qt/source/scwx/qt/ui/edit_marker_dialog.cpp
Normal file
|
|
@ -0,0 +1,314 @@
|
|||
#include "edit_marker_dialog.hpp"
|
||||
#include "ui_edit_marker_dialog.h"
|
||||
|
||||
#include <scwx/qt/manager/marker_manager.hpp>
|
||||
#include <scwx/qt/types/marker_types.hpp>
|
||||
#include <scwx/qt/util/color.hpp>
|
||||
#include <scwx/qt/util/q_color_modulate.hpp>
|
||||
#include <scwx/util/logger.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QIcon>
|
||||
#include <QPixmap>
|
||||
#include <QColorDialog>
|
||||
#include <QPushButton>
|
||||
#include <QFileDialog>
|
||||
|
||||
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<manager::MarkerManager> 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<Impl>(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<uint8_t>(color.red()),
|
||||
static_cast<uint8_t>(color.green()),
|
||||
static_cast<uint8_t>(color.blue()),
|
||||
static_cast<uint8_t>(color.alpha())}));
|
||||
|
||||
setup(p->editId_);
|
||||
p->adding_ = true;
|
||||
}
|
||||
|
||||
void EditMarkerDialog::setup(types::MarkerId id)
|
||||
{
|
||||
std::optional<types::MarkerInfo> 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
|
||||
34
scwx-qt/source/scwx/qt/ui/edit_marker_dialog.hpp
Normal file
34
scwx-qt/source/scwx/qt/ui/edit_marker_dialog.hpp
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
#pragma once
|
||||
#include <scwx/qt/types/marker_types.hpp>
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
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<Impl> p;
|
||||
Ui::EditMarkerDialog* ui;
|
||||
};
|
||||
|
||||
} // namespace scwx::qt::ui
|
||||
210
scwx-qt/source/scwx/qt/ui/edit_marker_dialog.ui
Normal file
210
scwx-qt/source/scwx/qt/ui/edit_marker_dialog.ui
Normal file
|
|
@ -0,0 +1,210 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>EditMarkerDialog</class>
|
||||
<widget class="QDialog" name="EditMarkerDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>249</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Edit Location Marker</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="9" column="0">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="4" column="2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QFrame" name="iconColorFrame">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Shape::Box</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Shadow::Plain</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="iconColorLineEdit">
|
||||
<property name="text">
|
||||
<string>#ffffffff</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="iconColorButton">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../../scwx-qt.qrc">
|
||||
<normaloff>:/res/icons/font-awesome-6/palette-solid.svg</normaloff>:/res/icons/font-awesome-6/palette-solid.svg</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QDoubleSpinBox" name="latitudeDoubleSpinBox">
|
||||
<property name="correctionMode">
|
||||
<enum>QAbstractSpinBox::CorrectionMode::CorrectToNearestValue</enum>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>-90.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>90.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Name</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Icon</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="0" colspan="3">
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::StandardButton::Apply|QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Longitude</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Icon Color</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Latitude</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="3">
|
||||
<widget class="QToolButton" name="iconFileOpenButton">
|
||||
<property name="toolTip">
|
||||
<string>Add Custom Icon</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QDoubleSpinBox" name="longitudeDoubleSpinBox">
|
||||
<property name="correctionMode">
|
||||
<enum>QAbstractSpinBox::CorrectionMode::CorrectToNearestValue</enum>
|
||||
</property>
|
||||
<property name="decimals">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>-180.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>180.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="2">
|
||||
<widget class="QLineEdit" name="nameLineEdit"/>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QComboBox" name="iconComboBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="autoFillBackground">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="../../../../scwx-qt.qrc"/>
|
||||
</resources>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>EditMarkerDialog</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>EditMarkerDialog</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>
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
#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/qt/ui/edit_marker_dialog.hpp>
|
||||
#include <scwx/util/logger.hpp>
|
||||
|
||||
#include <QSortFilterProxyModel>
|
||||
|
|
@ -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<manager::MarkerManager> markerManager_ {
|
||||
manager::MarkerManager::Instance()};
|
||||
std::shared_ptr<ui::EditMarkerDialog> 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<ui::EditMarkerDialog>(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<types::MarkerId> id =
|
||||
markerModel_->getId(row);
|
||||
if (!id)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
editMarkerDialog_->setup(*id);
|
||||
editMarkerDialog_->show();
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace ui
|
||||
|
|
|
|||
64
scwx-qt/source/scwx/qt/util/q_color_modulate.cpp
Normal file
64
scwx-qt/source/scwx/qt/util/q_color_modulate.cpp
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
#include <scwx/qt/util/q_color_modulate.hpp>
|
||||
|
||||
#include <QColor>
|
||||
#include <QImage>
|
||||
#include <QIcon>
|
||||
#include <QPixmap>
|
||||
#include <QSize>
|
||||
|
||||
namespace scwx::qt::util
|
||||
{
|
||||
|
||||
void modulateColors_(QImage& image, const QColor& color)
|
||||
{
|
||||
for (int y = 0; y < image.height(); ++y)
|
||||
{
|
||||
QRgb* line = reinterpret_cast<QRgb*>(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
|
||||
16
scwx-qt/source/scwx/qt/util/q_color_modulate.hpp
Normal file
16
scwx-qt/source/scwx/qt/util/q_color_modulate.hpp
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#pragma once
|
||||
|
||||
#include <QColor>
|
||||
#include <QImage>
|
||||
#include <QIcon>
|
||||
#include <QPixmap>
|
||||
#include <QSize>
|
||||
|
||||
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
|
||||
Loading…
Add table
Add a link
Reference in a new issue