tb_atomic_widgets.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903
  1. // ================================================================================
  2. // == This file is a part of Turbo Badger. (C) 2011-2014, Emil Segerås ==
  3. // == See tb_core.h for more information. ==
  4. // ================================================================================
  5. //
  6. // Copyright (c) 2016-2017, THUNDERBEAST GAMES LLC All rights reserved
  7. //
  8. // Permission is hereby granted, free of charge, to any person obtaining a copy
  9. // of this software and associated documentation files (the "Software"), to deal
  10. // in the Software without restriction, including without limitation the rights
  11. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12. // copies of the Software, and to permit persons to whom the Software is
  13. // furnished to do so, subject to the following conditions:
  14. //
  15. // The above copyright notice and this permission notice shall be included in
  16. // all copies or substantial portions of the Software.
  17. //
  18. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  24. // THE SOFTWARE.
  25. //
  26. #include "tb_widgets_reader.h"
  27. #include "tb_widgets_common.h"
  28. #include "tb_node_tree.h"
  29. #include "tb_system.h"
  30. #include "tb_atomic_widgets.h"
  31. #include "tb_editfield.h"
  32. #include "tb_menu_window.h"
  33. #include "tb_select.h"
  34. #include "tb_tab_container.h"
  35. #include <math.h>
  36. namespace tb {
  37. // == TBColorWidget =======================================
  38. TBColorWidget::TBColorWidget() : color_(), alpha_ ( 1.0f)
  39. {
  40. }
  41. void TBColorWidget::SetColor ( const char *name )
  42. {
  43. if ( name )
  44. color_.SetFromString(name, strlen(name));
  45. InvalidateSkinStates();
  46. Invalidate();
  47. }
  48. void TBColorWidget::SetColor(float r, float g, float b, float a)
  49. {
  50. color_.Set(TBColor(r, g, b, a));
  51. InvalidateSkinStates();
  52. Invalidate();
  53. }
  54. void TBColorWidget::SetAlpha ( float value )
  55. {
  56. if ( value < 0.0 || value > 1.0 )
  57. {
  58. alpha_ = 1.0;
  59. return;
  60. }
  61. alpha_ = value;
  62. InvalidateSkinStates();
  63. Invalidate();
  64. }
  65. void TBColorWidget::OnPaint(const PaintProps &paint_props)
  66. {
  67. TBRect local_rect = GetRect();
  68. local_rect.x = 0;
  69. local_rect.y = 0;
  70. float old_opacity = g_renderer->GetOpacity();
  71. g_renderer->SetOpacity(alpha_);
  72. g_renderer->DrawRectFill(local_rect, color_);
  73. g_renderer->SetOpacity(old_opacity);
  74. }
  75. void TBColorWidget::OnInflate(const INFLATE_INFO &info)
  76. {
  77. if (const char *colr = info.node->GetValueString("color", nullptr))
  78. SetColor(colr);
  79. TBWidget::OnInflate(info);
  80. }
  81. TB_WIDGET_FACTORY(TBColorWidget, TBValue::TYPE_NULL, WIDGET_Z_TOP) {}
  82. // == TBColorWheel =======================================
  83. TBColorWheel::TBColorWheel() :
  84. markerx_(128),
  85. markery_(128),
  86. markercolor_(),
  87. hue_(0.0),
  88. saturation_(0.0)
  89. {
  90. }
  91. void TBColorWheel::OnPaint(const PaintProps &paint_props)
  92. {
  93. TBWidget::OnPaint(paint_props); // draw the widget stuff
  94. TBRect local_rect ( 0,0,4,4 ); // AND draw a marker where we clicked.
  95. local_rect.x = markerx_ - 2;
  96. local_rect.y = markery_ - 2;
  97. g_renderer->DrawRect( local_rect, markercolor_);
  98. local_rect.x -= 1;
  99. local_rect.y -= 1;
  100. local_rect.w += 2;
  101. local_rect.h += 2;
  102. g_renderer->DrawRect( local_rect, markercolor_); // draw double box
  103. }
  104. bool TBColorWheel::OnEvent(const TBWidgetEvent &ev)
  105. {
  106. if (ev.target == this && ev.type == EVENT_TYPE_CLICK)
  107. {
  108. SetMarkerX ( ev.target_x );
  109. SetMarkerY ( ev.target_y );
  110. CalcHueSaturation( markerx_, markery_ );
  111. TBWidgetEvent ev(EVENT_TYPE_CHANGED);
  112. InvokeEvent(ev);
  113. }
  114. return TBWidget::OnEvent(ev);
  115. }
  116. void TBColorWheel::SetHueSaturation ( float hue, float saturation )
  117. {
  118. // suppose to set the marker position to match HS here
  119. hue_ = hue * 360.0;
  120. saturation_ = saturation * 128.0;
  121. Invalidate();
  122. }
  123. void TBColorWheel::CalcHueSaturation ( int rawx, int rawy )
  124. {
  125. TBRect rect = GetRect();
  126. int centerx = rect.w / 2;
  127. int centery = rect.h / 2;
  128. float X1 = rawx;
  129. float Y1 = rawy;
  130. float X2 = centerx;
  131. float Y2 = centery;
  132. float angle = 0.0;
  133. float xd = X2-X1;
  134. float yd = Y2-Y1;
  135. float dx = sqrt(xd * xd + yd * yd);
  136. // angle in degrees
  137. angle = atan2(Y2 - Y1, X2 - X1) * 180 / 3.14159265358979323846;
  138. if (angle < 0) angle += 360.0;
  139. // if the distance > 128, can we calculate the line point at 128 and set the marker there?
  140. if( dx > 128.0 ) dx = 128.0; // limit value
  141. saturation_ = dx;
  142. hue_ = angle;
  143. }
  144. void TBColorWheel::SetMarkerX ( int value )
  145. {
  146. markerx_ = value;
  147. }
  148. void TBColorWheel::SetMarkerY ( int value )
  149. {
  150. markery_ = value;
  151. }
  152. void TBColorWheel::SetMarkerColor ( const char *name )
  153. {
  154. if ( name )
  155. markercolor_.SetFromString(name, strlen(name));
  156. Invalidate();
  157. }
  158. void TBColorWheel::OnInflate(const INFLATE_INFO &info)
  159. {
  160. if (const char *colr = info.node->GetValueString("color", nullptr))
  161. SetMarkerColor(colr);
  162. TBWidget::OnInflate(info);
  163. }
  164. TB_WIDGET_FACTORY(TBColorWheel, TBValue::TYPE_FLOAT, WIDGET_Z_TOP) {}
  165. // == TBBarGraph =======================================
  166. TBBarGraph::TBBarGraph() : color_(255,255,255,255), m_value (0.0), m_axis(AXIS_X), m_margin(0)
  167. {
  168. SetSkinBg(TBIDC("background_solid"), WIDGET_INVOKE_INFO_NO_CALLBACKS);
  169. }
  170. void TBBarGraph::SetColor ( const char *name )
  171. {
  172. if ( name )
  173. color_.SetFromString(name, strlen(name));
  174. InvalidateSkinStates();
  175. Invalidate();
  176. }
  177. void TBBarGraph::SetColor(float r, float g, float b, float a)
  178. {
  179. color_.Set(TBColor(r, g, b, a));
  180. InvalidateSkinStates();
  181. Invalidate();
  182. }
  183. void TBBarGraph::OnPaint(const PaintProps &paint_props)
  184. {
  185. TBRect local_rect = GetRect();
  186. local_rect.x = 0;
  187. local_rect.y = 0;
  188. if ( m_axis == AXIS_X ) // horizontal bar
  189. {
  190. double w1 = (double)local_rect.w * ( m_value / 100.0 );
  191. local_rect.w = (int)w1;
  192. if ( m_margin > 0 && m_margin < (local_rect.h/2)-2)
  193. {
  194. local_rect.h -= (m_margin *2);
  195. local_rect.y += m_margin;
  196. }
  197. }
  198. else if ( m_axis == AXIS_Y ) // vertical bar
  199. {
  200. double h1 = (double)local_rect.h * ( m_value / 100.0 );
  201. local_rect.y = local_rect.h - (int)h1;
  202. local_rect.h = (int)h1;
  203. if ( m_margin > 0 && m_margin < (local_rect.w/2)-2 )
  204. {
  205. local_rect.w -= (m_margin*2);
  206. local_rect.x += m_margin;
  207. }
  208. }
  209. g_renderer->DrawRectFill(local_rect, color_);
  210. }
  211. void TBBarGraph::OnInflate(const INFLATE_INFO &info)
  212. {
  213. if (const char *colr = info.node->GetValueString("color", nullptr))
  214. SetColor(colr);
  215. if ( const char *axis = info.node->GetValueString("axis", "x") )
  216. SetAxis(*axis == 'x' ? AXIS_X : AXIS_Y);
  217. if (info.sync_type == TBValue::TYPE_FLOAT)
  218. SetValueDouble(info.node->GetValueFloat("value", 0));
  219. SetMargin( (unsigned)info.node->GetValueInt("margin", 0 ) );
  220. TBWidget::OnInflate(info);
  221. }
  222. void TBBarGraph::SetValueDouble(double value)
  223. {
  224. value = CLAMP(value, 0.0, 100.0);
  225. if (value == m_value)
  226. return;
  227. m_value = value;
  228. InvalidateSkinStates();
  229. Invalidate();
  230. }
  231. void TBBarGraph::SetAxis(AXIS axis)
  232. {
  233. m_axis = axis;
  234. InvalidateSkinStates();
  235. Invalidate();
  236. }
  237. TB_WIDGET_FACTORY(TBBarGraph, TBValue::TYPE_FLOAT, WIDGET_Z_TOP) {}
  238. // == TBPromptWindow =======================================
  239. TBPromptWindow::TBPromptWindow(TBWidget *target, TBID id)
  240. : m_target(target)
  241. {
  242. TBWidgetListener::AddGlobalListener(this);
  243. SetID(id);
  244. }
  245. TBPromptWindow::~TBPromptWindow()
  246. {
  247. TBWidgetListener::RemoveGlobalListener(this);
  248. if (TBWidget *dimmer = m_dimmer.Get())
  249. {
  250. dimmer->GetParent()->RemoveChild(dimmer);
  251. delete dimmer;
  252. }
  253. }
  254. bool TBPromptWindow::Show(const char *title, const char *message,
  255. const char *preset, int dimmer,
  256. int width, int height)
  257. {
  258. TBWidget *target = m_target.Get();
  259. if (!target)
  260. return false;
  261. TBWidget *root = target->GetParentRoot();
  262. const char *source = "TBLayout: axis: y, distribution: gravity, position: left\n"
  263. " TBLayout: axis: y, distribution: gravity, distribution-position: left\n"
  264. " TBTextField: id: 1, gravity: left right\n"
  265. " font: size: 14dp\n"
  266. " TBEditField: id: 2, multiline: 0, styling: 0, adapt-to-content: 0, gravity: left right\n"
  267. " font: size: 14dp\n"
  268. " TBSeparator: gravity: left right\n"
  269. " TBLayout: distribution: gravity\n"
  270. " TBButton: text: \" OK \", id: \"TBPromptWindow.ok\"\n"
  271. " font: size: 14dp\n"
  272. " TBButton: text: \"Cancel\", id: \"TBPromptWindow.cancel\"\n"
  273. " font: size: 14dp\n";
  274. if (!g_widgets_reader->LoadData(GetContentRoot(), source))
  275. return false;
  276. SetText(title);
  277. TBTextField *editfield = GetWidgetByIDAndType<TBTextField>(UIPROMPTMESSAGEID);
  278. editfield->SetText(message);
  279. editfield->SetSkinBg("");
  280. TBEditField *stringfield = GetWidgetByIDAndType<TBEditField>(UIPROMPTEDITID);
  281. if (preset)
  282. stringfield->SetText(preset);
  283. TBRect rect;
  284. // Size to fit content. This will use the default size of the textfield.
  285. if (width == 0 || height == 0)
  286. {
  287. ResizeToFitContent();
  288. rect = GetRect();
  289. }
  290. else
  291. {
  292. SetSize(width, height);
  293. rect = GetRect();
  294. }
  295. // Create background dimmer
  296. if (dimmer != 0)
  297. {
  298. if (TBDimmer *dimmer = new TBDimmer)
  299. {
  300. root->AddChild(dimmer);
  301. m_dimmer.Set(dimmer);
  302. }
  303. }
  304. // Center and size to the new height
  305. TBRect bounds(0, 0, root->GetRect().w, root->GetRect().h);
  306. SetRect(rect.CenterIn(bounds).MoveIn(bounds).Clip(bounds));
  307. root->AddChild(this);
  308. return true;
  309. }
  310. bool TBPromptWindow::OnEvent(const TBWidgetEvent &ev)
  311. {
  312. if (ev.type == EVENT_TYPE_CLICK && ev.target->IsOfType<TBButton>())
  313. {
  314. TBWidgetSafePointer this_widget(this);
  315. // Invoke the click on the target
  316. TBWidgetEvent target_ev(EVENT_TYPE_CLICK);
  317. target_ev.ref_id = ev.target->GetID();
  318. InvokeEvent(target_ev);
  319. // If target got deleted, close
  320. if (this_widget.Get())
  321. Close();
  322. return true;
  323. }
  324. else if (ev.type == EVENT_TYPE_KEY_DOWN && ev.special_key == TB_KEY_ESC)
  325. {
  326. TBWidgetEvent click_ev(EVENT_TYPE_CLICK);
  327. m_close_button.InvokeEvent(click_ev);
  328. return true;
  329. }
  330. return TBWindow::OnEvent(ev);
  331. }
  332. void TBPromptWindow::OnDie()
  333. {
  334. if (TBWidget *dimmer = m_dimmer.Get())
  335. dimmer->Die();
  336. }
  337. void TBPromptWindow::OnWidgetDelete(TBWidget *widget)
  338. {
  339. // If the target widget is deleted, close!
  340. if (!m_target.Get())
  341. Close();
  342. }
  343. bool TBPromptWindow::OnWidgetDying(TBWidget *widget)
  344. {
  345. // If the target widget or an ancestor of it is dying, close!
  346. if (widget == m_target.Get() || widget->IsAncestorOf(m_target.Get()))
  347. Close();
  348. return false;
  349. }
  350. // == TBFinderWindow =======================================
  351. TBFinderWindow::TBFinderWindow(TBWidget *target, TBID id)
  352. : m_target(target),
  353. rightMenuParent(NULL),
  354. rightMenuChild(NULL)
  355. {
  356. TBWidgetListener::AddGlobalListener(this);
  357. SetID(id);
  358. }
  359. TBFinderWindow::~TBFinderWindow()
  360. {
  361. TBWidgetListener::RemoveGlobalListener(this);
  362. if (TBWidget *dimmer = m_dimmer.Get())
  363. {
  364. dimmer->GetParent()->RemoveChild(dimmer);
  365. delete dimmer;
  366. }
  367. rightMenuParent=NULL;
  368. rightMenuChild=NULL;
  369. }
  370. bool TBFinderWindow::Show(const char *title,
  371. const char *preset, int dimmer,
  372. int width, int height)
  373. {
  374. TBWidget *target = m_target.Get();
  375. if (!target)
  376. return false;
  377. TBWidget *root = target->GetParentRoot();
  378. const char *source =
  379. "TBLayout: axis: y, size: available, position: gravity, distribution: gravity\n"
  380. " lp: min-width: 512dp, min-height: 500dp\n"
  381. " TBLayout: distribution: gravity, distribution-position: left\n"
  382. " TBEditField: id: 1, multiline: 0, styling: 0, adapt-to-content: 0, gravity: left right\n"
  383. " tooltip current folder location\n"
  384. " font: size: 14dp\n"
  385. " TBButton\n"
  386. " lp: height: 28dp, width: 28dp\n"
  387. " skin TBButton.uniformflat\n"
  388. " TBSkinImage: skin: FolderUp, id: up_image\n"
  389. " id 2\n"
  390. " tooltip Go up one folder\n"
  391. " TBWidget\n"
  392. " lp: height: 28dp, width: 28dp\n"
  393. " TBButton\n"
  394. " lp: height: 28dp, width: 28dp\n"
  395. " skin TBButton.uniformflat\n"
  396. " TBSkinImage: skin: BookmarkIcon, id: book_image\n"
  397. " id 3\n"
  398. " tooltip Bookmark current folder\n"
  399. " TBButton\n"
  400. " lp: height: 28dp, width: 28dp\n"
  401. " skin TBButton.uniformflat\n"
  402. " TBSkinImage: skin: FolderAdd, id: create_image\n"
  403. " id 4\n"
  404. " tooltip Create a new folder \n"
  405. " TBLayout: distribution: gravity, distribution-position: left\n"
  406. " TBLayout: axis: x, distribution: gravity\n"
  407. " TBSelectList: id: 5, gravity: all\n"
  408. " lp: max-width: 160dp, min-width: 160dp\n"
  409. " font: size: 14dp\n"
  410. " TBSelectList: id: 6, gravity: all\n"
  411. " font: size: 14dp\n"
  412. " TBLayout: distribution: gravity\n"
  413. " TBEditField: id: 7, multiline: 0, styling: 0, adapt-to-content: 0, gravity: left right\n"
  414. " tooltip name of the wanted file\n"
  415. " font: size: 14dp\n"
  416. " TBLayout: distribution: gravity\n"
  417. " TBButton: text: \" OK \", id: 8\n"
  418. " font: size: 14dp\n"
  419. " TBButton: text: \"Cancel\", id: 9\n"
  420. " font: size: 14dp\n";
  421. if (!g_widgets_reader->LoadData(GetContentRoot(), source))
  422. return false;
  423. SetText(title);
  424. TBRect rect;
  425. // Size to fit content. This will use the default size of the textfield.
  426. if (width == 0 || height == 0)
  427. {
  428. ResizeToFitContent();
  429. rect = GetRect();
  430. }
  431. else
  432. {
  433. SetSize(width, height);
  434. rect = GetRect();
  435. }
  436. // Create background dimmer
  437. if (dimmer != 0)
  438. {
  439. if (TBDimmer *dimmer = new TBDimmer)
  440. {
  441. root->AddChild(dimmer);
  442. m_dimmer.Set(dimmer);
  443. }
  444. }
  445. // Center and size to the new height
  446. TBRect bounds(0, 0, root->GetRect().w, root->GetRect().h);
  447. SetRect(rect.CenterIn(bounds).MoveIn(bounds).Clip(bounds));
  448. root->AddChild(this);
  449. return true;
  450. }
  451. bool TBFinderWindow::OnEvent(const TBWidgetEvent &ev)
  452. {
  453. if (ev.type == EVENT_TYPE_CLICK )
  454. {
  455. if ( ev.target->IsOfType<TBButton>())
  456. {
  457. TBWidgetSafePointer this_widget(this);
  458. // Invoke the click on the target
  459. TBWidgetEvent target_ev(EVENT_TYPE_CLICK);
  460. target_ev.ref_id = ev.target->GetID();
  461. InvokeEvent(target_ev);
  462. // these are internal buttons that do not close the finder window!
  463. bool isbuttons = (ev.target->GetID() == UIFINDERUPBUTTONID
  464. || ev.target->GetID() == UIFINDERBOOKBUTTONID
  465. || ev.target->GetID() == UIFINDERFOLDERBUTTONID );
  466. // If target got deleted, close
  467. if (this_widget.Get() && !isbuttons )
  468. Close();
  469. return true;
  470. }
  471. else if ( ev.target->GetID() == TBIDC("popupmenu"))
  472. {
  473. if (ev.ref_id == TBIDC("delete"))
  474. {
  475. // send EVENT_TYPE_CUSTOM, were gonna used cached information to send info how we got here
  476. if(rightMenuParent)
  477. {
  478. TBWidgetEvent custom_ev(EVENT_TYPE_CUSTOM);
  479. custom_ev.target = rightMenuParent; // were want to operate on this list
  480. custom_ev.ref_id = rightMenuChild?rightMenuChild->GetID():ev.ref_id; // on this entry
  481. custom_ev.special_key = TB_KEY_DELETE; // and what we wanna do to it
  482. rightMenuParent->InvokeEvent(custom_ev); // forward to delegate
  483. rightMenuChild = NULL; // clear the cached values
  484. rightMenuParent = NULL;
  485. }
  486. }
  487. else
  488. return false;
  489. return true;
  490. }
  491. }
  492. else if (ev.type == EVENT_TYPE_KEY_DOWN && ev.special_key == TB_KEY_ESC)
  493. {
  494. TBWidgetEvent click_ev(EVENT_TYPE_CLICK);
  495. m_close_button.InvokeEvent(click_ev);
  496. return true;
  497. }
  498. else if (ev.type == EVENT_TYPE_CONTEXT_MENU || ev.type == EVENT_TYPE_RIGHT_POINTER_UP ) // want to embed popup menu on TBSelectList id: 5
  499. {
  500. rightMenuChild = ev.target; // save for later, this is where we started
  501. rightMenuParent = FindParentList(ev.target); // save for later, omg why is this so hard!
  502. if ( rightMenuParent && rightMenuParent->GetID() == UIFINDERBOOKLISTID ) // if we clicked in bookmark list take action!
  503. {
  504. TBPoint pos_in_root(ev.target_x, ev.target_y);
  505. if (TBMenuWindow *menu = new TBMenuWindow(rightMenuParent, TBIDC("popupmenu")))
  506. {
  507. TBGenericStringItemSource *source = menu->GetList()->GetDefaultSource();
  508. source->AddItem(new TBGenericStringItem("delete", TBIDC("delete")));
  509. menu->Show(source, TBPopupAlignment(pos_in_root), -1);
  510. }
  511. return true;
  512. }
  513. }
  514. return TBWindow::OnEvent(ev);
  515. }
  516. void TBFinderWindow::OnDie()
  517. {
  518. if (TBWidget *dimmer = m_dimmer.Get())
  519. dimmer->Die();
  520. }
  521. void TBFinderWindow::OnWidgetDelete(TBWidget *widget)
  522. {
  523. // If the target widget is deleted, close!
  524. if (!m_target.Get())
  525. Close();
  526. }
  527. bool TBFinderWindow::OnWidgetDying(TBWidget *widget)
  528. {
  529. // If the target widget or an ancestor of it is dying, close!
  530. if (widget == m_target.Get() || widget->IsAncestorOf(m_target.Get()))
  531. Close();
  532. return false;
  533. }
  534. TBWidget *TBFinderWindow::FindParentList( TBWidget *widget) // utility for dealing with menus.
  535. {
  536. TBWidget *tmp = widget;
  537. while (tmp)
  538. {
  539. if ( tmp->IsOfType<TBSelectList>() ) return tmp;
  540. tmp = tmp->GetParent();
  541. }
  542. return NULL;
  543. }
  544. // == TBPulldownMenu ==========================================
  545. TBPulldownMenu::TBPulldownMenu()
  546. : m_value(-1)
  547. {
  548. SetSource(&m_default_source);
  549. SetSkinBg(TBIDC("TBSelectDropdown"), WIDGET_INVOKE_INFO_NO_CALLBACKS);
  550. }
  551. TBPulldownMenu::~TBPulldownMenu()
  552. {
  553. SetSource(nullptr);
  554. CloseWindow();
  555. }
  556. void TBPulldownMenu::OnSourceChanged()
  557. {
  558. m_value = -1;
  559. m_valueid = TBID();
  560. if (m_source && m_source->GetNumItems())
  561. SetValue(0);
  562. }
  563. void TBPulldownMenu::SetValue(int value)
  564. {
  565. if (!m_source)
  566. return;
  567. m_value = value;
  568. m_valueid = GetSelectedItemID();
  569. InvokeModifiedEvent( m_valueid );
  570. }
  571. TBID TBPulldownMenu::GetSelectedItemID()
  572. {
  573. if (m_source && m_value >= 0 && m_value < m_source->GetNumItems())
  574. return m_source->GetItemID(m_value);
  575. return TBID();
  576. }
  577. void TBPulldownMenu::InvokeModifiedEvent( TBID entryid )
  578. {
  579. TBWidgetEvent ev( EVENT_TYPE_CHANGED);
  580. // TBIDC does not register the TBID with the UI system, so do it this way
  581. ev.target = this; // who am I
  582. ev.ref_id = entryid; // id of whom we clicked
  583. TBWidget::OnEvent(ev); // forward to delegate
  584. }
  585. void TBPulldownMenu::OpenWindow()
  586. {
  587. if (!m_source || !m_source->GetNumItems() || m_window_pointer.Get())
  588. return;
  589. if (TBMenuWindow *window = new TBMenuWindow(this, TBIDC("TBPulldownMenu.menu")))
  590. {
  591. m_window_pointer.Set(window);
  592. window->SetSkinBg(TBIDC("TBSelectDropdown.window"));
  593. window->Show(m_source, TBPopupAlignment());
  594. }
  595. }
  596. void TBPulldownMenu::CloseWindow()
  597. {
  598. if (TBMenuWindow *window = GetMenuIfOpen())
  599. window->Close();
  600. }
  601. TBMenuWindow *TBPulldownMenu::GetMenuIfOpen() const
  602. {
  603. return TBSafeCast<TBMenuWindow>(m_window_pointer.Get());
  604. }
  605. bool TBPulldownMenu::OnEvent(const TBWidgetEvent &ev)
  606. {
  607. if ( ev.target->IsOfType<TBButton>() && ev.type == EVENT_TYPE_CLICK)
  608. {
  609. // Open the menu, or set the value and close it if already open (this will
  610. // happen when clicking by keyboard since that will call click on this button)
  611. if (TBMenuWindow *menu_window = GetMenuIfOpen())
  612. {
  613. TBWidgetSafePointer tmp(this);
  614. int value = menu_window->GetList()->GetValue();
  615. menu_window->Die();
  616. if (tmp.Get())
  617. SetValue(value);
  618. }
  619. else
  620. OpenWindow();
  621. return true;
  622. }
  623. else if (ev.target->GetID() == TBIDC("TBPulldownMenu.menu") && ev.type == EVENT_TYPE_CLICK )
  624. {
  625. if (TBMenuWindow *menu_window = GetMenuIfOpen())
  626. SetValue(menu_window->GetList()->GetValue());
  627. return true;
  628. }
  629. else if (ev.target == this && m_source && ev.IsKeyEvent())
  630. {
  631. if (TBMenuWindow *menu_window = GetMenuIfOpen())
  632. {
  633. // Redirect the key strokes to the list
  634. TBWidgetEvent redirected_ev(ev);
  635. return menu_window->GetList()->InvokeEvent(redirected_ev);
  636. }
  637. }
  638. return false;
  639. }
  640. TB_WIDGET_FACTORY( TBPulldownMenu, TBValue::TYPE_INT, WIDGET_Z_TOP) {}
  641. extern void ReadItems(TBNode *node, TBGenericStringItemSource *target_source); // blind function that lives in tb_widgets_reader.cpp
  642. void TBPulldownMenu::OnInflate(const INFLATE_INFO &info)
  643. {
  644. // Read items (if there is any) into the default source
  645. ReadItems(info.node, GetDefaultSource());
  646. TBWidget::OnInflate(info);
  647. }
  648. // == TBDockWindow ==========================================
  649. TBDockWindow::TBDockWindow( TBStr title, TBWidget *contentptr, int minwidth, int minheight ) : TBWindow()
  650. {
  651. m_mover.AddChild(&m_redock_button);
  652. m_redock_button.SetSkinBg(TBIDC("TBWindow.redock"));
  653. m_redock_button.SetIsFocusable(false);
  654. m_redock_button.SetID(TBIDC("TBWindow.redock"));
  655. m_redock_button.SetVisibilility(WIDGET_VISIBILITY_INVISIBLE);
  656. SetText(title);
  657. TBStr uilayout; // undock host ui layout
  658. uilayout.SetFormatted ( "TBLayout: axis: y, distribution: gravity\n\tlp: min-width: %ddp, min-height: %ddp\n\tTBLayout: id: \"undocklayout\", distribution: gravity\n", minwidth, minheight );
  659. g_widgets_reader->LoadData(this, uilayout );
  660. TBLayout *lo1 = GetWidgetByIDAndType<TBLayout>(TBID("undocklayout"));
  661. lo1->AddChild(contentptr); // jam it into the window before the pointer gets stale
  662. ResizeToFitContent();
  663. }
  664. TBDockWindow::~TBDockWindow()
  665. {
  666. if (m_resizer.GetParent()) RemoveChild(&m_resizer);
  667. if (m_mover.GetParent()) RemoveChild(&m_mover);
  668. if (m_close_button.GetParent()) m_mover.RemoveChild(&m_close_button);
  669. if (m_redock_button.GetParent()) m_mover.RemoveChild(&m_redock_button);
  670. m_mover.RemoveChild(&m_textfield);
  671. }
  672. void TBDockWindow::SetDockOrigin( TBID dockid )
  673. {
  674. m_dockid = dockid;
  675. if ( m_dockid > 0 ) //enable/show the (re)dock button is a return id is specified
  676. {
  677. m_redock_button.SetVisibilility(WIDGET_VISIBILITY_VISIBLE);
  678. }
  679. }
  680. void TBDockWindow::Show( TBWidget *host, int xpos, int ypos )
  681. {
  682. if ( host )
  683. {
  684. host->AddChild(this);
  685. SetPosition( TBPoint( xpos, ypos) );
  686. }
  687. }
  688. TBWidget *TBDockWindow::GetDockContent()
  689. {
  690. TBLayout *lo1 = GetWidgetByIDAndType<TBLayout>(TBID("undocklayout"));
  691. if ( lo1 )
  692. return lo1->GetChildFromIndex(0);
  693. }
  694. bool TBDockWindow::HasDockContent()
  695. {
  696. return ( GetDockContent() != NULL );
  697. }
  698. void TBDockWindow::Redock ()
  699. {
  700. if ( m_dockid > 0 ) // see if there is a dock point id specified
  701. {
  702. TBWidget *mytarget = GetParentRoot(true)->GetWidgetByID(m_dockid);
  703. if (mytarget)
  704. Dock (mytarget);
  705. }
  706. }
  707. void TBDockWindow::Dock ( TBWidget *target )
  708. {
  709. if ( !HasDockContent() ) return;
  710. if ( target ) // what kind of widget is it?
  711. {
  712. TBStr mystr;
  713. TBWidget *mypage = NULL;
  714. TBLayout *lo1 = NULL;
  715. TBTabContainer *tc1 = NULL;
  716. if ( tc1 = TBSafeCast<TBTabContainer>( target ) ) // handle TBTabContainer
  717. {
  718. mystr = GetText();
  719. mypage = GetDockContent();
  720. if (mypage)
  721. {
  722. TBButton *tbb = new TBButton();
  723. tbb->SetID (TBID(mystr));
  724. tbb->SetText(mystr);
  725. mypage->GetParent()->RemoveChild(mypage);
  726. tc1->GetContentRoot()->AddChild(mypage);
  727. tc1->GetTabLayout()->AddChild(tbb);
  728. tc1->Invalidate();
  729. tc1->SetCurrentPage(tc1->GetNumPages()-1);
  730. Close();
  731. }
  732. }
  733. }
  734. }
  735. bool TBDockWindow::OnEvent(const TBWidgetEvent &ev)
  736. {
  737. if (ev.target == &m_close_button)
  738. {
  739. if (ev.type == EVENT_TYPE_CLICK)
  740. Close();
  741. return true;
  742. }
  743. if (ev.target == &m_redock_button)
  744. {
  745. if (ev.type == EVENT_TYPE_CLICK)
  746. Redock();
  747. return true;
  748. }
  749. return TBWidget::OnEvent(ev);
  750. }
  751. void TBDockWindow::OnResized(int old_w, int old_h)
  752. {
  753. // Apply gravity on children
  754. TBWidget::OnResized(old_w, old_h);
  755. // Manually move our own decoration children
  756. // FIX: Put a layout in the TBMover so we can add things there nicely.
  757. int title_height = GetTitleHeight();
  758. m_mover.SetRect(TBRect(0, 0, GetRect().w, title_height));
  759. PreferredSize ps = m_resizer.GetPreferredSize();
  760. m_resizer.SetRect(TBRect(GetRect().w - ps.pref_w, GetRect().h - ps.pref_h, ps.pref_w, ps.pref_h));
  761. TBRect mover_rect = m_mover.GetPaddingRect();
  762. int button_size = mover_rect.h;
  763. m_close_button.SetRect(TBRect(mover_rect.x + mover_rect.w - button_size, mover_rect.y, button_size, button_size));
  764. if (m_settings & WINDOW_SETTINGS_CLOSE_BUTTON)
  765. mover_rect.w -= button_size;
  766. // add redock button to header
  767. m_redock_button.SetRect(TBRect(mover_rect.x + mover_rect.w - button_size, mover_rect.y, button_size, button_size));
  768. if (m_settings & WINDOW_SETTINGS_CLOSE_BUTTON)
  769. mover_rect.w -= button_size;
  770. m_textfield.SetRect(mover_rect);
  771. }
  772. }; // namespace tb