mirror of
https://github.com/MihailRis/voxelcore.git
synced 2026-10-04 18:41:51 +00:00
274 lines
6.7 KiB
C++
274 lines
6.7 KiB
C++
#include "Container.hpp"
|
|
|
|
#include "../GUI.hpp"
|
|
#include "graphics/core/Batch2D.hpp"
|
|
#include "graphics/core/DrawContext.hpp"
|
|
#include "window/Window.hpp"
|
|
|
|
#include <algorithm>
|
|
#include <utility>
|
|
|
|
using namespace gui;
|
|
|
|
Container::Container(GUI& gui, glm::vec2 size) : UINode(gui, size) {
|
|
actualLengthY = size.y;
|
|
setColor(glm::vec4());
|
|
}
|
|
|
|
Container::~Container() {
|
|
Container::clear();
|
|
}
|
|
|
|
std::shared_ptr<UINode> Container::getAt(const glm::vec2& pos) {
|
|
if (!isInteractive() || !isEnabled()) {
|
|
return nullptr;
|
|
}
|
|
if (!isInside(pos)) {
|
|
return nullptr;
|
|
}
|
|
int diff = (actualLengthY - 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::click(int x, int y) {
|
|
UINode::click(x, y);
|
|
|
|
if (scrollable) {
|
|
auto pos = calcPos();
|
|
x -= pos.x;
|
|
y -= pos.y;
|
|
if (x >= size.x - scrollBarWidth) {
|
|
scrollbarTriggered = true;
|
|
prevScrollY = y;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Container::mouseMove(int x, int y) {
|
|
UINode::mouseMove(x, y);
|
|
if (!scrollable || !scrollbarTriggered) {
|
|
return;
|
|
}
|
|
auto pos = calcPos();
|
|
x -= pos.x;
|
|
y -= pos.y;
|
|
int diff = (actualLengthY - size.y);
|
|
if (diff > 0) {
|
|
scrollY -=
|
|
(y - prevScrollY) / static_cast<float>(size.y) * actualLengthY;
|
|
scrollY = -glm::min(
|
|
glm::max(static_cast<float>(-scrollY), 0.0f), actualLengthY - size.y
|
|
);
|
|
}
|
|
prevScrollY = y;
|
|
}
|
|
|
|
void Container::mouseRelease(int x, int y) {
|
|
UINode::mouseRelease(x, y);
|
|
scrollbarTriggered = false;
|
|
}
|
|
|
|
void Container::act(float delta) {
|
|
UINode::act(delta);
|
|
for (const auto& node : nodes) {
|
|
if (node->isVisible()) {
|
|
node->act(delta);
|
|
}
|
|
}
|
|
if (!intervalEvents.empty()) {
|
|
// TODO: make it interval-based
|
|
gui.getWindow().setShouldRefresh();
|
|
}
|
|
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) {
|
|
auto size = getSize();
|
|
bool isVertical = actualLengthY > size.y;
|
|
int diff = (isVertical ? actualLengthY - size.y : actualLengthX - size.x);
|
|
int& scroll = (isVertical ? scrollY : scrollX);
|
|
|
|
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 = (actualLengthY - size.y);
|
|
if (scrollable && diff > 0) {
|
|
int h = glm::max(
|
|
size.y / actualLengthY * 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 - scrollY / static_cast<float>(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<UINode>& node) {
|
|
nodes.push_back(node);
|
|
node->setParent(this);
|
|
node->reposition();
|
|
mustRefresh = true;
|
|
|
|
auto parent = getParent();
|
|
while (parent) {
|
|
parent->setMustRefresh();
|
|
parent = parent->getParent();
|
|
}
|
|
gui.getWindow().setShouldRefresh();
|
|
}
|
|
|
|
void Container::add(const std::shared_ptr<UINode>& 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<UINode>& 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(const glm::vec2& size) {
|
|
if (size == getSize()) {
|
|
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->scrollY = scroll;
|
|
}
|
|
|
|
const std::vector<std::shared_ptr<UINode>>& Container::getNodes() const {
|
|
return nodes;
|
|
}
|