|
|
|
#include "ComponentBuilder.h"
|
|
|
|
#include <iostream>
|
|
|
|
|
|
|
|
#include "../elements/AElement.h"
|
|
|
|
#include "../elements/BLOCKQUOTEElement.h"
|
|
|
|
#include "../elements/H1Element.h"
|
|
|
|
#include "../elements/H2Element.h"
|
|
|
|
#include "../elements/H3Element.h"
|
|
|
|
#include "../elements/LIElement.h"
|
|
|
|
#include "../elements/PElement.h"
|
|
|
|
#include "../elements/SPANElement.h"
|
|
|
|
#include "../elements/DIVElement.h"
|
|
|
|
#include "../elements/STRONGElement.h"
|
|
|
|
#include "../elements/INPUTElement.h"
|
|
|
|
|
|
|
|
// fwd decl
|
|
|
|
std::shared_ptr<Component> searchComponentTree(const std::shared_ptr<Component> &component, const int passedX, const int passedY);
|
|
|
|
|
|
|
|
const std::unordered_map<std::string, std::shared_ptr<Element>> ComponentBuilder::elementMap {
|
|
|
|
{"a", std::make_shared<AElement>()},
|
|
|
|
{"blockquote", std::make_shared<BLOCKQUOTEElement>()},
|
|
|
|
{"h1", std::make_shared<H1Element>()},
|
|
|
|
{"h2", std::make_shared<H2Element>()},
|
|
|
|
{"h3", std::make_shared<H3Element>()},
|
|
|
|
{"li", std::make_shared<LIElement>()},
|
|
|
|
{"p", std::make_shared<PElement>()},
|
|
|
|
{"span", std::make_shared<SPANElement>()},
|
|
|
|
{"aside", std::make_shared<SPANElement>()},
|
|
|
|
{"div", std::make_shared<DIVElement>()},
|
|
|
|
{"br", std::make_shared<DIVElement>()},
|
|
|
|
{"strong", std::make_shared<STRONGElement>()},
|
|
|
|
{"input", std::make_shared<INPUTElement>()},
|
|
|
|
{"b", std::make_shared<STRONGElement>()},
|
|
|
|
{"i", std::make_shared<SPANElement>()}
|
|
|
|
};
|
|
|
|
|
|
|
|
// FIXME: pass the component it's attached too
|
|
|
|
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());
|
|
|
|
if (tagNode) {
|
|
|
|
tag = tagNode->tag;
|
|
|
|
}
|
|
|
|
} else if (node->nodeType == NodeType::TEXT) {
|
|
|
|
TagNode *tagNode = dynamic_cast<TagNode*>(node->parent.get());
|
|
|
|
if (tagNode) {
|
|
|
|
tag = tagNode->tag;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isInline = false;
|
|
|
|
|
|
|
|
std::unordered_map<std::string, std::shared_ptr<Element>>::const_iterator elementPair = elementMap.find(tag);
|
|
|
|
if (elementPair != elementMap.end()) {
|
|
|
|
std::shared_ptr<Element> element = elementPair->second;
|
|
|
|
isInline = parentComponent->isInline || element->isInline;
|
|
|
|
// also it's Inline if it's a TextNode
|
|
|
|
if (dynamic_cast<TextNode*>(node.get())) {
|
|
|
|
isInline = true;
|
|
|
|
}
|
|
|
|
//std::tie(x,y) = getPos(parentComponent, isInline, windowWidth);
|
|
|
|
//auto [x, y]=getPos(parentComponent, isInline);
|
|
|
|
|
|
|
|
component = element->renderer(node, 0, 0, windowWidth, windowHeight); // doesn't always make a component
|
|
|
|
} else {
|
|
|
|
//std::cout << "Unknown tag: " << tag << std::endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!component) {
|
|
|
|
//std::cout << "tag [" << tag << "] didn't yeild any component" << std::endl;
|
|
|
|
component = std::make_unique<Component>();
|
|
|
|
}
|
|
|
|
TextComponent *textComponent = dynamic_cast<TextComponent*>(component.get());
|
|
|
|
if (textComponent) {
|
|
|
|
//std::cout << "compositing [" << textComponent->text << "]" << std::endl;
|
|
|
|
if (!textComponent->onMousedown) {
|
|
|
|
textComponent->onMousedown = [textComponent](int x, int y) {
|
|
|
|
if (window->selectionList.size()) {
|
|
|
|
std::cout << "unselecting text" << std::endl;
|
|
|
|
for(std::vector<std::shared_ptr<Component>>::iterator it = window->selectionList.begin(); it != window->selectionList.end(); ++it) {
|
|
|
|
TextComponent *selectedTextComponent = dynamic_cast<TextComponent*>(it->get());
|
|
|
|
if (selectedTextComponent) {
|
|
|
|
selectedTextComponent->textSelected = false;
|
|
|
|
selectedTextComponent->updateHighlight();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
window->selectionList.clear();
|
|
|
|
}
|
|
|
|
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;
|
|
|
|
textComponent->highlightStartX = x;
|
|
|
|
textComponent->highlightStartY = ny;
|
|
|
|
std::cout << "Component at " << static_cast<int>(textComponent->x) << "," << static_cast<int>(textComponent->y) << std::endl;
|
|
|
|
};
|
|
|
|
// mouseover to update selection renderer
|
|
|
|
textComponent->onMouseup = [textComponent, parentComponent](int x, int y) {
|
|
|
|
std::cout << "TextSelection ending at " << x << "," << y << std::endl;
|
|
|
|
// find all components in that range
|
|
|
|
|
|
|
|
for(int cx = textComponent->highlightStartX; cx < x; ++cx) {
|
|
|
|
for(int cy = textComponent->highlightStartY; cy < y; ++cy) {
|
|
|
|
std::shared_ptr<Component> cp = searchComponentTree(parentComponent, cx, cy);
|
|
|
|
TextComponent *selectedTextComponent = dynamic_cast<TextComponent*>(cp.get());
|
|
|
|
if (selectedTextComponent) {
|
|
|
|
std::vector<std::shared_ptr<Component>>::iterator it = std::find(window->selectionList.begin(), window->selectionList.end(), cp);
|
|
|
|
if (it == window->selectionList.end()) {
|
|
|
|
selectedTextComponent->textSelected = true;
|
|
|
|
selectedTextComponent->updateHighlight();
|
|
|
|
window->renderDirty = true;
|
|
|
|
window->selectionList.push_back(cp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
std::cout << "selected " << window->selectionList.size() << " components" << std::endl;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
InputComponent *inputComponent = dynamic_cast<InputComponent*>(component.get());
|
|
|
|
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;
|
|
|
|
|
|
|
|
// set our available dimensions
|
|
|
|
component->windowWidth = windowWidth;
|
|
|
|
component->windowHeight = windowHeight;
|
|
|
|
// set our type
|
|
|
|
component->isInline = isInline;
|
|
|
|
|
|
|
|
// need to bind it to the page
|
|
|
|
component->boundToPage = true;
|
|
|
|
|
|
|
|
// place us in tree
|
|
|
|
component->setParent(parentComponent);
|
|
|
|
if (parentComponent) {
|
|
|
|
parentComponent->children.push_back(component);
|
|
|
|
} else {
|
|
|
|
std::cout << "componentBuilder::build - no parentComponent for " << typeOfComponent(component) << std::endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
// figure out our position, size, texture
|
|
|
|
component->layout();
|
|
|
|
/*
|
|
|
|
InputComponent *inputComponent = dynamic_cast<InputComponent*>(component.get());
|
|
|
|
if (inputComponent) {
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
// these aren't used in any elements yet
|
|
|
|
#include "DocumentComponent.h"
|
|
|
|
#include "TabbedComponent.h"
|
|
|
|
#include "AnimeComponent.h"
|
|
|
|
|
|
|
|
std::string typeOfComponent(const std::shared_ptr<Component> &component) {
|
|
|
|
TabbedComponent *tabComponent = dynamic_cast<TabbedComponent*>(component.get());
|
|
|
|
if (tabComponent) return "tab";
|
|
|
|
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";
|
|
|
|
AnimeComponent *animeComponent = dynamic_cast<AnimeComponent*>(component.get());
|
|
|
|
if (animeComponent) return "anime";
|
|
|
|
BoxComponent *boxComponent = dynamic_cast<BoxComponent*>(component.get());
|
|
|
|
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 "";
|
|
|
|
}
|
|
|
|
|
|
|
|
// used for picking
|
|
|
|
std::shared_ptr<Component> 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;
|
|
|
|
}
|