Refactor and clean GuiComponent

master
Nicole Collings 2020-03-01 12:57:53 -08:00
parent 5cd56de9d0
commit 26e770b1bd
10 changed files with 162 additions and 181 deletions

View File

@ -28,6 +28,10 @@ std::shared_ptr<GuiComponent> GameGuiBuilder::createComponent(SerialGui::Elem &d
}
}
if (c != nullptr) c->setCallbacks(cbLeftClick, cbRightClick, cbHover);
if (c != nullptr) {
c->setCallback(GuiComponent::CallbackType::PRIMARY, cbLeftClick);
c->setCallback(GuiComponent::CallbackType::SECONDARY, cbRightClick);
c->setCallback(GuiComponent::CallbackType::HOVER, cbHover);
}
return c;
}

View File

@ -156,7 +156,11 @@ std::shared_ptr<GuiComponent> GuiBuilder::createComponent(SerialGui::Elem& data,
break;
}
if (c != nullptr) c->setCallbacks(cbLeftClick, cbRightClick, cbHover);
if (c != nullptr) {
c->setCallback(GuiComponent::CallbackType::PRIMARY, cbLeftClick);
c->setCallback(GuiComponent::CallbackType::SECONDARY, cbRightClick);
c->setCallback(GuiComponent::CallbackType::HOVER, cbHover);
}
return c;
}

View File

@ -8,48 +8,101 @@
GuiComponent::GuiComponent(const std::string& key) :
key(key) {}
void GuiComponent::setScale(glm::vec2 scale) {
this->scale = scale;
entity.setScale({scale.x, scale.y, scale.x});
}
glm::vec2 GuiComponent::getScale() {
return scale;
}
void GuiComponent::setPadding(glm::vec4 padding) {
this->padding = padding;
}
glm::vec4 GuiComponent::getPadding() {
return padding;
}
void GuiComponent::setPos(glm::ivec2 pos) {
this->pos = pos;
if (parent != nullptr) {
glm::vec3 parentPos = parent->entity.getPos();
pos += glm::vec2 {parentPos.x, parentPos.y};
pos += glm::vec2 {parent->getPadding().w, parent->getPadding().x};
}
entity.setPos({pos.x, pos.y, depth});
void GuiComponent::update(double delta) {
for (const auto& child : children) {
child->updatePos();
child->update(delta);
}
}
const std::string& GuiComponent::getKey() {
return key;
}
glm::ivec2 GuiComponent::getPos() {
return pos;
}
void GuiComponent::setHideOverflow(bool hideOverflow) {
this->hideOverflow = hideOverflow;
void GuiComponent::setPos(glm::ivec2 pos) {
this->pos = pos;
if (parent != nullptr) {
glm::vec3 parentPos = parent->entity.getPos();
pos += glm::vec2 {parentPos.x, parentPos.y};
pos += glm::vec2 {parent->getPadding().w, parent->getPadding().x};
}
entity.setPos({pos.x, pos.y, 0});
for (const auto& child : children) {
child->updatePos();
}
}
void GuiComponent::add(std::shared_ptr<GuiComponent> component) {
component->parent = this;
component->updatePos();
children.push_back(std::move(component));
glm::vec2 GuiComponent::getScale() {
return scale;
}
void GuiComponent::setScale(glm::vec2 scale) {
this->scale = scale;
entity.setScale({scale.x, scale.y, scale.x});
}
glm::vec4 GuiComponent::getPadding() {
return padding;
}
void GuiComponent::setPadding(glm::vec4 padding) {
this->padding = padding;
}
void GuiComponent::setOverflows(bool overflows) {
this->overflows = overflows;
}
void GuiComponent::setVisible(bool visible) {
Drawable::setVisible(visible);
entity.setVisible(visible);
for (const auto& child : children) {
child->setVisible(visible);
}
}
void GuiComponent::setCallback(GuiComponent::CallbackType type, const callback& cb) {
callbacks[static_cast<unsigned int>(type)] = cb;
}
bool GuiComponent::mouseActivity(glm::ivec2 pos) {
bool isHovering = false;
for (auto& child : children) {
glm::ivec2 cp = pos - child->getPos() - glm::ivec2(child->getPadding().y, child->getPadding().x);
if (child->mouseActivity(cp)) isHovering = true;
}
auto& callback = callbacks[static_cast<unsigned int>(CallbackType::HOVER)];
if (pos.x >= 0 && pos.y >= 0 && pos.x <= hitbox.x && pos.y <= hitbox.y) {
if (callback) {
callback(true, pos);
hovered = true;
return true;
}
return isHovering;
}
else {
if (callback) {
callback(false, pos);
hovered = false;
}
}
return isHovering;
}
void GuiComponent::leftClickEvent(bool state, glm::ivec2 pos) {
clickEvent(true, state, pos);
}
void GuiComponent::rightClickEvent(bool state, glm::ivec2 pos) {
clickEvent(false, state, pos);
}
void GuiComponent::insert(unsigned int index, std::shared_ptr<GuiComponent> component) {
@ -58,6 +111,12 @@ void GuiComponent::insert(unsigned int index, std::shared_ptr<GuiComponent> comp
children.insert(std::next(children.begin(), index), std::move(component));
}
void GuiComponent::add(std::shared_ptr<GuiComponent> component) {
component->parent = this;
component->updatePos();
children.push_back(std::move(component));
}
void GuiComponent::remove(const std::string& key) {
for (auto it = children.cbegin(); it != children.cend(); it++) {
if (it->get()->key == key) {
@ -75,19 +134,27 @@ void GuiComponent::empty() {
void GuiComponent::draw(Renderer& renderer) {
entity.draw(renderer);
for (const auto& child : children) {
renderer.setClipBounds(hideOverflow ? glm::vec4 {entity.getPos().x, entity.getPos().y,
entity.getPos().x + scale.x, entity.getPos().y + scale.y} : glm::vec4 {});
renderer.setClipBounds(overflows ? glm::vec4 {} : glm::vec4 {entity.getPos().x, entity.getPos().y,
entity.getPos().x + scale.x, entity.getPos().y + scale.y});
child->draw(renderer);
}
}
void GuiComponent::setVisible(bool visible) {
Drawable::setVisible(visible);
entity.setVisible(visible);
for (const auto& child : children) {
child->setVisible(visible);
bool GuiComponent::clickEvent(bool left, bool state, glm::ivec2 pos) {
for (auto& child : children) {
glm::ivec2 cp = pos - child->getPos() - glm::ivec2(child->getPadding().y, child->getPadding().x);
if (child->clickEvent(left, state, cp)) return true;
}
auto& callback = callbacks[static_cast<unsigned int>(left ? CallbackType::PRIMARY : CallbackType::SECONDARY)];
if (pos.x >= 0 && pos.y >= 0 && pos.x <= hitbox.x && pos.y <= hitbox.y && callback) {
callback(state, pos);
return true;
}
return false;
}
void GuiComponent::updatePos() {
@ -97,78 +164,8 @@ void GuiComponent::updatePos() {
realPos += glm::vec2 {parentPos.x, parentPos.y};
realPos += glm::vec2 {parent->getPadding().w, parent->getPadding().x};
}
entity.setPos({realPos.x, realPos.y, depth});
entity.setPos({realPos.x, realPos.y, 0});
for (const auto& child : children) {
child->updatePos();
}
}
bool GuiComponent::mouseActivity(glm::ivec2 pos) {
bool isHovering = false;
for (auto child = children.rbegin(); child != children.rend(); ++child) {
if ((*child)->mouseActivity(pos - (*child)->getPos() - glm::ivec2((*child)->getPadding().y, (*child)->getPadding().x))) isHovering = true;
}
if (pos.x >= 0 && pos.y >= 0 && pos.x <= hitbox.x && pos.y <= hitbox.y) {
if (cbHover) {
cbHover(true, pos);
hovered = true;
return true;
}
return isHovering;
}
else {
if (cbHover) {
cbHover(false, pos);
hovered = false;
}
}
return isHovering;
}
void GuiComponent::update(double delta) {
for (const auto& child : children) {
child->update(delta);
}
}
void GuiComponent::leftClickEvent(bool state, glm::ivec2 pos) {
clickEvent(true, state, pos);
}
void GuiComponent::rightClickEvent(bool state, glm::ivec2 pos) {
clickEvent(false, state, pos);
}
void GuiComponent::setHoverCallback(const callback& hoverCallback) {
cbHover = hoverCallback;
}
void GuiComponent::setLeftClickCallback(const callback& leftClickCallback) {
cbLeftClick = leftClickCallback;
}
void GuiComponent::setRightClickCallback(const callback& rightClickCallback) {
cbRightClick = rightClickCallback;
}
void GuiComponent::setCallbacks(const callback &left, const callback &right, const callback &hover) {
setLeftClickCallback(left);
setRightClickCallback(right);
setHoverCallback(hover);
}
const std::string &GuiComponent::getKey() {
return key;
}
bool GuiComponent::clickEvent(bool left, bool state, glm::ivec2 pos) {
for (auto child = children.rbegin(); child != children.rend(); ++child) {
glm::ivec2 cp = pos - (*child)->getPos() - glm::ivec2((*child)->getPadding().y, (*child)->getPadding().x);
if ((*child)->clickEvent(left, state, cp)) return true;
}
if (pos.x >= 0 && pos.y >= 0 && pos.x <= hitbox.x && pos.y <= hitbox.y && (left ? cbLeftClick : cbRightClick)) {
(left ? cbLeftClick : cbRightClick)(state, pos);
return true;
}
return false;
}

View File

@ -12,35 +12,31 @@
class GuiComponent : public Drawable {
public:
enum class CallbackType { PRIMARY, SECONDARY, HOVER };
typedef std::function<void(bool, glm::ivec2)> callback;
GuiComponent() = default;
explicit GuiComponent(const std::string& key);
virtual void setScale(glm::vec2 scale);
virtual glm::vec2 getScale();
virtual void setPadding(glm::vec4 padding);
virtual glm::vec4 getPadding();
virtual void setPos(glm::ivec2 pos);
virtual glm::ivec2 getPos();
void setHideOverflow(bool hideOverflow);
virtual void update(double delta) override;
const std::string& getKey();
virtual glm::ivec2 getPos();
virtual void setPos(glm::ivec2 pos);
virtual glm::vec2 getScale();
virtual void setScale(glm::vec2 scale);
virtual glm::vec4 getPadding();
virtual void setPadding(glm::vec4 padding);
void setOverflows(bool overflows);
void setVisible(bool visible) override;
virtual void setCallback(CallbackType type, const callback& cb);
bool mouseActivity(glm::ivec2 pos);
void leftClickEvent(bool state, glm::ivec2 pos);
void rightClickEvent(bool state, glm::ivec2 pos);
virtual void setHoverCallback(const callback& hoverCallback);
virtual void setLeftClickCallback(const callback& leftClickCallback);
virtual void setRightClickCallback(const callback& rightClickCallback);
void setCallbacks(const callback& left, const callback& right, const callback& hover);
void add(std::shared_ptr<GuiComponent> component);
void insert(unsigned int index, std::shared_ptr<GuiComponent> component);
template<class T> std::shared_ptr<T> get(const std::string &key) {
for (auto &it : children) {
if (it.get()->key == key) {
@ -48,15 +44,14 @@ public:
}
}
};
void insert(unsigned int index, std::shared_ptr<GuiComponent> component);
void add(std::shared_ptr<GuiComponent> component);
void remove(const std::string& key);
void empty();
const std::string& getKey();
void setVisible(bool visible) override;
void draw(Renderer& renderer) override;
bool hovered = false;
protected:
bool clickEvent(bool left, bool state, glm::ivec2 pos);
@ -64,22 +59,18 @@ protected:
GuiComponent* parent = nullptr;
std::list<std::shared_ptr<GuiComponent>> children;
bool visible = true;
glm::ivec2 pos {};
glm::vec2 scale {};
glm::vec4 padding {};
glm::ivec2 hitbox {};
bool hideOverflow = false;
callback cbLeftClick = nullptr;
callback cbRightClick = nullptr;
callback cbHover = nullptr;
bool visible = true;
bool hovered = false;
bool overflows = false;
Entity entity;
protected:
float depth = 0;
std::array<callback, 3> callbacks;
private:
void updatePos();
};

View File

@ -27,7 +27,7 @@ std::shared_ptr<GuiRect> GuiRect::fromSerialized(SerialGui::Elem s, ClientGame&
if (background[0] == '#') rect->create(size, padding, Util::hexToColorVec(background));
else if (background.size() > 0) rect->create(size, padding, game.textures[background]);
else rect->create(size, padding, glm::vec4 {});
rect->setHideOverflow(hideOverflow);
rect->setOverflows(!hideOverflow);
rect->setPos(pos);
return rect;
}

View File

@ -34,7 +34,7 @@ std::shared_ptr<GuiImageButton> GuiImageButton::fromSerialized(SerialGui::Elem s
auto button = std::make_shared<GuiImageButton>(s.key);
button->create(size, padding, game.textures[background], game.textures[background_hover]);
button->setHideOverflow(hideOverflow);
button->setOverflows(!hideOverflow);
button->setPos(pos);
if (content != "") {
@ -55,14 +55,17 @@ void GuiImageButton::create(glm::vec2 scale, glm::vec4 padding, std::shared_ptr<
this->hoverTexture = hoverTexture;
GuiRect::create(scale, padding, texture);
setHoverCallback(nullptr);
setCallback(GuiComponent::CallbackType::HOVER, nullptr);
}
void GuiImageButton::setHoverCallback(const callback& hoverCallback) {
GuiComponent::setHoverCallback([&, hoverCallback](bool nowHovered, glm::ivec2 pos) {
if (hoverCallback) hoverCallback(nowHovered, pos);
if (nowHovered != hovered) this->rebuild(nowHovered);
});
void GuiImageButton::setCallback(GuiComponent::CallbackType type, const GuiComponent::callback &cb) {
if (type == CallbackType::HOVER) {
GuiComponent::setCallback(type, [&, cb](bool nowHovered, glm::ivec2 pos) {
if (cb) cb(nowHovered, pos);
if (nowHovered != hovered) this->rebuild(nowHovered);
});
}
else GuiComponent::setCallback(type, cb);
}
void GuiImageButton::rebuild(bool hover) {

View File

@ -15,7 +15,7 @@ public:
void create(glm::vec2 scale, glm::vec4 padding, std::shared_ptr<AtlasRef> texture, std::shared_ptr<AtlasRef> hoverTexture);
void setHoverCallback(const callback& hoverCallback) override;
void setCallback(CallbackType type, const callback& cb) override;
private:
void rebuild(bool hover);
std::shared_ptr<AtlasRef> hoverTexture = nullptr;

View File

@ -49,31 +49,15 @@ void GuiInventoryList::create(glm::vec2 scale, glm::vec4 padding, glm::ivec2 inn
list->setGuiCallback(std::bind(&GuiInventoryList::drawContents, this));
hoverRect->create({}, {}, {1, 1, 1, 0.1});
setCallbacks(
[=](bool down, glm::ivec2 pos) { this->leftClick(down, pos); },
nullptr,
[=](bool hovered, glm::ivec2 pos){this->hoverEvent(hovered, pos);});
}
void GuiInventoryList::setHoverCallback(const callback& hoverCallback) {
GuiComponent::setHoverCallback([&, hoverCallback](bool hovered, glm::ivec2 pos) {
if (hoverCallback) hoverCallback(hovered, pos);
this->hoverEvent(hovered, pos);
});
}
void GuiInventoryList::setCallback(CallbackType type, const callback& cb) {
GuiComponent::setCallback(type, [&, cb, type](bool down, glm::ivec2 pos) {
if (cb) cb(down, pos);
void GuiInventoryList::setLeftClickCallback(const callback& leftClickCallback) {
GuiComponent::setLeftClickCallback([&, leftClickCallback](bool down, glm::ivec2 pos) {
if (leftClickCallback) leftClickCallback(down, pos);
this->leftClick(down, pos);
});
}
void GuiInventoryList::setRightClickCallback(const callback& rightClickCallback) {
GuiComponent::setRightClickCallback([&, rightClickCallback](bool down, glm::ivec2 pos) {
if (rightClickCallback) rightClickCallback(down, pos);
this->rightClick(down, pos);
if (type == GuiComponent::CallbackType::PRIMARY ) this->leftClick (down, pos);
else if (type == GuiComponent::CallbackType::SECONDARY) this->rightClick(down, pos);
else if (type == GuiComponent::CallbackType::HOVER ) this->hoverEvent(down, pos);
});
}

View File

@ -25,9 +25,7 @@ public:
void create(glm::vec2 scale, glm::vec4 padding, glm::ivec2 innerPadding,
std::shared_ptr<LocalInventoryList> list, std::shared_ptr<LocalInventoryList> hand, ClientGame& defs);
void setHoverCallback(const callback& hoverCallback) override;
void setLeftClickCallback(const callback& leftClickCallback) override;
void setRightClickCallback(const callback& rightClickCallback) override;
void setCallback(CallbackType type, const callback& cb) override;
void hoverEvent(bool hovered, glm::ivec2 pos);
void leftClick(bool down, glm::ivec2 pos);

View File

@ -50,7 +50,7 @@ MainMenuScene::MainMenuScene(ClientState& state) :
closeButton->create({16 * GS, 16 * GS}, {},
state.defs.textures["crop(0, 0, 16, 16, menu_flag_quit)"],
state.defs.textures["crop(16, 0, 16, 16, menu_flag_quit)"]);
closeButton->setLeftClickCallback([](bool down, glm::ivec2) { if (down) exit(0); });
closeButton->setCallback(GuiComponent::CallbackType::PRIMARY, [](bool down, glm::ivec2) { if (down) exit(0); });
navigationBar->get<GuiContainer>("navigationBarIcons")->add(closeButton);
auto serversButton = std::make_shared<GuiImageButton>("serversButton");
@ -65,7 +65,7 @@ MainMenuScene::MainMenuScene(ClientState& state) :
state.defs.textures["crop(0, 0, 16, 16, menu_flag_content)"],
state.defs.textures["crop(16, 0, 16, 16, menu_flag_content)"]);
contentButton->setPos({GS + GS * 18, GS});
contentButton->setLeftClickCallback([&](bool down, glm::ivec2) { if (down) state.desiredState = "connect"; });
contentButton->setCallback(GuiComponent::CallbackType::PRIMARY, [&](bool down, glm::ivec2) { if (down) state.desiredState = "connect"; });
navigationBarIcons->add(contentButton);
auto divider = std::make_shared<GuiRect>("divider");
@ -82,7 +82,7 @@ MainMenuScene::MainMenuScene(ClientState& state) :
state.defs.textures["crop(0, 0, 16, 16, " + subgame.iconRef->name + ")"],
state.defs.textures["crop(16, 0, 16, 16, " + subgame.iconRef->name + ")"]);
button->setPos({GS * 7 + GS * 18 * (i + 2), GS});
button->setLeftClickCallback([&, i](bool down, glm::ivec2) {
button->setCallback(GuiComponent::CallbackType::PRIMARY, [&, i](bool down, glm::ivec2) {
if (down) {
selectedSubgame = &subgame;
sandbox.load(*selectedSubgame);