#include "Container.hpp" #include "graphics/core/DrawContext.hpp" #include "graphics/core/Batch2D.hpp" #include #include using namespace gui; Container::Container(GUI& gui, glm::vec2 size) : UINode(gui, size) { actualLength = size.y; setColor(glm::vec4()); } Container::~Container() { Container::clear(); } std::shared_ptr Container::getAt(const glm::vec2& pos) { if (!isInteractive() || !isEnabled()) { return nullptr; } if (!isInside(pos)) { return nullptr; } int diff = (actualLength-size.y); if (scrollable && diff > 0 && pos.x > calcPos().x + getSize().x - scrollBarWidth) { return UINode::getAt(pos); } for (int i = nodes.size()-1; i >= 0; i--) { auto& node = nodes[i]; if (!node->isVisible()) continue; auto hover = node->getAt(pos); if (hover != nullptr) { return hover; } } return UINode::getAt(pos); } void Container::mouseMove(int x, int y) { UINode::mouseMove(x, y); if (!scrollable) { return; } auto pos = calcPos(); x -= pos.x; y -= pos.y; if (prevScrollY == -1) { if (x >= size.x - scrollBarWidth) { prevScrollY = y; } return; } int diff = (actualLength-size.y); if (diff > 0) { scroll -= (y - prevScrollY) / static_cast(size.y) * actualLength; scroll = -glm::min( glm::max(static_cast(-scroll), 0.0f), actualLength - size.y ); } prevScrollY = y; } void Container::mouseRelease(int x, int y) { UINode::mouseRelease(x, y); prevScrollY = -1; } void Container::act(float delta) { for (const auto& node : nodes) { if (node->isVisible()) { node->act(delta); } } for (IntervalEvent& event : intervalEvents) { event.timer += delta; if (event.timer > event.interval) { event.callback(); event.timer = fmod(event.timer, event.interval); if (event.repeat > 0) { event.repeat--; } } } intervalEvents.erase(std::remove_if( intervalEvents.begin(), intervalEvents.end(), [](const IntervalEvent& event) { return event.repeat == 0; } ), intervalEvents.end()); } void Container::scrolled(int value) { int diff = (actualLength-getSize().y); if (scroll < 0 && diff <= 0) { scroll = 0; } if (diff > 0 && scrollable) { scroll += value * scrollStep; if (scroll > 0) scroll = 0; if (-scroll > diff) { scroll = -diff; } } else if (parent) { parent->scrolled(value); } } void Container::setScrollable(bool flag) { scrollable = flag; } void Container::draw(const DrawContext& pctx, const Assets& assets) { glm::vec2 pos = calcPos(); glm::vec2 size = getSize(); drawBackground(pctx, assets); auto batch = pctx.getBatch2D(); batch->texture(nullptr); if (!nodes.empty()) { batch->flush(); DrawContext ctx = pctx.sub(); ctx.setScissors(glm::vec4(pos.x, pos.y, glm::ceil(size.x), glm::ceil(size.y))); for (const auto& node : nodes) { if (node->isVisible()) node->draw(pctx, assets); } int diff = (actualLength-size.y); if (scrollable && diff > 0) { int h = glm::max(size.y / actualLength * size.y, scrollBarWidth / 2.0f); batch->untexture(); batch->setColor(glm::vec4(1, 1, 1, 0.3f)); batch->rect( pos.x + size.x - scrollBarWidth, pos.y - scroll / static_cast(diff) * (size.y - h), scrollBarWidth, h ); } batch->flush(); } } void Container::drawBackground(const DrawContext& pctx, const Assets&) { glm::vec4 color = calcColor(); if (color.a <= 0.001f) return; glm::vec2 pos = calcPos(); auto batch = pctx.getBatch2D(); batch->texture(nullptr); batch->setColor(color); batch->rect(pos.x, pos.y, glm::ceil(size.x), glm::ceil(size.y)); } void Container::add(const std::shared_ptr& node) { nodes.push_back(node); node->setParent(this); node->reposition(); refresh(); } void Container::add(const std::shared_ptr& node, glm::vec2 pos) { node->setPos(pos); add(node); } void Container::remove(UINode* selected) { selected->setParent(nullptr); nodes.erase(std::remove_if(nodes.begin(), nodes.end(), [selected](const std::shared_ptr& node) { return node.get() == selected; } ), nodes.end()); refresh(); } void Container::remove(const std::string& id) { for (auto& node : nodes) { if (node->getId() == id) { return remove(node.get()); } } } void Container::clear() { for (const auto& node : nodes) { node->setParent(nullptr); } nodes.clear(); refresh(); } void Container::listenInterval(float interval, ontimeout callback, int repeat) { intervalEvents.push_back({std::move(callback), interval, 0.0f, repeat}); } void Container::setSize(glm::vec2 size) { if (size == getSize()) { refresh(); return; } UINode::setSize(size); refresh(); for (auto& node : nodes) { node->reposition(); } } int Container::getScrollStep() const { return scrollStep; } void Container::setScrollStep(int step) { scrollStep = step; } void Container::refresh() { std::stable_sort(nodes.begin(), nodes.end(), [](const auto& a, const auto& b) { return a->getZIndex() < b->getZIndex(); }); } void Container::setScroll(int scroll) { this->scroll = scroll; } const std::vector>& Container::getNodes() const { return nodes; }