/** * @file llscrolllistcell.cpp * @brief Scroll lists are composed of rows (items), each of which * contains columns (cells). * * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #include "linden_common.h" #include "llscrolllistcell.h" #include "llcheckboxctrl.h" #include "llui.h" // LLUIImage #include "lluictrlfactory.h" //static LLScrollListCell* LLScrollListCell::create(const LLScrollListCell::Params& cell_p) { LLScrollListCell* cell = NULL; if (cell_p.type() == "icon") { cell = new LLScrollListIcon(cell_p); } else if (cell_p.type() == "checkbox") { cell = new LLScrollListCheck(cell_p); } else if (cell_p.type() == "date") { cell = new LLScrollListDate(cell_p); } else if (cell_p.type() == "icontext") { cell = new LLScrollListIconText(cell_p); } else if (cell_p.type() == "bar") { cell = new LLScrollListBar(cell_p); } else // default is "text" { cell = new LLScrollListText(cell_p); } if (cell_p.value.isProvided()) { cell->setValue(cell_p.value); } return cell; } LLScrollListCell::LLScrollListCell(const LLScrollListCell::Params& p) : mWidth(p.width), mToolTip(p.tool_tip) {} // virtual const LLSD LLScrollListCell::getValue() const { return LLStringUtil::null; } // virtual const LLSD LLScrollListCell::getAltValue() const { return LLStringUtil::null; } // // LLScrollListIcon // LLScrollListIcon::LLScrollListIcon(const LLScrollListCell::Params& p) : LLScrollListCell(p), mIcon(LLUI::getUIImage(p.value().asString())), mColor(p.color), mAlignment(p.font_halign) {} LLScrollListIcon::~LLScrollListIcon() { } /*virtual*/ S32 LLScrollListIcon::getHeight() const { return mIcon ? mIcon->getHeight() : 0; } /*virtual*/ const LLSD LLScrollListIcon::getValue() const { return mIcon.isNull() ? LLStringUtil::null : mIcon->getName(); } void LLScrollListIcon::setValue(const LLSD& value) { if (value.isUUID()) { // don't use default image specified by LLUUID::null, use no image in that case LLUUID image_id = value.asUUID(); mIcon = image_id.notNull() ? LLUI::getUIImageByID(image_id) : LLUIImagePtr(NULL); } else { std::string value_string = value.asString(); if (LLUUID::validate(value_string)) { setValue(LLUUID(value_string)); } else if (!value_string.empty()) { mIcon = LLUI::getUIImage(value.asString()); } else { mIcon = NULL; } } } void LLScrollListIcon::setColor(const LLColor4& color) { mColor = color; } S32 LLScrollListIcon::getWidth() const { // if no specified fix width, use width of icon if (LLScrollListCell::getWidth() == 0 && mIcon.notNull()) { return mIcon->getWidth(); } return LLScrollListCell::getWidth(); } void LLScrollListIcon::draw(const LLColor4& color, const LLColor4& highlight_color) const { if (mIcon) { switch(mAlignment) { case LLFontGL::LEFT: mIcon->draw(0, 0, mColor); break; case LLFontGL::RIGHT: mIcon->draw(getWidth() - mIcon->getWidth(), 0, mColor); break; case LLFontGL::HCENTER: mIcon->draw((getWidth() - mIcon->getWidth()) / 2, 0, mColor); break; default: break; } } } // // LLScrollListBar // LLScrollListBar::LLScrollListBar(const LLScrollListCell::Params& p) : LLScrollListCell(p), mRatio(0), mColor(p.color), mBottom(1), mLeftPad(1), mRightPad(1) {} LLScrollListBar::~LLScrollListBar() { } /*virtual*/ S32 LLScrollListBar::getHeight() const { return LLScrollListCell::getHeight(); } /*virtual*/ const LLSD LLScrollListBar::getValue() const { return LLStringUtil::null; } void LLScrollListBar::setValue(const LLSD& value) { if (value.has("ratio")) { mRatio = (F32)value["ratio"].asReal(); } if (value.has("bottom")) { mBottom = value["bottom"].asInteger(); } if (value.has("left_pad")) { mLeftPad = value["left_pad"].asInteger(); } if (value.has("right_pad")) { mRightPad = value["right_pad"].asInteger(); } } void LLScrollListBar::setColor(const LLColor4& color) { mColor = color; } S32 LLScrollListBar::getWidth() const { return LLScrollListCell::getWidth(); } void LLScrollListBar::draw(const LLColor4& color, const LLColor4& highlight_color) const { S32 bar_width = getWidth() - mLeftPad - mRightPad; S32 left = (S32)(bar_width - bar_width * mRatio); left = llclamp(left, mLeftPad, getWidth() - mRightPad - 1); gl_rect_2d(left, mBottom, getWidth() - mRightPad, mBottom - 1, mColor); } // // LLScrollListText // U32 LLScrollListText::sCount = 0; LLScrollListText::LLScrollListText(const LLScrollListCell::Params& p) : LLScrollListCell(p), mText(p.label.isProvided() ? p.label() : p.value().asString()), mAltText(p.alt_value().asString()), mFont(p.font), mColor(p.color), mUseColor(p.color.isProvided()), mFontAlignment(p.font_halign), mVisible(p.visible), mHighlightCount( 0 ), mHighlightOffset( 0 ) { sCount++; mTextWidth = getWidth(); // initialize rounded rect image if (!mRoundedRectImage) { mRoundedRectImage = LLUI::getUIImage("Rounded_Square"); } } //virtual void LLScrollListText::highlightText(S32 offset, S32 num_chars) { mHighlightOffset = offset; mHighlightCount = llmax(0, num_chars); } //virtual bool LLScrollListText::isText() const { return true; } // virtual const std::string &LLScrollListText::getToolTip() const { // If base class has a tooltip, return that if (! LLScrollListCell::getToolTip().empty()) return LLScrollListCell::getToolTip(); // ...otherwise, return the value itself as the tooltip return mText.getString(); } // virtual bool LLScrollListText::needsToolTip() const { // If base class has a tooltip, return that if (LLScrollListCell::needsToolTip()) return LLScrollListCell::needsToolTip(); // ...otherwise, show tooltips for truncated text return mFont->getWidth(mText.getWString().c_str()) > getWidth(); } //virtual bool LLScrollListText::getVisible() const { return mVisible; } //virtual S32 LLScrollListText::getHeight() const { return mFont->getLineHeight(); } LLScrollListText::~LLScrollListText() { sCount--; } S32 LLScrollListText::getContentWidth() const { return mFont->getWidth(mText.getWString().c_str()); } void LLScrollListText::setColor(const LLColor4& color) { mColor = color; mUseColor = true; } void LLScrollListText::setText(const LLStringExplicit& text) { mText = text; } void LLScrollListText::setFontStyle(const U8 font_style) { LLFontDescriptor new_desc(mFont->getFontDesc()); new_desc.setStyle(font_style); mFont = LLFontGL::getFont(new_desc); } //virtual void LLScrollListText::setValue(const LLSD& text) { setText(text.asString()); } //virtual void LLScrollListText::setAltValue(const LLSD& text) { mAltText = text.asString(); } //virtual const LLSD LLScrollListText::getValue() const { return LLSD(mText.getString()); } //virtual const LLSD LLScrollListText::getAltValue() const { return LLSD(mAltText.getString()); } void LLScrollListText::draw(const LLColor4& color, const LLColor4& highlight_color) const { LLColor4 display_color; if (mUseColor) { display_color = mColor; } else { display_color = color; } if (mHighlightCount > 0) { // Highlight text S32 left = 0; switch(mFontAlignment) { case LLFontGL::LEFT: left = mFont->getWidth(mText.getWString().c_str(), 1, mHighlightOffset); break; case LLFontGL::RIGHT: left = getWidth() - mFont->getWidth(mText.getWString().c_str(), mHighlightOffset, S32_MAX); break; case LLFontGL::HCENTER: left = (getWidth() - mFont->getWidth(mText.getWString().c_str())) / 2; break; } LLRect highlight_rect(left - 2, mFont->getLineHeight() + 1, left + mFont->getWidth(mText.getWString().c_str(), mHighlightOffset, mHighlightCount) + 1, 1); mRoundedRectImage->draw(highlight_rect, highlight_color); } // Try to draw the entire string F32 right_x; U32 string_chars = mText.length(); F32 start_x = 0.f; switch(mFontAlignment) { case LLFontGL::LEFT: start_x = 1.f; break; case LLFontGL::RIGHT: start_x = (F32)getWidth(); break; case LLFontGL::HCENTER: start_x = (F32)getWidth() * 0.5f; break; } mFont->render(mText.getWString(), 0, start_x, 0.f, display_color, mFontAlignment, LLFontGL::BOTTOM, 0, LLFontGL::NO_SHADOW, string_chars, getTextWidth(), &right_x, true); } // // LLScrollListCheck // LLScrollListCheck::LLScrollListCheck(const LLScrollListCell::Params& p) : LLScrollListCell(p) { LLCheckBoxCtrl::Params checkbox_p; checkbox_p.name("checkbox"); checkbox_p.rect = LLRect(0, p.width, p.width, 0); checkbox_p.enabled(p.enabled); checkbox_p.initial_value(p.value()); mCheckBox = LLUICtrlFactory::create(checkbox_p); LLRect rect(mCheckBox->getRect()); if (p.width) { rect.mRight = rect.mLeft + p.width; mCheckBox->setRect(rect); setWidth(p.width); } else { setWidth(rect.getWidth()); //check_box->getWidth(); } mCheckBox->setColor(p.color()); } LLScrollListCheck::~LLScrollListCheck() { delete mCheckBox; mCheckBox = NULL; } void LLScrollListCheck::draw(const LLColor4& color, const LLColor4& highlight_color) const { mCheckBox->draw(); } bool LLScrollListCheck::handleClick() { if (mCheckBox->getEnabled()) { mCheckBox->toggle(); } // don't change selection when clicking on embedded checkbox return true; } /*virtual*/ const LLSD LLScrollListCheck::getValue() const { return mCheckBox->getValue(); } /*virtual*/ void LLScrollListCheck::setValue(const LLSD& value) { mCheckBox->setValue(value); } /*virtual*/ void LLScrollListCheck::onCommit() { mCheckBox->onCommit(); } /*virtual*/ void LLScrollListCheck::setEnabled(bool enable) { mCheckBox->setEnabled(enable); } // // LLScrollListDate // LLScrollListDate::LLScrollListDate( const LLScrollListCell::Params& p) : LLScrollListText(p), mDate(p.value().asDate()) {} void LLScrollListDate::setValue(const LLSD& value) { mDate = value.asDate(); LLScrollListText::setValue(mDate.asRFC1123()); } const LLSD LLScrollListDate::getValue() const { return mDate; } // // LLScrollListIconText // LLScrollListIconText::LLScrollListIconText(const LLScrollListCell::Params& p) : LLScrollListText(p), mIcon(p.value().isUUID() ? LLUI::getUIImageByID(p.value().asUUID()) : LLUI::getUIImage(p.value().asString())), mPad(4) { mTextWidth = getWidth() - mPad /*padding*/ - mFont->getLineHeight(); } LLScrollListIconText::~LLScrollListIconText() { } const LLSD LLScrollListIconText::getValue() const { if (mIcon.isNull()) { return LLStringUtil::null; } return mIcon->getName(); } void LLScrollListIconText::setValue(const LLSD& value) { if (value.isUUID()) { // don't use default image specified by LLUUID::null, use no image in that case LLUUID image_id = value.asUUID(); mIcon = image_id.notNull() ? LLUI::getUIImageByID(image_id) : LLUIImagePtr(NULL); } else { std::string value_string = value.asString(); if (LLUUID::validate(value_string)) { setValue(LLUUID(value_string)); } else if (!value_string.empty()) { mIcon = LLUI::getUIImage(value.asString()); } else { mIcon = NULL; } } } void LLScrollListIconText::setWidth(S32 width) { LLScrollListCell::setWidth(width); // Assume that iamge height and width is identical to font height and width mTextWidth = width - mPad /*padding*/ - mFont->getLineHeight(); } void LLScrollListIconText::draw(const LLColor4& color, const LLColor4& highlight_color) const { LLColor4 display_color; if (mUseColor) { display_color = mColor; } else { display_color = color; } S32 icon_height = mFont->getLineHeight(); S32 icon_space = mIcon ? (icon_height + mPad) : 0; if (mHighlightCount > 0) { S32 left = 0; switch (mFontAlignment) { case LLFontGL::LEFT: left = mFont->getWidth(mText.getWString().c_str(), icon_space + 1, mHighlightOffset); break; case LLFontGL::RIGHT: left = getWidth() - mFont->getWidth(mText.getWString().c_str(), mHighlightOffset, S32_MAX) - icon_space; break; case LLFontGL::HCENTER: left = (getWidth() - mFont->getWidth(mText.getWString().c_str()) - icon_space) / 2; break; } LLRect highlight_rect(left - 2, mFont->getLineHeight() + 1, left + mFont->getWidth(mText.getWString().c_str(), mHighlightOffset, mHighlightCount) + 1, 1); mRoundedRectImage->draw(highlight_rect, highlight_color); } // Try to draw the entire string F32 right_x; U32 string_chars = mText.length(); F32 start_text_x = 0.f; S32 start_icon_x = 0; switch (mFontAlignment) { case LLFontGL::LEFT: start_text_x = icon_space + 1.f; start_icon_x = 1; break; case LLFontGL::RIGHT: start_text_x = (F32)getWidth(); start_icon_x = getWidth() - mFont->getWidth(mText.getWString().c_str()) - icon_space; break; case LLFontGL::HCENTER: F32 center = (F32)getWidth()* 0.5f; start_text_x = center + ((F32)icon_space * 0.5f); start_icon_x = (S32)(center - (((F32)icon_space + mFont->getWidth(mText.getWString().c_str())) * 0.5f)); break; } mFont->render(mText.getWString(), 0, start_text_x, 0.f, display_color, mFontAlignment, LLFontGL::BOTTOM, 0, LLFontGL::NO_SHADOW, string_chars, getTextWidth(), &right_x, true); if (mIcon) { mIcon->draw(start_icon_x, 0, icon_height, icon_height, mColor); } }