#ifndef MWGUI_MAPWINDOW_H #define MWGUI_MAPWINDOW_H #include #include #include #include #include "windowpinnablebase.hpp" #include #include namespace MWRender { class GlobalMap; class LocalMap; } namespace ESM { class ESMReader; class ESMWriter; } namespace MWWorld { class Cell; class CellStore; } namespace Loading { class Listener; } namespace SceneUtil { class WorkQueue; } namespace MWGui { class CustomMarkerCollection { public: void addMarker(const ESM::CustomMarker& marker, bool triggerEvent = true); void deleteMarker(const ESM::CustomMarker& marker); void updateMarker(const ESM::CustomMarker& marker, const std::string& newNote); void clear(); size_t size() const; typedef std::multimap ContainerType; typedef std::pair RangeType; ContainerType::const_iterator begin() const; ContainerType::const_iterator end() const; RangeType getMarkers(const ESM::RefId& cellId) const; typedef MyGUI::delegates::MultiDelegate<> EventHandle_Void; EventHandle_Void eventMarkersChanged; private: ContainerType mMarkers; }; class LocalMapBase { public: LocalMapBase(CustomMarkerCollection& markers, MWRender::LocalMap* localMapRender, bool fogOfWarEnabled); virtual ~LocalMapBase(); void init(MyGUI::ScrollView* widget, MyGUI::ImageBox* compass, int cellDistance = Constants::CellGridRadius); void setActiveCell(const MWWorld::Cell& cell); void requestMapRender(const MWWorld::CellStore* cell); void setPlayerDir(const float x, const float y); void setPlayerPos(int cellX, int cellY, const float nx, const float ny); void onFrame(float dt); bool toggleFogOfWar(); struct MarkerUserData { MarkerUserData(MWRender::LocalMap* map) : mLocalMapRender(map) , cellX(0) , cellY(0) , nX(0.f) , nY(0.f) { } bool isPositionExplored() const; MWRender::LocalMap* mLocalMapRender; int cellX; int cellY; float nX; float nY; std::vector notes; std::string caption; }; protected: void updateLocalMap(); float mLocalMapZoom = 1.f; MWRender::LocalMap* mLocalMapRender; const MWWorld::Cell* mActiveCell; bool mHasALastActiveCell = false; osg::Vec2f mCurPos; // the position of the player in the world (in cell coords) MyGUI::ScrollView* mLocalMap; MyGUI::ImageBox* mCompass; bool mFogOfWarToggled; bool mFogOfWarEnabled; int mNumCells; // for convenience, mCellDistance * 2 + 1 int mCellDistance; // Stores markers that were placed by a player. May be shared between multiple map views. CustomMarkerCollection& mCustomMarkers; struct MapEntry { MapEntry(MyGUI::ImageBox* mapWidget, MyGUI::ImageBox* fogWidget) : mMapWidget(mapWidget) , mFogWidget(fogWidget) , mCellX(0) , mCellY(0) { } MyGUI::ImageBox* mMapWidget; MyGUI::ImageBox* mFogWidget; std::unique_ptr mMapTexture; std::unique_ptr mFogTexture; int mCellX; int mCellY; }; std::vector mMaps; // Keep track of created marker widgets, just to easily remove them later. std::vector mExteriorDoorMarkerWidgets; std::map, std::vector> mExteriorDoorsByCell; std::vector mInteriorDoorMarkerWidgets; std::vector mMagicMarkerWidgets; std::vector mCustomMarkerWidgets; std::vector mDoorMarkersToRecycle; std::vector& currentDoorMarkersWidgets(); virtual void updateCustomMarkers(); void applyFogOfWar(); MyGUI::IntPoint getPosition(int cellX, int cellY, float nx, float ny) const; MyGUI::IntPoint getMarkerPosition(float worldX, float worldY, MarkerUserData& markerPos) const; MyGUI::IntCoord getMarkerCoordinates( float worldX, float worldY, MarkerUserData& markerPos, size_t markerSize) const; MyGUI::Widget* createDoorMarker(const std::string& name, float x, float y) const; MyGUI::IntCoord getMarkerCoordinates(MyGUI::Widget* widget, size_t markerSize) const; virtual void notifyPlayerUpdate() {} virtual void centerView(); virtual void notifyMapChanged() {} virtual void customMarkerCreated(MyGUI::Widget* marker) {} virtual void doorMarkerCreated(MyGUI::Widget* marker) {} void updateRequiredMaps(); void updateMagicMarkers(); void addDetectionMarkers(int type); void redraw(); float getWidgetSize() const; float mMarkerUpdateTimer; float mLastDirectionX; float mLastDirectionY; bool mNeedDoorMarkersUpdate; private: void updateDoorMarkers(); }; class EditNoteDialog : public MWGui::WindowModal { public: EditNoteDialog(); void onOpen() override; void showDeleteButton(bool show); bool getDeleteButtonShown(); void setText(const std::string& text); std::string getText(); typedef MyGUI::delegates::MultiDelegate<> EventHandle_Void; EventHandle_Void eventDeleteClicked; EventHandle_Void eventOkClicked; private: void onCancelButtonClicked(MyGUI::Widget* sender); void onOkButtonClicked(MyGUI::Widget* sender); void onDeleteButtonClicked(MyGUI::Widget* sender); MyGUI::TextBox* mTextEdit; MyGUI::Button* mOkButton; MyGUI::Button* mCancelButton; MyGUI::Button* mDeleteButton; }; class MapWindow : public MWGui::WindowPinnableBase, public LocalMapBase, public NoDrop { public: MapWindow(CustomMarkerCollection& customMarkers, DragAndDrop* drag, MWRender::LocalMap* localMapRender, SceneUtil::WorkQueue* workQueue); virtual ~MapWindow(); void setCellName(const std::string& cellName); void setAlpha(float alpha) override; void setVisible(bool visible) override; void renderGlobalMap(); /// adds the marker to the global map /// @param name The ESM::Cell::mName void addVisitedLocation(const std::string& name, int x, int y); // reveals this cell's map on the global map void cellExplored(int x, int y); void setGlobalMapPlayerPosition(float worldX, float worldY); void setGlobalMapPlayerDir(const float x, const float y); void ensureGlobalMapLoaded(); void onOpen() override; void onFrame(float dt) override; void updateCustomMarkers() override; /// Clear all savegame-specific data void clear() override; void write(ESM::ESMWriter& writer, Loading::Listener& progress); void readRecord(ESM::ESMReader& reader, uint32_t type); void asyncPrepareSaveMap(); std::string_view getWindowIdForLua() const override { return "Map"; } private: void onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); void onMouseDrag(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); void onWorldButtonClicked(MyGUI::Widget* _sender); void onMapDoubleClicked(MyGUI::Widget* sender); void onMapZoomed(MyGUI::Widget* sender, int rel); void zoomOnCursor(float speedDiff); void updateGlobalMap(); void onCustomMarkerDoubleClicked(MyGUI::Widget* sender); void onNoteEditOk(); void onNoteEditDelete(); void onNoteEditDeleteConfirm(); void onNoteDoubleClicked(MyGUI::Widget* sender); void onChangeScrollWindowCoord(MyGUI::Widget* sender); void globalMapUpdatePlayer(); void setGlobalMapMarkerTooltip(MyGUI::Widget* widget, int x, int y); float getMarkerSize(size_t agregatedWeight) const; void resizeGlobalMap(); void worldPosToGlobalMapImageSpace(float x, float z, float& imageX, float& imageY) const; MyGUI::IntCoord createMarkerCoords(float x, float y, float agregatedWeight) const; MyGUI::Widget* createMarker(const std::string& name, float x, float y, float agregatedWeight); MyGUI::ScrollView* mGlobalMap; std::unique_ptr mGlobalMapTexture; std::unique_ptr mGlobalMapOverlayTexture; MyGUI::ImageBox* mGlobalMapImage; MyGUI::ImageBox* mGlobalMapOverlay; MyGUI::ImageBox* mPlayerArrowLocal; MyGUI::ImageBox* mPlayerArrowGlobal; MyGUI::Button* mButton; MyGUI::IntPoint mLastDragPos; MyGUI::IntCoord mLastScrollWindowCoordinates; // Markers on global map typedef std::pair CellId; std::set mMarkers; MyGUI::Button* mEventBoxGlobal; MyGUI::Button* mEventBoxLocal; float mGlobalMapZoom = 1.0f; std::unique_ptr mGlobalMapRender; struct MapMarkerType { osg::Vec2f position; MyGUI::Widget* widget = nullptr; bool operator<(const MapMarkerType& right) const { return widget < right.widget; } }; std::map mGlobalMapMarkersByName; std::map> mGlobalMapMarkers; EditNoteDialog mEditNoteDialog; ESM::CustomMarker mEditingMarker; void onPinToggled() override; void onTitleDoubleClicked() override; void doorMarkerCreated(MyGUI::Widget* marker) override; void customMarkerCreated(MyGUI::Widget* marker) override; void notifyPlayerUpdate() override; void centerView() override; }; } #endif