From b40cacdd3a6a21c6e8eae934e4114f8ea831f1df Mon Sep 17 00:00:00 2001 From: Marukyu Date: Sat, 18 Jun 2016 00:24:16 +0200 Subject: [PATCH] Added hover tooltips for tile tool, object tool and editor panel --- src/Client/Editor/Editor.cpp | 5 + src/Client/Editor/Editor.hpp | 2 + src/Client/Editor/SelectionPanel.cpp | 102 ++++++++++++------ src/Client/Editor/SelectionPanel.hpp | 20 ++-- src/Client/Editor/Tool.cpp | 5 + src/Client/Editor/Tool.hpp | 8 +- src/Client/Editor/Tools/ObjectTool.cpp | 5 + src/Client/Editor/Tools/ObjectTool.hpp | 5 + .../Editor/Tools/Panels/ObjectToolPanel.cpp | 14 +++ .../Editor/Tools/Panels/ObjectToolPanel.hpp | 10 +- .../Editor/Tools/Panels/TileToolPanel.cpp | 23 ++++ .../Editor/Tools/Panels/TileToolPanel.hpp | 9 +- src/Client/Editor/Tools/TileTool.cpp | 5 + src/Client/Editor/Tools/TileTool.hpp | 5 + src/Client/System/NEWindow.cpp | 30 ++++++ src/Client/System/NEWindow.hpp | 4 + src/Shared/Utils/Utilities.cpp | 27 +++++ src/Shared/Utils/Utilities.hpp | 1 + 18 files changed, 240 insertions(+), 40 deletions(-) diff --git a/src/Client/Editor/Editor.cpp b/src/Client/Editor/Editor.cpp index da55579..8cf6669 100644 --- a/src/Client/Editor/Editor.cpp +++ b/src/Client/Editor/Editor.cpp @@ -68,6 +68,11 @@ Tool * Editor::getTool() const return tool; } +sf::Vector2i Editor::getMousePositionTile() const +{ + return lastMousePosition; +} + void Editor::resetCamera() { float tileSize = TileAppearanceManager::TILE_SIZE; diff --git a/src/Client/Editor/Editor.hpp b/src/Client/Editor/Editor.hpp index 132eebf..bb72182 100644 --- a/src/Client/Editor/Editor.hpp +++ b/src/Client/Editor/Editor.hpp @@ -49,6 +49,8 @@ class Editor : public gui2::Widget void setTool(Tool * tool); Tool * getTool() const; + sf::Vector2i getMousePositionTile() const; + void resetCamera(); bool isVertexRenderable() const override; diff --git a/src/Client/Editor/SelectionPanel.cpp b/src/Client/Editor/SelectionPanel.cpp index 938bc37..fa531f9 100644 --- a/src/Client/Editor/SelectionPanel.cpp +++ b/src/Client/Editor/SelectionPanel.cpp @@ -27,18 +27,20 @@ gui2::Ptr SelectionPanel::make() } SelectionPanel::SelectionPanel() : - mapper([](ID id) - { - static ItemEntry invalidEntry; - return invalidEntry; - }), - texture(nullptr), - wasSelectionChanged(false), - selectionExists(false), - selection(0), - itemCount(0), - itemSize(24.f, 24.f), - scrollVelocity(0) + mapper([](ID id) + { + static ItemEntry invalidEntry; + return invalidEntry; + }), + texture(nullptr), + wasSelectionChanged(false), + selectionExists(false), + selection(0), + hoveredItemExists(false), + hoveredItem(0), + itemCount(0), + itemSize(24.f, 24.f), + scrollVelocity(0) { } @@ -71,6 +73,16 @@ bool SelectionPanel::hasSelection() const return selectionExists; } +SelectionPanel::ID SelectionPanel::getHoveredItem() const +{ + return hoveredItem; +} + +bool SelectionPanel::hasHoveredItem() const +{ + return hoveredItemExists; +} + void SelectionPanel::setMapper(Mapper mapper, std::size_t itemCount) { this->mapper = mapper; @@ -130,6 +142,16 @@ void SelectionPanel::update() } } +bool SelectionPanel::wasChanged() +{ + if (wasSelectionChanged) + { + wasSelectionChanged = false; + return true; + } + return false; +} + bool SelectionPanel::isVertexRenderable() const { return false; @@ -143,7 +165,7 @@ void SelectionPanel::onProcess(const gui2::WidgetEvents& events) { scrollVelocity -= events.mouseWheelDelta * 5; } - + if (std::abs(scrollVelocity) > 0.0001f) { float newSliderValue = slider->getValue() + scrollVelocity; @@ -161,14 +183,26 @@ void SelectionPanel::onProcess(const gui2::WidgetEvents& events) scrollVelocity *= 0.75f; } } + + if (isMouseOver()) + { + std::pair itemAtMousePos = getItemAtPosition(events.mousePosition); + + hoveredItemExists = itemAtMousePos.first; + hoveredItem = itemAtMousePos.second; + } + else + { + hoveredItemExists = false; + } } void SelectionPanel::onDraw(sf::RenderTarget& target, sf::RenderStates states) const { states.transform *= getTransform(); - + sf::Transform origTransform = states.transform; - + states.transform.translate(0, -slider->getValue()); states.texture = this->texture; @@ -222,17 +256,12 @@ void SelectionPanel::onMouseDown(sf::Vector2f pos, Input button) { if (button == sf::Mouse::Left) { - for (ID i = 0; i < getItemCount(); ++i) + auto itemAtPos = getItemAtPosition(pos); + + if (itemAtPos.first && (!hasSelection() || getSelection() != itemAtPos.second)) { - if (getShiftedItemRect(i).contains(pos)) - { - if (!hasSelection() || getSelection() != i) - { - setSelection(i); - wasSelectionChanged = true; - } - break; - } + setSelection(itemAtPos.second); + wasSelectionChanged = true; } } } @@ -253,12 +282,25 @@ sf::FloatRect SelectionPanel::getShiftedItemRect(ID item) const return moveRect(getItemRect(item), sf::Vector2f(0, -slider->getValue())); } -bool SelectionPanel::wasChanged() +sf::FloatRect SelectionPanel::getClickableItemRect(ID item) const { - if (wasSelectionChanged) + return expandRect(getShiftedItemRect(item), sf::Vector2f(MARGIN / 2, MARGIN / 2)); +} + +std::pair SelectionPanel::getItemAtPosition(sf::Vector2f pos) const +{ + // Optimization. + if (hasHoveredItem() && getClickableItemRect(getHoveredItem()).contains(pos)) { - wasSelectionChanged = false; - return true; + return std::make_pair(true, getHoveredItem()); } - return false; + + for (ID i = 0; i < getItemCount(); ++i) + { + if (getClickableItemRect(i).contains(pos)) + { + return std::make_pair(true, i); + } + } + return std::make_pair(false, 0); } diff --git a/src/Client/Editor/SelectionPanel.hpp b/src/Client/Editor/SelectionPanel.hpp index c8187c8..795a135 100644 --- a/src/Client/Editor/SelectionPanel.hpp +++ b/src/Client/Editor/SelectionPanel.hpp @@ -11,6 +11,7 @@ #include #include #include +#include #include namespace sf @@ -51,6 +52,9 @@ class SelectionPanel : public gui2::Widget ID getSelection() const; bool hasSelection() const; + ID getHoveredItem() const; + bool hasHoveredItem() const; + void setMapper(Mapper mapper, std::size_t itemCount); const Mapper & getMapper() const; std::size_t getItemCount() const; @@ -62,15 +66,15 @@ class SelectionPanel : public gui2::Widget const sf::Texture * getTexture() const; void update(); - + bool wasChanged(); SelectionPanel(); bool isVertexRenderable() const override; - + protected: - + virtual void init() override; private: @@ -78,7 +82,7 @@ class SelectionPanel : public gui2::Widget void onProcess(const gui2::WidgetEvents & events) override; void onDraw(sf::RenderTarget & target, sf::RenderStates states) const; void onResize() override; - + void onMouseDown(sf::Vector2f pos, Input button) override; std::size_t getRowCount() const; @@ -86,6 +90,8 @@ class SelectionPanel : public gui2::Widget sf::FloatRect getItemRect(ID item) const; sf::FloatRect getShiftedItemRect(ID item) const; + sf::FloatRect getClickableItemRect(ID item) const; + std::pair getItemAtPosition(sf::Vector2f pos) const; Mapper mapper; @@ -93,12 +99,14 @@ class SelectionPanel : public gui2::Widget bool wasSelectionChanged; bool selectionExists; - std::size_t selection; + ID selection; + bool hoveredItemExists; + ID hoveredItem; std::size_t itemCount; sf::Vector2f itemSize; std::vector vertices; - + gui2::Ptr slider; float scrollVelocity; }; diff --git a/src/Client/Editor/Tool.cpp b/src/Client/Editor/Tool.cpp index fe56f75..cd6be70 100644 --- a/src/Client/Editor/Tool.cpp +++ b/src/Client/Editor/Tool.cpp @@ -46,6 +46,11 @@ void Tool::onDrawPreview(sf::RenderTarget& target, sf::RenderStates states, sf:: { } +std::string Tool::getTooltip() const +{ + return ""; +} + gui2::Ptr Tool::getSettingsPanel() const { return nullptr; diff --git a/src/Client/Editor/Tool.hpp b/src/Client/Editor/Tool.hpp index a1aefae..511f07b 100644 --- a/src/Client/Editor/Tool.hpp +++ b/src/Client/Editor/Tool.hpp @@ -6,6 +6,7 @@ #include #include #include +#include class Level; class ObjectAppearanceManager; @@ -89,6 +90,11 @@ class Tool : public NamedFactory */ virtual void onDrawPreview(sf::RenderTarget & target, sf::RenderStates states, sf::Vector2i cursorPosition); + /** + * Called every frame to determine the current tooltip/status string to be displayed in the editor. + */ + virtual std::string getTooltip() const; + /** * Returns the settings panel associated with this tool. This has to be a consistent and unique instance; the return * value must not change between calls. @@ -104,7 +110,7 @@ class Tool : public NamedFactory * Returns the editor information given to this tool. */ const EditorData & getEditorData() const; - + /** * Initializes the Named Factory of tools, if it is not initialized yet. */ diff --git a/src/Client/Editor/Tools/ObjectTool.cpp b/src/Client/Editor/Tools/ObjectTool.cpp index ef378b8..201f3bc 100644 --- a/src/Client/Editor/Tools/ObjectTool.cpp +++ b/src/Client/Editor/Tools/ObjectTool.cpp @@ -73,6 +73,11 @@ gui2::Ptr ObjectTool::getSettingsPanel() const return settingsPanel; } +std::string ObjectTool::getTooltip() const +{ + return settingsPanel->getTooltip(); +} + const Brush& ObjectTool::getPrimaryBrush() const { primaryBrush.setObject(settingsPanel->getSelectedObject()); diff --git a/src/Client/Editor/Tools/ObjectTool.hpp b/src/Client/Editor/Tools/ObjectTool.hpp index 0dd6134..796b728 100644 --- a/src/Client/Editor/Tools/ObjectTool.hpp +++ b/src/Client/Editor/Tools/ObjectTool.hpp @@ -18,6 +18,11 @@ class ObjectTool : public BrushTool virtual gui2::Ptr getSettingsPanel() const override; + /** + * Returns the tooltip for this object tool. + */ + virtual std::string getTooltip() const override; + protected: virtual const Brush & getPrimaryBrush() const override; diff --git a/src/Client/Editor/Tools/Panels/ObjectToolPanel.cpp b/src/Client/Editor/Tools/Panels/ObjectToolPanel.cpp index b63a63b..d84a272 100644 --- a/src/Client/Editor/Tools/Panels/ObjectToolPanel.cpp +++ b/src/Client/Editor/Tools/Panels/ObjectToolPanel.cpp @@ -51,6 +51,11 @@ Brush::ObjectMode ObjectToolPanel::getSecondaryMode() const return static_cast(secondaryModeMenu->getSelection()); } +std::string ObjectToolPanel::getTooltip() const +{ + return hoveredObject.getType() != Object::Type::None ? objectAppearance->getObjectName(hoveredObject) : ""; +} + void ObjectToolPanel::init() { gui2::Container::init(); @@ -116,6 +121,15 @@ void ObjectToolPanel::onProcessContainer(gui2::WidgetEvents& events) propertyPanel->update(); } } + + if (selectionPanel->hasHoveredItem()) + { + hoveredObject = Object(objects[selectionPanel->getHoveredItem()]); + } + else + { + hoveredObject.setType(Object::Type::None); + } } void ObjectToolPanel::addDefaultPropertiesToObject() diff --git a/src/Client/Editor/Tools/Panels/ObjectToolPanel.hpp b/src/Client/Editor/Tools/Panels/ObjectToolPanel.hpp index cb10011..4f74661 100644 --- a/src/Client/Editor/Tools/Panels/ObjectToolPanel.hpp +++ b/src/Client/Editor/Tools/Panels/ObjectToolPanel.hpp @@ -18,7 +18,7 @@ class ObjectToolPanel : public gui2::Container public: static gui2::Ptr make(std::vector objects, - const ObjectAppearanceManager & objectAppearance); + const ObjectAppearanceManager & objectAppearance); ObjectToolPanel(std::vector objects, const ObjectAppearanceManager & objectAppearance); virtual ~ObjectToolPanel(); @@ -38,8 +38,13 @@ class ObjectToolPanel : public gui2::Container */ Brush::ObjectMode getSecondaryMode() const; + /** + * Returns the name of the currently hovered tile. + */ + std::string getTooltip() const; + protected: - + virtual void init() override; private: @@ -52,6 +57,7 @@ class ObjectToolPanel : public gui2::Container std::vector objects; Object selectedObject; + Object hoveredObject; gui2::Ptr primaryModeMenu; gui2::Ptr secondaryModeMenu; diff --git a/src/Client/Editor/Tools/Panels/TileToolPanel.cpp b/src/Client/Editor/Tools/Panels/TileToolPanel.cpp index b0f8441..b958215 100644 --- a/src/Client/Editor/Tools/Panels/TileToolPanel.cpp +++ b/src/Client/Editor/Tools/Panels/TileToolPanel.cpp @@ -43,6 +43,11 @@ const Tile& TileToolPanel::getSelectedTile() const return selectedTile; } +std::string TileToolPanel::getTooltip() const +{ + return hoveredTile.exists() ? tileAppearance->getTileName(hoveredTile) : ""; +} + void TileToolPanel::init() { gui2::BorderPanel::init(); @@ -140,6 +145,22 @@ void TileToolPanel::updateSelectedTile() } } +void TileToolPanel::updateHoveredTile() +{ + if (floorPanel->hasHoveredItem()) + { + hoveredTile = floors[floorPanel->getHoveredItem()]; + } + else if (wallPanel->hasHoveredItem()) + { + hoveredTile = walls[wallPanel->getHoveredItem()]; + } + else + { + hoveredTile = Tile(); + } +} + void TileToolPanel::onProcessContainer(gui2::WidgetEvents& events) { if (floorPanel->wasChanged()) @@ -183,4 +204,6 @@ void TileToolPanel::onProcessContainer(gui2::WidgetEvents& events) baseTile.setCracked(tileCrackCheckbox->isChecked()); updateSelectors(); } + + updateHoveredTile(); } diff --git a/src/Client/Editor/Tools/Panels/TileToolPanel.hpp b/src/Client/Editor/Tools/Panels/TileToolPanel.hpp index 2758a14..830eccf 100644 --- a/src/Client/Editor/Tools/Panels/TileToolPanel.hpp +++ b/src/Client/Editor/Tools/Panels/TileToolPanel.hpp @@ -27,8 +27,13 @@ class TileToolPanel : public gui2::BorderPanel */ const Tile & getSelectedTile() const; + /** + * Returns the name of the currently hovered tile. + */ + std::string getTooltip() const; + protected: - + virtual void init() override; private: @@ -37,6 +42,7 @@ class TileToolPanel : public gui2::BorderPanel void updateTileProperties(std::vector & tileList, const Tile & sourceTile); void updateSelectors(); void updateSelectedTile(); + void updateHoveredTile(); void onProcessContainer(gui2::WidgetEvents & events) override; @@ -45,6 +51,7 @@ class TileToolPanel : public gui2::BorderPanel std::vector floors; std::vector walls; Tile selectedTile; + Tile hoveredTile; Tile baseTile; gui2::Ptr floorPanel; diff --git a/src/Client/Editor/Tools/TileTool.cpp b/src/Client/Editor/Tools/TileTool.cpp index 41db2cd..5cff0e7 100644 --- a/src/Client/Editor/Tools/TileTool.cpp +++ b/src/Client/Editor/Tools/TileTool.cpp @@ -44,6 +44,11 @@ gui2::Ptr TileTool::getSettingsPanel() const return settingsPanel; } +std::string TileTool::getTooltip() const +{ + return settingsPanel->getTooltip(); +} + const Brush& TileTool::getPrimaryBrush() const { primaryBrush.setTile(settingsPanel->getSelectedTile()); diff --git a/src/Client/Editor/Tools/TileTool.hpp b/src/Client/Editor/Tools/TileTool.hpp index 4d40de0..8ccc18c 100644 --- a/src/Client/Editor/Tools/TileTool.hpp +++ b/src/Client/Editor/Tools/TileTool.hpp @@ -16,6 +16,11 @@ class TileTool : public BrushTool virtual gui2::Ptr getSettingsPanel() const override; + /** + * Returns the tooltip for this tile tool. + */ + virtual std::string getTooltip() const override; + protected: virtual const Brush & getPrimaryBrush() const override; diff --git a/src/Client/System/NEWindow.cpp b/src/Client/System/NEWindow.cpp index 2b98fe3..dd303d0 100644 --- a/src/Client/System/NEWindow.cpp +++ b/src/Client/System/NEWindow.cpp @@ -176,6 +176,11 @@ void NEWindow::initPanels() levelPanel = LevelPanel::make(); levelPanel->setMessageBoxTarget(this); mainPanel->add(levelPanel, gui2::BorderPanel::Right, 150); + + tooltip = gui2::Text::make(); + tooltip->setZPosition(10); + tooltip->setEnabled(false); + add(tooltip); } void NEWindow::initLevelPanel() @@ -328,6 +333,29 @@ void NEWindow::updateTilePanels() } } +void NEWindow::updateTooltip() +{ + float tooltipMargin = 10.f; + tooltip->setTextAlignment(gui2::Text::AlignBottomLeft); + tooltip->setPosition(mainPanel->getSideSize(gui2::BorderPanel::Left) + tooltipMargin, + getSize().y / getViewMultiplier() - tooltipMargin); + + std::vector tooltips; + + if (getTool()) + { + tooltips.push_back(getTool()->getTooltip()); + } + + if (editor->isMouseOver()) + { + tooltips.push_back("x: " + cNtoS(editor->getMousePositionTile().x)); + tooltips.push_back("y: " + cNtoS(editor->getMousePositionTile().y)); + } + + tooltip->setText(joinStrings(tooltips, "\n", true)); +} + void NEWindow::onProcessWindow(const gui2::WidgetEvents& events) { for (std::size_t i = 0; i < toolButtons.size(); ++i) @@ -440,6 +468,8 @@ void NEWindow::onProcessWindow(const gui2::WidgetEvents& events) { saveDungeon(); } + + updateTooltip(); } NEApplication* NEWindow::getParentApplication() const diff --git a/src/Client/System/NEWindow.hpp b/src/Client/System/NEWindow.hpp index 362b2ad..9a84790 100644 --- a/src/Client/System/NEWindow.hpp +++ b/src/Client/System/NEWindow.hpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -66,6 +67,7 @@ class NEWindow : public gui2::Window std::map generateEnumMap(const std::string & section) const; void updateTilePanels(); + void updateTooltip(); void onProcessWindow(const gui2::WidgetEvents & events) override; @@ -103,6 +105,8 @@ class NEWindow : public gui2::Window gui2::Ptr editor; + gui2::Ptr tooltip; + std::vector floors, walls; std::unique_ptr texturePacker; diff --git a/src/Shared/Utils/Utilities.cpp b/src/Shared/Utils/Utilities.cpp index 9a31b29..9c8a0c1 100644 --- a/src/Shared/Utils/Utilities.cpp +++ b/src/Shared/Utils/Utilities.cpp @@ -145,6 +145,33 @@ std::vector splitString(const std::string & str, const std::string return std::move(results); } +std::string joinStrings(const std::vector& strs, const std::string& separator, bool ignoreEmpty) +{ + std::string result; + bool skipSeparator = true; + + for (const auto & str : strs) + { + if (ignoreEmpty && str.empty()) + { + continue; + } + + if (skipSeparator) + { + skipSeparator = false; + } + else + { + result += separator; + } + + result += str; + } + + return result; +} + std::vector extractSection(const std::vector& vector, const std::string& sectionName) { std::vector section; diff --git a/src/Shared/Utils/Utilities.hpp b/src/Shared/Utils/Utilities.hpp index 1c06501..b393cbc 100644 --- a/src/Shared/Utils/Utilities.hpp +++ b/src/Shared/Utils/Utilities.hpp @@ -17,6 +17,7 @@ bool equalsIgnoreCase(const std::string & a, const std::string & b); //void splitString(const std::string & str, const std::string & separator, std::vector & results, bool ignoreEmpty = false); std::vector splitString(const std::string & str, const std::string & separator, bool ignoreEmpty = false); +std::string joinStrings(const std::vector & strs, const std::string & separator, bool ignoreEmpty = false); /** * Extracts a specific section from an ini-like vector.