diff options
Diffstat (limited to 'indra/newview/lllocationinputctrl.cpp')
-rw-r--r-- | indra/newview/lllocationinputctrl.cpp | 1239 |
1 files changed, 315 insertions, 924 deletions
diff --git a/indra/newview/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp index 67bf2d7265..fac0de0f33 100644 --- a/indra/newview/lllocationinputctrl.cpp +++ b/indra/newview/lllocationinputctrl.cpp @@ -1,5 +1,5 @@ -/** - * @file lllocationinputmonitorctrl.cpp +/** + * @file lllocationinputctrl.cpp * @brief Combobox-like location input control * * $LicenseInfo:firstyear=2009&license=viewergpl$ @@ -36,1091 +36,482 @@ #include "lllocationinputctrl.h" // common includes -#include <llstring.h> -#include <llcombobox.h> - -// newview includes #include "llbutton.h" -#include "llkeyboard.h" -#include "llscrolllistctrl.h" -#include "llwindow.h" -#include "llfloater.h" -#include "llscrollbar.h" -#include "llscrolllistcell.h" -#include "llscrolllistitem.h" -#include "llcontrol.h" +#include "llfloaterreg.h" #include "llfocusmgr.h" -#include "lllineeditor.h" -#include "v2math.h" +#include "llkeyboard.h" +#include "llstring.h" #include "lluictrlfactory.h" +#include "v2math.h" -// Globals -static S32 MAX_COMBO_WIDTH = 500; - -static LLRegisterWidget<LLLocationInputCtrl> r("location_input"); - -LLLocationInputCtrl::LLLocationInputCtrl(const LLLocationInputCtrl::Params& p) -: LLUICtrl(p), - mTextEntry(NULL), - mTextEntryTentative(TRUE), - mListPosition(BELOW), - mAllowTextEntry(p.allow_text_entry), - mSelectOnFocus(p.select_on_focus), - mHasAutocompletedText(false), - mMaxChars(p.max_chars), - mPrearrangeCallback(p.prearrange_callback()), - mTextEntryCallback(p.text_entry_callback()), - mSelectionCallback(p.selection_callback()), - mArrowImage(p.arrow_image) -{ - // Text label button - - LLButton::Params button_params; - button_params.name(p.label); - button_params.image_unselected.name("square_btn_32x128.tga"); - button_params.image_selected.name("square_btn_selected_32x128.tga"); - button_params.image_disabled.name("square_btn_32x128.tga"); - button_params.image_disabled_selected.name("square_btn_selected_32x128.tga"); - button_params.image_overlay.name("combobox_arrow.tga"); - button_params.image_overlay_alignment("right"); - button_params.scale_image(true); - button_params.mouse_down_callback.function(boost::bind(&LLLocationInputCtrl::onButtonDown, this)); - button_params.font(LLFontGL::getFontSansSerifSmall()); - button_params.follows.flags(FOLLOWS_LEFT|FOLLOWS_BOTTOM|FOLLOWS_RIGHT); - button_params.font_halign(LLFontGL::LEFT); - button_params.rect(p.rect); - button_params.pad_right(2); - - mButton = LLUICtrlFactory::create<LLButton>(button_params); - mButton->setRightHPad(2); //redo to compensate for button hack that leaves space for a character - addChild(mButton); - - LLScrollListCtrl::Params params; - params.name ("LocationInput"); - params.commit_callback.function(boost::bind(&LLLocationInputCtrl::onItemSelected, this, _2)); - params.visible(false); - params.bg_writeable_color(LLColor4::white); - params.commit_on_keyboard_movement(false); - - mList = LLUICtrlFactory::create<LLScrollListCtrl>(params); - addChild(mList); - - for (LLInitParam::ParamIterator<LLScrollListItem::Params>::const_iterator it = p.items().begin(); - it != p.items().end(); - ++it) - { - mList->addRow(*it); - } - - setTopLostCallback(boost::bind(&LLLocationInputCtrl::hideList, this)); -} - -LLLocationInputCtrl::~LLLocationInputCtrl() -{ - // children automatically deleted, including mMenu, mButton -} - -void LLLocationInputCtrl::setEnabled(BOOL enabled) -{ - LLView::setEnabled(enabled); - mButton->setEnabled(enabled); -} - -void LLLocationInputCtrl::clear() -{ - if (mTextEntry) - { - mTextEntry->setText(LLStringUtil::null); - } - mButton->setLabelSelected(LLStringUtil::null); - mButton->setLabelUnselected(LLStringUtil::null); - mButton->setDisabledLabel(LLStringUtil::null); - mButton->setDisabledSelectedLabel(LLStringUtil::null); - mList->deselectAllItems(); -} - -void LLLocationInputCtrl::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(); -} - -// virtual -BOOL LLLocationInputCtrl::isDirty() const -{ - BOOL grubby = FALSE; - if ( mList ) - { - grubby = mList->isDirty(); - } - return grubby; -} - -// virtual Clear dirty state -void LLLocationInputCtrl::resetDirty() -{ - if ( mList ) - { - mList->resetDirty(); - } -} +// newview includes +#include "llagent.h" +#include "llfloaterland.h" +#include "llinventorymodel.h" +#include "lllandmarklist.h" +#include "lllocationhistory.h" +#include "llpanelplaces.h" +#include "llsidetray.h" +#include "llviewerinventory.h" +#include "llviewerparcelmgr.h" +//============================================================================ +/* + * "ADD LANDMARK" BUTTON UPDATING LOGIC + * + * If the current parcel has been landmarked, we should draw + * a special image on the button. + * + * To avoid determining the appropriate image on every draw() we do that + * only in the following cases: + * 1) Navbar is shown for the first time after login. + * 2) Agent moves to another parcel. + * 3) A landmark is created or removed. + * + * The first case is handled by the handleLoginComplete() method. + * + * The second case is handled by setting the "agent parcel changed" callback + * on LLViewerParcelMgr. + * + * The third case is the most complex one. We have two inventory observers for that: + * one is designated to handle adding landmarks, the other handles removal. + * Let's see how the former works. + * + * When we get notified about landmark addition, the landmark position is unknown yet. What we can + * do at that point is initiate loading the landmark data by LLLandmarkList and set the + * "loading finished" callback on it. Finally, when the callback is triggered, + * we can determine whether the landmark refers to a point within the current parcel + * and choose the appropriate image for the "Add landmark" button. + */ -// add item "name" to menu -LLScrollListItem* LLLocationInputCtrl::add(const std::string& name, EAddPosition pos, BOOL enabled) +// Returns true if the given inventory item is a landmark pointing to the current parcel. +// Used to filter inventory items. +class LLIsAgentParcelLandmark : public LLInventoryCollectFunctor { - LLScrollListItem* item = mList->addSimpleElement(name, pos); - item->setEnabled(enabled); - if (!mAllowTextEntry && mLabel.empty()) +public: + /*virtual*/ bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) { - selectFirstItem(); - } - return item; -} + if (!item || item->getType() != LLAssetType::AT_LANDMARK) + return false; -// add item "name" with a unique id to menu -LLScrollListItem* LLLocationInputCtrl::add(const std::string& name, const LLUUID& id, EAddPosition pos, BOOL enabled ) -{ - LLScrollListItem* item = mList->addSimpleElement(name, pos, id); - item->setEnabled(enabled); - if (!mAllowTextEntry && mLabel.empty()) - { - selectFirstItem(); - } - return item; -} + LLLandmark* landmark = gLandmarkList.getAsset(item->getAssetUUID()); + if (!landmark) // the landmark not been loaded yet + return false; -// add item "name" with attached userdata -LLScrollListItem* LLLocationInputCtrl::add(const std::string& name, void* userdata, EAddPosition pos, BOOL enabled ) -{ - LLScrollListItem* item = mList->addSimpleElement(name, pos); - item->setEnabled(enabled); - item->setUserdata( userdata ); - if (!mAllowTextEntry && mLabel.empty()) - { - selectFirstItem(); - } - return item; -} + LLVector3d landmark_global_pos; + if (!landmark->getGlobalPos(landmark_global_pos)) + return false; -// add item "name" with attached generic data -LLScrollListItem* LLLocationInputCtrl::add(const std::string& name, LLSD value, EAddPosition pos, BOOL enabled ) -{ - LLScrollListItem* item = mList->addSimpleElement(name, pos, value); - item->setEnabled(enabled); - if (!mAllowTextEntry && mLabel.empty()) - { - selectFirstItem(); + return LLViewerParcelMgr::getInstance()->inAgentParcel(landmark_global_pos); } - return item; -} +}; -LLScrollListItem* LLLocationInputCtrl::addSeparator(EAddPosition pos) -{ - return mList->addSeparator(pos); -} - -void LLLocationInputCtrl::sortByName(BOOL ascending) -{ - mList->sortOnce(0, ascending); -} - - -// Choose an item with a given name in the menu. -// Returns TRUE if the item was found. -BOOL LLLocationInputCtrl::setSimple(const LLStringExplicit& name) +/** + * Initiates loading the landmarks that have been just added. + * + * Once the loading is complete we'll be notified + * with the callback we set for LLLandmarkList. + */ +class LLAddLandmarkObserver : public LLInventoryAddedObserver { - BOOL found = mList->selectItemByLabel(name, FALSE); - - if (found) - { - setLabel(name); - } +public: + LLAddLandmarkObserver(LLLocationInputCtrl* input) : mInput(input) {} - return found; -} - -// virtual -void LLLocationInputCtrl::setValue(const LLSD& value) -{ - BOOL found = mList->selectByValue(value); - if (found) +private: + /*virtual*/ void done() { - LLScrollListItem* item = mList->getFirstSelected(); - if (item) + std::vector<LLUUID>::const_iterator it = mAdded.begin(), end = mAdded.end(); + for(; it != end; ++it) { - setLabel( mList->getSelectedItemLabel() ); + LLInventoryItem* item = gInventory.getItem(*it); + if (!item || item->getType() != LLAssetType::AT_LANDMARK) + continue; + + // Start loading the landmark. + LLLandmark* lm = gLandmarkList.getAsset( + item->getAssetUUID(), + boost::bind(&LLLocationInputCtrl::onLandmarkLoaded, mInput, _1)); + if (lm) + { + // Already loaded? Great, handle it immediately (the callback won't be called). + mInput->onLandmarkLoaded(lm); + } } - } -} -const std::string LLLocationInputCtrl::getSimple() const -{ - const std::string res = mList->getSelectedItemLabel(); - if (res.empty() && mAllowTextEntry) - { - return mTextEntry->getText(); - } - else - { - return res; + mAdded.clear(); } -} -const std::string LLLocationInputCtrl::getSelectedItemLabel(S32 column) const -{ - return mList->getSelectedItemLabel(column); -} + LLLocationInputCtrl* mInput; +}; -// virtual -LLSD LLLocationInputCtrl::getValue() const +/** + * Updates the "Add landmark" button once a landmark gets removed. + */ +class LLRemoveLandmarkObserver : public LLInventoryObserver { - LLScrollListItem* item = mList->getFirstSelected(); - if( item ) - { - return item->getValue(); - } - else if (mAllowTextEntry) - { - return mTextEntry->getValue(); - } - else - { - return LLSD(); - } -} +public: + LLRemoveLandmarkObserver(LLLocationInputCtrl* input) : mInput(input) {} -void LLLocationInputCtrl::setLabel(const LLStringExplicit& name) -{ - if ( mTextEntry ) +private: + /*virtual*/ void changed(U32 mask) { - mTextEntry->setText(name); - if (mList->selectItemByLabel(name, FALSE)) + if (mask & (~(LLInventoryObserver::LABEL|LLInventoryObserver::INTERNAL|LLInventoryObserver::ADD))) { - mTextEntry->setTentative(FALSE); - } - else - { - mTextEntry->setTentative(mTextEntryTentative); + mInput->updateAddLandmarkButton(); } } - - if (!mAllowTextEntry) - { - mButton->setLabelUnselected(name); - mButton->setLabelSelected(name); - mButton->setDisabledLabel(name); - mButton->setDisabledSelectedLabel(name); - } -} + LLLocationInputCtrl* mInput; +}; -BOOL LLLocationInputCtrl::remove(const std::string& name) -{ - BOOL found = mList->selectItemByLabel(name); - - if (found) - { - LLScrollListItem* item = mList->getFirstSelected(); - if (item) - { - mList->deleteSingleItem(mList->getItemIndex(item)); - } - } +//============================================================================ - return found; -} -BOOL LLLocationInputCtrl::remove(S32 index) -{ - if (index < mList->getItemCount()) - { - mList->deleteSingleItem(index); - return TRUE; - } - return FALSE; -} +static LLDefaultWidgetRegistry::Register<LLLocationInputCtrl> r("location_input"); -// Keyboard focus lost. -void LLLocationInputCtrl::onFocusLost() +LLLocationInputCtrl::Params::Params() +: add_landmark_image_enabled("add_landmark_image_enabled"), + add_landmark_image_disabled("add_landmark_image_disabled"), + add_landmark_button("add_landmark_button"), + add_landmark_hpad("add_landmark_hpad", 0), + info_button("info_button"), + background("background") { - hideList(); - // if valid selection - if (mAllowTextEntry && getCurrentIndex() != -1) - { - mTextEntry->selectAll(); - } - LLUICtrl::onFocusLost(); } -void LLLocationInputCtrl::setButtonVisible(BOOL visible) -{ - static LLUICachedControl<S32> drop_shadow_button ("DropShadowButton", 0); - - mButton->setVisible(visible); - if (mTextEntry) +LLLocationInputCtrl::LLLocationInputCtrl(const LLLocationInputCtrl::Params& p) +: LLComboBox(p), + mAddLandmarkHPad(p.add_landmark_hpad), + mInfoBtn(NULL), + mAddLandmarkBtn(NULL) +{ + // Background image. + LLButton::Params bg_params = p.background; + mBackground = LLUICtrlFactory::create<LLButton>(bg_params); + addChildInBack(mBackground); + + // "Place information" button. + LLButton::Params info_params = p.info_button; + mInfoBtn = LLUICtrlFactory::create<LLButton>(info_params); + mInfoBtn->setClickedCallback(boost::bind(&LLLocationInputCtrl::onInfoButtonClicked, this)); + addChild(mInfoBtn); + + // "Add landmark" button. + LLButton::Params al_params = p.add_landmark_button; + if (p.add_landmark_image_enabled()) { - LLRect text_entry_rect(0, getRect().getHeight(), getRect().getWidth(), 0); - if (visible) - { - text_entry_rect.mRight -= llmax(8,mArrowImage->getWidth()) + 2 * drop_shadow_button; - } - //mTextEntry->setRect(text_entry_rect); - mTextEntry->reshape(text_entry_rect.getWidth(), text_entry_rect.getHeight(), TRUE); + al_params.image_unselected = p.add_landmark_image_enabled; + al_params.image_selected = p.add_landmark_image_enabled; } -} - -/*virtual*/ -BOOL LLLocationInputCtrl::postBuild() -{ - // If providing user text entry or descriptive label don't select an item under the hood - if (!acceptsTextInput() && mLabel.empty()) + if (p.add_landmark_image_disabled()) { - selectFirstItem(); + al_params.image_disabled = p.add_landmark_image_disabled; + al_params.image_disabled_selected = p.add_landmark_image_disabled; } - updateLayout(); - return TRUE; -} + al_params.click_callback.function(boost::bind(&LLLocationInputCtrl::onAddLandmarkButtonClicked, this)); + mAddLandmarkBtn = LLUICtrlFactory::create<LLButton>(al_params); + enableAddLandmarkButton(true); + addChild(mAddLandmarkBtn); + + setFocusReceivedCallback(boost::bind(&LLLocationInputCtrl::onFocusReceived, this)); + setFocusLostCallback(boost::bind(&LLLocationInputCtrl::onFocusLost, this)); + setPrearrangeCallback(boost::bind(&LLLocationInputCtrl::onLocationPrearrange, this, _2)); -void LLLocationInputCtrl::draw() -{ - mButton->setEnabled(getEnabled() /*&& !mList->isEmpty()*/); + updateWidgetlayout(); - // Draw children normally - LLUICtrl::draw(); -} + // - Make the "Add landmark" button updated when either current parcel gets changed + // or a landmark gets created or removed from the inventory. + // - Update the location string on parcel change. + LLViewerParcelMgr::getInstance()->setAgentParcelChangedCallback( + boost::bind(&LLLocationInputCtrl::onAgentParcelChange, this)); -BOOL LLLocationInputCtrl::setCurrentByIndex( S32 index ) -{ - BOOL found = mList->selectNthItem( index ); - if (found) - { - setLabel(mList->getSelectedItemLabel()); - } - return found; -} + LLLocationHistory::getInstance()->setLoadedCallback( + boost::bind(&LLLocationInputCtrl::onLocationHistoryLoaded, this)); -S32 LLLocationInputCtrl::getCurrentIndex() const -{ - LLScrollListItem* item = mList->getFirstSelected(); - if( item ) - { - return mList->getItemIndex( item ); - } - return -1; + mRemoveLandmarkObserver = new LLRemoveLandmarkObserver(this); + mAddLandmarkObserver = new LLAddLandmarkObserver(this); + gInventory.addObserver(mRemoveLandmarkObserver); + gInventory.addObserver(mAddLandmarkObserver); } - -void LLLocationInputCtrl::updateLayout() +LLLocationInputCtrl::~LLLocationInputCtrl() { - static LLUICachedControl<S32> drop_shadow_button ("DropShadowButton", 0); - LLRect rect = getLocalRect(); - if (mAllowTextEntry) - { - S32 shadow_size = drop_shadow_button; - mButton->setRect(LLRect( getRect().getWidth() - llmax(8,mArrowImage->getWidth()) - 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 * drop_shadow_button; - // clear label on button - std::string cur_label = mButton->getLabelSelected(); - LLLineEditor::Params params; - params.name ("combo_text_entry"); - params.rect (text_entry_rect); - params.default_text (LLStringUtil::null); - params.font (LLFontGL::getFontSansSerifSmall()); - params.max_length_bytes (mMaxChars); - params.commit_callback.function(boost::bind(&LLLocationInputCtrl::onTextCommit, this, _2)); - params.keystroke_callback (boost::bind(&LLLocationInputCtrl::onTextEntry, this, _1)); - params.focus_lost_callback (NULL); - params.select_on_focus (mSelectOnFocus); - params.handle_edit_keys_directly (true); - params.commit_on_focus_lost (false); - params.follows.flags (FOLLOWS_ALL); - mTextEntry = LLUICtrlFactory::create<LLLineEditor> (params); - mTextEntry->setText(cur_label); - mTextEntry->setIgnoreTab(TRUE); - mTextEntry->setRevertOnEsc(FALSE); - //mTextEntry->setFocusReceivedCallback(boost::bind(&LLLocationInputCtrl::hideList, this)); - addChild(mTextEntry); - } - else - { - mTextEntry->setVisible(TRUE); - mTextEntry->setMaxTextLength(mMaxChars); - } - - // clear label on button - setLabel(LLStringUtil::null); - - mButton->setFollows(FOLLOWS_BOTTOM | FOLLOWS_TOP | FOLLOWS_RIGHT); - } - else if (!mAllowTextEntry) - { - mButton->setRect(rect); - mButton->setTabStop(TRUE); - mButton->setHAlign(LLFontGL::LEFT); - - if (mTextEntry) - { - mTextEntry->setVisible(FALSE); - } - mButton->setFollowsAll(); - } + gInventory.removeObserver(mRemoveLandmarkObserver); + gInventory.removeObserver(mAddLandmarkObserver); + delete mRemoveLandmarkObserver; + delete mAddLandmarkObserver; } -void* LLLocationInputCtrl::getCurrentUserdata() +void LLLocationInputCtrl::setEnabled(BOOL enabled) { - LLScrollListItem* item = mList->getFirstSelected(); - if( item ) - { - return item->getUserdata(); - } - return NULL; + LLComboBox::setEnabled(enabled); + mAddLandmarkBtn->setEnabled(enabled); } - -void LLLocationInputCtrl::showList() +void LLLocationInputCtrl::hideList() { - // 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->fitContents( 192, llfloor((F32)window_size.mY / LLUI::sGLScaleFactor.mV[VY]) - 50 ); - - // Make sure that we can see the whole list - LLRect root_view_local; - LLView* root_view = getRootView(); - root_view->localRectToOtherView(root_view->getLocalRect(), &root_view_local, this); - - LLRect rect = mList->getRect(); - - S32 min_width = getRect().getWidth(); - S32 max_width = llmax(min_width, MAX_COMBO_WIDTH); - // make sure we have up to date content width metrics - mList->calcColumnWidths(); - S32 list_width = llclamp(mList->getMaxContentWidth(), min_width, max_width); - - if (mListPosition == BELOW) - { - if (rect.getHeight() <= -root_view_local.mBottom) - { - // Move rect so it hangs off the bottom of this view - rect.setLeftTopAndSize(0, 0, list_width, rect.getHeight() ); - } - else - { - // stack on top or bottom, depending on which has more room - if (-root_view_local.mBottom > root_view_local.mTop - getRect().getHeight()) - { - // Move rect so it hangs off the bottom of this view - rect.setLeftTopAndSize(0, 0, list_width, llmin(-root_view_local.mBottom, rect.getHeight())); - } - else - { - // move rect so it stacks on top of this view (clipped to size of screen) - rect.setOriginAndSize(0, getRect().getHeight(), list_width, llmin(root_view_local.mTop - getRect().getHeight(), rect.getHeight())); - } - } - } - else // ABOVE - { - if (rect.getHeight() <= root_view_local.mTop - getRect().getHeight()) - { - // move rect so it stacks on top of this view (clipped to size of screen) - rect.setOriginAndSize(0, getRect().getHeight(), list_width, llmin(root_view_local.mTop - getRect().getHeight(), rect.getHeight())); - } - else - { - // stack on top or bottom, depending on which has more room - if (-root_view_local.mBottom > root_view_local.mTop - getRect().getHeight()) - { - // Move rect so it hangs off the bottom of this view - rect.setLeftTopAndSize(0, 0, list_width, llmin(-root_view_local.mBottom, rect.getHeight())); - } - else - { - // move rect so it stacks on top of this view (clipped to size of screen) - rect.setOriginAndSize(0, getRect().getHeight(), list_width, llmin(root_view_local.mTop - getRect().getHeight(), rect.getHeight())); - } - } - - } - mList->setOrigin(rect.mLeft, rect.mBottom); - mList->reshape(rect.getWidth(), rect.getHeight()); - mList->translateIntoRect(root_view_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); - } - - // NB: this call will trigger the focuslost callback which will hide the list, so do it first - // before finally showing the list - - 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); - - setUseBoundingRect(TRUE); + LLComboBox::hideList(); + if (mTextEntry && hasFocus()) + focusTextEntry(); } -void LLLocationInputCtrl::hideList() +BOOL LLLocationInputCtrl::handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect_screen) { - //*HACK: store the original value explicitly somewhere, not just in label - std::string orig_selection = mAllowTextEntry ? mTextEntry->getText() : mButton->getLabelSelected(); - - // assert selection in list - mList->selectItemByLabel(orig_selection, FALSE); - - mButton->setToggleState(FALSE); - mList->setVisible(FALSE); - mList->mouseOverHighlightNthItem(-1); - - setUseBoundingRect(FALSE); - - if( gFocusMgr.getTopCtrl() == this ) + // Let the buttons show their tooltips. + if (LLUICtrl::handleToolTip(x, y, msg, sticky_rect_screen) && !msg.empty()) { - gFocusMgr.setTopCtrl(NULL); + return TRUE; } -} -void LLLocationInputCtrl::onButtonDown() -{ - if (!mList->getVisible()) + // Cursor is above the text entry. + msg = LLUI::sShowXUINames ? getShowNamesToolTip() : gAgent.getSLURL(); + if (mTextEntry && sticky_rect_screen) { -#if 0 // XXX VS - LLScrollListItem* last_selected_item = mList->getLastSelectedItem(); - if (last_selected_item) - { - // highlight the original selection before potentially selecting a new item - mList->mouseOverHighlightNthItem(mList->getItemIndex(last_selected_item)); - } -#endif - - prearrangeList(); - - if (mList->getItemCount() != 0) - { - showList(); - } - - setFocus( TRUE ); - - // pass mouse capture on to list if button is depressed - if (mButton->hasMouseCapture()) - { - gFocusMgr.setMouseCapture(mList); - } + *sticky_rect_screen = mTextEntry->calcScreenRect(); } - else - { - hideList(); - // XXX VS - mTextEntry->setFocus(TRUE); - } + return TRUE; } - -//------------------------------------------------------------------ -// static functions -//------------------------------------------------------------------ - -void LLLocationInputCtrl::onItemSelected(const LLSD& data) +BOOL LLLocationInputCtrl::handleKeyHere(KEY key, MASK mask) { - const std::string name = mList->getSelectedItemLabel(); + BOOL result = LLComboBox::handleKeyHere(key, mask); - S32 cur_id = getCurrentIndex(); - if (cur_id != -1) + if (key == KEY_DOWN && hasFocus() && mList->getItemCount() != 0) { - setLabel(name); - - if (mAllowTextEntry) - { - gFocusMgr.setKeyboardFocus(mTextEntry); - mTextEntry->selectAll(); - } + showList(); } - // hiding the list reasserts the old value stored in the text editor/dropdown button - hideList(); - - // commit does the reverse, asserting the value in the list - onCommit(); - - // call the callback if it exists - if(mSelectionCallback) - { - mSelectionCallback(this, data); - } + return result; } -BOOL LLLocationInputCtrl::handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect_screen) +void LLLocationInputCtrl::onTextEntry(LLLineEditor* line_editor) { - std::string tool_tip; + KEY key = gKeyboard->currentKey(); - if(LLUICtrl::handleToolTip(x, y, msg, sticky_rect_screen)) - { - return TRUE; - } - - if (LLUI::sShowXUINames) - { - tool_tip = getShowNamesToolTip(); - } - else + if (line_editor->getText().empty()) { - tool_tip = getToolTip(); - if (tool_tip.empty()) - { - 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) ); + prearrangeList(); // resets filter + hideList(); } - return TRUE; -} - -BOOL LLLocationInputCtrl::handleKeyHere(KEY key, MASK mask) -{ - BOOL result = FALSE; - if (hasFocus()) + // Typing? (moving cursor should not affect showing the list) + else if (key != KEY_LEFT && key != KEY_RIGHT && key != KEY_HOME && key != KEY_END) { - if (mList->getVisible() - && key == KEY_ESCAPE && mask == MASK_NONE) - { - hideList(); - // XXX VS - mTextEntry->setFocus(TRUE); - 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->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 - // XXX VS -#if 1 - else if(key == KEY_DOWN && mList->getItemCount() != 0) -#else - else if (mList->getLastSelectedItem() != last_selected_item) -#endif + prearrangeList(line_editor->getText()); + if (mList->getItemCount() != 0) { showList(); + focusTextEntry(); } - - } - return result; -} - -BOOL LLLocationInputCtrl::handleUnicodeCharHere(llwchar uni_char) -{ - BOOL result = FALSE; - if (gFocusMgr.childHasKeyboardFocus(this)) - { - // space bar just shows the list - if (' ' != uni_char ) + else { - LLScrollListItem* last_selected_item = mList->getLastSelectedItem(); - if (last_selected_item) - { - // highlight the original selection before potentially selecting a new item - mList->mouseOverHighlightNthItem(mList->getItemIndex(last_selected_item)); - } - result = mList->handleUnicodeCharHere(uni_char); - if (mList->getLastSelectedItem() != last_selected_item) - { - showList(); - } + // Hide the list if it's empty. + hideList(); } } - return result; -} - -void LLLocationInputCtrl::setTextEntry(const LLStringExplicit& text) -{ - if (mTextEntry) - { - setText(text); - updateSelection(); - } + + LLComboBox::onTextEntry(line_editor); } /** * Useful if we want to just set the text entry value, no matter what the list contains. - * + * * This is faster than setTextEntry(). */ void LLLocationInputCtrl::setText(const LLStringExplicit& text) { if (mTextEntry) - mTextEntry->setText(text); -} - -void LLLocationInputCtrl::onTextEntry(LLLineEditor* line_editor) -{ - if (mTextEntryCallback != NULL) - { - (mTextEntryCallback)(line_editor, LLSD()); - } - - KEY key = gKeyboard->currentKey(); - - // XXX VS - { - if (line_editor->getText().empty()) - { - prearrangeList(); // resets filter - hideList(); - } - // Moving cursor should not affect showing the list. - else if (key != KEY_LEFT && key != KEY_RIGHT && key != KEY_HOME && key != KEY_END) - { - prearrangeList(line_editor->getText()); - if (mList->getItemCount() != 0) - { - showList(); - } - else - { - // Hide the list if it's empty. - hideList(); - } - - mTextEntry->setFocus(TRUE); - } - } - - if (key == KEY_BACKSPACE || - key == KEY_DELETE) - { - if (mList->selectItemByLabel(line_editor->getText(), FALSE)) - { - line_editor->setTentative(FALSE); - } - else - { - line_editor->setTentative(mTextEntryTentative); - mList->deselectAllItems(); - } - return; - } - - if (key == KEY_LEFT || - key == KEY_RIGHT) - { - return; - } - - if (key == KEY_DOWN) { - setCurrentByIndex(llmin(getItemCount() - 1, getCurrentIndex() + 1)); - if (!mList->getVisible()) - { - prearrangeList(); - - if (mList->getItemCount() != 0) - { - showList(); - } - } - line_editor->selectAll(); - line_editor->setTentative(FALSE); - } - else - { - // RN: presumably text entry - updateSelection(); + mTextEntry->setText(text); + mHasAutocompletedText = FALSE; } } -void LLLocationInputCtrl::updateSelection() +void LLLocationInputCtrl::setFocus(BOOL b) { - 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 = 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 ) - { - prearrangeList(mTextEntry->getText()); - } + LLComboBox::setFocus(b); - if (mList->selectItemByLabel(full_string, FALSE)) - { - mTextEntry->setTentative(FALSE); - } - else if (mList->selectItemByPrefix(left_wstring, FALSE)) - { - LLWString selected_item = utf8str_to_wstring(mList->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; - } - else // no matching items found - { - mList->deselectAllItems(); - mTextEntry->setText(wstring_to_utf8str(user_wstring)); // removes text added by autocompletion - mTextEntry->setTentative(mTextEntryTentative); - mHasAutocompletedText = FALSE; - } + if (mTextEntry && b && !mList->getVisible()) + mTextEntry->setFocus(TRUE); } -void LLLocationInputCtrl::onTextCommit(const LLSD& data) +void LLLocationInputCtrl::handleLoginComplete() { - std::string text = mTextEntry->getText(); - setSimple(text); - onCommit(); - mTextEntry->selectAll(); + // An agent parcel update hasn't occurred yet, so we have to + // manually set location and the appropriate "Add landmark" icon. + refresh(); } -void LLLocationInputCtrl::setFocus(BOOL b) -{ - LLUICtrl::setFocus(b); +//== private methods ========================================================= - if (b) - { - mList->clearSearchString(); - if (mList->getVisible()) - { - mList->setFocus(TRUE); - } - else - { - mTextEntry->setFocus(TRUE); - } - } +void LLLocationInputCtrl::onFocusReceived() +{ + prearrangeList(); + setText(gAgent.getSLURL()); + if (mTextEntry) + mTextEntry->endSelection(); // we don't want handleMouseUp() to "finish" the selection } -//============================================================================ -// LLCtrlListInterface functions - -S32 LLLocationInputCtrl::getItemCount() const +void LLLocationInputCtrl::onFocusLost() { - return mList->getItemCount(); + refreshLocation(); } -void LLLocationInputCtrl::addColumn(const LLSD& column, EAddPosition pos) +void LLLocationInputCtrl::onInfoButtonClicked() { - mList->clearColumns(); - mList->addColumn(column, pos); + LLSD key; + key["type"] = LLPanelPlaces::AGENT; + + LLSideTray::getInstance()->showPanel("panel_places", key); } -void LLLocationInputCtrl::clearColumns() +void LLLocationInputCtrl::onAddLandmarkButtonClicked() { - mList->clearColumns(); + LLFloaterReg::showInstance("add_landmark"); } -void LLLocationInputCtrl::setColumnLabel(const std::string& column, const std::string& label) +void LLLocationInputCtrl::onAgentParcelChange() { - mList->setColumnLabel(column, label); + refresh(); } -LLScrollListItem* LLLocationInputCtrl::addElement(const LLSD& value, EAddPosition pos, void* userdata) +void LLLocationInputCtrl::onLandmarkLoaded(LLLandmark* lm) { - return mList->addElement(value, pos, userdata); + (void) lm; + updateAddLandmarkButton(); } -LLScrollListItem* LLLocationInputCtrl::addSimpleElement(const std::string& value, EAddPosition pos, const LLSD& id) +void LLLocationInputCtrl::onLocationHistoryLoaded() { - return mList->addSimpleElement(value, pos, id); + rebuildLocationHistory(); } -void LLLocationInputCtrl::clearRows() +void LLLocationInputCtrl::onLocationPrearrange(const LLSD& data) { - mList->clearRows(); + std::string filter = data.asString(); + rebuildLocationHistory(filter); + mList->mouseOverHighlightNthItem(-1); // Clear highlight on the last selected item. } -void LLLocationInputCtrl::sortByColumn(const std::string& name, BOOL ascending) +void LLLocationInputCtrl::refresh() { - mList->sortByColumn(name, ascending); + refreshLocation(); // update location string + updateAddLandmarkButton(); // indicate whether current parcel has been landmarked } -//============================================================================ -//LLCtrlSelectionInterface functions - -BOOL LLLocationInputCtrl::setCurrentByID(const LLUUID& id) +void LLLocationInputCtrl::refreshLocation() { - BOOL found = mList->selectByID( id ); + // Is one of our children focused? + if (LLUICtrl::hasFocus() || mButton->hasFocus() || mList->hasFocus() || + (mTextEntry && mTextEntry->hasFocus()) || (mAddLandmarkBtn->hasFocus())) - if (found) { - setLabel(mList->getSelectedItemLabel()); + llwarns << "Location input should not be refreshed when having focus" << llendl; + return; } - return found; -} + // Update location field. + std::string location_name; -LLUUID LLLocationInputCtrl::getCurrentID() const -{ - return mList->getStringUUIDSelectedItem(); -} -BOOL LLLocationInputCtrl::setSelectedByValue(const LLSD& value, BOOL selected) -{ - BOOL found = mList->setSelectedByValue(value, selected); - if (found) - { - setLabel(mList->getSelectedItemLabel()); - } - return found; -} - -LLSD LLLocationInputCtrl::getSelectedValue() -{ - return mList->getSelectedValue(); -} + if (!gAgent.buildLocationString(location_name, LLAgent::LOCATION_FORMAT_NORMAL)) + location_name = "Unknown"; -BOOL LLLocationInputCtrl::isSelected(const LLSD& value) const -{ - return mList->isSelected(value); + setText(location_name); } -BOOL LLLocationInputCtrl::operateOnSelection(EOperation op) +void LLLocationInputCtrl::rebuildLocationHistory(std::string filter) { - if (op == OP_DELETE) + LLLocationHistory::location_list_t filtered_items; + const LLLocationHistory::location_list_t* itemsp = NULL; + LLLocationHistory* lh = LLLocationHistory::getInstance(); + + if (filter.empty()) { - mList->deleteSelectedItems(); - return TRUE; + itemsp = &lh->getItems(); } - return FALSE; -} - -BOOL LLLocationInputCtrl::operateOnAll(EOperation op) -{ - if (op == OP_DELETE) + else { - clearRows(); - return TRUE; + lh->getMatchingItems(filter, filtered_items); + itemsp = &filtered_items; } - return FALSE; -} - -BOOL LLLocationInputCtrl::selectItemRange( S32 first, S32 last ) -{ - return mList->selectItemRange(first, last); -} - -void LLLocationInputCtrl::prearrangeList(std::string filter) -{ - if (mPrearrangeCallback) + + removeall(); + for (LLLocationHistory::location_list_t::const_reverse_iterator it = itemsp->rbegin(); it != itemsp->rend(); it++) { - mPrearrangeCallback(this, LLSD(filter)); + add(*it); } } -//=========================================================================== - -BOOL LLLocationInputCtrl::childHasFocus() const +void LLLocationInputCtrl::focusTextEntry() { - return LLUICtrl::hasFocus() || mButton->hasFocus() || mList->hasFocus() || mTextEntry->hasFocus(); + // We can't use "mTextEntry->setFocus(TRUE)" instead because + // if the "select_on_focus" parameter is true it places the cursor + // at the beginning (after selecting text), thus screwing up updateSelection(). + if (mTextEntry) + gFocusMgr.setKeyboardFocus(mTextEntry); } -BOOL LLLocationInputCtrl::canCut() const +void LLLocationInputCtrl::enableAddLandmarkButton(bool val) { - return mTextEntry ? mTextEntry->canCut() : false; + // Enable/disable the button. + mAddLandmarkBtn->setEnabled(val); } -BOOL LLLocationInputCtrl::canCopy() const +// Change the "Add landmark" button image +// depending on whether current parcel has been landmarked. +void LLLocationInputCtrl::updateAddLandmarkButton() { - return mTextEntry ? mTextEntry->canCopy() : false; -} + bool cur_parcel_landmarked = false; -BOOL LLLocationInputCtrl::canPaste() const -{ - return mTextEntry ? mTextEntry->canPaste() : false; -} + // Determine whether there are landmarks pointing to the current parcel. + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + LLIsAgentParcelLandmark is_current_parcel_landmark; + gInventory.collectDescendentsIf(gAgent.getInventoryRootID(), + cats, + items, + LLInventoryModel::EXCLUDE_TRASH, + is_current_parcel_landmark); + cur_parcel_landmarked = !items.empty(); -BOOL LLLocationInputCtrl::canDeselect() const -{ - return mTextEntry ? mTextEntry->canDeselect() : false; + enableAddLandmarkButton(!cur_parcel_landmarked); } -BOOL LLLocationInputCtrl::canSelectAll() const +void LLLocationInputCtrl::updateWidgetlayout() { - return mTextEntry ? mTextEntry->canSelectAll() : false; -} + const LLRect& rect = getLocalRect(); + const LLRect& hist_btn_rect = mButton->getRect(); + LLRect info_btn_rect = mButton->getRect(); -void LLLocationInputCtrl::cut() -{ - if (mTextEntry) - mTextEntry->cut(); -} + // info button + info_btn_rect.setOriginAndSize( + 0, (rect.getHeight() - info_btn_rect.getHeight()) / 2, + info_btn_rect.getWidth(), info_btn_rect.getHeight()); + mInfoBtn->setRect(info_btn_rect); -void LLLocationInputCtrl::copy() -{ - if (mTextEntry) - mTextEntry->copy(); -} + // background + mBackground->setRect(LLRect(info_btn_rect.getWidth(), rect.mTop, + rect.mRight - hist_btn_rect.getWidth(), rect.mBottom)); -void LLLocationInputCtrl::paste() -{ - if (mTextEntry) - mTextEntry->paste(); -} + // history button + mButton->setRightHPad(0); -void LLLocationInputCtrl::deleteSelection() -{ - if (mTextEntry) - mTextEntry->deleteSelection(); -} + // "Add Landmark" button + { + LLRect al_btn_rect = mAddLandmarkBtn->getRect(); + al_btn_rect.translate( + hist_btn_rect.mLeft - mAddLandmarkHPad - al_btn_rect.getWidth(), + (rect.getHeight() - al_btn_rect.getHeight()) / 2); + mAddLandmarkBtn->setRect(al_btn_rect); + } -void LLLocationInputCtrl::selectAll() -{ + // text entry if (mTextEntry) - mTextEntry->selectAll(); + { + LLRect text_entry_rect(rect); + text_entry_rect.mLeft = info_btn_rect.getWidth(); + text_entry_rect.mRight = mAddLandmarkBtn->getRect().mLeft; + text_entry_rect.stretch(0, -1); // make space for border + mTextEntry->setRect(text_entry_rect); + } } |