Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

DocumentComponent.cpp 30KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675
  1. #include "DocumentComponent.h"
  2. #include <cmath>
  3. #include <iostream>
  4. #include "InputComponent.h"
  5. #include "ButtonComponent.h"
  6. #include "TabbedComponent.h"
  7. #include <ctime>
  8. #include "../graphical/renderers/glfw/Shader.h"
  9. #include "../../tools/Log.h"
  10. #include "../../tools/WebResource.h"
  11. #include "../../app/browser/Browser.h"
  12. #include "../../parsers/markup/html/HTMLParser.h"
  13. void deleteComponent(std::shared_ptr<Component> &component);
  14. void deleteNode(std::shared_ptr<Node> node);
  15. extern std::unique_ptr<Browser> browser;
  16. #include <utility>
  17. // well we need to know how many chars in a lines
  18. // we also need to know where a line starts (pos)
  19. // lines start at 0 for first line
  20. std::pair<size_t, size_t> getLine(std::string text, int findLine) {
  21. //std::cout << "DocumentComponent.getLine [" << text << "] findLine: " << findLine << std::endl;
  22. size_t pos = 0;
  23. size_t lPos = 0;
  24. pos = text.find("\r");
  25. size_t line = 0;
  26. while(pos != std::string::npos) {
  27. lPos = pos;
  28. pos = text.find("\r", lPos + 1);
  29. if (line == static_cast<unsigned int>(findLine)) {
  30. //std::cout << "lPos: " << lPos << " pos: " << pos << " line: " << line << std::endl;
  31. //std::cout << "DocumentComponent.getLine start " << (lPos + line + 1) << " end " << (pos == std::string::npos ? text.length() : (lPos + pos)) << std::endl;
  32. return std::make_pair(lPos + line + 1, pos == std::string::npos ? text.length() : (lPos + pos));
  33. }
  34. line++;
  35. }
  36. //std::cout << "end lPos: " << lPos << " pos: " << pos << " line: " << line << std::endl;
  37. //std::cout << "DocumentComponent.getLine result end of text" << findLine << std::endl;
  38. return std::make_pair(lPos + line, text.size());
  39. }
  40. size_t getNumberOfLines(std::string text) {
  41. size_t pos = text.find("\r");
  42. size_t lines = 0;
  43. while(pos != std::string::npos) {
  44. lines++;
  45. pos = text.find("\r", pos + 1);
  46. }
  47. return lines;
  48. }
  49. #include <fstream>
  50. DocumentComponent::DocumentComponent(const float rawX, const float rawY, const float rawWidth, const float rawHeight, const int passedWindowWidth, const int passedWindowHeight) : MultiComponent(rawX, rawY, rawWidth, rawHeight, passedWindowWidth, passedWindowHeight) {
  51. //std::cout << "DocumentComponent::DocumentComponent" << std::endl;
  52. windowWidth = passedWindowWidth;
  53. windowHeight = passedWindowHeight;
  54. //std::cout << "DocumentComponent::DocumentComponent - window size: " << windowWidth << "x" << windowHeight << std::endl;
  55. std::shared_ptr<Component> rootComponent = std::make_shared<Component>();
  56. this->layers.push_back(rootComponent);
  57. x = rawX;
  58. y = rawY;
  59. width = rawWidth;
  60. height = rawHeight;
  61. if (height < 0) {
  62. std::cout << "DocumentComponent::DocumentComponent - height was less than zero" << std::endl;
  63. height = 0;
  64. }
  65. std::ifstream fin("res/ntr_bootstrap.js");
  66. std::stringstream buffer;
  67. buffer << fin.rdbuf();
  68. std::string bootstrap_js = buffer.str();
  69. if (bootstrap_js == "") {
  70. std::cout << "DocumentComponent::DocumentComponent - ERROR: Could not load res/ntr_bootstrap.js" << std::endl;
  71. } else {
  72. //std::cout << "DocumentComponent::DocumentComponent - Loaded [" << bootstrap_js << "] ntr_bootstrap.js\n";
  73. this->bootstrapScript = std::make_shared<JavaScript>();
  74. this->bootstrapScript->parse(bootstrap_js);
  75. }
  76. //std::cout << "DocumentComponent::DocumentComponent - our size" << static_cast<int>(width) << "x" << static_cast<int>(height) << std::endl;
  77. onMousemove=[this](int passedX, int passedY) {
  78. // set hover component
  79. static int lx = 0;
  80. static int ly = 0;
  81. //std::cout << "DocumentComponent::DocumentComponent:onMousemove - at " << passedX << "," << passedY << std::endl;
  82. if (lx == passedX && ly == passedY) {
  83. return;
  84. }
  85. lx = passedX;
  86. ly = passedY;
  87. //std::cout << "DocumentComponent::DocumentComponent:onMousemove - size " << this->windowWidth << "," << this->windowHeight << std::endl;
  88. //std::cout << "DocumentComponent::DocumentComponent:onMousemove - at " << passedX << "," << passedY << " scroll: " << (int)(((this->transformMatrix[13] / 2) - 1) * this->windowHeight) << std::endl;
  89. std::shared_ptr<Component> newHover = nullptr;
  90. // FIXME: we may need to iterator backwards here (top layer to back layer)
  91. for(auto layer: this->layers) {
  92. //this->hoverComponent = this->searchComponentTree(this->rootComponent, passedX, passedY + (((this->transformMatrix[13] / 2) - 1) * this->windowHeight));
  93. // apply scroll transformation
  94. std::shared_ptr<Component> found = this->searchComponentTree(layer, passedX, passedY + (((this->transformMatrix[13] / 2) - 1) * this->windowHeight));
  95. if (found) {
  96. newHover = found;
  97. break;
  98. }
  99. }
  100. // FIXME: no mouseOver or out?
  101. this->hoverComponent = newHover;
  102. if (this->hoverComponent) {
  103. //std::cout << "DocumentComponent::DocumentComponent:onMousemove - hovering over " << typeOfComponent(this->hoverComponent) << " component" << std::endl;
  104. if (this->hoverComponent->onMousemove) {
  105. // this could communicate the cursor to use
  106. this->hoverComponent->onMousemove(passedX, passedY);
  107. }
  108. if (this->hoverComponent->onClick || typeOfComponent(this->hoverComponent) == "button") {
  109. glfwSetCursor(this->win->window, this->win->cursorHand);
  110. } else {
  111. glfwSetCursor(this->win->window, this->win->cursorIbeam);
  112. }
  113. } else {
  114. glfwSetCursor(this->win->window, this->win->cursorArrow);
  115. }
  116. };
  117. onWheel=[this](int passedX, int passedY) {
  118. //std::cout << "DocumentComponent::DocumentComponent:::onWheel - scroll yDelta: " << passedY << std::endl;
  119. this->scrollY(passedY);
  120. };
  121. onMousedown=[this](int passedX, int passedY) {
  122. //std::cout << "document left press" << std::endl;
  123. if (this->hoverComponent) {
  124. // if we're hovering over a component that's not focused
  125. if (this->focusedComponent != this->hoverComponent) {
  126. // blur old component
  127. if (this->focusedComponent) {
  128. if (this->focusedComponent->onBlur) {
  129. this->focusedComponent->onBlur();
  130. }
  131. }
  132. // focus new component
  133. if (this->hoverComponent->onFocus) {
  134. this->hoverComponent->onFocus();
  135. }
  136. }
  137. // set hover component as focused
  138. this->focusedComponent = this->hoverComponent;
  139. if (this->focusedComponent->onMousedown) {
  140. //std::cout << "click event" << std::endl;
  141. this->focusedComponent->onMousedown(passedX, passedY);
  142. }
  143. }
  144. };
  145. onMouseup=[this](int passedX, int passedY) {
  146. //std::cout << "document left release" << std::endl;
  147. if (this->hoverComponent) {
  148. //std::cout << "DocumentComponent::DocumentComponent:onMouseup - hovering over " << typeOfComponent(this->hoverComponent) << " component" << std::endl;
  149. if (this->focusedComponent != this->hoverComponent) {
  150. // blur old component
  151. if (this->focusedComponent) {
  152. if (this->focusedComponent->onBlur) {
  153. this->focusedComponent->onBlur();
  154. }
  155. }
  156. // focus new component
  157. if (this->hoverComponent->onFocus) {
  158. this->hoverComponent->onFocus();
  159. }
  160. }
  161. this->focusedComponent = this->hoverComponent;
  162. //std::cout << "DocumentComponent::DocumentComponent:onMouseup - hovering over " << typeOfComponent(this->hoverComponent) << " component, focused on " << typeOfComponent(this->focusedComponent) << std::endl;
  163. if (this->focusedComponent->onMouseup) {
  164. //std::cout << "click event" << std::endl;
  165. this->focusedComponent->onMouseup(passedX, passedY);
  166. }
  167. if (this->focusedComponent && this->focusedComponent->onClick) {
  168. //std::cout << "click event" << std::endl;
  169. this->focusedComponent->onClick();
  170. }
  171. }
  172. };
  173. onKeyUp=[this](int key, int scancode, int action, int mods) {
  174. ///std::cout << "DocumentComponent::DocumentComponent:onKeyup - focus: " << typeOfComponent(this->focusedComponent) << " key: " << key << " scancode: " << scancode << " mods: " << mods << std::endl;
  175. InputComponent *focusedInputComponent = dynamic_cast<InputComponent*>(this->focusedComponent.get());
  176. if (focusedInputComponent) {
  177. //std::cout << "inputComponent is focused, key pressed " << key << " action: " <<action << std::endl;
  178. // FIXME: not going to get repeat events here...
  179. // action 1 is down, 0 is up, 2 is a repeat
  180. if (action == 0 || action == 2) {
  181. // key up
  182. // it's always uppercase...
  183. // FIXME: switch statement this
  184. if (key == GLFW_KEY_BACKSPACE) {
  185. focusedInputComponent->backSpace();
  186. return;
  187. }
  188. if (key == GLFW_KEY_UP) {
  189. focusedInputComponent->updateCursor(0, -1);
  190. return;
  191. }
  192. if (key == GLFW_KEY_DOWN) {
  193. focusedInputComponent->updateCursor(0, 1);
  194. return;
  195. }
  196. if (key == GLFW_KEY_LEFT) {
  197. focusedInputComponent->updateCursor(-1, 0);
  198. return;
  199. }
  200. if (key == GLFW_KEY_RIGHT) {
  201. focusedInputComponent->updateCursor(1, 0);
  202. return;
  203. }
  204. if (key == GLFW_KEY_ENTER) {
  205. //std::cout << "DocumentComponent::onKeyUp - enter!" << std::endl;
  206. if (focusedInputComponent->multiLine) {
  207. // harfbuzz or freetype2 (something?) doesn't like \n //focusedInputComponent->value += "\r";
  208. focusedInputComponent->addChar('\r');
  209. } else {
  210. std::cout << "should submit form!" << std::endl;
  211. if (focusedInputComponent->onEnter) {
  212. focusedInputComponent->onEnter(focusedInputComponent->getValue());
  213. }
  214. return;
  215. }
  216. } else {
  217. if (key < 256) {
  218. if (mods & GLFW_MOD_SHIFT) {
  219. // SHIFT
  220. if (key >= '1' && key <= '9') {
  221. key -= 16;
  222. }
  223. switch(key) {
  224. case GLFW_KEY_SLASH: key='?'; break;
  225. case GLFW_KEY_APOSTROPHE: key='"'; break;
  226. case GLFW_KEY_COMMA: key='<'; break;
  227. case GLFW_KEY_MINUS: key='_'; break;
  228. case GLFW_KEY_PERIOD: key='>'; break;
  229. case GLFW_KEY_SEMICOLON: key=':'; break;
  230. case GLFW_KEY_EQUAL: key='+'; break;
  231. case GLFW_KEY_LEFT_BRACKET: key='{'; break;
  232. case GLFW_KEY_BACKSLASH: key='|'; break;
  233. case GLFW_KEY_RIGHT_BRACKET: key='}'; break;
  234. case GLFW_KEY_GRAVE_ACCENT: key='~'; break;
  235. case GLFW_KEY_0: key=')'; break;
  236. default:
  237. // a key we don't care about atm
  238. break;
  239. }
  240. } else {
  241. // no shift or caplocks
  242. // basically: when SHIFT isn't pressed but key is in A-Z range, add ascii offset to make it lower case
  243. if (key >= 'A' && key <= 'Z') {
  244. key += 'a' - 'A';
  245. }
  246. }
  247. focusedInputComponent->addChar(key);
  248. } // otherwise I think it's some weird control char
  249. }
  250. }
  251. }
  252. //std::cout << "nothing focused " << GLFW_RELEASE << "==" << action << std::endl;
  253. // was press but we don't get those events here
  254. if (key == GLFW_KEY_Q && action == GLFW_RELEASE) {
  255. std::cout << "Q was pressed. Exiting." << std::endl;
  256. exit(0);
  257. }
  258. if (key == GLFW_KEY_E && action == GLFW_RELEASE) {
  259. printf("Printing NodeTree\n\n");
  260. printNode(this->domRootNode, 1);
  261. printf("\n\n");
  262. }
  263. if (key == GLFW_KEY_D && action == GLFW_RELEASE) {
  264. printf("Printing ComponentTree\n\n");
  265. Component::printComponentTree(this->layers[0], 0);
  266. printf("\n\n");
  267. }
  268. if (key == GLFW_KEY_F && action == GLFW_RELEASE) {
  269. printf("Printing UI ComponentTree\n\n");
  270. for(auto layer: this->win->ui->layers) {
  271. Component::printComponentTree(layer, 0);
  272. }
  273. printf("\n\n");
  274. }
  275. if (key == GLFW_KEY_V && action == GLFW_RELEASE) {
  276. printf("Printing JS Variables\n\n");
  277. //std::cout << "DocumentComponent::render - JS var state" << std::endl;
  278. for(auto it : this->mainScript->rootScope.locals.value) {
  279. std::cout << "[" << it.first << "=" << it.second << "]" << std::endl;
  280. }
  281. printf("\n\n");
  282. }
  283. if (key == GLFW_KEY_T && action == GLFW_RELEASE) {
  284. browser->NextTheme();
  285. }
  286. if (key == GLFW_KEY_N && action == GLFW_RELEASE) {
  287. browser->addWindow();
  288. }
  289. // FIXME: probably should just direct set the scroll
  290. // we should have a function for setting scrollY position
  291. if (key == GLFW_KEY_HOME && (action == GLFW_RELEASE || action == GLFW_REPEAT)) {
  292. std::cout << "Home is/was pressed. Scrolling up." << std::endl;
  293. this->scrollY(INT_MAX);
  294. }
  295. if (key == GLFW_KEY_END && (action == GLFW_RELEASE || action == GLFW_REPEAT)) {
  296. std::cout << "End is/was pressed. Scrolling down." << std::endl;
  297. this->scrollY(-INT_MAX);
  298. }
  299. if (key == GLFW_KEY_PAGE_UP && (action == GLFW_RELEASE || action == GLFW_REPEAT)) {
  300. std::cout << "PgUp is/was pressed. Scrolling up." << std::endl;
  301. this->scrollY(170);
  302. }
  303. if (key == GLFW_KEY_PAGE_DOWN && (action == GLFW_RELEASE || action == GLFW_REPEAT)) {
  304. std::cout << "PgDn is/was pressed. Scrolling down." << std::endl;
  305. this->scrollY(-170);
  306. }
  307. if ((key == GLFW_KEY_J || key == GLFW_KEY_UP) && (action == GLFW_RELEASE || action == GLFW_REPEAT)) {
  308. std::cout << "J is/was pressed. Scrolling up." << std::endl;
  309. this->scrollY(4);
  310. }
  311. if ((key == GLFW_KEY_K || key == GLFW_KEY_DOWN) && (action == GLFW_RELEASE || action == GLFW_REPEAT)) {
  312. std::cout << "K is/was pressed. Scrolling down." << std::endl;
  313. this->scrollY(-4);
  314. }
  315. };
  316. onKeyPress=[this](int key, int scancode, int action, int mods) {
  317. InputComponent *focusedInputComponent = dynamic_cast<InputComponent*>(this->focusedComponent.get());
  318. if (focusedInputComponent) {
  319. return;
  320. }
  321. std::cout << "DocumentComponent onKeyPresss - no input component focused" << std::endl;
  322. int yOffsetScroll = 1;
  323. if (key == GLFW_KEY_PAGE_UP && (action == GLFW_PRESS || action == GLFW_REPEAT)) {
  324. std::cout << "PgUp is/was pressed. Scrolling down." << std::endl;
  325. this->scrollY(-yOffsetScroll*0.1);
  326. }
  327. if (key == GLFW_KEY_PAGE_DOWN && (action == GLFW_PRESS || action == GLFW_REPEAT)) {
  328. std::cout << "PgDn is/was pressed. Scrolling up." << std::endl;
  329. this->scrollY(yOffsetScroll*0.1);
  330. }
  331. // FIXME Scrolling with this can scroll past boundary whereas the same doesn't happen with
  332. // scrolling wheel
  333. if (key == GLFW_KEY_J && (action == GLFW_PRESS || action == GLFW_REPEAT)) {
  334. std::cout << "J is/was pressed. Scrolling down." << std::endl;
  335. this->scrollY(-yOffsetScroll*0.1);
  336. }
  337. // FIXME Scrolling with this can scroll past boundary whereas the same doesn't happen with
  338. // scrolling wheel
  339. if (key == GLFW_KEY_K && (action == GLFW_PRESS || action == GLFW_REPEAT)) {
  340. std::cout << "K is/was pressed. Scrolling up." << std::endl;
  341. this->scrollY(yOffsetScroll*0.1);
  342. }
  343. };
  344. }
  345. void DocumentComponent::scrollY(int py) {
  346. //std::cout << "DocumentComponent::scrollY - adjusting Y by " << (py * 0.01) << std::endl;
  347. // we're going to reduce here, so we can get the full signal all the way here
  348. this->transformMatrix[13] -= py * 0.01;
  349. this->textureTransformMatrix[13] -= py * 0.01;
  350. //std::cout << "transformMatrix : " << this->transformMatrix[13] << std::endl;
  351. //std::cout << "textureTransformMatrix: " << this->textureTransformMatrix[13] << std::endl;
  352. // check bounds
  353. if (this->transformMatrix[13] < 2) {
  354. this->transformMatrix[13] = 2;
  355. }
  356. if (this->textureTransformMatrix[13] < 0) {
  357. this->textureTransformMatrix[13] = 0;
  358. }
  359. std::shared_ptr<Component> rootComponent = this->layers[0]; // we only have one layer (currently)
  360. // calculate scroll max by calculating how many screens are in the rootComponent's Height
  361. if (this->transformMatrix[13] > std::max( (rootComponent->height - rootComponent->y) / this->windowHeight * 2.0f, 2.0f)) {
  362. this->transformMatrix[13] = std::max( (rootComponent->height - rootComponent->y) / this->windowHeight * 2.0f, 2.0f);
  363. }
  364. if (this->textureTransformMatrix[13] > std::max( (rootComponent->height - rootComponent->y) / this->windowHeight * 2.0f, 2.0f) - 2.0) {
  365. this->textureTransformMatrix[13] = std::max( (rootComponent->height - rootComponent->y) / this->windowHeight * 2.0f, 2.0f) - 2.0;
  366. }
  367. this->transformMatrixDirty = true;
  368. this->win->renderDirty = true;
  369. }
  370. void deleteComponent(std::shared_ptr<Component> &component) {
  371. // delete all my child first
  372. for (std::shared_ptr<Component> child : component->children) {
  373. deleteComponent(child);
  374. }
  375. component->parent=nullptr;
  376. component->previous=nullptr;
  377. component->children.clear();
  378. component.reset();
  379. // now delete self
  380. }
  381. void deleteNode(std::shared_ptr<Node> node) {
  382. for (std::shared_ptr<Node> child : node->children) {
  383. deleteNode(child);
  384. }
  385. node->parent=nullptr;
  386. node->children.clear();
  387. node->component=nullptr; // disassociate component
  388. node.reset();
  389. }
  390. void DocumentComponent::setDOM(const std::shared_ptr<Node> rootNode) {
  391. std::shared_ptr<Component> rootComponent = this->layers[0]; // we only have one layer (currently)
  392. // reset rootComponent
  393. if (rootComponent) {
  394. deleteComponent(rootComponent);
  395. }
  396. if (domRootNode) {
  397. deleteNode(domRootNode);
  398. }
  399. // reset JS engine
  400. //mainScript.clear();
  401. mainScript = std::make_shared<JavaScript>();
  402. if (this->bootstrapScript) {
  403. mainScript->applyScope(this->bootstrapScript);
  404. mainScript->append(this->bootstrapScript);
  405. } else {
  406. std::cout << "DocumentComponent::setDOM - no bootstrap JS loaded\n";
  407. }
  408. // reset scroll position
  409. //transformMatrix[13] = 2;
  410. //transformMatrixDirty = true;
  411. this->scrollY(0);
  412. // new root component
  413. rootComponent = std::make_shared<Component>();
  414. rootComponent->name = "rootComponent of " + name;
  415. rootComponent->y = y;
  416. domRootNode = rootNode;
  417. //std::cout << "DocumentComponent::setDOM - printing nodes" << endl; printNode(domRootNode, 0);
  418. domDirty = true;
  419. }
  420. void DocumentComponent::render() {
  421. //std::cout << "DocumentComponent::render" << std::endl;
  422. std::shared_ptr<Component> rootComponent = this->layers[0]; // we only have one layer (currently)
  423. if (domDirty) {
  424. const std::clock_t begin = clock();
  425. createComponentTree(domRootNode, rootComponent);
  426. const std::clock_t end = clock();
  427. // root component here doesn't have any children...
  428. std::cout << "built & laid out document components in: " << std::fixed << ((static_cast<double>(end - begin)) / CLOCKS_PER_SEC) << std::scientific << " seconds" << std::endl;
  429. //Component::printComponentTree(rootComponent, 0);
  430. domDirty = false;
  431. /*
  432. std::cout << "DocumentComponent::render - JS var state" << std::endl;
  433. for(auto it : this->mainScript->rootScope.variables) {
  434. std::cout << "[" << it.first << "=" << it.second << "]" << std::endl;
  435. }
  436. */
  437. //std::cout << "root Height: " << static_cast<int>(rootComponent->height) << " window Height: " << windowHeight << " y " << static_cast<int>(this->y) << std::endl;
  438. //scrollHeight = std::max(0, static_cast<int>(rootComponent->height - (windowHeight + (this->y * 2))));
  439. // FIXME recalculate both right?
  440. // recalculate scroll max by calculating how many screens are in the rootComponent's Height
  441. if (transformMatrix[13]>std::max((rootComponent->height)/(windowHeight)*2.0f, 2.0f)) {
  442. transformMatrix[13]=std::max((rootComponent->height)/(windowHeight)*2.0f, 2.0f);
  443. transformMatrixDirty = true;
  444. }
  445. // after we load in the document, allow scroll to work
  446. this->updateMouse();
  447. }
  448. // we have to do this each time because window resets it
  449. //if (transformMatrixDirty) {
  450. //const std::clock_t begin = clock();
  451. Shader *fontShader = this->win->shaderLoader.getShader(VertexShader("FontShader.vert"),
  452. FragmentShader("FontShader.frag"));
  453. GLint transformLocation = fontShader->uniform("transform");
  454. glUniformMatrix4fv(transformLocation, 1, GL_FALSE, transformMatrix);
  455. //const std::clock_t end = clock();
  456. //std::cout << "Updated font matrix in: " << std::fixed << ((static_cast<double>(end - begin)) / CLOCKS_PER_SEC) << std::scientific << " seconds" << std::endl;
  457. Shader *textureShader = this->win->shaderLoader.getShader(VertexShader("TextureShader.vert"),
  458. FragmentShader("TextureShader.frag"));
  459. transformMatrixDirty = false;
  460. //}
  461. //std::cout << "DocumentComponent::render - renderDirty" << std::endl;
  462. textureShader->bind();
  463. GLint transformLocation2 = textureShader->uniform("transform");
  464. glUniformMatrix4fv(transformLocation2, 1, GL_FALSE, textureTransformMatrix);
  465. //std::cout << "DocumentComponent::render - start Box components" << std::endl;
  466. //renderBoxComponents(rootComponent);
  467. this->renderComponentType("input", rootComponent);
  468. this->renderComponentType("button", rootComponent);
  469. //std::cout << "DocumentComponent::render - end Box components" << std::endl;
  470. //textureShader->release(); // just set it to 0, bind is better call
  471. fontShader->bind();
  472. //std::cout << "DocumentComponent::render - start components" << std::endl;
  473. //renderComponents(rootComponent);
  474. this->renderComponentType("text", rootComponent);
  475. //std::cout << "DocumentComponent::render - end components" << std::endl;
  476. fontShader->release();
  477. }
  478. // create this component and all it's children
  479. void DocumentComponent::createComponentTree(const std::shared_ptr<Node> node, const std::shared_ptr<Component> &parentComponent) {
  480. std::shared_ptr<Component> component = componentBuilder.build(node, parentComponent, this->win, this);
  481. //std::cout << "DocumentComponent::createComponentTree" << std::endl;
  482. if (!component) {
  483. //std::cout << "DocumentComponent::createComponentTree - no component" << std::endl;
  484. return;
  485. }
  486. // don't build text node of button component because it'll mess with the picking
  487. if (typeOfComponent(component) == "button") {
  488. // if this button node has children, extract the text before discarding it
  489. if (node->children.size()) {
  490. TextNode *textNode = dynamic_cast<TextNode*>(node->children.front().get());
  491. if (textNode) {
  492. //std::cout << "Button text: " << textNode->text << std::endl;
  493. ButtonComponent *buttonComponent = dynamic_cast<ButtonComponent*>(component.get());
  494. if (buttonComponent) {
  495. // FIXME: strip out more than 1 new line
  496. std::string line(textNode->text);
  497. line.erase(line.find_last_not_of(" \t\n\r\f\v") + 1);
  498. buttonComponent->value = line;
  499. buttonComponent->resizeToTextSize();
  500. buttonComponent->updateText();
  501. }
  502. }
  503. }
  504. return;
  505. }
  506. if (node==domRootNode) {
  507. // if this is the root node
  508. component->reqWidth = windowWidth;
  509. component->reqHeight = windowHeight;
  510. }
  511. // create children elements
  512. for (std::shared_ptr<Node> child : node->children) {
  513. createComponentTree(child, component);
  514. }
  515. }
  516. // used for picking
  517. std::shared_ptr<Component> DocumentComponent::searchComponentTree(const std::shared_ptr<Component> &component, const int passedX, const int passedY) {
  518. // only get hits on leaves (and not to hit the rootComponent every time)
  519. if (component->children.empty()) {
  520. //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;
  521. //std::cout << "DocumentComponent::searchComponentTree - y search: " << static_cast<int>(-component->y) << "<" << static_cast<int>(passedY) << "<" << static_cast<int>(-component->y + component->height) << std::endl;
  522. if (-component->y < passedY && -component->y + component->height > passedY) {
  523. //std::cout << "DocumentComponent::searchComponentTree - x search: " << static_cast<int>(component->x) << "<" << static_cast<int>(passedX) << "<" << static_cast<int>(component->x + component->width) << std::endl;
  524. if (component->x < passedX && component->x + component->width > passedX) {
  525. //std::cout << "DocumentComponent::searchComponentTree - hit " << typeOfComponent(component) << " name: " << component->name << std::endl;
  526. return component;
  527. }
  528. }
  529. } else {
  530. for (std::shared_ptr<Component> child : component->children) {
  531. std::shared_ptr<Component> found = searchComponentTree(child, passedX, passedY);
  532. if (found) {
  533. return found;
  534. }
  535. }
  536. }
  537. return nullptr;
  538. }
  539. // moving naviagtion closer to window, as window is now the owner of currentURL
  540. // preparation for multiple HTML documents
  541. void DocumentComponent::navTo(const std::string url) {
  542. logDebug() << "DocumentComponent::navTo(" << url << ")" << std::endl;
  543. this->currentURL = currentURL.merge(URL(url));
  544. logDebug() << "DocumentComponent::navTo - go to: " << currentURL << std::endl;
  545. //setWindowContent(currentURL);
  546. logDebug() << "main::setWindowContent - " << url << std::endl;
  547. // integrity check
  548. TabbedComponent *tabComponent = dynamic_cast<TabbedComponent*>(this->win->tabComponent.get());
  549. if (!tabComponent->tabs.size()) {
  550. std::cout << "DocumentComponent::navTo - There's a document when there's not tabs" << std::endl;
  551. }
  552. // download URL
  553. WebResource res = getWebResource(this->currentURL);
  554. this->handleResource(res, currentURL.toString());
  555. }
  556. void DocumentComponent::handleResource(WebResource &res, std::string url) {
  557. if (res.resourceType == ResourceType::INVALID) {
  558. logError() << "DocumentComponent::handleResource - Invalid resource type: " << res.raw << std::endl;
  559. std::shared_ptr<Node> rootNode = std::make_shared<Node>(NodeType::ROOT);
  560. std::shared_ptr<TagNode> tagNode = std::make_shared<TagNode>();
  561. tagNode->tag="p";
  562. // bind tag to root
  563. tagNode->parent = rootNode;
  564. rootNode->children.push_back(tagNode);
  565. std::shared_ptr<TextNode> textNode = std::make_shared<TextNode>();
  566. textNode->text = "Invalid Resource Type, HTTP Result Status: " + res.raw;
  567. // bind text to tag
  568. textNode->parent = tagNode;
  569. tagNode->children.push_back(textNode);
  570. // send NodeTree to window
  571. //this->win->setDOM(rootNode);
  572. this->setDOM(rootNode);
  573. }
  574. //std::cout << "body: " << res.raw << std::endl;
  575. //std::cout << "type: " << res.resourceType << std::endl;
  576. // parse HTML
  577. if (res.resourceType == ResourceType::HTML) {
  578. HTMLParser parser;
  579. const std::clock_t begin = clock();
  580. std::shared_ptr<Node> rootNode = parser.parse(res.raw);
  581. const std::clock_t end = clock();
  582. logDebug() << "DocumentComponent::handleResource - Parsed document in: " << std::fixed << ((static_cast<double>(end - begin)) / CLOCKS_PER_SEC) << std::scientific << " seconds" << std::endl;
  583. // send NodeTree to window
  584. //this->win->setDOM(rootNode);
  585. //printNode(rootNode, 0);
  586. // we need a way to communicate with our tabComponent
  587. // maybe an event is best
  588. if (this->onBeforeLoad) {
  589. this->onBeforeLoad(url);
  590. }
  591. this->setDOM(rootNode);
  592. } else if (res.resourceType == ResourceType::TXT) {
  593. std::cout << "DocumentComponent::handleResource - Rendering text document" << std::endl;
  594. std::shared_ptr<Node> rootNode = std::make_shared<Node>(NodeType::ROOT);
  595. std::shared_ptr<TagNode> tagNode = std::make_shared<TagNode>();
  596. tagNode->tag = "p";
  597. // bind tag to root
  598. tagNode->parent = rootNode;
  599. rootNode->children.push_back(tagNode);
  600. std::shared_ptr<TextNode> textNode = std::make_shared<TextNode>();
  601. textNode->text = res.raw;
  602. // bind text to tag
  603. textNode->parent = tagNode;
  604. tagNode->children.push_back(textNode);
  605. // send NodeTree to window
  606. //this->win->setDOM(rootNode);
  607. this->setDOM(rootNode);
  608. } else {
  609. std::cout << "DocumentComponent::handleResource - I don't know how to render non-html files" << std::endl;
  610. }
  611. if (this->win) {
  612. this->win->renderDirty = true;
  613. }
  614. }