diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..b7c077b --- /dev/null +++ b/.clang-format @@ -0,0 +1,29 @@ +Language: Cpp +BasedOnStyle: LLVM +IndentWidth: 4 +UseTab: Always +TabWidth: 4 +ColumnLimit: 0 +IndentCaseLabels: true +AllowShortIfStatementsOnASingleLine: true +FixNamespaceComments: false +SpaceBeforeParens: Never +SpaceAfterCStyleCast: true +SeparateDefinitionBlocks: Always +PackConstructorInitializers: Never +IncludeBlocks: Preserve +SpaceBeforeInheritanceColon: false +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignTrailingComments: false +AlignOperands: false +AlignEscapedNewlines: false +AlignConsecutiveMacros: false +AllowShortCaseLabelsOnASingleLine: false +SpaceBeforeCtorInitializerColon: false +SpaceBeforeAssignmentOperators: true +AllowShortLoopsOnASingleLine: true +AlignAfterOpenBracket: DontAlign +LambdaBodyIndentation: Signature +LineEnding: LF +ContinuationIndentWidth: 4 diff --git a/.clangd b/.clangd new file mode 100644 index 0000000..359a391 --- /dev/null +++ b/.clangd @@ -0,0 +1,2 @@ +CompileFlags: + Add: [-std=c++20] diff --git a/CMakeLists.txt b/CMakeLists.txt index f9cf196..dbdf0f0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,9 +37,9 @@ file(GLOB_RECURSE KEKGAME_RELATIVE_RESOURCE_FILES RELATIVE ${KEKGAME_RESOURCE_DI add_compile_definitions(FT_CONFIG_OPTION_ERROR_STRINGS) # Freetype error strings if(${KEKENGINE_DEBUG}) - add_compile_options(-Wall -g) + add_compile_options(-Wall -std=c++20 -g) else() - add_compile_options(-Wall -O3) + add_compile_options(-Wall -std=c++20 -O3) endif() block() diff --git a/src/kekengine/cpp/common/defaults.cpp b/src/kekengine/cpp/common/defaults.cpp index 6df00bb..9835e68 100644 --- a/src/kekengine/cpp/common/defaults.cpp +++ b/src/kekengine/cpp/common/defaults.cpp @@ -20,10 +20,7 @@ static KeyBinding static ButtonElement *options; -static void defaultInput(GLFWwindow *window, void *data) { - if(Input::isKeyboardCaptured()) return; - - // TODO: move input handling to controller class, add NoclipController +static void defaultPeriodic(PeriodicEvent event, void *data) { kekData.player->controller->update(); } @@ -55,6 +52,7 @@ static void doUIMouseHover(double x, double y) { static void doUIMouseClick(double x, double y, GLFWMouseButton button) { UIElement *clickedElement = nullptr; + UIElement *focusedElement = nullptr; for(UIElement *element : kekData.ui->elements) { UIPoint childPos = element->getPosition(); @@ -63,34 +61,41 @@ static void doUIMouseClick(double x, double y, GLFWMouseButton button) { UIBounds bounds = element->getBounds(); if(!bounds.contains(clickedAt)) continue; - clickedElement = element; + if(element->clickable) clickedElement = element; + if(element->focusable) focusedElement = element; } if(clickedElement) { - /*if(clickedElement != kekData.ui->focusedElement) { // TODO: check for focusable on children etc - if(kekData.ui->focusedElement != nullptr) { - kekData.ui->focusedElement->focusExit(); - } - - clickedElement->focusEnter(); - }*/ - UIPoint childPos = clickedElement->getPosition(); UIPoint clickedAt = UIPoint((int) x - childPos.x, (int) y - childPos.y); clickedElement->clickAll(clickedAt, UIPoint((int) x, (int) y), button); } + + if(button == GLFWMouseButton::LEFT && focusedElement != kekData.ui->focusedElement) { + if(kekData.ui->focusedElement != nullptr) { + kekData.ui->focusedElement->focusExit(); + } + + if(focusedElement) { + UIPoint childPos = focusedElement->getPosition(); + UIPoint clickedAt = UIPoint((int) x - childPos.x, (int) y - childPos.y); + focusedElement->focusEnterAll(clickedAt, UIPoint((int) x, (int) y)); + } + + kekData.ui->focusedElement = focusedElement; + } } -static void defaultKeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods, void *data) { - if(key == Input::getKeyBinding(keyExit).key && action == GLFW_PRESS) { - glfwSetWindowShouldClose(window, true); +static void defaultKeyCallback(KeyEvent event, void *data) { + if(event.key == Input::getKeyBinding(keyExit).key && event.action == GLFW_PRESS) { + glfwSetWindowShouldClose(event.window, true); } - if(key == Input::getKeyBinding(keyOptions).key && action == GLFW_PRESS) { + if(event.key == Input::getKeyBinding(keyOptions).key && event.action == GLFW_PRESS) { options->visible = !options->visible; } - if(key == Input::getKeyBinding(keyToggleCursorMode).key && action == GLFW_PRESS) { + if(event.key == Input::getKeyBinding(keyToggleCursorMode).key && event.action == GLFW_PRESS) { if(Input::getCursorMode() == GLFWCursorMode::CAPTURE) { Input::setCursorMode(GLFWCursorMode::FREE); double x, y; @@ -105,7 +110,7 @@ static void defaultKeyCallback(GLFWwindow *window, int key, int scancode, int ac } } - if(key == Input::getKeyBinding(keyToggleNoclip).key && action == GLFW_PRESS) { + if(event.key == Input::getKeyBinding(keyToggleNoclip).key && event.action == GLFW_PRESS) { kekData.player->noclip = !kekData.player->noclip; kekData.player->controller = kekData.player->noclip ? (PlayerController *) noclipController : (PlayerController *) defaultController; if(kekData.player->noclip) { @@ -116,19 +121,19 @@ static void defaultKeyCallback(GLFWwindow *window, int key, int scancode, int ac } } -static void defaultMouseCallback(GLFWwindow *window, double x, double y, void *data) { +static void defaultMouseCallback(MouseEvent event, void *data) { static bool firstMouse = true; static double lastX = 0, lastY = 0; if(firstMouse) { - lastX = x; - lastY = y; + lastX = event.x; + lastY = event.y; firstMouse = false; } switch(Input::getCursorMode()) { case GLFWCursorMode::CAPTURE: { - float xoff = lastX - x; - float yoff = lastY - y; + float xoff = lastX - event.x; + float yoff = lastY - event.y; xoff *= 0.1f; yoff *= 0.1f; @@ -139,16 +144,16 @@ static void defaultMouseCallback(GLFWwindow *window, double x, double y, void *d } case GLFWCursorMode::FREE: case GLFWCursorMode::HIDDEN: { - doUIMouseHover(x, y); + doUIMouseHover(event.x, event.y); break; } } - lastX = x; - lastY = y; + lastX = event.x; + lastY = event.y; } -static void defaultMouseButtonCallback(GLFWwindow *window, int button, int action, int mods, void *data) { +static void defaultMouseButtonCallback(MouseButtonEvent event, void *data) { switch(Input::getCursorMode()) { case GLFWCursorMode::CAPTURE: { // TODO @@ -156,13 +161,13 @@ static void defaultMouseButtonCallback(GLFWwindow *window, int button, int actio } case GLFWCursorMode::FREE: case GLFWCursorMode::HIDDEN: { - switch(action) { + switch(event.action) { case GLFW_PRESS: break; case GLFW_RELEASE: { double x, y; - glfwGetCursorPos(window, &x, &y); - doUIMouseClick(x, y, (GLFWMouseButton) button); + glfwGetCursorPos(event.window, &x, &y); + doUIMouseClick(x, y, (GLFWMouseButton) event.button); } } @@ -185,7 +190,7 @@ void init() { keyToggleNoclip = Input::createKeyBinding("Toggle Noclip", GLFW_KEY_N); keyExit = Input::createKeyBinding("Exit", GLFW_KEY_ESCAPE); - Input::addPeriodicCallback(PeriodicCallback(defaultInput, nullptr)); + Input::addPeriodicCallback(PeriodicCallback(defaultPeriodic, nullptr)); Input::addKeyListener(KeyCallback(defaultKeyCallback, nullptr)); Input::addMouseListener(MouseCallback(defaultMouseCallback, nullptr)); Input::addMouseButtonListener(MouseButtonCallback(defaultMouseButtonCallback, nullptr)); diff --git a/src/kekengine/cpp/common/engine.cpp b/src/kekengine/cpp/common/engine.cpp index 366d0f0..cad2b58 100644 --- a/src/kekengine/cpp/common/engine.cpp +++ b/src/kekengine/cpp/common/engine.cpp @@ -1,5 +1,6 @@ #include "engine.h" +#include #include #include #include @@ -183,7 +184,7 @@ int start() { Physics::step(kekData.lastFrameTime); for(auto cb : kekData.input->periodicCallbacks) { - cb.second(kekData.window); + cb.second(PeriodicEvent{kekData.window}); } if(kekData.activeScene) { diff --git a/src/kekengine/cpp/input/input.cpp b/src/kekengine/cpp/input/input.cpp index f28c7a6..e28d739 100644 --- a/src/kekengine/cpp/input/input.cpp +++ b/src/kekengine/cpp/input/input.cpp @@ -20,7 +20,7 @@ void destroy() { void onCursorPosCallback(GLFWwindow *window, double x, double y) { for(auto cb : kekData.input->mouseCallbacks) { - cb.second(window, x, y); + cb.second(MouseEvent{window, x, y}); } } @@ -32,32 +32,32 @@ void onKeyCallback(GLFWwindow *window, int key, int scancode, int action, int mo } if(key == GLFW_KEY_BACKSPACE && (action == GLFW_PRESS || action == GLFW_REPEAT)) { - kekData.input->activeKeyboardCapture.charCallback(window, KEK_INPUT_DELETE); + kekData.input->activeKeyboardCapture.charCallback(KeyCharEvent{window, KEK_INPUT_DELETE}); } - kekData.input->activeKeyboardCapture.keyCallback(window, key, scancode, action, mods); + kekData.input->activeKeyboardCapture.keyCallback(KeyEvent{window, key, scancode, action, mods}); return; } for(auto cb : kekData.input->keyCallbacks) { - cb.second(window, key, scancode, action, mods); + cb.second(KeyEvent{window, key, scancode, action, mods}); } } void onKeyCharCallback(GLFWwindow *window, unsigned int codepoint) { if(Input::isKeyboardCaptured()) { - kekData.input->activeKeyboardCapture.charCallback(window, codepoint); + kekData.input->activeKeyboardCapture.charCallback(KeyCharEvent{window, codepoint}); return; } for(auto cb : kekData.input->keyCharCallbacks) { - cb.second(window, codepoint); + cb.second(KeyCharEvent{window, codepoint}); } } void onMouseButtonCallback(GLFWwindow *window, int button, int action, int mods) { for(auto cb : kekData.input->mouseButtonCallbacks) { - cb.second(window, button, action, mods); + cb.second(MouseButtonEvent{window, button, action, mods}); } } @@ -163,12 +163,13 @@ KeyboardCapture captureKeyboardInput(KeyCharCallback charCallback, KeyCallback k bool uncaptureKeyboardInput(KeyboardCapture capture) { if(capture == KEK_INVALID_ID || capture != kekData.input->activeKeyboardCapture.id) return false; - kekData.input->activeKeyboardCapture.uncaptureCallback(); + ActiveKeyboardCapture oldCapture = kekData.input->activeKeyboardCapture; kekData.input->activeKeyboardCapture = { KEK_INVALID_ID, KeyCharCallback(), KeyCallback(), Callable()}; + oldCapture.uncaptureCallback(); return true; } @@ -176,4 +177,8 @@ bool isKeyboardCaptured() { return kekData.input->activeKeyboardCapture.id != KEK_INVALID_ID; } +KeyboardCapture getActiveKeyboardCapture() { + return kekData.input->activeKeyboardCapture.id; +} + } diff --git a/src/kekengine/cpp/player/defaultplayercontroller.cpp b/src/kekengine/cpp/player/defaultplayercontroller.cpp index f4ccead..59c0ed9 100644 --- a/src/kekengine/cpp/player/defaultplayercontroller.cpp +++ b/src/kekengine/cpp/player/defaultplayercontroller.cpp @@ -1,5 +1,6 @@ #include "defaultplayercontroller.h" +#include "input.h" #include "internal.h" #include "internal/physics.h" @@ -100,31 +101,33 @@ void DefaultPlayerController::update() { glm::vec3 direction = glm::vec3(0); - if(Input::getKeyState(keyForward) == GLFW_PRESS) { - direction += kekData.activeCamera->direction; - } + if(!Input::isKeyboardCaptured()) { + if(Input::getKeyState(keyForward) == GLFW_PRESS) { + direction += kekData.activeCamera->direction; + } - if(Input::getKeyState(keyBackward) == GLFW_PRESS) { - direction += -kekData.activeCamera->direction; - } + if(Input::getKeyState(keyBackward) == GLFW_PRESS) { + direction += -kekData.activeCamera->direction; + } - if(Input::getKeyState(keyLeft) == GLFW_PRESS) { - direction += -glm::normalize(glm::cross(kekData.activeCamera->direction, glm::vec3(0.0f, 1.0f, 0.0f))); - } + if(Input::getKeyState(keyLeft) == GLFW_PRESS) { + direction += -glm::normalize(glm::cross(kekData.activeCamera->direction, glm::vec3(0.0f, 1.0f, 0.0f))); + } - if(Input::getKeyState(keyRight) == GLFW_PRESS) { - direction += glm::normalize(glm::cross(kekData.activeCamera->direction, glm::vec3(0.0f, 1.0f, 0.0f))); - } + if(Input::getKeyState(keyRight) == GLFW_PRESS) { + 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) { - velocity += glm::vec3(0, jumpVelocity, 0); - } + if(Input::getKeyState(keyJump) == GLFW_PRESS && kekData.player->onGround) { + velocity += glm::vec3(0, jumpVelocity, 0); + } - direction = glm::vec3(direction.x, 0, direction.z); + direction = glm::vec3(direction.x, 0, direction.z); - if(onGround) { - // Project movement onto ground - direction = glm::normalize(glm::cross(groundNormal, glm::cross(direction, groundNormal))); + if(onGround) { + // Project movement onto ground + direction = glm::normalize(glm::cross(groundNormal, glm::cross(direction, groundNormal))); + } } glm::vec3 move = velocity; diff --git a/src/kekengine/cpp/player/noclipplayercontroller.cpp b/src/kekengine/cpp/player/noclipplayercontroller.cpp index 1c5d86b..b2df940 100644 --- a/src/kekengine/cpp/player/noclipplayercontroller.cpp +++ b/src/kekengine/cpp/player/noclipplayercontroller.cpp @@ -1,5 +1,6 @@ #include "noclipplayercontroller.h" +#include "input.h" #include "internal.h" namespace kek { @@ -16,6 +17,8 @@ glm::vec3 NoclipPlayerController::move(glm::vec3 movement) { } void NoclipPlayerController::update() { + if(Input::isKeyboardCaptured()) return; + glm::vec3 direction = glm::vec3(0); if(Input::getKeyState(keyForward) == GLFW_PRESS) { diff --git a/src/kekengine/cpp/ui/ui.cpp b/src/kekengine/cpp/ui/ui.cpp index f95709d..592d1b7 100644 --- a/src/kekengine/cpp/ui/ui.cpp +++ b/src/kekengine/cpp/ui/ui.cpp @@ -1,7 +1,11 @@ #include "ui.h" -#include +#include +#include +#include +#include +#include "input.h" #include "internal.h" #include "internal/ui.h" @@ -13,6 +17,7 @@ UIElement::UIElement(UIValue x, UIValue y) } UIElement::~UIElement() { + UI::unfocusElement(this); } // Returns the element's position relative to its parent in pixels @@ -50,7 +55,7 @@ void UIElement::addChild(UIElement *child) { void UIElement::removeChild(UIElement *child) { child->parent = nullptr; - std::remove(children.begin(), children.end(), child); + std::erase(children, child); } int UIElement::uiToScreen(UIValue val) { @@ -188,9 +193,6 @@ void UIElement::clickAll(UIPoint pos, UIPoint screenPos, GLFWMouseButton button) } bool UIElement::focusEnterAll(UIPoint pos, UIPoint screenPos) { - UIBounds bounds = getBounds(); - if(!bounds.contains(pos)) return false; - UIElement *focusedChild = nullptr; for(UIElement *child : children) { UIPoint childPos = child->getPosition(); @@ -271,21 +273,26 @@ std::vector UI::getElements() { } void UI::focusElement(UIElement *element) { - if(kekData.ui->focusedElement != nullptr) { - unfocusElement(); - } + if(kekData.ui->focusedElement != element) { + if(kekData.ui->focusedElement != nullptr) { + unfocusElement(kekData.ui->focusedElement); + } - kekData.ui->focusedElement = element; - if(element != nullptr) { - element->focusEnter(); + kekData.ui->focusedElement = element; + if(element != nullptr) { + element->focused = true; + element->focusEnter(); + } } } -void UI::unfocusElement() { - if(kekData.ui->focusedElement == nullptr) return; +void UI::unfocusElement(UIElement *element) { + if(kekData.ui->focusedElement == nullptr || element != kekData.ui->focusedElement) return; - kekData.ui->focusedElement->focusExit(); + UIElement *oldFocus = kekData.ui->focusedElement; kekData.ui->focusedElement = nullptr; + oldFocus->focused = false; + oldFocus->focusExit(); } } diff --git a/src/kekengine/cpp/ui/uielements.cpp b/src/kekengine/cpp/ui/uielements.cpp index 32b1508..3cf4a6e 100644 --- a/src/kekengine/cpp/ui/uielements.cpp +++ b/src/kekengine/cpp/ui/uielements.cpp @@ -1,10 +1,15 @@ #include "uielements.h" +#include #include +#include "constants.h" +#include "input.h" #include "internal.h" #include "internal/ui.h" #include "ui.h" +#include "unicode.h" +#include "utils.h" namespace kek { @@ -195,17 +200,25 @@ TextFieldElement::TextFieldElement(UIValue x, UIValue y, UIValue w, Font *font) this->enableClipping = true; this->focusable = true; this->color = Colors::WHITE; - this->text = "Hello World"; + this->focusColor = Colors::GRAY; + this->text = ""; + + RectangleElement::color = color; this->textElement = new TextElement(uiPx(0), uiPx(0)); textElement->textBounds = TextBounds::LINE; - textElement->color = Colors::RED; + textElement->color = Colors::BLACK; textElement->setText(text); addChild(textElement); int textH = textElement->getBounds().h; - std::cout << "TEXTH" << textH << std::endl; h = uiPx(textH); + + this->cursor = new RectangleElement(uiPx(0), uiPx(2), uiPx(1), uiPx(textH - 4)); + cursor->color = Colors::BLACK; + addChild(cursor); + + this->capture = KEK_INVALID_ID; } TextFieldElement::TextFieldElement(UIValue x, UIValue y, UIValue w) @@ -213,15 +226,72 @@ TextFieldElement::TextFieldElement(UIValue x, UIValue y, UIValue w) } TextFieldElement::~TextFieldElement() { + Input::uncaptureKeyboardInput(capture); + capture = KEK_INVALID_ID; + delete textElement; + delete cursor; } UIElementType TextFieldElement::getType() { return UIElementType::TEXT_FIELD; } +void TextFieldElement::focusEnter() { + RectangleElement::color = focusColor; + cursor->visible = true; + + capture = Input::captureKeyboardInput( + KeyCharCallback([](KeyCharEvent event, void *data) { + TextFieldElement *_this = (TextFieldElement *) data; + + std::u32string str = Unicode::convertStdToU32(_this->text); + if(event.codepoint == KEK_INPUT_DELETE) { + if(str.length() == 0) return; + str = str.substr(0, str.length() - 1); + } else { + str.push_back(event.codepoint); + } + + _this->text = Unicode::convertU32ToStd(str); + _this->textElement->setText(_this->text); + + _this->lastCharTyped = glfwGetTime(); + _this->cursor->x = uiPx(_this->textElement->getBounds().w); + }, + this), + KeyCallback([](KeyEvent event, void *data) { + TextFieldElement *_this = (TextFieldElement *) data; + if(event.key == GLFW_KEY_ENTER && event.action == GLFW_PRESS) { + Input::uncaptureKeyboardInput(_this->capture); + } + }, + this), + Callable([](void *data) { + TextFieldElement *_this = (TextFieldElement *) data; + UI::unfocusElement(_this); + }, + this)); +} + +void TextFieldElement::focusExit() { + RectangleElement::color = color; + cursor->visible = false; + + Input::uncaptureKeyboardInput(capture); + capture = KEK_INVALID_ID; +} + void TextFieldElement::draw(UIPoint screenPos, glm::mat4 projection) { RectangleElement::draw(screenPos, projection); + + double time = glfwGetTime(); + cursor->visible = focused ? (time - lastCharTyped < 0.5 || (int) time % 2 == 0) : false; +} + +void TextFieldElement::setText(std::string text) { + this->text = text; + this->textElement->setText(text); } } diff --git a/src/kekengine/include/color.h b/src/kekengine/include/color.h index 258222c..24b68eb 100644 --- a/src/kekengine/include/color.h +++ b/src/kekengine/include/color.h @@ -28,6 +28,10 @@ struct Color { constexpr Color brighter(float factor = 0.7) const { return Color(r / factor, g / factor, b / factor, a); } + + constexpr bool operator==(const Color &other) { + return r == other.r && g == other.g && b == other.g; + } }; class Colors { diff --git a/src/kekengine/include/constants.h b/src/kekengine/include/constants.h index b6904e3..8f8fcab 100644 --- a/src/kekengine/include/constants.h +++ b/src/kekengine/include/constants.h @@ -38,7 +38,7 @@ #define KEK_FONT_BITMAP_CHAR_MASK 0xFF // = KEK_FONT_BITMAP_CHAR_BITS 1s in binary #define KEK_TEXT_BLOCK_SIZE 8 -#define KEK_DEFAULT_FONT "font/MaredivRegular-yeg3.ttf" +#define KEK_DEFAULT_FONT "font/JupiteroidRegular.ttf" #define KEK_DEFAULT_FONT_SIZE_PIXELS 24 #define KEK_INPUT_DELETE -1u diff --git a/src/kekengine/include/input.h b/src/kekengine/include/input.h index 7ca3f44..c2e5aa3 100644 --- a/src/kekengine/include/input.h +++ b/src/kekengine/include/input.h @@ -7,11 +7,41 @@ namespace kek { -typedef GenericCallable PeriodicCallback; // periodicCallback(GLFWwindow *window) -typedef GenericCallable KeyCallback; // keyCallback(GLFWwindow *window, int key, int scancode, int action, int mods) -typedef GenericCallable KeyCharCallback; // keyCharCallback(GLFWwindow *window, unsigned int codepoint) -typedef GenericCallable MouseCallback; // mouseCallback(GLFWwindow *window, double x, double y) -typedef GenericCallable MouseButtonCallback; // void mouseButtonCallback(GLFWwindow* window, int button, int action, int mods) +typedef struct { + GLFWwindow *window; +} PeriodicEvent; + +typedef struct { + GLFWwindow *window; + int key; + int scancode; + int action; + int mods; +} KeyEvent; + +typedef struct { + GLFWwindow *window; + unsigned int codepoint; +} KeyCharEvent; + +typedef struct { + GLFWwindow *window; + double x; + double y; +} MouseEvent; + +typedef struct { + GLFWwindow *window; + int button; + int action; + int mods; +} MouseButtonEvent; + +typedef GenericCallable PeriodicCallback; // periodicCallback(GLFWwindow *window) +typedef GenericCallable KeyCallback; // keyCallback(GLFWwindow *window, int key, int scancode, int action, int mods) +typedef GenericCallable KeyCharCallback; // keyCharCallback(GLFWwindow *window, unsigned int codepoint) +typedef GenericCallable MouseCallback; // mouseCallback(GLFWwindow *window, double x, double y) +typedef GenericCallable MouseButtonCallback; // void mouseButtonCallback(GLFWwindow* window, int button, int action, int mods) typedef unsigned int InputListener; typedef int GLFWKey; @@ -69,5 +99,6 @@ GLFWCursorMode getCursorMode(); KeyboardCapture captureKeyboardInput(KeyCharCallback charCallback, KeyCallback keyCallback, Callable uncaptureCallback); bool uncaptureKeyboardInput(KeyboardCapture capture); bool isKeyboardCaptured(); +KeyboardCapture getActiveKeyboardCapture(); } diff --git a/src/kekengine/include/ui.h b/src/kekengine/include/ui.h index 31edd61..a37c436 100644 --- a/src/kekengine/include/ui.h +++ b/src/kekengine/include/ui.h @@ -136,11 +136,13 @@ class UIElement { bool enableClipping = false; bool clickable = false; - bool hovering = false; bool visible = true; bool focusable = false; bool draggable = false; + bool hovering = false; + bool focused = false; + UIElement(UIValue x, UIValue y); virtual ~UIElement(); @@ -202,7 +204,7 @@ void addElement(UIElement *element); void removeElement(UIElement *element); void focusElement(UIElement *element); -void unfocusElement(); +void unfocusElement(UIElement *element); }; diff --git a/src/kekengine/include/uielements.h b/src/kekengine/include/uielements.h index f9e8ebf..9eea97a 100644 --- a/src/kekengine/include/uielements.h +++ b/src/kekengine/include/uielements.h @@ -101,7 +101,14 @@ class TextFieldElement: public RectangleElement { protected: std::string text; + Color color; + Color focusColor; + TextElement *textElement; + RectangleElement *cursor; + + KeyboardCapture capture; + float lastCharTyped = 0; public: TextFieldElement(UIValue x, UIValue y, UIValue w, Font *font); @@ -112,7 +119,12 @@ class TextFieldElement: public RectangleElement { virtual UIElementType getType(); + virtual void focusEnter(); + virtual void focusExit(); + virtual void draw(UIPoint screenPos, glm::mat4 projection); + + void setText(std::string text); }; } diff --git a/src/kekengine/include/utils.h b/src/kekengine/include/utils.h index 48da7d1..1c88f2b 100644 --- a/src/kekengine/include/utils.h +++ b/src/kekengine/include/utils.h @@ -20,9 +20,8 @@ struct GenericCallable { : function(nullptr), data(nullptr) {} - GenericCallable(GenericFunction function) - : function(function), - data(nullptr){}; + GenericCallable(GenericFunction function) + : GenericCallable([](void *f) { ((GenericFunction) f)(); }, (void *) function) {} GenericCallable(GenericFunction function, void *data) : function(function), diff --git a/src/kekengine/res/font/JupiteroidBold.ttf b/src/kekengine/res/font/JupiteroidBold.ttf new file mode 100644 index 0000000..fb544aa Binary files /dev/null and b/src/kekengine/res/font/JupiteroidBold.ttf differ diff --git a/src/kekengine/res/font/JupiteroidBoldItalic.ttf b/src/kekengine/res/font/JupiteroidBoldItalic.ttf new file mode 100644 index 0000000..4c34c49 Binary files /dev/null and b/src/kekengine/res/font/JupiteroidBoldItalic.ttf differ diff --git a/src/kekengine/res/font/JupiteroidItalic.ttf b/src/kekengine/res/font/JupiteroidItalic.ttf new file mode 100644 index 0000000..bbfaeb6 Binary files /dev/null and b/src/kekengine/res/font/JupiteroidItalic.ttf differ diff --git a/src/kekengine/res/font/JupiteroidLight.ttf b/src/kekengine/res/font/JupiteroidLight.ttf new file mode 100644 index 0000000..5f1edc2 Binary files /dev/null and b/src/kekengine/res/font/JupiteroidLight.ttf differ diff --git a/src/kekengine/res/font/JupiteroidLightItalic.ttf b/src/kekengine/res/font/JupiteroidLightItalic.ttf new file mode 100644 index 0000000..b29b1fd Binary files /dev/null and b/src/kekengine/res/font/JupiteroidLightItalic.ttf differ diff --git a/src/kekengine/res/font/JupiteroidRegular.ttf b/src/kekengine/res/font/JupiteroidRegular.ttf new file mode 100644 index 0000000..2c438df Binary files /dev/null and b/src/kekengine/res/font/JupiteroidRegular.ttf differ diff --git a/src/kekengine/res/font/MaredivRegular-yeg3.ttf b/src/kekengine/res/font/MaredivRegular.ttf similarity index 100% rename from src/kekengine/res/font/MaredivRegular-yeg3.ttf rename to src/kekengine/res/font/MaredivRegular.ttf diff --git a/src/kekgame/cpp/kekgame.cpp b/src/kekgame/cpp/kekgame.cpp index 934f072..475d0d0 100644 --- a/src/kekgame/cpp/kekgame.cpp +++ b/src/kekgame/cpp/kekgame.cpp @@ -1,5 +1,6 @@ #include +#include "input.h" #include "kekengine.h" #include #include @@ -16,42 +17,24 @@ using namespace kek; static ButtonElement *button; -static KeyboardCapture capture = KEK_INVALID_ID; -void periodicCallback(GLFWwindow *window, void *data) { +void periodicCallback(PeriodicEvent event, void *data) { } -void keyCallback(GLFWwindow *window, int key, int scancode, int action, int mods, void *data) { +void keyCallback(KeyEvent event, void *data) { } -void mouseButtonCallback(GLFWwindow *window, int button, int action, int mods, void *data) { +void mouseButtonCallback(MouseButtonEvent event, void *data) { } void onButtonClick(void *data) { - button->color = Colors::RED; - button->hoverColor = Colors::ORANGE; - capture = Input::captureKeyboardInput( - KeyCharCallback([](GLFWwindow *window, unsigned int codepoint, void *data) { - std::u32string str = Unicode::convertStdToU32(button->text->getText()); - if(codepoint == KEK_INPUT_DELETE) { - str = str.substr(0, str.length() - 1); - } else { - str.push_back(codepoint); - } - button->text->setText(Unicode::convertU32ToStd(str)); - }, - nullptr), - KeyCallback([](GLFWwindow *window, int key, int scancode, int action, int mods, void *data) { - if(key == GLFW_KEY_ENTER && action == GLFW_PRESS) { - Input::uncaptureKeyboardInput(capture); - } - }, - nullptr), - Callable([](void *data) { - button->color = Colors::WHITE; - button->hoverColor = Colors::GRAY; - }, - nullptr)); + if(button->color == Colors::RED) { + button->color = Colors::GREEN; + button->hoverColor = Colors::GREEN.darker(); + } else { + button->color = Colors::RED; + button->hoverColor = Colors::RED.darker(); + } } int main(int argc, char **argv) { @@ -142,7 +125,7 @@ int main(int argc, char **argv) { button3->addChild(rect); UI::addElement(button3); - TextFieldElement *textField = new TextFieldElement(uiPx(10), uiPx(200), uiPx(50)); + TextFieldElement *textField = new TextFieldElement(uiPx(10), uiPx(200), uiPx(500)); UI::addElement(textField); if(Engine::start() != KEK_SUCCESS) return 1;