diff --git a/src/kekengine/cpp/common/defaults.cpp b/src/kekengine/cpp/common/defaults.cpp index aa3340e..e4cef71 100644 --- a/src/kekengine/cpp/common/defaults.cpp +++ b/src/kekengine/cpp/common/defaults.cpp @@ -32,7 +32,7 @@ static void doUIMouseHover(double x, double y) { UIPoint hoveredAt = UIPoint((int) x - childPos.x, (int) y - childPos.y); UIBounds bounds = element->getBounds(); - if(!bounds.contains(hoveredAt)) continue; + if(!bounds.containsOffset(hoveredAt)) continue; hoveredElement = element; } @@ -58,7 +58,7 @@ static void doUIMouseClick(double x, double y, GLFWMouseButton button) { UIPoint clickedAt = UIPoint((int) x - childPos.x, (int) y - childPos.y); UIBounds bounds = element->getBounds(); - if(!bounds.contains(clickedAt)) continue; + if(!bounds.containsOffset(clickedAt)) continue; clickedElement = element; } diff --git a/src/kekengine/cpp/render/fonts.cpp b/src/kekengine/cpp/render/fonts.cpp index ac48239..0dbaaed 100644 --- a/src/kekengine/cpp/render/fonts.cpp +++ b/src/kekengine/cpp/render/fonts.cpp @@ -100,6 +100,8 @@ void TextObject::allocateBuffer(TextBlock *block, int numChars) { } TextMetrics TextObject::measureChars(std::u32string str, unsigned int offset, unsigned int length, std::map> *chars) { + // TODO: returned metrics are incorrect when there are multiple lines of text + if(offset != 0 || length != str.length()) { length = std::min(length, (unsigned int) (str.length() - offset)); str = str.substr(offset, length); diff --git a/src/kekengine/cpp/ui/ui.cpp b/src/kekengine/cpp/ui/ui.cpp index 8de1d86..095cba0 100644 --- a/src/kekengine/cpp/ui/ui.cpp +++ b/src/kekengine/cpp/ui/ui.cpp @@ -20,14 +20,20 @@ UIElement::~UIElement() { UI::unfocusElement(this); } -// Returns the element's position relative to its parent in pixels -UIPoint UIElement::getPosition() { +// 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)); } +// Returns the element's position relative to its parent in pixels (offset by getBounds()) +UIPoint UIElement::getPosition() { + UIBounds bounds = getBounds(); + return UIPoint(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 = getPosition(); + UIPoint pos = getOriginPosition(); if(parent) { UIPoint parentPos = parent->getScreenPosition(); pos.x += parentPos.x; @@ -119,11 +125,11 @@ UIBounds UIElement::offsetUIBounds(int w, int h, Origin origin) { void UIElement::drawAll(UIPoint screenPos, glm::mat4 projection) { if(!visible) return; + UIBounds bounds = getBounds(); + if(enableClipping) { glEnable(GL_SCISSOR_TEST); - UIPoint pos = getScreenPosition(); - UIBounds bounds = getBounds(); - glScissor(pos.x, kekData.screenHeight - (pos.y + bounds.h), bounds.w, bounds.h); + glScissor(screenPos.x, kekData.screenHeight - (screenPos.y + bounds.h), bounds.w, bounds.h); } draw(screenPos, projection); @@ -145,7 +151,7 @@ void UIElement::hoverAll(UIPoint pos, UIPoint screenPos) { int relX = pos.x - childPos.x; int relY = pos.y - childPos.y; UIBounds b = child->getBounds(); - if(!b.contains(UIPoint(relX, relY))) continue; + if(!b.containsOffset(UIPoint(relX, relY))) continue; hoveredChild = child; } @@ -179,7 +185,7 @@ bool UIElement::clickAll(UIPoint pos, UIPoint screenPos, GLFWMouseButton button) int relX = pos.x - childPos.x; int relY = pos.y - childPos.y; UIBounds b = child->getBounds(); - if(!b.contains(UIPoint(relX, relY))) continue; + if(!b.containsOffset(UIPoint(relX, relY))) continue; clickedChild = child; } @@ -203,7 +209,7 @@ bool UIElement::focusEnterAll(UIPoint pos, UIPoint screenPos) { int relX = pos.x - childPos.x; int relY = pos.y - childPos.y; UIBounds b = child->getBounds(); - if(!b.contains(UIPoint(relX, relY))) continue; + if(!b.containsOffset(UIPoint(relX, relY))) continue; focusedChild = child; } @@ -230,7 +236,7 @@ UIElement *UIElement::dragEnterAll(UIPoint pos, UIPoint screenPos) { int relX = pos.x - childPos.x; int relY = pos.y - childPos.y; UIBounds b = child->getBounds(); - if(!b.contains(UIPoint(relX, relY))) continue; + if(!b.containsOffset(UIPoint(relX, relY))) continue; draggedChild = child; } diff --git a/src/kekengine/cpp/ui/uielements.cpp b/src/kekengine/cpp/ui/uielements.cpp index c724cd0..ed07439 100644 --- a/src/kekengine/cpp/ui/uielements.cpp +++ b/src/kekengine/cpp/ui/uielements.cpp @@ -39,23 +39,21 @@ UIElementType TextElement::getType() { UIBounds TextElement::getBounds() { TextMetrics metrics = text->getMetrics(sizePixels); - int w = metrics.width, h, offsetY = 0; + int w = metrics.width, h; switch(textBounds) { case TextBounds::SMALLEST: default: h = metrics.height; - offsetY = metrics.offsetY; break; case TextBounds::LINE: FontMetrics metrics = text->getFont()->getMetrics(sizePixels); h = metrics.lineHeight; - offsetY = metrics.ascender; break; } switch(textMode) { case TextMode::BASELINE: - return UIBounds(offsetX(w, origin), -offsetY, w, h); + return UIBounds(offsetX(w, origin), 0, w, h); case TextMode::ORIGIN: default: return offsetUIBounds(w, h, origin); @@ -71,22 +69,20 @@ std::string TextElement::getText() { } void TextElement::draw(UIPoint screenPos, glm::mat4 projection) { - UIBounds offset = getBounds(); - switch(textMode) { case TextMode::BASELINE: - text->getFont()->drawText(text, projection, offset.x + screenPos.x, screenPos.y, sizePixels, color); + text->getFont()->drawText(text, projection, screenPos.x, screenPos.y, sizePixels, color); break; case TextMode::ORIGIN: switch(textBounds) { case TextBounds::SMALLEST: default: - text->getFont()->drawTextFromOrigin(text, projection, offset.x + screenPos.x, offset.y + screenPos.y, sizePixels, color); + text->getFont()->drawTextFromOrigin(text, projection, screenPos.x, screenPos.y, sizePixels, color); break; case TextBounds::LINE: FontMetrics metrics = text->getFont()->getMetrics(sizePixels); int offsetY = metrics.ascender; - text->getFont()->drawText(text, projection, offset.x + screenPos.x, offset.y + screenPos.y + offsetY, sizePixels, color); + text->getFont()->drawText(text, projection, screenPos.x, screenPos.y + offsetY, sizePixels, color); break; } diff --git a/src/kekengine/include/ui.h b/src/kekengine/include/ui.h index f20279b..5d869b4 100644 --- a/src/kekengine/include/ui.h +++ b/src/kekengine/include/ui.h @@ -31,9 +31,15 @@ struct UIBounds { w(w), h(h) {} + // Checks if a point is contained in the bounds inline bool contains(UIPoint 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) { + return pos.x > 0 && pos.y > 0 && pos.x < w && pos.y < h; + } }; enum class UIElementType { @@ -149,7 +155,10 @@ class UIElement { virtual UIElementType getType() = 0; - // Returns the element's position relative to its parent in pixels + // Returns the element's origin position relative to its parent in pixels (not offset by getBounds()) + UIPoint getOriginPosition(); + + // Returns the element's position relative to its parent in pixels (offset by getBounds()) UIPoint getPosition(); // Returns the element's origin position on the screen in pixels (not offset by getBounds()) diff --git a/src/kekgame/cpp/kekgame.cpp b/src/kekgame/cpp/kekgame.cpp index 833c402..c1f75a9 100644 --- a/src/kekgame/cpp/kekgame.cpp +++ b/src/kekgame/cpp/kekgame.cpp @@ -1,5 +1,6 @@ #include +#include "color.h" #include "input.h" #include "kekengine.h" #include @@ -128,7 +129,13 @@ int main(int argc, char **argv) { button3->addChild(rect); UI::addElement(button3); - TextFieldElement *textField = new TextFieldElement(uiPx(10), uiPx(200), uiPx(500)); + RectangleElement *rect2 = new RectangleElement(uiPx(0), uiSh(0.5), uiPx(500), uiPx(250)); + rect2->origin = Origin::LEFT_CENTER; + rect2->enableClipping = true; + UI::addElement(rect2); + + TextFieldElement *textField = new TextFieldElement(uiPx(0), uiPh(1) - uiPx(10), uiPx(500)); + textField->origin = kek::Origin::BOTTOM_LEFT; textField->color = Colors::GREEN; textField->focusColor = Colors::RED; textField->textElement->color = Colors::WHITE; @@ -152,11 +159,18 @@ int main(int argc, char **argv) { ep->t->onSubmit = SubmitCallback(); }, &e); - UI::addElement(textField); + rect2->addChild(textField); - TextElement *text = new TextElement(uiPx(10), uiPx(260)); - text->setText("Lorem ipsum\ndolor sit amet\nsussy amogus, KekEngine sample text\nWhen the impostor is\nAmogus"); - UI::addElement(text); + TextElement *text = new TextElement(uiPx(0), uiPx(0)); + text->setText("Lorem ipsum dolorg"); + text->textMode = TextMode::ORIGIN; + text->textBounds = TextBounds::SMALLEST; + + UIBounds bounds = text->getBounds(); + RectangleElement *box = new RectangleElement(uiPx(bounds.x), uiPx(bounds.y), uiPx(bounds.w), uiPx(bounds.h)); + box->color = Colors::GRAY; + rect2->addChild(box); + rect2->addChild(text); if(Engine::start() != KEK_SUCCESS) return 1; return 0;