summaryrefslogtreecommitdiff
path: root/indra/llui/llcombobox.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llui/llcombobox.cpp')
-rw-r--r--indra/llui/llcombobox.cpp841
1 files changed, 346 insertions, 495 deletions
diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp
index 538641d060..910bab9a97 100644
--- a/indra/llui/llcombobox.cpp
+++ b/indra/llui/llcombobox.cpp
@@ -2,30 +2,25 @@
* @file llcombobox.cpp
* @brief LLComboBox base class
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
- * 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
+ * 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.
*
- * 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
+ * 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.
*
- * 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.
+ * 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
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -47,179 +42,161 @@
#include "llwindow.h"
#include "llfloater.h"
#include "llscrollbar.h"
+#include "llscrolllistcell.h"
+#include "llscrolllistitem.h"
#include "llcontrol.h"
#include "llfocusmgr.h"
#include "lllineeditor.h"
#include "v2math.h"
+#include "lluictrlfactory.h"
+#include "lltooltip.h"
// Globals
S32 LLCOMBOBOX_HEIGHT = 0;
S32 LLCOMBOBOX_WIDTH = 0;
S32 MAX_COMBO_WIDTH = 500;
-static LLRegisterWidget<LLComboBox> r1("combo_box");
+static LLDefaultChildRegistry::Register<LLComboBox> register_combo_box("combo_box");
-LLComboBox::LLComboBox( const LLString& name, const LLRect &rect, const LLString& label,
- void (*commit_callback)(LLUICtrl*,void*),
- void *callback_userdata
- )
-: LLUICtrl(name, rect, TRUE, commit_callback, callback_userdata,
- FOLLOWS_LEFT | FOLLOWS_TOP),
- mTextEntry(NULL),
- mArrowImage(NULL),
- mAllowTextEntry(FALSE),
- mMaxChars(20),
- mTextEntryTentative(TRUE),
- mListPosition(BELOW),
- mPrearrangeCallback( NULL ),
- mTextEntryCallback( NULL )
+void LLComboBox::PreferredPositionValues::declareValues()
{
- // Always use text box
- // Text label button
- mButton = new LLButton(label,
- LLRect(),
- LLString::null,
- NULL, this);
- mButton->setImageUnselected("square_btn_32x128.tga");
- mButton->setImageSelected("square_btn_selected_32x128.tga");
- mButton->setImageDisabled("square_btn_32x128.tga");
- mButton->setImageDisabledSelected("square_btn_selected_32x128.tga");
- mButton->setScaleImage(TRUE);
-
- mButton->setMouseDownCallback(onButtonDown);
- mButton->setFont(LLFontGL::sSansSerifSmall);
- mButton->setFollows(FOLLOWS_LEFT | FOLLOWS_BOTTOM | FOLLOWS_RIGHT);
- mButton->setHAlign( LLFontGL::LEFT );
- mButton->setRightHPad(2);
- addChild(mButton);
-
- // disallow multiple selection
- mList = new LLScrollListCtrl(
- "ComboBox", LLRect(),
- &LLComboBox::onItemSelected, this, FALSE);
- mList->setVisible(FALSE);
- mList->setBgWriteableColor( LLColor4(1,1,1,1) );
- mList->setCommitOnKeyboardMovement(FALSE);
- addChild(mList);
-
- mArrowImage = LLUI::sImageProvider->getUIImage("combobox_arrow.tga");
- mButton->setImageOverlay("combobox_arrow.tga", LLFontGL::RIGHT);
+ declare("above", ABOVE);
+ declare("below", BELOW);
+}
- updateLayout();
+LLComboBox::ItemParams::ItemParams()
+: label("label")
+{
}
-LLComboBox::~LLComboBox()
+LLComboBox::Params::Params()
+: allow_text_entry("allow_text_entry", false),
+ allow_new_values("allow_new_values", false),
+ show_text_as_tentative("show_text_as_tentative", true),
+ max_chars("max_chars", 20),
+ list_position("list_position", BELOW),
+ items("item"),
+ combo_button("combo_button"),
+ combo_list("combo_list"),
+ combo_editor("combo_editor"),
+ drop_down_button("drop_down_button")
{
- // children automatically deleted, including mMenu, mButton
+ addSynonym(items, "combo_item");
}
-// virtual
-LLXMLNodePtr LLComboBox::getXML(bool save_children) const
+
+LLComboBox::LLComboBox(const LLComboBox::Params& p)
+: LLUICtrl(p),
+ mTextEntry(NULL),
+ mTextEntryTentative(p.show_text_as_tentative),
+ mHasAutocompletedText(false),
+ mAllowTextEntry(p.allow_text_entry),
+ mAllowNewValues(p.allow_new_values),
+ mMaxChars(p.max_chars),
+ mPrearrangeCallback(p.prearrange_callback()),
+ mTextEntryCallback(p.text_entry_callback()),
+ mListPosition(p.list_position),
+ mLastSelectedIndex(-1),
+ mLabel(p.label)
{
- LLXMLNodePtr node = LLUICtrl::getXML();
+ // Text label button
- // Attributes
+ LLButton::Params button_params = (mAllowTextEntry ? p.combo_button : p.drop_down_button);
+ button_params.mouse_down_callback.function(
+ boost::bind(&LLComboBox::onButtonMouseDown, this));
+ button_params.follows.flags(FOLLOWS_LEFT|FOLLOWS_BOTTOM|FOLLOWS_RIGHT);
+ button_params.rect(p.rect);
- node->createChild("allow_text_entry", TRUE)->setBoolValue(mAllowTextEntry);
+ if(mAllowTextEntry)
+ {
+ button_params.pad_right(2);
+ }
- node->createChild("max_chars", TRUE)->setIntValue(mMaxChars);
+ mArrowImage = button_params.image_unselected;
- // Contents
+ mButton = LLUICtrlFactory::create<LLButton>(button_params);
- std::vector<LLScrollListItem*> data_list = mList->getAllData();
- std::vector<LLScrollListItem*>::iterator data_itor;
- for (data_itor = data_list.begin(); data_itor != data_list.end(); ++data_itor)
+
+ if(mAllowTextEntry)
{
- LLScrollListItem* item = *data_itor;
- LLScrollListCell* cell = item->getColumn(0);
- if (cell)
- {
- LLXMLNodePtr item_node = node->createChild("combo_item", FALSE);
- LLSD value = item->getValue();
- item_node->createChild("value", TRUE)->setStringValue(value.asString());
- item_node->createChild("enabled", TRUE)->setBoolValue(item->getEnabled());
- item_node->setStringValue(cell->getValue().asString());
- }
+ //redo to compensate for button hack that leaves space for a character
+ //unless it is a "minimal combobox"(drop down)
+ mButton->setRightHPad(2);
}
+ addChild(mButton);
- return node;
-}
-
-// static
-LLView* LLComboBox::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
-{
- LLString name("combo_box");
- node->getAttributeString("name", name);
-
- LLString label("");
- node->getAttributeString("label", label);
+ LLScrollListCtrl::Params params = p.combo_list;
+ params.name("ComboBox");
+ params.commit_callback.function(boost::bind(&LLComboBox::onItemSelected, this, _2));
+ params.visible(false);
+ params.commit_on_keyboard_movement(false);
- LLRect rect;
- createRect(node, rect, parent, LLRect());
+ mList = LLUICtrlFactory::create<LLScrollListCtrl>(params);
+ addChild(mList);
- BOOL allow_text_entry = FALSE;
- node->getAttributeBOOL("allow_text_entry", allow_text_entry);
+ // Mouse-down on button will transfer mouse focus to the list
+ // Grab the mouse-up event and make sure the button state is correct
+ mList->setMouseUpCallback(boost::bind(&LLComboBox::onListMouseUp, this));
- S32 max_chars = 20;
- node->getAttributeS32("max_chars", max_chars);
+ for (LLInitParam::ParamIterator<ItemParams>::const_iterator it = p.items().begin();
+ it != p.items().end();
+ ++it)
+ {
+ LLScrollListItem::Params item_params = *it;
+ if (it->label.isProvided())
+ {
+ item_params.columns.add().value(it->label());
+ }
- LLUICtrlCallback callback = NULL;
+ mList->addRow(item_params);
+ }
- LLComboBox* combo_box = new LLComboBox(name,
- rect,
- label,
- callback,
- NULL);
- combo_box->setAllowTextEntry(allow_text_entry, max_chars);
+ createLineEditor(p);
- combo_box->initFromXML(node, parent);
+ mTopLostSignalConnection = setTopLostCallback(boost::bind(&LLComboBox::hideList, this));
+}
- const LLString& contents = node->getValue();
+void LLComboBox::initFromParams(const LLComboBox::Params& p)
+{
+ LLUICtrl::initFromParams(p);
- if (contents.find_first_not_of(" \n\t") != contents.npos)
+ if (!acceptsTextInput() && mLabel.empty())
{
- llerrs << "Legacy combo box item format used! Please convert to <combo_item> tags!" << llendl;
+ selectFirstItem();
}
- else
- {
- LLXMLNodePtr child;
- for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
- {
- if (child->hasName("combo_item"))
- {
- LLString label = child->getTextContents();
-
- LLString value = label;
- child->getAttributeString("value", value);
+}
- combo_box->add(label, LLSD(value) );
- }
- }
+// virtual
+BOOL LLComboBox::postBuild()
+{
+ if (mControlVariable)
+ {
+ setValue(mControlVariable->getValue()); // selects the appropriate item
}
-
- combo_box->selectFirstItem();
-
- return combo_box;
+ return TRUE;
}
-void LLComboBox::setEnabled(BOOL enabled)
+
+LLComboBox::~LLComboBox()
{
- LLView::setEnabled(enabled);
- mButton->setEnabled(enabled);
+ // children automatically deleted, including mMenu, mButton
+
+ // explicitly disconect this signal, since base class destructor might fire top lost
+ mTopLostSignalConnection.disconnect();
}
+
void LLComboBox::clear()
{
if (mTextEntry)
{
- mTextEntry->setText(LLString::null);
+ mTextEntry->setText(LLStringUtil::null);
}
- mButton->setLabelSelected(LLString::null);
- mButton->setLabelUnselected(LLString::null);
- mButton->setDisabledLabel(LLString::null);
- mButton->setDisabledSelectedLabel(LLString::null);
+ mButton->setLabelSelected(LLStringUtil::null);
+ mButton->setLabelUnselected(LLStringUtil::null);
mList->deselectAllItems();
+ mLastSelectedIndex = -1;
}
void LLComboBox::onCommit()
@@ -231,6 +208,7 @@ void LLComboBox::onCommit()
mTextEntry->setValue(getSimple());
mTextEntry->setTentative(FALSE);
}
+ setControlValue(getValue());
LLUICtrl::onCommit();
}
@@ -256,39 +234,51 @@ void LLComboBox::resetDirty()
// add item "name" to menu
-LLScrollListItem* LLComboBox::add(const LLString& name, EAddPosition pos, BOOL enabled)
+LLScrollListItem* LLComboBox::add(const std::string& name, EAddPosition pos, BOOL enabled)
{
LLScrollListItem* item = mList->addSimpleElement(name, pos);
item->setEnabled(enabled);
- mList->selectFirstItem();
+ if (!mAllowTextEntry && mLabel.empty())
+ {
+ selectFirstItem();
+ }
return item;
}
// add item "name" with a unique id to menu
-LLScrollListItem* LLComboBox::add(const LLString& name, const LLUUID& id, EAddPosition pos, BOOL enabled )
+LLScrollListItem* LLComboBox::add(const std::string& name, const LLUUID& id, EAddPosition pos, BOOL enabled )
{
LLScrollListItem* item = mList->addSimpleElement(name, pos, id);
item->setEnabled(enabled);
- mList->selectFirstItem();
+ if (!mAllowTextEntry && mLabel.empty())
+ {
+ selectFirstItem();
+ }
return item;
}
// add item "name" with attached userdata
-LLScrollListItem* LLComboBox::add(const LLString& name, void* userdata, EAddPosition pos, BOOL enabled )
+LLScrollListItem* LLComboBox::add(const std::string& name, void* userdata, EAddPosition pos, BOOL enabled )
{
LLScrollListItem* item = mList->addSimpleElement(name, pos);
item->setEnabled(enabled);
item->setUserdata( userdata );
- mList->selectFirstItem();
+ if (!mAllowTextEntry && mLabel.empty())
+ {
+ selectFirstItem();
+ }
return item;
}
// add item "name" with attached generic data
-LLScrollListItem* LLComboBox::add(const LLString& name, LLSD value, EAddPosition pos, BOOL enabled )
+LLScrollListItem* LLComboBox::add(const std::string& name, LLSD value, EAddPosition pos, BOOL enabled )
{
LLScrollListItem* item = mList->addSimpleElement(name, pos, value);
item->setEnabled(enabled);
- mList->selectFirstItem();
+ if (!mAllowTextEntry && mLabel.empty())
+ {
+ selectFirstItem();
+ }
return item;
}
@@ -297,9 +287,9 @@ LLScrollListItem* LLComboBox::addSeparator(EAddPosition pos)
return mList->addSeparator(pos);
}
-void LLComboBox::sortByName()
+void LLComboBox::sortByName(BOOL ascending)
{
- mList->sortByColumn(0, TRUE);
+ mList->sortOnce(0, ascending);
}
@@ -312,6 +302,7 @@ BOOL LLComboBox::setSimple(const LLStringExplicit& name)
if (found)
{
setLabel(name);
+ mLastSelectedIndex = mList->getFirstSelectedIndex();
}
return found;
@@ -326,14 +317,19 @@ void LLComboBox::setValue(const LLSD& value)
LLScrollListItem* item = mList->getFirstSelected();
if (item)
{
- setLabel( mList->getSelectedItemLabel() );
+ setLabel(getSelectedItemLabel());
}
+ mLastSelectedIndex = mList->getFirstSelectedIndex();
+ }
+ else
+ {
+ mLastSelectedIndex = -1;
}
}
-const LLString LLComboBox::getSimple() const
+const std::string LLComboBox::getSimple() const
{
- const LLString res = mList->getSelectedItemLabel();
+ const std::string res = getSelectedItemLabel();
if (res.empty() && mAllowTextEntry)
{
return mTextEntry->getText();
@@ -344,7 +340,7 @@ const LLString LLComboBox::getSimple() const
}
}
-const LLString LLComboBox::getSelectedItemLabel(S32 column) const
+const std::string LLComboBox::getSelectedItemLabel(S32 column) const
{
return mList->getSelectedItemLabel(column);
}
@@ -375,6 +371,7 @@ void LLComboBox::setLabel(const LLStringExplicit& name)
if (mList->selectItemByLabel(name, FALSE))
{
mTextEntry->setTentative(FALSE);
+ mLastSelectedIndex = mList->getFirstSelectedIndex();
}
else
{
@@ -384,15 +381,12 @@ void LLComboBox::setLabel(const LLStringExplicit& name)
if (!mAllowTextEntry)
{
- mButton->setLabelUnselected(name);
- mButton->setLabelSelected(name);
- mButton->setDisabledLabel(name);
- mButton->setDisabledSelectedLabel(name);
+ mButton->setLabel(name);
}
}
-BOOL LLComboBox::remove(const LLString& name)
+BOOL LLComboBox::remove(const std::string& name)
{
BOOL found = mList->selectItemByLabel(name);
@@ -403,6 +397,7 @@ BOOL LLComboBox::remove(const LLString& name)
{
mList->deleteSingleItem(mList->getItemIndex(item));
}
+ mLastSelectedIndex = mList->getFirstSelectedIndex();
}
return found;
@@ -413,6 +408,7 @@ BOOL LLComboBox::remove(S32 index)
if (index < mList->getItemCount())
{
mList->deleteSingleItem(index);
+ setLabel(getSelectedItemLabel());
return TRUE;
}
return FALSE;
@@ -430,41 +426,31 @@ void LLComboBox::onFocusLost()
LLUICtrl::onFocusLost();
}
-void LLComboBox::onLostTop()
-{
- hideList();
-}
-
-
void LLComboBox::setButtonVisible(BOOL visible)
{
+ static LLUICachedControl<S32> drop_shadow_button ("DropShadowButton", 0);
+
mButton->setVisible(visible);
if (mTextEntry)
{
LLRect text_entry_rect(0, getRect().getHeight(), getRect().getWidth(), 0);
if (visible)
{
- text_entry_rect.mRight -= llmax(8,mArrowImage->getWidth()) + 2 * LLUI::sConfigGroup->getS32("DropShadowButton");
+ S32 arrow_width = mArrowImage ? mArrowImage->getWidth() : 0;
+ text_entry_rect.mRight -= llmax(8,arrow_width) + 2 * drop_shadow_button;
}
//mTextEntry->setRect(text_entry_rect);
mTextEntry->reshape(text_entry_rect.getWidth(), text_entry_rect.getHeight(), TRUE);
}
}
-void LLComboBox::draw()
-{
- mButton->setEnabled(getEnabled() /*&& !mList->isEmpty()*/);
-
- // Draw children normally
- LLUICtrl::draw();
-}
-
BOOL LLComboBox::setCurrentByIndex( S32 index )
{
BOOL found = mList->selectNthItem( index );
if (found)
{
- setLabel(mList->getSelectedItemLabel());
+ setLabel(getSelectedItemLabel());
+ mLastSelectedIndex = index;
}
return found;
}
@@ -480,55 +466,49 @@ S32 LLComboBox::getCurrentIndex() const
}
-void LLComboBox::updateLayout()
+void LLComboBox::createLineEditor(const LLComboBox::Params& p)
{
+ static LLUICachedControl<S32> drop_shadow_button ("DropShadowButton", 0);
LLRect rect = getLocalRect();
if (mAllowTextEntry)
{
- S32 shadow_size = LLUI::sConfigGroup->getS32("DropShadowButton");
- mButton->setRect(LLRect( getRect().getWidth() - llmax(8,mArrowImage->getWidth()) - 2 * shadow_size,
+ S32 arrow_width = mArrowImage ? mArrowImage->getWidth() : 0;
+ S32 shadow_size = drop_shadow_button;
+ mButton->setRect(LLRect( getRect().getWidth() - llmax(8,arrow_width) - 2 * shadow_size,
rect.mTop, rect.mRight, rect.mBottom));
mButton->setTabStop(FALSE);
+ mButton->setHAlign(LLFontGL::HCENTER);
- if (!mTextEntry)
- {
- LLRect text_entry_rect(0, getRect().getHeight(), getRect().getWidth(), 0);
- text_entry_rect.mRight -= llmax(8,mArrowImage->getWidth()) + 2 * LLUI::sConfigGroup->getS32("DropShadowButton");
- // clear label on button
- LLString cur_label = mButton->getLabelSelected();
- mTextEntry = new LLLineEditor("combo_text_entry",
- text_entry_rect,
- "",
- LLFontGL::sSansSerifSmall,
- mMaxChars,
- onTextCommit,
- onTextEntry,
- NULL,
- this);
- mTextEntry->setSelectAllonFocusReceived(TRUE);
- mTextEntry->setHandleEditKeysDirectly(TRUE);
- mTextEntry->setCommitOnFocusLost(FALSE);
- mTextEntry->setText(cur_label);
- mTextEntry->setIgnoreTab(TRUE);
- mTextEntry->setFollowsAll();
- addChild(mTextEntry);
- }
- else
- {
- mTextEntry->setVisible(TRUE);
- mTextEntry->setMaxTextLength(mMaxChars);
- }
+ LLRect text_entry_rect(0, getRect().getHeight(), getRect().getWidth(), 0);
+ text_entry_rect.mRight -= llmax(8,arrow_width) + 2 * drop_shadow_button;
+ // clear label on button
+ std::string cur_label = mButton->getLabelSelected();
+ LLLineEditor::Params params = p.combo_editor;
+ params.rect(text_entry_rect);
+ params.default_text(LLStringUtil::null);
+ params.max_length_bytes(mMaxChars);
+ params.commit_callback.function(boost::bind(&LLComboBox::onTextCommit, this, _2));
+ params.keystroke_callback(boost::bind(&LLComboBox::onTextEntry, this, _1));
+ params.commit_on_focus_lost(false);
+ params.follows.flags(FOLLOWS_ALL);
+ params.label(mLabel);
+ mTextEntry = LLUICtrlFactory::create<LLLineEditor> (params);
+ mTextEntry->setText(cur_label);
+ mTextEntry->setIgnoreTab(TRUE);
+ addChild(mTextEntry);
// clear label on button
- setLabel(LLString::null);
+ setLabel(LLStringUtil::null);
mButton->setFollows(FOLLOWS_BOTTOM | FOLLOWS_TOP | FOLLOWS_RIGHT);
}
- else if (!mAllowTextEntry)
+ else
{
mButton->setRect(rect);
mButton->setTabStop(TRUE);
-
+ mButton->setHAlign(LLFontGL::LEFT);
+ mButton->setLabel(mLabel.getString());
+
if (mTextEntry)
{
mTextEntry->setVisible(FALSE);
@@ -632,140 +612,131 @@ void LLComboBox::showList()
mList->setFocus(TRUE);
- // register ourselves as a "top" control
- // effectively putting us into a special draw layer
- // and not affecting the bounding rectangle calculation
- gFocusMgr.setTopCtrl(this);
-
// Show the list and push the button down
mButton->setToggleState(TRUE);
mList->setVisible(TRUE);
+ LLUI::addPopup(this);
+
setUseBoundingRect(TRUE);
+// updateBoundingRect();
}
void LLComboBox::hideList()
{
- //*HACK: store the original value explicitly somewhere, not just in label
- LLString orig_selection = mAllowTextEntry ? mTextEntry->getText() : mButton->getLabelSelected();
-
- // assert selection in list
- mList->selectItemByLabel(orig_selection, FALSE);
+ if (mList->getVisible())
+ {
+ // assert selection in list
+ if(mAllowNewValues)
+ {
+ // mLastSelectedIndex = -1 means that we entered a new value, don't select
+ // any of existing items in this case.
+ if(mLastSelectedIndex >= 0)
+ mList->selectNthItem(mLastSelectedIndex);
+ }
+ else if(mLastSelectedIndex >= 0)
+ mList->selectNthItem(mLastSelectedIndex);
- mButton->setToggleState(FALSE);
- mList->setVisible(FALSE);
- mList->highlightNthItem(-1);
+ mButton->setToggleState(FALSE);
+ mList->setVisible(FALSE);
+ mList->mouseOverHighlightNthItem(-1);
- setUseBoundingRect(FALSE);
- if( gFocusMgr.getTopCtrl() == this )
- {
- gFocusMgr.setTopCtrl(NULL);
+ setUseBoundingRect(FALSE);
+ LLUI::removePopup(this);
+// updateBoundingRect();
}
}
-//------------------------------------------------------------------
-// static functions
-//------------------------------------------------------------------
-
-// static
-void LLComboBox::onButtonDown(void *userdata)
+void LLComboBox::onButtonMouseDown()
{
- LLComboBox *self = (LLComboBox *)userdata;
-
- if (!self->mList->getVisible())
+ if (!mList->getVisible())
{
- LLScrollListItem* last_selected_item = self->mList->getLastSelectedItem();
- if (last_selected_item)
- {
- // highlight the original selection before potentially selecting a new item
- self->mList->highlightNthItem(self->mList->getItemIndex(last_selected_item));
- }
+ // this might change selection, so do it first
+ prearrangeList();
- if( self->mPrearrangeCallback )
+ // highlight the last selected item from the original selection before potentially selecting a new item
+ // as visual cue to original value of combo box
+ LLScrollListItem* last_selected_item = mList->getLastSelectedItem();
+ if (last_selected_item)
{
- self->mPrearrangeCallback( self, self->mCallbackUserData );
+ mList->mouseOverHighlightNthItem(mList->getItemIndex(last_selected_item));
}
- if (self->mList->getItemCount() != 0)
+ if (mList->getItemCount() != 0)
{
- self->showList();
+ showList();
}
- self->setFocus( TRUE );
+ setFocus( TRUE );
// pass mouse capture on to list if button is depressed
- if (self->mButton->hasMouseCapture())
+ if (mButton->hasMouseCapture())
{
- gFocusMgr.setMouseCapture(self->mList);
+ gFocusMgr.setMouseCapture(mList);
+
+ // But keep the "pressed" look, which buttons normally lose when they
+ // lose focus
+ mButton->setForcePressedState(true);
}
}
else
{
- self->hideList();
+ hideList();
}
}
-// static
-void LLComboBox::onItemSelected(LLUICtrl* item, void *userdata)
+void LLComboBox::onListMouseUp()
{
- // Note: item is the LLScrollListCtrl
- LLComboBox *self = (LLComboBox *) userdata;
+ // In some cases this is the termination of a mouse click that started on
+ // the button, so clear its pressed state
+ mButton->setForcePressedState(false);
+}
- const LLString name = self->mList->getSelectedItemLabel();
+//------------------------------------------------------------------
+// static functions
+//------------------------------------------------------------------
- S32 cur_id = self->getCurrentIndex();
- if (cur_id != -1)
+void LLComboBox::onItemSelected(const LLSD& data)
+{
+ mLastSelectedIndex = getCurrentIndex();
+ if (mLastSelectedIndex != -1)
{
- self->setLabel(name);
+ setLabel(getSelectedItemLabel());
- if (self->mAllowTextEntry)
+ if (mAllowTextEntry)
{
- gFocusMgr.setKeyboardFocus(self->mTextEntry);
- self->mTextEntry->selectAll();
+ gFocusMgr.setKeyboardFocus(mTextEntry);
+ mTextEntry->selectAll();
}
}
-
// hiding the list reasserts the old value stored in the text editor/dropdown button
- self->hideList();
+ hideList();
// commit does the reverse, asserting the value in the list
- self->onCommit();
+ onCommit();
}
-BOOL LLComboBox::handleToolTip(S32 x, S32 y, LLString& msg, LLRect* sticky_rect_screen)
+BOOL LLComboBox::handleToolTip(S32 x, S32 y, MASK mask)
{
- LLString tool_tip;
+ std::string tool_tip;
- if(LLUICtrl::handleToolTip(x, y, msg, sticky_rect_screen))
+ if(LLUICtrl::handleToolTip(x, y, mask))
{
return TRUE;
}
- if (LLUI::sShowXUINames)
- {
- tool_tip = getShowNamesToolTip();
- }
- else
+ tool_tip = getToolTip();
+ if (tool_tip.empty())
{
- tool_tip = getToolTip();
- if (tool_tip.empty())
- {
- tool_tip = getSelectedItemLabel();
- }
+ tool_tip = getSelectedItemLabel();
}
if( !tool_tip.empty() )
{
- msg = tool_tip;
-
- // Convert rect local to screen coordinates
- localPointToScreen(
- 0, 0,
- &(sticky_rect_screen->mLeft), &(sticky_rect_screen->mBottom) );
- localPointToScreen(
- getRect().getWidth(), getRect().getHeight(),
- &(sticky_rect_screen->mRight), &(sticky_rect_screen->mTop) );
+ LLToolTipMgr::instance().show(LLToolTip::Params()
+ .message(tool_tip)
+ .sticky_rect(calcScreenRect()));
}
return TRUE;
}
@@ -775,16 +746,32 @@ BOOL LLComboBox::handleKeyHere(KEY key, MASK mask)
BOOL result = FALSE;
if (hasFocus())
{
+ if (mList->getVisible()
+ && key == KEY_ESCAPE && mask == MASK_NONE)
+ {
+ hideList();
+ return TRUE;
+ }
//give list a chance to pop up and handle key
LLScrollListItem* last_selected_item = mList->getLastSelectedItem();
if (last_selected_item)
{
// highlight the original selection before potentially selecting a new item
- mList->highlightNthItem(mList->getItemIndex(last_selected_item));
+ mList->mouseOverHighlightNthItem(mList->getItemIndex(last_selected_item));
}
result = mList->handleKeyHere(key, mask);
+
+ // will only see return key if it is originating from line editor
+ // since the dropdown button eats the key
+ if (key == KEY_RETURN)
+ {
+ // don't show list and don't eat key input when committing
+ // free-form text entry with RETURN since user already knows
+ // what they are trying to select
+ return FALSE;
+ }
// if selection has changed, pop open list
- if (mList->getLastSelectedItem() != last_selected_item)
+ else if (mList->getLastSelectedItem() != last_selected_item)
{
showList();
}
@@ -804,7 +791,7 @@ BOOL LLComboBox::handleUnicodeCharHere(llwchar uni_char)
if (last_selected_item)
{
// highlight the original selection before potentially selecting a new item
- mList->highlightNthItem(mList->getItemIndex(last_selected_item));
+ mList->mouseOverHighlightNthItem(mList->getItemIndex(last_selected_item));
}
result = mList->handleUnicodeCharHere(uni_char);
if (mList->getLastSelectedItem() != last_selected_item)
@@ -816,46 +803,37 @@ BOOL LLComboBox::handleUnicodeCharHere(llwchar uni_char)
return result;
}
-void LLComboBox::setAllowTextEntry(BOOL allow, S32 max_chars, BOOL set_tentative)
-{
- mAllowTextEntry = allow;
- mTextEntryTentative = set_tentative;
- mMaxChars = max_chars;
-
- updateLayout();
-}
-
void LLComboBox::setTextEntry(const LLStringExplicit& text)
{
if (mTextEntry)
{
mTextEntry->setText(text);
+ mHasAutocompletedText = FALSE;
updateSelection();
}
}
-//static
-void LLComboBox::onTextEntry(LLLineEditor* line_editor, void* user_data)
+void LLComboBox::onTextEntry(LLLineEditor* line_editor)
{
- LLComboBox* self = (LLComboBox*)user_data;
-
- if (self->mTextEntryCallback)
+ if (mTextEntryCallback != NULL)
{
- (*self->mTextEntryCallback)(line_editor, self->mCallbackUserData);
+ (mTextEntryCallback)(line_editor, LLSD());
}
KEY key = gKeyboard->currentKey();
if (key == KEY_BACKSPACE ||
key == KEY_DELETE)
{
- if (self->mList->selectItemByLabel(line_editor->getText(), FALSE))
+ if (mList->selectItemByLabel(line_editor->getText(), FALSE))
{
line_editor->setTentative(FALSE);
+ mLastSelectedIndex = mList->getFirstSelectedIndex();
}
else
{
- line_editor->setTentative(self->mTextEntryTentative);
- self->mList->deselectAllItems();
+ line_editor->setTentative(mTextEntryTentative);
+ mList->deselectAllItems();
+ mLastSelectedIndex = -1;
}
return;
}
@@ -868,17 +846,14 @@ void LLComboBox::onTextEntry(LLLineEditor* line_editor, void* user_data)
if (key == KEY_DOWN)
{
- self->setCurrentByIndex(llmin(self->getItemCount() - 1, self->getCurrentIndex() + 1));
- if (!self->mList->getVisible())
+ setCurrentByIndex(llmin(getItemCount() - 1, getCurrentIndex() + 1));
+ if (!mList->getVisible())
{
- if( self->mPrearrangeCallback )
- {
- self->mPrearrangeCallback( self, self->mCallbackUserData );
- }
+ prearrangeList();
- if (self->mList->getItemCount() != 0)
+ if (mList->getItemCount() != 0)
{
- self->showList();
+ showList();
}
}
line_editor->selectAll();
@@ -886,17 +861,14 @@ void LLComboBox::onTextEntry(LLLineEditor* line_editor, void* user_data)
}
else if (key == KEY_UP)
{
- self->setCurrentByIndex(llmax(0, self->getCurrentIndex() - 1));
- if (!self->mList->getVisible())
+ setCurrentByIndex(llmax(0, getCurrentIndex() - 1));
+ if (!mList->getVisible())
{
- if( self->mPrearrangeCallback )
- {
- self->mPrearrangeCallback( self, self->mCallbackUserData );
- }
+ prearrangeList();
- if (self->mList->getItemCount() != 0)
+ if (mList->getItemCount() != 0)
{
- self->showList();
+ showList();
}
}
line_editor->selectAll();
@@ -905,7 +877,7 @@ void LLComboBox::onTextEntry(LLLineEditor* line_editor, void* user_data)
else
{
// RN: presumably text entry
- self->updateSelection();
+ updateSelection();
}
}
@@ -914,49 +886,49 @@ void LLComboBox::updateSelection()
LLWString left_wstring = mTextEntry->getWText().substr(0, mTextEntry->getCursor());
// user-entered portion of string, based on assumption that any selected
// text was a result of auto-completion
- LLWString user_wstring = mTextEntry->hasSelection() ? left_wstring : mTextEntry->getWText();
- LLString full_string = mTextEntry->getText();
+ LLWString user_wstring = mHasAutocompletedText ? left_wstring : mTextEntry->getWText();
+ std::string full_string = mTextEntry->getText();
// go ahead and arrange drop down list on first typed character, even
// though we aren't showing it... some code relies on prearrange
// callback to populate content
if( mTextEntry->getWText().size() == 1 )
{
- if (mPrearrangeCallback)
- {
- mPrearrangeCallback( this, mCallbackUserData );
- }
+ prearrangeList(mTextEntry->getText());
}
if (mList->selectItemByLabel(full_string, FALSE))
{
mTextEntry->setTentative(FALSE);
+ mLastSelectedIndex = mList->getFirstSelectedIndex();
}
- else if (!mList->selectItemByPrefix(left_wstring, FALSE))
- {
- mList->deselectAllItems();
- mTextEntry->setText(wstring_to_utf8str(user_wstring));
- mTextEntry->setTentative(mTextEntryTentative);
- }
- else
+ else if (mList->selectItemByPrefix(left_wstring, FALSE))
{
- LLWString selected_item = utf8str_to_wstring(mList->getSelectedItemLabel());
+ LLWString selected_item = utf8str_to_wstring(getSelectedItemLabel());
LLWString wtext = left_wstring + selected_item.substr(left_wstring.size(), selected_item.size());
mTextEntry->setText(wstring_to_utf8str(wtext));
mTextEntry->setSelection(left_wstring.size(), mTextEntry->getWText().size());
mTextEntry->endSelection();
mTextEntry->setTentative(FALSE);
+ mHasAutocompletedText = TRUE;
+ mLastSelectedIndex = mList->getFirstSelectedIndex();
+ }
+ else // no matching items found
+ {
+ mList->deselectAllItems();
+ mTextEntry->setText(wstring_to_utf8str(user_wstring)); // removes text added by autocompletion
+ mTextEntry->setTentative(mTextEntryTentative);
+ mHasAutocompletedText = FALSE;
+ mLastSelectedIndex = -1;
}
}
-//static
-void LLComboBox::onTextCommit(LLUICtrl* caller, void* user_data)
+void LLComboBox::onTextCommit(const LLSD& data)
{
- LLComboBox* self = (LLComboBox*)user_data;
- LLString text = self->mTextEntry->getText();
- self->setSimple(text);
- self->onCommit();
- self->mTextEntry->selectAll();
+ std::string text = mTextEntry->getText();
+ setSimple(text);
+ onCommit();
+ mTextEntry->selectAll();
}
void LLComboBox::setFocus(BOOL b)
@@ -973,6 +945,14 @@ void LLComboBox::setFocus(BOOL b)
}
}
+void LLComboBox::prearrangeList(std::string filter)
+{
+ if (mPrearrangeCallback)
+ {
+ mPrearrangeCallback(this, LLSD(filter));
+ }
+}
+
//============================================================================
// LLCtrlListInterface functions
@@ -992,7 +972,7 @@ void LLComboBox::clearColumns()
mList->clearColumns();
}
-void LLComboBox::setColumnLabel(const LLString& column, const LLString& label)
+void LLComboBox::setColumnLabel(const std::string& column, const std::string& label)
{
mList->setColumnLabel(column, label);
}
@@ -1002,7 +982,7 @@ LLScrollListItem* LLComboBox::addElement(const LLSD& value, EAddPosition pos, vo
return mList->addElement(value, pos, userdata);
}
-LLScrollListItem* LLComboBox::addSimpleElement(const LLString& value, EAddPosition pos, const LLSD& id)
+LLScrollListItem* LLComboBox::addSimpleElement(const std::string& value, EAddPosition pos, const LLSD& id)
{
return mList->addSimpleElement(value, pos, id);
}
@@ -1012,8 +992,9 @@ void LLComboBox::clearRows()
mList->clearRows();
}
-void LLComboBox::sortByColumn(LLString name, BOOL ascending)
+void LLComboBox::sortByColumn(const std::string& name, BOOL ascending)
{
+ mList->sortByColumn(name, ascending);
}
//============================================================================
@@ -1025,7 +1006,8 @@ BOOL LLComboBox::setCurrentByID(const LLUUID& id)
if (found)
{
- setLabel(mList->getSelectedItemLabel());
+ setLabel(getSelectedItemLabel());
+ mLastSelectedIndex = mList->getFirstSelectedIndex();
}
return found;
@@ -1040,7 +1022,7 @@ BOOL LLComboBox::setSelectedByValue(const LLSD& value, BOOL selected)
BOOL found = mList->setSelectedByValue(value, selected);
if (found)
{
- setLabel(mList->getSelectedItemLabel());
+ setLabel(getSelectedItemLabel());
}
return found;
}
@@ -1081,153 +1063,22 @@ BOOL LLComboBox::selectItemRange( S32 first, S32 last )
}
-//
-// LLFlyoutButton
-//
-
-static LLRegisterWidget<LLFlyoutButton> r2("flyout_button");
+static LLDefaultChildRegistry::Register<LLIconsComboBox> register_icons_combo_box("icons_combo_box");
-const S32 FLYOUT_BUTTON_ARROW_WIDTH = 24;
+LLIconsComboBox::Params::Params()
+: icon_column("icon_column", ICON_COLUMN),
+ label_column("label_column", LABEL_COLUMN)
+{}
-LLFlyoutButton::LLFlyoutButton(
- const LLString& name,
- const LLRect &rect,
- const LLString& label,
- void (*commit_callback)(LLUICtrl*, void*) ,
- void *callback_userdata)
-: LLComboBox(name, rect, LLString::null, commit_callback, callback_userdata),
- mToggleState(FALSE),
- mActionButton(NULL)
-{
- // Always use text box
- // Text label button
- mActionButton = new LLButton(label,
- LLRect(), LLString::null, NULL, this);
- mActionButton->setScaleImage(TRUE);
-
- mActionButton->setClickedCallback(onActionButtonClick);
- mActionButton->setFollowsAll();
- mActionButton->setHAlign( LLFontGL::HCENTER );
- mActionButton->setLabel(label);
- addChild(mActionButton);
-
- mActionButtonImage = LLUI::getUIImage("flyout_btn_left.tga");
- mExpanderButtonImage = LLUI::getUIImage("flyout_btn_right.tga");
- mActionButtonImageSelected = LLUI::getUIImage("flyout_btn_left_selected.tga");
- mExpanderButtonImageSelected = LLUI::getUIImage("flyout_btn_right_selected.tga");
- mActionButtonImageDisabled = LLUI::getUIImage("flyout_btn_left_disabled.tga");
- mExpanderButtonImageDisabled = LLUI::getUIImage("flyout_btn_right_disabled.tga");
-
- mActionButton->setImageSelected(mActionButtonImageSelected);
- mActionButton->setImageUnselected(mActionButtonImage);
- mActionButton->setImageDisabled(mActionButtonImageDisabled);
- mActionButton->setImageDisabledSelected(LLPointer<LLUIImage>(NULL));
-
- mButton->setImageSelected(mExpanderButtonImageSelected);
- mButton->setImageUnselected(mExpanderButtonImage);
- mButton->setImageDisabled(mExpanderButtonImageDisabled);
- mButton->setImageDisabledSelected(LLPointer<LLUIImage>(NULL));
- mButton->setRightHPad(6);
-
- updateLayout();
-}
+LLIconsComboBox::LLIconsComboBox(const LLIconsComboBox::Params& p)
+: LLComboBox(p),
+ mIconColumnIndex(p.icon_column),
+ mLabelColumnIndex(p.label_column)
+{}
-//static
-LLView* LLFlyoutButton::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
+const std::string LLIconsComboBox::getSelectedItemLabel(S32 column) const
{
- LLString name = "flyout_button";
- node->getAttributeString("name", name);
-
- LLString label("");
- node->getAttributeString("label", label);
-
- LLRect rect;
- createRect(node, rect, parent, LLRect());
-
- LLUICtrlCallback callback = NULL;
-
- LLFlyoutButton* flyout_button = new LLFlyoutButton(name,
- rect,
- label,
- callback,
- NULL);
+ mButton->setImageOverlay(LLComboBox::getSelectedItemLabel(mIconColumnIndex), mButton->getImageOverlayHAlign());
- LLString list_position;
- node->getAttributeString("list_position", list_position);
- if (list_position == "below")
- {
- flyout_button->mListPosition = BELOW;
- }
- else if (list_position == "above")
- {
- flyout_button->mListPosition = ABOVE;
- }
-
-
- flyout_button->initFromXML(node, parent);
-
- LLXMLNodePtr child;
- for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling())
- {
- if (child->hasName("flyout_button_item"))
- {
- LLString label = child->getTextContents();
-
- LLString value = label;
- child->getAttributeString("value", value);
-
- flyout_button->add(label, LLSD(value) );
- }
- }
-
- flyout_button->updateLayout();
-
- return flyout_button;
-}
-
-void LLFlyoutButton::updateLayout()
-{
- LLComboBox::updateLayout();
-
- mButton->setOrigin(getRect().getWidth() - FLYOUT_BUTTON_ARROW_WIDTH, 0);
- mButton->reshape(FLYOUT_BUTTON_ARROW_WIDTH, getRect().getHeight());
- mButton->setFollows(FOLLOWS_RIGHT | FOLLOWS_TOP | FOLLOWS_BOTTOM);
- mButton->setTabStop(FALSE);
- mButton->setImageOverlay(mListPosition == BELOW ? "down_arrow.tga" : "up_arrow.tga", LLFontGL::RIGHT);
-
- mActionButton->setOrigin(0, 0);
- mActionButton->reshape(getRect().getWidth() - FLYOUT_BUTTON_ARROW_WIDTH, getRect().getHeight());
-}
-
-//static
-void LLFlyoutButton::onActionButtonClick(void *user_data)
-{
- LLFlyoutButton* buttonp = (LLFlyoutButton*)user_data;
- // remember last list selection?
- buttonp->mList->deselect();
- buttonp->onCommit();
+ return LLComboBox::getSelectedItemLabel(mLabelColumnIndex);
}
-
-void LLFlyoutButton::draw()
-{
- mActionButton->setToggleState(mToggleState);
- mButton->setToggleState(mToggleState);
-
- //FIXME: this should be an attribute of comboboxes, whether they have a distinct label or
- // the label reflects the last selected item, for now we have to manually remove the label
- mButton->setLabel(LLString::null);
- LLComboBox::draw();
-}
-
-void LLFlyoutButton::setEnabled(BOOL enabled)
-{
- mActionButton->setEnabled(enabled);
- LLComboBox::setEnabled(enabled);
-}
-
-
-void LLFlyoutButton::setToggleState(BOOL state)
-{
- mToggleState = state;
-}
-