llpanel.cpp 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786
  1. /**
  2. * @file llpanel.cpp
  3. * @brief LLPanel base class
  4. *
  5. * $LicenseInfo:firstyear=2001&license=viewergpl$
  6. *
  7. * Copyright (c) 2001-2009, Linden Research, Inc.
  8. *
  9. * Second Life Viewer Source Code
  10. * The source code in this file ("Source Code") is provided by Linden Lab
  11. * to you under the terms of the GNU General Public License, version 2.0
  12. * ("GPL"), unless you have obtained a separate licensing agreement
  13. * ("Other License"), formally executed by you and Linden Lab. Terms of
  14. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16. *
  17. * There are special exceptions to the terms and conditions of the GPL as
  18. * it is applied to this Source Code. View the full text of the exception
  19. * in the file doc/FLOSS-exception.txt in this software distribution, or
  20. * online at
  21. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22. *
  23. * By copying, modifying or distributing this software, you acknowledge
  24. * that you have read and understood your obligations described above,
  25. * and agree to abide by those obligations.
  26. *
  27. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29. * COMPLETENESS OR PERFORMANCE.
  30. * $/LicenseInfo$
  31. */
  32. // Opaque view with a background and a border. Can contain LLUICtrls.
  33. #include "linden_common.h"
  34. #include "llpanel.h"
  35. #include "llalertdialog.h"
  36. #include "llbutton.h"
  37. #include "llcontrol.h"
  38. #include "llcriticaldamp.h" // Used by LLLayoutStack
  39. #include "llkeyboard.h"
  40. #include "llfloater.h"
  41. #include "lliconctrl.h"
  42. #include "lllineeditor.h"
  43. #include "llmenugl.h"
  44. #include "llresizebar.h" // Used by LLLayoutStack
  45. #include "llstl.h" // For DeletePointer()
  46. #include "lltextbox.h"
  47. #include "lltimer.h"
  48. #include "lluictrl.h"
  49. #include "lluictrlfactory.h"
  50. #include "llviewborder.h"
  51. constexpr S32 RESIZE_BAR_OVERLAP = 1;
  52. constexpr S32 RESIZE_BAR_HEIGHT = 3;
  53. static const std::string LL_LAYOUT_PANEL_TAG = "layout_panel";
  54. static const std::string LL_PANEL_TAG = "panel";
  55. static LLRegisterWidget<LLPanel> r14(LL_PANEL_TAG);
  56. void LLPanel::init()
  57. {
  58. // mRectControl
  59. mBgColorAlpha = LLUI::sDefaultBackgroundColor;
  60. mBgColorOpaque = LLUI::sFocusBackgroundColor;
  61. mDefaultBtnHighlight = LLUI::sDefaultHighlightLight;
  62. mBgVisible = false;
  63. mBgOpaque = false;
  64. mBorder = NULL;
  65. mDefaultBtn = NULL;
  66. setIsChrome(false); // is this a decorator to a live window or a form ?
  67. mLastTabGroup = 0;
  68. setTabStop(false);
  69. }
  70. LLPanel::LLPanel()
  71. {
  72. init();
  73. setName(LL_PANEL_TAG);
  74. }
  75. LLPanel::LLPanel(const std::string& name)
  76. : LLUICtrl(name, LLRect(0, 0, 0, 0), true, NULL, NULL)
  77. {
  78. init();
  79. }
  80. LLPanel::LLPanel(const std::string& name, const LLRect& rect, bool bordered)
  81. : LLUICtrl(name, rect, true, NULL, NULL)
  82. {
  83. init();
  84. if (bordered)
  85. {
  86. addBorder();
  87. }
  88. }
  89. LLPanel::LLPanel(const std::string& name, const std::string& rect_control,
  90. bool bordered)
  91. : LLUICtrl(name, LLUI::sConfigGroup->getRect(rect_control.c_str()), true,
  92. NULL, NULL),
  93. mRectControl(rect_control)
  94. {
  95. init();
  96. if (bordered)
  97. {
  98. addBorder();
  99. }
  100. }
  101. LLPanel::~LLPanel()
  102. {
  103. storeRectControl();
  104. }
  105. // virtual
  106. bool LLPanel::postBuild()
  107. {
  108. return true;
  109. }
  110. void LLPanel::addBorder(LLViewBorder::EBevel border_bevel,
  111. LLViewBorder::EStyle border_style,
  112. S32 border_thickness)
  113. {
  114. removeBorder();
  115. mBorder = new LLViewBorder("panel border",
  116. LLRect(0, getRect().getHeight(),
  117. getRect().getWidth(), 0),
  118. border_bevel, border_style, border_thickness);
  119. mBorder->setSaveToXML(false);
  120. addChild(mBorder);
  121. }
  122. void LLPanel::removeBorder()
  123. {
  124. delete mBorder;
  125. mBorder = NULL;
  126. }
  127. // virtual
  128. void LLPanel::clearCtrls()
  129. {
  130. LLView::ctrl_list_t ctrls = getCtrlList();
  131. for (LLView::ctrl_list_t::iterator ctrl_it = ctrls.begin(), end = ctrls.end();
  132. ctrl_it != end; ++ctrl_it)
  133. {
  134. LLUICtrl* ctrl = *ctrl_it;
  135. ctrl->setFocus(false);
  136. ctrl->setEnabled(false);
  137. ctrl->clear();
  138. }
  139. }
  140. void LLPanel::setCtrlsEnabled(bool b)
  141. {
  142. LLView::ctrl_list_t ctrls = getCtrlList();
  143. for (LLView::ctrl_list_t::iterator ctrl_it = ctrls.begin(), end = ctrls.end();
  144. ctrl_it != end; ++ctrl_it)
  145. {
  146. LLUICtrl* ctrl = *ctrl_it;
  147. ctrl->setEnabled(b);
  148. }
  149. }
  150. void LLPanel::draw()
  151. {
  152. // Draw background
  153. if (mBgVisible)
  154. {
  155. // RN: I do not see the point of this
  156. S32 top = getRect().getHeight(); // - LLPANEL_BORDER_WIDTH;
  157. S32 right = getRect().getWidth(); // - LLPANEL_BORDER_WIDTH;
  158. if (mBgOpaque)
  159. {
  160. gl_rect_2d(0, top, right, 0, mBgColorOpaque);
  161. }
  162. else
  163. {
  164. gl_rect_2d(0, top, right, 0, mBgColorAlpha);
  165. }
  166. }
  167. updateDefaultBtn();
  168. LLView::draw();
  169. }
  170. //virtual
  171. void LLPanel::setAlpha(F32 alpha)
  172. {
  173. mBgColorOpaque.setAlpha(alpha);
  174. }
  175. void LLPanel::updateDefaultBtn()
  176. {
  177. // This method does not call LLView::draw() so callers will need
  178. // to take care of that themselves at the appropriate place in
  179. // their rendering sequence
  180. if (mDefaultBtn)
  181. {
  182. if (gFocusMgr.childHasKeyboardFocus(this) &&
  183. mDefaultBtn->getEnabled())
  184. {
  185. LLButton* buttonp;
  186. buttonp = dynamic_cast<LLButton*>(gFocusMgr.getKeyboardFocus());
  187. bool focus_is_child_button = buttonp && buttonp->getCommitOnReturn();
  188. // only enable default button when current focus is not a
  189. // return-capturing button
  190. mDefaultBtn->setBorderEnabled(!focus_is_child_button);
  191. }
  192. else
  193. {
  194. mDefaultBtn->setBorderEnabled(false);
  195. }
  196. }
  197. }
  198. void LLPanel::refresh()
  199. {
  200. // do nothing by default
  201. // but is automatically called in setFocus(true)
  202. }
  203. void LLPanel::setDefaultBtn(LLButton* btn)
  204. {
  205. if (mDefaultBtn && mDefaultBtn->getEnabled())
  206. {
  207. mDefaultBtn->setBorderEnabled(false);
  208. }
  209. mDefaultBtn = btn;
  210. if (mDefaultBtn)
  211. {
  212. mDefaultBtn->setBorderEnabled(true);
  213. }
  214. }
  215. void LLPanel::setDefaultBtn(const char* id)
  216. {
  217. LLButton* button = NULL;
  218. if (id[0])
  219. {
  220. button = getChild<LLButton>(id, true, false);
  221. }
  222. setDefaultBtn(button);
  223. }
  224. void LLPanel::addCtrl(LLUICtrl* ctrl, S32 tab_group)
  225. {
  226. mLastTabGroup = tab_group;
  227. LLView::addCtrl(ctrl, tab_group);
  228. }
  229. void LLPanel::addCtrlAtEnd(LLUICtrl* ctrl, S32 tab_group)
  230. {
  231. mLastTabGroup = tab_group;
  232. LLView::addCtrlAtEnd(ctrl, tab_group);
  233. }
  234. bool LLPanel::handleKeyHere(KEY key, MASK mask)
  235. {
  236. bool handled = false;
  237. LLUICtrl* cur_focus = gFocusMgr.getKeyboardFocusUICtrl();
  238. // Handle user hitting ESC to defocus
  239. if (key == KEY_ESCAPE && mask == MASK_NONE)
  240. {
  241. gFocusMgr.setKeyboardFocus(NULL);
  242. return true;
  243. }
  244. else if (mask == MASK_SHIFT && KEY_TAB == key)
  245. {
  246. // SHIFT-TAB
  247. if (cur_focus)
  248. {
  249. LLUICtrl* focus_root = cur_focus->findRootMostFocusRoot();
  250. if (focus_root)
  251. {
  252. handled = focus_root->focusPrevItem(false);
  253. }
  254. }
  255. }
  256. else if (mask == MASK_NONE && KEY_TAB == key)
  257. {
  258. // TAB
  259. if (cur_focus)
  260. {
  261. LLUICtrl* focus_root = cur_focus->findRootMostFocusRoot();
  262. if (focus_root)
  263. {
  264. handled = focus_root->focusNextItem(false);
  265. }
  266. }
  267. }
  268. // If we have a default button, click it when return is pressed, unless
  269. // current focus is a return-capturing button in which case *that* button
  270. // will handle the return key
  271. LLButton* focused_button = dynamic_cast<LLButton*>(cur_focus);
  272. if (cur_focus && !(focused_button && focused_button->getCommitOnReturn()))
  273. {
  274. // RETURN key means hit default button in this case
  275. if (key == KEY_RETURN && mask == MASK_NONE && mDefaultBtn != NULL &&
  276. mDefaultBtn->getVisible() && mDefaultBtn->getEnabled())
  277. {
  278. mDefaultBtn->onCommit();
  279. handled = true;
  280. }
  281. }
  282. if (key == KEY_RETURN && mask == MASK_NONE)
  283. {
  284. // set keyboard focus to self to trigger commitOnFocusLost behavior on
  285. // current ctrl
  286. if (cur_focus && cur_focus->acceptsTextInput())
  287. {
  288. cur_focus->onCommit();
  289. handled = true;
  290. }
  291. }
  292. return handled;
  293. }
  294. void LLPanel::setFocus(bool b)
  295. {
  296. if (b)
  297. {
  298. if (!gFocusMgr.childHasKeyboardFocus(this))
  299. {
  300. #if 0
  301. refresh();
  302. #endif
  303. if (!focusFirstItem())
  304. {
  305. LLUICtrl::setFocus(true);
  306. }
  307. onFocusReceived();
  308. }
  309. }
  310. else
  311. {
  312. if (this == gFocusMgr.getKeyboardFocus())
  313. {
  314. gFocusMgr.setKeyboardFocus(NULL);
  315. }
  316. else
  317. {
  318. //RN: why is this here?
  319. LLView::ctrl_list_t ctrls = getCtrlList();
  320. for (LLView::ctrl_list_t::iterator ctrl_it = ctrls.begin(),
  321. end = ctrls.end();
  322. ctrl_it != end; ++ctrl_it)
  323. {
  324. LLUICtrl* ctrl = *ctrl_it;
  325. ctrl->setFocus(false);
  326. }
  327. }
  328. }
  329. }
  330. void LLPanel::setBorderVisible(bool b)
  331. {
  332. if (mBorder)
  333. {
  334. mBorder->setVisible(b);
  335. }
  336. }
  337. //virtual
  338. const std::string& LLPanel::getTag() const
  339. {
  340. return LL_PANEL_TAG;
  341. }
  342. // virtual
  343. LLXMLNodePtr LLPanel::getXML(bool save_children) const
  344. {
  345. LLXMLNodePtr node = LLUICtrl::getXML();
  346. node->setName(LL_PANEL_TAG);
  347. if (mBorder && mBorder->getVisible())
  348. {
  349. node->createChild("border", true)->setBoolValue(true);
  350. }
  351. if (!mRectControl.empty())
  352. {
  353. node->createChild("rect_control", true)->setStringValue(mRectControl);
  354. }
  355. if (!mLabel.empty())
  356. {
  357. node->createChild("label", true)->setStringValue(mLabel);
  358. }
  359. ui_string_map_t::const_iterator i = mUIStrings.begin();
  360. ui_string_map_t::const_iterator end = mUIStrings.end();
  361. for ( ; i != end; ++i)
  362. {
  363. LLXMLNodePtr child_node = node->createChild("string", false);
  364. child_node->setStringValue(i->second);
  365. child_node->createChild("name", true)->setStringValue(i->first);
  366. }
  367. if (save_children)
  368. {
  369. LLView::child_list_const_reverse_iter_t rit;
  370. for (rit = getChildList()->rbegin(); rit != getChildList()->rend();
  371. ++rit)
  372. {
  373. LLView* childp = *rit;
  374. if (childp->getSaveToXML())
  375. {
  376. LLXMLNodePtr xml_node = childp->getXML();
  377. node->addChild(xml_node);
  378. }
  379. }
  380. }
  381. return node;
  382. }
  383. LLView* LLPanel::fromXML(LLXMLNodePtr nodep, LLView* parentp,
  384. LLUICtrlFactory* factoryp)
  385. {
  386. std::string name = LL_PANEL_TAG;
  387. nodep->getAttributeString("name", name);
  388. LLPanel* panelp = factoryp->createFactoryPanel(name);
  389. // Fall back on a default panel, if there was no special factory.
  390. if (!panelp)
  391. {
  392. LLRect rect;
  393. createRect(nodep, rect, parentp, LLRect());
  394. // Create a new panel without a border, by default
  395. panelp = new LLPanel(name, rect, false);
  396. panelp->initPanelXML(nodep, parentp, factoryp);
  397. // Preserve the panel width and height, but override the location.
  398. const LLRect& panelrect = panelp->getRect();
  399. S32 w = panelrect.getWidth();
  400. S32 h = panelrect.getHeight();
  401. rect.setLeftTopAndSize(rect.mLeft, rect.mTop, w, h);
  402. panelp->setRect(rect);
  403. }
  404. else
  405. {
  406. panelp->initPanelXML(nodep, parentp, factoryp);
  407. }
  408. return panelp;
  409. }
  410. bool LLPanel::initPanelXML(LLXMLNodePtr nodep, LLView* parentp,
  411. LLUICtrlFactory* factoryp)
  412. {
  413. std::string name = getName();
  414. nodep->getAttributeString("name", name);
  415. setName(name);
  416. setPanelParameters(nodep, parentp);
  417. initChildrenXML(nodep, factoryp);
  418. std::string xml_filename;
  419. nodep->getAttributeString("filename", xml_filename);
  420. bool did_post;
  421. if (!xml_filename.empty())
  422. {
  423. did_post = factoryp->buildPanel(this, xml_filename, NULL);
  424. LLRect new_rect = getRect();
  425. // Override rectangle with embedding parameters as provided
  426. createRect(nodep, new_rect, parentp);
  427. setOrigin(new_rect.mLeft, new_rect.mBottom);
  428. reshape(new_rect.getWidth(), new_rect.getHeight());
  429. // Optionally override follows flags from including nodes
  430. parseFollowsFlags(nodep);
  431. }
  432. else
  433. {
  434. did_post = false;
  435. }
  436. if (!did_post)
  437. {
  438. postBuild();
  439. did_post = true;
  440. }
  441. return did_post;
  442. }
  443. void LLPanel::initChildrenXML(LLXMLNodePtr nodep, LLUICtrlFactory* factoryp)
  444. {
  445. LLXMLNodePtr childp;
  446. for (childp = nodep->getFirstChild(); childp.notNull();
  447. childp = childp->getNextSibling())
  448. {
  449. // Look for string declarations for programmatic text
  450. if (childp->hasName("string"))
  451. {
  452. std::string string_name;
  453. childp->getAttributeString("name", string_name);
  454. if (!string_name.empty())
  455. {
  456. mUIStrings[string_name] = childp->getTextContents();
  457. }
  458. }
  459. else
  460. {
  461. factoryp->createWidget(this, childp);
  462. }
  463. }
  464. }
  465. void LLPanel::setPanelParameters(LLXMLNodePtr nodep, LLView* parentp)
  466. {
  467. // Rect, follows, tool_tip, enabled, visible attributes
  468. initFromXML(nodep, parentp);
  469. // Border attributes
  470. bool border = mBorder != NULL;
  471. nodep->getAttributeBool("border", border);
  472. if (border)
  473. {
  474. LLViewBorder::EBevel bevel_style = LLViewBorder::BEVEL_OUT;
  475. LLViewBorder::getBevelFromAttribute(nodep, bevel_style);
  476. LLViewBorder::EStyle border_style = LLViewBorder::STYLE_LINE;
  477. std::string border_string;
  478. nodep->getAttributeString("border_style", border_string);
  479. LLStringUtil::toLower(border_string);
  480. if (border_string == "texture")
  481. {
  482. border_style = LLViewBorder::STYLE_TEXTURE;
  483. }
  484. S32 border_thickness = LLPANEL_BORDER_WIDTH;
  485. nodep->getAttributeS32("border_thickness", border_thickness);
  486. addBorder(bevel_style, border_style, border_thickness);
  487. }
  488. else
  489. {
  490. removeBorder();
  491. }
  492. // Background attributes
  493. bool background_visible = mBgVisible;
  494. nodep->getAttributeBool("background_visible", background_visible);
  495. setBackgroundVisible(background_visible);
  496. bool background_opaque = mBgOpaque;
  497. nodep->getAttributeBool("background_opaque", background_opaque);
  498. setBackgroundOpaque(background_opaque);
  499. LLColor4 color;
  500. color = mBgColorOpaque;
  501. LLUICtrlFactory::getAttributeColor(nodep, "bg_opaque_color", color);
  502. setBackgroundColor(color);
  503. color = mBgColorAlpha;
  504. LLUICtrlFactory::getAttributeColor(nodep, "bg_alpha_color", color);
  505. setTransparentColor(color);
  506. // Label
  507. std::string label = getLabel();
  508. nodep->getAttributeString("label", label);
  509. setLabel(label);
  510. }
  511. LLFloater* LLPanel::getParentFloater() const
  512. {
  513. LLFloater* floaterp = NULL;
  514. LLView* parentp = getParent();
  515. while (parentp && !floaterp)
  516. {
  517. floaterp = parentp->asFloater();
  518. parentp = parentp->getParent();
  519. }
  520. return floaterp;
  521. }
  522. std::string LLPanel::getString(const std::string& name,
  523. const LLStringUtil::format_map_t& args) const
  524. {
  525. LL_DEBUGS("GetStringUI") << "Requested UI string: " << name << LL_ENDL;
  526. ui_string_map_t::const_iterator found_it = mUIStrings.find(name);
  527. if (found_it != mUIStrings.end())
  528. {
  529. // Make a copy as format works in place
  530. LLUIString formatted_string = LLUIString(found_it->second);
  531. formatted_string.setArgList(args);
  532. return formatted_string.getString();
  533. }
  534. llwarns << "Failed to find string " << name << " in panel " << getName()
  535. << llendl;
  536. return LLStringUtil::null;
  537. }
  538. std::string LLPanel::getString(const std::string& name) const
  539. {
  540. LL_DEBUGS("GetStringUI") << "Requested UI string: " << name << LL_ENDL;
  541. ui_string_map_t::const_iterator found_it = mUIStrings.find(name);
  542. if (found_it != mUIStrings.end())
  543. {
  544. return found_it->second;
  545. }
  546. llwarns << "Failed to find string " << name << " in panel " << getName()
  547. << llendl;
  548. return LLStringUtil::null;
  549. }
  550. void LLPanel::childSetVisible(const char* id, bool visible)
  551. {
  552. LLView* child = getChild<LLView>(id);
  553. if (child)
  554. {
  555. child->setVisible(visible);
  556. }
  557. }
  558. bool LLPanel::childIsVisible(const char* id) const
  559. {
  560. LLView* child = getChild<LLView>(id);
  561. if (child)
  562. {
  563. return (bool)child->getVisible();
  564. }
  565. return false;
  566. }
  567. void LLPanel::childSetEnabled(const char* id, bool enabled)
  568. {
  569. LLView* child = getChild<LLView>(id);
  570. if (child)
  571. {
  572. child->setEnabled(enabled);
  573. }
  574. }
  575. void LLPanel::childSetTentative(const char* id, bool tentative)
  576. {
  577. LLView* child = getChild<LLView>(id);
  578. if (child)
  579. {
  580. child->setTentative(tentative);
  581. }
  582. }
  583. bool LLPanel::childIsEnabled(const char* id) const
  584. {
  585. LLView* child = getChild<LLView>(id);
  586. if (child)
  587. {
  588. return (bool)child->getEnabled();
  589. }
  590. return false;
  591. }
  592. void LLPanel::childSetToolTip(const char* id, const std::string& msg)
  593. {
  594. LLView* child = getChild<LLView>(id);
  595. if (child)
  596. {
  597. child->setToolTip(msg);
  598. }
  599. }
  600. void LLPanel::childSetRect(const char* id, const LLRect& rect)
  601. {
  602. LLView* child = getChild<LLView>(id);
  603. if (child)
  604. {
  605. child->setRect(rect);
  606. }
  607. }
  608. bool LLPanel::childGetRect(const char* id, LLRect& rect) const
  609. {
  610. LLView* child = getChild<LLView>(id);
  611. if (child)
  612. {
  613. rect = child->getRect();
  614. return true;
  615. }
  616. return false;
  617. }
  618. void LLPanel::childSetFocus(const char* id, bool focus)
  619. {
  620. LLUICtrl* child = getChild<LLUICtrl>(id, true);
  621. if (child)
  622. {
  623. child->setFocus(focus);
  624. }
  625. }
  626. bool LLPanel::childHasFocus(const char* id)
  627. {
  628. LLUICtrl* child = getChild<LLUICtrl>(id, true);
  629. if (child)
  630. {
  631. return child->hasFocus();
  632. }
  633. childNotFound(id);
  634. return false;
  635. }
  636. void LLPanel::childSetFocusChangedCallback(const char* id,
  637. void (*cb)(LLFocusableElement*, void*),
  638. void* user_data)
  639. {
  640. LLUICtrl* child = getChild<LLUICtrl>(id, true);
  641. if (child)
  642. {
  643. child->setFocusChangedCallback(cb, user_data);
  644. }
  645. }
  646. void LLPanel::childSetCommitCallback(const char* id,
  647. void (*cb)(LLUICtrl*, void*),
  648. void *userdata)
  649. {
  650. LLUICtrl* child = getChild<LLUICtrl>(id, true);
  651. if (child)
  652. {
  653. child->setCommitCallback(cb);
  654. child->setCallbackUserData(userdata);
  655. }
  656. }
  657. void LLPanel::childSetDoubleClickCallback(const char* id,
  658. void (*cb)(void*), void* userdata)
  659. {
  660. LLUICtrl* child = getChild<LLUICtrl>(id, true);
  661. if (child)
  662. {
  663. child->setDoubleClickCallback(cb);
  664. if (userdata)
  665. {
  666. child->setCallbackUserData(userdata);
  667. }
  668. }
  669. }
  670. void LLPanel::childSetValidate(const char* id,
  671. bool (*cb)(LLUICtrl*, void*))
  672. {
  673. LLUICtrl* child = getChild<LLUICtrl>(id, true);
  674. if (child)
  675. {
  676. child->setValidateBeforeCommit(cb);
  677. }
  678. }
  679. void LLPanel::childSetUserData(const char* id, void* userdata)
  680. {
  681. LLUICtrl* child = getChild<LLUICtrl>(id, true);
  682. if (child)
  683. {
  684. child->setCallbackUserData(userdata);
  685. }
  686. }
  687. void LLPanel::childSetColor(const char* id, const LLColor4& color)
  688. {
  689. LLUICtrl* child = getChild<LLUICtrl>(id, true);
  690. if (child)
  691. {
  692. child->setColor(color);
  693. }
  694. }
  695. void LLPanel::childSetAlpha(const char* id, F32 alpha)
  696. {
  697. LLUICtrl* child = getChild<LLUICtrl>(id, true);
  698. if (child)
  699. {
  700. child->setAlpha(alpha);
  701. }
  702. }
  703. void LLPanel::childSetValue(const char* id, LLSD value)
  704. {
  705. LLView* child = getChild<LLView>(id, true);
  706. if (child)
  707. {
  708. child->setValue(value);
  709. }
  710. }
  711. LLSD LLPanel::childGetValue(const char* id) const
  712. {
  713. LLView* child = getChild<LLView>(id, true);
  714. if (child)
  715. {
  716. return child->getValue();
  717. }
  718. // Not found => return undefined
  719. return LLSD();
  720. }
  721. bool LLPanel::childSetTextArg(const char* id, const std::string& key,
  722. const std::string& text)
  723. {
  724. LLUICtrl* child = getChild<LLUICtrl>(id, true);
  725. if (child)
  726. {
  727. return child->setTextArg(key, text);
  728. }
  729. return false;
  730. }
  731. bool LLPanel::childSetLabelArg(const char* id, const std::string& key,
  732. const std::string& text)
  733. {
  734. LLView* child = getChild<LLView>(id);
  735. if (child)
  736. {
  737. return child->setLabelArg(key, text);
  738. }
  739. return false;
  740. }
  741. bool LLPanel::childSetToolTipArg(const char* id, const std::string& key,
  742. const std::string& text)
  743. {
  744. LLView* child = getChildView(id, true, false);
  745. if (child)
  746. {
  747. return child->setToolTipArg(key, text);
  748. }
  749. return false;
  750. }
  751. void LLPanel::childSetBadge(const char* id, Badge badge, bool visible)
  752. {
  753. LLIconCtrl* child = getChild<LLIconCtrl>(id);
  754. if (child)
  755. {
  756. child->setVisible(visible);
  757. switch (badge)
  758. {
  759. default:
  760. case BADGE_OK:
  761. child->setImage("badge_ok.j2c");
  762. break;
  763. case BADGE_NOTE:
  764. child->setImage("badge_note.j2c");
  765. break;
  766. case BADGE_WARN:
  767. child->setImage("badge_warn.j2c");
  768. break;
  769. case BADGE_ERROR:
  770. child->setImage("badge_error.j2c");
  771. }
  772. }
  773. }
  774. void LLPanel::childSetMinValue(const char* id, LLSD min_value)
  775. {
  776. LLUICtrl* child = getChild<LLUICtrl>(id, true);
  777. if (child)
  778. {
  779. child->setMinValue(min_value);
  780. }
  781. }
  782. void LLPanel::childSetMaxValue(const char* id, LLSD max_value)
  783. {
  784. LLUICtrl* child = getChild<LLUICtrl>(id, true);
  785. if (child)
  786. {
  787. child->setMaxValue(max_value);
  788. }
  789. }
  790. void LLPanel::childShowTab(const char* id, const std::string& tabname,
  791. bool visible)
  792. {
  793. LLTabContainer* child = getChild<LLTabContainer>(id);
  794. if (child)
  795. {
  796. child->selectTabByName(tabname);
  797. }
  798. }
  799. LLPanel *LLPanel::childGetVisibleTab(const char* id) const
  800. {
  801. LLTabContainer* child = getChild<LLTabContainer>(id);
  802. if (child)
  803. {
  804. return child->getCurrentPanel();
  805. }
  806. return NULL;
  807. }
  808. void LLPanel::childSetTabChangeCallback(const char* id,
  809. const std::string& tabname,
  810. void (*on_tab_clicked)(void*, bool),
  811. void *userdata,
  812. void (*on_precommit)(void*, bool))
  813. {
  814. LLTabContainer* child = getChild<LLTabContainer>(id);
  815. if (child)
  816. {
  817. LLPanel* panel = child->getPanelByName(tabname);
  818. if (panel)
  819. {
  820. child->setTabChangeCallback(panel, on_tab_clicked);
  821. child->setTabUserData(panel, userdata);
  822. if (on_precommit)
  823. {
  824. child->setTabPrecommitChangeCallback(panel, on_precommit);
  825. }
  826. }
  827. }
  828. }
  829. void LLPanel::childSetKeystrokeCallback(const char* id,
  830. void (*keystroke_callback)(LLLineEditor* caller, void* user_data),
  831. void* user_data)
  832. {
  833. LLLineEditor* child = getChild<LLLineEditor>(id);
  834. if (child)
  835. {
  836. child->setKeystrokeCallback(keystroke_callback);
  837. if (user_data)
  838. {
  839. child->setCallbackUserData(user_data);
  840. }
  841. }
  842. }
  843. void LLPanel::childSetPrevalidate(const char* id,
  844. bool (*func)(const LLWString &))
  845. {
  846. LLLineEditor* child = getChild<LLLineEditor>(id);
  847. if (child)
  848. {
  849. child->setPrevalidate(func);
  850. }
  851. }
  852. void LLPanel::childSetWrappedText(const char* id,
  853. const std::string& text, bool visible)
  854. {
  855. LLTextBox* child = getChild<LLTextBox>(id);
  856. if (child)
  857. {
  858. child->setVisible(visible);
  859. child->setWrappedText(text);
  860. }
  861. }
  862. void LLPanel::childSetAction(const char* id, void(*function)(void*),
  863. void* value)
  864. {
  865. LLButton* button = getChild<LLButton>(id);
  866. if (button)
  867. {
  868. button->setClickedCallback(function, value);
  869. }
  870. }
  871. void LLPanel::childSetActionTextbox(const char* id,
  872. void(*function)(void*), void* value)
  873. {
  874. LLTextBox* textbox = getChild<LLTextBox>(id);
  875. if (textbox)
  876. {
  877. textbox->setClickedCallback(function, value);
  878. }
  879. }
  880. void LLPanel::childSetControlName(const char* id, const char* control_name)
  881. {
  882. LLView* view = getChild<LLView>(id);
  883. if (view)
  884. {
  885. view->setControlName(control_name, NULL);
  886. }
  887. }
  888. //virtual
  889. LLView* LLPanel::getChildView(const char* name, bool recurse,
  890. bool create_if_missing) const
  891. {
  892. // Just get child, do not try to create a dummy one
  893. LLView* view = LLUICtrl::getChildView(name, recurse, false);
  894. if (!view && !recurse)
  895. {
  896. childNotFound(name);
  897. }
  898. if (!view && create_if_missing)
  899. {
  900. view = createDummyWidget<LLView>(name);
  901. }
  902. return view;
  903. }
  904. void LLPanel::childNotFound(const char* id) const
  905. {
  906. if (mExpectedMembers.find(id) == mExpectedMembers.end())
  907. {
  908. mNewExpectedMembers.emplace(id);
  909. }
  910. }
  911. void LLPanel::childDisplayNotFound()
  912. {
  913. if (mNewExpectedMembers.empty())
  914. {
  915. return;
  916. }
  917. std::string msg;
  918. expected_members_list_t::iterator itor;
  919. for (itor = mNewExpectedMembers.begin(); itor != mNewExpectedMembers.end();
  920. ++itor)
  921. {
  922. msg.append(*itor);
  923. msg.append("\n");
  924. mExpectedMembers.emplace(*itor);
  925. }
  926. mNewExpectedMembers.clear();
  927. LLSD args;
  928. args["CONTROLS"] = msg;
  929. gNotifications.add("FloaterNotFound", args);
  930. }
  931. void LLPanel::storeRectControl()
  932. {
  933. if (!mRectControl.empty())
  934. {
  935. LLUI::sConfigGroup->setRect(mRectControl.c_str(), getRect());
  936. }
  937. }
  938. //
  939. // LLLayoutStack
  940. //
  941. struct LLLayoutStack::LLEmbeddedPanel
  942. {
  943. LLEmbeddedPanel(LLPanel* panelp, eLayoutOrientation orientation,
  944. S32 min_width, S32 min_height,
  945. bool auto_resize, bool user_resize)
  946. : mPanel(panelp),
  947. mMinWidth(min_width),
  948. mMinHeight(min_height),
  949. mAutoResize(auto_resize),
  950. mUserResize(user_resize),
  951. mOrientation(orientation),
  952. mCollapsed(false),
  953. mCollapseAmt(0.f),
  954. mVisibleAmt(1.f) // default to fully visible
  955. {
  956. LLResizeBar::Side side;
  957. S32 min_dim;
  958. if (orientation == HORIZONTAL)
  959. {
  960. side = LLResizeBar::RIGHT;
  961. min_dim = mMinHeight;
  962. }
  963. else
  964. {
  965. side = LLResizeBar::BOTTOM;
  966. min_dim = mMinWidth;
  967. }
  968. mResizeBar = new LLResizeBar("resizer", mPanel, LLRect(), min_dim,
  969. S32_MAX, side);
  970. mResizeBar->setEnableSnapping(false);
  971. // Panels initialized as hidden should not start out partially visible
  972. if (!mPanel->getVisible())
  973. {
  974. mVisibleAmt = 0.f;
  975. }
  976. }
  977. ~LLEmbeddedPanel()
  978. {
  979. // Probably not necessary, but...
  980. delete mResizeBar;
  981. mResizeBar = NULL;
  982. }
  983. F32 getCollapseFactor()
  984. {
  985. F32 collapse_amt;
  986. if (mOrientation == HORIZONTAL)
  987. {
  988. collapse_amt =
  989. clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f,
  990. (F32)mMinWidth /
  991. (F32)llmax(1, mPanel->getRect().getWidth()));
  992. }
  993. else
  994. {
  995. collapse_amt =
  996. clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f,
  997. llmin(1.f, (F32)mMinHeight /
  998. (F32)llmax(1, mPanel->getRect().getHeight())));
  999. }
  1000. return mVisibleAmt * collapse_amt;
  1001. }
  1002. LLPanel* mPanel;
  1003. LLResizeBar* mResizeBar;
  1004. S32 mMinWidth;
  1005. S32 mMinHeight;
  1006. F32 mVisibleAmt;
  1007. F32 mCollapseAmt;
  1008. eLayoutOrientation mOrientation;
  1009. bool mAutoResize;
  1010. bool mUserResize;
  1011. bool mCollapsed;
  1012. };
  1013. static const std::string LL_LAYOUT_STACK_TAG = "layout_stack";
  1014. static LLRegisterWidget<LLLayoutStack> r15(LL_LAYOUT_STACK_TAG);
  1015. LLLayoutStack::LLLayoutStack(eLayoutOrientation orientation)
  1016. : mOrientation(orientation),
  1017. mMinWidth(0),
  1018. mMinHeight(0),
  1019. mPanelSpacing(RESIZE_BAR_HEIGHT)
  1020. {
  1021. }
  1022. //virtual
  1023. LLLayoutStack::~LLLayoutStack()
  1024. {
  1025. std::for_each(mPanels.begin(), mPanels.end(), DeletePointer());
  1026. mPanels.clear();
  1027. }
  1028. //virtual
  1029. void LLLayoutStack::draw()
  1030. {
  1031. updateLayout();
  1032. for (e_panel_list_t::iterator it = mPanels.begin(), end = mPanels.end();
  1033. it != end; ++it)
  1034. {
  1035. LLPanel* panelp = (*it)->mPanel;
  1036. if (!panelp) continue; // Paranoia
  1037. // Clip to layout rectangle, not bounding rectangle
  1038. LLRect clip_rect = panelp->getRect();
  1039. // Scale clipping rectangle by visible amount
  1040. if (mOrientation == HORIZONTAL)
  1041. {
  1042. clip_rect.mRight = clip_rect.mLeft +
  1043. ll_roundp((F32)clip_rect.getWidth() *
  1044. (*it)->getCollapseFactor());
  1045. }
  1046. else
  1047. {
  1048. clip_rect.mBottom = clip_rect.mTop -
  1049. ll_roundp((F32)clip_rect.getHeight() *
  1050. (*it)->getCollapseFactor());
  1051. }
  1052. LLLocalClipRect clip(clip_rect);
  1053. // Only force drawing invisible children if visible amount is non-zero
  1054. drawChild(panelp, 0, 0, !clip_rect.isEmpty());
  1055. }
  1056. }
  1057. void LLLayoutStack::deleteAllChildren()
  1058. {
  1059. mPanels.clear();
  1060. LLView::deleteAllChildren();
  1061. mMinWidth = mMinHeight = 0;
  1062. }
  1063. void LLLayoutStack::removeCtrl(LLUICtrl* ctrl)
  1064. {
  1065. LLEmbeddedPanel* embeddedp = findEmbeddedPanel((LLPanel*)ctrl);
  1066. if (embeddedp)
  1067. {
  1068. mPanels.erase(std::find(mPanels.begin(), mPanels.end(), embeddedp));
  1069. LLView::removeChild(ctrl);
  1070. }
  1071. else
  1072. {
  1073. LLView::removeCtrl(ctrl);
  1074. }
  1075. // Need to update resizebars
  1076. calcMinExtents();
  1077. }
  1078. //virtual
  1079. const std::string& LLLayoutStack::getTag() const
  1080. {
  1081. return LL_LAYOUT_STACK_TAG;
  1082. }
  1083. LLXMLNodePtr LLLayoutStack::getXML(bool save_children) const
  1084. {
  1085. LLXMLNodePtr nodep = LLView::getXML();
  1086. nodep->setName(LL_LAYOUT_STACK_TAG);
  1087. if (mOrientation == HORIZONTAL)
  1088. {
  1089. nodep->createChild("orientation", true)->setStringValue("horizontal");
  1090. }
  1091. else
  1092. {
  1093. nodep->createChild("orientation", true)->setStringValue("vertical");
  1094. }
  1095. if (save_children)
  1096. {
  1097. for (child_list_const_reverse_iter_t rit = getChildList()->rbegin(),
  1098. rend = getChildList()->rend();
  1099. rit != rend; ++rit)
  1100. {
  1101. LLView* childp = *rit;
  1102. if (childp->getSaveToXML())
  1103. {
  1104. LLXMLNodePtr xml_node = childp->getXML();
  1105. if (xml_node->hasName(LL_PANEL_TAG))
  1106. {
  1107. xml_node->setName(LL_LAYOUT_PANEL_TAG);
  1108. }
  1109. nodep->addChild(xml_node);
  1110. }
  1111. }
  1112. }
  1113. return nodep;
  1114. }
  1115. //static
  1116. LLView* LLLayoutStack::fromXML(LLXMLNodePtr nodep, LLView* parentp,
  1117. LLUICtrlFactory* factoryp)
  1118. {
  1119. std::string orientation_string("vertical");
  1120. nodep->getAttributeString("orientation", orientation_string);
  1121. eLayoutOrientation orientation = VERTICAL;
  1122. if (orientation_string == "horizontal")
  1123. {
  1124. orientation = HORIZONTAL;
  1125. }
  1126. else if (orientation_string == "vertical")
  1127. {
  1128. orientation = VERTICAL;
  1129. }
  1130. else
  1131. {
  1132. llwarns << "Unknown orientation " << orientation_string
  1133. << ", using vertical" << llendl;
  1134. }
  1135. LLLayoutStack* layout_stackp = new LLLayoutStack(orientation);
  1136. nodep->getAttributeS32("border_size", layout_stackp->mPanelSpacing);
  1137. // don't allow negative spacing values
  1138. layout_stackp->mPanelSpacing = llmax(layout_stackp->mPanelSpacing, 0);
  1139. std::string name = "stack";
  1140. nodep->getAttributeString("name", name);
  1141. layout_stackp->setName(name);
  1142. layout_stackp->initFromXML(nodep, parentp);
  1143. LLXMLNodePtr childp;
  1144. for (childp = nodep->getFirstChild(); childp.notNull();
  1145. childp = childp->getNextSibling())
  1146. {
  1147. S32 min_width = 0;
  1148. S32 min_height = 0;
  1149. bool auto_resize = true;
  1150. childp->getAttributeS32("min_width", min_width);
  1151. childp->getAttributeS32("min_height", min_height);
  1152. childp->getAttributeBool("auto_resize", auto_resize);
  1153. if (childp->hasName(LL_LAYOUT_PANEL_TAG))
  1154. {
  1155. bool user_resize = true;
  1156. childp->getAttributeBool("user_resize", user_resize);
  1157. LLPanel* panelp = (LLPanel*)LLPanel::fromXML(childp, layout_stackp,
  1158. factoryp);
  1159. if (panelp)
  1160. {
  1161. panelp->setFollowsNone();
  1162. layout_stackp->addPanel(panelp, min_width, min_height,
  1163. auto_resize, user_resize);
  1164. }
  1165. }
  1166. else
  1167. {
  1168. bool user_resize = false;
  1169. childp->getAttributeBool("user_resize", user_resize);
  1170. LLPanel* panelp = new LLPanel("auto_panel");
  1171. LLView* new_childp = factoryp->createWidget(panelp, childp);
  1172. if (new_childp)
  1173. {
  1174. // Put child in new embedded panel
  1175. layout_stackp->addPanel(panelp, min_width, min_height,
  1176. auto_resize, user_resize);
  1177. // Resize panel to contain widget and move widget to be
  1178. // contained in panel
  1179. panelp->setRect(new_childp->getRect());
  1180. new_childp->setOrigin(0, 0);
  1181. }
  1182. else
  1183. {
  1184. panelp->die();
  1185. }
  1186. }
  1187. }
  1188. layout_stackp->updateLayout();
  1189. return layout_stackp;
  1190. }
  1191. S32 LLLayoutStack::getDefaultHeight(S32 cur_height)
  1192. {
  1193. // If we are spanning our children (crude upward propagation of size) then
  1194. // do not enforce our size on our children
  1195. if (mOrientation == HORIZONTAL)
  1196. {
  1197. cur_height = llmax(mMinHeight, getRect().getHeight());
  1198. }
  1199. return cur_height;
  1200. }
  1201. S32 LLLayoutStack::getDefaultWidth(S32 cur_width)
  1202. {
  1203. // If we are spanning our children (crude upward propagation of size) then
  1204. // do not enforce our size on our children
  1205. if (mOrientation == VERTICAL)
  1206. {
  1207. cur_width = llmax(mMinWidth, getRect().getWidth());
  1208. }
  1209. return cur_width;
  1210. }
  1211. void LLLayoutStack::addPanel(LLPanel* panelp, S32 min_width, S32 min_height,
  1212. bool auto_resize, bool user_resize,
  1213. EAnimate animate, S32 index)
  1214. {
  1215. // Panel starts off invisible (collapsed)
  1216. if (animate == ANIMATE)
  1217. {
  1218. panelp->setVisible(false);
  1219. }
  1220. LLEmbeddedPanel* embeddedp = new LLEmbeddedPanel(panelp, mOrientation,
  1221. min_width, min_height,
  1222. auto_resize, user_resize);
  1223. mPanels.insert(mPanels.begin() + llclamp(index, 0, (S32)mPanels.size()),
  1224. embeddedp);
  1225. addChild(panelp);
  1226. addChild(embeddedp->mResizeBar);
  1227. // Bring all resize bars to the front so that they are clickable even over
  1228. // the panels with a bit of overlap
  1229. for (e_panel_list_t::iterator it = mPanels.begin(), end = mPanels.end();
  1230. it != end; ++it)
  1231. {
  1232. LLResizeBar* resize_barp = (*it)->mResizeBar;
  1233. sendChildToFront(resize_barp);
  1234. }
  1235. // Start expanding panel animation
  1236. if (animate == ANIMATE)
  1237. {
  1238. panelp->setVisible(true);
  1239. }
  1240. }
  1241. void LLLayoutStack::removePanel(LLPanel* panel)
  1242. {
  1243. removeChild(panel);
  1244. }
  1245. void LLLayoutStack::collapsePanel(LLPanel* panel, bool collapsed)
  1246. {
  1247. LLEmbeddedPanel* embeddedp = findEmbeddedPanel(panel);
  1248. if (embeddedp)
  1249. {
  1250. embeddedp->mCollapsed = collapsed;
  1251. }
  1252. }
  1253. void LLLayoutStack::updateLayout(bool force_resize)
  1254. {
  1255. calcMinExtents();
  1256. // Calculate current extents
  1257. S32 total_width = 0;
  1258. S32 total_height = 0;
  1259. constexpr F32 ANIM_OPEN_TIME = 0.02f;
  1260. F32 open_interpolant = LLCriticalDamp::getInterpolant(ANIM_OPEN_TIME);
  1261. constexpr F32 ANIM_CLOSE_TIME = 0.03f;
  1262. F32 close_interpolant = LLCriticalDamp::getInterpolant(ANIM_CLOSE_TIME);
  1263. for (e_panel_list_t::iterator it = mPanels.begin(), end = mPanels.end();
  1264. it != end; ++it)
  1265. {
  1266. LLPanel* panelp = (*it)->mPanel;
  1267. if (!panelp) continue; // Paranoia
  1268. F32& visible_amt = (*it)->mVisibleAmt;
  1269. if (panelp->getVisible())
  1270. {
  1271. visible_amt = lerp(visible_amt, 1.f, open_interpolant);
  1272. if (visible_amt > 0.99f)
  1273. {
  1274. visible_amt = 1.f;
  1275. }
  1276. }
  1277. else // Not visible
  1278. {
  1279. visible_amt = lerp(visible_amt, 0.f, close_interpolant);
  1280. if (visible_amt < 0.001f)
  1281. {
  1282. visible_amt = 0.f;
  1283. }
  1284. }
  1285. F32& collapse_amt = (*it)->mCollapseAmt;
  1286. if ((*it)->mCollapsed)
  1287. {
  1288. collapse_amt = lerp(collapse_amt, 1.f, close_interpolant);
  1289. }
  1290. else
  1291. {
  1292. collapse_amt = lerp(collapse_amt, 0.f, close_interpolant);
  1293. }
  1294. if (mOrientation == HORIZONTAL)
  1295. {
  1296. S32 min_width = (*it)->mMinWidth;
  1297. // Enforce minimize size constraint by default
  1298. if (panelp->getRect().getWidth() < min_width)
  1299. {
  1300. panelp->reshape(min_width, panelp->getRect().getHeight());
  1301. }
  1302. total_width += ll_roundp(panelp->getRect().getWidth() *
  1303. (*it)->getCollapseFactor());
  1304. // Want n-1 panel gaps for n panels
  1305. if (it != mPanels.begin())
  1306. {
  1307. total_width += mPanelSpacing;
  1308. }
  1309. }
  1310. else // VERTICAL
  1311. {
  1312. S32 min_height = (*it)->mMinHeight;
  1313. // Enforce minimize size constraint by default
  1314. if (panelp->getRect().getHeight() < min_height)
  1315. {
  1316. panelp->reshape(panelp->getRect().getWidth(),
  1317. min_height);
  1318. }
  1319. total_height += ll_roundp(panelp->getRect().getHeight() *
  1320. (*it)->getCollapseFactor());
  1321. if (it != mPanels.begin())
  1322. {
  1323. total_height += mPanelSpacing;
  1324. }
  1325. }
  1326. }
  1327. S32 num_resizable_panels = 0;
  1328. S32 shrink_headroom_available = 0;
  1329. S32 shrink_headroom_total = 0;
  1330. for (e_panel_list_t::iterator it = mPanels.begin(), end = mPanels.end();
  1331. it != end; ++it)
  1332. {
  1333. // Panels that are not fully visible do not count towards shrink
  1334. // headroom
  1335. if ((*it)->getCollapseFactor() < 1.f)
  1336. {
  1337. continue;
  1338. }
  1339. LLPanel* panelp = (*it)->mPanel;
  1340. if (!panelp) continue; // Paranoia
  1341. S32 min_width = (*it)->mMinWidth;
  1342. S32 min_height = (*it)->mMinHeight;
  1343. // If currently resizing a panel or the panel is flagged as not
  1344. // automatically resizing only track total available headroom, but do
  1345. // not use it for automatic resize logic
  1346. if ((*it)->mResizeBar->hasMouseCapture() ||
  1347. (!(*it)->mAutoResize && !force_resize))
  1348. {
  1349. if (mOrientation == HORIZONTAL)
  1350. {
  1351. shrink_headroom_total += panelp->getRect().getWidth() -
  1352. min_width;
  1353. }
  1354. else // VERTICAL
  1355. {
  1356. shrink_headroom_total += panelp->getRect().getHeight() -
  1357. min_height;
  1358. }
  1359. }
  1360. else
  1361. {
  1362. ++num_resizable_panels;
  1363. if (mOrientation == HORIZONTAL)
  1364. {
  1365. shrink_headroom_available += panelp->getRect().getWidth() -
  1366. min_width;
  1367. shrink_headroom_total += panelp->getRect().getWidth() -
  1368. min_width;
  1369. }
  1370. else // VERTICAL
  1371. {
  1372. shrink_headroom_available += panelp->getRect().getHeight() -
  1373. min_height;
  1374. shrink_headroom_total += panelp->getRect().getHeight() -
  1375. min_height;
  1376. }
  1377. }
  1378. }
  1379. // Calculate how many pixels need to be distributed among layout panels
  1380. // positive means panels need to grow, negative means shrink
  1381. S32 pixels_to_distribute;
  1382. if (mOrientation == HORIZONTAL)
  1383. {
  1384. pixels_to_distribute = getRect().getWidth() - total_width;
  1385. }
  1386. else // VERTICAL
  1387. {
  1388. pixels_to_distribute = getRect().getHeight() - total_height;
  1389. }
  1390. // Now we distribute the pixels...
  1391. S32 cur_x = 0;
  1392. S32 cur_y = getRect().getHeight();
  1393. for (e_panel_list_t::iterator it = mPanels.begin(), end = mPanels.end();
  1394. it != end; ++it)
  1395. {
  1396. LLPanel* panelp = (*it)->mPanel;
  1397. if (!panelp) continue; // Paranoia
  1398. S32 min_width = (*it)->mMinWidth;
  1399. S32 min_height = (*it)->mMinHeight;
  1400. S32 cur_width = panelp->getRect().getWidth();
  1401. S32 cur_height = panelp->getRect().getHeight();
  1402. S32 new_width = llmax(min_width, cur_width);
  1403. S32 new_height = llmax(min_height, cur_height);
  1404. S32 delta_size = 0;
  1405. // If panel can automatically resize (not animating, and resize flag
  1406. // set)...
  1407. if ((*it)->getCollapseFactor() == 1.f &&
  1408. (force_resize || (*it)->mAutoResize) &&
  1409. !(*it)->mResizeBar->hasMouseCapture())
  1410. {
  1411. if (mOrientation == HORIZONTAL)
  1412. {
  1413. if (pixels_to_distribute < 0) // If we are shrinking
  1414. {
  1415. // Shrink proportionally to amount over minimum so we can
  1416. // do this in one pass
  1417. delta_size = 0;
  1418. if (shrink_headroom_available > 0)
  1419. {
  1420. delta_size =
  1421. ll_roundp((F32)pixels_to_distribute *
  1422. ((F32)(cur_width - min_width) /
  1423. (F32)shrink_headroom_available));
  1424. }
  1425. shrink_headroom_available -= cur_width - min_width;
  1426. }
  1427. else // Grow all elements equally
  1428. {
  1429. delta_size = ll_roundp((F32)pixels_to_distribute /
  1430. (F32)num_resizable_panels);
  1431. --num_resizable_panels;
  1432. }
  1433. pixels_to_distribute -= delta_size;
  1434. new_width = llmax(min_width, cur_width + delta_size);
  1435. }
  1436. else
  1437. {
  1438. new_width = getDefaultWidth(new_width);
  1439. }
  1440. if (mOrientation == VERTICAL)
  1441. {
  1442. if (pixels_to_distribute < 0)
  1443. {
  1444. // Shrink proportionally to amount over minimum so we can
  1445. // do this in one pass
  1446. delta_size = shrink_headroom_available > 0 ?
  1447. ll_roundp((F32)pixels_to_distribute *
  1448. ((F32)(cur_height - min_height) /
  1449. (F32)shrink_headroom_available))
  1450. : 0;
  1451. shrink_headroom_available -= cur_height - min_height;
  1452. }
  1453. else
  1454. {
  1455. delta_size = ll_roundp((F32)pixels_to_distribute /
  1456. (F32)num_resizable_panels);
  1457. num_resizable_panels--;
  1458. }
  1459. pixels_to_distribute -= delta_size;
  1460. new_height = llmax(min_height, cur_height + delta_size);
  1461. }
  1462. else
  1463. {
  1464. new_height = getDefaultHeight(new_height);
  1465. }
  1466. }
  1467. else
  1468. {
  1469. if (mOrientation == HORIZONTAL)
  1470. {
  1471. new_height = getDefaultHeight(new_height);
  1472. }
  1473. else // VERTICAL
  1474. {
  1475. new_width = getDefaultWidth(new_width);
  1476. }
  1477. }
  1478. // Adjust running headroom count based on new sizes
  1479. shrink_headroom_total += delta_size;
  1480. panelp->reshape(new_width, new_height);
  1481. panelp->setOrigin(cur_x, cur_y - new_height);
  1482. LLRect panel_rect = panelp->getRect();
  1483. LLRect resize_bar_rect = panel_rect;
  1484. if (mOrientation == HORIZONTAL)
  1485. {
  1486. resize_bar_rect.mLeft = panel_rect.mRight - RESIZE_BAR_OVERLAP;
  1487. resize_bar_rect.mRight = panel_rect.mRight + mPanelSpacing +
  1488. RESIZE_BAR_OVERLAP;
  1489. }
  1490. else
  1491. {
  1492. resize_bar_rect.mTop = panel_rect.mBottom + RESIZE_BAR_OVERLAP;
  1493. resize_bar_rect.mBottom = panel_rect.mBottom - mPanelSpacing -
  1494. RESIZE_BAR_OVERLAP;
  1495. }
  1496. (*it)->mResizeBar->setRect(resize_bar_rect);
  1497. if (mOrientation == HORIZONTAL)
  1498. {
  1499. cur_x += ll_roundp(new_width * (*it)->getCollapseFactor()) +
  1500. mPanelSpacing;
  1501. }
  1502. else // VERTICAL
  1503. {
  1504. cur_y -= ll_roundp(new_height * (*it)->getCollapseFactor()) +
  1505. mPanelSpacing;
  1506. }
  1507. }
  1508. // Update resize bars with new limits
  1509. LLResizeBar* last_resize_bar = NULL;
  1510. for (e_panel_list_t::iterator it = mPanels.begin(), end = mPanels.end();
  1511. it != end; ++it)
  1512. {
  1513. LLPanel* panelp = (*it)->mPanel;
  1514. if (!panelp) continue; // Paranoia
  1515. if (mOrientation == HORIZONTAL)
  1516. {
  1517. S32 min_width = (*it)->mMinWidth;
  1518. (*it)->mResizeBar->setResizeLimits(min_width,
  1519. min_width +
  1520. shrink_headroom_total);
  1521. }
  1522. else // VERTICAL
  1523. {
  1524. S32 min_height = (*it)->mMinHeight;
  1525. (*it)->mResizeBar->setResizeLimits(min_height,
  1526. min_height +
  1527. shrink_headroom_total);
  1528. }
  1529. // Toggle resize bars based on panel visibility, resizability, etc
  1530. bool resize_bar_enabled = panelp->getVisible() && (*it)->mUserResize;
  1531. (*it)->mResizeBar->setVisible(resize_bar_enabled);
  1532. if (resize_bar_enabled)
  1533. {
  1534. last_resize_bar = (*it)->mResizeBar;
  1535. }
  1536. }
  1537. // Hide last resize bar as there is nothing past it; resize bars need to be
  1538. // in between two resizable panels.
  1539. if (last_resize_bar)
  1540. {
  1541. last_resize_bar->setVisible(false);
  1542. }
  1543. // Not enough room to fit existing contents
  1544. if (!force_resize &&
  1545. // layout did not complete by reaching target position
  1546. ((mOrientation == VERTICAL && cur_y != -mPanelSpacing) ||
  1547. (mOrientation == HORIZONTAL &&
  1548. cur_x != getRect().getWidth() + mPanelSpacing)))
  1549. {
  1550. // Do another layout pass with all stacked elements contributing even
  1551. // those that do not usually resize
  1552. updateLayout(true);
  1553. }
  1554. }
  1555. LLLayoutStack::LLEmbeddedPanel* LLLayoutStack::findEmbeddedPanel(LLPanel* panelp) const
  1556. {
  1557. if (!panelp) return NULL;
  1558. for (e_panel_list_t::const_iterator it = mPanels.begin(),
  1559. end = mPanels.end();
  1560. it != end; ++it)
  1561. {
  1562. if ((*it)->mPanel == panelp)
  1563. {
  1564. return *it;
  1565. }
  1566. }
  1567. return NULL;
  1568. }
  1569. void LLLayoutStack::calcMinExtents()
  1570. {
  1571. mMinWidth = mMinHeight = 0;
  1572. for (e_panel_list_t::iterator it = mPanels.begin(), end = mPanels.end();
  1573. it != end; ++it)
  1574. {
  1575. if (mOrientation == HORIZONTAL)
  1576. {
  1577. mMinHeight = llmax(mMinHeight, (*it)->mMinHeight);
  1578. mMinWidth += (*it)->mMinWidth;
  1579. if (it != mPanels.begin())
  1580. {
  1581. mMinWidth += mPanelSpacing;
  1582. }
  1583. }
  1584. else // VERTICAL
  1585. {
  1586. mMinWidth = llmax(mMinWidth, (*it)->mMinWidth);
  1587. mMinHeight += (*it)->mMinHeight;
  1588. if (it != mPanels.begin())
  1589. {
  1590. mMinHeight += mPanelSpacing;
  1591. }
  1592. }
  1593. }
  1594. }