From 38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 Mon Sep 17 00:00:00 2001 From: Jacek Antonelli Date: Fri, 15 Aug 2008 23:44:46 -0500 Subject: Second Life viewer sources 1.13.2.12 --- linden/indra/llui/lltextbox.cpp | 457 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 457 insertions(+) create mode 100644 linden/indra/llui/lltextbox.cpp (limited to 'linden/indra/llui/lltextbox.cpp') 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 @@ +/** + * @file lltextbox.cpp + * @brief A text display widget + * + * Copyright (c) 2001-2007, Linden Research, Inc. + * + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + */ + +#include "linden_common.h" + +#include "lltextbox.h" + +#include "llerror.h" +#include "llgl.h" +#include "llui.h" +#include "lluictrlfactory.h" +#include "llcontrol.h" +#include "llfocusmgr.h" +#include "llstl.h" +#include + +LLTextBox::LLTextBox(const LLString& name, const LLRect& rect, const LLString& text, + const LLFontGL* font, BOOL mouse_opaque) +: LLUICtrl(name, rect, mouse_opaque, NULL, NULL, FOLLOWS_LEFT | FOLLOWS_TOP ), + mTextColor( LLUI::sColorsGroup->getColor( "LabelTextColor" ) ), + mDisabledColor( LLUI::sColorsGroup->getColor( "LabelDisabledColor" ) ), + mBackgroundColor( LLUI::sColorsGroup->getColor( "DefaultBackgroundColor" ) ), + mBorderColor( LLUI::sColorsGroup->getColor( "DefaultHighlightLight" ) ), + mBackgroundVisible( FALSE ), + mBorderVisible( FALSE ), + mDropshadowVisible( TRUE ), + mBorderDropShadowVisible( FALSE ), + mHPad(0), + mVPad(0), + mHAlign( LLFontGL::LEFT ), + mVAlign( LLFontGL::TOP ), + mClickedCallback(NULL), + mCallbackUserData(NULL) +{ + // TomY TODO Nuke this eventually + setText( !text.empty() ? text : name ); + mFontGL = font ? font : LLFontGL::sSansSerifSmall; + setTabStop(FALSE); +} + +LLTextBox::LLTextBox(const LLString& name, const LLString& text, F32 max_width, + const LLFontGL* font, BOOL mouse_opaque) : + LLUICtrl(name, LLRect(0, 0, 1, 1), mouse_opaque, NULL, NULL, FOLLOWS_LEFT | FOLLOWS_TOP), + mFontGL(font ? font : LLFontGL::sSansSerifSmall), + mTextColor(LLUI::sColorsGroup->getColor("LabelTextColor")), + mDisabledColor(LLUI::sColorsGroup->getColor("LabelDisabledColor")), + mBackgroundColor(LLUI::sColorsGroup->getColor("DefaultBackgroundColor")), + mBorderColor(LLUI::sColorsGroup->getColor("DefaultHighlightLight")), + mBackgroundVisible(FALSE), + mBorderVisible(FALSE), + mDropshadowVisible(TRUE), + mBorderDropShadowVisible(FALSE), + mHPad(0), + mVPad(0), + mHAlign(LLFontGL::LEFT), + mVAlign( LLFontGL::TOP ), + mClickedCallback(NULL), + mCallbackUserData(NULL) +{ + setWrappedText(!text.empty() ? text : name, max_width); + reshapeToFitText(); + setTabStop(FALSE); +} + +LLTextBox::~LLTextBox() +{ +} + +// virtual +EWidgetType LLTextBox::getWidgetType() const +{ + return WIDGET_TYPE_TEXT_BOX; +} + +// virtual +LLString LLTextBox::getWidgetTag() const +{ + return LL_TEXT_BOX_TAG; +} + +BOOL LLTextBox::handleMouseDown(S32 x, S32 y, MASK mask) +{ + BOOL handled = FALSE; + + // HACK: Only do this if there actually is a click callback, so that + // overly large text boxes in the older UI won't start eating clicks. + if (mClickedCallback) + { + handled = TRUE; + + // Route future Mouse messages here preemptively. (Release on mouse up.) + gFocusMgr.setMouseCapture( this, NULL ); + + if (mSoundFlags & MOUSE_DOWN) + { + make_ui_sound("UISndClick"); + } + } + + return handled; +} + + +BOOL LLTextBox::handleMouseUp(S32 x, S32 y, MASK mask) +{ + BOOL handled = FALSE; + + // We only handle the click if the click both started and ended within us + + // HACK: Only do this if there actually is a click callback, so that + // overly large text boxes in the older UI won't start eating clicks. + if (mClickedCallback + && this == gFocusMgr.getMouseCapture()) + { + handled = TRUE; + + // Release the mouse + gFocusMgr.setMouseCapture( NULL, NULL ); + + if (mSoundFlags & MOUSE_UP) + { + make_ui_sound("UISndClickRelease"); + } + + // DO THIS AT THE VERY END to allow the button to be destroyed as a result of being clicked. + // If mouseup in the widget, it's been clicked + if (mClickedCallback) + { + (*mClickedCallback)( mCallbackUserData ); + } + } + + return handled; +} + +void LLTextBox::setText(const LLString& text) +{ + mText.assign(text); + setLineLengths(); +} + +void LLTextBox::setLineLengths() +{ + mLineLengthList.clear(); + + LLString::size_type cur = 0; + LLString::size_type len = mText.getWString().size(); + + while (cur < len) + { + LLString::size_type end = mText.getWString().find('\n', cur); + LLString::size_type runLen; + + if (end == LLString::npos) + { + runLen = len - cur; + cur = len; + } + else + { + runLen = end - cur; + cur = end + 1; // skip the new line character + } + + mLineLengthList.push_back( (S32)runLen ); + } +} + +void LLTextBox::setWrappedText(const LLString& in_text, F32 max_width) +{ + if (max_width < 0.0) + { + max_width = (F32)getRect().getWidth(); + } + + LLWString wtext = utf8str_to_wstring(in_text); + LLWString final_wtext; + + LLWString::size_type cur = 0;; + LLWString::size_type len = wtext.size(); + + while (cur < len) + { + LLWString::size_type end = wtext.find('\n', cur); + if (end == LLWString::npos) + { + end = len; + } + + LLWString::size_type runLen = end - cur; + if (runLen > 0) + { + LLWString run(wtext, cur, runLen); + LLWString::size_type useLen = + mFontGL->maxDrawableChars(run.c_str(), max_width, runLen, TRUE); + + final_wtext.append(wtext, cur, useLen); + cur += useLen; + } + + if (cur < len) + { + if (wtext[cur] == '\n') + { + cur += 1; + } + final_wtext += '\n'; + } + } + + LLString final_text = wstring_to_utf8str(final_wtext); + setText(final_text); +} + +S32 LLTextBox::getTextPixelWidth() +{ + S32 max_line_width = 0; + if( mLineLengthList.size() > 0 ) + { + S32 cur_pos = 0; + for (std::vector::iterator iter = mLineLengthList.begin(); + iter != mLineLengthList.end(); ++iter) + { + S32 line_length = *iter; + S32 line_width = mFontGL->getWidth( mText.getWString().c_str(), cur_pos, line_length ); + if( line_width > max_line_width ) + { + max_line_width = line_width; + } + cur_pos += line_length+1; + } + } + else + { + max_line_width = mFontGL->getWidth(mText.getWString().c_str()); + } + return max_line_width; +} + +S32 LLTextBox::getTextPixelHeight() +{ + S32 num_lines = mLineLengthList.size(); + if( num_lines < 1 ) + { + num_lines = 1; + } + return (S32)(num_lines * mFontGL->getLineHeight()); +} + + +void LLTextBox::setValue(const LLSD& value ) +{ + setText(value.asString()); +} + +LLSD LLTextBox::getValue() const +{ + return LLSD(getText()); +} + +BOOL LLTextBox::setTextArg( const LLString& key, const LLString& text ) +{ + mText.setArg(key, text); + setLineLengths(); + return TRUE; +} + +void LLTextBox::draw() +{ + if( getVisible() ) + { + if (mBorderVisible) + { + gl_rect_2d_offset_local(getLocalRect(), 2, FALSE); + } + + if( mBorderDropShadowVisible ) + { + static LLColor4 color_drop_shadow = LLUI::sColorsGroup->getColor("ColorDropShadow"); + static S32 drop_shadow_tooltip = LLUI::sConfigGroup->getS32("DropShadowTooltip"); + gl_drop_shadow(0, mRect.getHeight(), mRect.getWidth(), 0, + color_drop_shadow, drop_shadow_tooltip); + } + + if (mBackgroundVisible) + { + LLRect r( 0, mRect.getHeight(), mRect.getWidth(), 0 ); + gl_rect_2d( r, mBackgroundColor ); + } + + S32 text_x = 0; + switch( mHAlign ) + { + case LLFontGL::LEFT: + text_x = mHPad; + break; + case LLFontGL::HCENTER: + text_x = mRect.getWidth() / 2; + break; + case LLFontGL::RIGHT: + text_x = mRect.getWidth() - mHPad; + break; + } + + S32 text_y = mRect.getHeight() - mVPad; + + if ( getEnabled() ) + { + drawText( text_x, text_y, mTextColor ); + } + else + { + drawText( text_x, text_y, mDisabledColor ); + } + + if (sDebugRects) + { + drawDebugRect(); + } + } +} + +void LLTextBox::reshape(S32 width, S32 height, BOOL called_from_parent) +{ + // reparse line lengths + setText(mText); + LLView::reshape(width, height, called_from_parent); +} + +void LLTextBox::drawText( S32 x, S32 y, const LLColor4& color ) +{ + if( !mLineLengthList.empty() ) + { + S32 cur_pos = 0; + for (std::vector::iterator iter = mLineLengthList.begin(); + iter != mLineLengthList.end(); ++iter) + { + S32 line_length = *iter; + mFontGL->render(mText.getWString(), cur_pos, (F32)x, (F32)y, color, + mHAlign, mVAlign, + mDropshadowVisible ? LLFontGL::DROP_SHADOW : LLFontGL::NORMAL, + line_length, mRect.getWidth(), NULL, TRUE ); + cur_pos += line_length + 1; + y -= llfloor(mFontGL->getLineHeight()); + } + } + else + { + mFontGL->render(mText.getWString(), 0, (F32)x, (F32)y, color, + mHAlign, mVAlign, + mDropshadowVisible ? LLFontGL::DROP_SHADOW : LLFontGL::NORMAL, + S32_MAX, mRect.getWidth(), NULL, TRUE); + } +} + + +void LLTextBox::reshapeToFitText() +{ + S32 width = getTextPixelWidth(); + S32 height = getTextPixelHeight(); + reshape( width + 2 * mHPad, height + 2 * mVPad ); +} + +// virtual +LLXMLNodePtr LLTextBox::getXML(bool save_children) const +{ + LLXMLNodePtr node = LLUICtrl::getXML(); + + // Attributes + + node->createChild("font", TRUE)->setStringValue(LLFontGL::nameFromFont(mFontGL)); + + node->createChild("halign", TRUE)->setStringValue(LLFontGL::nameFromHAlign(mHAlign)); + + addColorXML(node, mTextColor, "text_color", "LabelTextColor"); + addColorXML(node, mDisabledColor, "disabled_color", "LabelDisabledColor"); + addColorXML(node, mBackgroundColor, "bg_color", "DefaultBackgroundColor"); + addColorXML(node, mBorderColor, "border_color", "DefaultHighlightLight"); + + node->createChild("bg_visible", TRUE)->setBoolValue(mBackgroundVisible); + + node->createChild("border_visible", TRUE)->setBoolValue(mBorderVisible); + + node->createChild("drop_shadow_visible", TRUE)->setBoolValue(mDropshadowVisible); + + node->createChild("border_drop_shadow_visible", TRUE)->setBoolValue(mBorderDropShadowVisible); + + node->createChild("h_pad", TRUE)->setIntValue(mHPad); + + node->createChild("v_pad", TRUE)->setIntValue(mVPad); + + // Contents + + node->setStringValue(mText); + + return node; +} + +// static +LLView* LLTextBox::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) +{ + LLString name("text_box"); + node->getAttributeString("name", name); + LLFontGL* font = LLView::selectFont(node); + + LLString text = node->getTextContents(); + + // TomY Yes I know this is a hack, but insert a space to make a blank text field + if (text == "") + { + text = " "; + } + + LLTextBox* text_box = new LLTextBox(name, + LLRect(), + text, + font, + FALSE); + + LLFontGL::HAlign halign = LLView::selectFontHAlign(node); + text_box->setHAlign(halign); + + text_box->initFromXML(node, parent); + + if(node->hasAttribute("text_color")) + { + LLColor4 color; + LLUICtrlFactory::getAttributeColor(node, "text_color", color); + text_box->setColor(color); + } + + return text_box; +} -- cgit v1.1