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

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