Refactor UI code

This commit is contained in:
MrLetsplay 2024-08-24 22:41:14 +02:00
parent 26b532c926
commit d9cfcba0ba
Signed by: mr
SSH Key Fingerprint: SHA256:92jBH80vpXyaZHjaIl47pjRq+Yt7XGTArqQg1V7hSqg
13 changed files with 240 additions and 156 deletions

View File

@ -1,11 +1,15 @@
#include "constants.h"
#include "defaultplayercontroller.h"
#include "input.h"
#include "internal.h"
#include "internal/input.h"
#include "internal/physics.h"
#include "internal/ui.h"
#include "noclipplayercontroller.h"
#include "types.h"
#include "ui.h"
#include "uielements.h"
#include <GLFW/glfw3.h>
namespace kek::Defaults {
@ -25,17 +29,10 @@ static void defaultPeriodic(PeriodicEvent event, void *data) {
}
static void doUIMouseHover(double x, double y) {
UIElement *hoveredElement = nullptr;
if(Input::getMouseButtonState(GLFWMouseButton::LEFT) == GLFWMouseButtonState::PRESSED) return;
for(UIElement *element : kekData.ui->elements) {
UIPoint childPos = element->getPosition();
UIPoint hoveredAt = UIPoint((int) x - childPos.x, (int) y - childPos.y);
UIBounds bounds = element->getBounds();
if(!bounds.containsOffset(hoveredAt)) continue;
hoveredElement = element;
}
IntPoint2 mousePosition = IntPoint2((int) x, (int) y);
UIElement *hoveredElement = UI::findElementAt(mousePosition);
for(UIElement *element : kekData.ui->elements) {
if(element->hovering && element != hoveredElement) {
@ -44,36 +41,54 @@ static void doUIMouseHover(double x, double y) {
}
if(hoveredElement) {
UIPoint childPos = hoveredElement->getPosition();
UIPoint hoveredAt = UIPoint((int) x - childPos.x, (int) y - childPos.y);
hoveredElement->hoverAll(hoveredAt, UIPoint((int) x, (int) y));
IntPoint2 childPos = hoveredElement->getPosition();
hoveredElement->hoverAll(mousePosition - childPos, mousePosition);
}
}
static void doUIMouseDrag(double x, double y) {
if(Input::getMouseButtonState(GLFWMouseButton::LEFT) != GLFWMouseButtonState::PRESSED) {
kekData.input->mouseDown = false;
return;
}
if(!kekData.input->mouseDown) {
kekData.input->mouseDownPosition = IntPoint2((int) x, (int) y);
}
int deltaX = (int) x - kekData.input->mouseDownPosition.x;
int deltaY = (int) y - kekData.input->mouseDownPosition.y;
if(deltaX * deltaX + deltaY * deltaY >= KEK_UI_MIN_DRAG_DISTANCE_SQUARED) {
// Initiate drag
IntPoint2 mousePosition = IntPoint2((int) x, (int) y);
UIElement *draggedElement = UI::findElementAt(mousePosition);
if(draggedElement) {
IntPoint2 childPos = draggedElement->getPosition();
draggedElement->dragEnterAll(mousePosition - childPos, mousePosition);
}
}
// TODO: drag dragged element, exit drag
kekData.input->mouseDown = true;
}
static void doUIMouseClick(double x, double y, GLFWMouseButton button) {
UIElement *clickedElement = nullptr;
for(UIElement *element : kekData.ui->elements) {
UIPoint childPos = element->getPosition();
UIPoint clickedAt = UIPoint((int) x - childPos.x, (int) y - childPos.y);
UIBounds bounds = element->getBounds();
if(!bounds.containsOffset(clickedAt)) continue;
clickedElement = element;
}
IntPoint2 mousePosition = IntPoint2((int) x, (int) y);
UIElement *clickedElement = UI::findElementAt(mousePosition);
if(clickedElement) {
UIPoint childPos = clickedElement->getPosition();
UIPoint clickedAt = UIPoint((int) x - childPos.x, (int) y - childPos.y);
IntPoint2 childPos = clickedElement->getPosition();
IntPoint2 clickedAt = mousePosition - childPos;
if(button == GLFWMouseButton::LEFT) {
if(!clickedElement->focusEnterAll(clickedAt, UIPoint((int) x, (int) y))) {
if(!clickedElement->focusEnterAll(clickedAt, IntPoint2((int) x, (int) y))) {
UI::unfocusElement(kekData.ui->focusedElement);
}
}
clickedElement->clickAll(clickedAt, UIPoint((int) x, (int) y), button);
clickedElement->clickAll(clickedAt, IntPoint2((int) x, (int) y), button);
} else {
UI::unfocusElement(kekData.ui->focusedElement);
}
@ -94,6 +109,7 @@ static void defaultKeyCallback(KeyEvent event, void *data) {
double x, y;
glfwGetCursorPos(kekData.window, &x, &y);
doUIMouseHover(x, y);
doUIMouseDrag(x, y);
} else {
Input::setCursorMode(GLFWCursorMode::CAPTURE);
@ -138,6 +154,7 @@ static void defaultMouseCallback(MouseEvent event, void *data) {
case GLFWCursorMode::FREE:
case GLFWCursorMode::HIDDEN: {
doUIMouseHover(event.x, event.y);
doUIMouseDrag(event.x, event.y);
break;
}
}

View File

@ -301,7 +301,7 @@ int start() {
prevTime = time;
for(UIElement *uiEl : kekData.ui->elements) {
UIPoint pos = uiEl->getScreenPosition();
IntPoint2 pos = uiEl->getScreenPosition();
uiEl->drawAll(pos, uiProjection);
}

View File

@ -147,8 +147,12 @@ KeyBindingData getKeyBinding(KeyBinding binding) {
GLFWKeyState getKeyState(KeyBinding binding) {
auto it = kekData.input->keyBindings.find(binding);
if(it == kekData.input->keyBindings.end()) return -1;
return glfwGetKey(kekData.window, it->second.key);
if(it == kekData.input->keyBindings.end()) return GLFWKeyState::ERROR_INVALID_KEY_BINDING;
return (GLFWKeyState) glfwGetKey(kekData.window, it->second.key);
}
GLFWMouseButtonState getMouseButtonState(GLFWMouseButton mouseButton) {
return (GLFWMouseButtonState) glfwGetMouseButton(kekData.window, (int) mouseButton);
}
void setCursorMode(GLFWCursorMode mode) {

View File

@ -105,23 +105,23 @@ void DefaultPlayerController::update() {
glm::vec3 direction = glm::vec3(0);
if(!Input::isKeyboardCaptured()) {
if(Input::getKeyState(keyForward) == GLFW_PRESS) {
if(Input::getKeyState(keyForward) == GLFWKeyState::PRESSED) {
direction += kekData.activeCamera->direction;
}
if(Input::getKeyState(keyBackward) == GLFW_PRESS) {
if(Input::getKeyState(keyBackward) == GLFWKeyState::PRESSED) {
direction += -kekData.activeCamera->direction;
}
if(Input::getKeyState(keyLeft) == GLFW_PRESS) {
if(Input::getKeyState(keyLeft) == GLFWKeyState::PRESSED) {
direction += -glm::normalize(glm::cross(kekData.activeCamera->direction, glm::vec3(0.0f, 1.0f, 0.0f)));
}
if(Input::getKeyState(keyRight) == GLFW_PRESS) {
if(Input::getKeyState(keyRight) == GLFWKeyState::PRESSED) {
direction += glm::normalize(glm::cross(kekData.activeCamera->direction, glm::vec3(0.0f, 1.0f, 0.0f)));
}
if(Input::getKeyState(keyJump) == GLFW_PRESS && kekData.player->onGround) {
if(Input::getKeyState(keyJump) == GLFWKeyState::PRESSED && kekData.player->onGround) {
velocity += glm::vec3(0, jumpVelocity, 0);
}

View File

@ -21,27 +21,27 @@ void NoclipPlayerController::update() {
glm::vec3 direction = glm::vec3(0);
if(Input::getKeyState(keyForward) == GLFW_PRESS) {
if(Input::getKeyState(keyForward) == GLFWKeyState::PRESSED) {
direction += kekData.activeCamera->direction;
}
if(Input::getKeyState(keyBackward) == GLFW_PRESS) {
if(Input::getKeyState(keyBackward) == GLFWKeyState::PRESSED) {
direction += -kekData.activeCamera->direction;
}
if(Input::getKeyState(keyLeft) == GLFW_PRESS) {
if(Input::getKeyState(keyLeft) == GLFWKeyState::PRESSED) {
direction += -glm::normalize(glm::cross(kekData.activeCamera->direction, glm::vec3(0.0f, 1.0f, 0.0f)));
}
if(Input::getKeyState(keyRight) == GLFW_PRESS) {
if(Input::getKeyState(keyRight) == GLFWKeyState::PRESSED) {
direction += glm::normalize(glm::cross(kekData.activeCamera->direction, glm::vec3(0.0f, 1.0f, 0.0f)));
}
if(Input::getKeyState(keyUp) == GLFW_PRESS) {
if(Input::getKeyState(keyUp) == GLFWKeyState::PRESSED) {
direction += glm::vec3(0, 1, 0);
}
if(Input::getKeyState(keyDown) == GLFW_PRESS) {
if(Input::getKeyState(keyDown) == GLFWKeyState::PRESSED) {
direction += glm::vec3(0, -1, 0);
}

View File

@ -8,6 +8,7 @@
#include "input.h"
#include "internal.h"
#include "internal/ui.h"
#include "types.h"
namespace kek {
@ -21,21 +22,21 @@ UIElement::~UIElement() {
}
// Returns the element's origin position relative to its parent in pixels (not offset by getBounds())
UIPoint UIElement::getOriginPosition() {
return UIPoint(uiToScreen(x), uiToScreen(y));
IntPoint2 UIElement::getOriginPosition() {
return IntPoint2(uiToScreen(x), uiToScreen(y));
}
// Returns the element's position relative to its parent in pixels (offset by getBounds())
UIPoint UIElement::getPosition() {
// Returns the element's position relative to its parent in pixels (offset by getBounds(), aka. the position of the top-left of the element)
IntPoint2 UIElement::getPosition() {
UIBounds bounds = getBounds();
return UIPoint(uiToScreen(x) + bounds.x, uiToScreen(y) + bounds.y);
return IntPoint2(uiToScreen(x) + bounds.x, uiToScreen(y) + bounds.y);
}
// Returns the element's origin position on the screen in pixels (not offset by getBounds())
UIPoint UIElement::getScreenOriginPosition() {
UIPoint pos = getOriginPosition();
IntPoint2 UIElement::getScreenOriginPosition() {
IntPoint2 pos = getOriginPosition();
if(parent) {
UIPoint parentPos = parent->getScreenPosition();
IntPoint2 parentPos = parent->getScreenPosition();
pos.x += parentPos.x;
pos.y += parentPos.y;
}
@ -43,11 +44,18 @@ UIPoint UIElement::getScreenOriginPosition() {
return pos;
}
// Returns the element's position on the screen in pixels (offset by getBounds())
UIPoint UIElement::getScreenPosition() {
UIPoint pos = getScreenOriginPosition();
// Returns the element's position on the screen in pixels (offset by getBounds(), aka. the position of the top-left of the element)
IntPoint2 UIElement::getScreenPosition() {
IntPoint2 pos = getScreenOriginPosition();
UIBounds bounds = getBounds();
return UIPoint(pos.x + bounds.x, pos.y + bounds.y);
return IntPoint2(pos.x + bounds.x, pos.y + bounds.y);
}
// Returns the bounds of the element on the screen
UIBounds UIElement::getScreenBounds() {
IntPoint2 pos = getScreenOriginPosition();
UIBounds bounds = getBounds();
return UIBounds(pos.x + bounds.x, pos.y + bounds.y, bounds.w, bounds.h);
}
std::vector<UIElement *> UIElement::getChildren() {
@ -122,7 +130,7 @@ UIBounds UIElement::offsetUIBounds(int w, int h, Origin origin) {
return UIBounds(offsetX(w, origin), offsetY(h, origin), w, h);
}
void UIElement::drawAll(UIPoint screenPos, glm::mat4 projection) {
void UIElement::drawAll(IntPoint2 screenPos, glm::mat4 projection) {
if(!visible) return;
UIBounds bounds = getBounds();
@ -135,8 +143,8 @@ void UIElement::drawAll(UIPoint screenPos, glm::mat4 projection) {
draw(screenPos, projection);
for(UIElement *child : children) {
UIPoint pos = child->getPosition();
child->drawAll(UIPoint(screenPos.x + pos.x, screenPos.y + pos.y), projection);
IntPoint2 pos = child->getPosition();
child->drawAll(IntPoint2(screenPos.x + pos.x, screenPos.y + pos.y), projection);
}
if(enableClipping) {
@ -144,24 +152,30 @@ void UIElement::drawAll(UIPoint screenPos, glm::mat4 projection) {
}
}
void UIElement::hoverAll(UIPoint pos, UIPoint screenPos) {
UIElement *hoveredChild = nullptr;
for(UIElement *child : children) {
UIPoint childPos = child->getPosition();
int relX = pos.x - childPos.x;
int relY = pos.y - childPos.y;
static UIElement *findChildAtRelativePos(UIElement *element, IntPoint2 pos) {
UIElement *foundChild = nullptr;
for(UIElement *child : element->getChildren()) {
IntPoint2 childPos = child->getPosition();
IntPoint2 relativeChildPos = pos - childPos;
UIBounds b = child->getBounds();
if(!b.containsOffset(UIPoint(relX, relY))) continue;
hoveredChild = child;
if(!b.containsOffset(relativeChildPos)) continue;
foundChild = child;
}
return foundChild;
}
void UIElement::hoverAll(IntPoint2 pos, IntPoint2 screenPos) {
UIElement *hoveredChild = findChildAtRelativePos(this, pos);
for(UIElement *child : children) {
if(child != hoveredChild && child->hovering) child->hoverExitAll();
}
if(hoveredChild) {
UIPoint childPos = hoveredChild->getPosition();
hoveredChild->hoverAll(UIPoint(pos.x - childPos.x, pos.y - childPos.y), screenPos);
IntPoint2 childPos = hoveredChild->getPosition();
hoveredChild->hoverAll(pos - childPos, screenPos);
}
if(!hovering) hoverEnter(pos, screenPos);
@ -178,20 +192,12 @@ void UIElement::hoverExitAll() {
hoverExit();
}
bool UIElement::clickAll(UIPoint pos, UIPoint screenPos, GLFWMouseButton button) {
UIElement *clickedChild = nullptr;
for(UIElement *child : children) {
UIPoint childPos = child->getPosition();
int relX = pos.x - childPos.x;
int relY = pos.y - childPos.y;
UIBounds b = child->getBounds();
if(!b.containsOffset(UIPoint(relX, relY))) continue;
clickedChild = child;
}
bool UIElement::clickAll(IntPoint2 pos, IntPoint2 screenPos, GLFWMouseButton button) {
UIElement *clickedChild = findChildAtRelativePos(this, pos);
if(clickedChild != nullptr) {
UIPoint childPos = clickedChild->getPosition();
if(clickedChild->clickAll(UIPoint(pos.x - childPos.x, pos.y - childPos.y), screenPos, button)) return true;
IntPoint2 childPos = clickedChild->getPosition();
if(clickedChild->clickAll(pos - childPos, screenPos, button)) return true;
}
if(clickable) {
@ -202,20 +208,12 @@ bool UIElement::clickAll(UIPoint pos, UIPoint screenPos, GLFWMouseButton button)
return false;
}
bool UIElement::focusEnterAll(UIPoint pos, UIPoint screenPos) {
UIElement *focusedChild = nullptr;
for(UIElement *child : children) {
UIPoint childPos = child->getPosition();
int relX = pos.x - childPos.x;
int relY = pos.y - childPos.y;
UIBounds b = child->getBounds();
if(!b.containsOffset(UIPoint(relX, relY))) continue;
focusedChild = child;
}
bool UIElement::focusEnterAll(IntPoint2 pos, IntPoint2 screenPos) {
UIElement *focusedChild = findChildAtRelativePos(this, pos);
if(focusedChild != nullptr) {
UIPoint childPos = focusedChild->getPosition();
if(focusedChild->focusEnterAll(UIPoint(pos.x - childPos.x, pos.y - childPos.y), screenPos)) return true;
IntPoint2 childPos = focusedChild->getPosition();
if(focusedChild->focusEnterAll(pos - childPos, screenPos)) return true;
}
if(focusable) {
@ -226,27 +224,19 @@ bool UIElement::focusEnterAll(UIPoint pos, UIPoint screenPos) {
return false;
}
UIElement *UIElement::dragEnterAll(UIPoint pos, UIPoint screenPos) {
UIBounds bounds = getBounds();
if(!bounds.contains(pos)) return nullptr; // Only used by topmost parent UIElement
UIElement *draggedChild = nullptr;
for(UIElement *child : children) {
UIPoint childPos = child->getPosition();
int relX = pos.x - childPos.x;
int relY = pos.y - childPos.y;
UIBounds b = child->getBounds();
if(!b.containsOffset(UIPoint(relX, relY))) continue;
draggedChild = child;
}
UIElement *UIElement::dragEnterAll(IntPoint2 pos, IntPoint2 screenPos) {
UIElement *draggedChild = findChildAtRelativePos(this, pos);
if(draggedChild) {
UIPoint childPos = draggedChild->getPosition();
UIElement *dragged = draggedChild->dragEnterAll(UIPoint(pos.x - childPos.x, pos.y - childPos.y), screenPos);
IntPoint2 childPos = draggedChild->getPosition();
UIElement *dragged = draggedChild->dragEnterAll(pos - childPos, screenPos);
if(dragged) return dragged;
}
if(draggable) return this;
if(draggable) {
// TODO: start drag
return this;
}
return nullptr;
}
@ -304,4 +294,17 @@ void UI::unfocusElement(UIElement *element) {
oldFocus->focusExit();
}
UIElement *UI::findElementAt(IntPoint2 screenPos) {
UIElement *foundElement = nullptr;
for(UIElement *element : kekData.ui->elements) {
UIBounds bounds = element->getScreenBounds();
if(!bounds.contains(screenPos)) continue;
foundElement = element;
}
return foundElement;
}
}

View File

@ -10,6 +10,7 @@
#include "input.h"
#include "internal.h"
#include "internal/ui.h"
#include "pango/pango-engine.h"
#include "ui.h"
#include "unicode.h"
#include "utils.h"
@ -68,7 +69,7 @@ std::string TextElement::getText() {
return text->getText();
}
void TextElement::draw(UIPoint screenPos, glm::mat4 projection) {
void TextElement::draw(IntPoint2 screenPos, glm::mat4 projection) {
switch(textMode) {
case TextMode::BASELINE:
text->getFont()->drawText(text, projection, screenPos.x, screenPos.y, sizePixels, color);
@ -136,7 +137,7 @@ UIBounds RectangleElement::getBounds() {
return offsetUIBounds(uiToScreen(w), uiToScreen(h), origin);
}
void RectangleElement::draw(UIPoint screenPos, glm::mat4 projection) {
void RectangleElement::draw(IntPoint2 screenPos, glm::mat4 projection) {
kekData.ui->rectangleShader->use();
UIBounds offset = getBounds();
@ -170,11 +171,11 @@ UIElementType ButtonElement::getType() {
return UIElementType::BUTTON;
}
void ButtonElement::click(UIPoint pos, UIPoint screenPos, GLFWMouseButton button) {
void ButtonElement::click(IntPoint2 pos, IntPoint2 screenPos, GLFWMouseButton button) {
onClick();
}
void ButtonElement::draw(UIPoint screenPos, glm::mat4 projection) {
void ButtonElement::draw(IntPoint2 screenPos, glm::mat4 projection) {
RectangleElement::color = hovering ? hoverColor : color;
RectangleElement::draw(screenPos, projection);
}
@ -318,7 +319,7 @@ void TextFieldElement::focusExit() {
updateText(Unicode::convertStdToU32(this->text));
}
void TextFieldElement::draw(UIPoint screenPos, glm::mat4 projection) {
void TextFieldElement::draw(IntPoint2 screenPos, glm::mat4 projection) {
RectangleElement::color = focused ? focusColor : color;
RectangleElement::draw(screenPos, projection);
@ -332,7 +333,8 @@ void TextFieldElement::setText(std::string text) {
}
UIWindowTitleBar::UIWindowTitleBar(UIValue height)
: RectangleElement(uiPx(0), uiPx(0), uiPw(1), height) {
: RectangleElement(uiPx(0), uiPx(0), uiPw(1), height),
dragDownPos(0, 0) {
this->color = Colors::GRAY;
this->draggable = true;
@ -354,15 +356,20 @@ UIWindowTitleBar::~UIWindowTitleBar() {
delete closeButton;
}
void UIWindowTitleBar::dragEnter(UIPoint pos, UIPoint screenPos) {
void UIWindowTitleBar::dragEnter(IntPoint2 pos, IntPoint2 screenPos) {
// TODO
std::cout << "Drag start" << std::endl;
this->dragDownPos = pos;
}
void UIWindowTitleBar::drag(UIPoint pos, UIPoint screenPos) {
void UIWindowTitleBar::drag(IntPoint2 pos, IntPoint2 screenPos) {
// TODO
std::cout << "Drag" << std::endl;
this->x = uiPx(screenPos.x + dragDownPos.x);
this->y = uiPx(screenPos.y + dragDownPos.y);
}
void UIWindowTitleBar::dragExit(UIPoint pos, UIPoint screenPos) {
void UIWindowTitleBar::dragExit(IntPoint2 pos, IntPoint2 screenPos) {
// TODO
}
@ -397,7 +404,7 @@ UIBounds UIWindow::getBounds() {
return offsetUIBounds(uiToScreen(w), uiToScreen(h), origin);
}
void UIWindow::draw(UIPoint screenPos, glm::mat4 projection) {
void UIWindow::draw(IntPoint2 screenPos, glm::mat4 projection) {
}
}

View File

@ -28,6 +28,7 @@
#define KEK_LIGHT_DEFAULT_SPECULAR_STRENGTH 0.1f
#define KEK_INVALID_KEY_BINDING_NAME "INVALID"
#define KEK_INVALID_KEY_BINDING_ID -1
#define KEK_INVALID_ID -1u
#define KEK_FONT_RESOLUTION 64
@ -48,3 +49,6 @@
#define KEK_PLAYER_HEIGHT 2
#define KEK_PLAYER_RADIUS 0.5f
#define KEK_PLAYER_EYE_OFFSET (KEK_PLAYER_HEIGHT / 2 - KEK_PLAYER_RADIUS)
#define KEK_UI_MIN_DRAG_DISTANCE 10
#define KEK_UI_MIN_DRAG_DISTANCE_SQUARED (KEK_UI_MIN_DRAG_DISTANCE * KEK_UI_MIN_DRAG_DISTANCE)

View File

@ -3,6 +3,7 @@
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "constants.h"
#include "utils.h"
namespace kek {
@ -45,7 +46,6 @@ typedef GenericCallable<MouseButtonEvent> MouseButtonCallback; // void mouseButt
typedef unsigned int InputListener;
typedef int GLFWKey;
typedef int GLFWKeyState;
typedef unsigned int KeyBinding;
typedef unsigned int KeyboardCapture;
@ -66,6 +66,17 @@ enum class GLFWMouseButton {
MIDDLE = GLFW_MOUSE_BUTTON_MIDDLE
};
enum class GLFWKeyState {
ERROR_INVALID_KEY_BINDING = KEK_INVALID_KEY_BINDING_ID,
PRESSED = GLFW_PRESS,
RELEASED = GLFW_RELEASE
};
enum class GLFWMouseButtonState {
PRESSED = GLFW_PRESS,
RELEASED = GLFW_RELEASE
};
}
namespace kek::Input {
@ -93,6 +104,8 @@ void reassignKeyBinding(KeyBinding mapping, GLFWKey key);
KeyBindingData getKeyBinding(KeyBinding mapping);
GLFWKeyState getKeyState(KeyBinding mapping);
GLFWMouseButtonState getMouseButtonState(GLFWMouseButton mouseButton);
void setCursorMode(GLFWCursorMode mode);
GLFWCursorMode getCursorMode();

View File

@ -3,6 +3,7 @@
#include <map>
#include "../input.h"
#include "ui.h"
namespace kek {
@ -23,6 +24,9 @@ struct InputData {
ActiveKeyboardCapture activeKeyboardCapture;
GLFWCursorMode cursorMode;
bool mouseDown;
IntPoint2 mouseDownPosition;
};
namespace Input {

View File

@ -24,4 +24,34 @@ class MemoryBuffer: public std::streambuf {
}
};
struct IntPoint2 {
int x, y;
IntPoint2(int x, int y)
: x(x),
y(y) {}
IntPoint2() = default;
constexpr IntPoint2 &operator+=(const IntPoint2 &rhs) {
this->x += rhs.x;
this->y += rhs.y;
return *this;
}
constexpr IntPoint2 &operator-=(const IntPoint2 &rhs) {
this->x -= rhs.x;
this->y -= rhs.y;
return *this;
}
constexpr friend IntPoint2 operator+(const IntPoint2 &lhs, const IntPoint2 &rhs) {
return IntPoint2(lhs) += rhs;
}
constexpr friend IntPoint2 operator-(const IntPoint2 &lhs, const IntPoint2 &rhs) {
return IntPoint2(lhs) -= rhs;
}
};
}

View File

@ -5,6 +5,7 @@
#include "fonts.h"
#include "input.h"
#include "types.h"
#define uiPx(val) kek::UIValue(val, kek::UIUnit::PIXELS)
#define uiPw(val) kek::UIValue(val, kek::UIUnit::PARENT_WIDTH)
@ -14,14 +15,6 @@
namespace kek {
struct UIPoint {
int x, y;
UIPoint(int x, int y)
: x(x),
y(y) {}
};
struct UIBounds {
int x, y, w, h;
@ -32,12 +25,12 @@ struct UIBounds {
h(h) {}
// Checks if a point is contained in the bounds
inline bool contains(UIPoint pos) {
inline bool contains(IntPoint2 pos) {
return pos.x > x && pos.y > y && pos.x < x + w && pos.y < y + h;
}
// Checks if an already offset point is contained in the bounds
inline bool containsOffset(UIPoint pos) {
inline bool containsOffset(IntPoint2 pos) {
return pos.x > 0 && pos.y > 0 && pos.x < w && pos.y < h;
}
};
@ -156,16 +149,22 @@ class UIElement {
virtual UIElementType getType() = 0;
// Returns the element's origin position relative to its parent in pixels (not offset by getBounds())
UIPoint getOriginPosition();
IntPoint2 getOriginPosition();
// Returns the element's position relative to its parent in pixels (offset by getBounds())
UIPoint getPosition();
IntPoint2 getPosition();
// Returns the element's origin position on the screen in pixels (not offset by getBounds())
UIPoint getScreenOriginPosition();
IntPoint2 getScreenOriginPosition();
// Returns the element's position on the screen in pixels (offset by getBounds())
UIPoint getScreenPosition();
IntPoint2 getScreenPosition();
// Returns the bounds of the element relative to its origin
virtual UIBounds getBounds() = 0;
// Returns the bounds of the element on the screen
UIBounds getScreenBounds();
std::vector<UIElement *> getChildren();
void addChild(UIElement *child);
@ -178,29 +177,26 @@ class UIElement {
static UIBounds offsetUIBounds(int w, int h, Origin origin);
public:
// Returns the bounds of the element relative to its origin
virtual UIBounds getBounds() = 0;
void drawAll(IntPoint2 screenPos, glm::mat4 projection);
virtual void draw(IntPoint2 screenPos, glm::mat4 projection) = 0;
void drawAll(UIPoint screenPos, glm::mat4 projection);
virtual void draw(UIPoint screenPos, glm::mat4 projection) = 0;
void hoverAll(UIPoint pos, UIPoint screenPos);
void hoverAll(IntPoint2 pos, IntPoint2 screenPos);
void hoverExitAll();
virtual void hoverEnter(UIPoint pos, UIPoint screenPos){};
virtual void hover(UIPoint pos, UIPoint screenPos){};
virtual void hoverEnter(IntPoint2 pos, IntPoint2 screenPos){};
virtual void hover(IntPoint2 pos, IntPoint2 screenPos){};
virtual void hoverExit(){};
bool clickAll(UIPoint pos, UIPoint screenPos, GLFWMouseButton button);
virtual void click(UIPoint pos, UIPoint screenPos, GLFWMouseButton button){};
bool clickAll(IntPoint2 pos, IntPoint2 screenPos, GLFWMouseButton button);
virtual void click(IntPoint2 pos, IntPoint2 screenPos, GLFWMouseButton button){};
bool focusEnterAll(UIPoint pos, UIPoint screenPos);
bool focusEnterAll(IntPoint2 pos, IntPoint2 screenPos);
virtual void focusEnter(){};
virtual void focusExit(){};
UIElement *dragEnterAll(UIPoint pos, UIPoint screenPos);
virtual void dragEnter(UIPoint pos, UIPoint screenPos){};
virtual void drag(UIPoint pos, UIPoint screenPos){};
virtual void dragExit(UIPoint pos, UIPoint screenPos){};
UIElement *dragEnterAll(IntPoint2 pos, IntPoint2 screenPos);
virtual void dragEnter(IntPoint2 pos, IntPoint2 screenPos){};
virtual void drag(IntPoint2 pos, IntPoint2 screenPos){};
virtual void dragExit(IntPoint2 pos, IntPoint2 screenPos){};
};
namespace UI {
@ -215,6 +211,9 @@ void removeElement(UIElement *element);
void focusElement(UIElement *element);
void unfocusElement(UIElement *element);
// Finds the first (topmost) element at the given screen position
UIElement *findElementAt(IntPoint2 screenPos);
};
}

View File

@ -42,7 +42,7 @@ class TextElement: public UIElement {
std::string getText();
virtual void draw(UIPoint screenPos, glm::mat4 projection);
virtual void draw(IntPoint2 screenPos, glm::mat4 projection);
};
class RectangleElement: public UIElement {
@ -64,7 +64,7 @@ class RectangleElement: public UIElement {
virtual UIBounds getBounds();
virtual void draw(UIPoint screenPos, glm::mat4 projection);
virtual void draw(IntPoint2 screenPos, glm::mat4 projection);
};
class ButtonElement: public RectangleElement {
@ -81,9 +81,9 @@ class ButtonElement: public RectangleElement {
virtual UIElementType getType();
virtual void click(UIPoint pos, UIPoint screenPos, GLFWMouseButton button);
virtual void click(IntPoint2 pos, IntPoint2 screenPos, GLFWMouseButton button);
virtual void draw(UIPoint screenPos, glm::mat4 projection);
virtual void draw(IntPoint2 screenPos, glm::mat4 projection);
};
typedef GenericCallable<std::string> SubmitCallback;
@ -119,13 +119,16 @@ class TextFieldElement: public RectangleElement {
virtual void focusEnter();
virtual void focusExit();
virtual void draw(UIPoint screenPos, glm::mat4 projection);
virtual void draw(IntPoint2 screenPos, glm::mat4 projection);
void setText(std::string text);
};
class UIWindowTitleBar: public RectangleElement {
protected:
IntPoint2 dragDownPos;
public:
TextElement *text;
ButtonElement *closeButton;
@ -134,9 +137,9 @@ class UIWindowTitleBar: public RectangleElement {
virtual ~UIWindowTitleBar();
virtual void dragEnter(UIPoint pos, UIPoint screenPos);
virtual void drag(UIPoint pos, UIPoint screenPos);
virtual void dragExit(UIPoint pos, UIPoint screenPos);
virtual void dragEnter(IntPoint2 pos, IntPoint2 screenPos);
virtual void drag(IntPoint2 pos, IntPoint2 screenPos);
virtual void dragExit(IntPoint2 pos, IntPoint2 screenPos);
};
class UIWindow: public UIElement {
@ -155,7 +158,7 @@ class UIWindow: public UIElement {
virtual UIBounds getBounds();
virtual void draw(UIPoint screenPos, glm::mat4 projection);
virtual void draw(IntPoint2 screenPos, glm::mat4 projection);
};
}