diff --git a/src/Log.cpp b/src/Log.cpp index 2b2181dabbe92d995793090240eb507b8ce4e89a..fe335622bd571b35b1d37360977139c5b0c85f80 100644 --- a/src/Log.cpp +++ b/src/Log.cpp @@ -24,7 +24,7 @@ namespace { loggerCache.insert(newEntry); } return loggerCache[lt](); -} + } } Logger::Logger() : diff --git a/src/URL.cpp b/src/URL.cpp index 0efc3bcc9fc3279a985376777c8fd9bd7d29c914..6e6776ec324eaca4dfb2097a64003e2801045722 100644 --- a/src/URL.cpp +++ b/src/URL.cpp @@ -102,7 +102,7 @@ std::tuple<std::unique_ptr<URL>,enum URIParseError> parseUri(std::string raw) { last = cursor + 1; state = AUTHORITY; if (uri->scheme == "file") { - std::cout << "file scheme, current path[" << uri->path << "]" << std::endl; + //std::cout << "URL:::parseUri file scheme, current path[" << uri->path << "]" << std::endl; state = PATH; } } else { diff --git a/src/graphics/components/BoxComponent.cpp b/src/graphics/components/BoxComponent.cpp index 72d764e18ec5e03d7315f68d00ed44ab90b829eb..5373131450d16e28ae9c4b5e0606ca2ad35c180f 100644 --- a/src/graphics/components/BoxComponent.cpp +++ b/src/graphics/components/BoxComponent.cpp @@ -151,6 +151,26 @@ void BoxComponent::render() { // can actuall delete vertices here } +void BoxComponent::changeColor(const unsigned int hexColor) { + // really a texture swap + + // set texture color + data[0][0][0] = (hexColor >> 24) & 0xFF; + data[0][0][1] = (hexColor >> 16) & 0xFF; + data[0][0][2] = (hexColor >> 8) & 0xFF; + data[0][0][3] = (hexColor >> 0) & 0xFF; + + glBindVertexArray(vertexArrayObject); + + // now replace existing texture + glBindTexture(GL_TEXTURE_2D, texture); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + glGenerateMipmap(GL_TEXTURE_2D); + + glBindVertexArray(0); // unbind to prevent anything from accidentally changing it +} + // this seems to work 17-08-10 // for box // anime girl, we'll get aspect ratio breakage @@ -158,7 +178,7 @@ void BoxComponent::resize(const int passedWindowWidth, const int passedWindowHei //std::cout << "BoxComponent::resize" << std::endl; windowWidth = passedWindowWidth; windowHeight = passedWindowHeight; - + //std::cout << "BoxComponent::resize - boundToPage " << boundToPage << std::endl; // figure out new vertices float vx = x; @@ -185,77 +205,3 @@ void BoxComponent::resize(const int passedWindowWidth, const int passedWindowHei verticesDirty = true; } - -void BoxComponent::changeColor(const unsigned int hexColor) { - // really a texture swap - - // set texture color - data[0][0][0] = (hexColor >> 24) & 0xFF; - data[0][0][1] = (hexColor >> 16) & 0xFF; - data[0][0][2] = (hexColor >> 8) & 0xFF; - data[0][0][3] = (hexColor >> 0) & 0xFF; - - glBindVertexArray(vertexArrayObject); - - // now replace existing texture - glBindTexture(GL_TEXTURE_2D, texture); - - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); - glGenerateMipmap(GL_TEXTURE_2D); - - glBindVertexArray(0); // unbind to prevent anything from accidentally changing it -} - -/* -void BoxComponent::resize(const int passedWindowWidth, const int passedWindowHeight) { - - std::cout << "BoxComponent::resize" << std::endl; - windowWidth = passedWindowWidth; - windowHeight = passedWindowHeight; - - if (boundToPage) { - std::cout << "BoxComponent::resize - boundToPage doing nothing" << std::endl; - } else { - - // figure out our percentages - // 0 / WW = 0 - // 768 / 1024 = 75% - float xPer = initialX / (float)initialWindowWidth; - float yPer = initialY / (float)initialWindowHeight; - // adjust width - float wPer = initialWidth / (float)initialWindowWidth; - //float hPer = initialHeight / (float)initialWindowHeight; - - float vx = xPer * windowWidth; - float vy = yPer * windowHeight; - - // nah I don't think we want things to stretch - //float vWidth = wPer * windowWidth; - //float vHeight = hPer * windowHeight; - - // ugh these just need to be relaid out - //float vWidth = width; - float vWidth = wPer * windowWidth; - float vHeight = height; - - //std::cout << "initial: " << initialX << "x" << initialY << " size: " << initialWidth << "x" << initialHeight << " window size: " << initialWindowWidth << "x" << initialWindowHeight << std::endl; - - //std::cout << "scaled to: " << (int)vx << "x" << (int)vy << " size: " << (int)vWidth << "x" << (int)vHeight << " window size: " << windowWidth << "x" << windowHeight << std::endl; - - - pointToViewport(vx, vy); - distanceToViewport(vWidth, vHeight); - - vertices[(0 * 5) + 0] = vx; - vertices[(0 * 5) + 1] = vy + vHeight; - vertices[(1 * 5) + 0] = vx + vWidth; - vertices[(1 * 5) + 1] = vy + vHeight; - vertices[(2 * 5) + 0] = vx + vWidth; - vertices[(2 * 5) + 1] = vy; - vertices[(3 * 5) + 0] = vx; - vertices[(3 * 5) + 1] = vy; - - verticesDirty = true; - } -} -*/ diff --git a/src/graphics/components/Component.cpp b/src/graphics/components/Component.cpp index 27700f4d78326d2461f1b60c9c11fc522902dd91..e9d57f917ad546960a372e7f61bee17bc39feb25 100644 --- a/src/graphics/components/Component.cpp +++ b/src/graphics/components/Component.cpp @@ -107,7 +107,7 @@ void Component::layout() { std::cout << "Component::layout[" << textComponent->text << "]" << std::endl; } */ - //std::cout << "Component::layout - name: " << name << " boundToPage: " << boundToPage << std::endl; + //std::cout << "Component::layout - name: " << name << " type " << typeOfComponent(this) << " boundToPage: " << boundToPage << std::endl; // if we're a child, get our parents position if (parent && boundToPage) { @@ -216,6 +216,7 @@ void Component::layout() { // resize/wordwrap to available width // our position is required void Component::wrap() { + //std::cout << "Component::wrap - " << typeOfComponent(this) << std::endl; float lW = width; float lH = height; resize(windowWidth, windowHeight); // this may change our w/h @@ -232,6 +233,7 @@ void Component::wrap() { // measure current, apply changes to parent // our size is required void Component::updateParentSize() { + //std::cout << "Component::updateParentSize - " << typeOfComponent(this) << std::endl; if (!parent) { //std::cout << "Component::updateParentSize - can't update parent size, no parent" << std::endl; return; @@ -246,7 +248,6 @@ void Component::updateParentSize() { // find max width of all siblings unsigned int maxWidth = width; // float? unsigned int heightAccum = 0; - bool wasInline = false; unsigned int totalHeight = 0; // integrity check @@ -257,6 +258,7 @@ void Component::updateParentSize() { } // look at siblings + bool wasInline = false; for (std::shared_ptr<Component> child : parent->children) { maxWidth = std::max(maxWidth, static_cast<unsigned int>(child->width)); if (child->isInline) { @@ -421,7 +423,7 @@ void Component::printComponentTree(const std::shared_ptr<Component> &component, } InputComponent *inputComponent = dynamic_cast<InputComponent*>(component.get()); if (inputComponent) { - std::cout << std::fixed << "X: " << static_cast<int>(inputComponent->x) << " Y: " << static_cast<int>(inputComponent->y) << " WIDTH: " << static_cast<int>(inputComponent->width) << " HEIGHT: " << static_cast<int>(inputComponent->height) << " INLINE: " << inputComponent->isInline << " INPUT: " << inputComponent->value << std::endl; + std::cout << std::fixed << "X: " << static_cast<int>(inputComponent->x) << " Y: " << static_cast<int>(inputComponent->y) << " WIDTH: " << static_cast<int>(inputComponent->width) << " HEIGHT: " << static_cast<int>(inputComponent->height) << " INLINE: " << inputComponent->isInline << " Bound: " << inputComponent->boundToPage << " INPUT: " << inputComponent->value << std::endl; } else { TextComponent *textComponent = dynamic_cast<TextComponent*>(component.get()); if (textComponent) { diff --git a/src/graphics/components/Component.h b/src/graphics/components/Component.h index 2440a444e61940f2c53c37f4f89d1cacdf4334b3..ceb544c5dce73f3cdccedb323bb19907bdf91efa 100644 --- a/src/graphics/components/Component.h +++ b/src/graphics/components/Component.h @@ -167,7 +167,10 @@ public: std::function<void(int x, int y)> onMouseup = nullptr; std::function<void(int x, int y)> onMousemove = nullptr; std::function<void(int x, int y)> onWheel = nullptr; + // https://www.quirksmode.org/dom/events/keys.html std::function<void(int key, int scancode, int action, int mods)> onKeyup = nullptr; + // "Fires when an actual character is being inserted in, for instance, a text input. It repeats while the user keeps the key depressed." + std::function<void(int key, int scancode, int action, int mods)> onKeyPress = nullptr; std::function<void()> onClick = nullptr; std::function<void()> onFocus = nullptr; std::function<void()> onBlur = nullptr; diff --git a/src/graphics/components/ComponentBuilder.cpp b/src/graphics/components/ComponentBuilder.cpp index 07c187c6a387e772dc982c22aaf7bedf868749ce..819eef603d868b9da7739e7b20413f3ed4a0fbb6 100644 --- a/src/graphics/components/ComponentBuilder.cpp +++ b/src/graphics/components/ComponentBuilder.cpp @@ -95,6 +95,8 @@ std::shared_ptr<Component> ComponentBuilder::build(const std::shared_ptr<Node> n if (inputComponent) { // any input set up we need to do? // boundToPage defaults to true for components, InputComponent doesn't have it overridded + //std::cout << "Just built an inputComponent" << std::endl; + inputComponent->win = window.get(); } //std::cout << "composting component, initial: " << (int)component->width << "x" << (int)component->height << std::endl; @@ -123,7 +125,10 @@ std::shared_ptr<Component> ComponentBuilder::build(const std::shared_ptr<Node> n std::cout << "ComponentBuilder::build - Just laid out input component" << std::endl; } */ - + // not sure why only this component needs this but it fixes it + if (inputComponent) { + inputComponent->updateParentSize(); + } //std::cout << "post layout placed: " << (int)component->x << "x" << (int)component->y << " w/h: " << (int)component->width << "x" << (int)component->height << std::endl; return component; } @@ -148,3 +153,20 @@ std::string typeOfComponent(const std::shared_ptr<Component> &component) { if (boxComponent) return "box"; return ""; } + +std::string typeOfComponent(Component *component) { + TabbedComponent *tabComponent = dynamic_cast<TabbedComponent*>(component); + if (tabComponent) return "tab"; + DocumentComponent *docComponent = dynamic_cast<DocumentComponent*>(component); + if (docComponent) return "doc"; + TextComponent *textComponent = dynamic_cast<TextComponent*>(component); + if (textComponent) return "text"; + InputComponent *inputComponent = dynamic_cast<InputComponent*>(component); + if (inputComponent) return "input"; + AnimeComponent *animeComponent = dynamic_cast<AnimeComponent*>(component); + if (animeComponent) return "anime"; + BoxComponent *boxComponent = dynamic_cast<BoxComponent*>(component); + if (boxComponent) return "box"; + return ""; +} + diff --git a/src/graphics/components/ComponentBuilder.h b/src/graphics/components/ComponentBuilder.h index ea6f79e0f8693dd779e9529e201c7ac5233abf15..b735b32cc037934a72e19ce58408966f9407c68c 100644 --- a/src/graphics/components/ComponentBuilder.h +++ b/src/graphics/components/ComponentBuilder.h @@ -21,5 +21,6 @@ public: // getComponentType std::string typeOfComponent(const std::shared_ptr<Component> &component); +std::string typeOfComponent(Component *component); #endif diff --git a/src/graphics/components/DocumentComponent.cpp b/src/graphics/components/DocumentComponent.cpp index 9a4f838cacc614e117eab19ffb8f17aba54dcb73..3535fd6c2693f0b33427bb9764ec9c662e034658 100644 --- a/src/graphics/components/DocumentComponent.cpp +++ b/src/graphics/components/DocumentComponent.cpp @@ -111,7 +111,7 @@ DocumentComponent::DocumentComponent(const float rawX, const float rawY, const f //this->renderDirty = true; }; onMousedown=[this](int passedX, int passedY) { - std::cout << "document left press" << std::endl; + //std::cout << "document left press" << std::endl; if (this->hoverComponent) { if (this->focusedComponent != this->hoverComponent) { // blur old component @@ -133,7 +133,7 @@ DocumentComponent::DocumentComponent(const float rawX, const float rawY, const f } }; onMouseup=[this](int passedX, int passedY) { - std::cout << "document left release" << std::endl; + //std::cout << "document left release" << std::endl; if (this->hoverComponent) { //std::cout << "DocumentComponent::DocumentComponent:onMouseup - hovering over " << typeOfComponent(this->hoverComponent) << " component" << std::endl; if (this->focusedComponent != this->hoverComponent) { @@ -149,6 +149,7 @@ DocumentComponent::DocumentComponent(const float rawX, const float rawY, const f } } this->focusedComponent = this->hoverComponent; + //std::cout << "DocumentComponent::DocumentComponent:onMouseup - hovering over " << typeOfComponent(this->hoverComponent) << " component, focused on " << typeOfComponent(this->focusedComponent) << std::endl; if (this->focusedComponent->onMouseup) { //std::cout << "click event" << std::endl; this->focusedComponent->onMouseup(passedX, passedY); @@ -160,7 +161,7 @@ DocumentComponent::DocumentComponent(const float rawX, const float rawY, const f } }; onKeyup=[this](int key, int scancode, int action, int mods) { - //std::cout << "DocumentComponent::DocumentComponent:onKeyup" << std::endl; + //std::cout << "DocumentComponent::DocumentComponent:onKeyup" << typeOfComponent(this->focusedComponent) << std::endl; InputComponent *inputComponent = dynamic_cast<InputComponent*>(this->focusedComponent.get()); if (inputComponent) { //std::cout << "inputComponent is focused, key pressed " << key << " action: " <<action << std::endl; @@ -318,7 +319,7 @@ std::shared_ptr<Component> DocumentComponent::searchComponentTree(const std::sha if (-component->y < passedY && -component->y + component->height > passedY) { //std::cout << "DocumentComponent::searchComponentTree - x search: " << static_cast<int>(component->x) << "<" << static_cast<int>(passedX) << "<" << static_cast<int>(component->x + component->width) << std::endl; if (component->x < passedX && component->x + component->width > passedX) { - //std::cout << "hit " << typeOfComponent(component) << std::endl; + //std::cout << "DocumentComponent::searchComponentTree - hit " << typeOfComponent(component) << std::endl; return component; } } diff --git a/src/graphics/components/InputComponent.cpp b/src/graphics/components/InputComponent.cpp index 06757ad21707800682d0e38de20b577d0a058ed1..dc9d326efc1d433ad13303f8acbe659f8ba31ad6 100644 --- a/src/graphics/components/InputComponent.cpp +++ b/src/graphics/components/InputComponent.cpp @@ -1,14 +1,15 @@ #include "InputComponent.h" #include <iostream> -#include "../opengl/Window.h" #include "../text/TextRasterizerCache.h" +#include "../../scheduler.h" extern TextRasterizerCache *rasterizerCache; +extern std::unique_ptr<Scheduler> scheduler; // : BoxComponent(rawX, rawY, rawWidth, rawHeight, passedWindowWidth, passedWindowHeight) InputComponent::InputComponent(const float rawX, const float rawY, const float rawWidth, const float rawHeight, const int passedWindowWidth, const int passedWindowHeight) { - //std::cout << "InputComponent::InputComponent - data" << std::endl; + //std::cout << "InputComponent::InputComponent - create, boundToPage" << boundToPage << std::endl; //std::cout << "InputComponent::InputComponent - window: " << windowWidth << "x" << windowHeight << " passed " << passedWindowWidth << "x" << passedWindowHeight << std::endl; //boundToPage = true; @@ -17,12 +18,41 @@ InputComponent::InputComponent(const float rawX, const float rawY, const float r // set up state windowWidth = passedWindowWidth; windowHeight = passedWindowHeight; + // lets not set, like resize set, and then maybe parent width will be correct + // didn't really changed anything width = rawWidth; height = rawHeight; // ugh x = rawX; y = rawY; lastRenderedWindowHeight = windowHeight; + + // const float rawX, const float rawY, const float rawWidth, const float rawHeight, const unsigned int hexColor, const int passedWindowWidth, const int passedWindowHeight + this->cursorBox = new BoxComponent(x, y, 2, rawHeight, 0x000000FF, windowWidth, windowHeight); + this->cursorBox->boundToPage = this->boundToPage; + + this->cursorBox->x = x; + this->cursorBox->y = y; + if (boundToPage) { + this->cursorBox->y = this->windowHeight + y - 13; + } + this->cursorBox->resize(this->windowWidth, this->windowHeight); + this->updateText(); + + onFocus=[this]() { + this->focused = true; + this->cursorBox->x = x ; + this->cursorBox->y = y; + if (this->boundToPage) { + this->cursorBox->y = this->windowHeight + y - 13; + } + this->cursorBox->resize(this->windowWidth, this->windowHeight); + this->win->renderDirty = true; + }; + onBlur=[this]() { + this->focused = false; + this->win->renderDirty = true; + }; //std::cout << "InputComponent::InputComponent - placing box at " << (int)x << "," << (int)y << " size: " << (int)width << "x" << (int)height << std::endl; @@ -90,7 +120,8 @@ InputComponent::InputComponent(const float rawX, const float rawY, const float r } void InputComponent::render() { - //std::cout << "InputComponent::render" << std::endl; + //std::cout << "InputComponent::render - at " << (int)x << "," << (int)y << std::endl; + //std::cout << "InputComponent::render - boundToPage " << boundToPage << std::endl; GLenum glErr=glGetError(); if(glErr != GL_NO_ERROR) { std::cout << "InputComponent::render - start not ok: " << glErr << std::endl; @@ -135,6 +166,7 @@ void InputComponent::render() { if(glErr != GL_NO_ERROR) { std::cout << "InputComponent::render - glGetUniformLocation not ok: " << glErr << std::endl; } + // it's about the document transformMatrix glUniformMatrix4fv(transformLocation, 1, GL_FALSE, window->transformMatrix); glErr=glGetError(); if(glErr != GL_NO_ERROR) { @@ -145,10 +177,26 @@ void InputComponent::render() { userInputText->render(); glUseProgram(window->textureProgram); } + if (focused) { + //std::cout << "Rendering cursor" << std::endl; + + // blink cursor + if (cursorTimer != nullptr) { + scheduler->clearInterval(cursorTimer); + } + cursorTimer = scheduler->setInterval([this]() { + this->showCursor = !this->showCursor; + //std::cout << "showCursor " << this->showCursor << std::endl; + this->win->renderDirty = true; + }, 500); + + // render it if we need to + if (showCursor) { + cursorBox->render(); + } + } } -// this doesn't seem to work -// text is fine though void InputComponent::resize(const int passedWindowWidth, const int passedWindowHeight) { //std::cout << "InputComponent::resize" << std::endl; //std::cout << "InputComponent::resize - rasterizing at " << (int)x << "x" << (int)y << " size: " << (int)width << "x" << (int)height << std::endl; @@ -157,7 +205,9 @@ void InputComponent::resize(const int passedWindowWidth, const int passedWindowH // set up state windowWidth = passedWindowWidth; windowHeight = passedWindowHeight; - + + //std::cout << "InputComponent::resize - boxShader: " << useBoxShader << " boundToPage: " << boundToPage << std::endl; + /* if (!boundToPage) { // ok because box shader is anchored to the bottom of the screen @@ -184,25 +234,11 @@ void InputComponent::resize(const int passedWindowWidth, const int passedWindowH float vx = x; float vy = y; - //float vx1 = x + width; - //float vy1 = y - height; - /* - std::cout << "placing box at " << (int)vx << "," << (int)vy << " size: " << (int)width << "x" << (int)height << " v1: " << (int)vx1 << "," << (int)vy1 << std::endl; - //float vWidth = width; - //float vHeight = height; - boundToPage = true; - pointToViewport(vx, vy); - pointToViewport(vx1, vy1); - std::cout << "TRUE placing box at GL v: " << vx << "," << vy << " v1: " << vx1 << "," << vy1 << std::endl; - - vx = x; - vy = y; - vx1 = x + width; - vy1 = y - height; - boundToPage = false; - */ + if (boundToPage) { + vy = this->windowHeight + y - height; + //std::cout << "InputComponent::resize - Adjust y to " << vy << " from " << y << " h: " << (int)height << std::endl; + } pointToViewport(vx, vy); - //pointToViewport(vx1, vy1); float vWidth = width; float vHeight = height; @@ -210,15 +246,8 @@ void InputComponent::resize(const int passedWindowWidth, const int passedWindowH float vx1 = vx + vWidth; float vy1 = vy + vHeight; - //std::cout << "FALSE placing box at GL v: " << vx << "," << vy << " v1: " << vx1 << "," << vy1 << std::endl; //std::cout << "InputComponent::resize - placing box at GL " << vx << "," << vy << " to " << vx1 << "," << vy1 << " size: " << vWidth << "x" << vHeight << std::endl; - // converts 512 to 1 and 1 to 2 - //std::cout << "vWidth before: " << (int)vWidth << std::endl; - //distanceToViewport(vWidth, vHeight); - //std::cout << "vWidth after: " << (int)vWidth << std::endl; - - vertices[(0 * 5) + 0] = vx; vertices[(0 * 5) + 1] = vy1; @@ -232,19 +261,15 @@ void InputComponent::resize(const int passedWindowWidth, const int passedWindowH vertices[(3 * 5) + 1] = vy; glBindVertexArray(vertexArrayObject); - glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); - - //glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBufferObject); - //glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); - - glBindVertexArray(0); // protect what we created against any further modification //updateText(); if (userInputText) { + // do we need updateText here? userInputText->resize(passedWindowWidth, passedWindowHeight); + } } @@ -273,6 +298,7 @@ void InputComponent::updateText() { } else { userInputText->y = y - windowHeight + 16; } + userInputText->boundToPage = this->boundToPage; //std::cout << "placed userInputText at " << static_cast<int>(x) << "," << static_cast<int>(y - windowHeight) << std::endl; // 125 pixels width // but first we need to know how wide the text is @@ -299,6 +325,16 @@ void InputComponent::updateText() { //std::cout << "scrolling text" << std::endl; userInputText->rasterStartX = estWidth - width; } + // this is texture shader coordinates now (not text shader coords) + cursorBox->x = x + estWidth; + if (boundToPage) { + cursorBox->y = windowHeight + y - 13; + } else { + cursorBox->y = y; + } + //std::cout << "placing cursor at " << (int)cursorBox->x << "," << (int)cursorBox->y << std::endl; + cursorBox->resize(windowWidth, windowHeight); + userInputText->noWrap = true; // why does changing the width mess shit up? //std::cout << "InputComponent::updateText - our width: " << static_cast<int>(width) << " windowWidth: " << windowWidth << std::endl; diff --git a/src/graphics/components/InputComponent.h b/src/graphics/components/InputComponent.h index 3e7a7b5273e2f77b6cba14cf680fd1a456615794..e6e0d778a4835dba01d7a8097a2f766b9ecb66be 100644 --- a/src/graphics/components/InputComponent.h +++ b/src/graphics/components/InputComponent.h @@ -6,6 +6,7 @@ #include "BoxComponent.h" #include "TextComponent.h" #include "../opengl/Window.h" +#include "../../scheduler.h" class Window; @@ -22,9 +23,13 @@ public: void updateText(); std::string value=""; TextComponent *userInputText = nullptr; + BoxComponent *cursorBox = nullptr; std::function<void(std::string value)> onEnter = nullptr; // needed for our shader's resizing int lastRenderedWindowHeight; + bool focused = false; + bool showCursor = true; + std::shared_ptr<timer_handle> cursorTimer = nullptr; // handle to signal that a redraw is needed, and access to shader programs Window *win; }; diff --git a/src/graphics/components/MultiComponent.cpp b/src/graphics/components/MultiComponent.cpp index 7b1e6458229aa5ecf664cf599ffef37ef57df99d..ba44b4fbb25b94893cc3598a1a82a1504ffe1408 100644 --- a/src/graphics/components/MultiComponent.cpp +++ b/src/graphics/components/MultiComponent.cpp @@ -111,7 +111,16 @@ MultiComponent::MultiComponent(const float rawX, const float rawY, const float r // should we mark win->renderDirty = true? }; onKeyup=[this](int key, int scancode, int action, int mods) { - //std::cout << "MultiComponent::MultiComponent:onKeyup" << std::endl; + //std::cout << "MultiComponent::MultiComponent:onKeyup - focused on " << typeOfComponent(this->focusedComponent) << std::endl; + DocumentComponent *docComponent = dynamic_cast<DocumentComponent*>(this->focusedComponent.get()); + if (docComponent) { + if (action == 0) { + if (docComponent->onKeyup) { + docComponent->onKeyup(key, scancode, action, mods); + } + } + return; + } InputComponent *inputComponent = dynamic_cast<InputComponent*>(this->focusedComponent.get()); if (inputComponent) { //std::cout << "inputComponent is focused, key pressed " << key << " action: " <<action << std::endl; @@ -216,12 +225,12 @@ void MultiComponent::render() { GLint transformLocation = glGetUniformLocation(win->fontProgram, "transform"); GLenum glErr=glGetError(); if(glErr != GL_NO_ERROR) { - std::cout << "InputComponent::render - glGetUniformLocation not ok: " << glErr << std::endl; + std::cout << "MultiComponent::render - glGetUniformLocation not ok: " << glErr << std::endl; } glUniformMatrix4fv(transformLocation, 1, GL_FALSE, win->transformMatrix); glErr=glGetError(); if(glErr != GL_NO_ERROR) { - std::cout << "InputComponent::render - glUniformMatrix4fv not ok: " << glErr << std::endl; + std::cout << "MultiComponent::render - glUniformMatrix4fv not ok: " << glErr << std::endl; } } renderComponents(rootComponent); @@ -294,7 +303,7 @@ void MultiComponent::renderBoxComponents(std::shared_ptr<Component> component) { void MultiComponent::renderComponentType(std::string str, std::shared_ptr<Component> component) { if (!component) { - std::cout << "Window::renderComponentType - got null passed" << std::endl; + std::cout << "MultiComponent::renderComponentType - got null passed" << std::endl; return; } if (typeOfComponent(component) == str) { diff --git a/src/graphics/components/MultiComponent.h b/src/graphics/components/MultiComponent.h index 9cba4faa19a83700391bd46b4ac366b4a339d356..e58d42429638977a9fb45ac0660d48bcc8882aec 100644 --- a/src/graphics/components/MultiComponent.h +++ b/src/graphics/components/MultiComponent.h @@ -50,6 +50,6 @@ public: double cursorY = 0; }; -extern const std::unique_ptr<Window> window; +//extern const std::unique_ptr<Window> window; #endif diff --git a/src/graphics/components/TabbedComponent.cpp b/src/graphics/components/TabbedComponent.cpp index e84cdbe16314e0ab78fd9f32947a7681f20e68fd..d38a68738699a06ffb8b76f77d30e7a1556abf91 100644 --- a/src/graphics/components/TabbedComponent.cpp +++ b/src/graphics/components/TabbedComponent.cpp @@ -355,11 +355,11 @@ void TabbedComponent::selectTab(std::shared_ptr<Tab> tab) { // we're not going to do a full set up uiContorl, we'll expect those to be set up and just adjust them // but then, we can't just call this to place things where we want in the cstr... hrm.. void TabbedComponent::layoutTab(std::vector<std::shared_ptr<Tab>>::iterator tab) { - std::cout << "TabbedComponent::layoutTab - id: " << tab->get()->id << std::endl; + //std::cout << "TabbedComponent::layoutTab - id: " << tab->get()->id << std::endl; // find text TextComponent *textComponent = tab->get()->titleBox.get(); if (!textComponent) { - std::cout << "TabbedComponent::loadDomIntoTab - titleBox isn't a TextComponent" << std::endl; + std::cout << "TabbedComponent::layoutTab - titleBox isn't a TextComponent" << std::endl; return; } @@ -369,13 +369,13 @@ void TabbedComponent::layoutTab(std::vector<std::shared_ptr<Tab>>::iterator tab) //Tab *prev = it->get(); Tab *prev = tab->get()->previousTab.get(); if (prev == nullptr) { - std::cout << "relaying out first tab, no prev" << std::endl; + //std::cout << "TabbedComponent::layoutTab - relaying out first tab, no prev" << std::endl; //prev = nullptr; tab->get()->x = x + 32; // our start + 32px for new tab button } else { tab->get()->x = prev->x + static_cast<int>(prev->w); } - std::cout << "placing tab at " << tab->get()->x << std::endl; + //std::cout << "TabbedComponent::layoutTab - placing tab at " << tab->get()->x << std::endl; // get text size for it's current string // we don't always need to adjust textWidth, only on text change @@ -417,7 +417,7 @@ void TabbedComponent::layoutTab(std::vector<std::shared_ptr<Tab>>::iterator tab) // maybe take in a starting tab? as tabs to left aren't affected void TabbedComponent::layoutTabs(std::vector<std::shared_ptr<Tab>>::iterator startTab, int xAdj) { - std::cout << "TabbedComponent::layoutTabs - startId: " << startTab->get()->id << " xadj: " << xAdj << std::endl; + //std::cout << "TabbedComponent::layoutTabs - startId: " << startTab->get()->id << " xadj: " << xAdj << std::endl; // luckily only one component at a time changes, we'll need to know how much x shifted for(std::vector<std::shared_ptr<Tab>>::iterator it = startTab; it!=this->tabs.end(); ++it) { //it->get()->x += xAdj; // adjust position diff --git a/src/graphics/components/TextComponent.cpp b/src/graphics/components/TextComponent.cpp index a845488edaede0c21fbe946464954259100ae76d..60d3c39d9209a10b99a54288c046d6da451aead6 100644 --- a/src/graphics/components/TextComponent.cpp +++ b/src/graphics/components/TextComponent.cpp @@ -110,14 +110,11 @@ void TextComponent::rasterize(const int rawX, const int rawY) { //glyphs = textRasterizer->rasterize(text, rawX, windowWidth, wrapToX, width, height, glyphCount, endingX, endingY, wrapped); rasterizationRequest request; request.text = text; - // startX needs to be relative to the parent x. Why? - // I think for non-boundComponents request.startX = rawX; // - x - /* if (!boundToPage) { + // startX needs to be relative to the parent x. Why? request.startX -= x; } - */ //std::cout << "TextComponent::rasterize - [" << text << "] request.startX: " << request.startX << " x: " << x << " rawX: " << rawX << std::endl; request.availableWidth = availableWidth; request.sourceStartX = rasterStartX; @@ -126,7 +123,8 @@ void TextComponent::rasterize(const int rawX, const int rawY) { //std::cout << "rasterizing [" << text << "] @" << rawX << " availableWidth: " << availableWidth << " sourceStartX: " << rasterStartX << " noWrap: " << noWrap << std::endl; std::shared_ptr<rasterizationResponse> response = textRasterizer->rasterize(request); if (response.get() == nullptr) { - std::cout << "TextComponent::rasterize - got nullptr from rasterizer" << std::endl; + // window could be minimized + //std::cout << "TextComponent::rasterize - got nullptr from rasterizer" << std::endl; return; } width = response->width; diff --git a/src/graphics/opengl/Window.cpp b/src/graphics/opengl/Window.cpp index b486406ace7eeabc3854d5bf1bef09bb786b285a..b7dce38c8ca73f9cd7db53041533f75fef0b9ea5 100644 --- a/src/graphics/opengl/Window.cpp +++ b/src/graphics/opengl/Window.cpp @@ -207,6 +207,7 @@ bool Window::init() { navAddressBar->uiControl.h = { 0, 24 }; // 24px navAddressBar->name = "navAddressBar"; navAddressBar->boundToPage = false; + navAddressBar->win = this; //navAddressBar->y = -48; // this works but breaks picking navAddressBar->value = currentURL.toString(); navAddressBar->updateText(); @@ -401,10 +402,12 @@ bool Window::initGLFW() { } } thiz->focusedComponent = thiz->hoverComponent; + /* InputComponent *inputComponent = dynamic_cast<InputComponent*>(thiz->focusedComponent.get()); if (inputComponent) { std::cout << "inputComponent focus" << std::endl; } + */ if (thiz->focusedComponent && thiz->focusedComponent->onMouseup) { //std::cout << "click event" << std::endl; thiz->focusedComponent->onMouseup(thiz->cursorX, thiz->cursorY); @@ -428,7 +431,25 @@ bool Window::initGLFW() { glfwSetKeyCallback(window, [](GLFWwindow *win, int key, int scancode, int action, int mods) { Window *thiz = reinterpret_cast<Window*>(glfwGetWindowUserPointer(win)); // we're focused on something + //std::cout << "glfwSetKeyCallback" << std::endl; if (thiz->focusedComponent) { + //std::cout << "glfwSetKeyCallback - focused on " << typeOfComponent(thiz->focusedComponent) << std::endl; + TabbedComponent *p_tabComponent = dynamic_cast<TabbedComponent*>(thiz->focusedComponent.get()); + if (p_tabComponent) { + // repeat or key up + if (action == 2 || action == 0) { + if (p_tabComponent->onKeyPress) { + p_tabComponent->onKeyPress(key, scancode, action, mods); + } + if (action == 0) { + if (p_tabComponent->onKeyup) { + p_tabComponent->onKeyup(key, scancode, action, mods); + } + } + } + return; + } + DocumentComponent *docComponent = dynamic_cast<DocumentComponent*>(thiz->focusedComponent.get()); if (docComponent) { if (action == 0) { @@ -526,7 +547,11 @@ bool Window::initGLFW() { } printf("\n\n"); } - + if (key == GLFW_KEY_F && action == GLFW_RELEASE) { + printf("Printing UI ComponentTree\n\n"); + Component::printComponentTree(thiz->rootComponent, 0); + printf("\n\n"); + } int yOffsetScroll = 1; if (key == GLFW_KEY_PAGE_UP && (action == GLFW_PRESS || action == GLFW_REPEAT)) { TabbedComponent *p_TabComponent = dynamic_cast<TabbedComponent*>(thiz->tabComponent.get()); @@ -634,7 +659,9 @@ bool Window::initGL() { } //std::cout << "OpenGL is set up" << std::endl; - + + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); + return true; } diff --git a/src/graphics/opengl/Window.h b/src/graphics/opengl/Window.h index 38ff8a39cb7babedbb74451ecd46258df452b1be..8d67109171b1719e12e458cfa1a82018c14d8b2f 100644 --- a/src/graphics/opengl/Window.h +++ b/src/graphics/opengl/Window.h @@ -39,6 +39,7 @@ public: void navTo(std::string url); // properties + int maxTextureSize = 0; float transformMatrix[16] = { 1, 0, 0, 0, 0, 1, 0, 0, diff --git a/src/graphics/text/TextRasterizer.cpp b/src/graphics/text/TextRasterizer.cpp index b1698f30b311195ce9c79e88e5cdcecb9a2a2e2d..735a46b6f52538042c5f58b8e0bb6ffefa7cbb4b 100644 --- a/src/graphics/text/TextRasterizer.cpp +++ b/src/graphics/text/TextRasterizer.cpp @@ -37,7 +37,10 @@ TextRasterizer::~TextRasterizer() { } std::unique_ptr<std::pair<int, int>> TextRasterizer::size(const rasterizationRequest &request) const { - + if (!request.availableWidth) { + // window is likely minimized, so no output + return nullptr; + } if (request.startX == request.availableWidth) { std::cout << "TextRasterizer::size - x [" << static_cast<int>(request.startX) << "] matches window width [" << static_cast<int>(request.availableWidth)<< "] for text[" << request.text << "] no room to render anything" << std::endl; return nullptr; @@ -151,6 +154,7 @@ std::unique_ptr<std::pair<int, int>> TextRasterizer::size(const rasterizationReq response->height = y1max; //std::cout << "adjusted:" << (int)width << "x" << (int)height << std::endl; } + // FIXME: how about endingX,Y? return std::make_unique<std::pair<int, int>>(std::pair<int, int>(response->width, response->height)); } @@ -310,12 +314,10 @@ std::unique_ptr<rasterizationResponse> TextRasterizer::rasterize(const rasteriza response->y1 = -response->height; //std::cout << "xd: " << static_cast<int>(response->x1-response->x0) << " yd: " << static_cast<int>(response->y0-response->y1) << std::endl; - GLint max; - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max); - std::cout << "Requesting texture of " << response->textureWidth << "x" << response->textureHeight << "max: " << max << std::endl; - if (response->textureHeight > static_cast<unsigned int>(max)) { + //std::cout << "Requesting texture of " << response->textureWidth << "x" << response->textureHeight << "max: " << win->maxTextureSize << std::endl; + if (response->textureHeight > static_cast<unsigned int>(win->maxTextureSize)) { std::cout << "Truncating text texture to fit in your video card" << std::endl; - response->textureHeight = static_cast<unsigned int>(max); + response->textureHeight = static_cast<unsigned int>(win->maxTextureSize); } // texture coords diff --git a/src/graphics/text/TextRasterizer.h b/src/graphics/text/TextRasterizer.h index 5a908adab413f698d7ffdeee1f017c9141636584..bbe66546fff9d8e01291d3e7ee039ac417a82d00 100644 --- a/src/graphics/text/TextRasterizer.h +++ b/src/graphics/text/TextRasterizer.h @@ -6,6 +6,7 @@ #include <memory> #include <string> #include <algorithm> +#include "../opengl/Window.h" struct Glyph { float x0; @@ -76,6 +77,7 @@ public: hb_font_t *font; hb_buffer_t *buffer; std::unique_ptr<FT_Face> face; + Window *win; }; #endif diff --git a/src/graphics/text/TextRasterizerCache.cpp b/src/graphics/text/TextRasterizerCache.cpp index 092a62d93f8354222921cc8b8b4a635362255c80..14b94b63660aca81a457659059951b7a406bd987 100644 --- a/src/graphics/text/TextRasterizerCache.cpp +++ b/src/graphics/text/TextRasterizerCache.cpp @@ -1,7 +1,10 @@ #include "TextRasterizerCache.h" +#include <iostream> TextRasterizerCache *rasterizerCache=new TextRasterizerCache; +extern const std::unique_ptr<Window> window; + // reduces this: // Updated DOM in: 6.787870 seconds // to this: @@ -9,14 +12,18 @@ TextRasterizerCache *rasterizerCache=new TextRasterizerCache; std::shared_ptr<TextRasterizer> TextRasterizerCache::loadFont(const unsigned int size, const bool bold) { if (bold) { if (fontSizes_bold.find(size) == fontSizes_bold.end()) { + //std::cout << "Making bold font" << std::endl; fontSizes_bold[size]=std::make_shared<TextRasterizer>("DejaVuSerif.ttf", size, 72, bold); + fontSizes_bold[size]->win = window.get(); } return fontSizes_bold[size]; } else { if (fontSizes_notbold.find(size) == fontSizes_notbold.end()) { + //std::cout << "Making font" << std::endl; fontSizes_notbold[size]=std::make_shared<TextRasterizer>("DejaVuSerif.ttf", size, 72, bold); + fontSizes_notbold[size]->win = window.get(); } return fontSizes_notbold[size]; } -} \ No newline at end of file +} diff --git a/src/main.cpp b/src/main.cpp index 680cdb5a79b5c79bff1749fce7e5b6dace91350e..84929419e5dcb5f707aae5e7e01ea1b79133955a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,6 +5,8 @@ #include "URL.h" #include "WebResource.h" #include "tlsf.h" +#include "scheduler.h" + #include <ctime> #include <iostream> #include <sys/stat.h> @@ -21,8 +23,11 @@ extern "C"{ #endif const std::unique_ptr<Window> window = std::make_unique<Window>(); +// why can't I const this? +std::unique_ptr<Scheduler> scheduler = std::make_unique<Scheduler>(); //URL currentURL; + bool setWindowContent(URL const& url) { logDebug() << "main::setWindowContent - " << url << std::endl; @@ -47,17 +52,19 @@ bool setWindowContent(URL const& url) { std::cout << "Rendering text document" << std::endl; std::shared_ptr<Node> rootNode = std::make_shared<Node>(NodeType::ROOT); std::shared_ptr<TagNode> tagNode = std::make_shared<TagNode>(); + tagNode->tag="p"; + // bind tag to root + tagNode->parent = rootNode; + rootNode->children.push_back(tagNode); + + std::shared_ptr<TextNode> textNode = std::make_shared<TextNode>(); textNode->text = res.raw; - tagNode->tag="p"; // bind text to tag textNode->parent = tagNode; tagNode->children.push_back(textNode); - // bind tag to root - tagNode->parent = rootNode; - rootNode->children.push_back(tagNode); // send NodeTree to window window->setDOM(rootNode); } else { @@ -124,11 +131,19 @@ int main(int argc, char *argv[]) { } } - while (!glfwWindowShouldClose(window->window)) { //const std::clock_t begin = clock(); window->render(); - glfwWaitEvents(); // block until something changes + scheduler->fireTimers(); // render may have taken some time + double next = scheduler->getNext(); + //std::cout << "next timer at " << next << std::endl; + if (next == LONG_MAX) { + glfwWaitEvents(); // block until something changes + } else { + glfwWaitEventsTimeout(next / 1000); + } + scheduler->fireTimers(); // check before we go into render again + //glfwWaitEventsTimeout(1.0 / 60.0); // increase the cpu from 0% to 2% on idle //const std::clock_t end = clock(); //std::cout << '\r' << std::fixed << (((static_cast<double>(end - begin)) / CLOCKS_PER_SEC) * 1000) << std::scientific << " ms/f " << std::flush; } diff --git a/src/scheduler.cpp b/src/scheduler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5e2b30ea795d3330584147981628bdf72ec9af03 --- /dev/null +++ b/src/scheduler.cpp @@ -0,0 +1,77 @@ +#include "scheduler.h" +#include <GLFW/glfw3.h> +#include <iostream> +#include <algorithm> + +std::shared_ptr<timer_handle> Scheduler::setTimeout(std::function<void()> callback, unsigned long delay) { + double now = glfwGetTime() * 1000; + std::shared_ptr<timer_handle> handle = std::make_shared<timer_handle>(); + handle->callback = callback; + handle->nextAt = now + delay; + handle->timeout = true; + this->timers.push_back(handle); + return handle; +} + +std::shared_ptr<timer_handle> Scheduler::setInterval(std::function<void()> callback, unsigned long delay) { + double now = glfwGetTime() * 1000; + //std::cout << "Scheduler::setInterval at " << (int)now << std::endl; + std::shared_ptr<timer_handle> handle = std::make_shared<timer_handle>(); + handle->callback = callback; + handle->nextAt = now + delay; + handle->timeout = false; + this->timers.push_back(handle); + //std::cout << "scheduled at " << (int)handle->nextAt << std::endl; + return handle; +} + +unsigned long Scheduler::getNext() { + unsigned long lowest = LONG_MAX; + double now = glfwGetTime() * 1000; // it's number of ms since start up + //std::cout << "there are " << this->timers.size() << std::endl; + for(std::vector<std::shared_ptr<timer_handle>>::iterator it=this->timers.begin(); it!=this->timers.end(); ++it) { + //std::cout << "nextAt " << (int)it->get()->nextAt << " long " << (int)(now - it->get()->nextAt) << std::endl; + //std::cout << "now " << (int)now << " nextAt: " << (int)it->get()->nextAt << std::endl; + int diff = now - it->get()->nextAt; + if (diff < 0) diff = 0; + //std::cout << "timer fires in " << diff << std::endl; + lowest = std::min(lowest, static_cast<unsigned long>(diff)); + } + //std::cout << "returning " << lowest << std::endl; + return lowest; +} + +bool Scheduler::fireTimer(std::shared_ptr<timer_handle> timer, double now) { + timer->callback(); + if (timer->timeout) { + return true; + } + // schedule the next one + timer->nextAt = now + timer->nextAt; + return false; +} + +void Scheduler::fireTimers() { + double now = glfwGetTime() * 1000; + for(std::vector<std::shared_ptr<timer_handle>>::iterator it=this->timers.begin(); it!=this->timers.end(); ++it) { + if (it->get()->nextAt < now) { + if (this->fireTimer(*it, now)) { + it = this->timers.erase(it); + if (it == this->timers.end()) break; + } + } + } +} + +bool Scheduler::clearInterval(std::shared_ptr<timer_handle> timer) { + // find and remove it + //it2 = std::find(this->rootComponent->children.begin(), this->rootComponent->children.end(), it->get()->selectorBox); + std::vector<std::shared_ptr<timer_handle>>::iterator it = std::find(this->timers.begin(), this->timers.end(), timer); + if (it != this->timers.end()) { + //std::cout << "Clearing Interval" << std::endl; + this->timers.erase(it); + } else { + std::cout << "Couldnt find timer" << std::endl; + } + return true; +} diff --git a/src/scheduler.h b/src/scheduler.h new file mode 100644 index 0000000000000000000000000000000000000000..e02d37286726272a962c41b6faf5613b60a517b9 --- /dev/null +++ b/src/scheduler.h @@ -0,0 +1,27 @@ +#ifndef SCHEDULER_H +#define SCHEDULER_H + +#include <memory> +#include <vector> +#include <functional> +#include <limits.h> + +class timer_handle { +public: + double nextAt; // in milliseconds + bool timeout; + std::function<void()> callback; +}; + +class Scheduler { +public: + std::shared_ptr<timer_handle> setTimeout(std::function<void()> callback, unsigned long delay); + std::shared_ptr<timer_handle> setInterval(std::function<void()> callback, unsigned long delay); + unsigned long getNext(); + bool fireTimer(std::shared_ptr<timer_handle> timer, double now); + void fireTimers(); + bool clearInterval(std::shared_ptr<timer_handle> timer); + std::vector<std::shared_ptr<timer_handle>> timers; +}; + +#endif