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.

MultiComponent.cpp 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. #include "MultiComponent.h"
  2. #include <iostream>
  3. #include "DocumentComponent.h"
  4. #include "TabbedComponent.h"
  5. #include "AnimeComponent.h"
  6. #include "InputComponent.h"
  7. #include "../opengl/Shader.h"
  8. #include "../opengl/ShaderLoader.h"
  9. MultiComponent::MultiComponent(const float rawX, const float rawY, const float rawWidth, const float rawHeight, const int passedWindowWidth, const int passedWindowHeight) {
  10. // take our space (for parent picking)
  11. x = rawX;
  12. y = rawY;
  13. width = rawWidth;
  14. height = rawHeight;
  15. // not really needed but nothing else sets this
  16. windowWidth = passedWindowWidth;
  17. windowHeight = passedWindowHeight;
  18. // we need a mouseout to mouseout our hovercomponent
  19. onMouseout=[this]() {
  20. if (this->hoverComponent && this->hoverComponent->onMouseout) {
  21. this->hoverComponent->onMouseout();
  22. }
  23. // select nothing
  24. this->hoverComponent = nullptr;
  25. };
  26. onMousemove=[this](int passedX, int passedY) {
  27. //std::cout << "MultiComponent::MultiComponent:onMousemove - at " << passedX << "," << passedY << std::endl;
  28. if (this->cursorX == passedX && this->cursorY == passedY) {
  29. return;
  30. }
  31. this->cursorX = passedX;
  32. this->cursorY = passedY;
  33. //std::cout << "MultiComponent::MultiComponent:onMousemove - size " << this->windowWidth << "," << this->windowHeight << std::endl;
  34. this->updateMouse();
  35. };
  36. onMousedown=[this](int passedX, int passedY) {
  37. //std::cout << "MultiComponent left press" << std::endl;
  38. if (this->hoverComponent) {
  39. if (this->focusedComponent != this->hoverComponent) {
  40. // blur old component
  41. if (this->focusedComponent) {
  42. if (this->focusedComponent->onBlur) {
  43. this->focusedComponent->onBlur();
  44. }
  45. }
  46. // focus new component
  47. if (this->hoverComponent->onFocus) {
  48. this->hoverComponent->onFocus();
  49. }
  50. }
  51. this->focusedComponent = this->hoverComponent;
  52. if (this->focusedComponent->onMousedown) {
  53. //std::cout << "click event" << std::endl;
  54. this->focusedComponent->onMousedown(passedX, passedY);
  55. }
  56. }
  57. };
  58. onMouseup=[this](int passedX, int passedY) {
  59. //std::cout << "MultiComponent left release" << std::endl;
  60. if (this->hoverComponent) {
  61. //std::cout << "DocumentComponent::DocumentComponent:onMouseup - hovering over " << typeOfComponent(this->hoverComponent) << " component" << std::endl;
  62. if (this->focusedComponent != this->hoverComponent) {
  63. // blur old component
  64. if (this->focusedComponent) {
  65. if (this->focusedComponent->onBlur) {
  66. this->focusedComponent->onBlur();
  67. }
  68. }
  69. // focus new component
  70. if (this->hoverComponent->onFocus) {
  71. this->hoverComponent->onFocus();
  72. }
  73. }
  74. this->focusedComponent = this->hoverComponent;
  75. if (this->focusedComponent && this->focusedComponent->onMouseup) {
  76. //std::cout << "click event" << std::endl;
  77. //std::cout << "unloaded1 " << this->parent->unloaded << std::endl;
  78. this->focusedComponent->onMouseup(passedX, passedY);
  79. // ok we can't communicate through the component
  80. //std::cout << "unloaded2 " << this->parent->unloaded << std::endl;
  81. // we can through the window global
  82. //std::cout << "window unloaded focus: " << window->focusedComponent << std::endl;
  83. //std::cout << "window unloaded hover: " << window->hoverComponent << std::endl;
  84. //std::cout << "win unloaded focus: " << this->win->focusedComponent << std::endl;
  85. //std::cout << "win unloaded hover: " << this->win->hoverComponent << std::endl;
  86. }
  87. // make sure we weren't unloaded by last click and check for additional events
  88. if (this->win->focusedComponent != nullptr && this->focusedComponent->onClick) {
  89. //std::cout << "click event" << std::endl;
  90. this->focusedComponent->onClick();
  91. }
  92. }
  93. };
  94. onWheel=[this](int passedX, int passedY) {
  95. //std::cout << "MultiComponent::MultiComponent:onWheel " << passedX << "," << passedY << std::endl;
  96. // if we're hovering over somethign
  97. if (this->hoverComponent) {
  98. // and it receives these messages
  99. if (this->hoverComponent->onWheel) {
  100. // send the event down
  101. this->hoverComponent->onWheel(passedX, passedY);
  102. }
  103. }
  104. //renderDirty = true;
  105. // should we mark win->renderDirty = true?
  106. };
  107. onKeyup=[this](int key, int scancode, int action, int mods) {
  108. //std::cout << "MultiComponent::MultiComponent:onKeyup - focused on " << typeOfComponent(this->focusedComponent) << std::endl;
  109. DocumentComponent *docComponent = dynamic_cast<DocumentComponent*>(this->focusedComponent.get());
  110. if (docComponent) {
  111. if (action == 0) {
  112. if (docComponent->onKeyup) {
  113. docComponent->onKeyup(key, scancode, action, mods);
  114. }
  115. }
  116. return;
  117. }
  118. InputComponent *inputComponent = dynamic_cast<InputComponent*>(this->focusedComponent.get());
  119. if (inputComponent) {
  120. //std::cout << "inputComponent is focused, key pressed " << key << " action: " <<action << std::endl;
  121. // action 1 is down, 0 is up, 2 is a repeat
  122. if (action == 0 || action == 2) {
  123. // key up
  124. // it's always uppercase...
  125. if (key == 259) {
  126. inputComponent->backSpace();
  127. } else if (key == 257) {
  128. std::cout << "enter!" << std::endl;
  129. } else {
  130. if (key < 256) {
  131. if (mods & GLFW_MOD_SHIFT) {
  132. // SHIFT
  133. if (key == GLFW_KEY_SLASH) key='?';
  134. if (key == GLFW_KEY_APOSTROPHE) key='"';
  135. if (key == GLFW_KEY_COMMA) key='<';
  136. if (key == GLFW_KEY_MINUS) key='_';
  137. if (key == GLFW_KEY_PERIOD) key='>';
  138. if (key == GLFW_KEY_SEMICOLON) key=':';
  139. if (key == GLFW_KEY_EQUAL) key='+';
  140. if (key == GLFW_KEY_LEFT_BRACKET) key='{';
  141. if (key == GLFW_KEY_BACKSLASH) key='|';
  142. if (key == GLFW_KEY_RIGHT_BRACKET) key='}';
  143. if (key == GLFW_KEY_GRAVE_ACCENT) key='~';
  144. } else {
  145. // no shift or caplocks
  146. // basically: when SHIFT isn't pressed but key is in A-Z range, add ascii offset to make it lower case
  147. if (key >= 'A' && key <= 'Z') {
  148. key += 'a' - 'A';
  149. }
  150. }
  151. inputComponent->addChar(key);
  152. } // otherwise I think it's some weird control char
  153. }
  154. }
  155. }
  156. };
  157. }
  158. // update component hover (need to call on component change)
  159. void MultiComponent::updateMouse() {
  160. // do we need to make pX/pY relative to this component? no, we just made the picking system take mouse coordinates
  161. std::shared_ptr<Component> newHover = this->searchComponentTree(this->rootComponent, this->cursorX, this->cursorY);
  162. if (newHover != this->hoverComponent) {
  163. if (this->hoverComponent && this->hoverComponent->onMouseout) {
  164. this->hoverComponent->onMouseout();
  165. }
  166. if (newHover && newHover->onMouseover) {
  167. newHover->onMouseover();
  168. }
  169. this->hoverComponent = newHover;
  170. }
  171. if (this->hoverComponent) {
  172. //std::cout << "MultiComponent::MultiComponent:onMousemove - hovering over " << typeOfComponent(this->hoverComponent) << " component" << std::endl;
  173. if (this->hoverComponent->onMousemove) {
  174. // this could communicate the cursor to use
  175. this->hoverComponent->onMousemove(this->cursorX, this->cursorY);
  176. } else {
  177. if (this->hoverComponent->onClick) {
  178. glfwSetCursor(this->win->window, this->win->cursorHand);
  179. } else {
  180. glfwSetCursor(this->win->window, this->win->cursorIbeam);
  181. }
  182. }
  183. } else {
  184. glfwSetCursor(this->win->window, this->win->cursorArrow);
  185. }
  186. }
  187. //#include "ComponentBuilder.h"
  188. void MultiComponent::resize(const int passedWindowWidth, const int passedWindowHeight) {
  189. // can't get this to work
  190. // , my type: " << typeOfComponent(std::make_shared<Component>(this))
  191. //std::cout << "MultiComponent::resize - relaying out. Name: " << name << std::endl;
  192. windowWidth = passedWindowWidth;
  193. windowHeight = passedWindowHeight;
  194. //Component::printComponentTree(rootComponent, 0);
  195. rootComponent->windowWidth = passedWindowWidth;
  196. rootComponent->windowHeight = passedWindowHeight;
  197. rootComponent->layout();
  198. //Component::printComponentTree(rootComponent, 0);
  199. //renderDirty = true;
  200. // should we mark win->renderDirty = true?
  201. }
  202. void MultiComponent::render() {
  203. //std::cout << "MultiComponent::render" << std::endl;
  204. Shader *fontShader = ShaderLoader::getShader(VertexShader("FontShader.vert"),
  205. FragmentShader("FontShader.frag"));
  206. fontShader->bind();
  207. renderDocumentComponents(rootComponent);
  208. fontShader->release();
  209. Shader *textureShader = ShaderLoader::getShader(VertexShader("TextureShader.vert"),
  210. FragmentShader("TextureShader.frag"));
  211. textureShader->bind();
  212. renderBoxComponents(rootComponent);
  213. textureShader->release();
  214. // if we flip, we can't put tab labels on top of the tab
  215. fontShader->bind();
  216. if (!boundToPage) {
  217. GLint transformLocation = fontShader->uniform("transform");
  218. GLenum glErr=glGetError();
  219. if(glErr != GL_NO_ERROR) {
  220. std::cout << "MultiComponent::render - glGetUniformLocation not ok: " << glErr << std::endl;
  221. }
  222. glUniformMatrix4fv(transformLocation, 1, GL_FALSE, win->transformMatrix);
  223. glErr=glGetError();
  224. if(glErr != GL_NO_ERROR) {
  225. std::cout << "MultiComponent::render - glUniformMatrix4fv not ok: " << glErr << std::endl;
  226. }
  227. }
  228. renderComponents(rootComponent);
  229. }
  230. // draw this component and all it's children
  231. void MultiComponent::renderComponents(std::shared_ptr<Component> component) {
  232. if (!component) {
  233. std::cout << "DocumentComponent::renderComponents - got null passed" << std::endl;
  234. return;
  235. }
  236. /*
  237. DocumentComponent *docComponent = dynamic_cast<DocumentComponent*>(component.get());
  238. if (docComponent) {
  239. docComponent->render();
  240. }
  241. */
  242. TextComponent *textComponent = dynamic_cast<TextComponent*>(component.get());
  243. if (textComponent) {
  244. textComponent->render();
  245. }
  246. // is this needed?
  247. if (component->children.empty()) {
  248. return;
  249. }
  250. for (std::shared_ptr<Component> &child : component->children) {
  251. renderComponents(child);
  252. }
  253. }
  254. void MultiComponent::renderDocumentComponents(std::shared_ptr<Component> component) {
  255. if (!component) {
  256. std::cout << "MultiComponent::renderBoxComponents - got null passed" << std::endl;
  257. return;
  258. }
  259. //std::cout << "MultiComponent::renderBoxComponents - renderering: " << component->name << std::endl;
  260. // render non-text components too
  261. DocumentComponent *docComponent = dynamic_cast<DocumentComponent*>(component.get());
  262. if (docComponent) {
  263. docComponent->render();
  264. }
  265. // is this needed?
  266. if (component->children.empty()) {
  267. return;
  268. }
  269. for (std::shared_ptr<Component> &child : component->children) {
  270. this->renderDocumentComponents(child);
  271. }
  272. }
  273. void MultiComponent::renderBoxComponents(std::shared_ptr<Component> component) {
  274. if (!component) {
  275. std::cout << "MultiComponent::renderBoxComponents - got null passed" << std::endl;
  276. return;
  277. }
  278. //std::cout << "MultiComponent::renderBoxComponents - renderering: " << component->name << std::endl;
  279. // render non-text components too
  280. BoxComponent *boxComponent = dynamic_cast<BoxComponent*>(component.get());
  281. if (boxComponent) {
  282. boxComponent->render();
  283. }
  284. // is this needed?
  285. if (component->children.empty()) {
  286. return;
  287. }
  288. for (std::shared_ptr<Component> &child : component->children) {
  289. this->renderBoxComponents(child);
  290. }
  291. }
  292. void MultiComponent::renderComponentType(std::string str, std::shared_ptr<Component> component) {
  293. if (!component) {
  294. std::cout << "MultiComponent::renderComponentType - got null passed" << std::endl;
  295. return;
  296. }
  297. if (typeOfComponent(component) == str) {
  298. // how slow is this?
  299. if (str == "doc") {
  300. DocumentComponent *docComponent = dynamic_cast<DocumentComponent*>(component.get());
  301. docComponent->render();
  302. } else if (str =="tab") {
  303. TabbedComponent *pTabComponent = dynamic_cast<TabbedComponent*>(component.get());
  304. pTabComponent->render();
  305. } else if (str =="text") {
  306. TextComponent *textComponent = dynamic_cast<TextComponent*>(component.get());
  307. textComponent->render();
  308. } else if (str =="input") {
  309. InputComponent *inputComponent = dynamic_cast<InputComponent*>(component.get());
  310. inputComponent->render();
  311. } else if (str =="anime") {
  312. AnimeComponent *animeComponent = dynamic_cast<AnimeComponent*>(component.get());
  313. animeComponent->render();
  314. } else if (str =="box") {
  315. //AnimeComponent *animeComponent = dynamic_cast<AnimeComponent*>(component.get());
  316. //if (!animeComponent) {
  317. BoxComponent *boxComponent = dynamic_cast<BoxComponent*>(component.get());
  318. boxComponent->render();
  319. //}
  320. } else {
  321. std::cout << "Unknown type " << str << std::endl;
  322. }
  323. //} else {
  324. //std::cout << "type: " << typeOfComponent(component) << "!=" << str << std::endl;
  325. }
  326. // is this needed?
  327. if (component->children.empty()) {
  328. return;
  329. }
  330. for (std::shared_ptr<Component> &child : component->children) {
  331. this->renderComponentType(str, child);
  332. }
  333. }
  334. // used for picking
  335. std::shared_ptr<Component> MultiComponent::searchComponentTree(const std::shared_ptr<Component> &component, const int passedX, const int passedY) {
  336. if (component->children.empty()) {
  337. //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;
  338. if (tabbed) {
  339. //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;
  340. if (component->windowHeight - component->y - component->height < passedY && component->windowHeight - component->y > passedY) {
  341. //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;
  342. if (component->x < passedX && component->x + component->width > passedX) {
  343. //std::cout << "MultiComponent::searchComponentTree:Tabbed - hit " << typeOfComponent(component) << std::endl;
  344. return component;
  345. }
  346. }
  347. } else {
  348. //std::cout << "MultiComponent::searchComponentTree - y search: " << static_cast<int>(-component->y) << "<" << static_cast<int>(passedY) << "<" << static_cast<int>(-component->y + component->height) << std::endl;
  349. if (-component->y < passedY && -component->y + component->height > passedY) {
  350. //std::cout << "DocumentComponent::searchComponentTree - x search: " << static_cast<int>(component->x) << "<" << static_cast<int>(passedX) << "<" << static_cast<int>(component->x + component->width) << std::endl;
  351. if (component->x < passedX && component->x + component->width > passedX) {
  352. //std::cout << "MultiComponent::searchComponentTree - hit " << typeOfComponent(component) << std::endl;
  353. return component;
  354. }
  355. }
  356. }
  357. }
  358. else {
  359. for (std::shared_ptr<Component> child : component->children) {
  360. std::shared_ptr<Component> found = searchComponentTree(child, passedX, passedY);
  361. if (found) {
  362. return found;
  363. }
  364. }
  365. }
  366. return nullptr;
  367. }