diff options
author | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
commit | 38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch) | |
tree | adca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/llui/lltextbox.cpp | |
parent | README.txt (diff) | |
download | meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2 meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz |
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/llui/lltextbox.cpp')
-rw-r--r-- | linden/indra/llui/lltextbox.cpp | 457 |
1 files changed, 457 insertions, 0 deletions
diff --git a/linden/indra/llui/lltextbox.cpp b/linden/indra/llui/lltextbox.cpp new file mode 100644 index 0000000..d70f223 --- /dev/null +++ b/linden/indra/llui/lltextbox.cpp | |||
@@ -0,0 +1,457 @@ | |||
1 | /** | ||
2 | * @file lltextbox.cpp | ||
3 | * @brief A text display widget | ||
4 | * | ||
5 | * Copyright (c) 2001-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #include "linden_common.h" | ||
29 | |||
30 | #include "lltextbox.h" | ||
31 | |||
32 | #include "llerror.h" | ||
33 | #include "llgl.h" | ||
34 | #include "llui.h" | ||
35 | #include "lluictrlfactory.h" | ||
36 | #include "llcontrol.h" | ||
37 | #include "llfocusmgr.h" | ||
38 | #include "llstl.h" | ||
39 | #include <boost/tokenizer.hpp> | ||
40 | |||
41 | LLTextBox::LLTextBox(const LLString& name, const LLRect& rect, const LLString& text, | ||
42 | const LLFontGL* font, BOOL mouse_opaque) | ||
43 | : LLUICtrl(name, rect, mouse_opaque, NULL, NULL, FOLLOWS_LEFT | FOLLOWS_TOP ), | ||
44 | mTextColor( LLUI::sColorsGroup->getColor( "LabelTextColor" ) ), | ||
45 | mDisabledColor( LLUI::sColorsGroup->getColor( "LabelDisabledColor" ) ), | ||
46 | mBackgroundColor( LLUI::sColorsGroup->getColor( "DefaultBackgroundColor" ) ), | ||
47 | mBorderColor( LLUI::sColorsGroup->getColor( "DefaultHighlightLight" ) ), | ||
48 | mBackgroundVisible( FALSE ), | ||
49 | mBorderVisible( FALSE ), | ||
50 | mDropshadowVisible( TRUE ), | ||
51 | mBorderDropShadowVisible( FALSE ), | ||
52 | mHPad(0), | ||
53 | mVPad(0), | ||
54 | mHAlign( LLFontGL::LEFT ), | ||
55 | mVAlign( LLFontGL::TOP ), | ||
56 | mClickedCallback(NULL), | ||
57 | mCallbackUserData(NULL) | ||
58 | { | ||
59 | // TomY TODO Nuke this eventually | ||
60 | setText( !text.empty() ? text : name ); | ||
61 | mFontGL = font ? font : LLFontGL::sSansSerifSmall; | ||
62 | setTabStop(FALSE); | ||
63 | } | ||
64 | |||
65 | LLTextBox::LLTextBox(const LLString& name, const LLString& text, F32 max_width, | ||
66 | const LLFontGL* font, BOOL mouse_opaque) : | ||
67 | LLUICtrl(name, LLRect(0, 0, 1, 1), mouse_opaque, NULL, NULL, FOLLOWS_LEFT | FOLLOWS_TOP), | ||
68 | mFontGL(font ? font : LLFontGL::sSansSerifSmall), | ||
69 | mTextColor(LLUI::sColorsGroup->getColor("LabelTextColor")), | ||
70 | mDisabledColor(LLUI::sColorsGroup->getColor("LabelDisabledColor")), | ||
71 | mBackgroundColor(LLUI::sColorsGroup->getColor("DefaultBackgroundColor")), | ||
72 | mBorderColor(LLUI::sColorsGroup->getColor("DefaultHighlightLight")), | ||
73 | mBackgroundVisible(FALSE), | ||
74 | mBorderVisible(FALSE), | ||
75 | mDropshadowVisible(TRUE), | ||
76 | mBorderDropShadowVisible(FALSE), | ||
77 | mHPad(0), | ||
78 | mVPad(0), | ||
79 | mHAlign(LLFontGL::LEFT), | ||
80 | mVAlign( LLFontGL::TOP ), | ||
81 | mClickedCallback(NULL), | ||
82 | mCallbackUserData(NULL) | ||
83 | { | ||
84 | setWrappedText(!text.empty() ? text : name, max_width); | ||
85 | reshapeToFitText(); | ||
86 | setTabStop(FALSE); | ||
87 | } | ||
88 | |||
89 | LLTextBox::~LLTextBox() | ||
90 | { | ||
91 | } | ||
92 | |||
93 | // virtual | ||
94 | EWidgetType LLTextBox::getWidgetType() const | ||
95 | { | ||
96 | return WIDGET_TYPE_TEXT_BOX; | ||
97 | } | ||
98 | |||
99 | // virtual | ||
100 | LLString LLTextBox::getWidgetTag() const | ||
101 | { | ||
102 | return LL_TEXT_BOX_TAG; | ||
103 | } | ||
104 | |||
105 | BOOL LLTextBox::handleMouseDown(S32 x, S32 y, MASK mask) | ||
106 | { | ||
107 | BOOL handled = FALSE; | ||
108 | |||
109 | // HACK: Only do this if there actually is a click callback, so that | ||
110 | // overly large text boxes in the older UI won't start eating clicks. | ||
111 | if (mClickedCallback) | ||
112 | { | ||
113 | handled = TRUE; | ||
114 | |||
115 | // Route future Mouse messages here preemptively. (Release on mouse up.) | ||
116 | gFocusMgr.setMouseCapture( this, NULL ); | ||
117 | |||
118 | if (mSoundFlags & MOUSE_DOWN) | ||
119 | { | ||
120 | make_ui_sound("UISndClick"); | ||
121 | } | ||
122 | } | ||
123 | |||
124 | return handled; | ||
125 | } | ||
126 | |||
127 | |||
128 | BOOL LLTextBox::handleMouseUp(S32 x, S32 y, MASK mask) | ||
129 | { | ||
130 | BOOL handled = FALSE; | ||
131 | |||
132 | // We only handle the click if the click both started and ended within us | ||
133 | |||
134 | // HACK: Only do this if there actually is a click callback, so that | ||
135 | // overly large text boxes in the older UI won't start eating clicks. | ||
136 | if (mClickedCallback | ||
137 | && this == gFocusMgr.getMouseCapture()) | ||
138 | { | ||
139 | handled = TRUE; | ||
140 | |||
141 | // Release the mouse | ||
142 | gFocusMgr.setMouseCapture( NULL, NULL ); | ||
143 | |||
144 | if (mSoundFlags & MOUSE_UP) | ||
145 | { | ||
146 | make_ui_sound("UISndClickRelease"); | ||
147 | } | ||
148 | |||
149 | // DO THIS AT THE VERY END to allow the button to be destroyed as a result of being clicked. | ||
150 | // If mouseup in the widget, it's been clicked | ||
151 | if (mClickedCallback) | ||
152 | { | ||
153 | (*mClickedCallback)( mCallbackUserData ); | ||
154 | } | ||
155 | } | ||
156 | |||
157 | return handled; | ||
158 | } | ||
159 | |||
160 | void LLTextBox::setText(const LLString& text) | ||
161 | { | ||
162 | mText.assign(text); | ||
163 | setLineLengths(); | ||
164 | } | ||
165 | |||
166 | void LLTextBox::setLineLengths() | ||
167 | { | ||
168 | mLineLengthList.clear(); | ||
169 | |||
170 | LLString::size_type cur = 0; | ||
171 | LLString::size_type len = mText.getWString().size(); | ||
172 | |||
173 | while (cur < len) | ||
174 | { | ||
175 | LLString::size_type end = mText.getWString().find('\n', cur); | ||
176 | LLString::size_type runLen; | ||
177 | |||
178 | if (end == LLString::npos) | ||
179 | { | ||
180 | runLen = len - cur; | ||
181 | cur = len; | ||
182 | } | ||
183 | else | ||
184 | { | ||
185 | runLen = end - cur; | ||
186 | cur = end + 1; // skip the new line character | ||
187 | } | ||
188 | |||
189 | mLineLengthList.push_back( (S32)runLen ); | ||
190 | } | ||
191 | } | ||
192 | |||
193 | void LLTextBox::setWrappedText(const LLString& in_text, F32 max_width) | ||
194 | { | ||
195 | if (max_width < 0.0) | ||
196 | { | ||
197 | max_width = (F32)getRect().getWidth(); | ||
198 | } | ||
199 | |||
200 | LLWString wtext = utf8str_to_wstring(in_text); | ||
201 | LLWString final_wtext; | ||
202 | |||
203 | LLWString::size_type cur = 0;; | ||
204 | LLWString::size_type len = wtext.size(); | ||
205 | |||
206 | while (cur < len) | ||
207 | { | ||
208 | LLWString::size_type end = wtext.find('\n', cur); | ||
209 | if (end == LLWString::npos) | ||
210 | { | ||
211 | end = len; | ||
212 | } | ||
213 | |||
214 | LLWString::size_type runLen = end - cur; | ||
215 | if (runLen > 0) | ||
216 | { | ||
217 | LLWString run(wtext, cur, runLen); | ||
218 | LLWString::size_type useLen = | ||
219 | mFontGL->maxDrawableChars(run.c_str(), max_width, runLen, TRUE); | ||
220 | |||
221 | final_wtext.append(wtext, cur, useLen); | ||
222 | cur += useLen; | ||
223 | } | ||
224 | |||
225 | if (cur < len) | ||
226 | { | ||
227 | if (wtext[cur] == '\n') | ||
228 | { | ||
229 | cur += 1; | ||
230 | } | ||
231 | final_wtext += '\n'; | ||
232 | } | ||
233 | } | ||
234 | |||
235 | LLString final_text = wstring_to_utf8str(final_wtext); | ||
236 | setText(final_text); | ||
237 | } | ||
238 | |||
239 | S32 LLTextBox::getTextPixelWidth() | ||
240 | { | ||
241 | S32 max_line_width = 0; | ||
242 | if( mLineLengthList.size() > 0 ) | ||
243 | { | ||
244 | S32 cur_pos = 0; | ||
245 | for (std::vector<S32>::iterator iter = mLineLengthList.begin(); | ||
246 | iter != mLineLengthList.end(); ++iter) | ||
247 | { | ||
248 | S32 line_length = *iter; | ||
249 | S32 line_width = mFontGL->getWidth( mText.getWString().c_str(), cur_pos, line_length ); | ||
250 | if( line_width > max_line_width ) | ||
251 | { | ||
252 | max_line_width = line_width; | ||
253 | } | ||
254 | cur_pos += line_length+1; | ||
255 | } | ||
256 | } | ||
257 | else | ||
258 | { | ||
259 | max_line_width = mFontGL->getWidth(mText.getWString().c_str()); | ||
260 | } | ||
261 | return max_line_width; | ||
262 | } | ||
263 | |||
264 | S32 LLTextBox::getTextPixelHeight() | ||
265 | { | ||
266 | S32 num_lines = mLineLengthList.size(); | ||
267 | if( num_lines < 1 ) | ||
268 | { | ||
269 | num_lines = 1; | ||
270 | } | ||
271 | return (S32)(num_lines * mFontGL->getLineHeight()); | ||
272 | } | ||
273 | |||
274 | |||
275 | void LLTextBox::setValue(const LLSD& value ) | ||
276 | { | ||
277 | setText(value.asString()); | ||
278 | } | ||
279 | |||
280 | LLSD LLTextBox::getValue() const | ||
281 | { | ||
282 | return LLSD(getText()); | ||
283 | } | ||
284 | |||
285 | BOOL LLTextBox::setTextArg( const LLString& key, const LLString& text ) | ||
286 | { | ||
287 | mText.setArg(key, text); | ||
288 | setLineLengths(); | ||
289 | return TRUE; | ||
290 | } | ||
291 | |||
292 | void LLTextBox::draw() | ||
293 | { | ||
294 | if( getVisible() ) | ||
295 | { | ||
296 | if (mBorderVisible) | ||
297 | { | ||
298 | gl_rect_2d_offset_local(getLocalRect(), 2, FALSE); | ||
299 | } | ||
300 | |||
301 | if( mBorderDropShadowVisible ) | ||
302 | { | ||
303 | static LLColor4 color_drop_shadow = LLUI::sColorsGroup->getColor("ColorDropShadow"); | ||
304 | static S32 drop_shadow_tooltip = LLUI::sConfigGroup->getS32("DropShadowTooltip"); | ||
305 | gl_drop_shadow(0, mRect.getHeight(), mRect.getWidth(), 0, | ||
306 | color_drop_shadow, drop_shadow_tooltip); | ||
307 | } | ||
308 | |||
309 | if (mBackgroundVisible) | ||
310 | { | ||
311 | LLRect r( 0, mRect.getHeight(), mRect.getWidth(), 0 ); | ||
312 | gl_rect_2d( r, mBackgroundColor ); | ||
313 | } | ||
314 | |||
315 | S32 text_x = 0; | ||
316 | switch( mHAlign ) | ||
317 | { | ||
318 | case LLFontGL::LEFT: | ||
319 | text_x = mHPad; | ||
320 | break; | ||
321 | case LLFontGL::HCENTER: | ||
322 | text_x = mRect.getWidth() / 2; | ||
323 | break; | ||
324 | case LLFontGL::RIGHT: | ||
325 | text_x = mRect.getWidth() - mHPad; | ||
326 | break; | ||
327 | } | ||
328 | |||
329 | S32 text_y = mRect.getHeight() - mVPad; | ||
330 | |||
331 | if ( getEnabled() ) | ||
332 | { | ||
333 | drawText( text_x, text_y, mTextColor ); | ||
334 | } | ||
335 | else | ||
336 | { | ||
337 | drawText( text_x, text_y, mDisabledColor ); | ||
338 | } | ||
339 | |||
340 | if (sDebugRects) | ||
341 | { | ||
342 | drawDebugRect(); | ||
343 | } | ||
344 | } | ||
345 | } | ||
346 | |||
347 | void LLTextBox::reshape(S32 width, S32 height, BOOL called_from_parent) | ||
348 | { | ||
349 | // reparse line lengths | ||
350 | setText(mText); | ||
351 | LLView::reshape(width, height, called_from_parent); | ||
352 | } | ||
353 | |||
354 | void LLTextBox::drawText( S32 x, S32 y, const LLColor4& color ) | ||
355 | { | ||
356 | if( !mLineLengthList.empty() ) | ||
357 | { | ||
358 | S32 cur_pos = 0; | ||
359 | for (std::vector<S32>::iterator iter = mLineLengthList.begin(); | ||
360 | iter != mLineLengthList.end(); ++iter) | ||
361 | { | ||
362 | S32 line_length = *iter; | ||
363 | mFontGL->render(mText.getWString(), cur_pos, (F32)x, (F32)y, color, | ||
364 | mHAlign, mVAlign, | ||
365 | mDropshadowVisible ? LLFontGL::DROP_SHADOW : LLFontGL::NORMAL, | ||
366 | line_length, mRect.getWidth(), NULL, TRUE ); | ||
367 | cur_pos += line_length + 1; | ||
368 | y -= llfloor(mFontGL->getLineHeight()); | ||
369 | } | ||
370 | } | ||
371 | else | ||
372 | { | ||
373 | mFontGL->render(mText.getWString(), 0, (F32)x, (F32)y, color, | ||
374 | mHAlign, mVAlign, | ||
375 | mDropshadowVisible ? LLFontGL::DROP_SHADOW : LLFontGL::NORMAL, | ||
376 | S32_MAX, mRect.getWidth(), NULL, TRUE); | ||
377 | } | ||
378 | } | ||
379 | |||
380 | |||
381 | void LLTextBox::reshapeToFitText() | ||
382 | { | ||
383 | S32 width = getTextPixelWidth(); | ||
384 | S32 height = getTextPixelHeight(); | ||
385 | reshape( width + 2 * mHPad, height + 2 * mVPad ); | ||
386 | } | ||
387 | |||
388 | // virtual | ||
389 | LLXMLNodePtr LLTextBox::getXML(bool save_children) const | ||
390 | { | ||
391 | LLXMLNodePtr node = LLUICtrl::getXML(); | ||
392 | |||
393 | // Attributes | ||
394 | |||
395 | node->createChild("font", TRUE)->setStringValue(LLFontGL::nameFromFont(mFontGL)); | ||
396 | |||
397 | node->createChild("halign", TRUE)->setStringValue(LLFontGL::nameFromHAlign(mHAlign)); | ||
398 | |||
399 | addColorXML(node, mTextColor, "text_color", "LabelTextColor"); | ||
400 | addColorXML(node, mDisabledColor, "disabled_color", "LabelDisabledColor"); | ||
401 | addColorXML(node, mBackgroundColor, "bg_color", "DefaultBackgroundColor"); | ||
402 | addColorXML(node, mBorderColor, "border_color", "DefaultHighlightLight"); | ||
403 | |||
404 | node->createChild("bg_visible", TRUE)->setBoolValue(mBackgroundVisible); | ||
405 | |||
406 | node->createChild("border_visible", TRUE)->setBoolValue(mBorderVisible); | ||
407 | |||
408 | node->createChild("drop_shadow_visible", TRUE)->setBoolValue(mDropshadowVisible); | ||
409 | |||
410 | node->createChild("border_drop_shadow_visible", TRUE)->setBoolValue(mBorderDropShadowVisible); | ||
411 | |||
412 | node->createChild("h_pad", TRUE)->setIntValue(mHPad); | ||
413 | |||
414 | node->createChild("v_pad", TRUE)->setIntValue(mVPad); | ||
415 | |||
416 | // Contents | ||
417 | |||
418 | node->setStringValue(mText); | ||
419 | |||
420 | return node; | ||
421 | } | ||
422 | |||
423 | // static | ||
424 | LLView* LLTextBox::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) | ||
425 | { | ||
426 | LLString name("text_box"); | ||
427 | node->getAttributeString("name", name); | ||
428 | LLFontGL* font = LLView::selectFont(node); | ||
429 | |||
430 | LLString text = node->getTextContents(); | ||
431 | |||
432 | // TomY Yes I know this is a hack, but insert a space to make a blank text field | ||
433 | if (text == "") | ||
434 | { | ||
435 | text = " "; | ||
436 | } | ||
437 | |||
438 | LLTextBox* text_box = new LLTextBox(name, | ||
439 | LLRect(), | ||
440 | text, | ||
441 | font, | ||
442 | FALSE); | ||
443 | |||
444 | LLFontGL::HAlign halign = LLView::selectFontHAlign(node); | ||
445 | text_box->setHAlign(halign); | ||
446 | |||
447 | text_box->initFromXML(node, parent); | ||
448 | |||
449 | if(node->hasAttribute("text_color")) | ||
450 | { | ||
451 | LLColor4 color; | ||
452 | LLUICtrlFactory::getAttributeColor(node, "text_color", color); | ||
453 | text_box->setColor(color); | ||
454 | } | ||
455 | |||
456 | return text_box; | ||
457 | } | ||