Update UI, more fonts & configs, Use C++20
This commit is contained in:
parent
f9041ffc28
commit
3b03637cd4
29
.clang-format
Normal file
29
.clang-format
Normal file
@ -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
|
@ -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
|
add_compile_definitions(FT_CONFIG_OPTION_ERROR_STRINGS) # Freetype error strings
|
||||||
|
|
||||||
if(${KEKENGINE_DEBUG})
|
if(${KEKENGINE_DEBUG})
|
||||||
add_compile_options(-Wall -g)
|
add_compile_options(-Wall -std=c++20 -g)
|
||||||
else()
|
else()
|
||||||
add_compile_options(-Wall -O3)
|
add_compile_options(-Wall -std=c++20 -O3)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
block()
|
block()
|
||||||
|
@ -20,10 +20,7 @@ static KeyBinding
|
|||||||
|
|
||||||
static ButtonElement *options;
|
static ButtonElement *options;
|
||||||
|
|
||||||
static void defaultInput(GLFWwindow *window, void *data) {
|
static void defaultPeriodic(PeriodicEvent event, void *data) {
|
||||||
if(Input::isKeyboardCaptured()) return;
|
|
||||||
|
|
||||||
// TODO: move input handling to controller class, add NoclipController
|
|
||||||
kekData.player->controller->update();
|
kekData.player->controller->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,6 +52,7 @@ static void doUIMouseHover(double x, double y) {
|
|||||||
|
|
||||||
static void doUIMouseClick(double x, double y, GLFWMouseButton button) {
|
static void doUIMouseClick(double x, double y, GLFWMouseButton button) {
|
||||||
UIElement *clickedElement = nullptr;
|
UIElement *clickedElement = nullptr;
|
||||||
|
UIElement *focusedElement = nullptr;
|
||||||
|
|
||||||
for(UIElement *element : kekData.ui->elements) {
|
for(UIElement *element : kekData.ui->elements) {
|
||||||
UIPoint childPos = element->getPosition();
|
UIPoint childPos = element->getPosition();
|
||||||
@ -63,34 +61,41 @@ static void doUIMouseClick(double x, double y, GLFWMouseButton button) {
|
|||||||
UIBounds bounds = element->getBounds();
|
UIBounds bounds = element->getBounds();
|
||||||
if(!bounds.contains(clickedAt)) continue;
|
if(!bounds.contains(clickedAt)) continue;
|
||||||
|
|
||||||
clickedElement = element;
|
if(element->clickable) clickedElement = element;
|
||||||
|
if(element->focusable) focusedElement = element;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(clickedElement) {
|
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 childPos = clickedElement->getPosition();
|
||||||
UIPoint clickedAt = UIPoint((int) x - childPos.x, (int) y - childPos.y);
|
UIPoint clickedAt = UIPoint((int) x - childPos.x, (int) y - childPos.y);
|
||||||
clickedElement->clickAll(clickedAt, UIPoint((int) x, (int) y), button);
|
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void defaultKeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods, void *data) {
|
if(focusedElement) {
|
||||||
if(key == Input::getKeyBinding(keyExit).key && action == GLFW_PRESS) {
|
UIPoint childPos = focusedElement->getPosition();
|
||||||
glfwSetWindowShouldClose(window, true);
|
UIPoint clickedAt = UIPoint((int) x - childPos.x, (int) y - childPos.y);
|
||||||
|
focusedElement->focusEnterAll(clickedAt, UIPoint((int) x, (int) y));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(key == Input::getKeyBinding(keyOptions).key && action == GLFW_PRESS) {
|
kekData.ui->focusedElement = focusedElement;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void defaultKeyCallback(KeyEvent event, void *data) {
|
||||||
|
if(event.key == Input::getKeyBinding(keyExit).key && event.action == GLFW_PRESS) {
|
||||||
|
glfwSetWindowShouldClose(event.window, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(event.key == Input::getKeyBinding(keyOptions).key && event.action == GLFW_PRESS) {
|
||||||
options->visible = !options->visible;
|
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) {
|
if(Input::getCursorMode() == GLFWCursorMode::CAPTURE) {
|
||||||
Input::setCursorMode(GLFWCursorMode::FREE);
|
Input::setCursorMode(GLFWCursorMode::FREE);
|
||||||
double x, y;
|
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->noclip = !kekData.player->noclip;
|
||||||
kekData.player->controller = kekData.player->noclip ? (PlayerController *) noclipController : (PlayerController *) defaultController;
|
kekData.player->controller = kekData.player->noclip ? (PlayerController *) noclipController : (PlayerController *) defaultController;
|
||||||
if(kekData.player->noclip) {
|
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 bool firstMouse = true;
|
||||||
static double lastX = 0, lastY = 0;
|
static double lastX = 0, lastY = 0;
|
||||||
if(firstMouse) {
|
if(firstMouse) {
|
||||||
lastX = x;
|
lastX = event.x;
|
||||||
lastY = y;
|
lastY = event.y;
|
||||||
firstMouse = false;
|
firstMouse = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(Input::getCursorMode()) {
|
switch(Input::getCursorMode()) {
|
||||||
case GLFWCursorMode::CAPTURE: {
|
case GLFWCursorMode::CAPTURE: {
|
||||||
float xoff = lastX - x;
|
float xoff = lastX - event.x;
|
||||||
float yoff = lastY - y;
|
float yoff = lastY - event.y;
|
||||||
|
|
||||||
xoff *= 0.1f;
|
xoff *= 0.1f;
|
||||||
yoff *= 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::FREE:
|
||||||
case GLFWCursorMode::HIDDEN: {
|
case GLFWCursorMode::HIDDEN: {
|
||||||
doUIMouseHover(x, y);
|
doUIMouseHover(event.x, event.y);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lastX = x;
|
lastX = event.x;
|
||||||
lastY = y;
|
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()) {
|
switch(Input::getCursorMode()) {
|
||||||
case GLFWCursorMode::CAPTURE: {
|
case GLFWCursorMode::CAPTURE: {
|
||||||
// TODO
|
// TODO
|
||||||
@ -156,13 +161,13 @@ static void defaultMouseButtonCallback(GLFWwindow *window, int button, int actio
|
|||||||
}
|
}
|
||||||
case GLFWCursorMode::FREE:
|
case GLFWCursorMode::FREE:
|
||||||
case GLFWCursorMode::HIDDEN: {
|
case GLFWCursorMode::HIDDEN: {
|
||||||
switch(action) {
|
switch(event.action) {
|
||||||
case GLFW_PRESS:
|
case GLFW_PRESS:
|
||||||
break;
|
break;
|
||||||
case GLFW_RELEASE: {
|
case GLFW_RELEASE: {
|
||||||
double x, y;
|
double x, y;
|
||||||
glfwGetCursorPos(window, &x, &y);
|
glfwGetCursorPos(event.window, &x, &y);
|
||||||
doUIMouseClick(x, y, (GLFWMouseButton) button);
|
doUIMouseClick(x, y, (GLFWMouseButton) event.button);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,7 +190,7 @@ void init() {
|
|||||||
keyToggleNoclip = Input::createKeyBinding("Toggle Noclip", GLFW_KEY_N);
|
keyToggleNoclip = Input::createKeyBinding("Toggle Noclip", GLFW_KEY_N);
|
||||||
keyExit = Input::createKeyBinding("Exit", GLFW_KEY_ESCAPE);
|
keyExit = Input::createKeyBinding("Exit", GLFW_KEY_ESCAPE);
|
||||||
|
|
||||||
Input::addPeriodicCallback(PeriodicCallback(defaultInput, nullptr));
|
Input::addPeriodicCallback(PeriodicCallback(defaultPeriodic, nullptr));
|
||||||
Input::addKeyListener(KeyCallback(defaultKeyCallback, nullptr));
|
Input::addKeyListener(KeyCallback(defaultKeyCallback, nullptr));
|
||||||
Input::addMouseListener(MouseCallback(defaultMouseCallback, nullptr));
|
Input::addMouseListener(MouseCallback(defaultMouseCallback, nullptr));
|
||||||
Input::addMouseButtonListener(MouseButtonCallback(defaultMouseButtonCallback, nullptr));
|
Input::addMouseButtonListener(MouseButtonCallback(defaultMouseButtonCallback, nullptr));
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include "engine.h"
|
#include "engine.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@ -183,7 +184,7 @@ int start() {
|
|||||||
Physics::step(kekData.lastFrameTime);
|
Physics::step(kekData.lastFrameTime);
|
||||||
|
|
||||||
for(auto cb : kekData.input->periodicCallbacks) {
|
for(auto cb : kekData.input->periodicCallbacks) {
|
||||||
cb.second(kekData.window);
|
cb.second(PeriodicEvent{kekData.window});
|
||||||
}
|
}
|
||||||
|
|
||||||
if(kekData.activeScene) {
|
if(kekData.activeScene) {
|
||||||
|
@ -20,7 +20,7 @@ void destroy() {
|
|||||||
|
|
||||||
void onCursorPosCallback(GLFWwindow *window, double x, double y) {
|
void onCursorPosCallback(GLFWwindow *window, double x, double y) {
|
||||||
for(auto cb : kekData.input->mouseCallbacks) {
|
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)) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto cb : kekData.input->keyCallbacks) {
|
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) {
|
void onKeyCharCallback(GLFWwindow *window, unsigned int codepoint) {
|
||||||
if(Input::isKeyboardCaptured()) {
|
if(Input::isKeyboardCaptured()) {
|
||||||
kekData.input->activeKeyboardCapture.charCallback(window, codepoint);
|
kekData.input->activeKeyboardCapture.charCallback(KeyCharEvent{window, codepoint});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto cb : kekData.input->keyCharCallbacks) {
|
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) {
|
void onMouseButtonCallback(GLFWwindow *window, int button, int action, int mods) {
|
||||||
for(auto cb : kekData.input->mouseButtonCallbacks) {
|
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) {
|
bool uncaptureKeyboardInput(KeyboardCapture capture) {
|
||||||
if(capture == KEK_INVALID_ID || capture != kekData.input->activeKeyboardCapture.id) return false;
|
if(capture == KEK_INVALID_ID || capture != kekData.input->activeKeyboardCapture.id) return false;
|
||||||
kekData.input->activeKeyboardCapture.uncaptureCallback();
|
ActiveKeyboardCapture oldCapture = kekData.input->activeKeyboardCapture;
|
||||||
kekData.input->activeKeyboardCapture = {
|
kekData.input->activeKeyboardCapture = {
|
||||||
KEK_INVALID_ID,
|
KEK_INVALID_ID,
|
||||||
KeyCharCallback(),
|
KeyCharCallback(),
|
||||||
KeyCallback(),
|
KeyCallback(),
|
||||||
Callable()};
|
Callable()};
|
||||||
|
oldCapture.uncaptureCallback();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,4 +177,8 @@ bool isKeyboardCaptured() {
|
|||||||
return kekData.input->activeKeyboardCapture.id != KEK_INVALID_ID;
|
return kekData.input->activeKeyboardCapture.id != KEK_INVALID_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KeyboardCapture getActiveKeyboardCapture() {
|
||||||
|
return kekData.input->activeKeyboardCapture.id;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include "defaultplayercontroller.h"
|
#include "defaultplayercontroller.h"
|
||||||
|
|
||||||
|
#include "input.h"
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
#include "internal/physics.h"
|
#include "internal/physics.h"
|
||||||
|
|
||||||
@ -100,6 +101,7 @@ void DefaultPlayerController::update() {
|
|||||||
|
|
||||||
glm::vec3 direction = glm::vec3(0);
|
glm::vec3 direction = glm::vec3(0);
|
||||||
|
|
||||||
|
if(!Input::isKeyboardCaptured()) {
|
||||||
if(Input::getKeyState(keyForward) == GLFW_PRESS) {
|
if(Input::getKeyState(keyForward) == GLFW_PRESS) {
|
||||||
direction += kekData.activeCamera->direction;
|
direction += kekData.activeCamera->direction;
|
||||||
}
|
}
|
||||||
@ -126,6 +128,7 @@ void DefaultPlayerController::update() {
|
|||||||
// Project movement onto ground
|
// Project movement onto ground
|
||||||
direction = glm::normalize(glm::cross(groundNormal, glm::cross(direction, groundNormal)));
|
direction = glm::normalize(glm::cross(groundNormal, glm::cross(direction, groundNormal)));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
glm::vec3 move = velocity;
|
glm::vec3 move = velocity;
|
||||||
if(glm::length2(direction) > 0) {
|
if(glm::length2(direction) > 0) {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include "noclipplayercontroller.h"
|
#include "noclipplayercontroller.h"
|
||||||
|
|
||||||
|
#include "input.h"
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
namespace kek {
|
namespace kek {
|
||||||
@ -16,6 +17,8 @@ glm::vec3 NoclipPlayerController::move(glm::vec3 movement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void NoclipPlayerController::update() {
|
void NoclipPlayerController::update() {
|
||||||
|
if(Input::isKeyboardCaptured()) return;
|
||||||
|
|
||||||
glm::vec3 direction = glm::vec3(0);
|
glm::vec3 direction = glm::vec3(0);
|
||||||
|
|
||||||
if(Input::getKeyState(keyForward) == GLFW_PRESS) {
|
if(Input::getKeyState(keyForward) == GLFW_PRESS) {
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
#include "ui.h"
|
#include "ui.h"
|
||||||
|
|
||||||
#include <bits/stdc++.h>
|
#include <iostream>
|
||||||
|
#include <numeric>
|
||||||
|
#include <string_view>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "input.h"
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
#include "internal/ui.h"
|
#include "internal/ui.h"
|
||||||
|
|
||||||
@ -13,6 +17,7 @@ UIElement::UIElement(UIValue x, UIValue y)
|
|||||||
}
|
}
|
||||||
|
|
||||||
UIElement::~UIElement() {
|
UIElement::~UIElement() {
|
||||||
|
UI::unfocusElement(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the element's position relative to its parent in pixels
|
// 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) {
|
void UIElement::removeChild(UIElement *child) {
|
||||||
child->parent = nullptr;
|
child->parent = nullptr;
|
||||||
std::remove(children.begin(), children.end(), child);
|
std::erase(children, child);
|
||||||
}
|
}
|
||||||
|
|
||||||
int UIElement::uiToScreen(UIValue val) {
|
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) {
|
bool UIElement::focusEnterAll(UIPoint pos, UIPoint screenPos) {
|
||||||
UIBounds bounds = getBounds();
|
|
||||||
if(!bounds.contains(pos)) return false;
|
|
||||||
|
|
||||||
UIElement *focusedChild = nullptr;
|
UIElement *focusedChild = nullptr;
|
||||||
for(UIElement *child : children) {
|
for(UIElement *child : children) {
|
||||||
UIPoint childPos = child->getPosition();
|
UIPoint childPos = child->getPosition();
|
||||||
@ -271,21 +273,26 @@ std::vector<UIElement *> UI::getElements() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void UI::focusElement(UIElement *element) {
|
void UI::focusElement(UIElement *element) {
|
||||||
|
if(kekData.ui->focusedElement != element) {
|
||||||
if(kekData.ui->focusedElement != nullptr) {
|
if(kekData.ui->focusedElement != nullptr) {
|
||||||
unfocusElement();
|
unfocusElement(kekData.ui->focusedElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
kekData.ui->focusedElement = element;
|
kekData.ui->focusedElement = element;
|
||||||
if(element != nullptr) {
|
if(element != nullptr) {
|
||||||
|
element->focused = true;
|
||||||
element->focusEnter();
|
element->focusEnter();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void UI::unfocusElement() {
|
void UI::unfocusElement(UIElement *element) {
|
||||||
if(kekData.ui->focusedElement == nullptr) return;
|
if(kekData.ui->focusedElement == nullptr || element != kekData.ui->focusedElement) return;
|
||||||
|
|
||||||
kekData.ui->focusedElement->focusExit();
|
UIElement *oldFocus = kekData.ui->focusedElement;
|
||||||
kekData.ui->focusedElement = nullptr;
|
kekData.ui->focusedElement = nullptr;
|
||||||
|
oldFocus->focused = false;
|
||||||
|
oldFocus->focusExit();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,15 @@
|
|||||||
#include "uielements.h"
|
#include "uielements.h"
|
||||||
|
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
#include <glm/gtc/type_ptr.hpp>
|
#include <glm/gtc/type_ptr.hpp>
|
||||||
|
|
||||||
|
#include "constants.h"
|
||||||
|
#include "input.h"
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
#include "internal/ui.h"
|
#include "internal/ui.h"
|
||||||
#include "ui.h"
|
#include "ui.h"
|
||||||
|
#include "unicode.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
namespace kek {
|
namespace kek {
|
||||||
|
|
||||||
@ -195,17 +200,25 @@ TextFieldElement::TextFieldElement(UIValue x, UIValue y, UIValue w, Font *font)
|
|||||||
this->enableClipping = true;
|
this->enableClipping = true;
|
||||||
this->focusable = true;
|
this->focusable = true;
|
||||||
this->color = Colors::WHITE;
|
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));
|
this->textElement = new TextElement(uiPx(0), uiPx(0));
|
||||||
textElement->textBounds = TextBounds::LINE;
|
textElement->textBounds = TextBounds::LINE;
|
||||||
textElement->color = Colors::RED;
|
textElement->color = Colors::BLACK;
|
||||||
textElement->setText(text);
|
textElement->setText(text);
|
||||||
addChild(textElement);
|
addChild(textElement);
|
||||||
|
|
||||||
int textH = textElement->getBounds().h;
|
int textH = textElement->getBounds().h;
|
||||||
std::cout << "TEXTH" << textH << std::endl;
|
|
||||||
h = uiPx(textH);
|
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)
|
TextFieldElement::TextFieldElement(UIValue x, UIValue y, UIValue w)
|
||||||
@ -213,15 +226,72 @@ TextFieldElement::TextFieldElement(UIValue x, UIValue y, UIValue w)
|
|||||||
}
|
}
|
||||||
|
|
||||||
TextFieldElement::~TextFieldElement() {
|
TextFieldElement::~TextFieldElement() {
|
||||||
|
Input::uncaptureKeyboardInput(capture);
|
||||||
|
capture = KEK_INVALID_ID;
|
||||||
|
|
||||||
delete textElement;
|
delete textElement;
|
||||||
|
delete cursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
UIElementType TextFieldElement::getType() {
|
UIElementType TextFieldElement::getType() {
|
||||||
return UIElementType::TEXT_FIELD;
|
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) {
|
void TextFieldElement::draw(UIPoint screenPos, glm::mat4 projection) {
|
||||||
RectangleElement::draw(screenPos, 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,10 @@ struct Color {
|
|||||||
constexpr Color brighter(float factor = 0.7) const {
|
constexpr Color brighter(float factor = 0.7) const {
|
||||||
return Color(r / factor, g / factor, b / factor, a);
|
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 {
|
class Colors {
|
||||||
|
@ -38,7 +38,7 @@
|
|||||||
#define KEK_FONT_BITMAP_CHAR_MASK 0xFF // = KEK_FONT_BITMAP_CHAR_BITS 1s in binary
|
#define KEK_FONT_BITMAP_CHAR_MASK 0xFF // = KEK_FONT_BITMAP_CHAR_BITS 1s in binary
|
||||||
#define KEK_TEXT_BLOCK_SIZE 8
|
#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_DEFAULT_FONT_SIZE_PIXELS 24
|
||||||
|
|
||||||
#define KEK_INPUT_DELETE -1u
|
#define KEK_INPUT_DELETE -1u
|
||||||
|
@ -7,11 +7,41 @@
|
|||||||
|
|
||||||
namespace kek {
|
namespace kek {
|
||||||
|
|
||||||
typedef GenericCallable<GLFWwindow *> PeriodicCallback; // periodicCallback(GLFWwindow *window)
|
typedef struct {
|
||||||
typedef GenericCallable<GLFWwindow *, int, int, int, int> KeyCallback; // keyCallback(GLFWwindow *window, int key, int scancode, int action, int mods)
|
GLFWwindow *window;
|
||||||
typedef GenericCallable<GLFWwindow *, unsigned int> KeyCharCallback; // keyCharCallback(GLFWwindow *window, unsigned int codepoint)
|
} PeriodicEvent;
|
||||||
typedef GenericCallable<GLFWwindow *, double, double> MouseCallback; // mouseCallback(GLFWwindow *window, double x, double y)
|
|
||||||
typedef GenericCallable<GLFWwindow *, int, int, int> MouseButtonCallback; // void mouseButtonCallback(GLFWwindow* window, int button, int action, int mods)
|
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<PeriodicEvent> PeriodicCallback; // periodicCallback(GLFWwindow *window)
|
||||||
|
typedef GenericCallable<KeyEvent> KeyCallback; // keyCallback(GLFWwindow *window, int key, int scancode, int action, int mods)
|
||||||
|
typedef GenericCallable<KeyCharEvent> KeyCharCallback; // keyCharCallback(GLFWwindow *window, unsigned int codepoint)
|
||||||
|
typedef GenericCallable<MouseEvent> MouseCallback; // mouseCallback(GLFWwindow *window, double x, double y)
|
||||||
|
typedef GenericCallable<MouseButtonEvent> MouseButtonCallback; // void mouseButtonCallback(GLFWwindow* window, int button, int action, int mods)
|
||||||
|
|
||||||
typedef unsigned int InputListener;
|
typedef unsigned int InputListener;
|
||||||
typedef int GLFWKey;
|
typedef int GLFWKey;
|
||||||
@ -69,5 +99,6 @@ GLFWCursorMode getCursorMode();
|
|||||||
KeyboardCapture captureKeyboardInput(KeyCharCallback charCallback, KeyCallback keyCallback, Callable uncaptureCallback);
|
KeyboardCapture captureKeyboardInput(KeyCharCallback charCallback, KeyCallback keyCallback, Callable uncaptureCallback);
|
||||||
bool uncaptureKeyboardInput(KeyboardCapture capture);
|
bool uncaptureKeyboardInput(KeyboardCapture capture);
|
||||||
bool isKeyboardCaptured();
|
bool isKeyboardCaptured();
|
||||||
|
KeyboardCapture getActiveKeyboardCapture();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -136,11 +136,13 @@ class UIElement {
|
|||||||
bool enableClipping = false;
|
bool enableClipping = false;
|
||||||
|
|
||||||
bool clickable = false;
|
bool clickable = false;
|
||||||
bool hovering = false;
|
|
||||||
bool visible = true;
|
bool visible = true;
|
||||||
bool focusable = false;
|
bool focusable = false;
|
||||||
bool draggable = false;
|
bool draggable = false;
|
||||||
|
|
||||||
|
bool hovering = false;
|
||||||
|
bool focused = false;
|
||||||
|
|
||||||
UIElement(UIValue x, UIValue y);
|
UIElement(UIValue x, UIValue y);
|
||||||
|
|
||||||
virtual ~UIElement();
|
virtual ~UIElement();
|
||||||
@ -202,7 +204,7 @@ void addElement(UIElement *element);
|
|||||||
void removeElement(UIElement *element);
|
void removeElement(UIElement *element);
|
||||||
|
|
||||||
void focusElement(UIElement *element);
|
void focusElement(UIElement *element);
|
||||||
void unfocusElement();
|
void unfocusElement(UIElement *element);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -101,7 +101,14 @@ class TextFieldElement: public RectangleElement {
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::string text;
|
std::string text;
|
||||||
|
Color color;
|
||||||
|
Color focusColor;
|
||||||
|
|
||||||
TextElement *textElement;
|
TextElement *textElement;
|
||||||
|
RectangleElement *cursor;
|
||||||
|
|
||||||
|
KeyboardCapture capture;
|
||||||
|
float lastCharTyped = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TextFieldElement(UIValue x, UIValue y, UIValue w, Font *font);
|
TextFieldElement(UIValue x, UIValue y, UIValue w, Font *font);
|
||||||
@ -112,7 +119,12 @@ class TextFieldElement: public RectangleElement {
|
|||||||
|
|
||||||
virtual UIElementType getType();
|
virtual UIElementType getType();
|
||||||
|
|
||||||
|
virtual void focusEnter();
|
||||||
|
virtual void focusExit();
|
||||||
|
|
||||||
virtual void draw(UIPoint screenPos, glm::mat4 projection);
|
virtual void draw(UIPoint screenPos, glm::mat4 projection);
|
||||||
|
|
||||||
|
void setText(std::string text);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -20,9 +20,8 @@ struct GenericCallable {
|
|||||||
: function(nullptr),
|
: function(nullptr),
|
||||||
data(nullptr) {}
|
data(nullptr) {}
|
||||||
|
|
||||||
GenericCallable(GenericFunction<Args..., void *> function)
|
GenericCallable(GenericFunction<Args...> function)
|
||||||
: function(function),
|
: GenericCallable([](void *f) { ((GenericFunction<Args...>) f)(); }, (void *) function) {}
|
||||||
data(nullptr){};
|
|
||||||
|
|
||||||
GenericCallable(GenericFunction<Args..., void *> function, void *data)
|
GenericCallable(GenericFunction<Args..., void *> function, void *data)
|
||||||
: function(function),
|
: function(function),
|
||||||
|
BIN
src/kekengine/res/font/JupiteroidBold.ttf
Normal file
BIN
src/kekengine/res/font/JupiteroidBold.ttf
Normal file
Binary file not shown.
BIN
src/kekengine/res/font/JupiteroidBoldItalic.ttf
Normal file
BIN
src/kekengine/res/font/JupiteroidBoldItalic.ttf
Normal file
Binary file not shown.
BIN
src/kekengine/res/font/JupiteroidItalic.ttf
Normal file
BIN
src/kekengine/res/font/JupiteroidItalic.ttf
Normal file
Binary file not shown.
BIN
src/kekengine/res/font/JupiteroidLight.ttf
Normal file
BIN
src/kekengine/res/font/JupiteroidLight.ttf
Normal file
Binary file not shown.
BIN
src/kekengine/res/font/JupiteroidLightItalic.ttf
Normal file
BIN
src/kekengine/res/font/JupiteroidLightItalic.ttf
Normal file
Binary file not shown.
BIN
src/kekengine/res/font/JupiteroidRegular.ttf
Normal file
BIN
src/kekengine/res/font/JupiteroidRegular.ttf
Normal file
Binary file not shown.
@ -1,5 +1,6 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "input.h"
|
||||||
#include "kekengine.h"
|
#include "kekengine.h"
|
||||||
#include <GL/glew.h>
|
#include <GL/glew.h>
|
||||||
#include <GLFW/glfw3.h>
|
#include <GLFW/glfw3.h>
|
||||||
@ -16,42 +17,24 @@
|
|||||||
using namespace kek;
|
using namespace kek;
|
||||||
|
|
||||||
static ButtonElement *button;
|
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) {
|
void onButtonClick(void *data) {
|
||||||
button->color = Colors::RED;
|
if(button->color == Colors::RED) {
|
||||||
button->hoverColor = Colors::ORANGE;
|
button->color = Colors::GREEN;
|
||||||
capture = Input::captureKeyboardInput(
|
button->hoverColor = Colors::GREEN.darker();
|
||||||
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 {
|
} else {
|
||||||
str.push_back(codepoint);
|
button->color = Colors::RED;
|
||||||
|
button->hoverColor = Colors::RED.darker();
|
||||||
}
|
}
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
@ -142,7 +125,7 @@ int main(int argc, char **argv) {
|
|||||||
button3->addChild(rect);
|
button3->addChild(rect);
|
||||||
UI::addElement(button3);
|
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);
|
UI::addElement(textField);
|
||||||
|
|
||||||
if(Engine::start() != KEK_SUCCESS) return 1;
|
if(Engine::start() != KEK_SUCCESS) return 1;
|
||||||
|
Loading…
Reference in New Issue
Block a user