Nubben 5 years ago
parent
commit
57ae678c72
  1. 2
      src/BrowsingHistory.cpp
  2. 2
      src/BrowsingHistory.h
  3. 33
      src/URL.cpp
  4. 9
      src/graphics/components/BoxComponent.cpp
  5. 88
      src/graphics/components/Component.cpp
  6. 28
      src/graphics/components/Component.h
  7. 42
      src/graphics/components/ComponentBuilder.cpp
  8. 2
      src/graphics/components/ComponentBuilder.h
  9. 323
      src/graphics/components/DocumentComponent.cpp
  10. 43
      src/graphics/components/DocumentComponent.h
  11. 38
      src/graphics/components/InputComponent.cpp
  12. 1
      src/graphics/components/InputComponent.h
  13. 19
      src/graphics/components/TextComponent.cpp
  14. 253
      src/graphics/opengl/Window.cpp
  15. 2
      src/graphics/opengl/Window.h
  16. 11
      src/graphics/text/TextRasterizer.cpp
  17. 1
      src/graphics/text/TextRasterizer.h
  18. 12
      src/main.cpp

2
src/BrowsingHistory.cpp

@ -5,7 +5,7 @@ BrowsingHistory::BrowsingHistory(std::function<void(URL const&)> onGotoPage_) : @@ -5,7 +5,7 @@ BrowsingHistory::BrowsingHistory(std::function<void(URL const&)> onGotoPage_) :
currentPosition(history.end()),
onGotoPage(onGotoPage_) {}
unsigned int BrowsingHistory::length() const {
size_t BrowsingHistory::length() const {
return history.size();
}

2
src/BrowsingHistory.h

@ -16,7 +16,7 @@ class BrowsingHistory { @@ -16,7 +16,7 @@ class BrowsingHistory {
public:
BrowsingHistory(std::function<void(URL const&)> onGotoPage_);
unsigned int length() const;
size_t length() const;
//void scrollRestoration(); // TODO: Implement this when it's relevant
//void* state() const; // TODO: Implement when we have Javascript objects.

33
src/URL.cpp

@ -44,10 +44,29 @@ std::tuple<std::unique_ptr<URL>,enum URIParseError> parseUri(std::string raw) { @@ -44,10 +44,29 @@ std::tuple<std::unique_ptr<URL>,enum URIParseError> parseUri(std::string raw) {
enum URIParseState state = SCHEME;
// TODO Validate at the end that every field were defined (ie: http:// is valid, but it's clearly not)
// Remember file:// doesn't need a port (for end validation)
// First character of scheme MUST be alphabetic
if (!isalpha(raw[cursor])) {
std::cerr << "invalid scheme: '" << raw.substr(last, cursor - last+1) << "'" << std::endl;
return std::make_tuple(std::move(uri), URI_PARSE_ERROR_SCHEME);
if (raw[cursor] == '/') {
// unless it's / for relative URLs
// need this so we can merge URLs
// make sure it's not // (relative scheme)
if (raw.length() > 1) {
if (raw[cursor + 1] == '/') {
// there is a host
uri->scheme = "relative";
state = AUTHORITY;
} else {
// relative path
uri->scheme = ""; // probably doesn't matter if it's "" or "relative"
state = PATH;
}
}
} else {
// First character of scheme MUST be alphabetic
if (!isalpha(raw[cursor])) {
std::cerr << "invalid scheme: '" << raw.substr(last, cursor - last+1) << "'" << std::endl;
return std::make_tuple(std::move(uri), URI_PARSE_ERROR_SCHEME);
}
}
for (cursor = 1; cursor < raw.length(); cursor++) {
/* TODO
@ -63,9 +82,9 @@ std::tuple<std::unique_ptr<URL>,enum URIParseError> parseUri(std::string raw) { @@ -63,9 +82,9 @@ std::tuple<std::unique_ptr<URL>,enum URIParseError> parseUri(std::string raw) {
}
state = FIRST_SLASH;
} else if (!isalpha(raw[cursor]) && !isdigit(raw[cursor]) && raw[cursor] != '+' &&
raw[cursor] != '-' && raw[cursor] != '.') {
raw[cursor] != '-' && raw[cursor] != '.' && raw[cursor] != '/') { // why this exception list?
/* URI MUST have a scheme */
std::cerr << "invalid scheme: '" << raw.substr(last, cursor - last+1) << "'" << std::endl;
std::cerr << "invalid scheme: '" << raw.substr(last, cursor - last+1) << "' cursor: " << cursor << std::endl;
return std::make_tuple(std::move(uri), URI_PARSE_ERROR_SCHEME);
}
} else if (state == FIRST_SLASH) {
@ -210,7 +229,7 @@ URL::URL(std::string const& url) { @@ -210,7 +229,7 @@ URL::URL(std::string const& url) {
}
std::string URL::toString() const {
std::cout << "scheme[" << scheme << "] host[" << host << "] path [" << path << "]" << std::endl;
//std::cout << "scheme[" << scheme << "] host[" << host << "] path [" << path << "]" << std::endl;
if (isRelative()) {
return path;
}

9
src/graphics/components/BoxComponent.cpp

@ -19,6 +19,11 @@ BoxComponent::BoxComponent(const float rawX, const float rawY, const float rawWi @@ -19,6 +19,11 @@ BoxComponent::BoxComponent(const float rawX, const float rawY, const float rawWi
height = rawHeight;
x = rawX;
y = rawY;
if (height < 0) {
std::cout << "BoxComponent::BoxComponent - height was less than zero" << std::endl;
height = 0;
}
// copy initial state
initialX = x;
@ -36,8 +41,8 @@ BoxComponent::BoxComponent(const float rawX, const float rawY, const float rawWi @@ -36,8 +41,8 @@ BoxComponent::BoxComponent(const float rawX, const float rawY, const float rawWi
float vx = rawX;
float vy = rawY;
//std::cout << "placing box at " << (int)vx << "x" << (int)vy << " size: " << (int)rawWidth << "x" << (int)rawHeight << std::endl;
float vWidth = rawWidth;
float vHeight = rawHeight;
float vWidth = width;
float vHeight = height;
pointToViewport(vx, vy);
/*

88
src/graphics/components/Component.cpp

@ -53,6 +53,7 @@ void Component::setParent(std::shared_ptr<Component> passedParent) { @@ -53,6 +53,7 @@ void Component::setParent(std::shared_ptr<Component> passedParent) {
// update our position
x = passedParent->x;
y = passedParent->y - passedParent->height;
//std::cout << "Component::setParent - placing at " << static_cast<int>(x) << "," << static_cast<int>(y) << std::endl;
// add new component as child to parent
//std::shared_ptr<Component> child=*new std::shared_ptr<Component>(this);
@ -67,9 +68,11 @@ void Component::layout() { @@ -67,9 +68,11 @@ void Component::layout() {
//int lx = x;
//int ly = y;
// if we want to position the root component and layout (because to move things we need to trigger a resize)
// then we need this to not reset because it will affect the position we're trying to relayout them out at
// reset position
x = 0;
y = 0;
//x = 0;
//y = 0;
/*
TextComponent *textComponent = dynamic_cast<TextComponent*>(this);
@ -132,7 +135,7 @@ void Component::layout() { @@ -132,7 +135,7 @@ void Component::layout() {
}
}
//std::cout << "Component::layout - adjusted by prev: " << (int)x << "x" << (int)y << std::endl;
//std::cout << "moving component to " << (int)x << "x" << (int)y << std::endl;
//std::cout << "Component::layout - moving component to " << (int)x << "x" << (int)y << std::endl;
// change in X position
//std::cout << "Component::layout - component was at " << lx << " moved(?) to " << (int)x << std::endl;
@ -242,15 +245,93 @@ void Component::updateParentSize() { @@ -242,15 +245,93 @@ void Component::updateParentSize() {
}
}
GLuint elementBufferObject = 0;
void Component::initTheElementBufferObject() const {
glGenBuffers(1, &elementBufferObject);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBufferObject);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
}
GLuint Component::CreateVertexArrayObject() const {
GLuint vertexArrayObject = 0;
glGenVertexArrays(1, &vertexArrayObject);
glBindVertexArray(vertexArrayObject);
// we may need the VBO here...
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBufferObject);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), nullptr);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), reinterpret_cast<void*>(3 * sizeof(float)));
glEnableVertexAttribArray(1);
//glBindVertexArray(0);
return vertexArrayObject;
}
GLuint Component::CreateVertexBufferObject() const {
GLuint vertexBufferObject = 0;
glGenBuffers(1, &vertexBufferObject);
return vertexBufferObject;
}
// this always creates, we probably should just respond to existing state
bool Component::setPosition4(GLuint vertexBufferObject, int x0, int y0, int x1, int y1) const {
float vertices[20] = {
0.0f, 0.0f, 0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 0.0f, 1.0f, 1.0f,
0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f
};
vertices[(0 * 5) + 0] = x0;
vertices[(0 * 5) + 1] = y1;
vertices[(1 * 5) + 0] = x1;
vertices[(1 * 5) + 1] = y1;
vertices[(2 * 5) + 0] = x1;
vertices[(2 * 5) + 1] = y0;
vertices[(3 * 5) + 0] = x0;
vertices[(3 * 5) + 1] = y0;
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject); // selects buffer
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // writes buffer
return true;
}
GLuint Component::CreateTexture() const {
GLuint textureNum = 0;
glGenTextures(1, &textureNum);
return textureNum;
}
bool Component::setTexture(GLuint textureNum, GLsizei w, GLsizei h, const unsigned char *texture) const {
glBindTexture(GL_TEXTURE_2D, textureNum);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, texture);
glGenerateMipmap(GL_TEXTURE_2D);
return true;
}
// converts 0-1 to screen
// but centered
void Component::pointToViewport(float &rawX, float &rawY) const {
if (boundToPage) {
//std::cout << "Component::pointToViewport - notBoundToPage converting from " << static_cast<int>(rawX) << "," << static_cast<int>(rawY) << std::endl;
//std::cout << "BoundToPage using " << screenWidth << "x" << screenHeight << std::endl;
rawX = ((rawX / windowWidth) * 2) - 1;
rawY = ((rawY / windowHeight) * 2) - 1;
//std::cout << "Component::pointToViewport - BoundToPage using " << static_cast<int>(rawX) << "x" << static_cast<int>(rawY) << std::endl;
//std::cout << "Component::pointToViewport - BoundToPage converted to " << rawX << "," << rawY << std::endl;
} else {
//std::cout << "notBoundToPage using " << screenWidth << "x" << screenHeight << std::endl;
//std::cout << "Component::pointToViewport - notBoundToPage converting from " << static_cast<int>(rawX) << "," << static_cast<int>(rawY) << std::endl;
if (rawX < 0) {
rawX += windowWidth;
}
@ -265,6 +346,7 @@ void Component::pointToViewport(float &rawX, float &rawY) const { @@ -265,6 +346,7 @@ void Component::pointToViewport(float &rawX, float &rawY) const {
}
rawX = (rawX * 2) - 1;
rawY = (rawY * 2) - 1;
//std::cout << "Component::pointToViewport - notBoundToPage converted to " << rawX << "," << rawY << std::endl;
}
}

28
src/graphics/components/Component.h

@ -4,6 +4,12 @@ @@ -4,6 +4,12 @@
#include <functional>
#include <memory>
#include <vector>
#include <GL/glew.h>
const unsigned int indices[6] = {
0, 1, 2,
0, 2, 3
};
struct rgba {
unsigned int r;
@ -35,7 +41,17 @@ public: @@ -35,7 +41,17 @@ public:
// but we may hang onto the variables to know what the state is set up for
// why pass it here? on resize we call layout no this...
virtual void resize(const int passedWindowWidth, const int passedWindowHeight);
// vab container has handle, shaderProtoType, vbo, ebo (const)
// we could just have 2 global vabs on for each shaderProto
// but then we'd might need to vbos each time (on top of the texture)
void initTheElementBufferObject() const;
GLuint CreateVertexArrayObject() const;
GLuint CreateVertexBufferObject() const;
bool setPosition4(GLuint vertexBufferObject, int x0, int y0, int x1, int y1) const ;
GLuint CreateTexture() const ;
bool setTexture(GLuint textureNum, GLsizei w, GLsizei h, const unsigned char *texture) const ;
void pointToViewport(float &rawX, float &rawY) const ;
void distanceToViewport(float &rawX, float &rawY) const ;
@ -51,13 +67,11 @@ public: @@ -51,13 +67,11 @@ public:
int windowHeight;
};
*/
// possible badly named as these aren't bound to a window
// how are these used?
int windowWidth;
int windowHeight;
bool boundToPage = true;
const unsigned int indices[6] = {
0, 1, 2,
0, 2, 3
};
bool verticesDirty = false;
std::shared_ptr<Component> parent = nullptr;
std::shared_ptr<Component> previous = nullptr;
@ -103,10 +117,14 @@ public: @@ -103,10 +117,14 @@ public:
rgba color;
bool isVisibile = true;
bool isInline = false; // text-only thing but there maybe other non-text inline
bool isPickable = true;
bool textureSetup = false;
// probably shoudl be vector (or maybe use the event emitter)
std::function<void(int x, int y)> onMousedown = nullptr;
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;
std::function<void(int key, int scancode, int action, int mods)> onKeyup = nullptr;
std::function<void()> onClick = nullptr;
std::function<void()> onFocus = nullptr;
std::function<void()> onBlur = nullptr;

42
src/graphics/components/ComponentBuilder.cpp

@ -21,6 +21,10 @@ const std::unordered_map<std::string, std::shared_ptr<Element>> ComponentBuilder @@ -21,6 +21,10 @@ const std::unordered_map<std::string, std::shared_ptr<Element>> ComponentBuilder
std::shared_ptr<Component> ComponentBuilder::build(const std::shared_ptr<Node> node, const std::shared_ptr<Component> &parentComponent, int windowWidth, int windowHeight) {
std::shared_ptr<Component> component;
std::string tag;
if (node == nullptr) {
std::cout << "ComponentBuilder::build - node is null" << std::endl;
return nullptr;
}
if (node->nodeType == NodeType::TAG) {
TagNode *tagNode = dynamic_cast<TagNode*>(node.get());
@ -59,17 +63,19 @@ std::shared_ptr<Component> ComponentBuilder::build(const std::shared_ptr<Node> n @@ -59,17 +63,19 @@ std::shared_ptr<Component> ComponentBuilder::build(const std::shared_ptr<Node> n
TextComponent *textComponent = dynamic_cast<TextComponent*>(component.get());
if (textComponent) {
//std::cout << "compositing [" << textComponent->text << "]" << std::endl;
component->onMousedown = [component](int x, int y) {
std::cout << "TextSelection starting at " << x << "," << y << std::endl;
// 0 to -640 (windowHeight)
// so if y=640 , f(y)=-640
int ny = -y;
std::cout << "TextSelection adjusted " << x << "," << ny << std::endl;
std::cout << "Component at " << static_cast<int>(component->x) << "," << static_cast<int>(component->y) << std::endl;
};
component->onMouseup = [component](int x, int y) {
std::cout << "TextSelection ending at " << x << "," << y << std::endl;
};
if (!component->onMousedown) {
component->onMousedown = [component](int x, int y) {
std::cout << "TextSelection starting at " << x << "," << y << std::endl;
// 0 to -640 (windowHeight)
// so if y=640 , f(y)=-640
int ny = -y;
std::cout << "TextSelection adjusted " << x << "," << ny << std::endl;
std::cout << "Component at " << static_cast<int>(component->x) << "," << static_cast<int>(component->y) << std::endl;
};
component->onMouseup = [component](int x, int y) {
std::cout << "TextSelection ending at " << x << "," << y << std::endl;
};
}
}
InputComponent *inputComponent = dynamic_cast<InputComponent*>(component.get());
if (inputComponent) {
@ -104,3 +110,17 @@ std::shared_ptr<Component> ComponentBuilder::build(const std::shared_ptr<Node> n @@ -104,3 +110,17 @@ std::shared_ptr<Component> ComponentBuilder::build(const std::shared_ptr<Node> n
//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;
}
#include "DocumentComponent.h"
std::string typeOfComponent(const std::shared_ptr<Component> &component) {
DocumentComponent *docComponent = dynamic_cast<DocumentComponent*>(component.get());
if (docComponent) return "doc";
TextComponent *textComponent = dynamic_cast<TextComponent*>(component.get());
if (textComponent) return "text";
InputComponent *inputComponent = dynamic_cast<InputComponent*>(component.get());
if (inputComponent) return "input";
BoxComponent *boxComponent = dynamic_cast<BoxComponent*>(component.get());
if (boxComponent) return "box";
return "";
}

2
src/graphics/components/ComponentBuilder.h

@ -30,4 +30,6 @@ public: @@ -30,4 +30,6 @@ public:
std::shared_ptr<Component> build(const std::shared_ptr<Node> node, const std::shared_ptr<Component> &parentComponent, int windowWidth, int windowHeight);
};
std::string typeOfComponent(const std::shared_ptr<Component> &component);
#endif

323
src/graphics/components/DocumentComponent.cpp

@ -0,0 +1,323 @@ @@ -0,0 +1,323 @@
#include "DocumentComponent.h"
#include <cmath>
#include <iostream>
#include "../../Log.h"
#include "InputComponent.h"
#include <ctime>
DocumentComponent::DocumentComponent(const float rawX, const float rawY, const float rawWidth, const float rawHeight, const int passedWindowWidth, const int passedWindowHeight) {
//std::cout << "DocumentComponent::DocumentComponent" << std::endl;
windowWidth = passedWindowWidth;
windowHeight = passedWindowHeight;
//std::cout << "DocumentComponent::DocumentComponent - window size: " << windowWidth << "x" << windowHeight << std::endl;
x = rawX;
y = rawY;
width = rawWidth;
height = rawHeight;
if (height < 0) {
std::cout << "DocumentComponent::DocumentComponent - height was less than zero" << std::endl;
height = 0;
}
//std::cout << "DocumentComponent::DocumentComponent - our size" << static_cast<int>(width) << "x" << static_cast<int>(height) << std::endl;
onMousemove=[this](int passedX, int passedY) {
// set hover component
static int lx = 0;
static int ly = 0;
//std::cout << "DocumentComponent::DocumentComponent:onMousemove - at " << x << "," << y << std::endl;
if (lx == passedX && ly == passedY) {
return;
}
lx = passedX;
ly = passedY;
//std::cout << "DocumentComponent::DocumentComponent:onMousemove - size " << this->windowWidth << "," << this->windowHeight << std::endl;
this->hoverComponent = this->searchComponentTree(this->rootComponent, x, y);
if (this->hoverComponent) {
//std::cout << "DocumentComponent::DocumentComponent:onMousemove - hovering over " << typeOfComponent(this->hoverComponent) << " component" << std::endl;
if (this->hoverComponent->onMousemove) {
// this could communicate the cursor to use
this->hoverComponent->onMousemove(passedX, passedY);
}
if (this->hoverComponent->onClick) {
glfwSetCursor(this->win->window, this->win->cursorHand);
} else {
glfwSetCursor(this->win->window, this->win->cursorIbeam);
}
} else {
glfwSetCursor(this->win->window, this->win->cursorArrow);
}
};
onWheel=[this](int passedX, int passedY) {
//std::cout << "scroll yDelta: " << y << std::endl;
this->scrollY -= passedX;
if (this->scrollY < 0) {
this->scrollY = 0;
} else if (this->scrollY > this->scrollHeight) {
this->scrollY = this->scrollHeight;
}
//std::cout << "scroll pos: " << scrollY << "/" << scrollHeight << std::endl;
//std::cout << "y: " << static_cast<int>(this->y) << " - " << this->scrollY << std::endl;
//std::cout << "root.y: " << static_cast<int>(rootComponent->y) << std::endl;
//std::cout << "windowSize: " << windowWidth << "," << windowHeight << std::endl;
// ajdust root position
rootComponent->y = this->y + this->scrollY;
//std::cout << "now root.y: " << static_cast<int>(rootComponent->y) << std::endl;
// reset root size
rootComponent->windowWidth = windowWidth;
rootComponent->windowHeight = windowHeight;
//printComponentTree(rootComponent, 0);
// this takes so long, we may want to delay until the input is adjusted
rootComponent->layout(); // need to update the vertices
//rootComponent->y = this->y - this->scrollY;
//std::cout << "after root.y: " << static_cast<int>(rootComponent->y) << std::endl;
// don't need this
//this->renderDirty = true;
};
onMousedown=[this](int passedX, int passedY) {
std::cout << "document left press" << std::endl;
if (this->hoverComponent) {
if (this->focusedComponent != this->hoverComponent) {
// blur old component
if (this->focusedComponent) {
if (this->focusedComponent->onBlur) {
this->focusedComponent->onBlur();
}
}
// focus new component
if (this->hoverComponent->onFocus) {
this->hoverComponent->onFocus();
}
}
this->focusedComponent = this->hoverComponent;
if (this->focusedComponent->onMousedown) {
//std::cout << "click event" << std::endl;
this->focusedComponent->onMousedown(passedX, passedY);
}
}
};
onMouseup=[this](int passedX, int passedY) {
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) {
// blur old component
if (this->focusedComponent) {
if (this->focusedComponent->onBlur) {
this->focusedComponent->onBlur();
}
}
// focus new component
if (this->hoverComponent->onFocus) {
this->hoverComponent->onFocus();
}
}
this->focusedComponent = this->hoverComponent;
if (this->focusedComponent->onMouseup) {
//std::cout << "click event" << std::endl;
this->focusedComponent->onMouseup(passedX, passedY);
}
if (this->focusedComponent->onClick) {
//std::cout << "click event" << std::endl;
this->focusedComponent->onClick();
}
}
};
onKeyup=[this](int key, int scancode, int action, int mods) {
//std::cout << "DocumentComponent::DocumentComponent:onKeyup" << std::endl;
InputComponent *inputComponent = dynamic_cast<InputComponent*>(this->focusedComponent.get());
if (inputComponent) {
//std::cout << "inputComponent is focused, key pressed " << key << " action: " <<action << std::endl;
// action 1 is down, 0 is up, 2 is a repeat
if (action == 0 || action == 2) {
// key up
// it's always uppercase...
if (key == 259) {
inputComponent->backSpace();
} else if (key == 257) {
std::cout << "enter!" << std::endl;
} else {
if (key < 256) {
if (mods & GLFW_MOD_SHIFT) {
// SHIFT
if (key == GLFW_KEY_SLASH) key='?';
if (key == GLFW_KEY_APOSTROPHE) key='"';
if (key == GLFW_KEY_COMMA) key='<';
if (key == GLFW_KEY_MINUS) key='_';
if (key == GLFW_KEY_PERIOD) key='>';
if (key == GLFW_KEY_SEMICOLON) key=':';
if (key == GLFW_KEY_EQUAL) key='+';
if (key == GLFW_KEY_LEFT_BRACKET) key='{';
if (key == GLFW_KEY_BACKSLASH) key='|';
if (key == GLFW_KEY_RIGHT_BRACKET) key='}';
if (key == GLFW_KEY_GRAVE_ACCENT) key='~';
} else {
// no shift or caplocks
// basically: when SHIFT isn't pressed but key is in A-Z range, add ascii offset to make it lower case
if (key >= 'A' && key <= 'Z') {
key += 'a' - 'A';
}
}
inputComponent->addChar(key);
} // otherwise I think it's some weird control char
}
}
}
};
}
void DocumentComponent::printComponentTree(const std::shared_ptr<Component> &component, int depth) {
for (int i = 0; i < depth; i++) {
std::cout << '\t';
}
TextComponent *textComponent = dynamic_cast<TextComponent*>(component.get());
if (textComponent) {
std::cout << std::fixed << "X: " << static_cast<int>(textComponent->x) << " Y: " << static_cast<int>(textComponent->y) << " WIDTH: " << static_cast<int>(textComponent->width) << " HEIGHT: " << static_cast<int>(textComponent->height) << " INLINE: " << textComponent->isInline << " TEXT: " << textComponent->text << std::endl;
}
else {
std::cout << std::fixed << "X: " << static_cast<int>(component->x) << " Y: " << static_cast<int>(component->y) << " WIDTH: " << static_cast<int>(component->width) << " HEIGHT: " << static_cast<int>(component->height) << " INLINE: " << component->isInline << std::endl;
}
for (std::shared_ptr<Component> child : component->children) {
printComponentTree(child, depth + 1);
}
}
void DocumentComponent::render() {
//std::cout << "DocumentComponent::render" << std::endl;
if (domDirty) {
const std::clock_t begin = clock();
createComponentTree(domRootNode, rootComponent);
const std::clock_t end = clock();
std::cout << "built & laid out document components in: " << std::fixed << ((static_cast<double>(end - begin)) / CLOCKS_PER_SEC) << std::scientific << " seconds" << std::endl;
//printComponentTree(rootComponent, 0);
domDirty = false;
renderDirty = true;
//std::cout << "root Height: " << static_cast<int>(rootComponent->height) << " window Height: " << windowHeight << " y " << static_cast<int>(this->y) << std::endl;
scrollHeight = std::max(0, static_cast<int>(rootComponent->height - (windowHeight + (this->y * 2))));
}
if (renderDirty) {
glUseProgram(win->textureProgram);
renderBoxComponents(rootComponent);
glUseProgram(win->fontProgram);
renderComponents(rootComponent);
}
}
// create this component and all it's children
void DocumentComponent::createComponentTree(const std::shared_ptr<Node> node, const std::shared_ptr<Component> &parentComponent) {
std::shared_ptr<Component> component = componentBuilder.build(node, parentComponent, windowWidth, windowHeight);
if (!component) {
//std::cout << "DocumentComponent::createComponentTree - no component" << std::endl;
return;
}
if (node==domRootNode) {
// if this is the root node
component->reqWidth = windowWidth;
component->reqHeight = windowHeight;
}
// create children elements
for (std::shared_ptr<Node> child : node->children) {
createComponentTree(child, component);
}
}
// draw this component and all it's children
void DocumentComponent::renderComponents(std::shared_ptr<Component> component) {
if (!component) {
std::cout << "DocumentComponent::renderComponents - got null passed" << std::endl;
return;
}
TextComponent *textComponent = dynamic_cast<TextComponent*>(component.get());
if (textComponent) {
textComponent->render();
}
// is this needed?
if (component->children.empty()) {
return;
}
for (std::shared_ptr<Component> &child : component->children) {
renderComponents(child);
}
}
void DocumentComponent::renderBoxComponents(std::shared_ptr<Component> component) {
if (!component) {
std::cout << "DocumentComponent::renderBoxComponents - got null passed" << std::endl;
return;
}
// render non-text components too
BoxComponent *boxComponent = dynamic_cast<BoxComponent*>(component.get());
//inputComponent->render();
if (boxComponent) {
/*
GLenum glErr=glGetError();
if(glErr != GL_NO_ERROR) {
std::cout << "Window::renderBoxComponents - box render start - not ok: " << glErr << std::endl;
}
*/
/*
glUseProgram(textureProgram);
glErr=glGetError();
if(glErr != GL_NO_ERROR) {
std::cout << "glUseProgram - not ok: " << glErr << std::endl;
}
*/
//std::cout << "Window::renderBoxComponents - Rendering at " << (int)boxComponent->x << "x" << (int)boxComponent->y << std::endl;
boxComponent->render();
}
/*
InputComponent *inputComponent = dynamic_cast<InputComponent*>(component.get());
if (inputComponent) {
glUseProgram(textureProgram);
inputComponent->render();
}
*/
// is this needed?
if (component->children.empty()) {
return;
}
for (std::shared_ptr<Component> &child : component->children) {
renderBoxComponents(child);
}
}
// used for picking
std::shared_ptr<Component> DocumentComponent::searchComponentTree(const std::shared_ptr<Component> &component, const int passedX, const int passedY) {
if (component->children.empty()) {
//std::cout << "DocumentComponent::searchComponentTree - component at " << static_cast<int>(component->x) << "," << static_cast<int>(component->y) << " size " << static_cast<int>(component->width) << "," << static_cast<int>(component->height) << std::endl;
//std::cout << "DocumentComponent::searchComponentTree - y search: " << static_cast<int>(-component->y) << "<" << static_cast<int>(y) << "<" << static_cast<int>(-component->y + component->height) << std::endl;
if (-component->y < passedY && -component->y + component->height > passedY) {
//std::cout << "DocumentComponent::searchComponentTree - x search: " << static_cast<int>(component->x) << "<" << static_cast<int>(x) << "<" << 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;
return component;
}
}
}
else {
for (std::shared_ptr<Component> child : component->children) {
std::shared_ptr<Component> found = searchComponentTree(child, x, y);
if (found) {
return found;
}
}
}
return nullptr;
}
// moving naviagtion closer to window, as window is now the owner of currentURL
// preparation for multiple HTML documents
void DocumentComponent::navTo(const std::string url) {
logDebug() << "navTo(" << url << ")" << std::endl;
currentURL = currentURL.merge(URL(url));
logDebug() << "go to: " << currentURL << std::endl;
setWindowContent(currentURL);
}

43
src/graphics/components/DocumentComponent.h

@ -0,0 +1,43 @@ @@ -0,0 +1,43 @@
#ifndef DOCUMENTCOMPONENT_H
#define DOCUMENTCOMPONENT_H
#include <GL/glew.h>
#include "Component.h"
#include "ComponentBuilder.h"
#include "../opengl/Window.h"
#include "../../html/Node.h"
#include "../../URL.h"
#include "../../networking/HTTPResponse.h"
class DocumentComponent : public Component {
public:
DocumentComponent(const float rawX, const float rawY, const float rawWidth, const float rawHeight, const int passedWindowWidth, const int passedWindowHeight);
void printComponentTree(const std::shared_ptr<Component> &component, int depth);
void render();
void createComponentTree(const std::shared_ptr<Node> node, const std::shared_ptr<Component> &parentComponent);
void renderComponents(std::shared_ptr<Component> component);
void renderBoxComponents(std::shared_ptr<Component> component);
std::shared_ptr<Component> searchComponentTree(const std::shared_ptr<Component> &component, const int x, const int y);
void navTo(const std::string url);
std::shared_ptr<Node> domRootNode = nullptr;
ComponentBuilder componentBuilder;
std::shared_ptr<Component> rootComponent = std::make_shared<Component>();
URL currentURL;
bool domDirty = false;
bool renderDirty = false;
// we'll need a way to pass events down and up
// also how do we handle scroll?
// we'll need searchComponentTree for picking
Window *win;
std::shared_ptr<Component> hoverComponent = nullptr;
std::shared_ptr<Component> focusedComponent = nullptr;
int scrollY = 0;
int scrollHeight = 0;
};
//bool setWindowContent(URL const& url);
//void handleRequest(const HTTPResponse &response);
extern const std::unique_ptr<Window> window;
#endif

38
src/graphics/components/InputComponent.cpp

@ -18,6 +18,7 @@ InputComponent::InputComponent(const float rawX, const float rawY, const float r @@ -18,6 +18,7 @@ InputComponent::InputComponent(const float rawX, const float rawY, const float r
windowHeight = passedWindowHeight;
width = rawWidth;
height = rawHeight;
// ugh
x = rawX;
y = rawY;
@ -121,7 +122,6 @@ void InputComponent::render() { @@ -121,7 +122,6 @@ void InputComponent::render() {
}
glBindVertexArray(0);
// can actuall delete vertices here
if (userInputText) {
glUseProgram(window->fontProgram);
//std::cout << "rendering some text" << std::endl;
@ -198,30 +198,36 @@ void InputComponent::resize(const int passedWindowWidth, const int passedWindowH @@ -198,30 +198,36 @@ void InputComponent::resize(const int passedWindowWidth, const int passedWindowH
glBindVertexArray(0); // protect what we created against any further modification
//updateText();
}
void InputComponent::addChar(char c) {
value+=c;
//std::cout << "input value is now: " << value << std::endl;
if (userInputText) {
delete userInputText;
}
//std::cout << "InputComponent::addChar - at " << (int)x << "," << (int)y << std::endl;
updateText();
}
void InputComponent::backSpace() {
value=value.substr(0, value.length() - 1);
if (userInputText) {
delete userInputText;
}
//std::cout << "InputComponent::addChar - at " << (int)x << "," << (int)y << std::endl;
//std::cout << "InputComponent::backSpace - at " << (int)x << "," << (int)y << std::endl;
updateText();
}
void InputComponent::updateText() {
std::cout << "InputComponent::updateText - input value is now: " << value << std::endl;
// maybe tie the fontsize to height
if (userInputText) {
delete userInputText;
}
userInputText=new TextComponent(value, 0, 0, 12, false, 0x000000FF, windowWidth, windowHeight);
//std::cout << "placing userInputText at " << static_cast<int>(x) << "," << static_cast<int>(y) << std::endl;
userInputText->x = x;
userInputText->y = y;
if (y < 0) {
userInputText->y = y;
} else {
userInputText->y = y - windowHeight + 16;
}
//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
const std::shared_ptr<TextRasterizer> textRasterizer=rasterizerCache->loadFont(12, false); // fontSize, bold
@ -232,24 +238,24 @@ void InputComponent::updateText() { @@ -232,24 +238,24 @@ void InputComponent::updateText() {
request.sourceStartX = 0;
request.sourceStartY = 0;
request.noWrap = true;
std::unique_ptr<std::pair<int, int>> textInfo=textRasterizer->size(request);
std::unique_ptr<std::pair<int, int>> textInfo = textRasterizer->size(request);
if (textInfo.get() == nullptr) {
std::cout << "InputComponent::updateText couldn't estimate value[" << value << "] size" << std::endl;
std::cout << "InputComponent::updateText - couldn't estimate value[" << value << "] size" << std::endl;
return;
}
int estWidth = std::get<0>(*textInfo.get());
//int estHeight = std::get<1>(*textInfo.get());
userInputText->rasterStartX = 0;
userInputText->rasterStartY = 0;
//std::cout << "estWidth: " << estWidth << " width: " << static_cast<int>(width) << std::endl;
//std::cout << "InputComponent::updateText - estWidth: " << estWidth << " width: " << static_cast<int>(width) << std::endl;
if (estWidth > width) {
//std::cout << "scrolling text" << std::endl;
userInputText->rasterStartX = estWidth - width;
}
userInputText->noWrap = true;
// FIXME: not really 125, if we're x>windowWidth-125
// why does changing the width mess shit up?
//std::cout << "our width: " << static_cast<int>(width) << " windowWidth: " << windowWidth << std::endl;
userInputText->resize(windowWidth, windowHeight, 125); // need to make sure there's a texture
//std::cout << "InputComponent::updateText - our width: " << static_cast<int>(width) << " windowWidth: " << windowWidth << std::endl;
userInputText->resize(windowWidth, windowHeight, width); // need to make sure there's a texture
window->renderDirty = true;
}

1
src/graphics/components/InputComponent.h

@ -19,6 +19,7 @@ public: @@ -19,6 +19,7 @@ public:
void updateText();
std::string value="";
TextComponent *userInputText = nullptr;
std::function<void(std::string value)> onEnter = nullptr;
};
#endif

19
src/graphics/components/TextComponent.cpp

@ -110,11 +110,13 @@ void TextComponent::rasterize(const int rawX, const int rawY) { @@ -110,11 +110,13 @@ 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;
request.startX = rawX;
// startX needs to be relative to the parent x
request.startX = rawX - x;
request.availableWidth = availableWidth;
request.sourceStartX = rasterStartX;
request.sourceStartY = rasterStartY;
request.noWrap = noWrap;
//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;
@ -124,8 +126,9 @@ void TextComponent::rasterize(const int rawX, const int rawY) { @@ -124,8 +126,9 @@ void TextComponent::rasterize(const int rawX, const int rawY) {
height = response->height;
endingX = response->endingX;
endingY = response->endingY;
//std::cout << "TextComponent::rasterize done [" << text << "] - start x: " << rawX << " width: " << (int)width << " wrapWidth: " << windowWidth << " wrapTo: " << wrapToX << std::endl;
// << " wrapTo: " << wrapToX
//std::cout << "TextComponent::rasterize done [" << text << "] - start x: " << rawX << " width: " << (int)width << " wrapWidth: " << windowWidth << std::endl;
//std::cout << "TextComponent::rasterize post-height: " << (int)height << std::endl;
//if (glyphs == nullptr) {
// return;
@ -198,6 +201,7 @@ void TextComponent::rasterize(const int rawX, const int rawY) { @@ -198,6 +201,7 @@ void TextComponent::rasterize(const int rawX, const int rawY) {
//}
//const std::clock_t end = clock();
//std::cout << "rasterize text [" << text << "] in: " << std::fixed << ((static_cast<double>(end - begin)) / CLOCKS_PER_SEC) << std::scientific << " seconds" << std::endl;
verticesDirty = true;
}
void TextComponent::render() {
@ -221,8 +225,8 @@ void TextComponent::render() { @@ -221,8 +225,8 @@ void TextComponent::render() {
glBindTexture(GL_TEXTURE_2D, textures[i - 1]); // load texture
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr); // draw primitives using vertices and texture
}
//} else {
//std::cout << "no textures" << std::endl;
} else {
std::cout << "TextComponent::render - no textures" << std::endl;
}
}
@ -237,8 +241,9 @@ void TextComponent::resize(const int passedWindowWidth, const int passedWindowHe @@ -237,8 +241,9 @@ void TextComponent::resize(const int passedWindowWidth, const int passedWindowHe
windowHeight = passedWindowHeight;
availableWidth = passedAvailableWidth;
//std::cout << "TextComponent::resize" << std::endl;
rasterize(x, y);
//std::cout << "TextComponent::resize - rasterizing at " << (int)x << "x" << (int)y << " size: " << (int)width << "x" << (int)height << std::endl;
rasterize(x, y);
//std::cout << "TextComponent::resize - rasterized at " << (int)x << "x" << (int)y << " size: " << (int)width << "x" << (int)height << std::endl;
// make sure we have glyphs
if (!glyphVertices.size()) {
@ -261,8 +266,6 @@ void TextComponent::resize(const int passedWindowWidth, const int passedWindowHe @@ -261,8 +266,6 @@ void TextComponent::resize(const int passedWindowWidth, const int passedWindowHe
glBindTexture(GL_TEXTURE_2D, textures.back()); // select texture
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, textureWidth, textureHeight, 0, GL_RED, GL_UNSIGNED_BYTE, textureData.get()); // update texture
glGenerateMipmap(GL_TEXTURE_2D);
verticesDirty = true;
}
void TextComponent::sanitize(std::string &str) {

253
src/graphics/opengl/Window.cpp

@ -10,6 +10,7 @@ @@ -10,6 +10,7 @@
#include "../../StringUtils.h"
#include "../../URL.h"
#include "../../Log.h"
#include "../components/DocumentComponent.h"
#include <cmath>
#include <ctime>
@ -44,7 +45,7 @@ bool Window::init() { @@ -44,7 +45,7 @@ bool Window::init() {
//UI
// at 0x(640-64) size (1024w, 64h)
boxComponents.push_back(std::make_unique<BoxComponent>(0.0f, 640.0f - 64.0f, 1024.0f, 64.0f, windowWidth, windowHeight));
//boxComponents.push_back(std::make_unique<BoxComponent>(0.0f, 640.0f - 64.0f, windowWidth, 64.0f, windowWidth, windowHeight));
//boxComponents.push_back(std::make_unique<BoxComponent>(0.0f, -96, 125, 13, windowWidth, windowHeight));
// grows from center
@ -58,9 +59,12 @@ bool Window::init() { @@ -58,9 +59,12 @@ bool Window::init() {
//boxComponents.back()->width = 125;
//boxComponents.back()->resize(windowWidth, windowHeight);
//boxComponents.push_back(std::make_unique<InputComponent>(0.0f, 20.0f, 123.0f, 13.0f, windowWidth, windowHeight));
// address bar
//boxComponents.push_back(std::make_unique<InputComponent>(192.0f, 640.0f - 48.0f, windowWidth - 384.0f, 24.0f, windowWidth, windowHeight));
//Mascot
boxComponents.push_back(std::make_unique<AnimeComponent>(768.0f, 0.0f, 512.0f, 512.0f, windowWidth, windowHeight));
//boxComponents.push_back(std::make_unique<AnimeComponent>(768.0f, 0.0f, 512.0f, 512.0f, windowWidth, windowHeight));
return true;
}
@ -80,8 +84,10 @@ bool Window::initGLFW() { @@ -80,8 +84,10 @@ bool Window::initGLFW() {
glfwSetErrorCallback([](int error, const char* description) {
std::cout << "glfw error [" << error << "]:" << description << std::endl;
});
window = glfwCreateWindow(1024, 640, "NetRunner", nullptr, nullptr);
windowWidth = 1024;
windowHeight = 640;
window = glfwCreateWindow(windowWidth, windowHeight, "NetRunner", nullptr, nullptr);
if (!window) {
glfwTerminate();
std::cout << "Could not create window" << std::endl;
@ -111,13 +117,50 @@ bool Window::initGLFW() { @@ -111,13 +117,50 @@ bool Window::initGLFW() {
Window *thiz = reinterpret_cast<Window*>(glfwGetWindowUserPointer(win));
thiz->cursorX = xPos;
thiz->cursorY = yPos;
//std::cout << "Window::Window:onMousemove - at " << static_cast<int>(xPos) << "," << static_cast<int>(yPos) << std::endl;
if (xPos < 0 || yPos < 0) return;
if (xPos > thiz->windowWidth || yPos > thiz->windowHeight) return;
// p. much worthless on double
/*
static double lx = 0;
static double ly = 0;
if (lx == xPos && ly == yPos) {
return;
}
lx = xPos;
ly = yPos;
std::cout << "Window::Window:onMousemove - noCache" << std::endl;
*/
//std::cout << "Window::Window:onMousemove - begin search" << std::endl;
thiz->hoverComponent = thiz->searchComponentTree(thiz->rootComponent, thiz->cursorX, (thiz->windowHeight - thiz->cursorY) + ((-thiz->transformMatrix[13] / 2) * thiz->windowHeight));
if (thiz->hoverComponent) {
/*
TextComponent *textComponent = dynamic_cast<TextComponent*>(thiz->hoverComponent.get());
if (textComponent) {
std::cout << "TextHover" << std::endl;
}
InputComponent *inputComponent = dynamic_cast<InputComponent*>(thiz->hoverComponent.get());
if (inputComponent) {
std::cout << "InputHover" << std::endl;
}
*/
// we don't care about BoxHover or AnimeHover
//std::cout << "hover event" << std::endl;
if (thiz->hoverComponent->onClick) {
glfwSetCursor(thiz->window, thiz->cursorHand);
} else {
glfwSetCursor(thiz->window, thiz->cursorIbeam);
TextComponent *textComponent = dynamic_cast<TextComponent*>(thiz->hoverComponent.get());
InputComponent *inputComponent = dynamic_cast<InputComponent*>(thiz->hoverComponent.get());
if (textComponent || inputComponent) {
glfwSetCursor(thiz->window, thiz->cursorIbeam);
}
// otherwise we could be an Box/Anime or Document Component
}
if (thiz->hoverComponent->onMousemove) {
// this could communicate the cursor to use
thiz->hoverComponent->onMousemove(thiz->cursorX, thiz->cursorY);
}
} else {
glfwSetCursor(thiz->window, thiz->cursorArrow);
@ -127,15 +170,20 @@ bool Window::initGLFW() { @@ -127,15 +170,20 @@ bool Window::initGLFW() {
Window *thiz = reinterpret_cast<Window*>(glfwGetWindowUserPointer(win));
// yOffset is a delta vector
thiz->transformMatrix[13] += -yOffset * 0.1;
if (thiz->hoverComponent) {
if (thiz->hoverComponent->onWheel) {
thiz->hoverComponent->onWheel(xOffset * 10, yOffset * 10);
}
}
// 2.0 is one screen height
// we draw from 0 downwards (y+), so can't scroll past our starting draw point
if (thiz->transformMatrix[13]<2) {
thiz->transformMatrix[13]=2;
if (thiz->transformMatrix[13] < 2) {
thiz->transformMatrix[13] = 2;
}
// calculate scroll max by calculating how many screens are in the rootComponent's Height
if (thiz->transformMatrix[13]>std::max((thiz->rootComponent->height)/(thiz->windowHeight)*2.0f, 2.0f)) {
thiz->transformMatrix[13]=std::max((thiz->rootComponent->height)/(thiz->windowHeight)*2.0f, 2.0f);
if (thiz->transformMatrix[13] > std::max( thiz->rootComponent->height / thiz->windowHeight * 2.0f, 2.0f)) {
thiz->transformMatrix[13] = std::max( thiz->rootComponent->height / thiz->windowHeight * 2.0f, 2.0f);
}
//std::cout << "scroll y is at " << thiz->transformMatrix[13] << "/" << static_cast<int>((thiz->transformMatrix[13]*10000) << std::endl;
thiz->transformMatrixDirty = true;
@ -182,6 +230,10 @@ bool Window::initGLFW() { @@ -182,6 +230,10 @@ 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->onMouseup) {
//std::cout << "click event" << std::endl;
thiz->focusedComponent->onMouseup(thiz->cursorX, thiz->cursorY);
@ -206,6 +258,15 @@ bool Window::initGLFW() { @@ -206,6 +258,15 @@ bool Window::initGLFW() {
Window *thiz = reinterpret_cast<Window*>(glfwGetWindowUserPointer(win));
// we're focused on something
if (thiz->focusedComponent) {
DocumentComponent *docComponent = dynamic_cast<DocumentComponent*>(thiz->focusedComponent.get());
if (docComponent) {
if (action == 0) {
if (docComponent->onKeyup) {
docComponent->onKeyup(key, scancode, action, mods);
}
}
return;
}
InputComponent *inputComponent = dynamic_cast<InputComponent*>(thiz->focusedComponent.get());
if (inputComponent) {
//std::cout << "inputComponent is focsued, key pressed " << key << " action: " <<action << std::endl;
@ -217,6 +278,9 @@ bool Window::initGLFW() { @@ -217,6 +278,9 @@ bool Window::initGLFW() {
inputComponent->backSpace();
} else if (key == 257) {
std::cout << "enter!" << std::endl;
if (inputComponent->onEnter) {
inputComponent->onEnter(inputComponent->value);
}
} else {
if (key < 256) {
if (mods & GLFW_MOD_SHIFT) {
@ -402,16 +466,16 @@ void Window::render() { @@ -402,16 +466,16 @@ void Window::render() {
std::cout << "restarting drawing" << std::endl;
// just delete and recreate
boxComponents.clear();
//boxComponents.clear();
//UI
// at 0x(640-64) size (1024w, 64h)
boxComponents.push_back(std::make_unique<BoxComponent>(0.0f, windowHeight - 64.0f, windowWidth, 64.0f, windowWidth, windowHeight));
//boxComponents.push_back(std::make_unique<BoxComponent>(0.0f, windowHeight - 64.0f, windowWidth, 64.0f, windowWidth, windowHeight));
// draws 13 px up from the bottom of 0
//boxComponents.push_back(std::make_unique<InputComponent>(0.0f, 0.0f, 123.0f, 13.0f, windowWidth, windowHeight));
//Mascot
boxComponents.push_back(std::make_unique<AnimeComponent>(windowWidth * 0.75f, 0.0f, 512.0f, 512.0f, windowWidth, windowHeight));
//boxComponents.push_back(std::make_unique<AnimeComponent>(windowWidth * 0.75f, 0.0f, 512.0f, 512.0f, windowWidth, windowHeight));
/*
for (const std::unique_ptr<BoxComponent> &boxComponent : boxComponents) {
@ -443,8 +507,9 @@ void Window::render() { @@ -443,8 +507,9 @@ void Window::render() {
const std::clock_t begin = clock();
createComponentTree(domRootNode, rootComponent);
const std::clock_t end = clock();
std::cout << "built & laid out components in: " << std::fixed << ((static_cast<double>(end - begin)) / CLOCKS_PER_SEC) << std::scientific << " seconds" << std::endl;
std::cout << "built & laid out window components in: " << std::fixed << ((static_cast<double>(end - begin)) / CLOCKS_PER_SEC) << std::scientific << " seconds" << std::endl;
//printComponentTree(rootComponent, 0);
//std::cout << "Window printComponentTree end" << std::endl;
domDirty = false;
renderDirty = true;
}
@ -462,9 +527,11 @@ void Window::render() { @@ -462,9 +527,11 @@ void Window::render() {
std::cout << "window::render - glUseProgram - not ok: " << glErr << std::endl;
}
//renderBoxComponents(rootComponent);
/*
for (const std::unique_ptr<BoxComponent> &boxComponent : boxComponents) {
boxComponent->render();
}
*/
renderBoxComponents(rootComponent);
// it's quick but done on scroll
glUseProgram(fontProgram);
@ -483,9 +550,11 @@ void Window::render() { @@ -483,9 +550,11 @@ void Window::render() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(textureProgram);
//renderBoxComponents(rootComponent);
/*
for (const std::unique_ptr<BoxComponent> &boxComponent : boxComponents) {
boxComponent->render();
}
*/
renderBoxComponents(rootComponent);
// it's quick but done on scroll
glUseProgram(fontProgram);
@ -533,8 +602,74 @@ void Window::setDOM(const std::shared_ptr<Node> rootNode) { @@ -533,8 +602,74 @@ void Window::setDOM(const std::shared_ptr<Node> rootNode) {
// new root component
rootComponent = std::make_shared<Component>();
rootComponent->y = 0;
domRootNode = rootNode;
domDirty = true;
// (re)build UI (top to bottom)
//std::cout << "Window::setDOM window size: " << windowWidth << "x" << windowHeight << std::endl;
// Nav background
std::shared_ptr<BoxComponent> navBackground = std::make_unique<BoxComponent>(0.0f, windowHeight - 64.0f, windowWidth, 64.0f, windowWidth, windowHeight);
//navBackground->y = -64;
navBackground->isPickable = false;
// add it to our components
navBackground->parent = rootComponent;
rootComponent->children.push_back(navBackground);
// Address Bar
std::shared_ptr<InputComponent> navAddressBar = std::make_unique<InputComponent>(192.0f, windowHeight - 48.0f, windowWidth - 384.0f, 24.0f, windowWidth, windowHeight);
// add it to our components
navAddressBar->x = 192.0f;
navAddressBar->y = windowHeight-48.0f;
//navAddressBar->y = -48; // this works but breaks picking
navAddressBar->value = currentURL.toString();
navAddressBar->updateText();
navAddressBar->onEnter=[this](std::string value) {
std::cout << "navAddressBar::onEnter got" << value << std::endl;
this->navTo(value);
};
render();
renderDirty = true;
//std::cout << "placing inputComponent at " << static_cast<int>(navAddressBar->x) << "," << static_cast<int>(navAddressBar->y) << std::endl;
navAddressBar->parent = rootComponent;
rootComponent->children.push_back(navAddressBar);
/*
// textTest
// TextComponent(const std::string &rawText, const int rawX, const int rawY, const unsigned int size, const bool bolded, const unsigned int hexColor, const int passedWindowWidth, const int passedWindowHeight);
std::shared_ptr<TextComponent> textTest = std::make_unique<TextComponent>("Test", -99, -99, 12, false, 0x000000ff, windowWidth, windowHeight);
textTest->x=192.0f;
textTest->y=-64.0f;
textTest->isPickable = false;
// add it to our components
textTest->parent = rootComponent;
rootComponent->children.push_back(textTest);
// we really don't want to layout because that's moves us relative to parent
// and this is static layout we want, not a free flow
//textTest->layout(); // to rasterize
textTest->resize(windowWidth, windowHeight);
*/
//Mascot
std::shared_ptr<AnimeComponent> mascot = std::make_unique<AnimeComponent>(windowWidth * 0.75f, 0.0f, 512.0f, 512.0f, windowWidth, windowHeight);
mascot->isPickable = false;
// add it to our components
mascot->parent = rootComponent;
rootComponent->children.push_back(mascot);
// create default document container
std::shared_ptr<DocumentComponent> documentComponent = std::make_shared<DocumentComponent>(0, 0, static_cast<float>(windowWidth), static_cast<float>(windowHeight - 64), windowWidth, windowHeight);
documentComponent->domRootNode = rootNode;
documentComponent->domDirty = true;
documentComponent->y = -64;
// nothing layouts this out beyond thi
documentComponent->rootComponent->y = documentComponent->y;
documentComponent->win = this;
// add it to our components
documentComponent->parent = rootComponent;
rootComponent->children.push_back(documentComponent);
//domRootNode = rootNode;
//domDirty = true;
}
void Window::createComponentTree(const std::shared_ptr<Node> node, const std::shared_ptr<Component> &parentComponent) {
@ -548,13 +683,16 @@ void Window::createComponentTree(const std::shared_ptr<Node> node, const std::sh @@ -548,13 +683,16 @@ void Window::createComponentTree(const std::shared_ptr<Node> node, const std::sh
// add new component as child to parent
//parentComponent->children.push_back(component);
//}
if (node==domRootNode) {
if (component && node==domRootNode) {
// if this is the root node
component->reqWidth = windowWidth;
component->reqHeight = windowHeight;
}
if (!node) {
return;
}
// create children elements
for (std::shared_ptr<Node> child : node->children) {
createComponentTree(child, component);
@ -625,35 +763,45 @@ void Window::renderComponents(std::shared_ptr<Component> component) { @@ -625,35 +763,45 @@ void Window::renderComponents(std::shared_ptr<Component> component) {
std::cout << "Window::renderComponents - got null passed" << std::endl;
return;
}
TextComponent *textComponent = dynamic_cast<TextComponent*>(component.get());
if (textComponent) {
//glUseProgram(fontProgram);
textComponent->render();
DocumentComponent *docComponent = dynamic_cast<DocumentComponent*>(component.get());
if (docComponent) {
docComponent->windowWidth = windowWidth;
docComponent->windowHeight = windowHeight;
docComponent->width = windowWidth;
docComponent->height = windowHeight - 64;
docComponent->render();
} else {
// render non-text components too
/*
BoxComponent *boxComponent = dynamic_cast<BoxComponent*>(component.get());
//inputComponent->render();
if (boxComponent) {
GLenum glErr=glGetError();
if(glErr != GL_NO_ERROR) {
std::cout << "box render start - not ok: " << glErr << std::endl;
TextComponent *textComponent = dynamic_cast<TextComponent*>(component.get());
if (textComponent) {
//glUseProgram(fontProgram);
//std::cout << "Window::renderComponents - rendering text" << std::endl;
textComponent->render();
} else {
// render non-text components too
/*
BoxComponent *boxComponent = dynamic_cast<BoxComponent*>(component.get());
//inputComponent->render();
if (boxComponent) {
GLenum glErr=glGetError();
if(glErr != GL_NO_ERROR) {
std::cout << "box render start - not ok: " << glErr << std::endl;
}
glUseProgram(textureProgram);
glErr=glGetError();
if(glErr != GL_NO_ERROR) {
std::cout << "glUseProgram - not ok: " << glErr << std::endl;
}
boxComponent->render();
}
glUseProgram(textureProgram);
glErr=glGetError();
if(glErr != GL_NO_ERROR) {
std::cout << "glUseProgram - not ok: " <