Tabs.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. namespace EE{
  4. /******************************************************************************/
  5. // TAB
  6. /******************************************************************************/
  7. void Tab:: addChild(GuiObj &child) {_children.add (child, T);}
  8. void Tab::removeChild(GuiObj &child) {_children.remove(child );}
  9. Tab& Tab::del()
  10. {
  11. _children.del();
  12. super::del(); return T;
  13. }
  14. Tab& Tab::create(C Str &text)
  15. {
  16. _children.del();
  17. super::create(text);
  18. _type =GO_TAB;
  19. mode =BUTTON_TOGGLE;
  20. _sub_type =BUTTON_TYPE_TAB_HORIZONTAL; // set initial sub type (this is the best guess)
  21. _focusable =false;
  22. _pixel_align=false;
  23. return T;
  24. }
  25. Tab& Tab::create(C Tab &src)
  26. {
  27. if(this!=&src)
  28. {
  29. _children.del();
  30. if(!src.is())del();else
  31. {
  32. super::create(src);
  33. _type=GO_TAB;
  34. }
  35. }
  36. return T;
  37. }
  38. Tab& Tab::setCornerTab(Bool right, Bool top)
  39. {
  40. _sub_type=(top ? right ? BUTTON_TYPE_TAB_TOP_RIGHT : BUTTON_TYPE_TAB_TOP_LEFT
  41. : right ? BUTTON_TYPE_TAB_BOTTOM_RIGHT : BUTTON_TYPE_TAB_BOTTOM_LEFT);
  42. return T;
  43. }
  44. Tab& Tab::text(C Str &text)
  45. {
  46. if(!Equal(super::text, text, true))
  47. {
  48. super::text=text;
  49. if(parent()->is(GO_TABS)) // Tab rect may depend on text width
  50. {
  51. Tabs &tabs=parent()->asTabs();
  52. if(tabs.autoSize() && tabs.actualLayout()==TABS_HORIZONTAL)tabs.setRect();
  53. }
  54. }
  55. return T;
  56. }
  57. Bool Tab::load(File &f, CChar *path)
  58. {
  59. del();
  60. if(super::load(f, path))
  61. {
  62. _type=GO_TAB;
  63. return true;
  64. }
  65. return false;
  66. }
  67. /******************************************************************************/
  68. // TABS
  69. /******************************************************************************/
  70. void Tabs::zero()
  71. {
  72. _valid =false;
  73. _auto_size =false;
  74. _layout =_actual_layout=TABS_AUTO;
  75. _sel =-1;
  76. _space =0;
  77. _func =null;
  78. _func_user =null;
  79. _func_immediate=false;
  80. }
  81. Tabs::Tabs() {zero();}
  82. Tabs& Tabs::del()
  83. {
  84. _tabs.del ();
  85. _skin.clear();
  86. super::del(); zero(); return T;
  87. }
  88. void Tabs::setButtonSubType()
  89. {
  90. // detect first and last visible tab
  91. Int first_i=0, last_i=0;
  92. FREPA(T)if(tab(i).visible()){first_i=i; break;}
  93. REPA(T)if(tab(i).visible()){ last_i=i; break;}
  94. // setup sub types
  95. BUTTON_TYPE first, middle, last;
  96. if(_actual_layout==TABS_HORIZONTAL){first=BUTTON_TYPE_TAB_LEFT; middle=BUTTON_TYPE_TAB_HORIZONTAL; last=BUTTON_TYPE_TAB_RIGHT ;}
  97. else {first=BUTTON_TYPE_TAB_TOP ; middle=BUTTON_TYPE_TAB_VERTICAL ; last=BUTTON_TYPE_TAB_BOTTOM;}
  98. REPA(T)
  99. {
  100. Tab &tab=T.tab(i);
  101. if(tab._sub_type<BUTTON_TYPE_TAB_CORNER_START || tab._sub_type>BUTTON_TYPE_TAB_CORNER_END) // if wasn't set to be a corner
  102. tab._sub_type=((i==first_i) ? first : (i==last_i) ? last : middle);
  103. }
  104. }
  105. void Tabs::setParams()
  106. {
  107. _type=GO_TABS;
  108. REPA(T)
  109. {
  110. Tab &tab=T.tab(i); tab._parent=this; tab._pixel_align=false;
  111. }
  112. setButtonSubType();
  113. }
  114. Tabs& Tabs::create(CChar8 **text, Int num, Bool auto_size)
  115. {
  116. del();
  117. _visible=true;
  118. _tabs.setNum(num);
  119. FREPAO(_tabs).create(text ? text[i] : null); // no need to apply skin for tabs because at this point Tabs skin is null
  120. T._auto_size=auto_size;
  121. setParams();
  122. return T;
  123. }
  124. Tabs& Tabs::create(CChar **text, Int num, Bool auto_size)
  125. {
  126. del();
  127. _visible=true;
  128. _tabs.setNum(num);
  129. FREPAO(_tabs).create(text ? text[i] : null); // no need to apply skin for tabs because at this point Tabs skin is null
  130. T._auto_size=auto_size;
  131. setParams();
  132. return T;
  133. }
  134. Tabs& Tabs::create(C Tabs &src)
  135. {
  136. if(this!=&src)
  137. {
  138. if(!src.is())del();else
  139. {
  140. del();
  141. copyParams(src);
  142. _type =GO_TABS;
  143. _skin =src._skin;
  144. _valid =src._valid;
  145. _auto_size =src._auto_size;
  146. _layout =src._layout;
  147. _actual_layout =src._actual_layout;
  148. _sel =src._sel;
  149. _space =src._space;
  150. _func =src._func;
  151. _func_user =src._func_user;
  152. _func_immediate=src._func_immediate;
  153. _tabs.setNum(src.tabs()); FREPAO(_tabs).create(src.tab(i))._parent=this;
  154. }
  155. }
  156. return T;
  157. }
  158. void Tabs::removeChild(GuiObj &child)
  159. {
  160. FREPA(T)tab(i).removeChild(child);
  161. }
  162. /******************************************************************************/
  163. Tabs& Tabs::func(void (*func)(Ptr), Ptr user, Bool immediate)
  164. {
  165. T._func =func;
  166. T._func_user =user;
  167. T._func_immediate=immediate;
  168. return T;
  169. }
  170. void Tabs::call(Bool sound)
  171. {
  172. if(sound)Gui.playClickSound();
  173. if(_func)if(_func_immediate)_func(_func_user);else Gui.addFuncCall(_func, _func_user);
  174. }
  175. /******************************************************************************/
  176. TABS_LAYOUT Tabs::actualLayout()C
  177. {
  178. TABS_LAYOUT layout=T.layout();
  179. if(layout==TABS_AUTO)
  180. {
  181. Flt aspect=2.8f, w=rect().w(), h=rect().h();
  182. layout=((AbsScale((w/_tabs.elms())/h, aspect) < AbsScale(w/(h/_tabs.elms()), aspect)) ? TABS_HORIZONTAL : TABS_VERTICAL);
  183. }
  184. return layout;
  185. }
  186. void Tabs::setRect()
  187. {
  188. if(_tabs.elms())
  189. {
  190. Flt w=rect().w(),
  191. h=rect().h();
  192. _actual_layout=actualLayout();
  193. setButtonSubType();
  194. if(_actual_layout==TABS_HORIZONTAL)
  195. {
  196. w-=(_tabs.elms()-1)*space();
  197. if(autoSize())
  198. {
  199. Flt x=rect().min.x, text_width=0, size=h;
  200. FREPA(T)text_width+=tab(i).textWidth(&size); Flt padd=(w-text_width)/_tabs.elms();
  201. FREPA(T)
  202. {
  203. Tab &tab=T.tab(i); Flt w=tab.textWidth(&size)+padd;
  204. tab.rect(Rect(x, rect().min.y, x+w, rect().max.y));
  205. x+=w+space();
  206. }
  207. }else
  208. {
  209. w/=_tabs.elms();
  210. REPA(T)tab(i).rect(Rect(rect().min.x+(w+space())*i, rect().min.y, rect().min.x+(w+space())*i+w, rect().max.y));
  211. }
  212. }else
  213. {
  214. h-=(_tabs.elms()-1)*space(); h/=_tabs.elms();
  215. REPA(T)tab(i).rect(Rect(rect().min.x, rect().max.y-(h+space())*i-h, rect().max.x, rect().max.y-(h+space())*i));
  216. }
  217. }
  218. }
  219. Tabs& Tabs::rect(C Rect &rect, Flt space, Bool auto_size)
  220. {
  221. if(T.rect()!=rect || T.space()!=space || T.autoSize()!=auto_size)
  222. {
  223. T._rect =rect;
  224. T._space =space;
  225. T._auto_size=auto_size;
  226. setRect();
  227. }
  228. return T;
  229. }
  230. /******************************************************************************/
  231. Tabs& Tabs::rect(C Rect &rect) {return T.rect(rect, space(), autoSize());}
  232. /******************************************************************************/
  233. Tabs& Tabs::layout(TABS_LAYOUT layout)
  234. {
  235. MIN(layout, TABS_NUM);
  236. if(T.layout()!=layout)
  237. {
  238. T._layout=layout;
  239. setRect();
  240. }
  241. return T;
  242. }
  243. /******************************************************************************/
  244. Tabs& Tabs::valid(Bool on) {T._valid=on; return T;}
  245. Tabs& Tabs::set(Int i, SET_MODE mode)
  246. {
  247. if(!InRange(i, _tabs))
  248. {
  249. if(valid())return T; // don't set to -1 if 'valid' is enabled
  250. i=-1; // set sel to -1
  251. }
  252. if(T()!=i)
  253. {
  254. Bool kb=contains(Gui.kb());
  255. if(valid() && InRange(T(), T)) // set highlight for previously selected tab if there's a hoverable MT above it
  256. {
  257. Tab &tab=T.tab(T());
  258. Bool lit=false; if(enabled())REPA(MT)if(MT.guiObj(i)==&tab && MT.hoverable(i)){lit=true; break;}
  259. tab._lit=lit;
  260. }
  261. _sel=i; REPAD(j, T)tab(j).set(i==j);
  262. if(valid() && InRange(T(), T))tab(T())._lit=0; // disable highlight for newly selected tab
  263. if(kb)if(InRange(T(), T))tab(T()).kbSet();else kbSet();
  264. if(mode!=QUIET)call(mode!=NO_SOUND);
  265. }
  266. return T;
  267. }
  268. Tabs& Tabs::toggle(Int i, SET_MODE mode) {return set((T()==i) ? -1 : i, mode);}
  269. /******************************************************************************/
  270. Tabs& Tabs::skin(C GuiSkinPtr &skin)
  271. {
  272. _skin=skin;
  273. REPAO(_tabs).skin=skin;
  274. return T;
  275. }
  276. /******************************************************************************/
  277. Tabs& Tabs::move(C Vec2 &delta)
  278. {
  279. if(delta.any())
  280. {
  281. super::move(delta);
  282. REPA(T)tab(i).move(delta);
  283. }
  284. return T;
  285. }
  286. /******************************************************************************/
  287. Tab& Tabs::New(C Str &text, Int i)
  288. {
  289. if(i<0)i=tabs();else if(i>tabs())i=tabs();
  290. if(_sel>=i)_sel++;
  291. Tab &tab=_tabs.NewAt(i).create(text); tab._parent=this; tab.skin=skin();
  292. setRect();
  293. return tab;
  294. }
  295. Tabs& Tabs::remove(Int i)
  296. {
  297. if(InRange(i, T))
  298. {
  299. if(_sel==i)_sel=-1;else
  300. if(_sel> i)_sel--;
  301. _tabs.removeValid(i, true);
  302. setRect();
  303. }
  304. return T;
  305. }
  306. /******************************************************************************/
  307. Tabs& Tabs::desc(C Str &desc)
  308. {
  309. super::desc(desc);
  310. REPA(T)tab(i).desc(desc);
  311. return T;
  312. }
  313. /******************************************************************************/
  314. GuiObj* Tabs::test(C GuiPC &gpc, C Vec2 &pos, GuiObj* &mouse_wheel)
  315. {
  316. if(visible() && gpc.visible && Cuts(pos, gpc.clip))
  317. {
  318. if(InRange(T(), T))if(GuiObj *go=tab(T())._children.test(gpc, pos, mouse_wheel))return go;
  319. if(Cuts(pos, rect()+gpc.offset))
  320. {
  321. REPA(T)if(GuiObj *go=tab(i).test(gpc, pos, mouse_wheel))return go;
  322. //return this; // don't return self
  323. }
  324. }
  325. return null;
  326. }
  327. /******************************************************************************/
  328. void Tabs::update(C GuiPC &gpc)
  329. {
  330. GuiPC gpc2(gpc, visible(), enabled());
  331. Bool enabled=gpc2.enabled;
  332. FREPA(T)
  333. {
  334. gpc2.enabled=(enabled && !(valid() && i==T())); // force disabled if 'valid' is enabled and we're processing activated Tab (this way we can't click pushed Tab)
  335. Tab &tab=T.tab(i); tab.update(gpc2);
  336. if((T()==i)!=tab())toggle(i); // if Tab update state changed
  337. }
  338. gpc2.enabled=enabled; // restore 'enabled' after loop, because it was changed inside it
  339. Bool visible=gpc2.visible;
  340. FREPA(T)
  341. {
  342. gpc2.visible=(visible && i==T());
  343. tab(i)._children.update(gpc2);
  344. }
  345. }
  346. void Tabs::draw(C GuiPC &gpc)
  347. {
  348. if(visible() && gpc.visible)
  349. {
  350. setButtonSubType();
  351. Rect r=rect()+gpc.offset; Vec2 ofs=D.alignScreenToPixelOffset(r.lu()); r+=ofs;
  352. GuiPC gpc2(gpc, visible(), enabled()); gpc2.offset+=ofs; // adjust offset so that all tabs have the same pixel alignment as the first one
  353. FREPA(T) tab(i ). draw(gpc2);
  354. if(T()>=0)tab(T())._children.draw(gpc );
  355. }
  356. }
  357. /******************************************************************************/
  358. Bool Tabs::save(File &f, CChar *path)C
  359. {
  360. if(super::save(f, path))
  361. {
  362. f.putMulti(Byte(1), _valid, _auto_size, _sel, _space, _layout); // version
  363. f._putAsset(_skin.name(path));
  364. f.cmpUIntV(_tabs.elms()); FREPA(_tabs)if(!_tabs[i].save(f, path))return false;
  365. return f.ok();
  366. }
  367. return false;
  368. }
  369. Bool Tabs::load(File &f, CChar *path)
  370. {
  371. del(); if(super::load(f, path))switch(f.decUIntV()) // version
  372. {
  373. case 1:
  374. {
  375. f.getMulti(_valid, _auto_size, _sel, _space, _layout);
  376. _skin.require(f._getAsset(), path);
  377. _tabs.clear().setNum(f.decUIntV()); FREPA(_tabs)if(!_tabs[i].load(f, path))goto error;
  378. if(f.ok())
  379. {
  380. _actual_layout=actualLayout();
  381. setParams();
  382. return true;
  383. }
  384. }break;
  385. case 0:
  386. {
  387. f._getStr();
  388. f>>_valid>>_auto_size>>_sel>>_space>>_layout;
  389. _tabs.clear().setNum(f.getInt()); FREPA(_tabs){Tab &tab=_tabs[i]; if(!tab.load(f, path))goto error; tab.enabled(true);} // restore enabled because in the past tabs were disabled on click
  390. if(f.ok())
  391. {
  392. _actual_layout=actualLayout();
  393. setParams();
  394. return true;
  395. }
  396. }break;
  397. }
  398. error:
  399. del(); return false;
  400. }
  401. /******************************************************************************/
  402. void Tab::parentClientRectChanged(C Rect *old_client, C Rect *new_client)
  403. {
  404. notifyChildrenOfClientRectChange(old_client, new_client); // pass on to the children
  405. }
  406. void Tabs::parentClientRectChanged(C Rect *old_client, C Rect *new_client)
  407. {
  408. notifyChildrenOfClientRectChange(old_client, new_client); // pass on to the children
  409. }
  410. /******************************************************************************/
  411. }
  412. /******************************************************************************/