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

View File

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

View File

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

View File

@ -105,23 +105,23 @@ void DefaultPlayerController::update() {
glm::vec3 direction = glm::vec3(0); glm::vec3 direction = glm::vec3(0);
if(!Input::isKeyboardCaptured()) { if(!Input::isKeyboardCaptured()) {
if(Input::getKeyState(keyForward) == GLFW_PRESS) { if(Input::getKeyState(keyForward) == GLFWKeyState::PRESSED) {
direction += kekData.activeCamera->direction; direction += kekData.activeCamera->direction;
} }
if(Input::getKeyState(keyBackward) == GLFW_PRESS) { if(Input::getKeyState(keyBackward) == GLFWKeyState::PRESSED) {
direction += -kekData.activeCamera->direction; 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))); 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))); 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); velocity += glm::vec3(0, jumpVelocity, 0);
} }

View File

@ -21,27 +21,27 @@ void NoclipPlayerController::update() {
glm::vec3 direction = glm::vec3(0); glm::vec3 direction = glm::vec3(0);
if(Input::getKeyState(keyForward) == GLFW_PRESS) { if(Input::getKeyState(keyForward) == GLFWKeyState::PRESSED) {
direction += kekData.activeCamera->direction; direction += kekData.activeCamera->direction;
} }
if(Input::getKeyState(keyBackward) == GLFW_PRESS) { if(Input::getKeyState(keyBackward) == GLFWKeyState::PRESSED) {
direction += -kekData.activeCamera->direction; 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))); 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))); 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); direction += glm::vec3(0, 1, 0);
} }
if(Input::getKeyState(keyDown) == GLFW_PRESS) { if(Input::getKeyState(keyDown) == GLFWKeyState::PRESSED) {
direction += glm::vec3(0, -1, 0); direction += glm::vec3(0, -1, 0);
} }

View File

@ -8,6 +8,7 @@
#include "input.h" #include "input.h"
#include "internal.h" #include "internal.h"
#include "internal/ui.h" #include "internal/ui.h"
#include "types.h"
namespace kek { namespace kek {
@ -21,21 +22,21 @@ UIElement::~UIElement() {
} }
// Returns the element's origin position relative to its parent in pixels (not offset by getBounds()) // Returns the element's origin position relative to its parent in pixels (not offset by getBounds())
UIPoint UIElement::getOriginPosition() { IntPoint2 UIElement::getOriginPosition() {
return UIPoint(uiToScreen(x), uiToScreen(y)); return IntPoint2(uiToScreen(x), uiToScreen(y));
} }
// Returns the element's position relative to its parent in pixels (offset by getBounds()) // Returns the element's position relative to its parent in pixels (offset by getBounds(), aka. the position of the top-left of the element)
UIPoint UIElement::getPosition() { IntPoint2 UIElement::getPosition() {
UIBounds bounds = getBounds(); 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()) // Returns the element's origin position on the screen in pixels (not offset by getBounds())
UIPoint UIElement::getScreenOriginPosition() { IntPoint2 UIElement::getScreenOriginPosition() {
UIPoint pos = getOriginPosition(); IntPoint2 pos = getOriginPosition();
if(parent) { if(parent) {
UIPoint parentPos = parent->getScreenPosition(); IntPoint2 parentPos = parent->getScreenPosition();
pos.x += parentPos.x; pos.x += parentPos.x;
pos.y += parentPos.y; pos.y += parentPos.y;
} }
@ -43,11 +44,18 @@ UIPoint UIElement::getScreenOriginPosition() {
return pos; return pos;
} }
// Returns the element's position on the screen in pixels (offset by getBounds()) // Returns the element's position on the screen in pixels (offset by getBounds(), aka. the position of the top-left of the element)
UIPoint UIElement::getScreenPosition() { IntPoint2 UIElement::getScreenPosition() {
UIPoint pos = getScreenOriginPosition(); IntPoint2 pos = getScreenOriginPosition();
UIBounds bounds = getBounds(); 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() { 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); 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; if(!visible) return;
UIBounds bounds = getBounds(); UIBounds bounds = getBounds();
@ -135,8 +143,8 @@ void UIElement::drawAll(UIPoint screenPos, glm::mat4 projection) {
draw(screenPos, projection); draw(screenPos, projection);
for(UIElement *child : children) { for(UIElement *child : children) {
UIPoint pos = child->getPosition(); IntPoint2 pos = child->getPosition();
child->drawAll(UIPoint(screenPos.x + pos.x, screenPos.y + pos.y), projection); child->drawAll(IntPoint2(screenPos.x + pos.x, screenPos.y + pos.y), projection);
} }
if(enableClipping) { if(enableClipping) {
@ -144,24 +152,30 @@ void UIElement::drawAll(UIPoint screenPos, glm::mat4 projection) {
} }
} }
void UIElement::hoverAll(UIPoint pos, UIPoint screenPos) { static UIElement *findChildAtRelativePos(UIElement *element, IntPoint2 pos) {
UIElement *hoveredChild = nullptr; UIElement *foundChild = nullptr;
for(UIElement *child : children) {
UIPoint childPos = child->getPosition(); for(UIElement *child : element->getChildren()) {
int relX = pos.x - childPos.x; IntPoint2 childPos = child->getPosition();
int relY = pos.y - childPos.y; IntPoint2 relativeChildPos = pos - childPos;
UIBounds b = child->getBounds(); UIBounds b = child->getBounds();
if(!b.containsOffset(UIPoint(relX, relY))) continue; if(!b.containsOffset(relativeChildPos)) continue;
hoveredChild = child; foundChild = child;
} }
return foundChild;
}
void UIElement::hoverAll(IntPoint2 pos, IntPoint2 screenPos) {
UIElement *hoveredChild = findChildAtRelativePos(this, pos);
for(UIElement *child : children) { for(UIElement *child : children) {
if(child != hoveredChild && child->hovering) child->hoverExitAll(); if(child != hoveredChild && child->hovering) child->hoverExitAll();
} }
if(hoveredChild) { if(hoveredChild) {
UIPoint childPos = hoveredChild->getPosition(); IntPoint2 childPos = hoveredChild->getPosition();
hoveredChild->hoverAll(UIPoint(pos.x - childPos.x, pos.y - childPos.y), screenPos); hoveredChild->hoverAll(pos - childPos, screenPos);
} }
if(!hovering) hoverEnter(pos, screenPos); if(!hovering) hoverEnter(pos, screenPos);
@ -178,20 +192,12 @@ void UIElement::hoverExitAll() {
hoverExit(); hoverExit();
} }
bool UIElement::clickAll(UIPoint pos, UIPoint screenPos, GLFWMouseButton button) { bool UIElement::clickAll(IntPoint2 pos, IntPoint2 screenPos, GLFWMouseButton button) {
UIElement *clickedChild = nullptr; UIElement *clickedChild = findChildAtRelativePos(this, pos);
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;
}
if(clickedChild != nullptr) { if(clickedChild != nullptr) {
UIPoint childPos = clickedChild->getPosition(); IntPoint2 childPos = clickedChild->getPosition();
if(clickedChild->clickAll(UIPoint(pos.x - childPos.x, pos.y - childPos.y), screenPos, button)) return true; if(clickedChild->clickAll(pos - childPos, screenPos, button)) return true;
} }
if(clickable) { if(clickable) {
@ -202,20 +208,12 @@ bool UIElement::clickAll(UIPoint pos, UIPoint screenPos, GLFWMouseButton button)
return false; return false;
} }
bool UIElement::focusEnterAll(UIPoint pos, UIPoint screenPos) { bool UIElement::focusEnterAll(IntPoint2 pos, IntPoint2 screenPos) {
UIElement *focusedChild = nullptr; UIElement *focusedChild = findChildAtRelativePos(this, pos);
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;
}
if(focusedChild != nullptr) { if(focusedChild != nullptr) {
UIPoint childPos = focusedChild->getPosition(); IntPoint2 childPos = focusedChild->getPosition();
if(focusedChild->focusEnterAll(UIPoint(pos.x - childPos.x, pos.y - childPos.y), screenPos)) return true; if(focusedChild->focusEnterAll(pos - childPos, screenPos)) return true;
} }
if(focusable) { if(focusable) {
@ -226,27 +224,19 @@ bool UIElement::focusEnterAll(UIPoint pos, UIPoint screenPos) {
return false; return false;
} }
UIElement *UIElement::dragEnterAll(UIPoint pos, UIPoint screenPos) { UIElement *UIElement::dragEnterAll(IntPoint2 pos, IntPoint2 screenPos) {
UIBounds bounds = getBounds(); UIElement *draggedChild = findChildAtRelativePos(this, pos);
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;
}
if(draggedChild) { if(draggedChild) {
UIPoint childPos = draggedChild->getPosition(); IntPoint2 childPos = draggedChild->getPosition();
UIElement *dragged = draggedChild->dragEnterAll(UIPoint(pos.x - childPos.x, pos.y - childPos.y), screenPos); UIElement *dragged = draggedChild->dragEnterAll(pos - childPos, screenPos);
if(dragged) return dragged; if(dragged) return dragged;
} }
if(draggable) return this; if(draggable) {
// TODO: start drag
return this;
}
return nullptr; return nullptr;
} }
@ -304,4 +294,17 @@ void UI::unfocusElement(UIElement *element) {
oldFocus->focusExit(); 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 "input.h"
#include "internal.h" #include "internal.h"
#include "internal/ui.h" #include "internal/ui.h"
#include "pango/pango-engine.h"
#include "ui.h" #include "ui.h"
#include "unicode.h" #include "unicode.h"
#include "utils.h" #include "utils.h"
@ -68,7 +69,7 @@ std::string TextElement::getText() {
return text->getText(); return text->getText();
} }
void TextElement::draw(UIPoint screenPos, glm::mat4 projection) { void TextElement::draw(IntPoint2 screenPos, glm::mat4 projection) {
switch(textMode) { switch(textMode) {
case TextMode::BASELINE: case TextMode::BASELINE:
text->getFont()->drawText(text, projection, screenPos.x, screenPos.y, sizePixels, color); 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); 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(); kekData.ui->rectangleShader->use();
UIBounds offset = getBounds(); UIBounds offset = getBounds();
@ -170,11 +171,11 @@ UIElementType ButtonElement::getType() {
return UIElementType::BUTTON; return UIElementType::BUTTON;
} }
void ButtonElement::click(UIPoint pos, UIPoint screenPos, GLFWMouseButton button) { void ButtonElement::click(IntPoint2 pos, IntPoint2 screenPos, GLFWMouseButton button) {
onClick(); onClick();
} }
void ButtonElement::draw(UIPoint screenPos, glm::mat4 projection) { void ButtonElement::draw(IntPoint2 screenPos, glm::mat4 projection) {
RectangleElement::color = hovering ? hoverColor : color; RectangleElement::color = hovering ? hoverColor : color;
RectangleElement::draw(screenPos, projection); RectangleElement::draw(screenPos, projection);
} }
@ -318,7 +319,7 @@ void TextFieldElement::focusExit() {
updateText(Unicode::convertStdToU32(this->text)); 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::color = focused ? focusColor : color;
RectangleElement::draw(screenPos, projection); RectangleElement::draw(screenPos, projection);
@ -332,7 +333,8 @@ void TextFieldElement::setText(std::string text) {
} }
UIWindowTitleBar::UIWindowTitleBar(UIValue height) 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->color = Colors::GRAY;
this->draggable = true; this->draggable = true;
@ -354,15 +356,20 @@ UIWindowTitleBar::~UIWindowTitleBar() {
delete closeButton; delete closeButton;
} }
void UIWindowTitleBar::dragEnter(UIPoint pos, UIPoint screenPos) { void UIWindowTitleBar::dragEnter(IntPoint2 pos, IntPoint2 screenPos) {
// TODO // 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 // 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 // TODO
} }
@ -397,7 +404,7 @@ UIBounds UIWindow::getBounds() {
return offsetUIBounds(uiToScreen(w), uiToScreen(h), origin); 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_LIGHT_DEFAULT_SPECULAR_STRENGTH 0.1f
#define KEK_INVALID_KEY_BINDING_NAME "INVALID" #define KEK_INVALID_KEY_BINDING_NAME "INVALID"
#define KEK_INVALID_KEY_BINDING_ID -1
#define KEK_INVALID_ID -1u #define KEK_INVALID_ID -1u
#define KEK_FONT_RESOLUTION 64 #define KEK_FONT_RESOLUTION 64
@ -48,3 +49,6 @@
#define KEK_PLAYER_HEIGHT 2 #define KEK_PLAYER_HEIGHT 2
#define KEK_PLAYER_RADIUS 0.5f #define KEK_PLAYER_RADIUS 0.5f
#define KEK_PLAYER_EYE_OFFSET (KEK_PLAYER_HEIGHT / 2 - KEK_PLAYER_RADIUS) #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 <GL/glew.h>
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#include "constants.h"
#include "utils.h" #include "utils.h"
namespace kek { namespace kek {
@ -45,7 +46,6 @@ typedef GenericCallable<MouseButtonEvent> MouseButtonCallback; // void mouseButt
typedef unsigned int InputListener; typedef unsigned int InputListener;
typedef int GLFWKey; typedef int GLFWKey;
typedef int GLFWKeyState;
typedef unsigned int KeyBinding; typedef unsigned int KeyBinding;
typedef unsigned int KeyboardCapture; typedef unsigned int KeyboardCapture;
@ -66,6 +66,17 @@ enum class GLFWMouseButton {
MIDDLE = GLFW_MOUSE_BUTTON_MIDDLE 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 { namespace kek::Input {
@ -93,6 +104,8 @@ void reassignKeyBinding(KeyBinding mapping, GLFWKey key);
KeyBindingData getKeyBinding(KeyBinding mapping); KeyBindingData getKeyBinding(KeyBinding mapping);
GLFWKeyState getKeyState(KeyBinding mapping); GLFWKeyState getKeyState(KeyBinding mapping);
GLFWMouseButtonState getMouseButtonState(GLFWMouseButton mouseButton);
void setCursorMode(GLFWCursorMode mode); void setCursorMode(GLFWCursorMode mode);
GLFWCursorMode getCursorMode(); GLFWCursorMode getCursorMode();

View File

@ -3,6 +3,7 @@
#include <map> #include <map>
#include "../input.h" #include "../input.h"
#include "ui.h"
namespace kek { namespace kek {
@ -23,6 +24,9 @@ struct InputData {
ActiveKeyboardCapture activeKeyboardCapture; ActiveKeyboardCapture activeKeyboardCapture;
GLFWCursorMode cursorMode; GLFWCursorMode cursorMode;
bool mouseDown;
IntPoint2 mouseDownPosition;
}; };
namespace Input { 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 "fonts.h"
#include "input.h" #include "input.h"
#include "types.h"
#define uiPx(val) kek::UIValue(val, kek::UIUnit::PIXELS) #define uiPx(val) kek::UIValue(val, kek::UIUnit::PIXELS)
#define uiPw(val) kek::UIValue(val, kek::UIUnit::PARENT_WIDTH) #define uiPw(val) kek::UIValue(val, kek::UIUnit::PARENT_WIDTH)
@ -14,14 +15,6 @@
namespace kek { namespace kek {
struct UIPoint {
int x, y;
UIPoint(int x, int y)
: x(x),
y(y) {}
};
struct UIBounds { struct UIBounds {
int x, y, w, h; int x, y, w, h;
@ -32,12 +25,12 @@ struct UIBounds {
h(h) {} h(h) {}
// Checks if a point is contained in the bounds // 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; 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 // 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; return pos.x > 0 && pos.y > 0 && pos.x < w && pos.y < h;
} }
}; };
@ -156,16 +149,22 @@ class UIElement {
virtual UIElementType getType() = 0; virtual UIElementType getType() = 0;
// Returns the element's origin position relative to its parent in pixels (not offset by getBounds()) // 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()) // 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()) // 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()) // 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(); std::vector<UIElement *> getChildren();
void addChild(UIElement *child); void addChild(UIElement *child);
@ -178,29 +177,26 @@ class UIElement {
static UIBounds offsetUIBounds(int w, int h, Origin origin); static UIBounds offsetUIBounds(int w, int h, Origin origin);
public: public:
// Returns the bounds of the element relative to its origin void drawAll(IntPoint2 screenPos, glm::mat4 projection);
virtual UIBounds getBounds() = 0; virtual void draw(IntPoint2 screenPos, glm::mat4 projection) = 0;
void drawAll(UIPoint screenPos, glm::mat4 projection); void hoverAll(IntPoint2 pos, IntPoint2 screenPos);
virtual void draw(UIPoint screenPos, glm::mat4 projection) = 0;
void hoverAll(UIPoint pos, UIPoint screenPos);
void hoverExitAll(); void hoverExitAll();
virtual void hoverEnter(UIPoint pos, UIPoint screenPos){}; virtual void hoverEnter(IntPoint2 pos, IntPoint2 screenPos){};
virtual void hover(UIPoint pos, UIPoint screenPos){}; virtual void hover(IntPoint2 pos, IntPoint2 screenPos){};
virtual void hoverExit(){}; virtual void hoverExit(){};
bool clickAll(UIPoint pos, UIPoint screenPos, GLFWMouseButton button); bool clickAll(IntPoint2 pos, IntPoint2 screenPos, GLFWMouseButton button);
virtual void click(UIPoint pos, UIPoint 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 focusEnter(){};
virtual void focusExit(){}; virtual void focusExit(){};
UIElement *dragEnterAll(UIPoint pos, UIPoint screenPos); UIElement *dragEnterAll(IntPoint2 pos, IntPoint2 screenPos);
virtual void dragEnter(UIPoint pos, UIPoint screenPos){}; virtual void dragEnter(IntPoint2 pos, IntPoint2 screenPos){};
virtual void drag(UIPoint pos, UIPoint screenPos){}; virtual void drag(IntPoint2 pos, IntPoint2 screenPos){};
virtual void dragExit(UIPoint pos, UIPoint screenPos){}; virtual void dragExit(IntPoint2 pos, IntPoint2 screenPos){};
}; };
namespace UI { namespace UI {
@ -215,6 +211,9 @@ void removeElement(UIElement *element);
void focusElement(UIElement *element); void focusElement(UIElement *element);
void unfocusElement(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(); std::string getText();
virtual void draw(UIPoint screenPos, glm::mat4 projection); virtual void draw(IntPoint2 screenPos, glm::mat4 projection);
}; };
class RectangleElement: public UIElement { class RectangleElement: public UIElement {
@ -64,7 +64,7 @@ class RectangleElement: public UIElement {
virtual UIBounds getBounds(); virtual UIBounds getBounds();
virtual void draw(UIPoint screenPos, glm::mat4 projection); virtual void draw(IntPoint2 screenPos, glm::mat4 projection);
}; };
class ButtonElement: public RectangleElement { class ButtonElement: public RectangleElement {
@ -81,9 +81,9 @@ class ButtonElement: public RectangleElement {
virtual UIElementType getType(); 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; typedef GenericCallable<std::string> SubmitCallback;
@ -119,13 +119,16 @@ class TextFieldElement: public RectangleElement {
virtual void focusEnter(); virtual void focusEnter();
virtual void focusExit(); virtual void focusExit();
virtual void draw(UIPoint screenPos, glm::mat4 projection); virtual void draw(IntPoint2 screenPos, glm::mat4 projection);
void setText(std::string text); void setText(std::string text);
}; };
class UIWindowTitleBar: public RectangleElement { class UIWindowTitleBar: public RectangleElement {
protected:
IntPoint2 dragDownPos;
public: public:
TextElement *text; TextElement *text;
ButtonElement *closeButton; ButtonElement *closeButton;
@ -134,9 +137,9 @@ class UIWindowTitleBar: public RectangleElement {
virtual ~UIWindowTitleBar(); virtual ~UIWindowTitleBar();
virtual void dragEnter(UIPoint pos, UIPoint screenPos); virtual void dragEnter(IntPoint2 pos, IntPoint2 screenPos);
virtual void drag(UIPoint pos, UIPoint screenPos); virtual void drag(IntPoint2 pos, IntPoint2 screenPos);
virtual void dragExit(UIPoint pos, UIPoint screenPos); virtual void dragExit(IntPoint2 pos, IntPoint2 screenPos);
}; };
class UIWindow: public UIElement { class UIWindow: public UIElement {
@ -155,7 +158,7 @@ class UIWindow: public UIElement {
virtual UIBounds getBounds(); virtual UIBounds getBounds();
virtual void draw(UIPoint screenPos, glm::mat4 projection); virtual void draw(IntPoint2 screenPos, glm::mat4 projection);
}; };
} }