diff --git a/src/core/location.cpp b/src/core/location.cpp index 5542b34f..b85e1918 100644 --- a/src/core/location.cpp +++ b/src/core/location.cpp @@ -458,6 +458,7 @@ json LocationSection::save() const {"cleared", _itemCleared} }; } + bool LocationSection::load(json& j) { if (j.type() == json::value_t::object) { @@ -471,6 +472,13 @@ bool LocationSection::load(json& j) return false; } +bool LocationSection::operator<(const LocationSection& rhs) const +{ + if (this->getParentID() == rhs.getParentID()) + return this->getName() < rhs.getName(); + return this->getParentID() < rhs.getParentID(); +} + #ifndef NDEBUG #include diff --git a/src/core/location.h b/src/core/location.h index b1dabd35..0f0ba7f5 100644 --- a/src/core/location.h +++ b/src/core/location.h @@ -61,6 +61,8 @@ class LocationSection final : public LuaInterface { virtual nlohmann::json save() const; virtual bool load(nlohmann::json& j); + bool operator<(const LocationSection& rhs) const; + protected: // lua interface static constexpr const char Lua_Name[] = "LocationSection"; static const LuaInterface::MethodMap Lua_Methods; diff --git a/src/core/tracker.cpp b/src/core/tracker.cpp index 307d4176..e1ce24f9 100644 --- a/src/core/tracker.cpp +++ b/src/core/tracker.cpp @@ -282,6 +282,7 @@ bool Tracker::AddLocations(const std::string& file) { _reachableCache.clear(); _providerCountCache.clear(); + _sectionRefs.clear(); for (auto& loc : Location::FromJSON(j, _locations)) { // find duplicate, warn and merge #ifdef MERGE_DUPLICATE_LOCATIONS // this should be default in the future @@ -329,10 +330,12 @@ bool Tracker::AddLocations(const std::string& file) { #endif _locations.push_back(std::move(loc)); // TODO: move constructor for (auto& sec : _locations.back().getSections()) { + if (!sec.getRef().empty()) + _sectionNameRefs[sec.getRef()].push_back(_locations.back().getID() + "/" + sec.getName()); sec.onChange += {this,[this,&sec](void*){ onLocationSectionChanged.emit(this, sec); }}; } } - + onLayoutChanged.emit(this, ""); // TODO: differentiate between structure and content return false; } @@ -570,7 +573,7 @@ Location& Tracker::getLocation(const std::string& id, bool partialMatch) return blankLocation; } -LocationSection& Tracker::getLocationSection(const std::string& id) +std::pair Tracker::getLocationAndSection(const std::string& id) { const char *start = id.c_str(); const char *t = strrchr(start, '/'); @@ -581,11 +584,47 @@ LocationSection& Tracker::getLocationSection(const std::string& id) auto& loc = getLocation(locid, true); for (auto& sec: loc.getSections()) { if (sec.getName() != secname) continue; - return sec; + return {loc, sec}; } + } + return {blankLocation, blankLocationSection}; +} +LocationSection& Tracker::getLocationSection(const std::string& id) +{ + return getLocationAndSection(id).second; +} + +const std::vector, std::reference_wrapper>>& +Tracker::getReferencingSections(const LocationSection& sec) +{ + static std::vector, std::reference_wrapper>> + blank = {}; + + if (_sectionRefs.empty() && !_sectionNameRefs.empty()) + rebuildSectionRefs(); + + auto it = _sectionRefs.find(sec); + if (it != _sectionRefs.end()) { + return it->second; + } + return blank; +} + +void Tracker::rebuildSectionRefs() +{ + _sectionRefs.clear(); + for (const auto& pair: _sectionNameRefs) { + const auto& target = getLocationSection(pair.first); + if (target.getName().empty()) + continue; + for (const auto& sourceName: pair.second) { + const auto& source = getLocationAndSection(sourceName); + if (source.second.getRef().empty()) + continue; + _sectionRefs[target].push_back(source); + } } - return blankLocationSection; } const Pack* Tracker::getPack() const diff --git a/src/core/tracker.h b/src/core/tracker.h index f3ecde3c..7b825342 100644 --- a/src/core/tracker.h +++ b/src/core/tracker.h @@ -12,6 +12,7 @@ #include "signal.h" #include #include +#include #include // nullptr_t #include @@ -81,7 +82,10 @@ class Tracker final : public LuaInterface { std::list getMapNames() const; std::list< std::pair > getMapLocations(const std::string& mapname) const; Location& getLocation(const std::string& name, bool partialMatch=false); + std::pair getLocationAndSection(const std::string& id); LocationSection& getLocationSection(const std::string& id); + const std::vector, std::reference_wrapper>>& + getReferencingSections(const LocationSection& sec); nlohmann::json saveState() const; bool loadState(nlohmann::json& state); @@ -114,6 +118,12 @@ class Tracker final : public LuaInterface { std::list _bulkItemUpdates; bool _bulkUpdate = false; + std::map> _sectionNameRefs; + std::map, + std::vector, + std::reference_wrapper>>, + std::less> _sectionRefs; + std::list* _parents = nullptr; static int _execLimit; @@ -124,6 +134,7 @@ class Tracker final : public LuaInterface { bool isVisible(const Location& location, std::list& parents); AccessibilityLevel isReachable(const std::list< std::list >& rules, bool visibilityRules, std::list& parents); + void rebuildSectionRefs(); protected: // Lua interface implementation static constexpr const char Lua_Name[] = "Tracker"; diff --git a/src/ui/trackerview.cpp b/src/ui/trackerview.cpp index fa43b87f..8b4b5a73 100644 --- a/src/ui/trackerview.cpp +++ b/src/ui/trackerview.cpp @@ -234,6 +234,9 @@ TrackerView::TrackerView(int x, int y, int w, int h, Tracker* tracker, const std }}; _tracker->onLocationSectionChanged += {this, [this](void *s, const LocationSection& sec) { updateLocation(sec.getParentID()); + for (const auto& pair: _tracker->getReferencingSections(sec)) + updateLocation(pair.first.get().getID()); + updateMapTooltip(); // TODO: move this into updateLocation and detect if the location is hovered }}; updateLayout(layoutRoot); updateState(""); @@ -360,12 +363,12 @@ void TrackerView::updateLayout(const std::string& layout) void TrackerView::updateLocations() { - updateLocation(""); + updateLocation("", true); + updateMapTooltip(); // TODO: move this into updateLocation and detect if the location is hovered } -void TrackerView::updateLocation(const std::string& location) +void TrackerView::updateLocation(const std::string& location, bool all) { - bool all = location.empty(); for (auto& mappair: _maps) { for (auto& w: mappair.second) { for (const auto& pair : _tracker->getMapLocations(mappair.first)) { @@ -381,7 +384,10 @@ void TrackerView::updateLocation(const std::string& location) } } } +} +void TrackerView::updateMapTooltip() +{ if (_mapTooltip && _mapTooltipOwner) { _mapTooltip->update(_tracker, [this](Item* w, const BaseItem& item) { updateItem(w, item); }); // update size if visibility of an item changed diff --git a/src/ui/trackerview.h b/src/ui/trackerview.h index c47253c0..908d9fb3 100644 --- a/src/ui/trackerview.h +++ b/src/ui/trackerview.h @@ -75,7 +75,8 @@ class TrackerView : public SimpleContainer { void updateDisplay(const std::string& check); void updateState(const std::string& check); void updateLocations(); - void updateLocation(const std::string& location); + void updateLocation(const std::string& location, bool all=false); + void updateMapTooltip(); void updateItem(Item* w, const BaseItem& item); size_t addLayoutNodes(Container* container, const std::list& nodes, size_t depth=0);