diff --git a/src/kekengine/cpp/common/defaults.cpp b/src/kekengine/cpp/common/defaults.cpp index ad8292f..f03440b 100644 --- a/src/kekengine/cpp/common/defaults.cpp +++ b/src/kekengine/cpp/common/defaults.cpp @@ -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 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 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; +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) { + 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; } } diff --git a/src/kekengine/cpp/common/engine.cpp b/src/kekengine/cpp/common/engine.cpp index b6ff748..4f49433 100644 --- a/src/kekengine/cpp/common/engine.cpp +++ b/src/kekengine/cpp/common/engine.cpp @@ -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); } diff --git a/src/kekengine/cpp/input/input.cpp b/src/kekengine/cpp/input/input.cpp index 3c67ed6..1f1deaf 100644 --- a/src/kekengine/cpp/input/input.cpp +++ b/src/kekengine/cpp/input/input.cpp @@ -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) { diff --git a/src/kekengine/cpp/player/defaultplayercontroller.cpp b/src/kekengine/cpp/player/defaultplayercontroller.cpp index fb05bb3..8d218cf 100644 --- a/src/kekengine/cpp/player/defaultplayercontroller.cpp +++ b/src/kekengine/cpp/player/defaultplayercontroller.cpp @@ -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); } diff --git a/src/kekengine/cpp/player/noclipplayercontroller.cpp b/src/kekengine/cpp/player/noclipplayercontroller.cpp index 445ac0b..3644021 100644 --- a/src/kekengine/cpp/player/noclipplayercontroller.cpp +++ b/src/kekengine/cpp/player/noclipplayercontroller.cpp @@ -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); } diff --git a/src/kekengine/cpp/ui/ui.cpp b/src/kekengine/cpp/ui/ui.cpp index 095cba0..e9eeec8 100644 --- a/src/kekengine/cpp/ui/ui.cpp +++ b/src/kekengine/cpp/ui/ui.cpp @@ -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::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; +} + } diff --git a/src/kekengine/cpp/ui/uielements.cpp b/src/kekengine/cpp/ui/uielements.cpp index 08fbdc5..4e3f0d1 100644 --- a/src/kekengine/cpp/ui/uielements.cpp +++ b/src/kekengine/cpp/ui/uielements.cpp @@ -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) { } } diff --git a/src/kekengine/include/constants.h b/src/kekengine/include/constants.h index 0eee88b..ae36e11 100644 --- a/src/kekengine/include/constants.h +++ b/src/kekengine/include/constants.h @@ -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) diff --git a/src/kekengine/include/input.h b/src/kekengine/include/input.h index c2e5aa3..9efbbb5 100644 --- a/src/kekengine/include/input.h +++ b/src/kekengine/include/input.h @@ -3,6 +3,7 @@ #include #include +#include "constants.h" #include "utils.h" namespace kek { @@ -45,7 +46,6 @@ typedef GenericCallable 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(); diff --git a/src/kekengine/include/internal/input.h b/src/kekengine/include/internal/input.h index a3b9c3d..e8fe705 100644 --- a/src/kekengine/include/internal/input.h +++ b/src/kekengine/include/internal/input.h @@ -3,6 +3,7 @@ #include #include "../input.h" +#include "ui.h" namespace kek { @@ -23,6 +24,9 @@ struct InputData { ActiveKeyboardCapture activeKeyboardCapture; GLFWCursorMode cursorMode; + + bool mouseDown; + IntPoint2 mouseDownPosition; }; namespace Input { diff --git a/src/kekengine/include/types.h b/src/kekengine/include/types.h index 86fe244..dc1108f 100644 --- a/src/kekengine/include/types.h +++ b/src/kekengine/include/types.h @@ -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; + } +}; + } diff --git a/src/kekengine/include/ui.h b/src/kekengine/include/ui.h index 5d869b4..37c5a07 100644 --- a/src/kekengine/include/ui.h +++ b/src/kekengine/include/ui.h @@ -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 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); + }; } diff --git a/src/kekengine/include/uielements.h b/src/kekengine/include/uielements.h index fae0961..3c945aa 100644 --- a/src/kekengine/include/uielements.h +++ b/src/kekengine/include/uielements.h @@ -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 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); }; }