diff --git a/include/TGUI/Renderers/PictureRenderer.hpp b/include/TGUI/Renderers/PictureRenderer.hpp new file mode 100644 index 00000000..c69ace2f --- /dev/null +++ b/include/TGUI/Renderers/PictureRenderer.hpp @@ -0,0 +1,86 @@ +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// TGUI - Texus' Graphical User Interface +// Copyright (C) 2012-2017 Bruno Van de Velde (vdv_b@tgui.eu) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +#ifndef TGUI_PICTURE_RENDERER_HPP +#define TGUI_PICTURE_RENDERER_HPP + + +#include + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +namespace tgui +{ + class TGUI_API PictureRenderer : public WidgetRenderer + { + public: + + using WidgetRenderer::WidgetRenderer; + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @brief Change the image that is displayed + /// + /// @param texture The new texture + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void setTexture(const Texture& texture); + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @brief Returns the image that is displayed + /// + /// @return texture of the image + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + Texture& getTexture() const; + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @brief Sets whether mouse events should be ignored on transparent parts of the texture + /// + /// @brief ignoreTransparentParts Should mouse events on transparent texture parts be ignored? + /// + /// When mouse events are ignored, they are passed to the other widget behind the widget. + /// By default, mouse events are NOT ignored and the widget will receive mouse events even on transparent texture parts. + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void setIgnoreTransparentParts(bool ignoreTransparentParts); + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// @brief Returns whether mouse events should be ignored on transparent parts of the texture + /// + /// @brief Whether mouse events on transparent texture parts are ignored + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + bool getIgnoreTransparentParts() const; + + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + }; + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#endif // TGUI_PICTURE_RENDERER_HPP diff --git a/include/TGUI/Widgets/Picture.hpp b/include/TGUI/Widgets/Picture.hpp index a10c063f..7ea15ae8 100644 --- a/include/TGUI/Widgets/Picture.hpp +++ b/include/TGUI/Widgets/Picture.hpp @@ -28,6 +28,7 @@ #include +#include ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -106,42 +107,15 @@ namespace tgui ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// @brief Changes the image + /// @brief Returns the renderer, which gives access to functions that determine how the widget is displayed /// - /// @param texture The texture to load the picture from - /// @param fullyClickable This affects what happens when clicking on a transparent pixel in the image. - /// Is the click caught by the picture, or does the event pass to the widgets behind it? - /// - /// @code - /// picture1->setTexture("image.png"); - /// - /// picture2->setTexture({"image.png", {20, 15, 60, 40}}); // Only load the part of the image from (20,15) to (80,55) - /// - /// sf::Texture texture; - /// texture.loadFromFile("image.png", {20, 15, 60, 40}); - /// picture3->setTexture(texture); - /// @endcode + /// @return Temporary pointer to the renderer /// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void setTexture(const Texture& texture, bool fullyClickable = true); - - - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// @brief Returns the texture used by the picture - /// - /// @return Internal texture - /// - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - const Texture& getTexture() const; - - - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// @brief Returns the texture used by the picture - /// - /// @return Reference to the internal texture - /// - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - Texture& getTexture(); + PictureRenderer* getRenderer() const + { + return aurora::downcast(m_renderer.get()); + } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -234,8 +208,8 @@ namespace tgui Sprite m_sprite; - // Set to false when clicks on transparent parts of the picture should go to the widgets behind the picture - bool m_fullyClickable = true; + // Set to true when clicks on transparent parts of the picture should go to the widgets behind the picture + bool m_ignoreTransparentParts = true; // Will be set to true after the first click, but gets reset to false when the second click does not occur soon after bool m_possibleDoubleClick = false; diff --git a/src/TGUI/CMakeLists.txt b/src/TGUI/CMakeLists.txt index b11b2da3..4b4acf52 100644 --- a/src/TGUI/CMakeLists.txt +++ b/src/TGUI/CMakeLists.txt @@ -36,6 +36,7 @@ set(TGUI_SRC Renderers/MenuBarRenderer.cpp Renderers/MessageBoxRenderer.cpp Renderers/PanelRenderer.cpp + Renderers/PictureRenderer.cpp Renderers/ProgressBarRenderer.cpp Renderers/RadioButtonRenderer.cpp Renderers/RangeSliderRenderer.cpp diff --git a/src/TGUI/Loading/WidgetLoader.cpp b/src/TGUI/Loading/WidgetLoader.cpp index 82297280..a8d51ae5 100644 --- a/src/TGUI/Loading/WidgetLoader.cpp +++ b/src/TGUI/Loading/WidgetLoader.cpp @@ -865,9 +865,6 @@ namespace tgui else picture = Picture::create(); - if (node->propertyValuePairs["texture"]) - picture = Picture::create(Deserializer::deserialize(ObjectConverter::Type::Texture, node->propertyValuePairs["texture"]->value).getTexture()); - loadWidget(node, picture); return picture; diff --git a/src/TGUI/Loading/WidgetSaver.cpp b/src/TGUI/Loading/WidgetSaver.cpp index 72ce9fb8..5fcab65d 100644 --- a/src/TGUI/Loading/WidgetSaver.cpp +++ b/src/TGUI/Loading/WidgetSaver.cpp @@ -534,10 +534,6 @@ namespace tgui { auto picture = std::static_pointer_cast(widget); auto node = WidgetSaver::getSaveFunction("widget")(picture); - - if (!picture->getTexture().getId().isEmpty()) - SET_PROPERTY("Texture", Serializer::serialize(picture->getTexture())); - return node; } diff --git a/src/TGUI/Renderers/PictureRenderer.cpp b/src/TGUI/Renderers/PictureRenderer.cpp new file mode 100644 index 00000000..be8b2d00 --- /dev/null +++ b/src/TGUI/Renderers/PictureRenderer.cpp @@ -0,0 +1,54 @@ +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// TGUI - Texus' Graphical User Interface +// Copyright (C) 2012-2017 Bruno Van de Velde (vdv_b@tgui.eu) +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it freely, +// subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; +// you must not claim that you wrote the original software. +// If you use this software in a product, an acknowledgment +// in the product documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, +// and must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +#include +#include + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +namespace tgui +{ + TGUI_RENDERER_PROPERTY_TEXTURE(PictureRenderer, Texture) + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + void PictureRenderer::setIgnoreTransparentParts(bool ignoreTransparentParts) + { + setProperty("ignoretransparentparts", ignoreTransparentParts); + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + bool PictureRenderer::getIgnoreTransparentParts() const + { + auto it = m_data->propertyValuePairs.find("ignoretransparentparts"); + if (it != m_data->propertyValuePairs.end()) + return it->second.getBool(); + else + return {}; + } +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/TGUI/Widgets/Picture.cpp b/src/TGUI/Widgets/Picture.cpp index 727a8b50..654efb4a 100644 --- a/src/TGUI/Widgets/Picture.cpp +++ b/src/TGUI/Widgets/Picture.cpp @@ -34,14 +34,19 @@ namespace tgui Picture::Picture() { m_type = "Picture"; + + m_renderer = aurora::makeCopied(); + setRenderer(RendererData::create({})); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - Picture::Picture(const Texture& texture, bool fullyClickable) : + Picture::Picture(const Texture& texture, bool ignoreTransparentParts) : Picture{} { - setTexture(texture, fullyClickable); + getRenderer()->setTexture(texture); + if (ignoreTransparentParts) + getRenderer()->setIgnoreTransparentParts(ignoreTransparentParts); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -63,32 +68,6 @@ namespace tgui ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void Picture::setTexture(const Texture& texture, bool fullyClickable) - { - if (!m_sprite.isSet() && (texture.getImageSize() != sf::Vector2f{0,0})) - setSize(texture.getImageSize()); - - m_fullyClickable = fullyClickable; - m_sprite.setTexture(texture); - m_sprite.setOpacity(m_opacityCached); - } - - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - const Texture& Picture::getTexture() const - { - return m_sprite.getTexture(); - } - - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - Texture& Picture::getTexture() - { - return m_sprite.getTexture(); - } - - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - void Picture::setSize(const Layout2d& size) { Widget::setSize(size); @@ -106,7 +85,7 @@ namespace tgui if (sf::FloatRect{0, 0, getSize().x, getSize().y}.contains(pos)) { // We sometimes want clicks to go through transparent parts of the picture - if (!m_fullyClickable && m_sprite.isTransparentPixel(pos)) + if (!m_ignoreTransparentParts && m_sprite.isTransparentPixel(pos)) return false; else return true; @@ -153,10 +132,26 @@ namespace tgui void Picture::rendererChanged(const std::string& property) { - Widget::rendererChanged(property); + if (property == "texture") + { + const auto& texture = getRenderer()->getTexture(); - if (property == "opacity") + if (!m_sprite.isSet() && (getSize() == sf::Vector2f{0,0})) + setSize(texture.getImageSize()); + + m_sprite.setTexture(texture); + } + else if (property == "ignoretransparentparts") + { + m_ignoreTransparentParts = getRenderer()->getIgnoreTransparentParts(); + } + else if (property == "opacity") + { + Widget::rendererChanged(property); m_sprite.setOpacity(m_opacityCached); + } + else + Widget::rendererChanged(property); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/tests/Widgets/Picture.cpp b/tests/Widgets/Picture.cpp index 80761a42..c0cc23fe 100644 --- a/tests/Widgets/Picture.cpp +++ b/tests/Widgets/Picture.cpp @@ -51,13 +51,13 @@ TEST_CASE("[Picture]") SECTION("from tgui::Texture") { REQUIRE_NOTHROW(picture = tgui::Picture::create("resources/image.png")); - REQUIRE(picture->getTexture().getId() == "resources/image.png"); + REQUIRE(picture->getRenderer()->getTexture().getId() == "resources/image.png"); } SECTION("from sf::Texture") { REQUIRE_NOTHROW(picture = tgui::Picture::create(texture)); - REQUIRE(picture->getTexture().getId() == ""); + REQUIRE(picture->getRenderer()->getTexture().getId() == ""); } REQUIRE(picture->getSize() == sf::Vector2f(texture.getSize())); @@ -74,36 +74,6 @@ TEST_CASE("[Picture]") REQUIRE(picture->getWidgetOffset() == sf::Vector2f(0, 0)); } - SECTION("setTexture") - { - picture->setSize(50, 50); - - SECTION("from tgui::Texture") - { - REQUIRE_NOTHROW(picture->setTexture("resources/image.png")); - REQUIRE(picture->getTexture().getId() == "resources/image.png"); - REQUIRE(picture->getSize() == sf::Vector2f(50, 50)); - - picture->setSize(100, 100); - REQUIRE_NOTHROW(picture->setTexture("resources/image.png")); - REQUIRE(picture->getSize() == sf::Vector2f(100, 100)); - } - - SECTION("from sf::Texture") - { - sf::Texture texture; - texture.loadFromFile("resources/image.png"); - - REQUIRE_NOTHROW(picture->setTexture(texture)); - REQUIRE(picture->getTexture().getId() == ""); - REQUIRE(picture->getSize() == sf::Vector2f(50, 50)); - - picture->setSize(100, 100); - REQUIRE_NOTHROW(picture->setTexture(texture)); - REQUIRE(picture->getSize() == sf::Vector2f(100, 100)); - } - } - SECTION("Events / Signals") { SECTION("ClickableWidget") @@ -113,7 +83,7 @@ TEST_CASE("[Picture]") SECTION("double click") { - picture->setTexture("resources/image.png"); + picture->getRenderer()->setTexture("resources/image.png"); picture->setPosition(40, 30); picture->setSize(150, 100); @@ -143,21 +113,31 @@ TEST_CASE("[Picture]") { auto renderer = picture->getRenderer(); + tgui::Texture texture("resources/Texture1.png"); + SECTION("set serialized property") { + REQUIRE_NOTHROW(renderer->setProperty("Texture", tgui::Serializer::serialize(texture))); + REQUIRE_NOTHROW(renderer->setProperty("IgnoreTransparentParts", "true")); REQUIRE_NOTHROW(renderer->setProperty("Opacity", "0.8")); } SECTION("set object property") { + REQUIRE_NOTHROW(renderer->setProperty("Texture", texture)); + REQUIRE_NOTHROW(renderer->setProperty("IgnoreTransparentParts", true)); REQUIRE_NOTHROW(renderer->setProperty("Opacity", 0.8f)); } SECTION("functions") { + renderer->setTexture(texture); + renderer->setIgnoreTransparentParts(true); renderer->setOpacity(0.8f); } + REQUIRE(renderer->getTexture().getData() == texture.getData()); + REQUIRE(renderer->getProperty("IgnoreTransparentParts").getBool()); REQUIRE(renderer->getProperty("Opacity").getNumber() == 0.8f); REQUIRE(renderer->getOpacity() == 0.8f); @@ -166,7 +146,7 @@ TEST_CASE("[Picture]") SECTION("Saving and loading from file") { - picture->setTexture("resources/image.png"); + picture->getRenderer()->setTexture("resources/image.png"); picture->setSize(80, 60); testSavingWidget("Picture", picture, false); @@ -176,7 +156,9 @@ TEST_CASE("[Picture]") { TEST_DRAW_INIT(60, 40, picture) - picture->setTexture("resources/image.png"); + picture->getRenderer()->setTexture("resources/image.png"); + picture->getRenderer()->setIgnoreTransparentParts(true); + picture->setPosition(10, 5); picture->setSize(40, 30);