diff options
author | James Cook <james@lindenlab.com> | 2007-01-02 08:33:20 +0000 |
---|---|---|
committer | James Cook <james@lindenlab.com> | 2007-01-02 08:33:20 +0000 |
commit | 420b91db29485df39fd6e724e782c449158811cb (patch) | |
tree | b471a94563af914d3ed3edd3e856d21cb1b69945 /indra/llui/llcombobox.cpp |
Print done when done.
Diffstat (limited to 'indra/llui/llcombobox.cpp')
-rw-r--r-- | indra/llui/llcombobox.cpp | 1133 |
1 files changed, 1133 insertions, 0 deletions
diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp new file mode 100644 index 0000000000..84c5d354be --- /dev/null +++ b/indra/llui/llcombobox.cpp @@ -0,0 +1,1133 @@ +/** + * @file llcombobox.cpp + * @brief LLComboBox base class + * + * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc. + * $License$ + */ + +// A control that displays the name of the chosen item, which when +// clicked shows a scrolling box of options. + +#include "linden_common.h" + +// file includes +#include "llcombobox.h" + +// common includes +#include "llstring.h" + +// newview includes +#include "llbutton.h" +#include "llkeyboard.h" +#include "llscrolllistctrl.h" +#include "llwindow.h" +#include "llfloater.h" +#include "llscrollbar.h" +#include "llcontrol.h" +#include "llfocusmgr.h" +#include "lllineeditor.h" +#include "v2math.h" + +// Globals +S32 LLCOMBOBOX_HEIGHT = 0; +S32 LLCOMBOBOX_WIDTH = 0; + +LLComboBox::LLComboBox( const LLString& name, const LLRect &rect, const LLString& label, + void (*commit_callback)(LLUICtrl*,void*), + void *callback_userdata, + S32 list_width + ) +: LLUICtrl(name, rect, TRUE, commit_callback, callback_userdata, + FOLLOWS_LEFT | FOLLOWS_TOP), + mDrawButton(TRUE), + mTextEntry(NULL), + mArrowImage(NULL), + mAllowTextEntry(FALSE), + mMaxChars(20), + mTextEntryTentative(TRUE), + mPrearrangeCallback( NULL ), + mTextEntryCallback( NULL ), + mListWidth(list_width) +{ + // For now, all comboboxes don't take keyboard focus when clicked. + // This might change if it is part of a modal dialog. + // mKeyboardFocusOnClick = FALSE; + + // Revert to standard behavior. When this control's parent is hidden, it needs to + // hide this ctrl--which won't just happen automatically since when LLComboBox is + // showing its list, it's also set to TopView. When keyboard focus is cleared all + // controls (including this one) know that they are no longer editing. + mKeyboardFocusOnClick = TRUE; + + LLRect r; + r.setOriginAndSize(0, 0, rect.getWidth(), rect.getHeight()); + + // Always use text box + // Text label button + mButton = new LLSquareButton("comboxbox button", + r, label, NULL, LLString::null, + &LLComboBox::onButtonClick, this); + mButton->setFont(LLFontGL::sSansSerifSmall); + mButton->setFollows(FOLLOWS_LEFT | FOLLOWS_BOTTOM | FOLLOWS_RIGHT); + mButton->setHAlign( LLFontGL::LEFT ); + + const S32 ARROW_WIDTH = 16; + mButton->setRightHPad( ARROW_WIDTH ); + addChild(mButton); + + // Default size, will be set by arrange() call in button callback. + if (list_width == 0) + { + list_width = mRect.getWidth() + SCROLLBAR_SIZE; + } + r.setOriginAndSize(0, 16, list_width, 220); + + // disallow multiple selection + mList = new LLScrollListCtrl( + "ComboBox", r, + &LLComboBox::onItemSelected, this, FALSE); + mList->setVisible(FALSE); + mList->setBgWriteableColor( LLColor4(1,1,1,1) ); + mList->setCommitOnKeyboardMovement(FALSE); + addChild(mList); + + LLRect border_rect(0, mRect.getHeight(), mRect.getWidth(), 0); + mBorder = new LLViewBorder( "combo border", border_rect ); + addChild( mBorder ); + mBorder->setFollows(FOLLOWS_LEFT|FOLLOWS_RIGHT|FOLLOWS_TOP|FOLLOWS_BOTTOM); + + LLUUID arrow_image_id( LLUI::sAssetsGroup->getString("combobox_arrow.tga") ); + mArrowImage = LLUI::sImageProvider->getUIImageByID(arrow_image_id); +} + + +LLComboBox::~LLComboBox() +{ + // children automatically deleted, including mMenu, mButton +} + +// virtual +LLXMLNodePtr LLComboBox::getXML(bool save_children) const +{ + LLXMLNodePtr node = LLUICtrl::getXML(); + + // Attributes + + node->createChild("allow_text_entry", TRUE)->setBoolValue(mAllowTextEntry); + + node->createChild("max_chars", TRUE)->setIntValue(mMaxChars); + + // Contents + + 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) + { + 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->getText()); + } + } + + 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); + + LLRect rect; + createRect(node, rect, parent, LLRect()); + + BOOL allow_text_entry = FALSE; + node->getAttributeBOOL("allow_text_entry", allow_text_entry); + + S32 max_chars = 20; + node->getAttributeS32("max_chars", max_chars); + + LLUICtrlCallback callback = NULL; + + LLComboBox* combo_box = new LLComboBox(name, + rect, + label, + callback, + NULL); + combo_box->setAllowTextEntry(allow_text_entry, max_chars); + + combo_box->initFromXML(node, parent); + + const LLString& contents = node->getValue(); + + if (contents.find_first_not_of(" \n\t") != contents.npos) + { + llerrs << "Legacy combo box item format used! Please convert to <combo_item> tags!" << llendl; + } + 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) ); + } + } + } + + combo_box->selectFirstItem(); + + return combo_box; +} + +void LLComboBox::setEnabled(BOOL enabled) +{ + LLUICtrl::setEnabled(enabled); + mButton->setEnabled(enabled); +} + +//FIXME: these are all hacks to support the fact that the combobox has mouse capture +// so we can hide the list when we don't handle the mouse up event +BOOL LLComboBox::handleHover(S32 x, S32 y, MASK mask) +{ + if (mList->getVisible()) + { + S32 local_x, local_y; + LLView::localPointToOtherView(x, y, &local_x, &local_y, mList); + if (mList->pointInView(local_x, local_y)) + { + return mList->handleHover(local_x, local_y, mask); + } + } + return LLUICtrl::handleHover(x, y, mask); +} + +BOOL LLComboBox::handleMouseDown(S32 x, S32 y, MASK mask) +{ + if (mList->getVisible()) + { + S32 local_x, local_y; + LLView::localPointToOtherView(x, y, &local_x, &local_y, mList); + if (mList->pointInView(local_x, local_y)) + { + return mList->handleMouseDown(local_x, local_y, mask); + } + } + BOOL has_focus_now = hasFocus(); + BOOL handled = LLUICtrl::handleMouseDown(x, y, mask); + if (handled && !has_focus_now) + { + onFocusReceived(); + } + + return handled; +} + +BOOL LLComboBox::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ + if (mList->getVisible()) + { + S32 local_x, local_y; + LLView::localPointToOtherView(x, y, &local_x, &local_y, mList); + if (mList->pointInView(local_x, local_y)) + { + return mList->handleRightMouseDown(local_x, local_y, mask); + } + } + return LLUICtrl::handleRightMouseDown(x, y, mask); +} + +BOOL LLComboBox::handleRightMouseUp(S32 x, S32 y, MASK mask) +{ + if (mList->getVisible()) + { + S32 local_x, local_y; + LLView::localPointToOtherView(x, y, &local_x, &local_y, mList); + if (mList->pointInView(local_x, local_y)) + { + return mList->handleRightMouseUp(local_x, local_y, mask); + } + } + return LLUICtrl::handleRightMouseUp(x, y, mask); +} + +BOOL LLComboBox::handleDoubleClick(S32 x, S32 y, MASK mask) +{ + if (mList->getVisible()) + { + S32 local_x, local_y; + LLView::localPointToOtherView(x, y, &local_x, &local_y, mList); + if (mList->pointInView(local_x, local_y)) + { + return mList->handleDoubleClick(local_x, local_y, mask); + } + } + return LLUICtrl::handleDoubleClick(x, y, mask); +} + +BOOL LLComboBox::handleMouseUp(S32 x, S32 y, MASK mask) +{ + BOOL handled = childrenHandleMouseUp(x, y, mask) != NULL; + + if (!handled && mList->getVisible()) + { + S32 local_x, local_y; + LLView::localPointToOtherView(x, y, &local_x, &local_y, mList); + if (mList->pointInView(local_x, local_y)) + { + handled = mList->handleMouseUp(local_x, local_y, mask); + } + } + + if( !handled && gFocusMgr.getMouseCapture() == this ) + { + // Mouse events that we didn't handle cause the list to be hidden. + // Eat mouse event, regardless of where on the screen it happens. + hideList(); + handled = TRUE; + } + + return handled; +} + +void LLComboBox::clear() +{ + if (mTextEntry) + { + mTextEntry->setText(""); + } + mButton->setLabelSelected(""); + mButton->setLabelUnselected(""); + mButton->setDisabledLabel(""); + mButton->setDisabledSelectedLabel(""); + mList->deselectAllItems(); +} + +void LLComboBox::onCommit() +{ + if (mAllowTextEntry && getCurrentIndex() != -1) + { + // we have selected an existing item, blitz the manual text entry with + // the properly capitalized item + mTextEntry->setValue(getSimple()); + mTextEntry->setTentative(FALSE); + } + LLUICtrl::onCommit(); +} + +// add item "name" to menu +void LLComboBox::add(const LLString& name, EAddPosition pos, BOOL enabled) +{ + mList->addSimpleItem(name, pos, enabled); + mList->selectFirstItem(); +} + +// add item "name" with a unique id to menu +void LLComboBox::add(const LLString& name, const LLUUID& id, EAddPosition pos, BOOL enabled ) +{ + mList->addSimpleItem(name, LLSD(id), pos, enabled); + mList->selectFirstItem(); +} + +// add item "name" with attached userdata +void LLComboBox::add(const LLString& name, void* userdata, EAddPosition pos, BOOL enabled ) +{ + LLScrollListItem* item = mList->addSimpleItem(name, pos, enabled); + item->setUserdata( userdata ); + mList->selectFirstItem(); +} + +// add item "name" with attached generic data +void LLComboBox::add(const LLString& name, LLSD value, EAddPosition pos, BOOL enabled ) +{ + mList->addSimpleItem(name, value, pos, enabled); + mList->selectFirstItem(); +} + + +void LLComboBox::sortByName() +{ + mList->sortByColumn(0, TRUE); +} + + +// Choose an item with a given name in the menu. +// Returns TRUE if the item was found. +BOOL LLComboBox::setSimple(const LLString& name) +{ + BOOL found = mList->selectSimpleItem(name, FALSE); + + if (found) + { + setLabel(name); + } + + return found; +} + +// virtual +void LLComboBox::setValue(const LLSD& value) +{ + BOOL found = mList->selectByValue(value); + if (found) + { + LLScrollListItem* item = mList->getFirstSelected(); + if (item) + { + setLabel( mList->getSimpleSelectedItem() ); + } + } +} + +const LLString& LLComboBox::getSimple() const +{ + const LLString& res = mList->getSimpleSelectedItem(); + if (res.empty() && mAllowTextEntry) + { + return mTextEntry->getText(); + } + else + { + return res; + } +} + +const LLString& LLComboBox::getSimpleSelectedItem(S32 column) const +{ + return mList->getSimpleSelectedItem(column); +} + +// virtual +LLSD LLComboBox::getValue() const +{ + LLScrollListItem* item = mList->getFirstSelected(); + if( item ) + { + return item->getValue(); + } + else if (mAllowTextEntry) + { + return mTextEntry->getValue(); + } + else + { + return LLSD(); + } +} + +void LLComboBox::setLabel(const LLString& name) +{ + if ( mAllowTextEntry ) + { + mTextEntry->setText(name); + if (mList->selectSimpleItem(name, FALSE)) + { + mTextEntry->setTentative(FALSE); + } + else + { + mTextEntry->setTentative(mTextEntryTentative); + } + } + else + { + mButton->setLabelUnselected(name); + mButton->setLabelSelected(name); + mButton->setDisabledLabel(name); + mButton->setDisabledSelectedLabel(name); + } +} + + +BOOL LLComboBox::remove(const LLString& name) +{ + BOOL found = mList->selectSimpleItem(name); + + if (found) + { + LLScrollListItem* item = mList->getFirstSelected(); + if (item) + { + mList->deleteSingleItem(mList->getItemIndex(item)); + } + } + + return found; +} + +BOOL LLComboBox::remove(S32 index) +{ + if (index < mList->getItemCount()) + { + mList->deleteSingleItem(index); + return TRUE; + } + return FALSE; +} + +// Keyboard focus lost. +void LLComboBox::onFocusLost() +{ + hideList(); + // if valid selection + if (mAllowTextEntry && getCurrentIndex() != -1) + { + mTextEntry->selectAll(); + } +} + +void LLComboBox::setButtonVisible(BOOL visible) +{ + mButton->setVisible(visible); + mDrawButton = visible; + if (mTextEntry) + { + LLRect text_entry_rect(0, mRect.getHeight(), mRect.getWidth(), 0); + if (visible) + { + text_entry_rect.mRight -= mArrowImage->getWidth() + 2 * LLUI::sConfigGroup->getS32("DropShadowButton"); + } + //mTextEntry->setRect(text_entry_rect); + mTextEntry->reshape(text_entry_rect.getWidth(), text_entry_rect.getHeight(), TRUE); + } +} + +void LLComboBox::draw() +{ + if( getVisible() ) + { + mBorder->setKeyboardFocusHighlight(hasFocus()); + + mButton->setEnabled(mEnabled /*&& !mList->isEmpty()*/); + + // Draw children + LLUICtrl::draw(); + + if (mDrawButton) + { + // Paste the graphic on the right edge + if (!mArrowImage.isNull()) + { + S32 left = mRect.getWidth() - mArrowImage->getWidth() - LLUI::sConfigGroup->getS32("DropShadowButton"); + + gl_draw_image( left, 0, mArrowImage, + LLColor4::white); + } + } + } +} + +BOOL LLComboBox::setCurrentByIndex( S32 index ) +{ + BOOL found = mList->selectNthItem( index ); + if (found) + { + setLabel(mList->getSimpleSelectedItem()); + } + return found; +} + +S32 LLComboBox::getCurrentIndex() const +{ + LLScrollListItem* item = mList->getFirstSelected(); + if( item ) + { + return mList->getItemIndex( item ); + } + return -1; +} + + +void* LLComboBox::getCurrentUserdata() +{ + LLScrollListItem* item = mList->getFirstSelected(); + if( item ) + { + return item->getUserdata(); + } + return NULL; +} + + +void LLComboBox::showList() +{ + // Make sure we don't go off top of screen. + LLCoordWindow window_size; + getWindow()->getSize(&window_size); + //HACK: shouldn't have to know about scale here + mList->arrange( 192, llfloor((F32)window_size.mY / LLUI::sGLScaleFactor.mV[VY]) - 50 ); + + // Move rect so it hangs off the bottom of this view + LLRect rect = mList->getRect(); + + rect.setLeftTopAndSize(0, 0, rect.getWidth(), rect.getHeight() ); + mList->setRect(rect); + + // Make sure that we can see the whole list + LLRect floater_area_screen; + LLRect floater_area_local; + gFloaterView->getParent()->localRectToScreen( gFloaterView->getRect(), &floater_area_screen ); + screenRectToLocal( floater_area_screen, &floater_area_local ); + mList->translateIntoRect( floater_area_local, FALSE ); + + // Make sure we didn't go off bottom of screen + S32 x, y; + mList->localPointToScreen(0, 0, &x, &y); + + if (y < 0) + { + mList->translate(0, -y); + } + + gFocusMgr.setMouseCapture( this, LLComboBox::onMouseCaptureLost ); + // NB: this call will trigger the focuslost callback which will hide the list, so do it first + // before finally showing the list + + if (!mList->getFirstSelected()) + { + // if nothing is selected, select the first item + // so that the callback is not immediately triggered on setFocus() + mList->selectFirstItem(); + } + gFocusMgr.setKeyboardFocus(mList, onListFocusLost); + + // Show the list and push the button down + mButton->setToggleState(TRUE); + mList->setVisible(TRUE); + + gFocusMgr.setTopView(mList, LLComboBox::onTopViewLost ); + +} + +void LLComboBox::hideList() +{ + mButton->setToggleState(FALSE); + mList->setVisible(FALSE); + mList->highlightNthItem(-1); + + if( gFocusMgr.getTopView() == mList ) + { + gFocusMgr.setTopView(NULL, NULL); + } + + if( gFocusMgr.getMouseCapture() == this ) + { + gFocusMgr.setMouseCapture( NULL, NULL ); + } + + if( gFocusMgr.getKeyboardFocus() == mList ) + { + if (mAllowTextEntry) + { + mTextEntry->setFocus(TRUE); + } + else + { + setFocus(TRUE); + } + } +} + + + +//------------------------------------------------------------------ +// static functions +//------------------------------------------------------------------ + +// static +void LLComboBox::onButtonClick(void *userdata) +{ + LLComboBox *self = (LLComboBox *)userdata; + + if (!self->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)); + } + + if( self->mPrearrangeCallback ) + { + self->mPrearrangeCallback( self, self->mCallbackUserData ); + } + + if (self->mList->getItemCount() != 0) + { + self->showList(); + } + + if (self->mKeyboardFocusOnClick && !self->hasFocus()) + { + self->setFocus( TRUE ); + } + } + else + { + // hide and release keyboard focus + self->hideList(); + + self->onCommit(); + } +} + + + +// static +void LLComboBox::onItemSelected(LLUICtrl* item, void *userdata) +{ + // Note: item is the LLScrollListCtrl + LLComboBox *self = (LLComboBox *) userdata; + + const LLString& name = self->mList->getSimpleSelectedItem(); + + self->hideList(); + + S32 cur_id = self->getCurrentIndex(); + if (cur_id != -1) + { + self->setLabel(self->mList->getSimpleSelectedItem()); + + if (self->mAllowTextEntry) + { + self->mTextEntry->setText(name); + self->mTextEntry->setTentative(FALSE); + gFocusMgr.setKeyboardFocus(self->mTextEntry, NULL); + self->mTextEntry->selectAll(); + } + else + { + self->mButton->setLabelUnselected( name ); + self->mButton->setLabelSelected( name ); + self->mButton->setDisabledLabel( name ); + self->mButton->setDisabledSelectedLabel( name ); + } + } + self->onCommit(); +} + +// static +void LLComboBox::onTopViewLost(LLView* old_focus) +{ + LLComboBox *self = (LLComboBox *) old_focus->getParent(); + self->hideList(); +} + + +// static +void LLComboBox::onMouseCaptureLost(LLMouseHandler*) +{ + // Can't hide the list here. If the list scrolls off the screen, + // and you click in the arrow buttons of the scroll bar, they must capture + // the mouse to handle scrolling-while-mouse-down. +} + +BOOL LLComboBox::handleToolTip(S32 x, S32 y, LLString& msg, LLRect* sticky_rect_screen) +{ + + LLString tool_tip; + + if (LLUI::sShowXUINames) + { + tool_tip = mName; + } + else + { + tool_tip = mToolTipMsg; + } + + if( getVisible() && pointInView( x, y ) ) + { + 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( + mRect.getWidth(), mRect.getHeight(), + &(sticky_rect_screen->mRight), &(sticky_rect_screen->mTop) ); + } + return TRUE; + } + return FALSE; +} + +BOOL LLComboBox::handleKeyHere(KEY key, MASK mask, BOOL called_from_parent) +{ + BOOL result = FALSE; + if (gFocusMgr.childHasKeyboardFocus(this)) + { + //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)); + } + result = mList->handleKeyHere(key, mask, FALSE); + // if selection has changed, pop open list + if (mList->getLastSelectedItem() != last_selected_item) + { + showList(); + } + } + return result; +} + +BOOL LLComboBox::handleUnicodeCharHere(llwchar uni_char, BOOL called_from_parent) +{ + BOOL result = FALSE; + if (gFocusMgr.childHasKeyboardFocus(this)) + { + // space bar just shows the list + if (' ' != uni_char ) + { + 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)); + } + result = mList->handleUnicodeCharHere(uni_char, called_from_parent); + if (mList->getLastSelectedItem() != last_selected_item) + { + showList(); + } + } + } + return result; +} + +void LLComboBox::setAllowTextEntry(BOOL allow, S32 max_chars, BOOL set_tentative) +{ + LLRect rect( 0, mRect.getHeight(), mRect.getWidth(), 0); + if (allow && !mAllowTextEntry) + { + S32 shadow_size = LLUI::sConfigGroup->getS32("DropShadowButton"); + mButton->setRect(LLRect( mRect.getWidth() - mArrowImage->getWidth() - 2 * shadow_size, + rect.mTop, rect.mRight, rect.mBottom)); + mButton->setTabStop(FALSE); + + // clear label on button + LLString cur_label = mButton->getLabelSelected(); + setLabel(""); + if (!mTextEntry) + { + LLRect text_entry_rect(0, mRect.getHeight(), mRect.getWidth(), 0); + text_entry_rect.mRight -= mArrowImage->getWidth() + 2 * LLUI::sConfigGroup->getS32("DropShadowButton"); + mTextEntry = new LLLineEditor("combo_text_entry", + text_entry_rect, + "", + LLFontGL::sSansSerifSmall, + max_chars, + onTextCommit, + onTextEntry, + NULL, + this, + NULL, // prevalidate func + LLViewBorder::BEVEL_NONE, + LLViewBorder::STYLE_LINE, + 0); // no border + mTextEntry->setSelectAllonFocusReceived(TRUE); + mTextEntry->setHandleEditKeysDirectly(TRUE); + mTextEntry->setCommitOnFocusLost(FALSE); + mTextEntry->setText(cur_label); + mTextEntry->setIgnoreTab(TRUE); + addChild(mTextEntry); + mMaxChars = max_chars; + } + else + { + mTextEntry->setVisible(TRUE); + } + } + else if (!allow && mAllowTextEntry) + { + mButton->setRect(rect); + mButton->setTabStop(TRUE); + + if (mTextEntry) + { + mTextEntry->setVisible(FALSE); + } + } + mAllowTextEntry = allow; + mTextEntryTentative = set_tentative; +} + +void LLComboBox::setTextEntry(const LLString& text) +{ + if (mTextEntry) + { + mTextEntry->setText(text); + updateSelection(); + } +} + +//static +void LLComboBox::onTextEntry(LLLineEditor* line_editor, void* user_data) +{ + LLComboBox* self = (LLComboBox*)user_data; + + if (self->mTextEntryCallback) + { + (*self->mTextEntryCallback)(line_editor, self->mCallbackUserData); + } + + KEY key = gKeyboard->currentKey(); + if (key == KEY_BACKSPACE || + key == KEY_DELETE) + { + if (self->mList->selectSimpleItem(line_editor->getText(), FALSE)) + { + line_editor->setTentative(FALSE); + } + else + { + line_editor->setTentative(self->mTextEntryTentative); + } + return; + } + + if (key == KEY_LEFT || + key == KEY_RIGHT) + { + return; + } + + if (key == KEY_DOWN) + { + self->setCurrentByIndex(llmin(self->getItemCount() - 1, self->getCurrentIndex() + 1)); + if (!self->mList->getVisible()) + { + if( self->mPrearrangeCallback ) + { + self->mPrearrangeCallback( self, self->mCallbackUserData ); + } + + if (self->mList->getItemCount() != 0) + { + self->showList(); + } + } + line_editor->selectAll(); + line_editor->setTentative(FALSE); + } + else if (key == KEY_UP) + { + self->setCurrentByIndex(llmax(0, self->getCurrentIndex() - 1)); + if (!self->mList->getVisible()) + { + if( self->mPrearrangeCallback ) + { + self->mPrearrangeCallback( self, self->mCallbackUserData ); + } + + if (self->mList->getItemCount() != 0) + { + self->showList(); + } + } + line_editor->selectAll(); + line_editor->setTentative(FALSE); + } + else + { + // RN: presumably text entry + self->updateSelection(); + } +} + +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(); + + // 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 ); + } + } + + if (mList->selectSimpleItem(full_string, FALSE)) + { + mTextEntry->setTentative(FALSE); + } + else if (!mList->selectSimpleItemByPrefix(left_wstring, FALSE)) + { + mList->deselectAllItems(); + mTextEntry->setText(wstring_to_utf8str(user_wstring)); + mTextEntry->setTentative(mTextEntryTentative); + } + else + { + LLWString selected_item = utf8str_to_wstring(mList->getSimpleSelectedItem()); + 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); + } +} + +//static +void LLComboBox::onTextCommit(LLUICtrl* caller, void* user_data) +{ + LLComboBox* self = (LLComboBox*)user_data; + LLString text = self->mTextEntry->getText(); + self->setSimple(text); + self->onCommit(); + self->mTextEntry->selectAll(); +} + +void LLComboBox::setFocus(BOOL b) +{ + LLUICtrl::setFocus(b); + + if (b) + { + mList->clearSearchString(); + } +} + +//============================================================================ +// LLCtrlListInterface functions + +S32 LLComboBox::getItemCount() const +{ + return mList->getItemCount(); +} + +void LLComboBox::addColumn(const LLSD& column, EAddPosition pos) +{ + mList->clearColumns(); + mList->addColumn(column, pos); +} + +void LLComboBox::clearColumns() +{ + mList->clearColumns(); +} + +void LLComboBox::setColumnLabel(const LLString& column, const LLString& label) +{ + mList->setColumnLabel(column, label); +} + +LLScrollListItem* LLComboBox::addElement(const LLSD& value, EAddPosition pos, void* userdata) +{ + return mList->addElement(value, pos, userdata); +} + +LLScrollListItem* LLComboBox::addSimpleElement(const LLString& value, EAddPosition pos, const LLSD& id) +{ + return mList->addSimpleElement(value, pos, id); +} + +void LLComboBox::clearRows() +{ + mList->clearRows(); +} + +void LLComboBox::sortByColumn(LLString name, BOOL ascending) +{ +} + +//============================================================================ +//LLCtrlSelectionInterface functions + +BOOL LLComboBox::setCurrentByID(const LLUUID& id) +{ + BOOL found = mList->selectByID( id ); + + if (found) + { + setLabel(mList->getSimpleSelectedItem()); + } + + return found; +} + +LLUUID LLComboBox::getCurrentID() +{ + return mList->getStringUUIDSelectedItem(); +} +BOOL LLComboBox::setSelectedByValue(LLSD value, BOOL selected) +{ + BOOL found = mList->setSelectedByValue(value, selected); + if (found) + { + setLabel(mList->getSimpleSelectedItem()); + } + return found; +} + +LLSD LLComboBox::getSimpleSelectedValue() +{ + return mList->getSimpleSelectedValue(); +} + +BOOL LLComboBox::isSelected(LLSD value) +{ + return mList->isSelected(value); +} + +BOOL LLComboBox::operateOnSelection(EOperation op) +{ + if (op == OP_DELETE) + { + mList->deleteSelectedItems(); + return TRUE; + } + return FALSE; +} + +BOOL LLComboBox::operateOnAll(EOperation op) +{ + if (op == OP_DELETE) + { + clearRows(); + return TRUE; + } + return FALSE; +} + +//static +void LLComboBox::onListFocusLost(LLUICtrl* old_focus) +{ + // if focus is going to nothing (user hit ESC), take it back + LLComboBox* combo = (LLComboBox*)old_focus->getParent(); + combo->hideList(); + if (gFocusMgr.getKeyboardFocus() == NULL) + { + combo->focusFirstItem(); + } +} |