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

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file llexpandabletextbox.cpp
  3.  * @brief LLExpandableTextBox and related class implementations
  4.  *
  5.  * $LicenseInfo:firstyear=2004&license=viewergpl$
  6.  * 
  7.  * Copyright (c) 2004-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 "llviewerprecompiledheaders.h"
  33. #include "llexpandabletextbox.h"
  34. #include "llscrollcontainer.h"
  35. #include "llwindow.h"
  36. static LLDefaultChildRegistry::Register<LLExpandableTextBox> t1("expandable_text");
  37. class LLExpanderSegment : public LLTextSegment
  38. {
  39. public:
  40. LLExpanderSegment(const LLStyleSP& style, S32 start, S32 end, const std::string& more_text, LLTextBase& editor )
  41. : LLTextSegment(start, end),
  42. mEditor(editor),
  43. mStyle(style),
  44. mExpanderLabel(more_text)
  45. {}
  46. /*virtual*/ bool getDimensions(S32 first_char, S32 num_chars, S32& width, S32& height) const 
  47. {
  48. // more label always spans width of text box
  49. if (num_chars == 0)
  50. {
  51. width = 0; 
  52. height = 0;
  53. }
  54. else
  55. {
  56. width = mEditor.getDocumentView()->getRect().getWidth() - mEditor.getHPad(); 
  57. height = llceil(mStyle->getFont()->getLineHeight());
  58. }
  59. return true;
  60. }
  61. /*virtual*/ S32 getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const 
  62. return start_offset;
  63. }
  64. /*virtual*/ S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const 
  65. // require full line to ourselves
  66. if (line_offset == 0) 
  67. {
  68. // print all our text
  69. return getEnd() - getStart(); 
  70. }
  71. else
  72. {
  73. // wait for next line
  74. return 0;
  75. }
  76. }
  77. /*virtual*/ F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect)
  78. {
  79. F32 right_x;
  80. mStyle->getFont()->renderUTF8(mExpanderLabel, start, 
  81. draw_rect.mRight, draw_rect.mTop, 
  82. mStyle->getColor(), 
  83. LLFontGL::RIGHT, LLFontGL::TOP, 
  84. 0, 
  85. mStyle->getShadowType(), 
  86. end - start, draw_rect.getWidth(), 
  87. &right_x, 
  88. mEditor.getUseEllipses());
  89. return right_x;
  90. }
  91. /*virtual*/ bool canEdit() const { return false; }
  92. // eat handleMouseDown event so we get the mouseup event
  93. /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask) { return TRUE; }
  94. /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask) { mEditor.onCommit(); return TRUE; }
  95. /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask) 
  96. {
  97. LLUI::getWindow()->setCursor(UI_CURSOR_HAND);
  98. return TRUE; 
  99. }
  100. private:
  101. LLTextBase& mEditor;
  102. LLStyleSP mStyle;
  103. std::string mExpanderLabel;
  104. };
  105. LLExpandableTextBox::LLTextBoxEx::Params::Params()
  106. : more_label("more_label")
  107. {
  108. }
  109. LLExpandableTextBox::LLTextBoxEx::LLTextBoxEx(const Params& p)
  110. : LLTextEditor(p),
  111. mExpanderLabel(p.more_label),
  112. mExpanderVisible(false)
  113. {
  114. setIsChrome(TRUE);
  115. }
  116. void LLExpandableTextBox::LLTextBoxEx::reshape(S32 width, S32 height, BOOL called_from_parent)
  117. {
  118. hideExpandText();
  119. LLTextEditor::reshape(width, height, called_from_parent);
  120. if (getTextPixelHeight() > getRect().getHeight())
  121. {
  122. showExpandText();
  123. }
  124. }
  125. void LLExpandableTextBox::LLTextBoxEx::setText(const LLStringExplicit& text,const LLStyle::Params& input_params)
  126. {
  127. // LLTextBox::setText will obliterate the expander segment, so make sure
  128. // we generate it again by clearing mExpanderVisible
  129. mExpanderVisible = false;
  130. LLTextEditor::setText(text, input_params);
  131. // text contents have changed, segments are cleared out
  132. // so hide the expander and determine if we need it
  133. //mExpanderVisible = false;
  134. if (getTextPixelHeight() > getRect().getHeight())
  135. {
  136. showExpandText();
  137. }
  138. else
  139. {
  140. hideExpandText();
  141. }
  142. }
  143. void LLExpandableTextBox::LLTextBoxEx::showExpandText()
  144. {
  145. if (!mExpanderVisible)
  146. {
  147. // make sure we're scrolled to top when collapsing
  148. if (mScroller)
  149. {
  150. mScroller->goToTop();
  151. }
  152. // get fully visible lines
  153. std::pair<S32, S32> visible_lines = getVisibleLines(true);
  154. S32 last_line = visible_lines.second - 1;
  155. LLStyle::Params expander_style(getDefaultStyleParams());
  156. expander_style.font.style = "UNDERLINE";
  157. expander_style.color = LLUIColorTable::instance().getColor("HTMLLinkColor");
  158. LLExpanderSegment* expanderp = new LLExpanderSegment(new LLStyle(expander_style), getLineStart(last_line), getLength() + 1, mExpanderLabel, *this);
  159. insertSegment(expanderp);
  160. mExpanderVisible = true;
  161. }
  162. }
  163. //NOTE: obliterates existing styles (including hyperlinks)
  164. void LLExpandableTextBox::LLTextBoxEx::hideExpandText() 
  165. if (mExpanderVisible)
  166. {
  167. // this will overwrite the expander segment and all text styling with a single style
  168. LLStyleConstSP sp(new LLStyle(getDefaultStyleParams()));
  169. LLNormalTextSegment* segmentp = new LLNormalTextSegment(sp, 0, getLength() + 1, *this);
  170. insertSegment(segmentp);
  171. mExpanderVisible = false;
  172. }
  173. }
  174. S32 LLExpandableTextBox::LLTextBoxEx::getVerticalTextDelta()
  175. {
  176. S32 text_height = getTextPixelHeight();
  177. S32 textbox_height = getRect().getHeight();
  178. return text_height - textbox_height;
  179. }
  180. S32 LLExpandableTextBox::LLTextBoxEx::getTextPixelHeight()
  181. {
  182. return getTextBoundingRect().getHeight();
  183. }
  184. //////////////////////////////////////////////////////////////////////////
  185. //////////////////////////////////////////////////////////////////////////
  186. //////////////////////////////////////////////////////////////////////////
  187. LLExpandableTextBox::Params::Params()
  188. : textbox("textbox"),
  189. scroll("scroll"),
  190. max_height("max_height", 0),
  191. bg_visible("bg_visible", false),
  192. expanded_bg_visible("expanded_bg_visible", true),
  193. bg_color("bg_color", LLColor4::black),
  194. expanded_bg_color("expanded_bg_color", LLColor4::black)
  195. {
  196. }
  197. LLExpandableTextBox::LLExpandableTextBox(const Params& p)
  198. : LLUICtrl(p),
  199. mMaxHeight(p.max_height),
  200. mBGVisible(p.bg_visible),
  201. mExpandedBGVisible(p.expanded_bg_visible),
  202. mBGColor(p.bg_color),
  203. mExpandedBGColor(p.expanded_bg_color),
  204. mExpanded(false)
  205. {
  206. LLRect rc = getLocalRect();
  207. LLScrollContainer::Params scroll_params = p.scroll;
  208. scroll_params.rect(rc);
  209. mScroll = LLUICtrlFactory::create<LLScrollContainer>(scroll_params);
  210. addChild(mScroll);
  211. LLTextBoxEx::Params textbox_params = p.textbox;
  212. textbox_params.rect(rc);
  213. mTextBox = LLUICtrlFactory::create<LLTextBoxEx>(textbox_params);
  214. mScroll->addChild(mTextBox);
  215. updateTextBoxRect();
  216. mTextBox->setCommitCallback(boost::bind(&LLExpandableTextBox::onExpandClicked, this));
  217. }
  218. void LLExpandableTextBox::draw()
  219. {
  220. if(mBGVisible && !mExpanded)
  221. {
  222. gl_rect_2d(getLocalRect(), mBGColor.get(), TRUE);
  223. }
  224. if(mExpandedBGVisible && mExpanded)
  225. {
  226. gl_rect_2d(getLocalRect(), mExpandedBGColor.get(), TRUE);
  227. }
  228. collapseIfPosChanged();
  229. LLUICtrl::draw();
  230. }
  231. void LLExpandableTextBox::collapseIfPosChanged()
  232. {
  233. if(mExpanded)
  234. {
  235. LLView* parentp = getParent();
  236. LLRect parent_rect = parentp->getRect();
  237. parentp->localRectToOtherView(parent_rect, &parent_rect, getRootView());
  238. if(parent_rect.mLeft != mParentRect.mLeft 
  239. || parent_rect.mTop != mParentRect.mTop)
  240. {
  241. collapseTextBox();
  242. }
  243. }
  244. }
  245. void LLExpandableTextBox::onExpandClicked()
  246. {
  247. expandTextBox();
  248. }
  249. void LLExpandableTextBox::updateTextBoxRect()
  250. {
  251. LLRect rc = getLocalRect();
  252. rc.mLeft += mScroll->getBorderWidth();
  253. rc.mRight -= mScroll->getBorderWidth();
  254. rc.mTop -= mScroll->getBorderWidth();
  255. rc.mBottom += mScroll->getBorderWidth();
  256. mTextBox->reshape(rc.getWidth(), rc.getHeight());
  257. mTextBox->setRect(rc);
  258. }
  259. S32 LLExpandableTextBox::recalculateTextDelta(S32 text_delta)
  260. {
  261. LLRect expanded_rect = getLocalRect();
  262. LLView* root_view = getRootView();
  263. LLRect window_rect = root_view->getRect();
  264. LLRect expanded_screen_rect;
  265. localRectToOtherView(expanded_rect, &expanded_screen_rect, root_view);
  266. // don't allow expanded text box bottom go off screen
  267. if(expanded_screen_rect.mBottom - text_delta < window_rect.mBottom)
  268. {
  269. text_delta = expanded_screen_rect.mBottom - window_rect.mBottom;
  270. }
  271. // show scroll bar if max_height is valid 
  272. // and expanded size is greater that max_height
  273. else if(mMaxHeight > 0 && expanded_rect.getHeight() + text_delta > mMaxHeight)
  274. {
  275. text_delta = mMaxHeight - expanded_rect.getHeight();
  276. }
  277. return text_delta;
  278. }
  279. void LLExpandableTextBox::expandTextBox()
  280. {
  281. // hide "more" link, and show full text contents
  282. mTextBox->hideExpandText();
  283. // *HACK dz
  284. // hideExpandText brakes text styles (replaces hyper-links with plain text), see ticket EXT-3290
  285. // Set text again to make text box re-apply styles.
  286. // *TODO Find proper solution to fix this issue.
  287. // Maybe add removeSegment to LLTextBase
  288. mTextBox->setTextBase(mText);
  289. S32 text_delta = mTextBox->getVerticalTextDelta();
  290. text_delta += mTextBox->getVPad() * 2;
  291. text_delta += mScroll->getBorderWidth() * 2;
  292. // no need to expand
  293. if(text_delta <= 0)
  294. {
  295. return;
  296. }
  297. saveCollapsedState();
  298. LLRect expanded_rect = getLocalRect();
  299. LLRect expanded_screen_rect;
  300. S32 updated_text_delta = recalculateTextDelta(text_delta);
  301. // actual expand
  302. expanded_rect.mBottom -= updated_text_delta;
  303. LLRect text_box_rect = mTextBox->getRect();
  304. // check if we need to show scrollbar
  305. if(text_delta != updated_text_delta)
  306. {
  307. static LLUICachedControl<S32> scrollbar_size ("UIScrollbarSize", 0);
  308. // disable horizontal scrollbar
  309. text_box_rect.mRight -= scrollbar_size;
  310. // text box size has changed - redo text wrap
  311. // Should be handled automatically in reshape() below. JC
  312. //mTextBox->setWrappedText(mText, text_box_rect.getWidth());
  313. // recalculate text delta since text wrap changed text height
  314. text_delta = mTextBox->getVerticalTextDelta() + mTextBox->getVPad() * 2;
  315. }
  316. // expand text
  317. text_box_rect.mBottom -= text_delta;
  318. mTextBox->reshape(text_box_rect.getWidth(), text_box_rect.getHeight());
  319. mTextBox->setRect(text_box_rect);
  320. // expand text box
  321. localRectToOtherView(expanded_rect, &expanded_screen_rect, getParent());
  322. reshape(expanded_screen_rect.getWidth(), expanded_screen_rect.getHeight(), FALSE);
  323. setRect(expanded_screen_rect);
  324. setFocus(TRUE);
  325. // this lets us receive top_lost event(needed to collapse text box)
  326. // it also draws text box above all other ui elements
  327. gFocusMgr.setTopCtrl(this);
  328. mExpanded = true;
  329. }
  330. void LLExpandableTextBox::collapseTextBox()
  331. {
  332. if(!mExpanded)
  333. {
  334. return;
  335. }
  336. mExpanded = false;
  337. reshape(mCollapsedRect.getWidth(), mCollapsedRect.getHeight(), FALSE);
  338. setRect(mCollapsedRect);
  339. updateTextBoxRect();
  340. if(gFocusMgr.getTopCtrl() == this)
  341. {
  342. gFocusMgr.setTopCtrl(NULL);
  343. }
  344. }
  345. void LLExpandableTextBox::onFocusLost()
  346. {
  347. collapseTextBox();
  348. LLUICtrl::onFocusLost();
  349. }
  350. void LLExpandableTextBox::onTopLost()
  351. {
  352. collapseTextBox();
  353. LLUICtrl::onTopLost();
  354. }
  355. void LLExpandableTextBox::setValue(const LLSD& value)
  356. {
  357. collapseTextBox();
  358. mText = value.asString();
  359. mTextBox->setValue(value);
  360. }
  361. void LLExpandableTextBox::setText(const std::string& str)
  362. {
  363. collapseTextBox();
  364. mText = str;
  365. mTextBox->setText(str);
  366. }
  367. void LLExpandableTextBox::saveCollapsedState()
  368. {
  369. mCollapsedRect = getRect();
  370. mParentRect = getParent()->getRect();
  371. // convert parent rect to screen coordinates, 
  372. // this will allow to track parent's position change
  373. getParent()->localRectToOtherView(mParentRect, &mParentRect, getRootView());
  374. }