You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

400 lines
18 KiB

#include "MultiComponent.h"
#include <iostream>
#include "DocumentComponent.h"
#include "TabbedComponent.h"
#include "AnimeComponent.h"
#include "InputComponent.h"
#include "../opengl/Shader.h"
MultiComponent::MultiComponent(const float rawX, const float rawY, const float rawWidth, const float rawHeight, const int passedWindowWidth, const int passedWindowHeight) {
// take our space (for parent picking)
x = rawX;
y = rawY;
width = rawWidth;
height = rawHeight;
// not really needed but nothing else sets this
windowWidth = passedWindowWidth;
windowHeight = passedWindowHeight;
// we need a mouseout to mouseout our hovercomponent
onMouseout=[this]() {
if (this->hoverComponent && this->hoverComponent->onMouseout) {
this->hoverComponent->onMouseout();
}
// select nothing
this->hoverComponent = nullptr;
};
onMousemove=[this](int passedX, int passedY) {
//std::cout << "MultiComponent::MultiComponent:onMousemove - at " << passedX << "," << passedY << std::endl;
if (this->cursorX == passedX && this->cursorY == passedY) {
return;
}
this->cursorX = passedX;
this->cursorY = passedY;
//std::cout << "MultiComponent::MultiComponent:onMousemove - size " << this->windowWidth << "," << this->windowHeight << std::endl;
this->updateMouse();
};
onMousedown=[this](int passedX, int passedY) {
//std::cout << "MultiComponent 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 << "MultiComponent 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 && this->focusedComponent->onMouseup) {
//std::cout << "click event" << std::endl;
//std::cout << "unloaded1 " << this->parent->unloaded << std::endl;
this->focusedComponent->onMouseup(passedX, passedY);
// ok we can't communicate through the component
//std::cout << "unloaded2 " << this->parent->unloaded << std::endl;
// we can through the window global
//std::cout << "window unloaded focus: " << window->focusedComponent << std::endl;
//std::cout << "window unloaded hover: " << window->hoverComponent << std::endl;
//std::cout << "win unloaded focus: " << this->win->focusedComponent << std::endl;
//std::cout << "win unloaded hover: " << this->win->hoverComponent << std::endl;
}
// make sure we weren't unloaded by last click and check for additional events
if (this->win->focusedComponent != nullptr && this->focusedComponent->onClick) {
//std::cout << "click event" << std::endl;
this->focusedComponent->onClick();
}
}
};
onWheel=[this](int passedX, int passedY) {
//std::cout << "MultiComponent::MultiComponent:onWheel " << passedX << "," << passedY << std::endl;
// if we're hovering over somethign
if (this->hoverComponent) {
// and it receives these messages
if (this->hoverComponent->onWheel) {
// send the event down
this->hoverComponent->onWheel(passedX, passedY);
}
}
//renderDirty = true;
// should we mark win->renderDirty = true?
};
onKeyUp=[this](int key, int scancode, int action, int mods) {
//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;
// 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
}
}
}
};
}
// update component hover (need to call on component change)
void MultiComponent::updateMouse() {
// do we need to make pX/pY relative to this component? no, we just made the picking system take mouse coordinates
std::shared_ptr<Component> newHover = this->searchComponentTree(this->rootComponent, this->cursorX, this->cursorY);
if (newHover != this->hoverComponent) {
if (this->hoverComponent && this->hoverComponent->onMouseout) {
this->hoverComponent->onMouseout();
}
if (newHover && newHover->onMouseover) {
newHover->onMouseover();
}
this->hoverComponent = newHover;
}
if (this->hoverComponent) {
//std::cout << "MultiComponent::MultiComponent:onMousemove - hovering over " << typeOfComponent(this->hoverComponent) << " component" << std::endl;
if (this->hoverComponent->onMousemove) {
// this could communicate the cursor to use
this->hoverComponent->onMousemove(this->cursorX, this->cursorY);
} else {
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);
}
}
//#include "ComponentBuilder.h"
void MultiComponent::resize(const int passedWindowWidth, const int passedWindowHeight) {
// can't get this to work
// , my type: " << typeOfComponent(std::make_shared<Component>(this))
//std::cout << "MultiComponent::resize - relaying out. Name: " << name << std::endl;
windowWidth = passedWindowWidth;
windowHeight = passedWindowHeight;
//Component::printComponentTree(rootComponent, 0);
rootComponent->windowWidth = passedWindowWidth;
rootComponent->windowHeight = passedWindowHeight;
rootComponent->layout();
//Component::printComponentTree(rootComponent, 0);
//renderDirty = true;
// should we mark win->renderDirty = true?
}
void MultiComponent::render() {
//std::cout << "MultiComponent::render" << std::endl;
Shader *fontShader = this->win->shaderLoader.getShader(VertexShader("FontShader.vert"),
FragmentShader("FontShader.frag"));
fontShader->bind();
renderDocumentComponents(rootComponent);
fontShader->release();
Shader *textureShader = this->win->shaderLoader.getShader(VertexShader("TextureShader.vert"),
FragmentShader("TextureShader.frag"));
textureShader->bind();
GLint transformLocation = textureShader->uniform("transform");
glUniformMatrix4fv(transformLocation, 1, GL_FALSE, this->win->textureTransformMatrix);
GLenum glErr=glGetError();
if(glErr != GL_NO_ERROR) {
std::cout << "MultiComponent::render - glUniformMatrix4fv - not ok: " << glErr << std::endl;
}
//std::cout << "MultiComponent::render - start Box components" << std::endl;
renderBoxComponents(rootComponent);
//std::cout << "MultiComponent::render - end Box components" << std::endl;
textureShader->release();
// if we flip, we can't put tab labels on top of the tab
fontShader->bind();
if (!boundToPage) {
GLint transformLocation2 = fontShader->uniform("transform");
glErr=glGetError();
if(glErr != GL_NO_ERROR) {
std::cout << "MultiComponent::render - glGetUniformLocation not ok: " << glErr << std::endl;
}
glUniformMatrix4fv(transformLocation2, 1, GL_FALSE, win->transformMatrix);
glErr=glGetError();
if(glErr != GL_NO_ERROR) {
std::cout << "MultiComponent::render - glUniformMatrix4fv not ok: " << glErr << std::endl;
}
}
//std::cout << "MultiComponent::render - start text components" << std::endl;
renderComponents(rootComponent);
//std::cout << "MultiComponent::render - end text components" << std::endl;
}
// draw this component and all it's children
void MultiComponent::renderComponents(std::shared_ptr<Component> component) {
if (!component) {
std::cout << "DocumentComponent::renderComponents - got null passed" << std::endl;
return;
}
/*
DocumentComponent *docComponent = dynamic_cast<DocumentComponent*>(component.get());
if (docComponent) {
docComponent->render();
}
*/
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 MultiComponent::renderDocumentComponents(std::shared_ptr<Component> component) {
if (!component) {
std::cout << "MultiComponent::renderBoxComponents - got null passed" << std::endl;
return;
}
//std::cout << "MultiComponent::renderBoxComponents - renderering: " << component->name << std::endl;
// render non-text components too
DocumentComponent *docComponent = dynamic_cast<DocumentComponent*>(component.get());
if (docComponent) {
docComponent->render();
}
// is this needed?
if (component->children.empty()) {
return;
}
for (std::shared_ptr<Component> &child : component->children) {
this->renderDocumentComponents(child);
}
}
void MultiComponent::renderBoxComponents(std::shared_ptr<Component> component) {
if (!component) {
std::cout << "MultiComponent::renderBoxComponents - got null passed" << std::endl;
return;
}
//std::cout << "MultiComponent::renderBoxComponents - renderering: " << component->name << std::endl;
// render non-text components too
BoxComponent *boxComponent = dynamic_cast<BoxComponent*>(component.get());
if (boxComponent) {
boxComponent->render();
}
// is this needed?
if (component->children.empty()) {
return;
}
for (std::shared_ptr<Component> &child : component->children) {
this->renderBoxComponents(child);
}
}
void MultiComponent::renderComponentType(std::string str, std::shared_ptr<Component> component) {
if (!component) {
std::cout << "MultiComponent::renderComponentType - got null passed" << std::endl;
return;
}
if (typeOfComponent(component) == str) {
// how slow is this?
if (str == "doc") {
DocumentComponent *docComponent = dynamic_cast<DocumentComponent*>(component.get());
docComponent->render();
} else if (str =="tab") {
TabbedComponent *pTabComponent = dynamic_cast<TabbedComponent*>(component.get());
pTabComponent->render();
} else if (str =="text") {
TextComponent *textComponent = dynamic_cast<TextComponent*>(component.get());
textComponent->render();
} else if (str =="input") {
InputComponent *inputComponent = dynamic_cast<InputComponent*>(component.get());
inputComponent->render();
} else if (str =="anime") {
AnimeComponent *animeComponent = dynamic_cast<AnimeComponent*>(component.get());
animeComponent->render();
} else if (str =="box") {
//AnimeComponent *animeComponent = dynamic_cast<AnimeComponent*>(component.get());
//if (!animeComponent) {
BoxComponent *boxComponent = dynamic_cast<BoxComponent*>(component.get());
boxComponent->render();
//}
} else {
std::cout << "Unknown type " << str << std::endl;
}
//} else {
//std::cout << "type: " << typeOfComponent(component) << "!=" << str << std::endl;
}
// is this needed?
if (component->children.empty()) {
return;
}
for (std::shared_ptr<Component> &child : component->children) {
this->renderComponentType(str, child);
}
}
// used for picking
std::shared_ptr<Component> MultiComponent::searchComponentTree(const std::shared_ptr<Component> &component, const int passedX, const int passedY) {
if (component->children.empty()) {
//std::cout << "MultiComponent::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;
if (tabbed) {
//std::cout << "MultiComponent::searchComponentTree:Tabbed - y search: " << static_cast<int>(component->windowHeight - component->y - component->height) << "<" << static_cast<int>(passedY) << "<" << static_cast<int>(component->windowHeight - component->y) << std::endl;
if (component->windowHeight - component->y - component->height < passedY && component->windowHeight - component->y > passedY) {
//std::cout << "DocumentComponent::searchComponentTree:Tabbed - 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 << "MultiComponent::searchComponentTree:Tabbed - hit " << typeOfComponent(component) << std::endl;
return component;
}
}
} else {
//std::cout << "MultiComponent::searchComponentTree - y search: " << static_cast<int>(-component->y) << "<" << static_cast<int>(passedY) << "<" << 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>(passedX) << "<" << static_cast<int>(component->x + component->width) << std::endl;
if (component->x < passedX && component->x + component->width > passedX) {
//std::cout << "MultiComponent::searchComponentTree - hit " << typeOfComponent(component) << std::endl;
return component;
}
}
}
}
else {
for (std::shared_ptr<Component> child : component->children) {
std::shared_ptr<Component> found = searchComponentTree(child, passedX, passedY);
if (found) {
return found;
}
}
}
return nullptr;
}