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.

TabbedComponent.cpp 29KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661
  1. #include "TabbedComponent.h"
  2. #include "DocumentComponent.h"
  3. #include "InputComponent.h"
  4. #include "BoxComponent.h"
  5. #include <iostream>
  6. TabbedComponent::TabbedComponent(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) {
  7. // picking flag
  8. tabbed = true;
  9. // make 2 multiComponents
  10. // put into rootDOM
  11. // one for the document
  12. // one for the tab UI
  13. // make sure boxes & text for document is draw first
  14. // then draw on top:
  15. // boxes & text for tab UI
  16. // or we can manually force doc components first and skipped later... sounds like a better start
  17. std::unique_ptr<BoxComponent> addNewBox = std::make_unique<BoxComponent>(x, passedWindowHeight - 96 - y, 32, 32, this->tabAddColor, passedWindowWidth, passedWindowHeight);
  18. addNewBox->name = "addNewTab";
  19. // needs to be adjust when our parent is adjusted...
  20. // pre-layout
  21. addNewBox->uiControl.x = { 0 , static_cast<int>(x) }; // 0
  22. addNewBox->uiControl.y = { 100, -96 - static_cast<int>(y) }; // height - 96px
  23. addNewBox->uiControl.w = { 0 , 32 }; // 32px
  24. addNewBox->uiControl.h = { 0 , 32 }; // 32px
  25. addNewBox->boundToPage = false;
  26. addNewBox->onClick = [this]() {
  27. //std::cout << "new tab" << std::endl;
  28. this->addTab("New Tab");
  29. };
  30. // this will cause problems if addNewBox goes out of scope but then not events should be firing
  31. BoxComponent *addBoxHandle = addNewBox.get();
  32. addNewBox->onMouseover = [addBoxHandle, this]() {
  33. //std::cout << "addNewBox->onMouseover" << std::endl;
  34. addBoxHandle->changeColor(this->tabAddHoverColor);
  35. this->win->renderDirty = true;
  36. };
  37. addNewBox->onMouseout = [addBoxHandle, this]() {
  38. //std::cout << "addNewBox->onMouseout" << std::endl;
  39. addBoxHandle->changeColor(this->tabAddColor);
  40. this->win->renderDirty = true;
  41. };
  42. // add to component tree
  43. addNewBox->setParent(rootComponent);
  44. rootComponent->children.push_back(std::move(addNewBox));
  45. // just set it to the end for now
  46. this->selectedTab = this->tabs.end();
  47. }
  48. void TabbedComponent::addTab(std::string passedTitle) {
  49. //std::cout << "TabbedComponent::addTab - windowSize: " << windowWidth << "x" << windowHeight << std::endl;
  50. auto tabId = ++tabCounter; // always increasing
  51. std::cout << "TabbedComponent::addTab - new tabId: " << tabId << std::endl;
  52. std::shared_ptr<Tab> newTab=std::make_shared<Tab>();
  53. //newTab->title = passedTitle;
  54. newTab->id = tabId;
  55. //(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)
  56. std::shared_ptr<TextComponent> newTabTitle = std::make_shared<TextComponent>(passedTitle, 0, 0, 12, false, this->tabTextColor, windowWidth, windowHeight);
  57. size_t textWidth = 0;
  58. newTabTitle->win = this->win;
  59. std::unique_ptr<sizeResponse> textInfo = newTabTitle->size();
  60. if (textInfo) {
  61. textWidth = static_cast<size_t>(textInfo->width);
  62. //std::cout << "tab text width: " << textWidth << std::endl;
  63. }
  64. textWidth += 10; // 5px padding each side
  65. // well we need to figure out where the last tab start
  66. size_t startX = x + 32; // our start + 32px for new tab button
  67. for(std::vector<std::shared_ptr<Tab>>::iterator it = this->tabs.begin(); it!=this->tabs.end(); ++it) {
  68. startX += it->get()->w;
  69. }
  70. newTab->x = static_cast<int>(startX);
  71. newTab->w = textWidth + 32;
  72. //std::cout << "TabbedComponent::addTab - windowHeight: " << windowHeight << " y: " << y << std::endl;
  73. std::shared_ptr<BoxComponent> newTabBox = std::make_shared<BoxComponent>(newTab->x, windowHeight - 96, newTab->w - 32, 32, this->tabInactiveColor, windowWidth, windowHeight);
  74. newTabBox->uiControl.x = { 0 , newTab->x }; // 0
  75. newTabBox->uiControl.y = { 100, -96 }; // height - 96px
  76. newTabBox->uiControl.w = { 0 , static_cast<int>(newTab->w) - 32 }; // 32px
  77. newTabBox->uiControl.h = { 0 , 32 }; // 32px
  78. newTabBox->name = "tabSelectorBox";
  79. newTabBox->boundToPage = false;
  80. newTabBox->onClick = [this, newTab]() {
  81. //std::cout << "TabbedComponent::addTab:onClick() - select tab " << newTab->id << std::endl;
  82. this->selectTab(newTab);
  83. };
  84. newTabBox->onMouseover = [newTabBox, this]() {
  85. //std::cout << "newTabBox->onMouseover" << std::endl;
  86. newTabBox->changeColor(this->tabHoverColor);
  87. this->win->renderDirty = true;
  88. };
  89. newTabBox->onMouseout = [newTabBox, tabId, this]() {
  90. //std::cout << "newTabBox->onMouseout" << std::endl;
  91. // if it an active or inactive tab
  92. if (this->selectedTabId == tabId) {
  93. newTabBox->changeColor(this->tabActiveColor);
  94. } else {
  95. newTabBox->changeColor(this->tabInactiveColor);
  96. }
  97. this->win->renderDirty = true;
  98. };
  99. //newTab->selectorBox=std::move(newTabBox);
  100. // add to component tree
  101. newTabBox->setParent(rootComponent);
  102. rootComponent->children.push_back(newTabBox);
  103. newTab->selectorBox = newTabBox;
  104. newTabTitle->x = newTab->x + 5;
  105. newTabTitle->y = -73;
  106. newTabTitle->uiControl.x = { 0 , newTab->x + 5 }; // 0
  107. newTabTitle->uiControl.y = { 0 , -73 }; // height - 73px
  108. newTabTitle->uiControl.w = { 0 , static_cast<int>(textWidth) }; // textWidth
  109. newTabTitle->uiControl.h = { 0 , 12 }; // 12px
  110. newTabTitle->resize(windowWidth, windowHeight); // rasterize
  111. newTabTitle->name = "add new tab label";
  112. newTabTitle->boundToPage = false;
  113. // add to component tree
  114. newTabTitle->setParent(rootComponent);
  115. rootComponent->children.push_back(newTabTitle);
  116. newTab->titleBox = newTabTitle;
  117. // x + 64 * (tabs.size() + 1)
  118. std::shared_ptr<BoxComponent> closeTabBox = std::make_shared<BoxComponent>(newTab->x + static_cast<int>(newTab->w) - 32, windowHeight - 96, 32, 32, this->tabCloseColor, windowWidth, windowHeight);
  119. closeTabBox->uiControl.x = { 0 , newTab->x + static_cast<int>(newTab->w) - 32 }; // 0
  120. closeTabBox->uiControl.y = { 100 , -96 }; // height - 96px
  121. closeTabBox->uiControl.w = { 0 , 32 }; // 32px
  122. closeTabBox->uiControl.h = { 0 , 32 }; // 32px
  123. closeTabBox->name = "tabCloseBox";
  124. closeTabBox->boundToPage = false;
  125. closeTabBox->onClick = [this, tabId]() {
  126. //std::cout << "close tab " << tabId << std::endl;
  127. this->removeTab(tabId);
  128. };
  129. closeTabBox->onMouseover = [closeTabBox, this]() {
  130. //std::cout << "closeTabBox->onMouseover" << std::endl;
  131. closeTabBox->changeColor(this->tabCloseHoverColor);
  132. this->win->renderDirty = true;
  133. };
  134. closeTabBox->onMouseout = [closeTabBox, this]() {
  135. //std::cout << "closeTabBox->onMouseout" << std::endl;
  136. closeTabBox->changeColor(this->tabCloseColor);
  137. this->win->renderDirty = true;
  138. };
  139. newTab->closeBox = closeTabBox;
  140. //newTab->selectorBox=std::move(newTabBox);
  141. // add to component tree
  142. closeTabBox->setParent(rootComponent);
  143. rootComponent->children.push_back(closeTabBox);
  144. // build empty document
  145. std::shared_ptr<DocumentComponent> docComponent = std::make_shared<DocumentComponent>(0, 0, windowWidth, windowHeight, windowWidth, windowHeight);
  146. docComponent->name = "TabX docComponent";
  147. docComponent->win = this->win;
  148. docComponent->boundToPage = false;
  149. docComponent->onBeforeLoad=[this](std::string url) {
  150. //std::cout << "tabbedComponent::addTab:::docComponent->onBeforeLoad - fire" << std::endl;
  151. // if we're in a tab
  152. if (this->mpSelectedTab) {
  153. // set tab
  154. TextComponent *textComponent = this->mpSelectedTab->titleBox.get();
  155. if (textComponent) {
  156. // similar to loadDomIntoTab
  157. textComponent->text = url;
  158. textComponent->wrap();
  159. // recalc what that just did to our fellow tabs
  160. this->layoutTabs(this->selectedTab, 0);
  161. this->selectedTab->get()->history->pushState(nullptr, url, url);
  162. }
  163. } else {
  164. std::cout << "tabbedComponent::addTab:::docComponent->onBeforeLoad - document component but no tab selected" << std::endl;
  165. // but we're loading into a specific tab, we have a doc component...
  166. if (!this->tabs.size()) {
  167. std::cout << "tabbedComponent::addTab:::docComponent->onBeforeLoad - document component but no tabs!" << std::endl;
  168. }
  169. }
  170. // set address bar
  171. InputComponent *ab = dynamic_cast<InputComponent*>(this->win->addressComponent.get());
  172. if (ab) {
  173. ab->value = url;
  174. ab->updateText();
  175. } else {
  176. std::cout << "No address component" << std::endl;
  177. }
  178. this->updateWindowState(url);
  179. };
  180. // set up position and resize info
  181. docComponent->y = -96; // our bar
  182. docComponent->uiControl.x = { 0, 0 }; // 0
  183. docComponent->uiControl.y = { 0, -96 }; // -96px
  184. docComponent->uiControl.w = { 100, 0 }; // 100%
  185. docComponent->uiControl.h = { 100, -96 }; // 100% - 96px
  186. // adjust rootComponent based on y
  187. docComponent->rootComponent->name = "root of doc";
  188. docComponent->rootComponent->y = docComponent->y;
  189. // don't attach this component to our root, yet...
  190. // don't need to touch dom, should be empty to start
  191. newTab->contents = docComponent;
  192. newTab->history = std::make_unique<BrowsingHistory>([this](URL const& goToURL) {
  193. std::cout << "history goto " << goToURL << std::endl;
  194. std::shared_ptr<DocumentComponent> p_docComponent = std::static_pointer_cast<DocumentComponent>(this->documentComponent);
  195. if (p_docComponent) {
  196. // now tell it to navigate somewhere
  197. p_docComponent->navTo(goToURL.toString());
  198. }
  199. //this->win->navTo(goToURL.toString());
  200. });
  201. if (tabs.size()) {
  202. newTab->previousTab = tabs.back();
  203. } else {
  204. newTab->previousTab = nullptr;
  205. }
  206. tabs.push_back(std::move(newTab));
  207. //std::cout << "tabs: " << tabs.size() << std::endl;
  208. //renderDirty = true;
  209. win->renderDirty = true;
  210. // also update the new picking system
  211. // likely won need to do this because the addTab never moves
  212. //this->updateMouse();
  213. }
  214. void TabbedComponent::updateWindowState(std::string newTitle) {
  215. //std::cout << "TabbedComponent::updateWindowState - newTitle: " << newTitle << std::endl;
  216. InputComponent *inputComponent = dynamic_cast<InputComponent*>(this->win->addressComponent.get());
  217. if (inputComponent) {
  218. inputComponent->value = newTitle;
  219. inputComponent->updateText();
  220. } else {
  221. std::cout << "TabbedComponent::updateWindowState - Window addressComponent isn't an inputComponent" << std::endl;
  222. }
  223. // need to update currentURL for navTo
  224. // if we're no tab, we have no relative point, no harm in setting http://
  225. //if (ab->value!="http://") {
  226. //this->win->currentURL = newTitle;
  227. // I'm not sure we need this
  228. /*
  229. DocumentComponent *docComponent = dynamic_cast<DocumentComponent*>(this->documentComponent.get());
  230. if (docComponent) {
  231. docComponent->currentURL = newTitle;
  232. }
  233. */
  234. //}
  235. // redraw pls
  236. this->win->renderDirty = true;
  237. // on DOM load mouse won't be over a tab
  238. // and select tab doesn't change any components
  239. //this->updateMouse();
  240. }
  241. // because iterators invalid, this is good for a quick lookup
  242. std::vector<std::shared_ptr<Tab>>::iterator TabbedComponent::getTab(size_t tabId) {
  243. // locate tabId
  244. std::vector<std::shared_ptr<Tab>>::iterator newTab;
  245. for(std::vector<std::shared_ptr<Tab>>::iterator it = this->tabs.begin(); it != this->tabs.end(); ++it) {
  246. if (it->get()->id == tabId) {
  247. return it;
  248. }
  249. }
  250. return this->tabs.end();
  251. }
  252. void TabbedComponent::selectTab(std::shared_ptr<Tab> tab) {
  253. //std::cout << "TabbedComponent::selectTab - select tab " << tabId << std::endl;
  254. // locate tab
  255. if (tab == nullptr) {
  256. std::cout << "TabbedComponent::selectTab - tab is nullptr" << std::endl;
  257. return;
  258. }
  259. /*
  260. std::vector<std::shared_ptr<Tab>>::iterator newTab = this->getTab(tabId);
  261. if (newTab == this->tabs.end()) {
  262. std::cout << "tab" << tabId << " doesn't exist" << std::endl;
  263. return;
  264. }
  265. if (newTab->get() == nullptr) {
  266. std::cout << "tab" << tabId << " points to null" << std::endl;
  267. return;
  268. }
  269. */
  270. //std::cout << "Found tab" << std::endl;
  271. // tab system is currently keeping component tree in memory
  272. // swap contents with document components
  273. // remove from our children
  274. std::vector<std::shared_ptr<Component>>::iterator it2;
  275. it2 = std::find(this->rootComponent->children.begin(), this->rootComponent->children.end(), this->documentComponent);
  276. if ( it2 != this->rootComponent->children.end() ) {
  277. //std::cout << "Found old contents" << std::endl;
  278. // FIXME: cast to doccomp and setDOM to null to make sure its clean
  279. it2->get()->parent = nullptr;
  280. this->rootComponent->children.erase(it2);
  281. }
  282. //std::cout << "adding new contents" << std::endl;
  283. // select new document
  284. this->rootComponent->children.push_back(tab->contents);
  285. tab->contents->setParent(this->rootComponent);
  286. this->documentComponent = tab->contents;
  287. InputComponent *ab = dynamic_cast<InputComponent*>(this->win->addressComponent.get());
  288. if (ab) {
  289. ab->value = tab->titleBox->text;
  290. //std::cout << "tab->titleBox->text: " << tab->titleBox->text << std::endl;
  291. if (ab->value == "New Tab") {
  292. ab->value = "http://"; // should be "" but we don't have an awesome-bar yet
  293. }
  294. ab->updateText();
  295. } else {
  296. std::cout << "TabbedComponent::selectTab - Window addressComponent isnt an inputcomponent" << std::endl;
  297. }
  298. // I can't get selectedTab to works always (tab size = 1 or 2)
  299. // so we'll rely on this more complex system
  300. int i=0;
  301. bool found = false;
  302. for(std::vector<std::shared_ptr<Tab>>::iterator it=this->tabs.begin(); it!=this->tabs.end(); ++it) {
  303. if (it==this->selectedTab) {
  304. //if (it->get()->id == tabId) {
  305. //std::cout << "found it at " << i << std::endl;
  306. found = true;
  307. break;
  308. }
  309. i++;
  310. }
  311. //std::cout << "i" << i << "/" << this->tabs.size() << std::endl;
  312. std::cout << "TabbedComponent::selectTab - selector found: " << found << std::endl;
  313. if (found) {
  314. // was there a previously selected tab?
  315. //if (this->selectedTab != this->tabs.end() && this->selectedTab != this->tabs.begin()) {
  316. BoxComponent *selector = dynamic_cast<BoxComponent*>(tab->selectorBox.get());
  317. if (selector) {
  318. selector->changeColor(this->tabActiveColor);
  319. }
  320. // if we had something selected
  321. // make sure we didn't just reselect ourself
  322. //if (this->selectedTabId != newTab->get()->id) {
  323. if (this->mpSelectedTab && this->mpSelectedTab != tab) {
  324. selector = dynamic_cast<BoxComponent*>(this->selectedTab->get()->selectorBox.get());
  325. if (selector) {
  326. // reset it's color
  327. selector->changeColor(this->tabInactiveColor);
  328. }
  329. }
  330. //}
  331. } else {
  332. // just mark all non-active color
  333. BoxComponent *selector;
  334. for(std::vector<std::shared_ptr<Tab>>::iterator it=this->tabs.begin(); it!=this->tabs.end(); ++it) {
  335. selector = dynamic_cast<BoxComponent*>(it->get()->selectorBox.get());
  336. if (selector) {
  337. // reset color
  338. selector->changeColor(this->tabInactiveColor);
  339. }
  340. }
  341. // mark selected one as active
  342. selector = dynamic_cast<BoxComponent*>(tab->selectorBox.get());
  343. if (selector) {
  344. selector->changeColor(this->tabActiveColor);
  345. } else {
  346. if (this->tabs.size()) {
  347. std::cout << "TabbedComponent::selectTab - Can't find selectorBox for tab" << std::endl;
  348. }
  349. }
  350. }
  351. // make sure we're the selected one
  352. this->selectedTab = this->getTab(tab->id); // iterator
  353. this->selectedTabId = tab->id; // integer
  354. // doesn't move, will this double free?
  355. this->mpSelectedTab = tab; // pointer
  356. this->updateWindowState(ab->value);
  357. }
  358. // we expect the tab to be set up (all components allocated)
  359. // calculate size and position for a tab
  360. // we're not going to do a full set up uiContorl, we'll expect those to be set up and just adjust them
  361. // but then, we can't just call this to place things where we want in the cstr... hrm..
  362. void TabbedComponent::layoutTab(std::vector<std::shared_ptr<Tab>>::iterator tab) {
  363. //std::cout << "TabbedComponent::layoutTab - id: " << tab->get()->id << std::endl;
  364. // find text
  365. TextComponent *textComponent = tab->get()->titleBox.get();
  366. if (!textComponent) {
  367. std::cout << "TabbedComponent::layoutTab - titleBox isn't a TextComponent" << std::endl;
  368. return;
  369. }
  370. // vector iterators can't go backwards
  371. //std::vector<std::shared_ptr<Tab>>::iterator it = tab;
  372. //--it;
  373. //Tab *prev = it->get();
  374. Tab *prev = tab->get()->previousTab.get();
  375. if (prev == nullptr) {
  376. //std::cout << "TabbedComponent::layoutTab - relaying out first tab, no prev" << std::endl;
  377. //prev = nullptr;
  378. tab->get()->x = x + 32; // our start + 32px for new tab button
  379. } else {
  380. tab->get()->x = prev->x + static_cast<int>(prev->w);
  381. }
  382. //std::cout << "TabbedComponent::layoutTab - placing tab at " << tab->get()->x << std::endl;
  383. // get text size for it's current string
  384. // we don't always need to adjust textWidth, only on text change
  385. int textWidthWPad = 0;
  386. std::unique_ptr<sizeResponse> textInfo = textComponent->size();
  387. if (textInfo) {
  388. textWidthWPad = textInfo->width;
  389. //std::cout << "tab text width: " << textWidth << std::endl;
  390. }
  391. // pad
  392. textWidthWPad += 10; // 5px padding each side
  393. // update tab width
  394. tab->get()->w = static_cast<size_t>(textWidthWPad) + 32; // selector Box (text + padding) + close Box
  395. // adjust ui map accordingly
  396. // adjust x of text
  397. textComponent->x = 5 + tab->get()->x;
  398. textComponent->width = textWidthWPad - 10; // ugh textComponent should be managing this...
  399. textComponent->uiControl.x = { 0, static_cast<int>(textComponent->x) };
  400. textComponent->uiControl.w = { 0, static_cast<int>(textComponent->width) };
  401. textComponent->resize(windowWidth, windowHeight); // apply new width
  402. // find selector
  403. // adjust x and w of selector
  404. tab->get()->selectorBox->x = tab->get()->x;
  405. tab->get()->selectorBox->width = textWidthWPad;
  406. // need to update the uiControl
  407. tab->get()->selectorBox->uiControl.x = { 0, tab->get()->x }; // tab->get()->x
  408. tab->get()->selectorBox->uiControl.w = { 0, textWidthWPad }; // textWidthWPad
  409. tab->get()->selectorBox->resize(windowWidth, windowHeight); // apply new width
  410. // find close and adjust x
  411. tab->get()->closeBox->x = tab->get()->x + static_cast<int>(tab->get()->w) - 32;
  412. tab->get()->closeBox->uiControl.x = { 0, tab->get()->x + static_cast<int>(tab->get()->w) - 32 }; // note it's not our width
  413. // need to update the uiControl
  414. tab->get()->closeBox->resize(windowWidth, windowHeight); // apply new position
  415. }
  416. // maybe take in a starting tab? as tabs to left aren't affected
  417. void TabbedComponent::layoutTabs(std::vector<std::shared_ptr<Tab>>::iterator startTab, int xAdj) {
  418. //std::cout << "TabbedComponent::layoutTabs - startId: " << startTab->get()->id << " xadj: " << xAdj << std::endl;
  419. // luckily only one component at a time changes, we'll need to know how much x shifted
  420. for(std::vector<std::shared_ptr<Tab>>::iterator it = startTab; it!=this->tabs.end(); ++it) {
  421. //it->get()->x += xAdj; // adjust position
  422. this->layoutTab(it);
  423. }
  424. }
  425. void TabbedComponent::loadDomIntoTab(std::shared_ptr<Node> newRoot, std::string newTitle) {
  426. DocumentComponent *docComponent = dynamic_cast<DocumentComponent*>(this->documentComponent.get());
  427. if (!docComponent) {
  428. // FIXME: could mean no tab is selected (on "default" no tab and a tab has been created)
  429. std::cout << "TabbedComponent::loadDomIntoTab - 'documentComponent' isn't a DocumentComponent" << std::endl;
  430. return;
  431. }
  432. docComponent->setDOM(newRoot);
  433. if (this->selectedTab == this->tabs.end()) {
  434. std::cout << "TabbedComponent::loadDomIntoTab - No current tab selected" << std::endl;
  435. return;
  436. }
  437. if (this->tabs.size() == 0) {
  438. std::cout << "TabbedComponent::loadDomIntoTab - No tabs that can be selected" << std::endl;
  439. return;
  440. }
  441. // std::string const& title, URL const& url
  442. // FIXME: reload, don't push on reload?
  443. // if the history cursor isn't at the end, we need to replace I think and nuked everything after it
  444. this->selectedTab->get()->history->pushState(nullptr, newTitle, newTitle);
  445. this->selectedTab->get()->history->print();
  446. // find our titleBox
  447. std::vector<std::shared_ptr<Component>>::iterator it2 = std::find(this->rootComponent->children.begin(), this->rootComponent->children.end(), this->selectedTab->get()->titleBox);
  448. if ( it2 == this->rootComponent->children.end() ) {
  449. std::cout << "TabbedComponent::loadDomIntoTab - Can't find selectedTab's titleBox in rootComponent" << std::endl;
  450. return;
  451. }
  452. std::cout << "found our titleBox component in parent tree" << std::endl;
  453. // get text component
  454. TextComponent *textComponent = dynamic_cast<TextComponent*>(it2->get());
  455. // actually change the text
  456. textComponent->text = newTitle;
  457. textComponent->wrap();
  458. // recalc what that just did to our fellow tabs
  459. this->layoutTabs(this->selectedTab, 0);
  460. /*
  461. TextComponent *textComponent = dynamic_cast<TextComponent*>(it2->get());
  462. if (!textComponent) {
  463. std::cout << "TabbedComponent::loadDomIntoTab - titleBox isn't a TextComponent" << std::endl;
  464. return;
  465. }
  466. textComponent->text = newTitle;
  467. textComponent->wrap();
  468. int textWidth = 0;
  469. std::unique_ptr<std::pair<int, int>> textInfo = textComponent->size();
  470. if (textInfo) {
  471. textWidth = textInfo->first;
  472. //std::cout << "tab text width: " << textWidth << std::endl;
  473. }
  474. textWidth += 10; // 5px padding each side
  475. // update width
  476. this->selectedTab->get()->w = static_cast<size_t>(textWidth) + 32; // selector Box (text + padding) + close Box
  477. // need to update selectorBox's width
  478. this->selectedTab->get()->selectorBox->width = textWidth;
  479. // need to update the uiControl
  480. this->selectedTab->get()->selectorBox->uiControl.w = { 0, textWidth }; //
  481. this->selectedTab->get()->selectorBox->resize(windowWidth, windowHeight); // apply new width
  482. // need to move all tabs after this one
  483. this->selectedTab->get()->closeBox->x = this->selectedTab->get()->x + static_cast<int>(this->selectedTab->get()->w) - 32;
  484. this->selectedTab->get()->closeBox->uiControl.x = { 0, this->selectedTab->get()->x + static_cast<int>(this->selectedTab->get()->w) - 32 }; // note it's not our width
  485. // need to update the uiControl
  486. this->selectedTab->get()->closeBox->resize(windowWidth, windowHeight); // apply new position
  487. */
  488. this->updateWindowState(newTitle);
  489. }
  490. //FIXME: make sure we update window's ptrs, we can't have documentComponent not pointing to nullptr when there's no tabs
  491. void TabbedComponent::removeTab(size_t tabId) {
  492. // find tabId
  493. bool found = false;
  494. size_t widthToRemove = 0;
  495. std::vector<std::shared_ptr<Tab>>::iterator prev = this->tabs.begin();
  496. for(std::vector<std::shared_ptr<Tab>>::iterator it = this->tabs.begin(); it!=this->tabs.end(); prev = it, ++it) {
  497. if (it->get()->id == tabId) {
  498. std::cout << "TabbedComponent::removeTab - found our tab" << std::endl;
  499. // remove our components form the component tree
  500. std::vector<std::shared_ptr<Component>>::iterator it2;
  501. it2 = std::find(this->rootComponent->children.begin(), this->rootComponent->children.end(), it->get()->selectorBox);
  502. if ( it2 != this->rootComponent->children.end() ) {
  503. //std::cout << "found our select component in parent tree" << std::endl;
  504. it2->get()->parent = nullptr;
  505. this->rootComponent->children.erase(it2);
  506. }
  507. it2 = std::find(this->rootComponent->children.begin(), this->rootComponent->children.end(), it->get()->closeBox);
  508. if ( it2 != this->rootComponent->children.end() ) {
  509. //std::cout << "found our close component in parent tree" << std::endl;
  510. it2->get()->parent = nullptr;
  511. this->rootComponent->children.erase(it2);
  512. }
  513. it2 = std::find(this->rootComponent->children.begin(), this->rootComponent->children.end(), it->get()->titleBox);
  514. if ( it2 != this->rootComponent->children.end() ) {
  515. //std::cout << "found our titleBox component in parent tree" << std::endl;
  516. it2->get()->parent = nullptr;
  517. this->rootComponent->children.erase(it2);
  518. }
  519. it2 = std::find(this->rootComponent->children.begin(), this->rootComponent->children.end(), it->get()->contents);
  520. if ( it2 != this->rootComponent->children.end() ) {
  521. //std::cout << "found our document component in parent tree" << std::endl;
  522. DocumentComponent *docComponent = dynamic_cast<DocumentComponent*>(it2->get());
  523. if (docComponent) {
  524. // unload components
  525. docComponent->setDOM(std::make_shared<Node>(NodeType::ROOT));
  526. } else {
  527. std::cout << "our contents aren't a document component" << std::endl;
  528. }
  529. it2->get()->parent = nullptr;
  530. this->rootComponent->children.erase(it2);
  531. }
  532. // remove tab
  533. widthToRemove = it->get()->w;
  534. // are we the selected tab
  535. if (this->selectedTab == it) {
  536. std::cout << "TabbedComponent::removeTab - removing selected tab" << std::endl;
  537. if (this->tabs.size() > 1) {
  538. size_t nextTabId = this->tabs.front()->id; // grab first tab
  539. std::shared_ptr<Tab> pSelectedTab = this->tabs.front();
  540. // if we are the firstTab, get the 2nd
  541. if (it->get()->id == nextTabId) {
  542. //nextTabId = this->tabs[1]->id;
  543. pSelectedTab = this->tabs[1];
  544. }
  545. this->selectTab(pSelectedTab);
  546. }
  547. }
  548. it->get()->contents.reset(); // nuke document
  549. //it->reset(); // free memory before losing track of it
  550. it = this->tabs.erase(it);
  551. it->get()->previousTab = *prev; // next tab, set it to our previous
  552. if (!this->tabs.size()) {
  553. // no tabs left
  554. std::cout << "TabbedComponent::removeTab - all tabs removed" << std::endl;
  555. this->selectedTab = this->tabs.end();
  556. this->selectedTabId = 0;
  557. this->mpSelectedTab = nullptr;
  558. // get last doc Component
  559. DocumentComponent *docComponent = dynamic_cast<DocumentComponent*>(this->documentComponent.get());
  560. if (docComponent) {
  561. // create empty document
  562. //docComponent->domRootNode = std::make_shared<Node>(NodeType::ROOT);
  563. //docComponent->domDirty = true;
  564. //docComponent->rootComponent = std::make_shared<Component>();
  565. //docComponent->rootComponent->name = "rootComponent";
  566. // properly clean up the DOM Tree
  567. docComponent->setDOM(std::make_shared<Node>(NodeType::ROOT));
  568. }
  569. //this->documentComponent = nullptr;
  570. }
  571. found = true;
  572. if (it == this->tabs.end()) break;
  573. }
  574. // we need to move (relayout) all remove tabs after this id
  575. if (found) {
  576. std::cout << "TabbedComponent::removeTab - Need to adjust: " << it->get()->id << std::endl;
  577. it->get()->titleBox->x -= widthToRemove;
  578. it->get()->titleBox->resize(windowWidth, windowHeight); // TextComponent, need a resize() to move vertices
  579. it->get()->selectorBox->x -= widthToRemove;
  580. it->get()->selectorBox->resize(windowWidth, windowHeight); // BoxComponent, need a resize() to move vertices
  581. it->get()->closeBox->x -= widthToRemove;
  582. it->get()->closeBox->resize(windowWidth, windowHeight); // BoxComponent, need a resize() to move vertices
  583. }
  584. }
  585. //this->renderDirty = true;
  586. this->win->renderDirty = true;
  587. // also update the new picking system
  588. this->updateMouse();
  589. }