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.

Window.cpp 43KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996
  1. #include "../../URL.h"
  2. #include "Window.h"
  3. #include "../../html/TagNode.h"
  4. #include "../../html/TextNode.h"
  5. #include "../../networking/HTTPRequest.h"
  6. #include "../../html/HTMLParser.h"
  7. #include "../../StringUtils.h"
  8. #include "../../URL.h"
  9. #include "../../Log.h"
  10. #include "../components/BoxComponent.h"
  11. #include "../components/AnimeComponent.h"
  12. #include "../components/DocumentComponent.h"
  13. #include "../components/TabbedComponent.h"
  14. #include "../components/TextComponent.h"
  15. #include "../components/TabbedComponent.h"
  16. #include "../components/InputComponent.h"
  17. #include "../opengl/Shader.h"
  18. #include "../opengl/ShaderLoader.h"
  19. #include "../opengl/shaders/gen/TextureShader.h"
  20. #include "../opengl/shaders/gen/FontShader.h"
  21. #include <cmath>
  22. #include <ctime>
  23. #include <iostream>
  24. Window::~Window() {
  25. glfwTerminate();
  26. }
  27. bool Window::init() {
  28. if (!initGLFW()) {
  29. return false;
  30. }
  31. if (!initGLEW()) {
  32. return false;
  33. }
  34. initGL();
  35. GLenum glErr=glGetError();
  36. if(glErr != GL_NO_ERROR) {
  37. std::cout << "window::init - post initGL - not ok: " << glErr << std::endl;
  38. }
  39. // set proper scroll position
  40. transformMatrix[13] = 2;
  41. transformMatrixDirty = true;
  42. // configure root component
  43. //rootComponent = std::make_shared<Component>();
  44. rootComponent->name = "rootComponent";
  45. //rootComponent->y = 0;
  46. // set up our UI with a new window
  47. // (re)build UI (top to bottom)
  48. //std::cout << "Window::setDOM window size: " << windowWidth << "x" << windowHeight << std::endl;
  49. // layout back to front
  50. // 4 multigroups
  51. // 1 -> mascot
  52. // 2 -> tabbed
  53. // 3 -> box
  54. // 4 -> input
  55. //Mascot
  56. std::shared_ptr<AnimeComponent> mascot = std::make_unique<AnimeComponent>(windowWidth * 0.75f, 0.0f, 512.0f, 512.0f, windowWidth, windowHeight);
  57. mascot->uiControl.x = { 75, 0 }; // 75% width
  58. mascot->uiControl.y = { 0, 0 }; // 0px
  59. mascot->uiControl.w = { 0, 512 }; // 512px
  60. mascot->uiControl.h = { 0, 512 }; // 512px
  61. mascot->boundToPage = false;
  62. mascot->isPickable = false;
  63. mascot->name = "mascot";
  64. // add it to our components
  65. mascot->setParent(rootComponent);
  66. rootComponent->children.push_back(mascot);
  67. // create tabbed component
  68. // doc text is still showing up ontop of buttons
  69. std::shared_ptr<TabbedComponent> tabbedComponent = std::make_shared<TabbedComponent>(0, 0, static_cast<float>(windowWidth), static_cast<float>(windowHeight - 64), windowWidth, windowHeight);
  70. tabbedComponent->name = "tabbedComponent";
  71. tabbedComponent->y = -64;
  72. tabbedComponent->uiControl.x = { 0 , 0 }; // 0
  73. tabbedComponent->uiControl.y = { 0 , -64 }; // -64px
  74. tabbedComponent->uiControl.w = { 100, 0 }; // 100%
  75. tabbedComponent->uiControl.h = { 100, -64 }; // 100% - 64px
  76. tabbedComponent->boundToPage = false;
  77. tabbedComponent->win = this;
  78. // add it to our components
  79. tabbedComponent->setParent(rootComponent);
  80. rootComponent->children.push_back(tabbedComponent);
  81. // Nav background
  82. std::shared_ptr<BoxComponent> navBackground = std::make_unique<BoxComponent>(0.0f, windowHeight - 64.0f, windowWidth, 64.0f, 0x888888FF, windowWidth, windowHeight);
  83. //navBackground->y = -64;
  84. navBackground->uiControl.y = { 100, -64 }; // -64px
  85. navBackground->uiControl.w = { 100, 0 }; // 100%
  86. navBackground->uiControl.h = { 0, 64 }; // 64px
  87. navBackground->isPickable = false;
  88. navBackground->name = "navBackground";
  89. navBackground->boundToPage = false;
  90. // add it to our components
  91. navBackground->setParent(rootComponent);
  92. rootComponent->children.push_back(navBackground);
  93. std::shared_ptr<BoxComponent> navBackButton = std::make_unique<BoxComponent>(32.0f, windowHeight - 48.0f, 32.0f, 32.0f, 0x000000FF, windowWidth, windowHeight);
  94. navBackButton->uiControl.x = { 0, 32 }; // 32px
  95. navBackButton->uiControl.y = { 100, -48 }; // top - 48px
  96. navBackButton->uiControl.w = { 0, 32 }; // 32px
  97. navBackButton->uiControl.h = { 0, 32 }; // 32px
  98. navBackButton->onClick=[this]() {
  99. //std::cout << "Back" << std::endl;
  100. TabbedComponent *pTabComponent = dynamic_cast<TabbedComponent*>(this->tabComponent.get());
  101. if (pTabComponent) {
  102. if (pTabComponent->selectedTabId) {
  103. pTabComponent->selectedTab->get()->history->back();
  104. }
  105. }
  106. };
  107. navBackButton->onMouseover = [navBackButton, this]() {
  108. //std::cout << "navBackButton->onMouseover" << std::endl;
  109. navBackButton->changeColor(0x880000FF);
  110. this->renderDirty = true;
  111. };
  112. navBackButton->onMouseout = [navBackButton, this]() {
  113. //std::cout << "navBackButton->onMouseout" << std::endl;
  114. navBackButton->changeColor(0x000000FF);
  115. this->renderDirty = true;
  116. };
  117. navBackButton->name = "navBackButton";
  118. navBackButton->boundToPage = false;
  119. // add it to our components
  120. navBackButton->setParent(rootComponent);
  121. rootComponent->children.push_back(navBackButton);
  122. std::shared_ptr<BoxComponent> navForwardButton = std::make_unique<BoxComponent>(74.0f, windowHeight - 48.0f, 32.0f, 32.0f, 0x000000FF, windowWidth, windowHeight);
  123. navForwardButton->uiControl.x = { 0, 74 }; // 74px
  124. navForwardButton->uiControl.y = { 100, -48 }; // top - 48px
  125. navForwardButton->uiControl.w = { 0, 32 }; // 32px
  126. navForwardButton->uiControl.h = { 0, 32 }; // 32px
  127. navForwardButton->onClick=[this]() {
  128. //std::cout << "Forward" << std::endl;
  129. TabbedComponent *pTabComponent = dynamic_cast<TabbedComponent*>(this->tabComponent.get());
  130. if (pTabComponent) {
  131. if (pTabComponent->selectedTabId) {
  132. pTabComponent->selectedTab->get()->history->forward();
  133. }
  134. }
  135. };
  136. navForwardButton->onMouseover = [navForwardButton, this]() {
  137. //std::cout << "navForwardButton->onMouseover" << std::endl;
  138. navForwardButton->changeColor(0x008800FF);
  139. this->renderDirty = true;
  140. };
  141. navForwardButton->onMouseout = [navForwardButton, this]() {
  142. //std::cout << "navForwardButton->onMouseout" << std::endl;
  143. navForwardButton->changeColor(0x000000FF);
  144. this->renderDirty = true;
  145. };
  146. navForwardButton->name = "navForwardButton";
  147. navForwardButton->boundToPage = false;
  148. // add it to our components
  149. //navForwardButton->parent = rootComponent;
  150. navForwardButton->setParent(rootComponent);
  151. rootComponent->children.push_back(navForwardButton);
  152. std::shared_ptr<BoxComponent> navRefreshButton = std::make_unique<BoxComponent>(116.0f, windowHeight - 48.0f, 32.0f, 32.0f, 0x000000FF, windowWidth, windowHeight);
  153. navRefreshButton->uiControl.x = { 0, 116 }; // 116px
  154. navRefreshButton->uiControl.y = { 100, -48 }; // top - 48px
  155. navRefreshButton->uiControl.w = { 0, 32 }; // 32px
  156. navRefreshButton->uiControl.h = { 0, 32 }; // 32px
  157. navRefreshButton->name = "navRefreshButton";
  158. navRefreshButton->boundToPage = false;
  159. navRefreshButton->onClick=[this]() {
  160. std::cout << "Refreshing " << this->currentURL << std::endl;
  161. this->navTo(this->currentURL.toString());
  162. };
  163. navRefreshButton->onMouseover = [navRefreshButton, this]() {
  164. //std::cout << "navRefreshButton->onMouseover" << std::endl;
  165. navRefreshButton->changeColor(0x000088FF);
  166. this->renderDirty = true;
  167. };
  168. navRefreshButton->onMouseout = [navRefreshButton, this]() {
  169. //std::cout << "navRefreshButton->onMouseout" << std::endl;
  170. navRefreshButton->changeColor(0x000000FF);
  171. this->renderDirty = true;
  172. }; // add it to our components
  173. navRefreshButton->setParent(rootComponent);
  174. rootComponent->children.push_back(navRefreshButton);
  175. // Address Bar
  176. std::shared_ptr<InputComponent> navAddressBar = std::make_unique<InputComponent>(192.0f, windowHeight - 48.0f, windowWidth - 384.0f, 24.0f, windowWidth, windowHeight);
  177. // add it to our components
  178. navAddressBar->x = 192.0f;
  179. navAddressBar->y = windowHeight-48.0f;
  180. navAddressBar->uiControl.x = { 0, 192 }; // 192px
  181. navAddressBar->uiControl.y = { 100, -48 }; // top - 48px
  182. navAddressBar->uiControl.w = { 100, -384 }; // w - 384px
  183. navAddressBar->uiControl.h = { 0, 24 }; // 24px
  184. navAddressBar->name = "navAddressBar";
  185. navAddressBar->boundToPage = false;
  186. navAddressBar->win = this;
  187. //navAddressBar->y = -48; // this works but breaks picking
  188. navAddressBar->value = currentURL.toString();
  189. navAddressBar->updateText();
  190. navAddressBar->onEnter=[this](std::string value) {
  191. std::cout << "navAddressBar::onEnter got " << value << std::endl;
  192. this->navTo(value);
  193. };
  194. this->addressComponent = navAddressBar;
  195. // we do this to prevent flashing
  196. render();
  197. renderDirty = true;
  198. //std::cout << "placing inputComponent at " << static_cast<int>(navAddressBar->x) << "," << static_cast<int>(navAddressBar->y) << std::endl;
  199. navAddressBar->setParent(rootComponent);
  200. rootComponent->children.push_back(navAddressBar);
  201. /*
  202. // textTest
  203. // 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);
  204. std::shared_ptr<TextComponent> textTest = std::make_unique<TextComponent>("Test", -99, -99, 12, false, 0x000000ff, windowWidth, windowHeight);
  205. textTest->x=192.0f;
  206. textTest->y=-64.0f;
  207. textTest->isPickable = false;
  208. // add it to our components
  209. textTest->parent = rootComponent;
  210. rootComponent->children.push_back(textTest);
  211. // we really don't want to layout because that's moves us relative to parent
  212. // and this is static layout we want, not a free flow
  213. //textTest->layout(); // to rasterize
  214. textTest->resize(windowWidth, windowHeight);
  215. */
  216. // set tab component
  217. this->tabComponent = tabbedComponent;
  218. return true;
  219. }
  220. bool Window::initGLFW() {
  221. if (!glfwInit()) {
  222. std::cout << "Could not initialize GLFW" << std::endl;
  223. return false;
  224. }
  225. glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
  226. glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
  227. glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
  228. glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
  229. //glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API);
  230. glfwSetErrorCallback([](int error, const char* description) {
  231. std::cout << "glfw error [" << error << "]:" << description << std::endl;
  232. });
  233. window = glfwCreateWindow(windowWidth, windowHeight, "NetRunner", nullptr, nullptr);
  234. if (!window) {
  235. glfwTerminate();
  236. std::cout << "Could not create window" << std::endl;
  237. return false;
  238. }
  239. // replace first parameter of all these callbacks with our window object instead of a GLFWwindow
  240. glfwSetWindowUserPointer(window, this);
  241. // set window w/h
  242. //glfwGetFramebufferSize(window, &windowWidth, &windowHeight); // in pixels
  243. glfwGetWindowSize(window, &windowWidth, &windowHeight); // use screen coordinates (not pixels) more retina friendly
  244. // set up event callbacks
  245. glfwSetFramebufferSizeCallback(window, [](GLFWwindow *win, int width, int height) {
  246. glViewport(0, 0, width, height);
  247. });
  248. glfwSetWindowSizeCallback(window, [](GLFWwindow *win, int width, int height) {
  249. Window *thiz = reinterpret_cast<Window*>(glfwGetWindowUserPointer(win));
  250. thiz->onResize(width, height);
  251. });
  252. cursorHand = glfwCreateStandardCursor(GLFW_HAND_CURSOR);
  253. cursorArrow = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
  254. cursorIbeam = glfwCreateStandardCursor(GLFW_IBEAM_CURSOR);
  255. glfwSetCursorPosCallback(window, [](GLFWwindow *win, double xPos, double yPos) {
  256. Window *thiz = reinterpret_cast<Window*>(glfwGetWindowUserPointer(win));
  257. thiz->cursorX = xPos;
  258. thiz->cursorY = yPos;
  259. //std::cout << "Window::Window:onMousemove - at " << static_cast<int>(xPos) << "," << static_cast<int>(yPos) << std::endl;
  260. if (xPos < 0 || yPos < 0) return;
  261. if (xPos > thiz->windowWidth || yPos > thiz->windowHeight) return;
  262. // p. much worthless on double
  263. /*
  264. static double lx = 0;
  265. static double ly = 0;
  266. if (lx == xPos && ly == yPos) {
  267. return;
  268. }
  269. lx = xPos;
  270. ly = yPos;
  271. std::cout << "Window::Window:onMousemove - noCache" << std::endl;
  272. */
  273. //std::cout << "Window::Window:onMousemove - begin search" << std::endl;
  274. //std::cout << "Window::Window:onMousemove - windowHeight: " << thiz->windowHeight << " cursorY: " << thiz->cursorY << " scrollY: " << thiz->transformMatrix[13] << std::endl;
  275. std::shared_ptr<Component> newHover = thiz->searchComponentTree(thiz->rootComponent, thiz->cursorX, (thiz->windowHeight - thiz->cursorY) + ((-thiz->transformMatrix[13] / 2) * thiz->windowHeight));
  276. if (newHover != thiz->hoverComponent) {
  277. if (thiz->hoverComponent && thiz->hoverComponent->onMouseout) {
  278. thiz->hoverComponent->onMouseout();
  279. }
  280. if (newHover && newHover->onMouseover) {
  281. newHover->onMouseover();
  282. }
  283. thiz->hoverComponent = newHover;
  284. }
  285. if (thiz->hoverComponent) {
  286. //std::cout << "Window::Window:onMousemove - hover " << typeOfComponent(thiz->hoverComponent) << std::endl;
  287. if (thiz->hoverComponent->onClick) {
  288. glfwSetCursor(thiz->window, thiz->cursorHand);
  289. } else {
  290. TextComponent *textComponent = dynamic_cast<TextComponent*>(thiz->hoverComponent.get());
  291. InputComponent *inputComponent = dynamic_cast<InputComponent*>(thiz->hoverComponent.get());
  292. if (textComponent || inputComponent) {
  293. glfwSetCursor(thiz->window, thiz->cursorIbeam);
  294. }
  295. // otherwise we could be an Box/Anime or Document Component
  296. }
  297. if (thiz->hoverComponent->onMousemove) {
  298. // this could communicate the cursor to use
  299. thiz->hoverComponent->onMousemove(thiz->cursorX, thiz->cursorY);
  300. }
  301. } else {
  302. glfwSetCursor(thiz->window, thiz->cursorArrow);
  303. }
  304. });
  305. glfwSetScrollCallback(window, [](GLFWwindow *win, double xOffset, double yOffset) {
  306. Window *thiz = reinterpret_cast<Window*>(glfwGetWindowUserPointer(win));
  307. // yOffset is a delta vector
  308. thiz->transformMatrix[13] += -yOffset * 0.1;
  309. if (thiz->hoverComponent) {
  310. //std::cout << "scroll - hovering over a component" << std::endl;
  311. if (thiz->hoverComponent->onWheel) {
  312. //std::cout << "scroll - hovering over a scrollabel component" << std::endl;
  313. thiz->hoverComponent->onWheel(xOffset * 100, yOffset * 100);
  314. }
  315. }
  316. // 2.0 is one screen height
  317. // we draw from 0 downwards (y+), so can't scroll past our starting draw point
  318. if (thiz->transformMatrix[13] < 2) {
  319. thiz->transformMatrix[13] = 2;
  320. }
  321. // calculate scroll max by calculating how many screens are in the rootComponent's Height
  322. if (thiz->transformMatrix[13] > std::max( thiz->rootComponent->height / thiz->windowHeight * 2.0f, 2.0f)) {
  323. thiz->transformMatrix[13] = std::max( thiz->rootComponent->height / thiz->windowHeight * 2.0f, 2.0f);
  324. }
  325. //std::cout << "scroll y is at " << thiz->transformMatrix[13] << "/" << static_cast<int>((thiz->transformMatrix[13]*10000) << std::endl;
  326. thiz->transformMatrixDirty = true;
  327. });
  328. glfwSetMouseButtonCallback(window, [](GLFWwindow *win, int button, int action, int mods) {
  329. Window *thiz = reinterpret_cast<Window*>(glfwGetWindowUserPointer(win));
  330. if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS) {
  331. //std::cout << "left press" << std::endl;
  332. if (thiz->hoverComponent) {
  333. //std::cout << "focus event" << std::endl;
  334. if (thiz->focusedComponent != thiz->hoverComponent) {
  335. // blur old component
  336. if (thiz->focusedComponent) {
  337. if (thiz->focusedComponent->onBlur) {
  338. thiz->focusedComponent->onBlur();
  339. }
  340. }
  341. // focus new component
  342. if (thiz->hoverComponent->onFocus) {
  343. thiz->hoverComponent->onFocus();
  344. }
  345. }
  346. thiz->focusedComponent = thiz->hoverComponent;
  347. if (thiz->focusedComponent->onMousedown) {
  348. //std::cout << "click event" << std::endl;
  349. thiz->focusedComponent->onMousedown(thiz->cursorX, thiz->cursorY);
  350. }
  351. }
  352. }
  353. if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_RELEASE) {
  354. //std::cout << "left release" << std::endl;
  355. if (thiz->hoverComponent) {
  356. //std::cout << "focus event" << std::endl;
  357. if (thiz->focusedComponent != thiz->hoverComponent) {
  358. // blur old component
  359. if (thiz->focusedComponent) {
  360. if (thiz->focusedComponent->onBlur) {
  361. thiz->focusedComponent->onBlur();
  362. }
  363. }
  364. // focus new component
  365. if (thiz->hoverComponent->onFocus) {
  366. thiz->hoverComponent->onFocus();
  367. }
  368. }
  369. thiz->focusedComponent = thiz->hoverComponent;
  370. /*
  371. InputComponent *inputComponent = dynamic_cast<InputComponent*>(thiz->focusedComponent.get());
  372. if (inputComponent) {
  373. std::cout << "inputComponent focus" << std::endl;
  374. }
  375. */
  376. if (thiz->focusedComponent && thiz->focusedComponent->onMouseup) {
  377. //std::cout << "click event" << std::endl;
  378. thiz->focusedComponent->onMouseup(thiz->cursorX, thiz->cursorY);
  379. }
  380. if (thiz->focusedComponent && thiz->focusedComponent->onClick) {
  381. //std::cout << "click event" << std::endl;
  382. thiz->focusedComponent->onClick();
  383. }
  384. }
  385. }
  386. });
  387. // works with utf-32 but we'll lkeep the low level for now
  388. /*
  389. glfwSetCharCallback(window, [](GLFWwindow* win, unsigned int codepoint) {
  390. Window *thiz = reinterpret_cast<Window*>(glfwGetWindowUserPointer(win));
  391. std::cout << "Window::glfwSetCharCallback - codepoint: " << codepoint << std::endl;
  392. });
  393. */
  394. glfwSetKeyCallback(window, [](GLFWwindow *win, int key, int scancode, int action, int mods) {
  395. Window *thiz = reinterpret_cast<Window*>(glfwGetWindowUserPointer(win));
  396. // we're focused on something
  397. //std::cout << "glfwSetKeyCallback" << std::endl;
  398. if (thiz->focusedComponent) {
  399. //std::cout << "glfwSetKeyCallback - focused on " << typeOfComponent(thiz->focusedComponent) << std::endl;
  400. TabbedComponent *p_tabComponent = dynamic_cast<TabbedComponent*>(thiz->focusedComponent.get());
  401. if (p_tabComponent) {
  402. // repeat or key up
  403. if (action == 2 || action == 0) {
  404. if (p_tabComponent->onKeyPress) {
  405. p_tabComponent->onKeyPress(key, scancode, action, mods);
  406. }
  407. if (action == 0) {
  408. if (p_tabComponent->onKeyup) {
  409. p_tabComponent->onKeyup(key, scancode, action, mods);
  410. }
  411. }
  412. }
  413. return;
  414. }
  415. DocumentComponent *docComponent = dynamic_cast<DocumentComponent*>(thiz->focusedComponent.get());
  416. if (docComponent) {
  417. if (action == 0) {
  418. if (docComponent->onKeyup) {
  419. docComponent->onKeyup(key, scancode, action, mods);
  420. }
  421. }
  422. return;
  423. }
  424. InputComponent *inputComponent = dynamic_cast<InputComponent*>(thiz->focusedComponent.get());
  425. if (inputComponent) {
  426. //std::cout << "inputComponent is focsued, key pressed " << key << " action: " <<action << std::endl;
  427. // action 1 is down, 0 is up, 2 is a repeat
  428. if (action == 0 || action == 2) {
  429. // key up
  430. // it's always uppercase...
  431. if (key == 259) {
  432. inputComponent->backSpace();
  433. } else if (key == 257) {
  434. std::cout << "enter!" << std::endl;
  435. if (inputComponent->onEnter) {
  436. inputComponent->onEnter(inputComponent->value);
  437. }
  438. } else {
  439. if (key < 256) {
  440. if (mods & GLFW_MOD_SHIFT) {
  441. // SHIFT
  442. if (key == GLFW_KEY_SLASH) key='?';
  443. if (key == GLFW_KEY_APOSTROPHE) key='"';
  444. if (key == GLFW_KEY_COMMA) key='<';
  445. if (key == GLFW_KEY_MINUS) key='_';
  446. if (key == GLFW_KEY_PERIOD) key='>';
  447. if (key == GLFW_KEY_SEMICOLON) key=':';
  448. if (key == GLFW_KEY_EQUAL) key='+';
  449. if (key == GLFW_KEY_LEFT_BRACKET) key='{';
  450. if (key == GLFW_KEY_BACKSLASH) key='|';
  451. if (key == GLFW_KEY_RIGHT_BRACKET) key='}';
  452. if (key == GLFW_KEY_GRAVE_ACCENT) key='~';
  453. } else {
  454. // no shift or caplocks
  455. // basically: when SHIFT isn't pressed but key is in A-Z range, add ascii offset to make it lower case
  456. if (key >= 'A' && key <= 'Z') {
  457. key += 'a' - 'A';
  458. }
  459. }
  460. inputComponent->addChar(key);
  461. } // otherwise I think it's some weird control char
  462. }
  463. }
  464. return;
  465. }
  466. }
  467. switch (key) {
  468. case GLFW_KEY_1:
  469. case GLFW_KEY_2:
  470. case GLFW_KEY_3:
  471. case GLFW_KEY_4:
  472. case GLFW_KEY_5:
  473. case GLFW_KEY_6:
  474. case GLFW_KEY_7:
  475. case GLFW_KEY_8:
  476. case GLFW_KEY_9:
  477. case GLFW_KEY_0:
  478. std::cout << "Key was pressed: " << key << std::endl;
  479. //thiz->transformMatrixIndex = key - GLFW_KEY_0;
  480. //std::cout << thiz->transformMatrixIndex << std::endl;
  481. break;
  482. default:
  483. break;
  484. }
  485. if (key == GLFW_KEY_Q && action == GLFW_PRESS) {
  486. std::cout << "Q was pressed. Exiting." << std::endl;
  487. exit(0);
  488. }
  489. if (key == GLFW_KEY_E && action == GLFW_RELEASE) {
  490. printf("Printing NodeTree\n\n");
  491. TabbedComponent *p_TabComponent = dynamic_cast<TabbedComponent*>(thiz->tabComponent.get());
  492. if (p_TabComponent) {
  493. DocumentComponent *p_DocComponent = dynamic_cast<DocumentComponent*>(p_TabComponent->documentComponent.get());
  494. if (p_DocComponent) {
  495. printNode(p_DocComponent->domRootNode, 1);
  496. }
  497. }
  498. printf("\n\n");
  499. }
  500. if (key == GLFW_KEY_D && action == GLFW_RELEASE) {
  501. printf("Printing ComponentTree\n\n");
  502. TabbedComponent *p_TabComponent = dynamic_cast<TabbedComponent*>(thiz->tabComponent.get());
  503. if (p_TabComponent) {
  504. DocumentComponent *p_DocComponent = dynamic_cast<DocumentComponent*>(p_TabComponent->documentComponent.get());
  505. if (p_DocComponent) {
  506. Component::printComponentTree(p_DocComponent->rootComponent, 0);
  507. }
  508. }
  509. printf("\n\n");
  510. }
  511. if (key == GLFW_KEY_F && action == GLFW_RELEASE) {
  512. printf("Printing UI ComponentTree\n\n");
  513. Component::printComponentTree(thiz->rootComponent, 0);
  514. printf("\n\n");
  515. }
  516. int yOffsetScroll = 1;
  517. if (key == GLFW_KEY_PAGE_UP && (action == GLFW_PRESS || action == GLFW_REPEAT)) {
  518. TabbedComponent *p_TabComponent = dynamic_cast<TabbedComponent*>(thiz->tabComponent.get());
  519. if (p_TabComponent) {
  520. DocumentComponent *p_DocComponent = dynamic_cast<DocumentComponent*>(p_TabComponent->documentComponent.get());
  521. if (p_DocComponent) {
  522. p_DocComponent->transformMatrix[13] += -yOffsetScroll * 0.1;
  523. p_DocComponent->transformMatrixDirty = true;
  524. thiz->renderDirty = true;
  525. }
  526. }
  527. }
  528. if (key == GLFW_KEY_PAGE_DOWN && (action == GLFW_PRESS || action == GLFW_REPEAT)) {
  529. TabbedComponent *p_TabComponent = dynamic_cast<TabbedComponent*>(thiz->tabComponent.get());
  530. if (p_TabComponent) {
  531. DocumentComponent *p_DocComponent = dynamic_cast<DocumentComponent*>(p_TabComponent->documentComponent.get());
  532. if (p_DocComponent) {
  533. p_DocComponent->transformMatrix[13] += yOffsetScroll * 0.1;
  534. p_DocComponent->transformMatrixDirty = true;
  535. thiz->renderDirty = true;
  536. }
  537. }
  538. }
  539. // FIXME Scrolling with this can scroll past boundary whereas the same doesn't happen with
  540. // scrolling wheel
  541. if (key == GLFW_KEY_J && (action == GLFW_PRESS || action == GLFW_REPEAT)) {
  542. std::cout << "J is/was pressed. Scrolling down." << std::endl;
  543. TabbedComponent *p_TabComponent = dynamic_cast<TabbedComponent*>(thiz->tabComponent.get());
  544. if (p_TabComponent) {
  545. DocumentComponent *p_DocComponent = dynamic_cast<DocumentComponent*>(p_TabComponent->documentComponent.get());
  546. if (p_DocComponent) {
  547. p_DocComponent->transformMatrix[13] += yOffsetScroll * 0.1;
  548. p_DocComponent->transformMatrixDirty = true;
  549. thiz->renderDirty = true;
  550. }
  551. }
  552. }
  553. // FIXME Scrolling with this can scroll past boundary whereas the same doesn't happen with
  554. // scrolling wheel
  555. if (key == GLFW_KEY_K && (action == GLFW_PRESS || action == GLFW_REPEAT)) {
  556. std::cout << "K is/was pressed. Scrolling up." << std::endl;
  557. TabbedComponent *p_TabComponent = dynamic_cast<TabbedComponent*>(thiz->tabComponent.get());
  558. if (p_TabComponent) {
  559. DocumentComponent *p_DocComponent = dynamic_cast<DocumentComponent*>(p_TabComponent->documentComponent.get());
  560. if (p_DocComponent) {
  561. p_DocComponent->transformMatrix[13] += -yOffsetScroll * 0.1;
  562. p_DocComponent->transformMatrixDirty = true;
  563. thiz->renderDirty = true;
  564. }
  565. }
  566. }
  567. });
  568. glfwMakeContextCurrent(window);
  569. return true;
  570. }
  571. bool Window::initGLEW() const {
  572. glewExperimental = GL_TRUE;
  573. const GLenum err = glewInit();
  574. if (err != GLEW_OK) {
  575. std::cout << "Could not initialize GLEW: " << glewGetErrorString(err) << std::endl;
  576. return false;
  577. }
  578. return true;
  579. }
  580. bool Window::initGL() {
  581. const GLubyte *renderer = glGetString(GL_RENDERER);
  582. const GLubyte *version = glGetString(GL_VERSION);
  583. std::cout << "Renderer: " << renderer << std::endl;
  584. std::cout << "Version: " << version << std::endl;
  585. glEnable(GL_BLEND);
  586. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  587. glClearColor(0.8f, 0.8f, 0.8f, 0.8f);
  588. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  589. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  590. GLenum glErr=glGetError();
  591. if(glErr != GL_NO_ERROR) {
  592. std::cout << "window::initGL - blend, clear, texParam - not ok: " << glErr << std::endl;
  593. }
  594. //std::cout << "OpenGL is set up" << std::endl;
  595. glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
  596. return true;
  597. }
  598. void Window::onResize(int passedWidth, int passedHeight) {
  599. this->windowWidth = passedWidth;
  600. this->windowHeight = passedHeight;
  601. this->delayResize = 1;
  602. }
  603. void Window::resize() {
  604. //std::cout << "Window::resize" << std::endl;
  605. const std::clock_t begin = clock();
  606. //resizeComponentTree(rootComponent, windowWidth, windowHeight);
  607. //this->printComponentTree(rootComponent, 0);
  608. //this->buildUI();
  609. rootComponent->windowWidth = windowWidth;
  610. rootComponent->windowHeight = windowHeight;
  611. rootComponent->layout();
  612. const std::clock_t end = clock();
  613. std::cout << "Window::resize - resized components in: " << std::fixed << ((static_cast<double>(end - begin)) / CLOCKS_PER_SEC) << std::scientific << " seconds" << std::endl;
  614. //this->printComponentTree(rootComponent, 0);
  615. // recalculate scroll max by calculating how many screens are in the rootComponent's Height
  616. if (transformMatrix[13]>std::max((rootComponent->height)/(windowHeight)*2.0f, 2.0f)) {
  617. transformMatrix[13]=std::max((rootComponent->height)/(windowHeight)*2.0f, 2.0f);
  618. transformMatrixDirty = true;
  619. }
  620. //thiz->printComponentTree(thiz->rootComponent, 0);
  621. //printComponentTree(rootComponent, 0);
  622. renderDirty = true;
  623. }
  624. void Window::render() {
  625. if (delayResize) {
  626. delayResize--;
  627. if (delayResize) {
  628. return;
  629. }
  630. //std::cout << "Window::render - restarting drawing" << std::endl;
  631. this->resize();
  632. }
  633. /*
  634. if (domDirty) {
  635. const std::clock_t begin = clock();
  636. createComponentTree(domRootNode, rootComponent);
  637. const std::clock_t end = clock();
  638. std::cout << "built & laid out window components in: " << std::fixed << ((static_cast<double>(end - begin)) / CLOCKS_PER_SEC) << std::scientific << " seconds" << std::endl;
  639. //printComponentTree(rootComponent, 0);
  640. //std::cout << "Window printComponentTree end" << std::endl;
  641. domDirty = false;
  642. renderDirty = true;
  643. }
  644. */
  645. if (renderDirty || transformMatrixDirty) {
  646. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  647. GLenum glErr=glGetError();
  648. if(glErr != GL_NO_ERROR) {
  649. std::cout << "window::render - box render start - not ok: " << glErr << std::endl;
  650. }
  651. Shader *textureShader = ShaderLoader::getShader(VertexShader(textureVertexShaderSource),
  652. FragmentShader(textureFragmentShaderSource));
  653. textureShader->bind();
  654. glErr=glGetError();
  655. if(glErr != GL_NO_ERROR) {
  656. std::cout << "window::render - glUseProgram - not ok: " << glErr << std::endl;
  657. }
  658. // draw anime 1st, tabbed components 2nd
  659. // then box shit
  660. // text last
  661. renderComponentType("anime", rootComponent);
  662. renderComponentType("tab", rootComponent);
  663. textureShader->bind();
  664. //GLint transformLocation = glGetUniformLocation(textureProgram, "transform");
  665. //glUniformMatrix4fv(transformLocation, 1, GL_FALSE, transformMatrix);
  666. renderComponentType("box", rootComponent);
  667. renderComponentType("input", rootComponent);
  668. // it's quick but done on scroll
  669. Shader *fontShader = ShaderLoader::getShader(VertexShader(fontVertexShaderSource),
  670. FragmentShader(fontFragmentShaderSource));
  671. fontShader->bind();
  672. // reset both, since components can change this
  673. // god we may have to reset this after each component render...
  674. // maybe we don't need too
  675. if (transformMatrixDirty) {
  676. //const std::clock_t begin = clock();
  677. GLint transformLocation = fontShader->uniform("transform");
  678. glErr=glGetError();
  679. if(glErr != GL_NO_ERROR) {
  680. std::cout << "window::render - glGetUniformLocation - not ok: " << glErr << std::endl;
  681. }
  682. glUniformMatrix4fv(transformLocation, 1, GL_FALSE, transformMatrix);
  683. glErr=glGetError();
  684. if(glErr != GL_NO_ERROR) {
  685. std::cout << "window::render - glUniformMatrix4fv - not ok: " << glErr << std::endl;
  686. }
  687. // didn't change much (could be we didnt' select the textureProgram first)
  688. //GLint transformLocation2 = glGetUniformLocation(textureProgram, "transform");
  689. //glUniformMatrix4fv(transformLocation2, 1, GL_FALSE, transformMatrix);
  690. //const std::clock_t end = clock();
  691. //std::cout << "Updated font matrix in: " << std::fixed << ((static_cast<double>(end - begin)) / CLOCKS_PER_SEC) << std::scientific << " seconds" << std::endl;
  692. transformMatrixDirty = false;
  693. }
  694. //renderComponents(rootComponent);
  695. renderComponentType("text", rootComponent);
  696. glfwSwapBuffers(window);
  697. // update 2nd buffer
  698. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  699. textureShader->bind();
  700. renderComponentType("anime", rootComponent);
  701. renderComponentType("tab", rootComponent);
  702. textureShader->bind();
  703. renderComponentType("box", rootComponent);
  704. renderComponentType("input", rootComponent);
  705. // it's quick but done on scroll
  706. fontShader->bind();
  707. renderComponentType("text", rootComponent);
  708. glfwSwapBuffers(window);
  709. renderDirty = false;
  710. }
  711. glfwSwapBuffers(window);
  712. glfwPollEvents();
  713. }
  714. void Window::setDOM(const std::shared_ptr<Node> rootNode) {
  715. // reset scroll position
  716. transformMatrix[13] = 2;
  717. transformMatrixDirty = true;
  718. if (!tabComponent) {
  719. std::cout << "Window::setDOM - no tabComponent" << std::endl;
  720. return;
  721. }
  722. std::cout << "Window::setDOM - tabComponent is already set up" << std::endl;
  723. TabbedComponent *tabbedComponent = dynamic_cast<TabbedComponent*>(tabComponent.get());
  724. if (!tabbedComponent->tabs.size()) {
  725. // if no tabs, make one
  726. tabbedComponent->addTab(currentURL.toString());
  727. //tabbedComponent->selectTab(tabbedComponent->tabs.back()->id);
  728. tabbedComponent->selectTab(tabbedComponent->tabs.back());
  729. }
  730. tabbedComponent->loadDomIntoTab(rootNode, currentURL.toString());
  731. }
  732. void Window::createComponentTree(const std::shared_ptr<Node> node, const std::shared_ptr<Component> &parentComponent) {
  733. std::shared_ptr<Component> component = componentBuilder.build(node, parentComponent, windowWidth, windowHeight);
  734. // ComponentBuilder now calls setParent and setParents adds children
  735. //component->setParent(parentComponent);
  736. // set parent of the newly created component
  737. //component->parent = parentComponent;
  738. //if (parentComponent) {
  739. // add new component as child to parent
  740. //parentComponent->children.push_back(component);
  741. //}
  742. if (component && component==this->rootComponent) {
  743. // if this is the root node
  744. component->reqWidth = windowWidth;
  745. component->reqHeight = windowHeight;
  746. }
  747. if (!node) {
  748. return;
  749. }
  750. // create children elements
  751. for (std::shared_ptr<Node> child : node->children) {
  752. createComponentTree(child, component);
  753. }
  754. // update parents, creation brings them up to date
  755. //updateComponentSize(component);
  756. }
  757. void Window::renderComponentType(std::string str, std::shared_ptr<Component> component) {
  758. if (!component) {
  759. std::cout << "Window::renderComponentType - got null passed" << std::endl;
  760. return;
  761. }
  762. if (typeOfComponent(component) == str) {
  763. // how slow is this?
  764. if (str == "doc") {
  765. DocumentComponent *docComponent = dynamic_cast<DocumentComponent*>(component.get());
  766. docComponent->render();
  767. } else if (str =="tab") {
  768. TabbedComponent *pTabComponent = dynamic_cast<TabbedComponent*>(component.get());
  769. pTabComponent->render();
  770. } else if (str =="text") {
  771. TextComponent *textComponent = dynamic_cast<TextComponent*>(component.get());
  772. textComponent->render();
  773. } else if (str =="input") {
  774. InputComponent *inputComponent = dynamic_cast<InputComponent*>(component.get());
  775. inputComponent->render();
  776. } else if (str =="anime") {
  777. AnimeComponent *animeComponent = dynamic_cast<AnimeComponent*>(component.get());
  778. animeComponent->render();
  779. } else if (str =="box") {
  780. //AnimeComponent *animeComponent = dynamic_cast<AnimeComponent*>(component.get());
  781. //if (!animeComponent) {
  782. BoxComponent *boxComponent = dynamic_cast<BoxComponent*>(component.get());
  783. boxComponent->render();
  784. //}
  785. } else {
  786. std::cout << "Unknown type " << str << std::endl;
  787. }
  788. //} else {
  789. //std::cout << "type: " << typeOfComponent(component) << "!=" << str << std::endl;
  790. }
  791. // is this needed?
  792. if (component->children.empty()) {
  793. return;
  794. }
  795. for (std::shared_ptr<Component> &child : component->children) {
  796. this->renderComponentType(str, child);
  797. }
  798. }
  799. // used for picking
  800. // should return multiple components
  801. std::shared_ptr<Component> Window::searchComponentTree(const std::shared_ptr<Component> &component, const int x, const int y) {
  802. if (component->children.empty()) {
  803. // x,y: 0,0 is the upper left
  804. //std::cout << "cursor at: " << x << "," << y << " 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;
  805. int ty = component->y;
  806. int ty1 = component->height + component->y;
  807. if (ty < 0) {
  808. ty = 0;
  809. ty1 += 64; // FIXME: hack (for what?)
  810. }
  811. //std::cout << "Window::searchComponentTree - y search: " << ty1 << ">" << static_cast<int>(this->windowHeight + y) << ">" << static_cast<int>(ty) << std::endl;
  812. if (ty1 > this->windowHeight + y && this->windowHeight + y > ty) {
  813. //std::cout << "y match" << std::endl;
  814. if (component->x < x && component->x + component->width > x) {
  815. //std::cout << "Window::searchComponentTree - hit " << typeOfComponent(component) << std::endl;
  816. return component;
  817. }
  818. }
  819. }
  820. else {
  821. for (std::shared_ptr<Component> child : component->children) {
  822. if (!child->isPickable) continue;
  823. std::shared_ptr<Component> found = searchComponentTree(child, x, y);
  824. if (found) {
  825. return found;
  826. }
  827. }
  828. }
  829. return nullptr;
  830. }
  831. // moving naviagtion closer to window, as window is now the owner of currentURL
  832. // preparation for multiple HTML documents
  833. void Window::navTo(std::string url) {
  834. logDebug() << "Window::navTo(" << url << ")" << std::endl;
  835. URL link=URL(url);
  836. logDebug() << "Window::navTo - URL marshalled [" << link << "]" << std::endl;
  837. currentURL = currentURL.merge(link);
  838. logDebug() << "go to: " << currentURL << std::endl;
  839. focusedComponent = nullptr;
  840. hoverComponent = nullptr;
  841. setWindowContent(currentURL);
  842. }
  843. /*
  844. void handleRequest(const HTTPResponse &response) {
  845. std::cout << "main:::handleRequest - statusCode: " << response.statusCode << std::endl;
  846. if (response.statusCode == 200) {
  847. const std::unique_ptr<HTMLParser> parser = std::make_unique<HTMLParser>();
  848. const std::clock_t begin = clock();
  849. std::shared_ptr<Node> rootNode = parser->parse(response.body);
  850. const std::clock_t end = clock();
  851. std::cout << "Parsed document in: " << std::fixed << ((static_cast<double>(end - begin)) / CLOCKS_PER_SEC) << std::scientific << " seconds" << std::endl;
  852. window->setDOM(rootNode);
  853. }
  854. else if (response.statusCode == 301) {
  855. std::string location;
  856. if (response.properties.find("Location")==response.properties.end()) {
  857. if (response.properties.find("location")==response.properties.end()) {
  858. std::cout << "::handleRequest - got 301 without a location" << std::endl;
  859. for(auto const &row : response.properties) {
  860. std::cout << "::handleRequest - " << row.first << "=" << response.properties.at(row.first) << std::endl;
  861. }
  862. return;
  863. } else {
  864. location = response.properties.at("location");
  865. }
  866. } else {
  867. location = response.properties.at("Location");
  868. }
  869. std::cout << "Redirect To: " << location << std::endl;
  870. std::shared_ptr<URI> uri = parseUri(location);
  871. const std::unique_ptr<HTTPRequest> request = std::make_unique<HTTPRequest>(uri);
  872. request->sendRequest(handleRequest);
  873. return;
  874. }
  875. else {
  876. std::cout << "Unknown Status Code: " << response.statusCode << std::endl;
  877. }
  878. }
  879. */
  880. // tried to make a window method
  881. void handleRequest(const HTTPResponse &response) {
  882. std::cout << "Window:::handleRequest - statusCode: " << response.statusCode << std::endl;
  883. if (response.statusCode == 200) {
  884. const std::unique_ptr<HTMLParser> parser = std::make_unique<HTMLParser>();
  885. const std::clock_t begin = clock();
  886. std::shared_ptr<Node> rootNode = parser->parse(response.body);
  887. const std::clock_t end = clock();
  888. std::cout << "Parsed document in: " << std::fixed << ((static_cast<double>(end - begin)) / CLOCKS_PER_SEC) << std::scientific << " seconds" << std::endl;
  889. window->setDOM(rootNode);
  890. }
  891. else if (response.statusCode == 301) {
  892. std::string location;
  893. if (response.properties.find("Location")==response.properties.end()) {
  894. if (response.properties.find("location")==response.properties.end()) {
  895. std::cout << "::handleRequest - got 301 without a location" << std::endl;
  896. for(auto const &row : response.properties) {
  897. std::cout << "::handleRequest - " << row.first << "=" << response.properties.at(row.first) << std::endl;
  898. }
  899. return;
  900. } else {
  901. location = response.properties.at("location");
  902. }
  903. } else {
  904. location = response.properties.at("Location");
  905. }
  906. std::cout << "Redirect To: " << location << std::endl;
  907. std::tuple<std::unique_ptr<URL>,enum URIParseError> result = parseUri(location);
  908. if (std::get<1>(result) != URI_PARSE_ERROR_NONE) {
  909. // TODO We probably wanna handle this better..
  910. std::cerr << "error parsing uri" << std::endl;
  911. return;
  912. }
  913. std::unique_ptr<URL> uri = std::move(std::get<0>(result));
  914. const std::unique_ptr<HTTPRequest> request = std::make_unique<HTTPRequest>(std::move(uri));
  915. request->sendRequest(handleRequest);
  916. return;
  917. }
  918. else {
  919. std::cout << "Unknown Status Code: " << response.statusCode << std::endl;
  920. }
  921. }