diff options
author | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 21:25:21 +0200 |
---|---|---|
committer | Andrey Lihatskiy <alihatskiy@productengine.com> | 2024-05-22 22:40:26 +0300 |
commit | e2e37cced861b98de8c1a7c9c0d3a50d2d90e433 (patch) | |
tree | 1bb897489ce524986f6196201c10ac0d8861aa5f /indra/newview/lllocationinputctrl.cpp | |
parent | 069ea06848f766466f1a281144c82a0f2bd79f3a (diff) |
Fix line endlings
Diffstat (limited to 'indra/newview/lllocationinputctrl.cpp')
-rw-r--r-- | indra/newview/lllocationinputctrl.cpp | 2580 |
1 files changed, 1290 insertions, 1290 deletions
diff --git a/indra/newview/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp index 39e578eb80..54dd5792a0 100644 --- a/indra/newview/lllocationinputctrl.cpp +++ b/indra/newview/lllocationinputctrl.cpp @@ -1,1290 +1,1290 @@ -/**
- * @file lllocationinputctrl.cpp
- * @brief Combobox-like location input control
- *
- * $LicenseInfo:firstyear=2009&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-
-// file includes
-#include "lllocationinputctrl.h"
-
-// common includes
-#include "llbutton.h"
-#include "llfocusmgr.h"
-#include "llhelp.h"
-#include "llmenugl.h"
-#include "llparcel.h"
-#include "llstring.h"
-#include "lltrans.h"
-#include "lluictrlfactory.h"
-#include "lltooltip.h"
-#include "llnotificationsutil.h"
-#include "llregionflags.h"
-
-// newview includes
-#include "llagent.h"
-#include "llfloaterreg.h"
-#include "llfloatersidepanelcontainer.h"
-#include "llinventoryobserver.h"
-#include "lllandmarkactions.h"
-#include "lllandmarklist.h"
-#include "llpathfindingmanager.h"
-#include "llpathfindingnavmesh.h"
-#include "llpathfindingnavmeshstatus.h"
-#include "llteleporthistory.h"
-#include "llslurl.h"
-#include "llstatusbar.h" // getHealth()
-#include "lltrans.h"
-#include "llviewerinventory.h"
-#include "llviewerparcelmgr.h"
-#include "llviewerregion.h"
-#include "llviewercontrol.h"
-#include "llviewermenu.h"
-#include "llurllineeditorctrl.h"
-#include "llagentui.h"
-
-#include "llmenuoptionpathfindingrebakenavmesh.h"
-#include "llpathfindingmanager.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.
- */
-
-/**
- * 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
-{
-public:
- LLAddLandmarkObserver(LLLocationInputCtrl* input) : mInput(input) {}
-
-private:
- /*virtual*/ void done()
- {
- const uuid_set_t& added = gInventory.getAddedIDs();
- for (uuid_set_t::const_iterator it = added.begin(); it != added.end(); ++it)
- {
- 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);
- }
- }
- }
-
- LLLocationInputCtrl* mInput;
-};
-
-/**
- * Updates the "Add landmark" button once a landmark gets removed.
- */
-class LLRemoveLandmarkObserver : public LLInventoryObserver
-{
-public:
- LLRemoveLandmarkObserver(LLLocationInputCtrl* input) : mInput(input) {}
-
-private:
- /*virtual*/ void changed(U32 mask)
- {
- if (mask & (~(LLInventoryObserver::LABEL|
- LLInventoryObserver::INTERNAL|
- LLInventoryObserver::ADD|
- LLInventoryObserver::CREATE|
- LLInventoryObserver::UPDATE_CREATE)))
- {
- mInput->updateAddLandmarkButton();
- }
- }
-
- LLLocationInputCtrl* mInput;
-};
-
-class LLParcelChangeObserver : public LLParcelObserver
-{
-public:
- LLParcelChangeObserver(LLLocationInputCtrl* input) : mInput(input) {}
-
-private:
- /*virtual*/ void changed()
- {
- if (mInput)
- {
- mInput->refreshParcelIcons();
- }
- }
-
- LLLocationInputCtrl* mInput;
-};
-
-//============================================================================
-
-
-static LLDefaultChildRegistry::Register<LLLocationInputCtrl> r("location_input");
-
-LLLocationInputCtrl::Params::Params()
-: icon_maturity_general("icon_maturity_general"),
- icon_maturity_adult("icon_maturity_adult"),
- icon_maturity_moderate("icon_maturity_moderate"),
- add_landmark_image_enabled("add_landmark_image_enabled"),
- add_landmark_image_disabled("add_landmark_image_disabled"),
- add_landmark_image_hover("add_landmark_image_hover"),
- add_landmark_image_selected("add_landmark_image_selected"),
- add_landmark_hpad("add_landmark_hpad", 0),
- icon_hpad("icon_hpad", 0),
- add_landmark_button("add_landmark_button"),
- for_sale_button("for_sale_button"),
- info_button("info_button"),
- maturity_button("maturity_button"),
- voice_icon("voice_icon"),
- fly_icon("fly_icon"),
- push_icon("push_icon"),
- build_icon("build_icon"),
- scripts_icon("scripts_icon"),
- damage_icon("damage_icon"),
- damage_text("damage_text"),
- see_avatars_icon("see_avatars_icon"),
- maturity_help_topic("maturity_help_topic"),
- pathfinding_dirty_icon("pathfinding_dirty_icon"),
- pathfinding_disabled_icon("pathfinding_disabled_icon")
-{
-}
-
-LLLocationInputCtrl::LLLocationInputCtrl(const LLLocationInputCtrl::Params& p)
-: LLComboBox(p),
- mIconHPad(p.icon_hpad),
- mAddLandmarkHPad(p.add_landmark_hpad),
- mLocationContextMenu(NULL),
- mAddLandmarkBtn(NULL),
- mForSaleBtn(NULL),
- mInfoBtn(NULL),
- mRegionCrossingSlot(),
- mNavMeshSlot(),
- mIsNavMeshDirty(false),
- mLandmarkImageOn(NULL),
- mLandmarkImageOff(NULL),
- mIconMaturityGeneral(NULL),
- mIconMaturityAdult(NULL),
- mIconMaturityModerate(NULL),
- mMaturityHelpTopic(p.maturity_help_topic)
-{
- // Lets replace default LLLineEditor with LLLocationLineEditor
- // to make needed escaping while copying and cutting url
- delete mTextEntry;
-
- // Can't access old mTextEntry fields as they are protected, so lets build new params
- // That is C&P from LLComboBox::createLineEditor function
- S32 arrow_width = mArrowImage ? mArrowImage->getWidth() : 0;
- LLRect text_entry_rect(0, getRect().getHeight(), getRect().getWidth(), 0);
- text_entry_rect.mRight -= llmax(8,arrow_width) + 2 * BTN_DROP_SHADOW;
-
- LLLineEditor::Params params = p.combo_editor;
- params.rect(text_entry_rect);
- params.default_text(LLStringUtil::null);
- params.max_length.bytes(p.max_chars);
- params.keystroke_callback(boost::bind(&LLLocationInputCtrl::onTextEntry, this, _1));
- params.commit_on_focus_lost(false);
- params.follows.flags(FOLLOWS_ALL);
- mTextEntry = LLUICtrlFactory::create<LLURLLineEditor>(params);
- mTextEntry->resetContextMenu();
- addChild(mTextEntry);
- // LLLineEditor is replaced with LLLocationLineEditor
-
- // "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;
-
- // Image for unselected state will be set in updateAddLandmarkButton(),
- // it will be either mLandmarkOn or mLandmarkOff
- if (p.add_landmark_image_enabled())
- {
- mLandmarkImageOn = p.add_landmark_image_enabled;
- }
- if (p.add_landmark_image_disabled())
- {
- mLandmarkImageOff = p.add_landmark_image_disabled;
- }
-
- if(p.add_landmark_image_selected)
- {
- al_params.image_selected = p.add_landmark_image_selected;
- }
- if (p.add_landmark_image_hover())
- {
- al_params.image_hover_unselected = p.add_landmark_image_hover;
- }
-
- al_params.click_callback.function(boost::bind(&LLLocationInputCtrl::onAddLandmarkButtonClicked, this));
- mAddLandmarkBtn = LLUICtrlFactory::create<LLButton>(al_params);
- enableAddLandmarkButton(true);
- addChild(mAddLandmarkBtn);
-
- if (p.icon_maturity_general())
- {
- mIconMaturityGeneral = p.icon_maturity_general;
- }
- if (p.icon_maturity_adult())
- {
- mIconMaturityAdult = p.icon_maturity_adult;
- }
- if(p.icon_maturity_moderate())
- {
- mIconMaturityModerate = p.icon_maturity_moderate;
- }
-
- LLButton::Params maturity_button = p.maturity_button;
- mMaturityButton = LLUICtrlFactory::create<LLButton>(maturity_button);
- addChild(mMaturityButton);
-
- LLButton::Params for_sale_button = p.for_sale_button;
- for_sale_button.tool_tip = LLTrans::getString("LocationCtrlForSaleTooltip");
- for_sale_button.click_callback.function(
- boost::bind(&LLLocationInputCtrl::onForSaleButtonClicked, this));
- mForSaleBtn = LLUICtrlFactory::create<LLButton>( for_sale_button );
- addChild(mForSaleBtn);
-
- // Parcel property icons
- // Must be mouse-opaque so cursor stays as an arrow when hovering to
- // see tooltip.
- LLIconCtrl::Params voice_icon = p.voice_icon;
- voice_icon.tool_tip = LLTrans::getString("LocationCtrlVoiceTooltip");
- voice_icon.mouse_opaque = true;
- mParcelIcon[VOICE_ICON] = LLUICtrlFactory::create<LLIconCtrl>(voice_icon);
- mParcelIcon[VOICE_ICON]->setMouseDownCallback(boost::bind(&LLLocationInputCtrl::onParcelIconClick, this, VOICE_ICON));
- addChild(mParcelIcon[VOICE_ICON]);
-
- LLIconCtrl::Params fly_icon = p.fly_icon;
- fly_icon.tool_tip = LLTrans::getString("LocationCtrlFlyTooltip");
- fly_icon.mouse_opaque = true;
- mParcelIcon[FLY_ICON] = LLUICtrlFactory::create<LLIconCtrl>(fly_icon);
- mParcelIcon[FLY_ICON]->setMouseDownCallback(boost::bind(&LLLocationInputCtrl::onParcelIconClick, this, FLY_ICON));
- addChild(mParcelIcon[FLY_ICON]);
-
- LLIconCtrl::Params push_icon = p.push_icon;
- push_icon.tool_tip = LLTrans::getString("LocationCtrlPushTooltip");
- push_icon.mouse_opaque = true;
- mParcelIcon[PUSH_ICON] = LLUICtrlFactory::create<LLIconCtrl>(push_icon);
- mParcelIcon[PUSH_ICON]->setMouseDownCallback(boost::bind(&LLLocationInputCtrl::onParcelIconClick, this, PUSH_ICON));
- addChild(mParcelIcon[PUSH_ICON]);
-
- LLIconCtrl::Params build_icon = p.build_icon;
- build_icon.tool_tip = LLTrans::getString("LocationCtrlBuildTooltip");
- build_icon.mouse_opaque = true;
- mParcelIcon[BUILD_ICON] = LLUICtrlFactory::create<LLIconCtrl>(build_icon);
- mParcelIcon[BUILD_ICON]->setMouseDownCallback(boost::bind(&LLLocationInputCtrl::onParcelIconClick, this, BUILD_ICON));
- addChild(mParcelIcon[BUILD_ICON]);
-
- LLIconCtrl::Params scripts_icon = p.scripts_icon;
- scripts_icon.tool_tip = LLTrans::getString("LocationCtrlScriptsTooltip");
- scripts_icon.mouse_opaque = true;
- mParcelIcon[SCRIPTS_ICON] = LLUICtrlFactory::create<LLIconCtrl>(scripts_icon);
- mParcelIcon[SCRIPTS_ICON]->setMouseDownCallback(boost::bind(&LLLocationInputCtrl::onParcelIconClick, this, SCRIPTS_ICON));
- addChild(mParcelIcon[SCRIPTS_ICON]);
-
- LLIconCtrl::Params damage_icon = p.damage_icon;
- damage_icon.tool_tip = LLTrans::getString("LocationCtrlDamageTooltip");
- damage_icon.mouse_opaque = true;
- mParcelIcon[DAMAGE_ICON] = LLUICtrlFactory::create<LLIconCtrl>(damage_icon);
- mParcelIcon[DAMAGE_ICON]->setMouseDownCallback(boost::bind(&LLLocationInputCtrl::onParcelIconClick, this, DAMAGE_ICON));
- addChild(mParcelIcon[DAMAGE_ICON]);
-
- LLIconCtrl::Params pathfinding_dirty_icon = p.pathfinding_dirty_icon;
- pathfinding_dirty_icon.tool_tip = LLTrans::getString("LocationCtrlPathfindingDirtyTooltip");
- pathfinding_dirty_icon.mouse_opaque = true;
- mParcelIcon[PATHFINDING_DIRTY_ICON] = LLUICtrlFactory::create<LLIconCtrl>(pathfinding_dirty_icon);
- mParcelIcon[PATHFINDING_DIRTY_ICON]->setMouseDownCallback(boost::bind(&LLLocationInputCtrl::onParcelIconClick, this, PATHFINDING_DIRTY_ICON));
- addChild(mParcelIcon[PATHFINDING_DIRTY_ICON]);
-
- LLIconCtrl::Params pathfinding_disabled_icon = p.pathfinding_disabled_icon;
- pathfinding_disabled_icon.tool_tip = LLTrans::getString("LocationCtrlPathfindingDisabledTooltip");
- pathfinding_disabled_icon.mouse_opaque = true;
- mParcelIcon[PATHFINDING_DISABLED_ICON] = LLUICtrlFactory::create<LLIconCtrl>(pathfinding_disabled_icon);
- mParcelIcon[PATHFINDING_DISABLED_ICON]->setMouseDownCallback(boost::bind(&LLLocationInputCtrl::onParcelIconClick, this, PATHFINDING_DISABLED_ICON));
- addChild(mParcelIcon[PATHFINDING_DISABLED_ICON]);
-
- LLTextBox::Params damage_text = p.damage_text;
- damage_text.tool_tip = LLTrans::getString("LocationCtrlDamageTooltip");
- damage_text.mouse_opaque = true;
- mDamageText = LLUICtrlFactory::create<LLTextBox>(damage_text);
- addChild(mDamageText);
-
- LLIconCtrl::Params see_avatars_icon = p.see_avatars_icon;
- see_avatars_icon.tool_tip = LLTrans::getString("LocationCtrlSeeAVsTooltip");
- see_avatars_icon.mouse_opaque = true;
- mParcelIcon[SEE_AVATARS_ICON] = LLUICtrlFactory::create<LLIconCtrl>(see_avatars_icon);
- mParcelIcon[SEE_AVATARS_ICON]->setMouseDownCallback(boost::bind(&LLLocationInputCtrl::onParcelIconClick, this, SEE_AVATARS_ICON));
- addChild(mParcelIcon[SEE_AVATARS_ICON]);
-
- // Register callbacks and load the location field context menu (NB: the order matters).
- LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Navbar.Action", boost::bind(&LLLocationInputCtrl::onLocationContextMenuItemClicked, this, _2));
- LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("Navbar.EnableMenuItem", boost::bind(&LLLocationInputCtrl::onLocationContextMenuItemEnabled, this, _2));
-
- setPrearrangeCallback(boost::bind(&LLLocationInputCtrl::onLocationPrearrange, this, _2));
- getTextEntry()->setMouseUpCallback(boost::bind(&LLLocationInputCtrl::changeLocationPresentation, this));
-
- // Load the location field context menu
- mLocationContextMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_navbar.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
- if (!mLocationContextMenu)
- {
- LL_WARNS() << "Error loading navigation bar context menu" << LL_ENDL;
-
- }
- //don't show default context menu
- getTextEntry()->setShowContextMenu(false);
- getTextEntry()->setRightMouseDownCallback(boost::bind(&LLLocationInputCtrl::onTextEditorRightClicked, this, _2, _3, _4));
- updateWidgetlayout();
-
- // Connecting signal for updating location on "Show Coordinates" setting change.
- LLControlVariable* coordinates_control = gSavedSettings.getControl("NavBarShowCoordinates").get();
- if (coordinates_control)
- {
- mCoordinatesControlConnection = coordinates_control->getSignal()->connect(boost::bind(&LLLocationInputCtrl::refreshLocation, this));
- }
-
- // Connecting signal for updating parcel icons on "Show Parcel Properties" setting change.
- LLControlVariable* parcel_properties_control = gSavedSettings.getControl("NavBarShowParcelProperties").get();
- if (parcel_properties_control)
- {
- mParcelPropertiesControlConnection = parcel_properties_control->getSignal()->connect(boost::bind(&LLLocationInputCtrl::refreshParcelIcons, this));
- }
-
- // - 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.
- mParcelMgrConnection = gAgent.addParcelChangedCallback(
- boost::bind(&LLLocationInputCtrl::onAgentParcelChange, this));
- // LLLocationHistory instance is being created before the location input control, so we have to update initial state of button manually.
- mButton->setEnabled(LLLocationHistory::instance().getItemCount() > 0);
- mLocationHistoryConnection = LLLocationHistory::getInstance()->setChangedCallback(
- boost::bind(&LLLocationInputCtrl::onLocationHistoryChanged, this,_1));
-
- mRegionCrossingSlot = gAgent.addRegionChangedCallback(boost::bind(&LLLocationInputCtrl::onRegionBoundaryCrossed, this));
- createNavMeshStatusListenerForCurrentRegion();
-
- mRemoveLandmarkObserver = new LLRemoveLandmarkObserver(this);
- mAddLandmarkObserver = new LLAddLandmarkObserver(this);
- gInventory.addObserver(mRemoveLandmarkObserver);
- gInventory.addObserver(mAddLandmarkObserver);
-
- mParcelChangeObserver = new LLParcelChangeObserver(this);
- LLViewerParcelMgr::getInstance()->addObserver(mParcelChangeObserver);
-
- mAddLandmarkTooltip = LLTrans::getString("LocationCtrlAddLandmarkTooltip");
- mEditLandmarkTooltip = LLTrans::getString("LocationCtrlEditLandmarkTooltip");
- mButton->setToolTip(LLTrans::getString("LocationCtrlComboBtnTooltip"));
- mInfoBtn->setToolTip(LLTrans::getString("LocationCtrlInfoBtnTooltip"));
-}
-
-LLLocationInputCtrl::~LLLocationInputCtrl()
-{
- gInventory.removeObserver(mRemoveLandmarkObserver);
- gInventory.removeObserver(mAddLandmarkObserver);
- delete mRemoveLandmarkObserver;
- delete mAddLandmarkObserver;
-
- LLViewerParcelMgr::getInstance()->removeObserver(mParcelChangeObserver);
- delete mParcelChangeObserver;
-
- mRegionCrossingSlot.disconnect();
- mNavMeshSlot.disconnect();
- mCoordinatesControlConnection.disconnect();
- mParcelPropertiesControlConnection.disconnect();
- mParcelMgrConnection.disconnect();
- mLocationHistoryConnection.disconnect();
-}
-
-void LLLocationInputCtrl::setEnabled(bool enabled)
-{
- LLComboBox::setEnabled(enabled);
- mAddLandmarkBtn->setEnabled(enabled);
-}
-
-void LLLocationInputCtrl::hideList()
-{
- LLComboBox::hideList();
- if (mTextEntry && hasFocus())
- focusTextEntry();
-}
-
-bool LLLocationInputCtrl::handleToolTip(S32 x, S32 y, MASK mask)
-{
-
- if(mAddLandmarkBtn->parentPointInView(x,y))
- {
- updateAddLandmarkTooltip();
- }
- // Let the buttons show their tooltips.
- if (LLUICtrl::handleToolTip(x, y, mask))
- {
- if (mList->getRect().pointInRect(x, y))
- {
- S32 loc_x, loc_y;
- //x,y - contain coordinates related to the location input control, but without taking the expanded list into account
- //So we have to convert it again into local coordinates of mList
- localPointToOtherView(x,y,&loc_x,&loc_y,mList);
-
- LLScrollListItem* item = mList->hitItem(loc_x,loc_y);
- if (item)
- {
- LLSD value = item->getValue();
- if (value.has("tooltip"))
- {
- LLToolTipMgr::instance().show(value["tooltip"]);
- }
- }
- }
-
- return true;
- }
-
- return false;
-}
-
-bool LLLocationInputCtrl::handleKeyHere(KEY key, MASK mask)
-{
- bool result = LLComboBox::handleKeyHere(key, mask);
-
- if (key == KEY_DOWN && hasFocus() && mList->getItemCount() != 0 && !mList->getVisible())
- {
- showList();
- }
-
- return result;
-}
-
-void LLLocationInputCtrl::onTextEntry(LLLineEditor* line_editor)
-{
- KEY key = gKeyboard->currentKey();
- MASK mask = gKeyboard->currentMask(true);
-
- // Typing? (moving cursor should not affect showing the list)
- bool typing = mask != MASK_CONTROL && key != KEY_LEFT && key != KEY_RIGHT && key != KEY_HOME && key != KEY_END;
- bool pasting = mask == MASK_CONTROL && key == 'V';
-
- if (line_editor->getText().empty())
- {
- prearrangeList(); // resets filter
- hideList();
- }
- else if (typing || pasting)
- {
- prearrangeList(line_editor->getText());
- if (mList->getItemCount() != 0)
- {
- showList();
- focusTextEntry();
- }
- else
- {
- // Hide the list if it's empty.
- hideList();
- }
- }
-
- 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);
- }
- mHasAutocompletedText = false;
-}
-
-void LLLocationInputCtrl::setFocus(bool b)
-{
- LLComboBox::setFocus(b);
-
- if (mTextEntry && b && !mList->getVisible())
- {
- mTextEntry->setFocus(true);
- }
-}
-
-void LLLocationInputCtrl::handleLoginComplete()
-{
- // An agent parcel update hasn't occurred yet, so we have to
- // manually set location and the appropriate "Add landmark" icon.
- refresh();
-}
-
-//== private methods =========================================================
-
-void LLLocationInputCtrl::onFocusReceived()
-{
- prearrangeList();
-}
-
-void LLLocationInputCtrl::onFocusLost()
-{
- LLUICtrl::onFocusLost();
- refreshLocation();
-
- // Setting cursor to 0 to show the left edge of the text. See STORM-370.
- mTextEntry->setCursor(0);
-
- if(mTextEntry->hasSelection()){
- mTextEntry->deselect();
- }
-}
-
-void LLLocationInputCtrl::draw()
-{
- static LLUICachedControl<bool> show_coords("NavBarShowCoordinates", false);
- if(!hasFocus() && show_coords)
- {
- refreshLocation();
- }
-
- static LLUICachedControl<bool> show_icons("NavBarShowParcelProperties", false);
- if (show_icons)
- {
- refreshHealth();
- }
- LLComboBox::draw();
-}
-
-void LLLocationInputCtrl::reshape(S32 width, S32 height, bool called_from_parent)
-{
- LLComboBox::reshape(width, height, called_from_parent);
-
- // Setting cursor to 0 to show the left edge of the text. See EXT-4967.
- mTextEntry->setCursor(0);
- if (mTextEntry->hasSelection())
- {
- // Deselecting because selection position is changed together with
- // cursor position change.
- mTextEntry->deselect();
- }
-
- if (isHumanReadableLocationVisible)
- {
- refreshMaturityButton();
- }
-}
-
-void LLLocationInputCtrl::onInfoButtonClicked()
-{
- LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "agent"));
-}
-
-void LLLocationInputCtrl::onForSaleButtonClicked()
-{
- handle_buy_land();
-}
-
-void LLLocationInputCtrl::onAddLandmarkButtonClicked()
-{
- LLViewerInventoryItem* landmark = LLLandmarkActions::findLandmarkForAgentPos();
- // Landmark exists, open it for preview and edit
- if(landmark && landmark->getUUID().notNull())
- {
- LLSD key;
- key["type"] = "landmark";
- key["id"] = landmark->getUUID();
-
- LLFloaterSidePanelContainer::showPanel("places", key);
- }
- else
- {
- LLFloaterReg::showInstance("add_landmark");
- }
-}
-
-void LLLocationInputCtrl::onAgentParcelChange()
-{
- refresh();
-}
-
-void LLLocationInputCtrl::onRegionBoundaryCrossed()
-{
- createNavMeshStatusListenerForCurrentRegion();
-}
-
-void LLLocationInputCtrl::onNavMeshStatusChange(const LLPathfindingNavMeshStatus &pNavMeshStatus)
-{
- mIsNavMeshDirty = pNavMeshStatus.isValid() && (pNavMeshStatus.getStatus() != LLPathfindingNavMeshStatus::kComplete);
- refreshParcelIcons();
-}
-
-void LLLocationInputCtrl::onLandmarkLoaded(LLLandmark* lm)
-{
- (void) lm;
- updateAddLandmarkButton();
-}
-
-void LLLocationInputCtrl::onLocationHistoryChanged(LLLocationHistory::EChangeType event)
-{
- if(event == LLLocationHistory::LOAD)
- {
- rebuildLocationHistory();
- }
- mButton->setEnabled(LLLocationHistory::instance().getItemCount() > 0);
-}
-
-void LLLocationInputCtrl::onLocationPrearrange(const LLSD& data)
-{
- std::string filter = data.asString();
- rebuildLocationHistory(filter);
-
- //Let's add landmarks to the top of the list if any
- if(!filter.empty() )
- {
- LLInventoryModel::item_array_t landmark_items = LLLandmarkActions::fetchLandmarksByName(filter, true);
-
- for(U32 i=0; i < landmark_items.size(); i++)
- {
- LLSD value;
- //TODO:: DO we need tooltip for Landmark??
-
- value["item_type"] = LANDMARK;
- value["AssetUUID"] = landmark_items[i]->getAssetUUID();
- addLocationHistoryEntry(landmark_items[i]->getName(), value);
-
- }
- //Let's add teleport history items
- LLTeleportHistory* th = LLTeleportHistory::getInstance();
- LLTeleportHistory::slurl_list_t th_items = th->getItems();
-
- std::set<std::string> new_item_titles;// duplicate control
- LLTeleportHistory::slurl_list_t::iterator result = std::find_if(
- th_items.begin(), th_items.end(), boost::bind(
- &LLLocationInputCtrl::findTeleportItemsByTitle, this,
- _1, filter));
-
- while (result != th_items.end())
- {
- //mTitile format - region_name[, parcel_name]
- //mFullTitile format - region_name[, parcel_name] (local_x,local_y, local_z)
- if (new_item_titles.insert(result->mFullTitle).second)
- {
- LLSD value;
- value["item_type"] = TELEPORT_HISTORY;
- value["global_pos"] = result->mGlobalPos.getValue();
- std::string region_name = result->mTitle.substr(0, result->mTitle.find(','));
- //TODO*: add Surl to teleportitem or parse region name from title
- value["tooltip"] = LLSLURL(region_name, result->mGlobalPos).getSLURLString();
- addLocationHistoryEntry(result->getTitle(), value);
- }
- result = std::find_if(result + 1, th_items.end(), boost::bind(
- &LLLocationInputCtrl::findTeleportItemsByTitle, this,
- _1, filter));
- }
- }
- sortByName();
-
- mList->mouseOverHighlightNthItem(-1); // Clear highlight on the last selected item.
-}
-
-bool LLLocationInputCtrl::findTeleportItemsByTitle(const LLTeleportHistoryItem& item, const std::string& filter)
-{
- return item.mTitle.find(filter) != std::string::npos;
-}
-
-void LLLocationInputCtrl::onTextEditorRightClicked(S32 x, S32 y, MASK mask)
-{
- if (mLocationContextMenu)
- {
- updateContextMenu();
- mLocationContextMenu->buildDrawLabels();
- mLocationContextMenu->updateParent(LLMenuGL::sMenuContainer);
- hideList();
- setFocus(true);
- changeLocationPresentation();
- LLMenuGL::showPopup(this, mLocationContextMenu, x, y);
- }
-}
-
-void LLLocationInputCtrl::refresh()
-{
- refreshLocation(); // update location string
- refreshParcelIcons();
- updateAddLandmarkButton(); // indicate whether current parcel has been landmarked
-}
-
-void LLLocationInputCtrl::refreshLocation()
-{
- // Is one of our children focused?
- if (LLUICtrl::hasFocus() || mButton->hasFocus() || mList->hasFocus() ||
- (mTextEntry && mTextEntry->hasFocus()) ||
- (mAddLandmarkBtn->hasFocus()))
- {
- LL_WARNS() << "Location input should not be refreshed when having focus" << LL_ENDL;
- return;
- }
-
- // Update location field.
- std::string location_name;
- LLAgentUI::ELocationFormat format =
- (gSavedSettings.getBOOL("NavBarShowCoordinates")
- ? LLAgentUI::LOCATION_FORMAT_FULL
- : LLAgentUI::LOCATION_FORMAT_NO_COORDS);
-
- if (!LLAgentUI::buildLocationString(location_name, format))
- {
- location_name = "???";
- }
- // store human-readable location to compare it in changeLocationPresentation()
- mHumanReadableLocation = location_name;
- setText(location_name);
- isHumanReadableLocationVisible = true;
-
- refreshMaturityButton();
-}
-
-// returns new right edge
-static S32 layout_widget(LLUICtrl* widget, S32 right)
-{
- if (widget->getVisible())
- {
- LLRect rect = widget->getRect();
- rect.mLeft = right - rect.getWidth();
- rect.mRight = right;
- widget->setRect( rect );
- right -= rect.getWidth();
- }
- return right;
-}
-
-void LLLocationInputCtrl::refreshParcelIcons()
-{
- // Our "cursor" moving right to left
- S32 x = mAddLandmarkBtn->getRect().mLeft;
-
- LLViewerParcelMgr* vpm = LLViewerParcelMgr::getInstance();
-
- LLViewerRegion* agent_region = gAgent.getRegion();
- LLParcel* agent_parcel = vpm->getAgentParcel();
- if (!agent_region || !agent_parcel)
- return;
-
- mForSaleBtn->setVisible(vpm->canAgentBuyParcel(agent_parcel, false));
-
- x = layout_widget(mForSaleBtn, x);
-
- if (gSavedSettings.getBOOL("NavBarShowParcelProperties"))
- {
- LLParcel* current_parcel;
- LLViewerRegion* selection_region = vpm->getSelectionRegion();
- LLParcel* selected_parcel = vpm->getParcelSelection()->getParcel();
-
- // If agent is in selected parcel we use its properties because
- // they are updated more often by LLViewerParcelMgr than agent parcel properties.
- // See LLViewerParcelMgr::processParcelProperties().
- // This is needed to reflect parcel restrictions changes without having to leave
- // the parcel and then enter it again. See EXT-2987
- if (selected_parcel && selected_parcel->getLocalID() == agent_parcel->getLocalID()
- && selection_region == agent_region)
- {
- current_parcel = selected_parcel;
- }
- else
- {
- current_parcel = agent_parcel;
- }
-
- bool allow_voice = vpm->allowAgentVoice(agent_region, current_parcel);
- bool allow_fly = vpm->allowAgentFly(agent_region, current_parcel);
- bool allow_push = vpm->allowAgentPush(agent_region, current_parcel);
- bool allow_build = vpm->allowAgentBuild(current_parcel); // true when anyone is allowed to build. See EXT-4610.
- bool allow_scripts = vpm->allowAgentScripts(agent_region, current_parcel);
- bool allow_damage = vpm->allowAgentDamage(agent_region, current_parcel);
- bool see_avs = current_parcel->getSeeAVs();
- bool pathfinding_dynamic_enabled = agent_region->dynamicPathfindingEnabled();
-
- // Most icons are "block this ability"
- mParcelIcon[VOICE_ICON]->setVisible( !allow_voice );
- mParcelIcon[FLY_ICON]->setVisible( !allow_fly );
- mParcelIcon[PUSH_ICON]->setVisible( !allow_push );
- mParcelIcon[BUILD_ICON]->setVisible( !allow_build );
- mParcelIcon[SCRIPTS_ICON]->setVisible( !allow_scripts );
- mParcelIcon[DAMAGE_ICON]->setVisible( allow_damage );
- mParcelIcon[PATHFINDING_DIRTY_ICON]->setVisible(mIsNavMeshDirty);
- mParcelIcon[PATHFINDING_DISABLED_ICON]->setVisible(!mIsNavMeshDirty && !pathfinding_dynamic_enabled);
-
- mDamageText->setVisible(allow_damage);
- mParcelIcon[SEE_AVATARS_ICON]->setVisible( !see_avs );
-
- // Padding goes to left of both landmark star and for sale btn
- x -= mAddLandmarkHPad;
-
- // Slide the parcel icons rect from right to left, adjusting rectangles
- for (S32 i = 0; i < ICON_COUNT; ++i)
- {
- x = layout_widget(mParcelIcon[i], x);
- x -= mIconHPad;
- }
- x = layout_widget(mDamageText, x);
- x -= mIconHPad;
- }
- else
- {
- for (S32 i = 0; i < ICON_COUNT; ++i)
- {
- mParcelIcon[i]->setVisible(false);
- }
- mDamageText->setVisible(false);
- }
-
- if (mTextEntry)
- {
- S32 left_pad, right_pad;
- mTextEntry->getTextPadding(&left_pad, &right_pad);
- right_pad = mTextEntry->getRect().mRight - x;
- mTextEntry->setTextPadding(left_pad, right_pad);
- }
-}
-
-void LLLocationInputCtrl::refreshHealth()
-{
- // *FIXME: Status bar owns health information, should be in agent
- if (gStatusBar)
- {
- static S32 last_health = -1;
- S32 health = gStatusBar->getHealth();
- if (health != last_health)
- {
- std::string text = llformat("%d%%", health);
- mDamageText->setText(text);
- last_health = health;
- }
- }
-}
-
-void LLLocationInputCtrl::refreshMaturityButton()
-{
- // Updating maturity rating icon.
- LLViewerRegion* region = gAgent.getRegion();
- if (!region)
- return;
-
- bool button_visible = true;
- LLPointer<LLUIImage> rating_image = NULL;
- std::string rating_tooltip;
-
- U8 sim_access = region->getSimAccess();
- switch(sim_access)
- {
- case SIM_ACCESS_PG:
- rating_image = mIconMaturityGeneral;
- rating_tooltip = LLTrans::getString("LocationCtrlGeneralIconTooltip");
- break;
-
- case SIM_ACCESS_ADULT:
- rating_image = mIconMaturityAdult;
- rating_tooltip = LLTrans::getString("LocationCtrlAdultIconTooltip");
- break;
-
- case SIM_ACCESS_MATURE:
- rating_image = mIconMaturityModerate;
- rating_tooltip = LLTrans::getString("LocationCtrlModerateIconTooltip");
- break;
-
- default:
- button_visible = false;
- break;
- }
-
- mMaturityButton->setVisible(button_visible);
- mMaturityButton->setToolTip(rating_tooltip);
- if(rating_image)
- {
- mMaturityButton->setImageUnselected(rating_image);
- mMaturityButton->setImagePressed(rating_image);
- }
- if (mMaturityButton->getVisible())
- {
- positionMaturityButton();
- }
-}
-
-void LLLocationInputCtrl::positionMaturityButton()
-{
- const LLFontGL* font = mTextEntry->getFont();
- if (!font)
- return;
-
- S32 left_pad, right_pad;
- mTextEntry->getTextPadding(&left_pad, &right_pad);
-
- // Calculate the right edge of rendered text + a whitespace.
- left_pad = left_pad + font->getWidth(mTextEntry->getText()) + font->getWidth(" ");
-
- LLRect rect = mMaturityButton->getRect();
- mMaturityButton->setRect(rect.setOriginAndSize(left_pad, rect.mBottom, rect.getWidth(), rect.getHeight()));
-
- // Hide icon if it text area is not width enough to display it, show otherwise.
- mMaturityButton->setVisible(rect.mRight < mTextEntry->getRect().getWidth() - right_pad);
-}
-
-void LLLocationInputCtrl::addLocationHistoryEntry(const std::string& title, const LLSD& value)
-{
- // SL-20286 : Duplication of autocomplete results occurs when entering some search queries in the navigation bar
- // Exclude visual duplicates (items with the same titles) in the dropdown list
- LLScrollListItem* item = mList->getItemByLabel(title);
- if (!item)
- {
- add(title, value);
- }
-}
-
-void LLLocationInputCtrl::rebuildLocationHistory(const std::string& filter)
-{
- LLLocationHistory::location_list_t filtered_items;
- const LLLocationHistory::location_list_t* itemsp = NULL;
- LLLocationHistory* lh = LLLocationHistory::getInstance();
-
- if (filter.empty())
- {
- itemsp = &lh->getItems();
- }
- else
- {
- lh->getMatchingItems(filter, filtered_items);
- itemsp = &filtered_items;
- }
-
- removeall();
- for (LLLocationHistory::location_list_t::const_reverse_iterator it = itemsp->rbegin(); it != itemsp->rend(); it++)
- {
- LLSD value;
- value["tooltip"] = it->getToolTip();
- //location history can contain only typed locations
- value["item_type"] = TYPED_REGION_SLURL;
- value["global_pos"] = it->mGlobalPos.getValue();
- addLocationHistoryEntry(it->getLocation(), value);
- }
-}
-
-void LLLocationInputCtrl::focusTextEntry()
-{
- // 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);
-
- // Enable the text entry to handle accelerator keys (EXT-8104).
- LLEditMenuHandler::gEditMenuHandler = mTextEntry;
- }
-}
-
-void LLLocationInputCtrl::enableAddLandmarkButton(bool val)
-{
- // We don't want to disable the button because it should be click able at any time,
- // instead switch images.
- LLUIImage* img = val ? mLandmarkImageOn : mLandmarkImageOff;
- if(img)
- {
- mAddLandmarkBtn->setImageUnselected(img);
- }
-}
-
-// Change the "Add landmark" button image
-// depending on whether current parcel has been landmarked.
-void LLLocationInputCtrl::updateAddLandmarkButton()
-{
- enableAddLandmarkButton(LLLandmarkActions::hasParcelLandmark());
-}
-void LLLocationInputCtrl::updateAddLandmarkTooltip()
-{
- std::string tooltip;
- if(LLLandmarkActions::landmarkAlreadyExists())
- {
- tooltip = mEditLandmarkTooltip;
- }
- else
- {
- tooltip = mAddLandmarkTooltip;
- }
- mAddLandmarkBtn->setToolTip(tooltip);
-}
-
-void LLLocationInputCtrl::updateContextMenu(){
-
- if (mLocationContextMenu)
- {
- LLMenuItemGL* landmarkItem = mLocationContextMenu->getChild<LLMenuItemGL>("Landmark");
- if (!LLLandmarkActions::landmarkAlreadyExists())
- {
- landmarkItem->setLabel(LLTrans::getString("AddLandmarkNavBarMenu"));
- }
- else
- {
- landmarkItem->setLabel(LLTrans::getString("EditLandmarkNavBarMenu"));
- }
- }
-}
-void LLLocationInputCtrl::updateWidgetlayout()
-{
- const LLRect& rect = getLocalRect();
- const LLRect& hist_btn_rect = mButton->getRect();
-
- // Info button is set in the XUI XML location_input.xml
-
- // "Add Landmark" button
- LLRect al_btn_rect = mAddLandmarkBtn->getRect();
- al_btn_rect.translate(
- hist_btn_rect.mLeft - mIconHPad - al_btn_rect.getWidth(),
- (rect.getHeight() - al_btn_rect.getHeight()) / 2);
- mAddLandmarkBtn->setRect(al_btn_rect);
-}
-
-void LLLocationInputCtrl::changeLocationPresentation()
-{
- if (!mTextEntry)
- return;
-
- //change location presentation only if user does not select/paste anything and
- //human-readable region name is being displayed
- if(!mTextEntry->hasSelection() && mTextEntry->getText() == mHumanReadableLocation)
- {
- //needs unescaped one
- LLSLURL slurl;
- LLAgentUI::buildSLURL(slurl, false);
- mTextEntry->setText(LLURI::unescape(slurl.getSLURLString()));
- mTextEntry->selectAll();
-
- mMaturityButton->setVisible(false);
-
- isHumanReadableLocationVisible = false;
- }
-}
-
-void LLLocationInputCtrl::onLocationContextMenuItemClicked(const LLSD& userdata)
-{
- std::string item = userdata.asString();
-
- if (item == "show_coordinates")
- {
- gSavedSettings.setBOOL("NavBarShowCoordinates",!gSavedSettings.getBOOL("NavBarShowCoordinates"));
- }
- else if (item == "show_properties")
- {
- gSavedSettings.setBOOL("NavBarShowParcelProperties",
- !gSavedSettings.getBOOL("NavBarShowParcelProperties"));
- }
- else if (item == "landmark")
- {
- LLViewerInventoryItem* landmark = LLLandmarkActions::findLandmarkForAgentPos();
-
- if(!landmark)
- {
- LLFloaterReg::showInstance("add_landmark");
- }
- else
- {
- LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "landmark").with("id",landmark->getUUID()));
-
- }
- }
- else if (item == "cut")
- {
- mTextEntry->cut();
- }
- else if (item == "copy")
- {
- mTextEntry->copy();
- }
- else if (item == "paste")
- {
- mTextEntry->paste();
- }
- else if (item == "delete")
- {
- mTextEntry->deleteSelection();
- }
- else if (item == "select_all")
- {
- mTextEntry->selectAll();
- }
-}
-
-bool LLLocationInputCtrl::onLocationContextMenuItemEnabled(const LLSD& userdata)
-{
- std::string item = userdata.asString();
-
- if (item == "can_cut")
- {
- return mTextEntry->canCut();
- }
- else if (item == "can_copy")
- {
- return mTextEntry->canCopy();
- }
- else if (item == "can_paste")
- {
- return mTextEntry->canPaste();
- }
- else if (item == "can_delete")
- {
- return mTextEntry->canDeselect();
- }
- else if (item == "can_select_all")
- {
- return mTextEntry->canSelectAll() && (mTextEntry->getLength() > 0);
- }
- else if(item == "show_coordinates")
- {
- return gSavedSettings.getBOOL("NavBarShowCoordinates");
- }
-
- return false;
-}
-
-void LLLocationInputCtrl::callbackRebakeRegion(const LLSD& notification, const LLSD& response)
-{
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
- if (option == 0) // OK
- {
- if (LLPathfindingManager::getInstance() != NULL)
- {
- LLMenuOptionPathfindingRebakeNavmesh::getInstance()->sendRequestRebakeNavmesh();
- }
- }
-}
-
-void LLLocationInputCtrl::onParcelIconClick(EParcelIcon icon)
-{
- switch (icon)
- {
- case VOICE_ICON:
- LLNotificationsUtil::add("NoVoice");
- break;
- case FLY_ICON:
- LLNotificationsUtil::add("NoFly");
- break;
- case PUSH_ICON:
- LLNotificationsUtil::add("PushRestricted");
- break;
- case BUILD_ICON:
- LLNotificationsUtil::add("NoBuild");
- break;
- case PATHFINDING_DIRTY_ICON:
- if (LLPathfindingManager::getInstance() != NULL)
- {
- LLMenuOptionPathfindingRebakeNavmesh *rebakeInstance = LLMenuOptionPathfindingRebakeNavmesh::getInstance();
- if (rebakeInstance && rebakeInstance->canRebakeRegion() && (rebakeInstance->getMode() == LLMenuOptionPathfindingRebakeNavmesh::kRebakeNavMesh_Available))
- {
- LLNotificationsUtil::add("PathfindingDirtyRebake", LLSD(), LLSD(),
- boost::bind(&LLLocationInputCtrl::callbackRebakeRegion, this, _1, _2));
- break;
- }
- }
- LLNotificationsUtil::add("PathfindingDirty");
- break;
- case PATHFINDING_DISABLED_ICON:
- LLNotificationsUtil::add("DynamicPathfindingDisabled");
- break;
- case SCRIPTS_ICON:
- {
- LLViewerRegion* region = gAgent.getRegion();
- if(region && region->getRegionFlag(REGION_FLAGS_ESTATE_SKIP_SCRIPTS))
- {
- LLNotificationsUtil::add("ScriptsStopped");
- }
- else if(region && region->getRegionFlag(REGION_FLAGS_SKIP_SCRIPTS))
- {
- LLNotificationsUtil::add("ScriptsNotRunning");
- }
- else
- {
- LLNotificationsUtil::add("NoOutsideScripts");
- }
- break;
- }
- case DAMAGE_ICON:
- LLNotificationsUtil::add("NotSafe");
- break;
- case SEE_AVATARS_ICON:
- LLNotificationsUtil::add("SeeAvatars");
- break;
- case ICON_COUNT:
- break;
- // no default to get compiler warning when a new icon gets added
- }
-}
-
-void LLLocationInputCtrl::createNavMeshStatusListenerForCurrentRegion()
-{
- if (mNavMeshSlot.connected())
- {
- mNavMeshSlot.disconnect();
- }
-
- LLViewerRegion *currentRegion = gAgent.getRegion();
- if (currentRegion != NULL)
- {
- mNavMeshSlot = LLPathfindingManager::getInstance()->registerNavMeshListenerForRegion(currentRegion, boost::bind(&LLLocationInputCtrl::onNavMeshStatusChange, this, _2));
- LLPathfindingManager::getInstance()->requestGetNavMeshForRegion(currentRegion, true);
- }
-}
+/** + * @file lllocationinputctrl.cpp + * @brief Combobox-like location input control + * + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +// file includes +#include "lllocationinputctrl.h" + +// common includes +#include "llbutton.h" +#include "llfocusmgr.h" +#include "llhelp.h" +#include "llmenugl.h" +#include "llparcel.h" +#include "llstring.h" +#include "lltrans.h" +#include "lluictrlfactory.h" +#include "lltooltip.h" +#include "llnotificationsutil.h" +#include "llregionflags.h" + +// newview includes +#include "llagent.h" +#include "llfloaterreg.h" +#include "llfloatersidepanelcontainer.h" +#include "llinventoryobserver.h" +#include "lllandmarkactions.h" +#include "lllandmarklist.h" +#include "llpathfindingmanager.h" +#include "llpathfindingnavmesh.h" +#include "llpathfindingnavmeshstatus.h" +#include "llteleporthistory.h" +#include "llslurl.h" +#include "llstatusbar.h" // getHealth() +#include "lltrans.h" +#include "llviewerinventory.h" +#include "llviewerparcelmgr.h" +#include "llviewerregion.h" +#include "llviewercontrol.h" +#include "llviewermenu.h" +#include "llurllineeditorctrl.h" +#include "llagentui.h" + +#include "llmenuoptionpathfindingrebakenavmesh.h" +#include "llpathfindingmanager.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. + */ + +/** + * 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 +{ +public: + LLAddLandmarkObserver(LLLocationInputCtrl* input) : mInput(input) {} + +private: + /*virtual*/ void done() + { + const uuid_set_t& added = gInventory.getAddedIDs(); + for (uuid_set_t::const_iterator it = added.begin(); it != added.end(); ++it) + { + 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); + } + } + } + + LLLocationInputCtrl* mInput; +}; + +/** + * Updates the "Add landmark" button once a landmark gets removed. + */ +class LLRemoveLandmarkObserver : public LLInventoryObserver +{ +public: + LLRemoveLandmarkObserver(LLLocationInputCtrl* input) : mInput(input) {} + +private: + /*virtual*/ void changed(U32 mask) + { + if (mask & (~(LLInventoryObserver::LABEL| + LLInventoryObserver::INTERNAL| + LLInventoryObserver::ADD| + LLInventoryObserver::CREATE| + LLInventoryObserver::UPDATE_CREATE))) + { + mInput->updateAddLandmarkButton(); + } + } + + LLLocationInputCtrl* mInput; +}; + +class LLParcelChangeObserver : public LLParcelObserver +{ +public: + LLParcelChangeObserver(LLLocationInputCtrl* input) : mInput(input) {} + +private: + /*virtual*/ void changed() + { + if (mInput) + { + mInput->refreshParcelIcons(); + } + } + + LLLocationInputCtrl* mInput; +}; + +//============================================================================ + + +static LLDefaultChildRegistry::Register<LLLocationInputCtrl> r("location_input"); + +LLLocationInputCtrl::Params::Params() +: icon_maturity_general("icon_maturity_general"), + icon_maturity_adult("icon_maturity_adult"), + icon_maturity_moderate("icon_maturity_moderate"), + add_landmark_image_enabled("add_landmark_image_enabled"), + add_landmark_image_disabled("add_landmark_image_disabled"), + add_landmark_image_hover("add_landmark_image_hover"), + add_landmark_image_selected("add_landmark_image_selected"), + add_landmark_hpad("add_landmark_hpad", 0), + icon_hpad("icon_hpad", 0), + add_landmark_button("add_landmark_button"), + for_sale_button("for_sale_button"), + info_button("info_button"), + maturity_button("maturity_button"), + voice_icon("voice_icon"), + fly_icon("fly_icon"), + push_icon("push_icon"), + build_icon("build_icon"), + scripts_icon("scripts_icon"), + damage_icon("damage_icon"), + damage_text("damage_text"), + see_avatars_icon("see_avatars_icon"), + maturity_help_topic("maturity_help_topic"), + pathfinding_dirty_icon("pathfinding_dirty_icon"), + pathfinding_disabled_icon("pathfinding_disabled_icon") +{ +} + +LLLocationInputCtrl::LLLocationInputCtrl(const LLLocationInputCtrl::Params& p) +: LLComboBox(p), + mIconHPad(p.icon_hpad), + mAddLandmarkHPad(p.add_landmark_hpad), + mLocationContextMenu(NULL), + mAddLandmarkBtn(NULL), + mForSaleBtn(NULL), + mInfoBtn(NULL), + mRegionCrossingSlot(), + mNavMeshSlot(), + mIsNavMeshDirty(false), + mLandmarkImageOn(NULL), + mLandmarkImageOff(NULL), + mIconMaturityGeneral(NULL), + mIconMaturityAdult(NULL), + mIconMaturityModerate(NULL), + mMaturityHelpTopic(p.maturity_help_topic) +{ + // Lets replace default LLLineEditor with LLLocationLineEditor + // to make needed escaping while copying and cutting url + delete mTextEntry; + + // Can't access old mTextEntry fields as they are protected, so lets build new params + // That is C&P from LLComboBox::createLineEditor function + S32 arrow_width = mArrowImage ? mArrowImage->getWidth() : 0; + LLRect text_entry_rect(0, getRect().getHeight(), getRect().getWidth(), 0); + text_entry_rect.mRight -= llmax(8,arrow_width) + 2 * BTN_DROP_SHADOW; + + LLLineEditor::Params params = p.combo_editor; + params.rect(text_entry_rect); + params.default_text(LLStringUtil::null); + params.max_length.bytes(p.max_chars); + params.keystroke_callback(boost::bind(&LLLocationInputCtrl::onTextEntry, this, _1)); + params.commit_on_focus_lost(false); + params.follows.flags(FOLLOWS_ALL); + mTextEntry = LLUICtrlFactory::create<LLURLLineEditor>(params); + mTextEntry->resetContextMenu(); + addChild(mTextEntry); + // LLLineEditor is replaced with LLLocationLineEditor + + // "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; + + // Image for unselected state will be set in updateAddLandmarkButton(), + // it will be either mLandmarkOn or mLandmarkOff + if (p.add_landmark_image_enabled()) + { + mLandmarkImageOn = p.add_landmark_image_enabled; + } + if (p.add_landmark_image_disabled()) + { + mLandmarkImageOff = p.add_landmark_image_disabled; + } + + if(p.add_landmark_image_selected) + { + al_params.image_selected = p.add_landmark_image_selected; + } + if (p.add_landmark_image_hover()) + { + al_params.image_hover_unselected = p.add_landmark_image_hover; + } + + al_params.click_callback.function(boost::bind(&LLLocationInputCtrl::onAddLandmarkButtonClicked, this)); + mAddLandmarkBtn = LLUICtrlFactory::create<LLButton>(al_params); + enableAddLandmarkButton(true); + addChild(mAddLandmarkBtn); + + if (p.icon_maturity_general()) + { + mIconMaturityGeneral = p.icon_maturity_general; + } + if (p.icon_maturity_adult()) + { + mIconMaturityAdult = p.icon_maturity_adult; + } + if(p.icon_maturity_moderate()) + { + mIconMaturityModerate = p.icon_maturity_moderate; + } + + LLButton::Params maturity_button = p.maturity_button; + mMaturityButton = LLUICtrlFactory::create<LLButton>(maturity_button); + addChild(mMaturityButton); + + LLButton::Params for_sale_button = p.for_sale_button; + for_sale_button.tool_tip = LLTrans::getString("LocationCtrlForSaleTooltip"); + for_sale_button.click_callback.function( + boost::bind(&LLLocationInputCtrl::onForSaleButtonClicked, this)); + mForSaleBtn = LLUICtrlFactory::create<LLButton>( for_sale_button ); + addChild(mForSaleBtn); + + // Parcel property icons + // Must be mouse-opaque so cursor stays as an arrow when hovering to + // see tooltip. + LLIconCtrl::Params voice_icon = p.voice_icon; + voice_icon.tool_tip = LLTrans::getString("LocationCtrlVoiceTooltip"); + voice_icon.mouse_opaque = true; + mParcelIcon[VOICE_ICON] = LLUICtrlFactory::create<LLIconCtrl>(voice_icon); + mParcelIcon[VOICE_ICON]->setMouseDownCallback(boost::bind(&LLLocationInputCtrl::onParcelIconClick, this, VOICE_ICON)); + addChild(mParcelIcon[VOICE_ICON]); + + LLIconCtrl::Params fly_icon = p.fly_icon; + fly_icon.tool_tip = LLTrans::getString("LocationCtrlFlyTooltip"); + fly_icon.mouse_opaque = true; + mParcelIcon[FLY_ICON] = LLUICtrlFactory::create<LLIconCtrl>(fly_icon); + mParcelIcon[FLY_ICON]->setMouseDownCallback(boost::bind(&LLLocationInputCtrl::onParcelIconClick, this, FLY_ICON)); + addChild(mParcelIcon[FLY_ICON]); + + LLIconCtrl::Params push_icon = p.push_icon; + push_icon.tool_tip = LLTrans::getString("LocationCtrlPushTooltip"); + push_icon.mouse_opaque = true; + mParcelIcon[PUSH_ICON] = LLUICtrlFactory::create<LLIconCtrl>(push_icon); + mParcelIcon[PUSH_ICON]->setMouseDownCallback(boost::bind(&LLLocationInputCtrl::onParcelIconClick, this, PUSH_ICON)); + addChild(mParcelIcon[PUSH_ICON]); + + LLIconCtrl::Params build_icon = p.build_icon; + build_icon.tool_tip = LLTrans::getString("LocationCtrlBuildTooltip"); + build_icon.mouse_opaque = true; + mParcelIcon[BUILD_ICON] = LLUICtrlFactory::create<LLIconCtrl>(build_icon); + mParcelIcon[BUILD_ICON]->setMouseDownCallback(boost::bind(&LLLocationInputCtrl::onParcelIconClick, this, BUILD_ICON)); + addChild(mParcelIcon[BUILD_ICON]); + + LLIconCtrl::Params scripts_icon = p.scripts_icon; + scripts_icon.tool_tip = LLTrans::getString("LocationCtrlScriptsTooltip"); + scripts_icon.mouse_opaque = true; + mParcelIcon[SCRIPTS_ICON] = LLUICtrlFactory::create<LLIconCtrl>(scripts_icon); + mParcelIcon[SCRIPTS_ICON]->setMouseDownCallback(boost::bind(&LLLocationInputCtrl::onParcelIconClick, this, SCRIPTS_ICON)); + addChild(mParcelIcon[SCRIPTS_ICON]); + + LLIconCtrl::Params damage_icon = p.damage_icon; + damage_icon.tool_tip = LLTrans::getString("LocationCtrlDamageTooltip"); + damage_icon.mouse_opaque = true; + mParcelIcon[DAMAGE_ICON] = LLUICtrlFactory::create<LLIconCtrl>(damage_icon); + mParcelIcon[DAMAGE_ICON]->setMouseDownCallback(boost::bind(&LLLocationInputCtrl::onParcelIconClick, this, DAMAGE_ICON)); + addChild(mParcelIcon[DAMAGE_ICON]); + + LLIconCtrl::Params pathfinding_dirty_icon = p.pathfinding_dirty_icon; + pathfinding_dirty_icon.tool_tip = LLTrans::getString("LocationCtrlPathfindingDirtyTooltip"); + pathfinding_dirty_icon.mouse_opaque = true; + mParcelIcon[PATHFINDING_DIRTY_ICON] = LLUICtrlFactory::create<LLIconCtrl>(pathfinding_dirty_icon); + mParcelIcon[PATHFINDING_DIRTY_ICON]->setMouseDownCallback(boost::bind(&LLLocationInputCtrl::onParcelIconClick, this, PATHFINDING_DIRTY_ICON)); + addChild(mParcelIcon[PATHFINDING_DIRTY_ICON]); + + LLIconCtrl::Params pathfinding_disabled_icon = p.pathfinding_disabled_icon; + pathfinding_disabled_icon.tool_tip = LLTrans::getString("LocationCtrlPathfindingDisabledTooltip"); + pathfinding_disabled_icon.mouse_opaque = true; + mParcelIcon[PATHFINDING_DISABLED_ICON] = LLUICtrlFactory::create<LLIconCtrl>(pathfinding_disabled_icon); + mParcelIcon[PATHFINDING_DISABLED_ICON]->setMouseDownCallback(boost::bind(&LLLocationInputCtrl::onParcelIconClick, this, PATHFINDING_DISABLED_ICON)); + addChild(mParcelIcon[PATHFINDING_DISABLED_ICON]); + + LLTextBox::Params damage_text = p.damage_text; + damage_text.tool_tip = LLTrans::getString("LocationCtrlDamageTooltip"); + damage_text.mouse_opaque = true; + mDamageText = LLUICtrlFactory::create<LLTextBox>(damage_text); + addChild(mDamageText); + + LLIconCtrl::Params see_avatars_icon = p.see_avatars_icon; + see_avatars_icon.tool_tip = LLTrans::getString("LocationCtrlSeeAVsTooltip"); + see_avatars_icon.mouse_opaque = true; + mParcelIcon[SEE_AVATARS_ICON] = LLUICtrlFactory::create<LLIconCtrl>(see_avatars_icon); + mParcelIcon[SEE_AVATARS_ICON]->setMouseDownCallback(boost::bind(&LLLocationInputCtrl::onParcelIconClick, this, SEE_AVATARS_ICON)); + addChild(mParcelIcon[SEE_AVATARS_ICON]); + + // Register callbacks and load the location field context menu (NB: the order matters). + LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Navbar.Action", boost::bind(&LLLocationInputCtrl::onLocationContextMenuItemClicked, this, _2)); + LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("Navbar.EnableMenuItem", boost::bind(&LLLocationInputCtrl::onLocationContextMenuItemEnabled, this, _2)); + + setPrearrangeCallback(boost::bind(&LLLocationInputCtrl::onLocationPrearrange, this, _2)); + getTextEntry()->setMouseUpCallback(boost::bind(&LLLocationInputCtrl::changeLocationPresentation, this)); + + // Load the location field context menu + mLocationContextMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_navbar.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + if (!mLocationContextMenu) + { + LL_WARNS() << "Error loading navigation bar context menu" << LL_ENDL; + + } + //don't show default context menu + getTextEntry()->setShowContextMenu(false); + getTextEntry()->setRightMouseDownCallback(boost::bind(&LLLocationInputCtrl::onTextEditorRightClicked, this, _2, _3, _4)); + updateWidgetlayout(); + + // Connecting signal for updating location on "Show Coordinates" setting change. + LLControlVariable* coordinates_control = gSavedSettings.getControl("NavBarShowCoordinates").get(); + if (coordinates_control) + { + mCoordinatesControlConnection = coordinates_control->getSignal()->connect(boost::bind(&LLLocationInputCtrl::refreshLocation, this)); + } + + // Connecting signal for updating parcel icons on "Show Parcel Properties" setting change. + LLControlVariable* parcel_properties_control = gSavedSettings.getControl("NavBarShowParcelProperties").get(); + if (parcel_properties_control) + { + mParcelPropertiesControlConnection = parcel_properties_control->getSignal()->connect(boost::bind(&LLLocationInputCtrl::refreshParcelIcons, this)); + } + + // - 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. + mParcelMgrConnection = gAgent.addParcelChangedCallback( + boost::bind(&LLLocationInputCtrl::onAgentParcelChange, this)); + // LLLocationHistory instance is being created before the location input control, so we have to update initial state of button manually. + mButton->setEnabled(LLLocationHistory::instance().getItemCount() > 0); + mLocationHistoryConnection = LLLocationHistory::getInstance()->setChangedCallback( + boost::bind(&LLLocationInputCtrl::onLocationHistoryChanged, this,_1)); + + mRegionCrossingSlot = gAgent.addRegionChangedCallback(boost::bind(&LLLocationInputCtrl::onRegionBoundaryCrossed, this)); + createNavMeshStatusListenerForCurrentRegion(); + + mRemoveLandmarkObserver = new LLRemoveLandmarkObserver(this); + mAddLandmarkObserver = new LLAddLandmarkObserver(this); + gInventory.addObserver(mRemoveLandmarkObserver); + gInventory.addObserver(mAddLandmarkObserver); + + mParcelChangeObserver = new LLParcelChangeObserver(this); + LLViewerParcelMgr::getInstance()->addObserver(mParcelChangeObserver); + + mAddLandmarkTooltip = LLTrans::getString("LocationCtrlAddLandmarkTooltip"); + mEditLandmarkTooltip = LLTrans::getString("LocationCtrlEditLandmarkTooltip"); + mButton->setToolTip(LLTrans::getString("LocationCtrlComboBtnTooltip")); + mInfoBtn->setToolTip(LLTrans::getString("LocationCtrlInfoBtnTooltip")); +} + +LLLocationInputCtrl::~LLLocationInputCtrl() +{ + gInventory.removeObserver(mRemoveLandmarkObserver); + gInventory.removeObserver(mAddLandmarkObserver); + delete mRemoveLandmarkObserver; + delete mAddLandmarkObserver; + + LLViewerParcelMgr::getInstance()->removeObserver(mParcelChangeObserver); + delete mParcelChangeObserver; + + mRegionCrossingSlot.disconnect(); + mNavMeshSlot.disconnect(); + mCoordinatesControlConnection.disconnect(); + mParcelPropertiesControlConnection.disconnect(); + mParcelMgrConnection.disconnect(); + mLocationHistoryConnection.disconnect(); +} + +void LLLocationInputCtrl::setEnabled(bool enabled) +{ + LLComboBox::setEnabled(enabled); + mAddLandmarkBtn->setEnabled(enabled); +} + +void LLLocationInputCtrl::hideList() +{ + LLComboBox::hideList(); + if (mTextEntry && hasFocus()) + focusTextEntry(); +} + +bool LLLocationInputCtrl::handleToolTip(S32 x, S32 y, MASK mask) +{ + + if(mAddLandmarkBtn->parentPointInView(x,y)) + { + updateAddLandmarkTooltip(); + } + // Let the buttons show their tooltips. + if (LLUICtrl::handleToolTip(x, y, mask)) + { + if (mList->getRect().pointInRect(x, y)) + { + S32 loc_x, loc_y; + //x,y - contain coordinates related to the location input control, but without taking the expanded list into account + //So we have to convert it again into local coordinates of mList + localPointToOtherView(x,y,&loc_x,&loc_y,mList); + + LLScrollListItem* item = mList->hitItem(loc_x,loc_y); + if (item) + { + LLSD value = item->getValue(); + if (value.has("tooltip")) + { + LLToolTipMgr::instance().show(value["tooltip"]); + } + } + } + + return true; + } + + return false; +} + +bool LLLocationInputCtrl::handleKeyHere(KEY key, MASK mask) +{ + bool result = LLComboBox::handleKeyHere(key, mask); + + if (key == KEY_DOWN && hasFocus() && mList->getItemCount() != 0 && !mList->getVisible()) + { + showList(); + } + + return result; +} + +void LLLocationInputCtrl::onTextEntry(LLLineEditor* line_editor) +{ + KEY key = gKeyboard->currentKey(); + MASK mask = gKeyboard->currentMask(true); + + // Typing? (moving cursor should not affect showing the list) + bool typing = mask != MASK_CONTROL && key != KEY_LEFT && key != KEY_RIGHT && key != KEY_HOME && key != KEY_END; + bool pasting = mask == MASK_CONTROL && key == 'V'; + + if (line_editor->getText().empty()) + { + prearrangeList(); // resets filter + hideList(); + } + else if (typing || pasting) + { + prearrangeList(line_editor->getText()); + if (mList->getItemCount() != 0) + { + showList(); + focusTextEntry(); + } + else + { + // Hide the list if it's empty. + hideList(); + } + } + + 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); + } + mHasAutocompletedText = false; +} + +void LLLocationInputCtrl::setFocus(bool b) +{ + LLComboBox::setFocus(b); + + if (mTextEntry && b && !mList->getVisible()) + { + mTextEntry->setFocus(true); + } +} + +void LLLocationInputCtrl::handleLoginComplete() +{ + // An agent parcel update hasn't occurred yet, so we have to + // manually set location and the appropriate "Add landmark" icon. + refresh(); +} + +//== private methods ========================================================= + +void LLLocationInputCtrl::onFocusReceived() +{ + prearrangeList(); +} + +void LLLocationInputCtrl::onFocusLost() +{ + LLUICtrl::onFocusLost(); + refreshLocation(); + + // Setting cursor to 0 to show the left edge of the text. See STORM-370. + mTextEntry->setCursor(0); + + if(mTextEntry->hasSelection()){ + mTextEntry->deselect(); + } +} + +void LLLocationInputCtrl::draw() +{ + static LLUICachedControl<bool> show_coords("NavBarShowCoordinates", false); + if(!hasFocus() && show_coords) + { + refreshLocation(); + } + + static LLUICachedControl<bool> show_icons("NavBarShowParcelProperties", false); + if (show_icons) + { + refreshHealth(); + } + LLComboBox::draw(); +} + +void LLLocationInputCtrl::reshape(S32 width, S32 height, bool called_from_parent) +{ + LLComboBox::reshape(width, height, called_from_parent); + + // Setting cursor to 0 to show the left edge of the text. See EXT-4967. + mTextEntry->setCursor(0); + if (mTextEntry->hasSelection()) + { + // Deselecting because selection position is changed together with + // cursor position change. + mTextEntry->deselect(); + } + + if (isHumanReadableLocationVisible) + { + refreshMaturityButton(); + } +} + +void LLLocationInputCtrl::onInfoButtonClicked() +{ + LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "agent")); +} + +void LLLocationInputCtrl::onForSaleButtonClicked() +{ + handle_buy_land(); +} + +void LLLocationInputCtrl::onAddLandmarkButtonClicked() +{ + LLViewerInventoryItem* landmark = LLLandmarkActions::findLandmarkForAgentPos(); + // Landmark exists, open it for preview and edit + if(landmark && landmark->getUUID().notNull()) + { + LLSD key; + key["type"] = "landmark"; + key["id"] = landmark->getUUID(); + + LLFloaterSidePanelContainer::showPanel("places", key); + } + else + { + LLFloaterReg::showInstance("add_landmark"); + } +} + +void LLLocationInputCtrl::onAgentParcelChange() +{ + refresh(); +} + +void LLLocationInputCtrl::onRegionBoundaryCrossed() +{ + createNavMeshStatusListenerForCurrentRegion(); +} + +void LLLocationInputCtrl::onNavMeshStatusChange(const LLPathfindingNavMeshStatus &pNavMeshStatus) +{ + mIsNavMeshDirty = pNavMeshStatus.isValid() && (pNavMeshStatus.getStatus() != LLPathfindingNavMeshStatus::kComplete); + refreshParcelIcons(); +} + +void LLLocationInputCtrl::onLandmarkLoaded(LLLandmark* lm) +{ + (void) lm; + updateAddLandmarkButton(); +} + +void LLLocationInputCtrl::onLocationHistoryChanged(LLLocationHistory::EChangeType event) +{ + if(event == LLLocationHistory::LOAD) + { + rebuildLocationHistory(); + } + mButton->setEnabled(LLLocationHistory::instance().getItemCount() > 0); +} + +void LLLocationInputCtrl::onLocationPrearrange(const LLSD& data) +{ + std::string filter = data.asString(); + rebuildLocationHistory(filter); + + //Let's add landmarks to the top of the list if any + if(!filter.empty() ) + { + LLInventoryModel::item_array_t landmark_items = LLLandmarkActions::fetchLandmarksByName(filter, true); + + for(U32 i=0; i < landmark_items.size(); i++) + { + LLSD value; + //TODO:: DO we need tooltip for Landmark?? + + value["item_type"] = LANDMARK; + value["AssetUUID"] = landmark_items[i]->getAssetUUID(); + addLocationHistoryEntry(landmark_items[i]->getName(), value); + + } + //Let's add teleport history items + LLTeleportHistory* th = LLTeleportHistory::getInstance(); + LLTeleportHistory::slurl_list_t th_items = th->getItems(); + + std::set<std::string> new_item_titles;// duplicate control + LLTeleportHistory::slurl_list_t::iterator result = std::find_if( + th_items.begin(), th_items.end(), boost::bind( + &LLLocationInputCtrl::findTeleportItemsByTitle, this, + _1, filter)); + + while (result != th_items.end()) + { + //mTitile format - region_name[, parcel_name] + //mFullTitile format - region_name[, parcel_name] (local_x,local_y, local_z) + if (new_item_titles.insert(result->mFullTitle).second) + { + LLSD value; + value["item_type"] = TELEPORT_HISTORY; + value["global_pos"] = result->mGlobalPos.getValue(); + std::string region_name = result->mTitle.substr(0, result->mTitle.find(',')); + //TODO*: add Surl to teleportitem or parse region name from title + value["tooltip"] = LLSLURL(region_name, result->mGlobalPos).getSLURLString(); + addLocationHistoryEntry(result->getTitle(), value); + } + result = std::find_if(result + 1, th_items.end(), boost::bind( + &LLLocationInputCtrl::findTeleportItemsByTitle, this, + _1, filter)); + } + } + sortByName(); + + mList->mouseOverHighlightNthItem(-1); // Clear highlight on the last selected item. +} + +bool LLLocationInputCtrl::findTeleportItemsByTitle(const LLTeleportHistoryItem& item, const std::string& filter) +{ + return item.mTitle.find(filter) != std::string::npos; +} + +void LLLocationInputCtrl::onTextEditorRightClicked(S32 x, S32 y, MASK mask) +{ + if (mLocationContextMenu) + { + updateContextMenu(); + mLocationContextMenu->buildDrawLabels(); + mLocationContextMenu->updateParent(LLMenuGL::sMenuContainer); + hideList(); + setFocus(true); + changeLocationPresentation(); + LLMenuGL::showPopup(this, mLocationContextMenu, x, y); + } +} + +void LLLocationInputCtrl::refresh() +{ + refreshLocation(); // update location string + refreshParcelIcons(); + updateAddLandmarkButton(); // indicate whether current parcel has been landmarked +} + +void LLLocationInputCtrl::refreshLocation() +{ + // Is one of our children focused? + if (LLUICtrl::hasFocus() || mButton->hasFocus() || mList->hasFocus() || + (mTextEntry && mTextEntry->hasFocus()) || + (mAddLandmarkBtn->hasFocus())) + { + LL_WARNS() << "Location input should not be refreshed when having focus" << LL_ENDL; + return; + } + + // Update location field. + std::string location_name; + LLAgentUI::ELocationFormat format = + (gSavedSettings.getBOOL("NavBarShowCoordinates") + ? LLAgentUI::LOCATION_FORMAT_FULL + : LLAgentUI::LOCATION_FORMAT_NO_COORDS); + + if (!LLAgentUI::buildLocationString(location_name, format)) + { + location_name = "???"; + } + // store human-readable location to compare it in changeLocationPresentation() + mHumanReadableLocation = location_name; + setText(location_name); + isHumanReadableLocationVisible = true; + + refreshMaturityButton(); +} + +// returns new right edge +static S32 layout_widget(LLUICtrl* widget, S32 right) +{ + if (widget->getVisible()) + { + LLRect rect = widget->getRect(); + rect.mLeft = right - rect.getWidth(); + rect.mRight = right; + widget->setRect( rect ); + right -= rect.getWidth(); + } + return right; +} + +void LLLocationInputCtrl::refreshParcelIcons() +{ + // Our "cursor" moving right to left + S32 x = mAddLandmarkBtn->getRect().mLeft; + + LLViewerParcelMgr* vpm = LLViewerParcelMgr::getInstance(); + + LLViewerRegion* agent_region = gAgent.getRegion(); + LLParcel* agent_parcel = vpm->getAgentParcel(); + if (!agent_region || !agent_parcel) + return; + + mForSaleBtn->setVisible(vpm->canAgentBuyParcel(agent_parcel, false)); + + x = layout_widget(mForSaleBtn, x); + + if (gSavedSettings.getBOOL("NavBarShowParcelProperties")) + { + LLParcel* current_parcel; + LLViewerRegion* selection_region = vpm->getSelectionRegion(); + LLParcel* selected_parcel = vpm->getParcelSelection()->getParcel(); + + // If agent is in selected parcel we use its properties because + // they are updated more often by LLViewerParcelMgr than agent parcel properties. + // See LLViewerParcelMgr::processParcelProperties(). + // This is needed to reflect parcel restrictions changes without having to leave + // the parcel and then enter it again. See EXT-2987 + if (selected_parcel && selected_parcel->getLocalID() == agent_parcel->getLocalID() + && selection_region == agent_region) + { + current_parcel = selected_parcel; + } + else + { + current_parcel = agent_parcel; + } + + bool allow_voice = vpm->allowAgentVoice(agent_region, current_parcel); + bool allow_fly = vpm->allowAgentFly(agent_region, current_parcel); + bool allow_push = vpm->allowAgentPush(agent_region, current_parcel); + bool allow_build = vpm->allowAgentBuild(current_parcel); // true when anyone is allowed to build. See EXT-4610. + bool allow_scripts = vpm->allowAgentScripts(agent_region, current_parcel); + bool allow_damage = vpm->allowAgentDamage(agent_region, current_parcel); + bool see_avs = current_parcel->getSeeAVs(); + bool pathfinding_dynamic_enabled = agent_region->dynamicPathfindingEnabled(); + + // Most icons are "block this ability" + mParcelIcon[VOICE_ICON]->setVisible( !allow_voice ); + mParcelIcon[FLY_ICON]->setVisible( !allow_fly ); + mParcelIcon[PUSH_ICON]->setVisible( !allow_push ); + mParcelIcon[BUILD_ICON]->setVisible( !allow_build ); + mParcelIcon[SCRIPTS_ICON]->setVisible( !allow_scripts ); + mParcelIcon[DAMAGE_ICON]->setVisible( allow_damage ); + mParcelIcon[PATHFINDING_DIRTY_ICON]->setVisible(mIsNavMeshDirty); + mParcelIcon[PATHFINDING_DISABLED_ICON]->setVisible(!mIsNavMeshDirty && !pathfinding_dynamic_enabled); + + mDamageText->setVisible(allow_damage); + mParcelIcon[SEE_AVATARS_ICON]->setVisible( !see_avs ); + + // Padding goes to left of both landmark star and for sale btn + x -= mAddLandmarkHPad; + + // Slide the parcel icons rect from right to left, adjusting rectangles + for (S32 i = 0; i < ICON_COUNT; ++i) + { + x = layout_widget(mParcelIcon[i], x); + x -= mIconHPad; + } + x = layout_widget(mDamageText, x); + x -= mIconHPad; + } + else + { + for (S32 i = 0; i < ICON_COUNT; ++i) + { + mParcelIcon[i]->setVisible(false); + } + mDamageText->setVisible(false); + } + + if (mTextEntry) + { + S32 left_pad, right_pad; + mTextEntry->getTextPadding(&left_pad, &right_pad); + right_pad = mTextEntry->getRect().mRight - x; + mTextEntry->setTextPadding(left_pad, right_pad); + } +} + +void LLLocationInputCtrl::refreshHealth() +{ + // *FIXME: Status bar owns health information, should be in agent + if (gStatusBar) + { + static S32 last_health = -1; + S32 health = gStatusBar->getHealth(); + if (health != last_health) + { + std::string text = llformat("%d%%", health); + mDamageText->setText(text); + last_health = health; + } + } +} + +void LLLocationInputCtrl::refreshMaturityButton() +{ + // Updating maturity rating icon. + LLViewerRegion* region = gAgent.getRegion(); + if (!region) + return; + + bool button_visible = true; + LLPointer<LLUIImage> rating_image = NULL; + std::string rating_tooltip; + + U8 sim_access = region->getSimAccess(); + switch(sim_access) + { + case SIM_ACCESS_PG: + rating_image = mIconMaturityGeneral; + rating_tooltip = LLTrans::getString("LocationCtrlGeneralIconTooltip"); + break; + + case SIM_ACCESS_ADULT: + rating_image = mIconMaturityAdult; + rating_tooltip = LLTrans::getString("LocationCtrlAdultIconTooltip"); + break; + + case SIM_ACCESS_MATURE: + rating_image = mIconMaturityModerate; + rating_tooltip = LLTrans::getString("LocationCtrlModerateIconTooltip"); + break; + + default: + button_visible = false; + break; + } + + mMaturityButton->setVisible(button_visible); + mMaturityButton->setToolTip(rating_tooltip); + if(rating_image) + { + mMaturityButton->setImageUnselected(rating_image); + mMaturityButton->setImagePressed(rating_image); + } + if (mMaturityButton->getVisible()) + { + positionMaturityButton(); + } +} + +void LLLocationInputCtrl::positionMaturityButton() +{ + const LLFontGL* font = mTextEntry->getFont(); + if (!font) + return; + + S32 left_pad, right_pad; + mTextEntry->getTextPadding(&left_pad, &right_pad); + + // Calculate the right edge of rendered text + a whitespace. + left_pad = left_pad + font->getWidth(mTextEntry->getText()) + font->getWidth(" "); + + LLRect rect = mMaturityButton->getRect(); + mMaturityButton->setRect(rect.setOriginAndSize(left_pad, rect.mBottom, rect.getWidth(), rect.getHeight())); + + // Hide icon if it text area is not width enough to display it, show otherwise. + mMaturityButton->setVisible(rect.mRight < mTextEntry->getRect().getWidth() - right_pad); +} + +void LLLocationInputCtrl::addLocationHistoryEntry(const std::string& title, const LLSD& value) +{ + // SL-20286 : Duplication of autocomplete results occurs when entering some search queries in the navigation bar + // Exclude visual duplicates (items with the same titles) in the dropdown list + LLScrollListItem* item = mList->getItemByLabel(title); + if (!item) + { + add(title, value); + } +} + +void LLLocationInputCtrl::rebuildLocationHistory(const std::string& filter) +{ + LLLocationHistory::location_list_t filtered_items; + const LLLocationHistory::location_list_t* itemsp = NULL; + LLLocationHistory* lh = LLLocationHistory::getInstance(); + + if (filter.empty()) + { + itemsp = &lh->getItems(); + } + else + { + lh->getMatchingItems(filter, filtered_items); + itemsp = &filtered_items; + } + + removeall(); + for (LLLocationHistory::location_list_t::const_reverse_iterator it = itemsp->rbegin(); it != itemsp->rend(); it++) + { + LLSD value; + value["tooltip"] = it->getToolTip(); + //location history can contain only typed locations + value["item_type"] = TYPED_REGION_SLURL; + value["global_pos"] = it->mGlobalPos.getValue(); + addLocationHistoryEntry(it->getLocation(), value); + } +} + +void LLLocationInputCtrl::focusTextEntry() +{ + // 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); + + // Enable the text entry to handle accelerator keys (EXT-8104). + LLEditMenuHandler::gEditMenuHandler = mTextEntry; + } +} + +void LLLocationInputCtrl::enableAddLandmarkButton(bool val) +{ + // We don't want to disable the button because it should be click able at any time, + // instead switch images. + LLUIImage* img = val ? mLandmarkImageOn : mLandmarkImageOff; + if(img) + { + mAddLandmarkBtn->setImageUnselected(img); + } +} + +// Change the "Add landmark" button image +// depending on whether current parcel has been landmarked. +void LLLocationInputCtrl::updateAddLandmarkButton() +{ + enableAddLandmarkButton(LLLandmarkActions::hasParcelLandmark()); +} +void LLLocationInputCtrl::updateAddLandmarkTooltip() +{ + std::string tooltip; + if(LLLandmarkActions::landmarkAlreadyExists()) + { + tooltip = mEditLandmarkTooltip; + } + else + { + tooltip = mAddLandmarkTooltip; + } + mAddLandmarkBtn->setToolTip(tooltip); +} + +void LLLocationInputCtrl::updateContextMenu(){ + + if (mLocationContextMenu) + { + LLMenuItemGL* landmarkItem = mLocationContextMenu->getChild<LLMenuItemGL>("Landmark"); + if (!LLLandmarkActions::landmarkAlreadyExists()) + { + landmarkItem->setLabel(LLTrans::getString("AddLandmarkNavBarMenu")); + } + else + { + landmarkItem->setLabel(LLTrans::getString("EditLandmarkNavBarMenu")); + } + } +} +void LLLocationInputCtrl::updateWidgetlayout() +{ + const LLRect& rect = getLocalRect(); + const LLRect& hist_btn_rect = mButton->getRect(); + + // Info button is set in the XUI XML location_input.xml + + // "Add Landmark" button + LLRect al_btn_rect = mAddLandmarkBtn->getRect(); + al_btn_rect.translate( + hist_btn_rect.mLeft - mIconHPad - al_btn_rect.getWidth(), + (rect.getHeight() - al_btn_rect.getHeight()) / 2); + mAddLandmarkBtn->setRect(al_btn_rect); +} + +void LLLocationInputCtrl::changeLocationPresentation() +{ + if (!mTextEntry) + return; + + //change location presentation only if user does not select/paste anything and + //human-readable region name is being displayed + if(!mTextEntry->hasSelection() && mTextEntry->getText() == mHumanReadableLocation) + { + //needs unescaped one + LLSLURL slurl; + LLAgentUI::buildSLURL(slurl, false); + mTextEntry->setText(LLURI::unescape(slurl.getSLURLString())); + mTextEntry->selectAll(); + + mMaturityButton->setVisible(false); + + isHumanReadableLocationVisible = false; + } +} + +void LLLocationInputCtrl::onLocationContextMenuItemClicked(const LLSD& userdata) +{ + std::string item = userdata.asString(); + + if (item == "show_coordinates") + { + gSavedSettings.setBOOL("NavBarShowCoordinates",!gSavedSettings.getBOOL("NavBarShowCoordinates")); + } + else if (item == "show_properties") + { + gSavedSettings.setBOOL("NavBarShowParcelProperties", + !gSavedSettings.getBOOL("NavBarShowParcelProperties")); + } + else if (item == "landmark") + { + LLViewerInventoryItem* landmark = LLLandmarkActions::findLandmarkForAgentPos(); + + if(!landmark) + { + LLFloaterReg::showInstance("add_landmark"); + } + else + { + LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "landmark").with("id",landmark->getUUID())); + + } + } + else if (item == "cut") + { + mTextEntry->cut(); + } + else if (item == "copy") + { + mTextEntry->copy(); + } + else if (item == "paste") + { + mTextEntry->paste(); + } + else if (item == "delete") + { + mTextEntry->deleteSelection(); + } + else if (item == "select_all") + { + mTextEntry->selectAll(); + } +} + +bool LLLocationInputCtrl::onLocationContextMenuItemEnabled(const LLSD& userdata) +{ + std::string item = userdata.asString(); + + if (item == "can_cut") + { + return mTextEntry->canCut(); + } + else if (item == "can_copy") + { + return mTextEntry->canCopy(); + } + else if (item == "can_paste") + { + return mTextEntry->canPaste(); + } + else if (item == "can_delete") + { + return mTextEntry->canDeselect(); + } + else if (item == "can_select_all") + { + return mTextEntry->canSelectAll() && (mTextEntry->getLength() > 0); + } + else if(item == "show_coordinates") + { + return gSavedSettings.getBOOL("NavBarShowCoordinates"); + } + + return false; +} + +void LLLocationInputCtrl::callbackRebakeRegion(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option == 0) // OK + { + if (LLPathfindingManager::getInstance() != NULL) + { + LLMenuOptionPathfindingRebakeNavmesh::getInstance()->sendRequestRebakeNavmesh(); + } + } +} + +void LLLocationInputCtrl::onParcelIconClick(EParcelIcon icon) +{ + switch (icon) + { + case VOICE_ICON: + LLNotificationsUtil::add("NoVoice"); + break; + case FLY_ICON: + LLNotificationsUtil::add("NoFly"); + break; + case PUSH_ICON: + LLNotificationsUtil::add("PushRestricted"); + break; + case BUILD_ICON: + LLNotificationsUtil::add("NoBuild"); + break; + case PATHFINDING_DIRTY_ICON: + if (LLPathfindingManager::getInstance() != NULL) + { + LLMenuOptionPathfindingRebakeNavmesh *rebakeInstance = LLMenuOptionPathfindingRebakeNavmesh::getInstance(); + if (rebakeInstance && rebakeInstance->canRebakeRegion() && (rebakeInstance->getMode() == LLMenuOptionPathfindingRebakeNavmesh::kRebakeNavMesh_Available)) + { + LLNotificationsUtil::add("PathfindingDirtyRebake", LLSD(), LLSD(), + boost::bind(&LLLocationInputCtrl::callbackRebakeRegion, this, _1, _2)); + break; + } + } + LLNotificationsUtil::add("PathfindingDirty"); + break; + case PATHFINDING_DISABLED_ICON: + LLNotificationsUtil::add("DynamicPathfindingDisabled"); + break; + case SCRIPTS_ICON: + { + LLViewerRegion* region = gAgent.getRegion(); + if(region && region->getRegionFlag(REGION_FLAGS_ESTATE_SKIP_SCRIPTS)) + { + LLNotificationsUtil::add("ScriptsStopped"); + } + else if(region && region->getRegionFlag(REGION_FLAGS_SKIP_SCRIPTS)) + { + LLNotificationsUtil::add("ScriptsNotRunning"); + } + else + { + LLNotificationsUtil::add("NoOutsideScripts"); + } + break; + } + case DAMAGE_ICON: + LLNotificationsUtil::add("NotSafe"); + break; + case SEE_AVATARS_ICON: + LLNotificationsUtil::add("SeeAvatars"); + break; + case ICON_COUNT: + break; + // no default to get compiler warning when a new icon gets added + } +} + +void LLLocationInputCtrl::createNavMeshStatusListenerForCurrentRegion() +{ + if (mNavMeshSlot.connected()) + { + mNavMeshSlot.disconnect(); + } + + LLViewerRegion *currentRegion = gAgent.getRegion(); + if (currentRegion != NULL) + { + mNavMeshSlot = LLPathfindingManager::getInstance()->registerNavMeshListenerForRegion(currentRegion, boost::bind(&LLLocationInputCtrl::onNavMeshStatusChange, this, _2)); + LLPathfindingManager::getInstance()->requestGetNavMeshForRegion(currentRegion, true); + } +} |