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.
 
 
 
 

248 lines
12 KiB

#include "ComponentBuilder.h"
#include <iostream>
#include "../elements/AElement.h"
#include "../elements/H1Element.h"
#include "../elements/H2Element.h"
#include "../elements/H3Element.h"
#include "../elements/LIElement.h"
#include "../elements/SPANElement.h"
#include "../elements/DIVElement.h"
#include "../elements/STRONGElement.h"
#include "../elements/INPUTElement.h"
#include "../elements/BUTTONElement.h"
#include "../elements/TEXTAREAElement.h"
#include "../elements/SCRIPTElement.h"
#include "../elements/LINKElement.h"
#include "InputComponent.h"
#include "ButtonComponent.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<DIVElement>()},
{"h1", std::make_shared<H1Element>()},
{"h2", std::make_shared<H2Element>()},
{"h3", std::make_shared<H3Element>()},
{"li", std::make_shared<LIElement>()},
{"p", std::make_shared<DIVElement>()},
{"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>()},
{"textarea", std::make_shared<TEXTAREAElement>()},
{"button", std::make_shared<BUTTONElement>()},
{"b", std::make_shared<STRONGElement>()},
{"script", std::make_shared<SCRIPTElement>()},
{"link", std::make_shared<LINKElement>()},
{"i", std::make_shared<SPANElement>()}
};
std::shared_ptr<Component> ComponentBuilder::build(const std::shared_ptr<Node> node, const std::shared_ptr<Component> &parentComponent, const std::shared_ptr<Window> win, DocumentComponent *docComponent) {
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
ElementRenderRequest request;
request.node = node;
request.parentComponent = parentComponent;
request.docComponent = docComponent;
component = element->renderer(request); // 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;
// FIXME: put in textcomponent
if (!textComponent->onMousedown) {
textComponent->onMousedown = [textComponent, win](int x, int y) {
if (win->selectionList.size()) {
//std::cout << "unselecting text" << std::endl;
for(std::vector<std::shared_ptr<Component>>::iterator it = win->selectionList.begin(); it != win->selectionList.end(); ++it) {
TextComponent *selectedTextComponent = dynamic_cast<TextComponent*>(it->get());
if (selectedTextComponent) {
selectedTextComponent->textSelected = false;
selectedTextComponent->updateHighlight();
}
}
win->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;
win->highlightStartX = x;
win->highlightStartY = y;
//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, win](int x, int y) {
//std::cout << "TextSelection ending at " << x << "," << y << std::endl;
//int ny = -y;
//std::cout << "TextSelection adjusted " << x << "," << ny << std::endl;
// find all components in that range
//std::cout << "TextSelection started at " << win->highlightStartX << "," << win->highlightStartY << std::endl;
int minX = std::min(win->highlightStartX, x);
int maxX = std::max(win->highlightStartX, x);
int minY = std::min(win->highlightStartY, y);
int maxY = std::max(win->highlightStartY, y);
// FIXME: find root component and search there
// can't use win because we maybe in a sub component
for(int cx = minX; cx < maxX; ++cx) {
for(int cy = minY; cy < maxY; ++cy) {
//std::cout << "textComponent inside " << cx << "," << cy << std::endl;
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(win->selectionList.begin(), win->selectionList.end(), cp);
if (it == win->selectionList.end()) {
selectedTextComponent->textSelected = true;
selectedTextComponent->updateHighlight();
win->renderDirty = true;
win->selectionList.push_back(cp);
}
}
}
}
//std::cout << "selected " << win->selectionList.size() << " components" << std::endl;
};
}
}
InputComponent *inputComponent = dynamic_cast<InputComponent*>(component.get());
ButtonComponent *buttonComponent = dynamic_cast<ButtonComponent*>(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 = win;
//}
//std::cout << "composting component, initial: " << (int)component->width << "x" << (int)component->height << std::endl;
// set our available dimensions
component->win = win;
component->windowWidth = win->windowWidth;
component->windowHeight = win->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();
// not sure why only this component needs this but it fixes it
if (inputComponent) {
//std::cout << "ComponentBuilder::build - Just laid out input component" << std::endl;
//std::cout << "ComponentBuilder::build - inputComponent at " << (int)inputComponent->x << "," << (int)inputComponent->y << std::endl;
inputComponent->updateParentSize();
}
if (buttonComponent) {
//std::cout << "ComponentBuilder::build - buttonComponent at " << (int)buttonComponent->x << "," << (int)buttonComponent->y << std::endl;
// since win is set
buttonComponent->updateText();
buttonComponent->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 "ImageComponent.h"
std::string typeOfComponent(const std::shared_ptr<Component> &component) {
return typeOfComponent(component.get());
}
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";
ButtonComponent *buttonComponent = dynamic_cast<ButtonComponent*>(component);
if (buttonComponent) return "button";
ImageComponent *imageComponent = dynamic_cast<ImageComponent*>(component);
if (imageComponent) return "image";
BoxComponent *boxComponent = dynamic_cast<BoxComponent*>(component);
if (boxComponent) return "box";
return "";
}
// used for picking for text selection
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;
//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;
}