llaccordionctrltab.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:16k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file LLAccordionCtrlTab.cpp
  3.  * @brief Collapsible control implementation
  4.  *
  5.  * $LicenseInfo:firstyear=2009&license=viewergpl$
  6.  * 
  7.  * Copyright (c) 2009-2010, 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. #include "linden_common.h"
  33. #include "lluictrl.h"
  34. #include "llaccordionctrltab.h"
  35. #include "lltextbox.h"
  36. static const std::string DD_BUTTON_NAME = "dd_button";
  37. static const std::string DD_TEXTBOX_NAME = "dd_textbox";
  38. static const std::string DD_HEADER_NAME = "dd_header";
  39. static const S32 HEADER_HEIGHT = 20;
  40. static const S32 HEADER_IMAGE_LEFT_OFFSET = 5;
  41. static const S32 HEADER_TEXT_LEFT_OFFSET = 30;
  42. static const F32 AUTO_OPEN_TIME = 1.f;
  43. static LLDefaultChildRegistry::Register<LLAccordionCtrlTab> t1("accordion_tab");
  44. class LLAccordionCtrlTab::LLAccordionCtrlTabHeader : public LLUICtrl
  45. {
  46. public:
  47. friend class LLUICtrlFactory;
  48. struct Params : public LLInitParam::Block<Params, LLAccordionCtrlTab::Params>
  49. {
  50. Params();
  51. };
  52. LLAccordionCtrlTabHeader(const LLAccordionCtrlTabHeader::Params& p);
  53. virtual ~LLAccordionCtrlTabHeader();
  54. virtual void draw();
  55. virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
  56. virtual BOOL postBuild();
  57. void setTitle(const std::string& title);
  58. virtual void onMouseEnter(S32 x, S32 y, MASK mask);
  59. virtual void onMouseLeave(S32 x, S32 y, MASK mask);
  60. virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent);
  61. virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
  62.    EDragAndDropType cargo_type,
  63.    void* cargo_data,
  64.    EAcceptance* accept,
  65.    std::string& tooltip_msg);
  66. private:
  67. LLTextBox* mHeaderTextbox;
  68. // Overlay images (arrows)
  69. LLPointer<LLUIImage> mImageCollapsed;
  70. LLPointer<LLUIImage> mImageExpanded;
  71. LLPointer<LLUIImage> mImageCollapsedPressed;
  72. LLPointer<LLUIImage> mImageExpandedPressed;
  73. // Background images
  74. LLPointer<LLUIImage> mImageHeader;
  75. LLPointer<LLUIImage> mImageHeaderOver;
  76. LLPointer<LLUIImage> mImageHeaderPressed;
  77. LLPointer<LLUIImage> mImageHeaderFocused;
  78. LLUIColor mHeaderBGColor;
  79. bool mNeedsHighlight;
  80. LLFrameTimer mAutoOpenTimer;
  81. };
  82. LLAccordionCtrlTab::LLAccordionCtrlTabHeader::Params::Params()
  83. {
  84. }
  85. LLAccordionCtrlTab::LLAccordionCtrlTabHeader::LLAccordionCtrlTabHeader(
  86. const LLAccordionCtrlTabHeader::Params& p)
  87. : LLUICtrl(p)
  88. , mHeaderBGColor(p.header_bg_color())
  89. ,mNeedsHighlight(false),
  90. mImageCollapsed(p.header_collapse_img),
  91. mImageCollapsedPressed(p.header_collapse_img_pressed),
  92. mImageExpanded(p.header_expand_img),
  93. mImageExpandedPressed(p.header_expand_img_pressed),
  94. mImageHeader(p.header_image),
  95. mImageHeaderOver(p.header_image_over),
  96. mImageHeaderPressed(p.header_image_pressed),
  97. mImageHeaderFocused(p.header_image_focused)
  98. {
  99. LLTextBox::Params textboxParams;
  100. textboxParams.name(DD_TEXTBOX_NAME);
  101. textboxParams.initial_value(p.title());
  102. textboxParams.text_color(p.header_text_color());
  103. textboxParams.follows.flags(FOLLOWS_NONE);
  104. textboxParams.font( p.font() );
  105. textboxParams.font_shadow(LLFontGL::NO_SHADOW);
  106. textboxParams.use_ellipses = true;
  107. textboxParams.bg_visible = false;
  108. textboxParams.mouse_opaque = false;
  109. mHeaderTextbox = LLUICtrlFactory::create<LLTextBox>(textboxParams);
  110. addChild(mHeaderTextbox);
  111. }
  112. LLAccordionCtrlTab::LLAccordionCtrlTabHeader::~LLAccordionCtrlTabHeader()
  113. {
  114. }
  115. BOOL LLAccordionCtrlTab::LLAccordionCtrlTabHeader::postBuild()
  116. {
  117. return TRUE;
  118. }
  119. void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::setTitle(const std::string& title)
  120. {
  121. if(mHeaderTextbox)
  122. mHeaderTextbox->setText(title);
  123. }
  124. void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::draw()
  125. {
  126. S32 width = getRect().getWidth();
  127. S32 height = getRect().getHeight();
  128. gl_rect_2d(0,0,width - 1 ,height - 1,mHeaderBGColor.get(),true);
  129. LLAccordionCtrlTab* parent = dynamic_cast<LLAccordionCtrlTab*>(getParent());
  130. bool collapsible = (parent && parent->getCollapsible());
  131. bool expanded = (parent && parent->getDisplayChildren());
  132. // Handle overlay images, if needed
  133. // Only show green "focus" background image if the accordion is open,
  134. // because the user's mental model of focus is that it goes away after
  135. // the accordion is closed.
  136. if (getParent()->hasFocus()
  137. /*&& !(collapsible && !expanded)*/ // WHY??
  138. )
  139. {
  140. mImageHeaderFocused->draw(0,0,width,height);
  141. }
  142. else
  143. {
  144. mImageHeader->draw(0,0,width,height);
  145. }
  146. if(mNeedsHighlight)
  147. {
  148. mImageHeaderOver->draw(0,0,width,height);
  149. }
  150. if(collapsible)
  151. {
  152. LLPointer<LLUIImage> overlay_image;
  153. if(expanded)
  154. {
  155. overlay_image = mImageExpanded;
  156. }
  157. else
  158. {
  159. overlay_image = mImageCollapsed;
  160. }
  161. overlay_image->draw(HEADER_IMAGE_LEFT_OFFSET,
  162. (height - overlay_image->getHeight()) / 2);
  163. }
  164. LLUICtrl::draw();
  165. }
  166. void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::reshape(S32 width, S32 height, BOOL called_from_parent /* = TRUE */)
  167. {
  168. S32 header_height = mHeaderTextbox->getTextPixelHeight();
  169. LLRect textboxRect(HEADER_TEXT_LEFT_OFFSET,(height+header_height)/2 ,width,(height-header_height)/2);
  170. mHeaderTextbox->reshape(textboxRect.getWidth(), textboxRect.getHeight());
  171. mHeaderTextbox->setRect(textboxRect);
  172. }
  173. void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::onMouseEnter(S32 x, S32 y, MASK mask)
  174. {
  175. LLUICtrl::onMouseEnter(x, y, mask);
  176. mNeedsHighlight = true;
  177. }
  178. void LLAccordionCtrlTab::LLAccordionCtrlTabHeader::onMouseLeave(S32 x, S32 y, MASK mask)
  179. {
  180. LLUICtrl::onMouseLeave(x, y, mask);
  181. mNeedsHighlight = false;
  182. mAutoOpenTimer.stop();
  183. }
  184. BOOL LLAccordionCtrlTab::LLAccordionCtrlTabHeader::handleKey(KEY key, MASK mask, BOOL called_from_parent)
  185. {
  186. if ( ( key == KEY_LEFT || key == KEY_RIGHT) && mask == MASK_NONE)
  187. {
  188. return getParent()->handleKey(key, mask, called_from_parent);
  189. }
  190. return LLUICtrl::handleKey(key, mask, called_from_parent);
  191. }
  192. BOOL LLAccordionCtrlTab::LLAccordionCtrlTabHeader::handleDragAndDrop(S32 x, S32 y, MASK mask,
  193.  BOOL drop,
  194.  EDragAndDropType cargo_type,
  195.  void* cargo_data,
  196.  EAcceptance* accept,
  197.  std::string& tooltip_msg)
  198. {
  199. LLAccordionCtrlTab* parent = dynamic_cast<LLAccordionCtrlTab*>(getParent());
  200. if ( parent && !parent->getDisplayChildren() && parent->getCollapsible() && parent->canOpenClose() )
  201. {
  202. if (mAutoOpenTimer.getStarted())
  203. {
  204. if (mAutoOpenTimer.getElapsedTimeF32() > AUTO_OPEN_TIME)
  205. {
  206. parent->changeOpenClose(false);
  207. mAutoOpenTimer.stop();
  208. return TRUE;
  209. }
  210. }
  211. else
  212. mAutoOpenTimer.start();
  213. }
  214. return LLUICtrl::handleDragAndDrop(x, y, mask, drop, cargo_type,
  215.    cargo_data, accept, tooltip_msg);
  216. }
  217. LLAccordionCtrlTab::Params::Params()
  218. : title("title")
  219. ,display_children("expanded", true)
  220. ,header_height("header_height", HEADER_HEIGHT),
  221. min_width("min_width", 0),
  222. min_height("min_height", 0)
  223. ,collapsible("collapsible", true)
  224. ,header_bg_color("header_bg_color")
  225. ,dropdown_bg_color("dropdown_bg_color")
  226. ,header_visible("header_visible",true)
  227. ,padding_left("padding_left",2)
  228. ,padding_right("padding_right",2)
  229. ,padding_top("padding_top",2)
  230. ,padding_bottom("padding_bottom",2)
  231. ,header_expand_img("header_expand_img")
  232. ,header_expand_img_pressed("header_expand_img_pressed")
  233. ,header_collapse_img("header_collapse_img")
  234. ,header_collapse_img_pressed("header_collapse_img_pressed")
  235. ,header_image("header_image")
  236. ,header_image_over("header_image_over")
  237. ,header_image_pressed("header_image_pressed")
  238. ,header_image_focused("header_image_focused")
  239. ,header_text_color("header_text_color")
  240. {
  241. mouse_opaque(false);
  242. }
  243. LLAccordionCtrlTab::LLAccordionCtrlTab(const LLAccordionCtrlTab::Params&p)
  244. : LLUICtrl(p)
  245. ,mDisplayChildren(p.display_children)
  246. ,mCollapsible(p.collapsible)
  247. ,mExpandedHeight(0)
  248. ,mDropdownBGColor(p.dropdown_bg_color())
  249. ,mHeaderVisible(p.header_visible)
  250. ,mPaddingLeft(p.padding_left)
  251. ,mPaddingRight(p.padding_right)
  252. ,mPaddingTop(p.padding_top)
  253. ,mPaddingBottom(p.padding_bottom)
  254. ,mCanOpenClose(true)
  255. {
  256. mStoredOpenCloseState = false;
  257. mWasStateStored = false;
  258. mDropdownBGColor = LLColor4::white;
  259. LLAccordionCtrlTabHeader::Params headerParams;
  260. headerParams.name(DD_HEADER_NAME);
  261. headerParams.title(p.title);
  262. mHeader = LLUICtrlFactory::create<LLAccordionCtrlTabHeader>(headerParams);
  263. addChild(mHeader, 1);
  264. reshape(100, 200,FALSE);
  265. }
  266. LLAccordionCtrlTab::~LLAccordionCtrlTab()
  267. {
  268. }
  269. void LLAccordionCtrlTab::setDisplayChildren(bool display)
  270. {
  271. mDisplayChildren = display;
  272. LLRect rect = getRect();
  273. rect.mBottom = rect.mTop - (getDisplayChildren() ? 
  274. mExpandedHeight : HEADER_HEIGHT);
  275. setRect(rect);
  276. for(child_list_const_iter_t it = getChildList()->begin();
  277. getChildList()->end() != it; ++it)
  278. {
  279. LLView* child = *it;
  280. if(DD_HEADER_NAME == child->getName())
  281. continue;
  282. child->setVisible(getDisplayChildren());
  283. }
  284. }
  285. void LLAccordionCtrlTab::reshape(S32 width, S32 height, BOOL called_from_parent /* = TRUE */)
  286. {
  287. LLRect headerRect;
  288. LLUICtrl::reshape(width, height, TRUE);
  289. headerRect.setLeftTopAndSize(
  290. 0,height,width,HEADER_HEIGHT);
  291. mHeader->setRect(headerRect);
  292. mHeader->reshape(headerRect.getWidth(), headerRect.getHeight());
  293. for(child_list_const_iter_t it = getChildList()->begin(); 
  294. getChildList()->end() != it; ++it)
  295. {
  296. LLView* child = *it;
  297. if(DD_HEADER_NAME == child->getName())
  298. continue;
  299. if(!child->getVisible())
  300. continue;
  301. LLRect childRect = child->getRect();
  302. S32 childWidth = width - getPaddingLeft() - getPaddingRight();
  303. S32 childHeight = height - getHeaderHeight() - getPaddingTop() - getPaddingBottom();
  304. child->reshape(childWidth,childHeight);
  305. childRect.setLeftTopAndSize(
  306. getPaddingLeft(),
  307. childHeight + getPaddingBottom(),
  308. childWidth, 
  309. childHeight);
  310. child->setRect(childRect);
  311. break;//suppose that there is only one panel
  312. }
  313. }
  314. void LLAccordionCtrlTab::changeOpenClose(bool is_open)
  315. {
  316. if(is_open)
  317. mExpandedHeight = getRect().getHeight();
  318. setDisplayChildren(!is_open);
  319. reshape(getRect().getWidth(), getRect().getHeight(), FALSE);
  320. if (mCommitSignal)
  321. {
  322. (*mCommitSignal)(this, getDisplayChildren());
  323. }
  324. }
  325. BOOL LLAccordionCtrlTab::handleMouseDown(S32 x, S32 y, MASK mask)
  326. {
  327. if(mCollapsible && mHeaderVisible && mCanOpenClose)
  328. {
  329. if(y >= (getRect().getHeight() - HEADER_HEIGHT) )
  330. {
  331. LLAccordionCtrlTabHeader* header = getChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
  332. header->setFocus(true);
  333. changeOpenClose(getDisplayChildren());
  334. //reset stored state
  335. mWasStateStored = false;
  336. return TRUE;
  337. }
  338. }
  339. return LLUICtrl::handleMouseDown(x,y,mask);
  340. }
  341. BOOL LLAccordionCtrlTab::handleMouseUp(S32 x, S32 y, MASK mask)
  342. {
  343. return LLUICtrl::handleMouseUp(x,y,mask);
  344. }
  345. boost::signals2::connection LLAccordionCtrlTab::setDropDownStateChangedCallback(commit_callback_t cb)
  346. {
  347. return setCommitCallback(cb);
  348. }
  349. bool LLAccordionCtrlTab::addChild(LLView* child, S32 tab_group)
  350. {
  351. if(DD_HEADER_NAME != child->getName())
  352. {
  353. reshape(child->getRect().getWidth() , child->getRect().getHeight() + HEADER_HEIGHT );
  354. mExpandedHeight = getRect().getHeight();
  355. }
  356. bool res = LLUICtrl::addChild(child, tab_group);
  357. if(DD_HEADER_NAME != child->getName())
  358. {
  359. if(!mCollapsible)
  360. setDisplayChildren(true);
  361. else
  362. setDisplayChildren(getDisplayChildren());
  363. }
  364. return res;
  365. }
  366. void LLAccordionCtrlTab::setAccordionView(LLView* panel)
  367. {
  368. addChild(panel,0);
  369. }
  370. LLView* LLAccordionCtrlTab::getAccordionView()
  371. {
  372. for(child_list_const_iter_t it = getChildList()->begin(); 
  373. getChildList()->end() != it; ++it)
  374. {
  375. LLView* child = *it;
  376. if(DD_HEADER_NAME == child->getName())
  377. continue;
  378. if(!child->getVisible())
  379. continue;
  380. return child;
  381. }
  382. return NULL;
  383. }
  384. S32 LLAccordionCtrlTab::getHeaderHeight()
  385. {
  386. return mHeaderVisible?HEADER_HEIGHT:0; 
  387. }
  388. void LLAccordionCtrlTab::setHeaderVisible(bool value) 
  389. {
  390. if(mHeaderVisible == value)
  391. return;
  392. mHeaderVisible = value;
  393. if(mHeader)
  394. mHeader->setVisible(value);
  395. reshape(getRect().getWidth(), getRect().getHeight(), FALSE);
  396. };
  397. //vurtual
  398. BOOL LLAccordionCtrlTab::postBuild()
  399. {
  400. mHeader->setVisible(mHeaderVisible);
  401. return LLUICtrl::postBuild();
  402. }
  403. bool LLAccordionCtrlTab::notifyChildren (const LLSD& info)
  404. {
  405. if(info.has("action"))
  406. {
  407. std::string str_action = info["action"];
  408. if(str_action == "store_state")
  409. {
  410. storeOpenCloseState();
  411. return true;
  412. }
  413. if(str_action == "restore_state")
  414. {
  415. restoreOpenCloseState();
  416. return true;
  417. }
  418. }
  419. return LLUICtrl::notifyChildren(info);
  420. }
  421. S32 LLAccordionCtrlTab::notifyParent(const LLSD& info)
  422. {
  423. if(info.has("action"))
  424. {
  425. std::string str_action = info["action"];
  426. if(str_action == "size_changes")
  427. {
  428. //
  429. S32 height = info["height"];
  430. height = llmax(height,10) + HEADER_HEIGHT + getPaddingTop() + getPaddingBottom();
  431. mExpandedHeight = height;
  432. if(isExpanded())
  433. {
  434. LLRect panel_rect = getRect();
  435. panel_rect.setLeftTopAndSize( panel_rect.mLeft, panel_rect.mTop, panel_rect.getWidth(), height);
  436. reshape(getRect().getWidth(),height);
  437. setRect(panel_rect);
  438. }
  439. //LLAccordionCtrl should rearrange accodion tab if one of accordion change its size
  440. getParent()->notifyParent(info);
  441. return 1;
  442. }
  443. else if(str_action == "select_prev") 
  444. {
  445. showAndFocusHeader();
  446. return 1;
  447. }
  448. }
  449. return LLUICtrl::notifyParent(info);
  450. }
  451. S32 LLAccordionCtrlTab::notify(const LLSD& info)
  452. {
  453. if(info.has("action"))
  454. {
  455. std::string str_action = info["action"];
  456. if(str_action == "select_first")
  457. {
  458. showAndFocusHeader();
  459. return 1;
  460. }
  461. else if( str_action == "select_last" )
  462. {
  463. if(getDisplayChildren() == false)
  464. {
  465. showAndFocusHeader();
  466. }
  467. else
  468. {
  469. LLView* view = getAccordionView();
  470. if(view)
  471. view->notify(LLSD().with("action","select_last"));
  472. }
  473. }
  474. }
  475. return 0;
  476. }
  477. BOOL LLAccordionCtrlTab::handleKey(KEY key, MASK mask, BOOL called_from_parent)
  478. {
  479. LLAccordionCtrlTabHeader* header = getChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
  480. if( !header->hasFocus() )
  481. return LLUICtrl::handleKey(key, mask, called_from_parent);
  482. if ( (key == KEY_ADD || key == KEY_RIGHT)&& mask == MASK_NONE)
  483. {
  484. if(getDisplayChildren() == false)
  485. {
  486. changeOpenClose(getDisplayChildren());
  487. return TRUE;
  488. }
  489. }
  490. if ( (key == KEY_SUBTRACT || key == KEY_LEFT)&& mask == MASK_NONE)
  491. {
  492. if(getDisplayChildren() == true)
  493. {
  494. changeOpenClose(getDisplayChildren());
  495. return TRUE;
  496. }
  497. }
  498. if ( key == KEY_DOWN && mask == MASK_NONE)
  499. {
  500. //if collapsed go to the next accordion
  501. if(getDisplayChildren() == false)
  502. //we processing notifyParent so let call parent directly
  503. getParent()->notifyParent(LLSD().with("action","select_next"));
  504. else
  505. {
  506. getAccordionView()->notify(LLSD().with("action","select_first"));
  507. }
  508. return TRUE;
  509. }
  510. if ( key == KEY_UP && mask == MASK_NONE)
  511. {
  512. //go to the previous accordion
  513. //we processing notifyParent so let call parent directly
  514. getParent()->notifyParent(LLSD().with("action","select_prev"));
  515. return TRUE;
  516. }
  517. return LLUICtrl::handleKey(key, mask, called_from_parent);
  518. }
  519. void LLAccordionCtrlTab::showAndFocusHeader()
  520. {
  521. LLAccordionCtrlTabHeader* header = getChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
  522. header->setFocus(true);
  523. LLRect screen_rc;
  524. LLRect selected_rc = header->getRect();
  525. localRectToScreen(selected_rc, &screen_rc);
  526. notifyParent(LLSD().with("scrollToShowRect",screen_rc.getValue()));
  527. }
  528. void    LLAccordionCtrlTab::storeOpenCloseState()
  529. {
  530. if(mWasStateStored)
  531. return;
  532. mStoredOpenCloseState = getDisplayChildren();
  533. mWasStateStored = true;
  534. }
  535. void   LLAccordionCtrlTab::restoreOpenCloseState()
  536. {
  537. if(!mWasStateStored)
  538. return;
  539. if(getDisplayChildren() != mStoredOpenCloseState)
  540. {
  541. changeOpenClose(getDisplayChildren());
  542. }
  543. mWasStateStored = false;
  544. }