/**
 * @file llnavigationbar.cpp
 * @brief Navigation bar implementation
 *
 * $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"

#include "llnavigationbar.h"

#include "v2math.h"

#include "llregionhandle.h"

#include "llfloaterreg.h"
#include "llfocusmgr.h"
#include "lliconctrl.h"
#include "llmenugl.h"

#include "llagent.h"
#include "llviewerregion.h"
#include "lllandmarkactions.h"
#include "lllocationhistory.h"
#include "lllocationinputctrl.h"
#include "llpaneltopinfobar.h"
#include "llteleporthistory.h"
#include "llresizebar.h"
#include "llsearchcombobox.h"
#include "llslurl.h"
#include "llurlregistry.h"
#include "llurldispatcher.h"
#include "llviewerinventory.h"
#include "llviewermenu.h"
#include "llviewerparcelmgr.h"
#include "llworldmapmessage.h"
#include "llappviewer.h"
#include "llviewercontrol.h"
#include "llweb.h"
#include "llhints.h"

#include "llfloatersidepanelcontainer.h"
#include "llinventorymodel.h"
#include "lllandmarkactions.h"

#include "llfavoritesbar.h"
#include "llagentui.h"

#include <boost/regex.hpp>

//-- LLTeleportHistoryMenuItem -----------------------------------------------

/**
 * Item look varies depending on the type (backward/current/forward).
 */
class LLTeleportHistoryMenuItem : public LLMenuItemCallGL
{
public:
    typedef enum e_item_type
    {
        TYPE_BACKWARD,
        TYPE_CURRENT,
        TYPE_FORWARD,
    } EType;

    struct Params : public LLInitParam::Block<Params, LLMenuItemCallGL::Params>
    {
        Mandatory<EType>        item_type;
        Optional<const LLFontGL*> back_item_font,
                                current_item_font,
                                forward_item_font;
        Optional<std::string>   back_item_image,
                                forward_item_image;
        Optional<S32>           image_hpad,
                                image_vpad;
        Params()
        :   item_type(),
            back_item_font("back_item_font"),
            current_item_font("current_item_font"),
            forward_item_font("forward_item_font"),
            back_item_image("back_item_image"),
            forward_item_image("forward_item_image"),
            image_hpad("image_hpad"),
            image_vpad("image_vpad")
        {}
    };

    /*virtual*/ void    draw();
    /*virtual*/ void    onMouseEnter(S32 x, S32 y, MASK mask);
    /*virtual*/ void    onMouseLeave(S32 x, S32 y, MASK mask);

private:
    LLTeleportHistoryMenuItem(const Params&);
    friend class LLUICtrlFactory;

    static const S32            ICON_WIDTH          = 16;
    static const S32            ICON_HEIGHT         = 16;

    LLIconCtrl*     mArrowIcon;
};

static LLDefaultChildRegistry::Register<LLTeleportHistoryMenuItem> r("teleport_history_menu_item");


LLTeleportHistoryMenuItem::LLTeleportHistoryMenuItem(const Params& p)
:   LLMenuItemCallGL(p),
    mArrowIcon(NULL)
{
    // Set appearance depending on the item type.
    if (p.item_type == TYPE_BACKWARD)
    {
        setFont( p.back_item_font );
    }
    else if (p.item_type == TYPE_CURRENT)
    {
        setFont( p.current_item_font );
    }
    else
    {
        setFont( p.forward_item_font );
    }

    LLIconCtrl::Params icon_params;
    icon_params.name("icon");
    LLRect rect(0, ICON_HEIGHT, ICON_WIDTH, 0);
    rect.translate( p.image_hpad, p.image_vpad );
    icon_params.rect( rect );
    icon_params.mouse_opaque(false);
    icon_params.follows.flags(FOLLOWS_LEFT | FOLLOWS_TOP);
    icon_params.visible(false);

    mArrowIcon = LLUICtrlFactory::create<LLIconCtrl> (icon_params);

    // no image for the current item
    if (p.item_type == TYPE_BACKWARD)
        mArrowIcon->setValue( p.back_item_image() );
    else if (p.item_type == TYPE_FORWARD)
        mArrowIcon->setValue( p.forward_item_image() );

    addChild(mArrowIcon);
}

void LLTeleportHistoryMenuItem::draw()
{
    // Draw menu item itself.
    LLMenuItemCallGL::draw();

    // Draw children if any. *TODO: move this to LLMenuItemGL?
    LLUICtrl::draw();
}

void LLTeleportHistoryMenuItem::onMouseEnter(S32 x, S32 y, MASK mask)
{
    mArrowIcon->setVisible(true);
}

void LLTeleportHistoryMenuItem::onMouseLeave(S32 x, S32 y, MASK mask)
{
    mArrowIcon->setVisible(false);
}

static LLDefaultChildRegistry::Register<LLPullButton> menu_button("pull_button");

LLPullButton::LLPullButton(const LLPullButton::Params& params) :
    LLButton(params)
{
    setDirectionFromName(params.direction);
}
boost::signals2::connection LLPullButton::setClickDraggingCallback(const commit_signal_t::slot_type& cb)
{
    return mClickDraggingSignal.connect(cb);
}

/*virtual*/
void LLPullButton::onMouseLeave(S32 x, S32 y, MASK mask)
{
    LLButton::onMouseLeave(x, y, mask);

    if (mMouseDownTimer.getStarted()) //an user have done a mouse down, if the timer started. see LLButton::handleMouseDown for details
    {
        const LLVector2 cursor_direction = LLVector2(F32(x), F32(y)) - mLastMouseDown;
        /* For now cursor_direction points to the direction of mouse movement
         * Need to decide whether should we fire a signal.
         * We fire if angle between mDraggingDirection and cursor_direction is less that 45 degree
         * Note:
         * 0.5 * F_PI_BY_TWO equals to PI/4 radian that equals to angle of 45 degrees
         */
        if (angle_between(mDraggingDirection, cursor_direction) < 0.5 * F_PI_BY_TWO)//call if angle < pi/4
        {
            mClickDraggingSignal(this, LLSD());
        }
    }

}

/*virtual*/
bool LLPullButton::handleMouseDown(S32 x, S32 y, MASK mask)
{
    bool handled = LLButton::handleMouseDown(x, y, mask);
    if (handled)
    {
        //if mouse down was handled by button,
        //capture mouse position to calculate the direction of  mouse move  after mouseLeave event
        mLastMouseDown.set(F32(x), F32(y));
    }
    return handled;
}

/*virtual*/
bool LLPullButton::handleMouseUp(S32 x, S32 y, MASK mask)
{
    // reset data to get ready for next circle
    mLastMouseDown.clear();
    return LLButton::handleMouseUp(x, y, mask);
}
/**
 * this function is setting up dragging direction vector.
 * Last one is just unit vector. It points to direction of mouse drag that we need to handle
 */
void LLPullButton::setDirectionFromName(const std::string& name)
{
    if (name == "left")
    {
        mDraggingDirection.set(F32(-1), F32(0));
    }
    else if (name == "right")
    {
        mDraggingDirection.set(F32(0), F32(1));
    }
    else if (name == "down")
    {
        mDraggingDirection.set(F32(0), F32(-1));
    }
    else if (name == "up")
    {
        mDraggingDirection.set(F32(0), F32(1));
    }
}

//-- LNavigationBar ----------------------------------------------------------

/*
TODO:
- Load navbar height from saved settings (as it's done for status bar) or think of a better way.
*/

LLNavigationBar::LLNavigationBar()
:   mTeleportHistoryMenu(NULL),
    mBtnBack(NULL),
    mBtnForward(NULL),
    mBtnHome(NULL),
    mCmbLocation(NULL),
    mSaveToLocationHistory(false),
    mNavigationPanel(NULL),
    mFavoritePanel(NULL),
    mNavPanWidth(0)
{
    buildFromFile( "panel_navigation_bar.xml");

    // set a listener function for LoginComplete event
    LLAppViewer::instance()->setOnLoginCompletedCallback(boost::bind(&LLNavigationBar::handleLoginComplete, this));
}

LLNavigationBar::~LLNavigationBar()
{
    mTeleportFinishConnection.disconnect();
    mTeleportFailedConnection.disconnect();
}

bool LLNavigationBar::postBuild()
{
    mBtnBack    = getChild<LLPullButton>("back_btn");
    mBtnForward = getChild<LLPullButton>("forward_btn");
    mBtnHome    = getChild<LLButton>("home_btn");
    mBtnLandmarks = getChild<LLButton>("landmarks_btn");

    mCmbLocation= getChild<LLLocationInputCtrl>("location_combo");

    mBtnBack->setEnabled(false);
    mBtnBack->setClickedCallback(boost::bind(&LLNavigationBar::onBackButtonClicked, this));
    mBtnBack->setHeldDownCallback(boost::bind(&LLNavigationBar::onBackOrForwardButtonHeldDown, this,_1, _2));
    mBtnBack->setClickDraggingCallback(boost::bind(&LLNavigationBar::showTeleportHistoryMenu, this,_1));

    mBtnForward->setEnabled(false);
    mBtnForward->setClickedCallback(boost::bind(&LLNavigationBar::onForwardButtonClicked, this));
    mBtnForward->setHeldDownCallback(boost::bind(&LLNavigationBar::onBackOrForwardButtonHeldDown, this, _1, _2));
    mBtnForward->setClickDraggingCallback(boost::bind(&LLNavigationBar::showTeleportHistoryMenu, this,_1));

    mBtnHome->setClickedCallback(boost::bind(&LLNavigationBar::onHomeButtonClicked, this));

    mBtnLandmarks->setClickedCallback(boost::bind(&LLNavigationBar::onLandmarksButtonClicked, this));

    mCmbLocation->setCommitCallback(boost::bind(&LLNavigationBar::onLocationSelection, this));

    mTeleportFinishConnection = LLViewerParcelMgr::getInstance()->
        setTeleportFinishedCallback(boost::bind(&LLNavigationBar::onTeleportFinished, this, _1));

    mTeleportFailedConnection = LLViewerParcelMgr::getInstance()->
        setTeleportFailedCallback(boost::bind(&LLNavigationBar::onTeleportFailed, this));

    mDefaultNbRect = getRect();
    mDefaultFpRect = getChild<LLFavoritesBarCtrl>("favorite")->getRect();

    // we'll be notified on teleport history changes
    LLTeleportHistory::getInstance()->setHistoryChangedCallback(
            boost::bind(&LLNavigationBar::onTeleportHistoryChanged, this));

    LLHints::getInstance()->registerHintTarget("nav_bar", getHandle());

    mNavigationPanel = getChild<LLLayoutPanel>("navigation_layout_panel");
    mFavoritePanel = getChild<LLLayoutPanel>("favorites_layout_panel");
    mNavigationPanel->getResizeBar()->setResizeListener(boost::bind(&LLNavigationBar::onNavbarResized, this));
    mFavoritePanel->getResizeBar()->setResizeListener(boost::bind(&LLNavigationBar::onNavbarResized, this));

    return true;
}

void LLNavigationBar::setVisible(bool visible)
{
    // change visibility of grandparent layout_panel to animate in and out
    if (getParent())
    {
        //to avoid some mysterious bugs like EXT-3352, at least try to log an incorrect parent to ping  about a problem.
        if(getParent()->getName() != "nav_bar_container")
        {
            LL_WARNS("LLNavigationBar")<<"NavigationBar has an unknown name of the parent: "<<getParent()->getName()<< LL_ENDL;
        }
        getParent()->setVisible(visible);
    }
}

void LLNavigationBar::draw()
{
    if (isBackgroundVisible())
    {
        static LLUIColor color_drop_shadow = LLUIColorTable::instance().getColor("ColorDropShadow");
        gl_drop_shadow(0, getRect().getHeight(), getRect().getWidth(), 0,
                           color_drop_shadow, DROP_SHADOW_FLOATER);
    }

    LLPanel::draw();
}

bool LLNavigationBar::handleRightMouseDown(S32 x, S32 y, MASK mask)
{
    bool handled = childrenHandleRightMouseDown( x, y, mask) != NULL;
    if(!handled && !gMenuHolder->hasVisibleMenu())
    {
        show_navbar_context_menu(this,x,y);
        handled = true;
    }
    return handled;
}

void LLNavigationBar::onBackButtonClicked()
{
    LLTeleportHistory::getInstance()->goBack();
}

void LLNavigationBar::onNavbarResized()
{
    S32 new_nav_pan_width = mNavigationPanel->getRect().getWidth();
    if(mNavPanWidth != new_nav_pan_width)
    {
        S32 new_stack_width = new_nav_pan_width + mFavoritePanel->getRect().getWidth();
        F32 ratio = (F32)new_nav_pan_width / (F32)new_stack_width;
        gSavedPerAccountSettings.setF32("NavigationBarRatio", ratio);
        mNavPanWidth = new_nav_pan_width;
    }
}

void LLNavigationBar::onBackOrForwardButtonHeldDown(LLUICtrl* ctrl, const LLSD& param)
{
    if (param["count"].asInteger() == 0)
        showTeleportHistoryMenu(ctrl);
}

void LLNavigationBar::onForwardButtonClicked()
{
    LLTeleportHistory::getInstance()->goForward();
}

void LLNavigationBar::onHomeButtonClicked()
{
    gAgent.teleportHome();
}

void LLNavigationBar::onLandmarksButtonClicked()
{
    LLFloaterReg::toggleInstanceOrBringToFront("places");
    LLFloaterSidePanelContainer::showPanel("places", LLSD().with("type", "open_landmark_tab"));
}

void LLNavigationBar::onTeleportHistoryMenuItemClicked(const LLSD& userdata)
{
    int idx = userdata.asInteger();
    LLTeleportHistory::getInstance()->goToItem(idx);
}

// This is called when user presses enter in the location input
// or selects a location from the typed locations dropdown.
void LLNavigationBar::onLocationSelection()
{
    std::string typed_location = mCmbLocation->getSimple();
    LLStringUtil::trim(typed_location);

    // Will not teleport to empty location.
    if (typed_location.empty())
        return;
    //get selected item from combobox item
    LLSD value = mCmbLocation->getSelectedValue();
    if(value.isUndefined() && !mCmbLocation->getTextEntry()->isDirty())
    {
        // At this point we know that: there is no selected item in list and text field has NOT been changed
        // So there is no sense to try to change the location
        return;
    }
    /* since navbar list support autocompletion it contains several types of item: landmark, teleport hystory item,
     * typed by user slurl or region name. Let's find out which type of item the user has selected
     * to make decision about adding this location into typed history. see mSaveToLocationHistory
     * Note:
     * Only TYPED_REGION_SLURL item will be added into LLLocationHistory
     */

    if(value.has("item_type"))
    {

        switch(value["item_type"].asInteger())
        {
        case LANDMARK:

            if(value.has("AssetUUID"))
            {
                gAgent.teleportViaLandmark( LLUUID(value["AssetUUID"].asString()));
                // user teleported by manually inputting inventory landmark's name
                mSaveToLocationHistory = false;
                return;
            }
            else
            {
                LLInventoryModel::item_array_t landmark_items =
                        LLLandmarkActions::fetchLandmarksByName(typed_location,
                                false);
                if (!landmark_items.empty())
                {
                    gAgent.teleportViaLandmark( landmark_items[0]->getAssetUUID());
                    mSaveToLocationHistory = true;
                    return;
                }
            }
            break;

        case TELEPORT_HISTORY:
            //in case of teleport item was selected, teleport by position too.
        case TYPED_REGION_SLURL:
            if(value.has("global_pos"))
            {
                gAgent.teleportViaLocation(LLVector3d(value["global_pos"]));
                return;
            }
            break;

        default:
            break;
        }
    }
    //Let's parse slurl or region name

    std::string region_name;
    LLVector3 local_coords(128, 128, 0);
    // Is the typed location a SLURL?
    LLSLURL slurl = LLSLURL(typed_location);
    if (slurl.getType() == LLSLURL::LOCATION)
    {
      region_name = slurl.getRegion();
      local_coords = slurl.getPosition();
    }
    else if(!slurl.isValid())
    {
      // we have to do this check after previous, because LLUrlRegistry contains handlers for slurl too
      // but we need to know whether typed_location is a simple http url.
      if (LLUrlRegistry::instance().isUrl(typed_location))
        {
        // display http:// URLs in the media browser, or
        // anything else is sent to the search floater
        LLWeb::loadURL(typed_location);
        return;
      }
      else
      {
          // assume that an user has typed the {region name} or possible {region_name, parcel}
          region_name  = typed_location.substr(0,typed_location.find(','));
        }
    }
    else
    {
      // was an app slurl, home, whatever.  Bail
      return;
    }

    // Resolve the region name to its global coordinates.
    // If resolution succeeds we'll teleport.
    LLWorldMapMessage::url_callback_t cb = boost::bind(
            &LLNavigationBar::onRegionNameResponse, this,
            typed_location, region_name, local_coords, _1, _2, _3, _4);
    mSaveToLocationHistory = true;
    LLWorldMapMessage::getInstance()->sendNamedRegionRequest(region_name, cb, std::string("unused"), false);
}

void LLNavigationBar::onTeleportFailed()
{
    mSaveToLocationHistory = false;
}

void LLNavigationBar::onTeleportFinished(const LLVector3d& global_agent_pos)
{
    if (!mSaveToLocationHistory)
        return;
    LLLocationHistory* lh = LLLocationHistory::getInstance();

    //TODO*: do we need convert slurl into readable format?
    std::string location;
    /*NOTE:
     * We can't use gAgent.getPositionAgent() in case of local teleport to build location.
     * At this moment gAgent.getPositionAgent() contains previous coordinates.
     * according to EXT-65 agent position is being reseted on each frame.
     */
        LLAgentUI::buildLocationString(location, LLAgentUI::LOCATION_FORMAT_NO_MATURITY,
                    gAgent.getPosAgentFromGlobal(global_agent_pos));
    std::string tooltip (LLSLURL(gAgent.getRegion()->getName(), global_agent_pos).getSLURLString());

    LLLocationHistoryItem item (location,
            global_agent_pos, tooltip,TYPED_REGION_SLURL);// we can add into history only TYPED location
    //Touch it, if it is at list already, add new location otherwise
    if ( !lh->touchItem(item) ) {
        lh->addItem(item);
    }

    lh->save();

    mSaveToLocationHistory = false;

}

void LLNavigationBar::onTeleportHistoryChanged()
{
    // Update navigation controls.
    LLTeleportHistory* h = LLTeleportHistory::getInstance();
    int cur_item = h->getCurrentItemIndex();
    mBtnBack->setEnabled(cur_item > 0);
    mBtnForward->setEnabled(cur_item < ((int)h->getItems().size() - 1));
}

void LLNavigationBar::rebuildTeleportHistoryMenu()
{
    // Has the pop-up menu been built?
    if (mTeleportHistoryMenu)
    {
        // Clear it.
        mTeleportHistoryMenu->empty();
    }
    else
    {
        // Create it.
        LLMenuGL::Params menu_p;
        menu_p.name("popup");
        menu_p.can_tear_off(false);
        menu_p.visible(false);
        menu_p.bg_visible(true);
        menu_p.scrollable(true);
        mTeleportHistoryMenu = LLUICtrlFactory::create<LLMenuGL>(menu_p);

        addChild(mTeleportHistoryMenu);
    }

    // Populate the menu with teleport history items.
    LLTeleportHistory* hist = LLTeleportHistory::getInstance();
    const LLTeleportHistory::slurl_list_t& hist_items = hist->getItems();
    int cur_item = hist->getCurrentItemIndex();

    // Items will be shown in the reverse order, just like in Firefox.
    for (int i = (int)hist_items.size()-1; i >= 0; i--)
    {
        LLTeleportHistoryMenuItem::EType type;
        if (i < cur_item)
            type = LLTeleportHistoryMenuItem::TYPE_BACKWARD;
        else if (i > cur_item)
            type = LLTeleportHistoryMenuItem::TYPE_FORWARD;
        else
            type = LLTeleportHistoryMenuItem::TYPE_CURRENT;

        LLTeleportHistoryMenuItem::Params item_params;
        item_params.label = item_params.name = hist_items[i].mTitle;
        item_params.item_type = type;
        item_params.on_click.function(boost::bind(&LLNavigationBar::onTeleportHistoryMenuItemClicked, this, i));
        LLTeleportHistoryMenuItem* new_itemp = LLUICtrlFactory::create<LLTeleportHistoryMenuItem>(item_params);
        //new_itemp->setFont()
        mTeleportHistoryMenu->addChild(new_itemp);
    }
}

void LLNavigationBar::onRegionNameResponse(
        std::string typed_location,
        std::string region_name,
        LLVector3 local_coords,
        U64 region_handle, const std::string& url, const LLUUID& snapshot_id, bool teleport)
{
    // Invalid location?
    if (region_handle)
    {
        // Teleport to the location.
        LLVector3d region_pos = from_region_handle(region_handle);
        LLVector3d global_pos = region_pos + (LLVector3d) local_coords;

        LL_INFOS() << "Teleporting to: " << LLSLURL(region_name,    global_pos).getSLURLString()  << LL_ENDL;
        gAgent.teleportViaLocation(global_pos);
    }
    else if (gSavedSettings.getBOOL("SearchFromAddressBar"))
    {
        invokeSearch(typed_location);
    }
}

void    LLNavigationBar::showTeleportHistoryMenu(LLUICtrl* btn_ctrl)
{
    // Don't show the popup if teleport history is empty.
    if (LLTeleportHistory::getInstance()->isEmpty())
    {
        LL_DEBUGS() << "Teleport history is empty, will not show the menu." << LL_ENDL;
        return;
    }

    rebuildTeleportHistoryMenu();

    if (mTeleportHistoryMenu == NULL)
        return;

    mTeleportHistoryMenu->updateParent(LLMenuGL::sMenuContainer);
    const S32 MENU_SPAWN_PAD = -1;
    LLMenuGL::showPopup(btn_ctrl, mTeleportHistoryMenu, 0, MENU_SPAWN_PAD);
    LLButton* nav_button = dynamic_cast<LLButton*>(btn_ctrl);
    if(nav_button)
    {
        if(mHistoryMenuConnection.connected())
        {
            LL_WARNS("Navgationbar")<<"mHistoryMenuConnection should be disconnected at this moment."<<LL_ENDL;
            mHistoryMenuConnection.disconnect();
        }
        mHistoryMenuConnection = gMenuHolder->setMouseUpCallback(boost::bind(&LLNavigationBar::onNavigationButtonHeldUp, this, nav_button));
        // pressed state will be update after mouseUp in  onBackOrForwardButtonHeldUp();
        nav_button->setForcePressedState(true);
    }
    // *HACK pass the mouse capturing to the drop-down menu
    // it need to let menu handle mouseup event
    gFocusMgr.setMouseCapture(gMenuHolder);
}
/**
 * Taking into account the HACK above,  this callback-function is responsible for correct handling of mouseUp event in case of holding-down the navigation buttons..
 * We need to process this case separately to update a pressed state of navigation button.
 */
void LLNavigationBar::onNavigationButtonHeldUp(LLButton* nav_button)
{
    if(nav_button)
    {
        nav_button->setForcePressedState(false);
    }
    if(gFocusMgr.getMouseCapture() == gMenuHolder)
    {
        // we had passed mouseCapture in  showTeleportHistoryMenu()
        // now we MUST release mouseCapture to continue a proper mouseevent workflow.
        gFocusMgr.setMouseCapture(NULL);
    }
    //gMenuHolder is using to display bunch of menus. Disconnect signal to avoid unnecessary calls.
    mHistoryMenuConnection.disconnect();
}

void LLNavigationBar::handleLoginComplete()
{
    LLTeleportHistory::getInstance()->handleLoginComplete();
    LLPanelTopInfoBar::instance().handleLoginComplete();
    mCmbLocation->handleLoginComplete();
    resizeLayoutPanel();
}

void LLNavigationBar::resizeLayoutPanel()
{
    LLRect nav_bar_rect = mNavigationPanel->getRect();

    S32 nav_panel_width = (S32)((nav_bar_rect.getWidth() + mFavoritePanel->getRect().getWidth()) * gSavedPerAccountSettings.getF32("NavigationBarRatio"));

    nav_bar_rect.setLeftTopAndSize(nav_bar_rect.mLeft, nav_bar_rect.mTop, nav_panel_width, nav_bar_rect.getHeight());
    mNavigationPanel->handleReshape(nav_bar_rect,true);
}
void LLNavigationBar::invokeSearch(std::string search_text)
{
    LLFloaterReg::showInstance("search", LLSD().with("category", "standard").with("query", LLSD(search_text)));
}

void LLNavigationBar::clearHistoryCache()
{
    mCmbLocation->removeall();
    LLLocationHistory* lh = LLLocationHistory::getInstance();
    lh->removeItems();
    lh->save();
    LLTeleportHistory::getInstance()->purgeItems();
}

int LLNavigationBar::getDefNavBarHeight()
{
    return mDefaultNbRect.getHeight();
}
int LLNavigationBar::getDefFavBarHeight()
{
    return mDefaultFpRect.getHeight();
}

bool LLNavigationBar::isRebakeNavMeshAvailable()
{
    return mCmbLocation->isNavMeshDirty();
}