1629 lines
50 KiB
C++
1629 lines
50 KiB
C++
/**
|
|
* @file llfloatertools.cpp
|
|
* @brief The edit tools, including move, position, land, etc.
|
|
*
|
|
* $LicenseInfo:firstyear=2002&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 "llfloatertools.h"
|
|
|
|
#include "llfontgl.h"
|
|
#include "llcoord.h"
|
|
//#include "llgl.h"
|
|
|
|
#include "llagent.h"
|
|
#include "llagentcamera.h"
|
|
#include "llbutton.h"
|
|
#include "llcheckboxctrl.h"
|
|
#include "llcombobox.h"
|
|
#include "lldraghandle.h"
|
|
#include "llerror.h"
|
|
#include "llfloaterbuildoptions.h"
|
|
#include "llfloatermediasettings.h"
|
|
#include "llfloateropenobject.h"
|
|
#include "llfloaterobjectweights.h"
|
|
#include "llfloaterreg.h"
|
|
#include "llfocusmgr.h"
|
|
#include "llmediaentry.h"
|
|
#include "llmenugl.h"
|
|
#include "llnotificationsutil.h"
|
|
#include "llpanelcontents.h"
|
|
#include "llpanelface.h"
|
|
#include "llpanelland.h"
|
|
#include "llpanelobjectinventory.h"
|
|
#include "llpanelobject.h"
|
|
#include "llpanelvolume.h"
|
|
#include "llpanelpermissions.h"
|
|
#include "llparcel.h"
|
|
#include "llradiogroup.h"
|
|
#include "llresmgr.h"
|
|
#include "llselectmgr.h"
|
|
#include "llslider.h"
|
|
#include "llstatusbar.h"
|
|
#include "lltabcontainer.h"
|
|
#include "lltextbox.h"
|
|
#include "lltoolbrush.h"
|
|
#include "lltoolcomp.h"
|
|
#include "lltooldraganddrop.h"
|
|
#include "lltoolface.h"
|
|
#include "lltoolfocus.h"
|
|
#include "lltoolgrab.h"
|
|
#include "lltoolgrab.h"
|
|
#include "lltoolindividual.h"
|
|
#include "lltoolmgr.h"
|
|
#include "lltoolpie.h"
|
|
#include "lltoolpipette.h"
|
|
#include "lltoolplacer.h"
|
|
#include "lltoolselectland.h"
|
|
#include "lltrans.h"
|
|
#include "llui.h"
|
|
#include "llviewercontrol.h"
|
|
#include "llviewerjoystick.h"
|
|
#include "llviewerregion.h"
|
|
#include "llviewermenu.h"
|
|
#include "llviewerparcelmgr.h"
|
|
#include "llviewerwindow.h"
|
|
#include "llvovolume.h"
|
|
#include "lluictrlfactory.h"
|
|
#include "qtoolalign.h"
|
|
#include "llselectmgr.h"
|
|
#include "llmeshrepository.h"
|
|
|
|
#include "llviewernetwork.h" // <FS:CR> Aurora Sim
|
|
#include "llvograss.h"
|
|
#include "llvotree.h"
|
|
|
|
// Globals
|
|
LLFloaterTools *gFloaterTools = NULL;
|
|
bool LLFloaterTools::sShowObjectCost = true;
|
|
bool LLFloaterTools::sPreviousFocusOnAvatar = false;
|
|
|
|
const std::string PANEL_NAMES[LLFloaterTools::PANEL_COUNT] =
|
|
{
|
|
std::string("General"), // PANEL_GENERAL,
|
|
std::string("Object"), // PANEL_OBJECT,
|
|
std::string("Features"), // PANEL_FEATURES,
|
|
std::string("Texture"), // PANEL_FACE,
|
|
std::string("Content"), // PANEL_CONTENTS,
|
|
};
|
|
|
|
|
|
// Local prototypes
|
|
void commit_grid_mode(LLUICtrl *ctrl);
|
|
void commit_select_component(void *data);
|
|
//void click_show_more(void*);
|
|
void click_popup_info(void*);
|
|
void click_popup_done(void*);
|
|
void click_popup_minimize(void*);
|
|
void commit_slider_dozer_force(LLUICtrl *);
|
|
void click_apply_to_selection(void*);
|
|
void commit_radio_group_focus(LLUICtrl* ctrl);
|
|
void commit_radio_group_move(LLUICtrl* ctrl);
|
|
void commit_radio_group_edit(LLUICtrl* ctrl);
|
|
void commit_radio_group_land(LLUICtrl* ctrl);
|
|
void commit_grid_mode(LLUICtrl *);
|
|
void commit_slider_zoom(LLUICtrl *ctrl);
|
|
|
|
// <FS:KC> show/hide build highlight
|
|
void commit_show_highlight(void *ctrl);
|
|
|
|
/**
|
|
* Class LLLandImpactsObserver
|
|
*
|
|
* An observer class to monitor parcel selection and update
|
|
* the land impacts data from a parcel containing the selected object.
|
|
*/
|
|
class LLLandImpactsObserver : public LLParcelObserver
|
|
{
|
|
public:
|
|
virtual void changed()
|
|
{
|
|
LLFloaterTools* tools_floater = LLFloaterReg::getTypedInstance<LLFloaterTools>("build");
|
|
if(tools_floater)
|
|
{
|
|
tools_floater->updateLandImpacts();
|
|
}
|
|
}
|
|
};
|
|
|
|
//static
|
|
void* LLFloaterTools::createPanelPermissions(void* data)
|
|
{
|
|
LLFloaterTools* floater = (LLFloaterTools*)data;
|
|
floater->mPanelPermissions = new LLPanelPermissions();
|
|
return floater->mPanelPermissions;
|
|
}
|
|
//static
|
|
void* LLFloaterTools::createPanelObject(void* data)
|
|
{
|
|
LLFloaterTools* floater = (LLFloaterTools*)data;
|
|
floater->mPanelObject = new LLPanelObject();
|
|
return floater->mPanelObject;
|
|
}
|
|
|
|
//static
|
|
void* LLFloaterTools::createPanelVolume(void* data)
|
|
{
|
|
LLFloaterTools* floater = (LLFloaterTools*)data;
|
|
floater->mPanelVolume = new LLPanelVolume();
|
|
return floater->mPanelVolume;
|
|
}
|
|
|
|
//static
|
|
void* LLFloaterTools::createPanelFace(void* data)
|
|
{
|
|
LLFloaterTools* floater = (LLFloaterTools*)data;
|
|
floater->mPanelFace = new LLPanelFace();
|
|
return floater->mPanelFace;
|
|
}
|
|
|
|
//static
|
|
void* LLFloaterTools::createPanelContents(void* data)
|
|
{
|
|
LLFloaterTools* floater = (LLFloaterTools*)data;
|
|
floater->mPanelContents = new LLPanelContents();
|
|
return floater->mPanelContents;
|
|
}
|
|
|
|
//static
|
|
void* LLFloaterTools::createPanelLandInfo(void* data)
|
|
{
|
|
LLFloaterTools* floater = (LLFloaterTools*)data;
|
|
floater->mPanelLandInfo = new LLPanelLandInfo();
|
|
return floater->mPanelLandInfo;
|
|
}
|
|
|
|
static const std::string toolNames[]={
|
|
"ToolCube",
|
|
"ToolPrism",
|
|
"ToolPyramid",
|
|
"ToolTetrahedron",
|
|
"ToolCylinder",
|
|
"ToolHemiCylinder",
|
|
"ToolCone",
|
|
"ToolHemiCone",
|
|
"ToolSphere",
|
|
"ToolHemiSphere",
|
|
"ToolTorus",
|
|
"ToolTube",
|
|
"ToolRing",
|
|
"ToolTree",
|
|
"ToolGrass"};
|
|
LLPCode toolData[]={
|
|
LL_PCODE_CUBE,
|
|
LL_PCODE_PRISM,
|
|
LL_PCODE_PYRAMID,
|
|
LL_PCODE_TETRAHEDRON,
|
|
LL_PCODE_CYLINDER,
|
|
LL_PCODE_CYLINDER_HEMI,
|
|
LL_PCODE_CONE,
|
|
LL_PCODE_CONE_HEMI,
|
|
LL_PCODE_SPHERE,
|
|
LL_PCODE_SPHERE_HEMI,
|
|
LL_PCODE_TORUS,
|
|
LLViewerObject::LL_VO_SQUARE_TORUS,
|
|
LLViewerObject::LL_VO_TRIANGLE_TORUS,
|
|
LL_PCODE_LEGACY_TREE,
|
|
LL_PCODE_LEGACY_GRASS};
|
|
|
|
BOOL LLFloaterTools::postBuild()
|
|
{
|
|
// Hide until tool selected
|
|
setVisible(FALSE);
|
|
|
|
// Since we constantly show and hide this during drags, don't
|
|
// make sounds on visibility changes.
|
|
setSoundFlags(LLView::SILENT);
|
|
|
|
getDragHandle()->setEnabled( !gSavedSettings.getBOOL("ToolboxAutoMove") );
|
|
|
|
LLRect rect;
|
|
mBtnFocus = getChild<LLButton>("button focus");//btn;
|
|
mBtnMove = getChild<LLButton>("button move");
|
|
mBtnEdit = getChild<LLButton>("button edit");
|
|
mBtnCreate = getChild<LLButton>("button create");
|
|
mBtnLand = getChild<LLButton>("button land" );
|
|
mTextStatus = getChild<LLTextBox>("text status");
|
|
mRadioGroupFocus = getChild<LLRadioGroup>("focus_radio_group");
|
|
mRadioGroupMove = getChild<LLRadioGroup>("move_radio_group");
|
|
mRadioGroupEdit = getChild<LLRadioGroup>("edit_radio_group");
|
|
mBtnGridOptions = getChild<LLButton>("Options...");
|
|
mBtnLink = getChild<LLButton>("link_btn");
|
|
mBtnUnlink = getChild<LLButton>("unlink_btn");
|
|
|
|
// <FS:PP> FIRE-14493: Buttons to cycle through linkset
|
|
mBtnPrevPart = getChild<LLButton>("prev_part_btn");
|
|
mBtnNextPart = getChild<LLButton>("next_part_btn");
|
|
// </FS:PP>
|
|
|
|
mCheckSelectIndividual = getChild<LLCheckBoxCtrl>("checkbox edit linked parts");
|
|
getChild<LLUICtrl>("checkbox edit linked parts")->setValue((BOOL)gSavedSettings.getBOOL("EditLinkedParts"));
|
|
mCheckSnapToGrid = getChild<LLCheckBoxCtrl>("checkbox snap to grid");
|
|
getChild<LLUICtrl>("checkbox snap to grid")->setValue((BOOL)gSavedSettings.getBOOL("SnapEnabled"));
|
|
mCheckStretchUniform = getChild<LLCheckBoxCtrl>("checkbox uniform");
|
|
getChild<LLUICtrl>("checkbox uniform")->setValue((BOOL)gSavedSettings.getBOOL("ScaleUniform"));
|
|
mCheckStretchTexture = getChild<LLCheckBoxCtrl>("checkbox stretch textures");
|
|
getChild<LLUICtrl>("checkbox stretch textures")->setValue((BOOL)gSavedSettings.getBOOL("ScaleStretchTextures"));
|
|
mComboGridMode = getChild<LLComboBox>("combobox grid mode");
|
|
|
|
// <FS:KC> show highlight
|
|
mCheckShowHighlight = getChild<LLCheckBoxCtrl>("checkbox show highlight");
|
|
mCheckShowHighlight->setValue(gSavedSettings.getBOOL("RenderHighlightSelections"));
|
|
LLSelectMgr::instance().setFSShowHideHighlight(FS_SHOW_HIDE_HIGHLIGHT_NORMAL);
|
|
|
|
mCheckActualRoot = getChild<LLCheckBoxCtrl>("checkbox actual root");
|
|
// </FS:KC>
|
|
|
|
|
|
//
|
|
// Create Buttons
|
|
//
|
|
|
|
for(size_t t=0; t<LL_ARRAY_SIZE(toolNames); ++t)
|
|
{
|
|
LLButton *found = getChild<LLButton>(toolNames[t]);
|
|
if(found)
|
|
{
|
|
found->setClickedCallback(boost::bind(&LLFloaterTools::setObjectType, toolData[t]));
|
|
mButtons.push_back( found );
|
|
}else{
|
|
LL_WARNS() << "Tool button not found! DOA Pending." << LL_ENDL;
|
|
}
|
|
}
|
|
mCheckCopySelection = getChild<LLCheckBoxCtrl>("checkbox copy selection");
|
|
getChild<LLUICtrl>("checkbox copy selection")->setValue((BOOL)gSavedSettings.getBOOL("CreateToolCopySelection"));
|
|
mCheckSticky = getChild<LLCheckBoxCtrl>("checkbox sticky");
|
|
getChild<LLUICtrl>("checkbox sticky")->setValue((BOOL)gSavedSettings.getBOOL("CreateToolKeepSelected"));
|
|
mCheckCopyCenters = getChild<LLCheckBoxCtrl>("checkbox copy centers");
|
|
getChild<LLUICtrl>("checkbox copy centers")->setValue((BOOL)gSavedSettings.getBOOL("CreateToolCopyCenters"));
|
|
mCheckCopyRotates = getChild<LLCheckBoxCtrl>("checkbox copy rotates");
|
|
getChild<LLUICtrl>("checkbox copy rotates")->setValue((BOOL)gSavedSettings.getBOOL("CreateToolCopyRotates"));
|
|
|
|
mRadioGroupLand = getChild<LLRadioGroup>("land_radio_group");
|
|
mBtnApplyToSelection = getChild<LLButton>("button apply to selection");
|
|
mSliderDozerSize = getChild<LLSlider>("slider brush size");
|
|
getChild<LLUICtrl>("slider brush size")->setValue(gSavedSettings.getF32("LandBrushSize"));
|
|
mSliderDozerForce = getChild<LLSlider>("slider force");
|
|
// the setting stores the actual force multiplier, but the slider is logarithmic, so we convert here
|
|
getChild<LLUICtrl>("slider force")->setValue(log10(gSavedSettings.getF32("LandBrushForce")));
|
|
// <FS:Ansariel> FIRE-7802: Grass and tree selection in build tool
|
|
mTreeGrassCombo = getChild<LLComboBox>("tree_grass_combo");
|
|
|
|
mCostTextBorder = getChild<LLViewBorder>("cost_text_border");
|
|
|
|
mTab = getChild<LLTabContainer>("Object Info Tabs");
|
|
if(mTab)
|
|
{
|
|
//mTab->setFollows(FOLLOWS_TOP | FOLLOWS_LEFT);
|
|
//mTab->setBorderVisible(FALSE);
|
|
mTab->selectFirstTab();
|
|
}
|
|
|
|
mStatusText["rotate"] = getString("status_rotate");
|
|
mStatusText["scale"] = getString("status_scale");
|
|
mStatusText["move"] = getString("status_move");
|
|
mStatusText["modifyland"] = getString("status_modifyland");
|
|
mStatusText["camera"] = getString("status_camera");
|
|
mStatusText["grab"] = getString("status_grab");
|
|
mStatusText["place"] = getString("status_place");
|
|
mStatusText["selectland"] = getString("status_selectland");
|
|
|
|
sShowObjectCost = gSavedSettings.getBOOL("ShowObjectRenderingCost");
|
|
|
|
// <FS:KC> Added back more/less button
|
|
LLButton* btnExpand = findChild<LLButton>("btnExpand");
|
|
if (btnExpand && mTab)
|
|
{
|
|
mExpandedHeight = getRect().getHeight();
|
|
mCollapsedHeight = mExpandedHeight - mTab->getRect().getHeight() + btnExpand->getRect().getHeight();
|
|
if (!gSavedSettings.getBOOL("FSToolboxExpanded"))
|
|
{
|
|
mTab->setVisible(FALSE);
|
|
reshape(getRect().getWidth(), mCollapsedHeight);
|
|
btnExpand->setImageOverlay("Arrow_Down", btnExpand->getImageOverlayHAlign());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gSavedSettings.setBOOL("FSToolboxExpanded", TRUE);
|
|
}
|
|
// </FS:KC>
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// <FS:CR> Aurora Sim
|
|
void LLFloaterTools::updateToolsSizeLimits()
|
|
{
|
|
mPanelObject->updateLimits(FALSE);
|
|
}
|
|
// </FS:CR> Aurora Sim
|
|
|
|
void LLFloaterTools::changePrecision(S32 decimal_precision)
|
|
{
|
|
// Precision gets funky at 8 digits.
|
|
if (decimal_precision < 0) decimal_precision = 0;
|
|
else if (decimal_precision > 7) decimal_precision = 7;
|
|
|
|
mPanelObject->changePrecision(decimal_precision);
|
|
mPanelFace->changePrecision(decimal_precision);
|
|
}
|
|
|
|
// Create the popupview with a dummy center. It will be moved into place
|
|
// during LLViewerWindow's per-frame hover processing.
|
|
LLFloaterTools::LLFloaterTools(const LLSD& key)
|
|
: LLFloater(key),
|
|
mBtnFocus(NULL),
|
|
mBtnMove(NULL),
|
|
mBtnEdit(NULL),
|
|
mBtnCreate(NULL),
|
|
mBtnLand(NULL),
|
|
mTextStatus(NULL),
|
|
|
|
mRadioGroupFocus(NULL),
|
|
mRadioGroupMove(NULL),
|
|
mRadioGroupEdit(NULL),
|
|
|
|
mCheckSelectIndividual(NULL),
|
|
|
|
mCheckSnapToGrid(NULL),
|
|
mBtnGridOptions(NULL),
|
|
mComboGridMode(NULL),
|
|
mCheckStretchUniform(NULL),
|
|
mCheckStretchTexture(NULL),
|
|
// <FS:KC>
|
|
mCheckShowHighlight(NULL),
|
|
mCheckActualRoot(NULL),
|
|
// </FS:KC>
|
|
|
|
mBtnRotateLeft(NULL),
|
|
mBtnRotateReset(NULL),
|
|
mBtnRotateRight(NULL),
|
|
|
|
mBtnLink(NULL),
|
|
mBtnUnlink(NULL),
|
|
|
|
// <FS:PP> FIRE-14493: Buttons to cycle through linkset
|
|
mBtnPrevPart(NULL),
|
|
mBtnNextPart(NULL),
|
|
// </FS:PP>
|
|
|
|
mBtnDelete(NULL),
|
|
mBtnDuplicate(NULL),
|
|
mBtnDuplicateInPlace(NULL),
|
|
|
|
// <FS:Ansariel> FIRE-7802: Grass and tree selection in build tool
|
|
mTreeGrassCombo(NULL),
|
|
|
|
mCheckSticky(NULL),
|
|
mCheckCopySelection(NULL),
|
|
mCheckCopyCenters(NULL),
|
|
mCheckCopyRotates(NULL),
|
|
mRadioGroupLand(NULL),
|
|
mSliderDozerSize(NULL),
|
|
mSliderDozerForce(NULL),
|
|
mBtnApplyToSelection(NULL),
|
|
|
|
mTab(NULL),
|
|
mPanelPermissions(NULL),
|
|
mPanelObject(NULL),
|
|
mPanelVolume(NULL),
|
|
mPanelContents(NULL),
|
|
mPanelFace(NULL),
|
|
mPanelLandInfo(NULL),
|
|
|
|
mCostTextBorder(NULL),
|
|
mTabLand(NULL),
|
|
|
|
mLandImpactsObserver(NULL),
|
|
|
|
mDirty(TRUE),
|
|
mHasSelection(TRUE)
|
|
{
|
|
gFloaterTools = this;
|
|
|
|
setAutoFocus(FALSE);
|
|
mFactoryMap["General"] = LLCallbackMap(createPanelPermissions, this);//LLPanelPermissions
|
|
mFactoryMap["Object"] = LLCallbackMap(createPanelObject, this);//LLPanelObject
|
|
mFactoryMap["Features"] = LLCallbackMap(createPanelVolume, this);//LLPanelVolume
|
|
mFactoryMap["Texture"] = LLCallbackMap(createPanelFace, this);//LLPanelFace
|
|
mFactoryMap["Contents"] = LLCallbackMap(createPanelContents, this);//LLPanelContents
|
|
mFactoryMap["land info panel"] = LLCallbackMap(createPanelLandInfo, this);//LLPanelLandInfo
|
|
|
|
mCommitCallbackRegistrar.add("BuildTool.setTool", boost::bind(&LLFloaterTools::setTool,this, _2));
|
|
mCommitCallbackRegistrar.add("BuildTool.commitZoom", boost::bind(&commit_slider_zoom, _1));
|
|
mCommitCallbackRegistrar.add("BuildTool.commitRadioFocus", boost::bind(&commit_radio_group_focus, _1));
|
|
mCommitCallbackRegistrar.add("BuildTool.commitRadioMove", boost::bind(&commit_radio_group_move,_1));
|
|
mCommitCallbackRegistrar.add("BuildTool.commitRadioEdit", boost::bind(&commit_radio_group_edit,_1));
|
|
|
|
mCommitCallbackRegistrar.add("BuildTool.gridMode", boost::bind(&commit_grid_mode,_1));
|
|
mCommitCallbackRegistrar.add("BuildTool.selectComponent", boost::bind(&commit_select_component, this));
|
|
mCommitCallbackRegistrar.add("BuildTool.gridOptions", boost::bind(&LLFloaterTools::onClickGridOptions,this));
|
|
mCommitCallbackRegistrar.add("BuildTool.applyToSelection", boost::bind(&click_apply_to_selection, this));
|
|
mCommitCallbackRegistrar.add("BuildTool.commitRadioLand", boost::bind(&commit_radio_group_land,_1));
|
|
mCommitCallbackRegistrar.add("BuildTool.LandBrushForce", boost::bind(&commit_slider_dozer_force,_1));
|
|
|
|
mCommitCallbackRegistrar.add("BuildTool.LinkObjects", boost::bind(&LLSelectMgr::linkObjects, LLSelectMgr::getInstance()));
|
|
mCommitCallbackRegistrar.add("BuildTool.UnlinkObjects", boost::bind(&LLSelectMgr::unlinkObjects, LLSelectMgr::getInstance()));
|
|
|
|
// <FS>
|
|
mCommitCallbackRegistrar.add("BuildTool.CopyKeys", boost::bind(&LLFloaterTools::onClickBtnCopyKeys,this));
|
|
mCommitCallbackRegistrar.add("BuildTool.Expand", boost::bind(&LLFloaterTools::onClickExpand,this));
|
|
mCommitCallbackRegistrar.add("BuildTool.Flip", boost::bind(&LLPanelFace::onCommitFlip, _1, _2));
|
|
// </FS>
|
|
|
|
// <FS:Ansariel> FIRE-7802: Grass and tree selection in build tool
|
|
mCommitCallbackRegistrar.add("BuildTool.TreeGrass", boost::bind(&LLFloaterTools::onSelectTreeGrassCombo, this));
|
|
|
|
// <FS:KC> show/hide build highlight
|
|
mCommitCallbackRegistrar.add("BuildTool.commitShowHighlight", boost::bind(&commit_show_highlight, this));
|
|
|
|
mLandImpactsObserver = new LLLandImpactsObserver();
|
|
LLViewerParcelMgr::getInstance()->addObserver(mLandImpactsObserver);
|
|
}
|
|
|
|
LLFloaterTools::~LLFloaterTools()
|
|
{
|
|
// children automatically deleted
|
|
gFloaterTools = NULL;
|
|
|
|
LLViewerParcelMgr::getInstance()->removeObserver(mLandImpactsObserver);
|
|
delete mLandImpactsObserver;
|
|
}
|
|
|
|
void LLFloaterTools::setStatusText(const std::string& text)
|
|
{
|
|
// <FS:ND> Can be 0 during login
|
|
if( !mTextStatus )
|
|
return;
|
|
// </FS:ND>
|
|
|
|
std::map<std::string, std::string>::iterator iter = mStatusText.find(text);
|
|
if (iter != mStatusText.end())
|
|
{
|
|
mTextStatus->setText(iter->second);
|
|
}
|
|
else
|
|
{
|
|
mTextStatus->setText(text);
|
|
}
|
|
}
|
|
|
|
void LLFloaterTools::refresh()
|
|
{
|
|
const S32 INFO_WIDTH = getRect().getWidth();
|
|
const S32 INFO_HEIGHT = 384;
|
|
LLRect object_info_rect(0, 0, INFO_WIDTH, -INFO_HEIGHT);
|
|
BOOL all_volume = LLSelectMgr::getInstance()->selectionAllPCode( LL_PCODE_VOLUME );
|
|
|
|
S32 idx_features = mTab->getPanelIndexByTitle(PANEL_NAMES[PANEL_FEATURES]);
|
|
S32 idx_face = mTab->getPanelIndexByTitle(PANEL_NAMES[PANEL_FACE]);
|
|
S32 idx_contents = mTab->getPanelIndexByTitle(PANEL_NAMES[PANEL_CONTENTS]);
|
|
|
|
S32 selected_index = mTab->getCurrentPanelIndex();
|
|
|
|
if (!all_volume && (selected_index == idx_features || selected_index == idx_face ||
|
|
selected_index == idx_contents))
|
|
{
|
|
mTab->selectFirstTab();
|
|
}
|
|
|
|
mTab->enableTabButton(idx_features, all_volume);
|
|
mTab->enableTabButton(idx_face, all_volume);
|
|
mTab->enableTabButton(idx_contents, all_volume);
|
|
|
|
// Refresh object and prim count labels
|
|
LLLocale locale(LLLocale::USER_LOCALE);
|
|
|
|
// <FS:KC>
|
|
std::string desc_string;
|
|
std::string num_string;
|
|
bool enable_link_count = true;
|
|
S32 prim_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount();
|
|
if (prim_count == 1 && LLToolMgr::getInstance()->getCurrentTool() == LLToolFace::getInstance())
|
|
{
|
|
desc_string = getString("selected_faces");
|
|
|
|
LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstRootObject();
|
|
LLSelectNode* nodep = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode();
|
|
if(!objectp || !nodep)
|
|
{
|
|
objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject();
|
|
nodep = LLSelectMgr::getInstance()->getSelection()->getFirstNode();
|
|
}
|
|
|
|
if (objectp && objectp->getNumTEs() == LLSelectMgr::getInstance()->getSelection()->getTECount())
|
|
num_string = "ALL_SIDES";
|
|
else if (objectp && nodep)
|
|
{
|
|
//S32 count = 0;
|
|
for (S32 i = 0; i < objectp->getNumTEs(); i++)
|
|
{
|
|
if (nodep->isTESelected(i))
|
|
{
|
|
if (!num_string.empty())
|
|
num_string.append(", ");
|
|
num_string.append(llformat("%d", i));
|
|
//count++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (prim_count == 1 && gSavedSettings.getBOOL("EditLinkedParts"))
|
|
{
|
|
desc_string = getString("link_number");
|
|
LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject();
|
|
if (objectp && objectp->getRootEdit())
|
|
{
|
|
LLViewerObject::child_list_t children = objectp->getRootEdit()->getChildren();
|
|
if (children.empty())
|
|
num_string = "0"; //a childless prim is always link zero, and unhappy
|
|
else if (objectp->getRootEdit()->isSelected())
|
|
num_string = "1"; //root prim is always link one
|
|
else
|
|
{
|
|
S32 index = 1;
|
|
for (LLViewerObject::child_list_t::iterator iter = children.begin(); iter != children.end(); ++iter)
|
|
{
|
|
index++;
|
|
if ((*iter)->isSelected())
|
|
{
|
|
LLResMgr::getInstance()->getIntegerString(num_string, index);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
enable_link_count = false;
|
|
}
|
|
getChild<LLUICtrl>("link_num_obj_count")->setTextArg("[DESC]", desc_string);
|
|
getChild<LLUICtrl>("link_num_obj_count")->setTextArg("[NUM]", num_string);
|
|
// </FS:KC>
|
|
#if 0
|
|
if (!gMeshRepo.meshRezEnabled())
|
|
{
|
|
std::string obj_count_string;
|
|
LLResMgr::getInstance()->getIntegerString(obj_count_string, LLSelectMgr::getInstance()->getSelection()->getRootObjectCount());
|
|
getChild<LLUICtrl>("selection_count")->setTextArg("[OBJ_COUNT]", obj_count_string);
|
|
std::string prim_count_string;
|
|
LLResMgr::getInstance()->getIntegerString(prim_count_string, LLSelectMgr::getInstance()->getSelection()->getObjectCount());
|
|
getChild<LLUICtrl>("selection_count")->setTextArg("[PRIM_COUNT]", prim_count_string);
|
|
|
|
// calculate selection rendering cost
|
|
if (sShowObjectCost)
|
|
{
|
|
std::string prim_cost_string;
|
|
S32 render_cost = LLSelectMgr::getInstance()->getSelection()->getSelectedObjectRenderCost();
|
|
LLResMgr::getInstance()->getIntegerString(prim_cost_string, render_cost);
|
|
// <FS:Ansariel> Was removed from floater_tools.xml as part of SH-1917 SH-1935
|
|
//getChild<LLUICtrl>("RenderingCost")->setTextArg("[COUNT]", prim_cost_string);
|
|
}
|
|
|
|
// disable the object and prim counts if nothing selected
|
|
bool have_selection = ! LLSelectMgr::getInstance()->getSelection()->isEmpty();
|
|
getChildView("link_num_obj_count")->setEnabled(have_selection);
|
|
//getChildView("obj_count")->setEnabled(have_selection);
|
|
// <FS:Ansariel> Was removed from floater_tools.xml as part of SH-1719
|
|
//getChildView("prim_count")->setEnabled(have_selection);
|
|
// <FS:Ansariel> Was removed from floater_tools.xml as part of SH-1917 SH-1935
|
|
//getChildView("RenderingCost")->setEnabled(have_selection && sShowObjectCost);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
|
|
F32 link_cost = selection->getSelectedLinksetCost();
|
|
// <FS:CR> FIRE-9287 - LI/Prim count not reflected on OpenSim
|
|
#ifdef OPENSIM
|
|
S32 prim_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount();
|
|
#endif // OPENSIM
|
|
// </FS:CR>
|
|
S32 link_count = selection->getRootObjectCount();
|
|
//S32 object_count = selection->getObjectCount(); // <FS:Ansariel> We got this already
|
|
|
|
LLCrossParcelFunctor func;
|
|
if (!LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, true))
|
|
{
|
|
// Unless multiple parcels selected, higlight parcel object is at.
|
|
LLViewerObject* selected_object = mObjectSelection->getFirstObject();
|
|
if (selected_object)
|
|
{
|
|
// <FS:Ansariel> FIRE-20387: Editing HUD attachment shows [CAPACITY_STRING] in tools floater
|
|
//LLViewerParcelMgr::getInstance()->selectParcelAt(selected_object->getPositionGlobal());
|
|
if (!selected_object->isAttachment())
|
|
{
|
|
LLViewerParcelMgr::getInstance()->selectParcelAt(selected_object->getPositionGlobal());
|
|
}
|
|
else
|
|
{
|
|
const LLStringExplicit empty_str("");
|
|
childSetTextArg("more info label", "[CAPACITY_STRING]", empty_str);
|
|
}
|
|
// </FS:Ansariel>
|
|
}
|
|
else
|
|
{
|
|
LL_WARNS() << "Failed to get selected object" << LL_ENDL;
|
|
}
|
|
}
|
|
// <FS:Ansariel> Bring back remaining capacity info
|
|
else
|
|
{
|
|
// Selection crosses parcel bounds.
|
|
// We don't display remaining land capacity in this case.
|
|
const LLStringExplicit empty_str("");
|
|
childSetTextArg("more info label", "[CAPACITY_STRING]", empty_str);
|
|
}
|
|
// </FS:Ansariel>
|
|
|
|
// <FS:Ansariel> We got this already
|
|
//if (object_count == 1)
|
|
//{
|
|
// // "selection_faces" shouldn't be visible if not LLToolFace::getInstance()
|
|
// // But still need to be populated in case user switches
|
|
|
|
// std::string faces_str = "";
|
|
|
|
// for (LLObjectSelection::iterator iter = selection->begin(); iter != selection->end();)
|
|
// {
|
|
// LLObjectSelection::iterator nextiter = iter++; // not strictly needed, we have only one object
|
|
// LLSelectNode* node = *nextiter;
|
|
// LLViewerObject* object = (*nextiter)->getObject();
|
|
// if (!object)
|
|
// continue;
|
|
// S32 num_tes = llmin((S32)object->getNumTEs(), (S32)object->getNumFaces());
|
|
// for (S32 te = 0; te < num_tes; ++te)
|
|
// {
|
|
// if (node->isTESelected(te))
|
|
// {
|
|
// if (!faces_str.empty())
|
|
// {
|
|
// faces_str += ", ";
|
|
// }
|
|
// faces_str += llformat("%d", te);
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
// childSetTextArg("selection_faces", "[FACES_STRING]", faces_str);
|
|
//}
|
|
|
|
//bool show_faces = (object_count == 1)
|
|
// && LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool();
|
|
//getChildView("selection_faces")->setVisible(show_faces);
|
|
// </FS:Ansariel>
|
|
|
|
LLStringUtil::format_map_t selection_args;
|
|
selection_args["OBJ_COUNT"] = llformat("%.1d", link_count);
|
|
// <FS:CR> FIRE-9287 - LI/Prim count not reflected on OpenSim
|
|
#ifdef OPENSIM
|
|
if (LLGridManager::getInstance()->isInOpenSim())
|
|
selection_args["LAND_IMPACT"] = llformat("%.1d", (link_cost ? (S32)link_cost : prim_count));
|
|
else
|
|
#endif // OPENSIM
|
|
// </FS:CR>
|
|
selection_args["LAND_IMPACT"] = llformat("%.1d", (S32)link_cost);
|
|
|
|
std::ostringstream selection_info;
|
|
|
|
selection_info << getString("status_selectcount", selection_args);
|
|
|
|
getChild<LLTextBox>("selection_count")->setText(selection_info.str());
|
|
}
|
|
|
|
// <FS> disable the object and prim counts if nothing selected
|
|
bool have_selection = ! LLSelectMgr::getInstance()->getSelection()->isEmpty();
|
|
getChildView("link_num_obj_count")->setEnabled(have_selection && enable_link_count);
|
|
// </FS>
|
|
|
|
// Refresh child tabs
|
|
mPanelPermissions->refresh();
|
|
mPanelObject->refresh();
|
|
mPanelVolume->refresh();
|
|
mPanelFace->refresh();
|
|
mPanelFace->refreshMedia();
|
|
mPanelContents->refresh();
|
|
mPanelLandInfo->refresh();
|
|
|
|
// Refresh the advanced weights floater
|
|
LLFloaterObjectWeights* object_weights_floater = LLFloaterReg::findTypedInstance<LLFloaterObjectWeights>("object_weights");
|
|
if(object_weights_floater && object_weights_floater->getVisible())
|
|
{
|
|
object_weights_floater->refresh();
|
|
}
|
|
|
|
// <FS:CR> Only enable Copy Keys when we have something selected
|
|
getChild<LLButton>("btnCopyKeys")->setEnabled(have_selection);
|
|
// </FS:CR>
|
|
}
|
|
|
|
void LLFloaterTools::draw()
|
|
{
|
|
BOOL has_selection = !LLSelectMgr::getInstance()->getSelection()->isEmpty();
|
|
if(!has_selection && (mHasSelection != has_selection))
|
|
{
|
|
mDirty = TRUE;
|
|
}
|
|
mHasSelection = has_selection;
|
|
|
|
if (mDirty)
|
|
{
|
|
refresh();
|
|
mDirty = FALSE;
|
|
}
|
|
|
|
// mCheckSelectIndividual->set(gSavedSettings.getBOOL("EditLinkedParts"));
|
|
LLFloater::draw();
|
|
}
|
|
|
|
void LLFloaterTools::dirty()
|
|
{
|
|
mDirty = TRUE;
|
|
LLFloaterOpenObject* instance = LLFloaterReg::findTypedInstance<LLFloaterOpenObject>("openobject");
|
|
if (instance) instance->dirty();
|
|
}
|
|
|
|
// Clean up any tool state that should not persist when the
|
|
// floater is closed.
|
|
void LLFloaterTools::resetToolState()
|
|
{
|
|
gCameraBtnZoom = TRUE;
|
|
gCameraBtnOrbit = FALSE;
|
|
gCameraBtnPan = FALSE;
|
|
|
|
gGrabBtnSpin = FALSE;
|
|
gGrabBtnVertical = FALSE;
|
|
}
|
|
|
|
void LLFloaterTools::updatePopup(LLCoordGL center, MASK mask)
|
|
{
|
|
LLTool *tool = LLToolMgr::getInstance()->getCurrentTool();
|
|
|
|
// HACK to allow seeing the buttons when you have the app in a window.
|
|
// Keep the visibility the same as it
|
|
if (tool == gToolNull)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( isMinimized() )
|
|
{ // SL looks odd if we draw the tools while the window is minimized
|
|
return;
|
|
}
|
|
|
|
// Focus buttons
|
|
BOOL focus_visible = ( tool == LLToolCamera::getInstance() );
|
|
|
|
mBtnFocus ->setToggleState( focus_visible );
|
|
|
|
mRadioGroupFocus->setVisible( focus_visible );
|
|
getChildView("slider zoom")->setVisible( focus_visible);
|
|
getChildView("slider zoom")->setEnabled(gCameraBtnZoom);
|
|
|
|
if (!gCameraBtnOrbit &&
|
|
!gCameraBtnPan &&
|
|
!(mask == MASK_ORBIT) &&
|
|
!(mask == (MASK_ORBIT | MASK_ALT)) &&
|
|
!(mask == MASK_PAN) &&
|
|
!(mask == (MASK_PAN | MASK_ALT)) )
|
|
{
|
|
mRadioGroupFocus->setValue("radio zoom");
|
|
}
|
|
else if ( gCameraBtnOrbit ||
|
|
(mask == MASK_ORBIT) ||
|
|
(mask == (MASK_ORBIT | MASK_ALT)) )
|
|
{
|
|
mRadioGroupFocus->setValue("radio orbit");
|
|
}
|
|
else if ( gCameraBtnPan ||
|
|
(mask == MASK_PAN) ||
|
|
(mask == (MASK_PAN | MASK_ALT)) )
|
|
{
|
|
mRadioGroupFocus->setValue("radio pan");
|
|
}
|
|
|
|
// multiply by correction factor because volume sliders go [0, 0.5]
|
|
getChild<LLUICtrl>("slider zoom")->setValue(gAgentCamera.getCameraZoomFraction() * 0.5f);
|
|
|
|
// Move buttons
|
|
BOOL move_visible = (tool == LLToolGrab::getInstance());
|
|
|
|
if (mBtnMove) mBtnMove ->setToggleState( move_visible );
|
|
|
|
// HACK - highlight buttons for next click
|
|
mRadioGroupMove->setVisible(move_visible);
|
|
if (!(gGrabBtnSpin ||
|
|
gGrabBtnVertical ||
|
|
(mask == MASK_VERTICAL) ||
|
|
(mask == MASK_SPIN)))
|
|
{
|
|
mRadioGroupMove->setValue("radio move");
|
|
}
|
|
else if ((mask == MASK_VERTICAL) ||
|
|
(gGrabBtnVertical && (mask != MASK_SPIN)))
|
|
{
|
|
mRadioGroupMove->setValue("radio lift");
|
|
}
|
|
else if ((mask == MASK_SPIN) ||
|
|
(gGrabBtnSpin && (mask != MASK_VERTICAL)))
|
|
{
|
|
mRadioGroupMove->setValue("radio spin");
|
|
}
|
|
|
|
// Edit buttons
|
|
BOOL edit_visible = tool == LLToolCompTranslate::getInstance() ||
|
|
tool == LLToolCompRotate::getInstance() ||
|
|
tool == LLToolCompScale::getInstance() ||
|
|
tool == LLToolFace::getInstance() ||
|
|
tool == LLToolIndividual::getInstance() ||
|
|
tool == QToolAlign::getInstance() ||
|
|
tool == LLToolPipette::getInstance();
|
|
|
|
mBtnEdit ->setToggleState( edit_visible );
|
|
mRadioGroupEdit->setVisible( edit_visible );
|
|
//bool linked_parts = gSavedSettings.getBOOL("EditLinkedParts");
|
|
static LLCachedControl<bool> linked_parts(gSavedSettings, "EditLinkedParts");
|
|
//getChildView("RenderingCost")->setVisible( !linked_parts && (edit_visible || focus_visible || move_visible) && sShowObjectCost);
|
|
|
|
mBtnLink->setVisible(edit_visible);
|
|
mBtnUnlink->setVisible(edit_visible);
|
|
|
|
mBtnLink->setEnabled(LLSelectMgr::instance().enableLinkObjects());
|
|
mBtnUnlink->setEnabled(LLSelectMgr::instance().enableUnlinkObjects());
|
|
|
|
// <FS:PP> FIRE-14493: Buttons to cycle through linkset
|
|
mBtnPrevPart->setVisible(edit_visible);
|
|
mBtnNextPart->setVisible(edit_visible);
|
|
|
|
bool select_btn_enabled = (!LLSelectMgr::getInstance()->getSelection()->isEmpty()
|
|
&& (linked_parts || LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool()));
|
|
mBtnPrevPart->setEnabled(select_btn_enabled);
|
|
mBtnNextPart->setEnabled(select_btn_enabled);
|
|
// </FS:PP>
|
|
|
|
if (mCheckSelectIndividual)
|
|
{
|
|
mCheckSelectIndividual->setVisible(edit_visible);
|
|
//mCheckSelectIndividual->set(gSavedSettings.getBOOL("EditLinkedParts"));
|
|
}
|
|
|
|
if ( tool == LLToolCompTranslate::getInstance() )
|
|
{
|
|
mRadioGroupEdit->setValue("radio position");
|
|
}
|
|
else if ( tool == LLToolCompRotate::getInstance() )
|
|
{
|
|
mRadioGroupEdit->setValue("radio rotate");
|
|
}
|
|
else if ( tool == LLToolCompScale::getInstance() )
|
|
{
|
|
mRadioGroupEdit->setValue("radio stretch");
|
|
}
|
|
else if ( tool == LLToolFace::getInstance() )
|
|
{
|
|
mRadioGroupEdit->setValue("radio select face");
|
|
}
|
|
else if ( tool == QToolAlign::getInstance() )
|
|
{
|
|
mRadioGroupEdit->setValue("radio align");
|
|
}
|
|
|
|
if (mComboGridMode)
|
|
{
|
|
mComboGridMode->setVisible( edit_visible );
|
|
S32 index = mComboGridMode->getCurrentIndex();
|
|
mComboGridMode->removeall();
|
|
|
|
switch (mObjectSelection->getSelectType())
|
|
{
|
|
case SELECT_TYPE_HUD:
|
|
mComboGridMode->add(getString("grid_screen_text"));
|
|
mComboGridMode->add(getString("grid_local_text"));
|
|
break;
|
|
case SELECT_TYPE_WORLD:
|
|
mComboGridMode->add(getString("grid_world_text"));
|
|
mComboGridMode->add(getString("grid_local_text"));
|
|
mComboGridMode->add(getString("grid_reference_text"));
|
|
break;
|
|
case SELECT_TYPE_ATTACHMENT:
|
|
mComboGridMode->add(getString("grid_attachment_text"));
|
|
mComboGridMode->add(getString("grid_local_text"));
|
|
mComboGridMode->add(getString("grid_reference_text"));
|
|
break;
|
|
}
|
|
|
|
mComboGridMode->setCurrentByIndex(index);
|
|
}
|
|
|
|
// Snap to grid disabled for grab tool - very confusing
|
|
if (mCheckSnapToGrid) mCheckSnapToGrid->setVisible( edit_visible /* || tool == LLToolGrab::getInstance() */ );
|
|
if (mBtnGridOptions) mBtnGridOptions->setVisible( edit_visible /* || tool == LLToolGrab::getInstance() */ );
|
|
|
|
//mCheckSelectLinked ->setVisible( edit_visible );
|
|
if (mCheckStretchUniform) mCheckStretchUniform->setVisible( edit_visible );
|
|
if (mCheckStretchTexture) mCheckStretchTexture->setVisible( edit_visible );
|
|
// <FS:KC>
|
|
if (mCheckShowHighlight) mCheckShowHighlight->setVisible( edit_visible );
|
|
if (mCheckActualRoot) mCheckActualRoot->setVisible( edit_visible );
|
|
// </FS:KC>
|
|
|
|
// Create buttons
|
|
BOOL create_visible = (tool == LLToolCompCreate::getInstance());
|
|
|
|
// <FS:Ansariel> FIRE-7802: Grass and tree selection in build tool
|
|
if (mTreeGrassCombo) mTreeGrassCombo->setVisible(create_visible);
|
|
if (create_visible) buildTreeGrassCombo();
|
|
|
|
mBtnCreate ->setToggleState( tool == LLToolCompCreate::getInstance() );
|
|
|
|
if (mCheckCopySelection
|
|
&& mCheckCopySelection->get())
|
|
{
|
|
// don't highlight any placer button
|
|
for (std::vector<LLButton*>::size_type i = 0; i < mButtons.size(); i++)
|
|
{
|
|
mButtons[i]->setToggleState(FALSE);
|
|
mButtons[i]->setVisible( create_visible );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Highlight the correct placer button
|
|
for( S32 t = 0; t < (S32)mButtons.size(); t++ )
|
|
{
|
|
LLPCode pcode = LLToolPlacer::getObjectType();
|
|
LLPCode button_pcode = toolData[t];
|
|
BOOL state = (pcode == button_pcode);
|
|
mButtons[t]->setToggleState( state );
|
|
mButtons[t]->setVisible( create_visible );
|
|
}
|
|
}
|
|
|
|
if (mCheckSticky) mCheckSticky ->setVisible( create_visible );
|
|
if (mCheckCopySelection) mCheckCopySelection ->setVisible( create_visible );
|
|
if (mCheckCopyCenters) mCheckCopyCenters ->setVisible( create_visible );
|
|
if (mCheckCopyRotates) mCheckCopyRotates ->setVisible( create_visible );
|
|
|
|
if (mCheckCopyCenters && mCheckCopySelection) mCheckCopyCenters->setEnabled( mCheckCopySelection->get() );
|
|
if (mCheckCopyRotates && mCheckCopySelection) mCheckCopyRotates->setEnabled( mCheckCopySelection->get() );
|
|
|
|
// Land buttons
|
|
BOOL land_visible = (tool == LLToolBrushLand::getInstance() || tool == LLToolSelectLand::getInstance() );
|
|
|
|
mCostTextBorder->setVisible(!land_visible);
|
|
|
|
if (mBtnLand) mBtnLand ->setToggleState( land_visible );
|
|
|
|
mRadioGroupLand->setVisible( land_visible );
|
|
if ( tool == LLToolSelectLand::getInstance() )
|
|
{
|
|
mRadioGroupLand->setValue("radio select land");
|
|
}
|
|
else if ( tool == LLToolBrushLand::getInstance() )
|
|
{
|
|
//S32 dozer_mode = gSavedSettings.getS32("RadioLandBrushAction");
|
|
static LLCachedControl<S32> dozer_mode(gSavedSettings, "RadioLandBrushAction");
|
|
switch(dozer_mode)
|
|
{
|
|
case 0:
|
|
mRadioGroupLand->setValue("radio flatten");
|
|
break;
|
|
case 1:
|
|
mRadioGroupLand->setValue("radio raise");
|
|
break;
|
|
case 2:
|
|
mRadioGroupLand->setValue("radio lower");
|
|
break;
|
|
case 3:
|
|
mRadioGroupLand->setValue("radio smooth");
|
|
break;
|
|
case 4:
|
|
mRadioGroupLand->setValue("radio noise");
|
|
break;
|
|
case 5:
|
|
mRadioGroupLand->setValue("radio revert");
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (mBtnApplyToSelection)
|
|
{
|
|
mBtnApplyToSelection->setVisible( land_visible );
|
|
mBtnApplyToSelection->setEnabled( land_visible && !LLViewerParcelMgr::getInstance()->selectionEmpty() && tool != LLToolSelectLand::getInstance());
|
|
}
|
|
if (mSliderDozerSize)
|
|
{
|
|
mSliderDozerSize ->setVisible( land_visible );
|
|
getChildView("Bulldozer:")->setVisible( land_visible);
|
|
getChildView("Dozer Size:")->setVisible( land_visible);
|
|
}
|
|
if (mSliderDozerForce)
|
|
{
|
|
mSliderDozerForce ->setVisible( land_visible );
|
|
getChildView("Strength:")->setVisible( land_visible);
|
|
}
|
|
|
|
// <FS>
|
|
static LLCachedControl<bool> sFSToolboxExpanded(gSavedSettings, "FSToolboxExpanded", TRUE);
|
|
mTab->setVisible(!land_visible && sFSToolboxExpanded);
|
|
mPanelLandInfo->setVisible(land_visible && sFSToolboxExpanded);
|
|
// </FS>
|
|
|
|
bool have_selection = !LLSelectMgr::getInstance()->getSelection()->isEmpty();
|
|
|
|
// <FS>
|
|
getChildView("more info label")->setVisible(!land_visible && have_selection);
|
|
getChildView("selection_count")->setVisible(!land_visible && have_selection);
|
|
// <FS:Ansariel> We got this already
|
|
//getChildView("selection_faces")->setVisible(LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool()
|
|
// && LLSelectMgr::getInstance()->getSelection()->getObjectCount() == 1);
|
|
getChildView("selection_empty")->setVisible(!land_visible && !have_selection);
|
|
|
|
//mTab->setVisible(!land_visible);
|
|
//mPanelLandInfo->setVisible(land_visible);
|
|
|
|
}
|
|
|
|
|
|
// virtual
|
|
BOOL LLFloaterTools::canClose()
|
|
{
|
|
// don't close when quitting, so camera will stay put
|
|
return !LLApp::isExiting();
|
|
}
|
|
|
|
// virtual
|
|
void LLFloaterTools::onOpen(const LLSD& key)
|
|
{
|
|
mParcelSelection = LLViewerParcelMgr::getInstance()->getFloatingParcelSelection();
|
|
mObjectSelection = LLSelectMgr::getInstance()->getEditSelection();
|
|
|
|
// <FS:KC> Set the check box value from the saved setting
|
|
// this function runs on selection change
|
|
if (!mOpen)
|
|
{
|
|
mOpen = TRUE;
|
|
mCheckShowHighlight->setValue(gSavedSettings.getBOOL("RenderHighlightSelections"));
|
|
}
|
|
// </FS:KC>
|
|
|
|
std::string panel = key.asString();
|
|
if (!panel.empty())
|
|
{
|
|
mTab->selectTabByName(panel);
|
|
}
|
|
|
|
LLTool* tool = LLToolMgr::getInstance()->getCurrentTool();
|
|
if (tool == LLToolCompInspect::getInstance()
|
|
|| tool == LLToolDragAndDrop::getInstance())
|
|
{
|
|
// Something called floater up while it was supressed (during drag n drop, inspect),
|
|
// so it won't be getting any layout or visibility updates, update once
|
|
// further updates will come from updateLayout()
|
|
LLCoordGL select_center_screen;
|
|
MASK mask = gKeyboard->currentMask(TRUE);
|
|
updatePopup(select_center_screen, mask);
|
|
}
|
|
|
|
//gMenuBarView->setItemVisible("BuildTools", TRUE);
|
|
}
|
|
|
|
// virtual
|
|
void LLFloaterTools::onClose(bool app_quitting)
|
|
{
|
|
mTab->setVisible(FALSE);
|
|
|
|
LLViewerJoystick::getInstance()->moveAvatar(false);
|
|
|
|
// destroy media source used to grab media title
|
|
mPanelFace->unloadMedia();
|
|
|
|
// Different from handle_reset_view in that it doesn't actually
|
|
// move the camera if EditCameraMovement is not set.
|
|
gAgentCamera.resetView(gSavedSettings.getBOOL("EditCameraMovement"));
|
|
|
|
// exit component selection mode
|
|
LLSelectMgr::getInstance()->promoteSelectionToRoot();
|
|
gSavedSettings.setBOOL("EditLinkedParts", FALSE);
|
|
|
|
// <FS:KC>
|
|
LLSelectMgr::instance().setFSShowHideHighlight(FS_SHOW_HIDE_HIGHLIGHT_NORMAL);
|
|
|
|
mOpen = FALSE; //hack cause onOpen runs on every selection change but onClose doesnt.
|
|
// </FS:KC>
|
|
|
|
gViewerWindow->showCursor();
|
|
|
|
resetToolState();
|
|
|
|
mParcelSelection = NULL;
|
|
mObjectSelection = NULL;
|
|
|
|
// <FS:Ansariel> Enable context/pie menu in mouselook
|
|
// Switch back to basic toolset
|
|
//LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset);
|
|
// we were already in basic toolset, using build tools
|
|
// so manually reset tool to default (pie menu tool)
|
|
//LLToolMgr::getInstance()->getCurrentToolset()->selectFirstTool();
|
|
if (!gAgentCamera.cameraMouselook())
|
|
{
|
|
LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset);
|
|
LLToolMgr::getInstance()->getCurrentToolset()->selectFirstTool();
|
|
}
|
|
else
|
|
{
|
|
// Switch back to mouselook toolset
|
|
LLToolMgr::getInstance()->setCurrentToolset(gMouselookToolset);
|
|
gViewerWindow->hideCursor();
|
|
gViewerWindow->moveCursorToCenter();
|
|
}
|
|
// </FS:Ansariel>
|
|
|
|
//gMenuBarView->setItemVisible("BuildTools", FALSE);
|
|
LLFloaterReg::hideInstance("media_settings");
|
|
|
|
// hide the advanced object weights floater
|
|
LLFloaterReg::hideInstance("object_weights");
|
|
|
|
// hide gltf material editor
|
|
LLFloaterReg::hideInstance("live_material_editor");
|
|
|
|
// prepare content for next call
|
|
mPanelContents->clearContents();
|
|
|
|
if(sPreviousFocusOnAvatar)
|
|
{
|
|
sPreviousFocusOnAvatar = false;
|
|
gAgentCamera.setAllowChangeToFollow(TRUE);
|
|
}
|
|
}
|
|
|
|
void click_popup_info(void*)
|
|
{
|
|
}
|
|
|
|
void click_popup_done(void*)
|
|
{
|
|
handle_reset_view();
|
|
}
|
|
|
|
void commit_radio_group_move(LLUICtrl* ctrl)
|
|
{
|
|
LLRadioGroup* group = (LLRadioGroup*)ctrl;
|
|
std::string selected = group->getValue().asString();
|
|
if (selected == "radio move")
|
|
{
|
|
gGrabBtnVertical = FALSE;
|
|
gGrabBtnSpin = FALSE;
|
|
}
|
|
else if (selected == "radio lift")
|
|
{
|
|
gGrabBtnVertical = TRUE;
|
|
gGrabBtnSpin = FALSE;
|
|
}
|
|
else if (selected == "radio spin")
|
|
{
|
|
gGrabBtnVertical = FALSE;
|
|
gGrabBtnSpin = TRUE;
|
|
}
|
|
}
|
|
|
|
void commit_radio_group_focus(LLUICtrl* ctrl)
|
|
{
|
|
LLRadioGroup* group = (LLRadioGroup*)ctrl;
|
|
std::string selected = group->getValue().asString();
|
|
if (selected == "radio zoom")
|
|
{
|
|
gCameraBtnZoom = TRUE;
|
|
gCameraBtnOrbit = FALSE;
|
|
gCameraBtnPan = FALSE;
|
|
}
|
|
else if (selected == "radio orbit")
|
|
{
|
|
gCameraBtnZoom = FALSE;
|
|
gCameraBtnOrbit = TRUE;
|
|
gCameraBtnPan = FALSE;
|
|
}
|
|
else if (selected == "radio pan")
|
|
{
|
|
gCameraBtnZoom = FALSE;
|
|
gCameraBtnOrbit = FALSE;
|
|
gCameraBtnPan = TRUE;
|
|
}
|
|
}
|
|
|
|
void commit_slider_zoom(LLUICtrl *ctrl)
|
|
{
|
|
// renormalize value, since max "volume" level is 0.5 for some reason
|
|
F32 zoom_level = (F32)ctrl->getValue().asReal() * 2.f; // / 0.5f;
|
|
gAgentCamera.setCameraZoomFraction(zoom_level);
|
|
}
|
|
|
|
void commit_slider_dozer_force(LLUICtrl *ctrl)
|
|
{
|
|
// the slider is logarithmic, so we exponentiate to get the actual force multiplier
|
|
F32 dozer_force = pow(10.f, (F32)ctrl->getValue().asReal());
|
|
gSavedSettings.setF32("LandBrushForce", dozer_force);
|
|
}
|
|
|
|
void click_apply_to_selection(void*)
|
|
{
|
|
LLToolBrushLand::getInstance()->modifyLandInSelectionGlobal();
|
|
}
|
|
|
|
void commit_radio_group_edit(LLUICtrl *ctrl)
|
|
{
|
|
S32 show_owners = gSavedSettings.getBOOL("ShowParcelOwners");
|
|
|
|
LLRadioGroup* group = (LLRadioGroup*)ctrl;
|
|
std::string selected = group->getValue().asString();
|
|
if (selected == "radio position")
|
|
{
|
|
LLFloaterTools::setEditTool( LLToolCompTranslate::getInstance() );
|
|
}
|
|
else if (selected == "radio rotate")
|
|
{
|
|
LLFloaterTools::setEditTool( LLToolCompRotate::getInstance() );
|
|
}
|
|
else if (selected == "radio stretch")
|
|
{
|
|
LLFloaterTools::setEditTool( LLToolCompScale::getInstance() );
|
|
}
|
|
else if (selected == "radio select face")
|
|
{
|
|
LLFloaterTools::setEditTool( LLToolFace::getInstance() );
|
|
}
|
|
else if (selected == "radio align")
|
|
{
|
|
LLFloaterTools::setEditTool( QToolAlign::getInstance() );
|
|
}
|
|
gSavedSettings.setBOOL("ShowParcelOwners", show_owners);
|
|
}
|
|
|
|
void commit_radio_group_land(LLUICtrl* ctrl)
|
|
{
|
|
LLRadioGroup* group = (LLRadioGroup*)ctrl;
|
|
std::string selected = group->getValue().asString();
|
|
if (selected == "radio select land")
|
|
{
|
|
LLFloaterTools::setEditTool( LLToolSelectLand::getInstance() );
|
|
}
|
|
else
|
|
{
|
|
LLFloaterTools::setEditTool( LLToolBrushLand::getInstance() );
|
|
S32 dozer_mode = gSavedSettings.getS32("RadioLandBrushAction");
|
|
if (selected == "radio flatten")
|
|
dozer_mode = 0;
|
|
else if (selected == "radio raise")
|
|
dozer_mode = 1;
|
|
else if (selected == "radio lower")
|
|
dozer_mode = 2;
|
|
else if (selected == "radio smooth")
|
|
dozer_mode = 3;
|
|
else if (selected == "radio noise")
|
|
dozer_mode = 4;
|
|
else if (selected == "radio revert")
|
|
dozer_mode = 5;
|
|
gSavedSettings.setS32("RadioLandBrushAction", dozer_mode);
|
|
}
|
|
}
|
|
void commit_select_component(void *data)
|
|
{
|
|
LLFloaterTools* floaterp = (LLFloaterTools*)data;
|
|
|
|
//forfeit focus
|
|
if (gFocusMgr.childHasKeyboardFocus(floaterp))
|
|
{
|
|
gFocusMgr.setKeyboardFocus(NULL);
|
|
}
|
|
|
|
BOOL select_individuals = floaterp->mCheckSelectIndividual->get();
|
|
gSavedSettings.setBOOL("EditLinkedParts", select_individuals);
|
|
floaterp->dirty();
|
|
|
|
if (select_individuals)
|
|
{
|
|
LLSelectMgr::getInstance()->demoteSelectionToIndividuals();
|
|
}
|
|
else
|
|
{
|
|
LLSelectMgr::getInstance()->promoteSelectionToRoot();
|
|
}
|
|
}
|
|
|
|
// <FS:KC> show/hide build highlight
|
|
void commit_show_highlight(void *data)
|
|
{
|
|
LLFloaterTools* floaterp = (LLFloaterTools*)data;
|
|
BOOL show_highlight = floaterp->mCheckShowHighlight->get();
|
|
if (show_highlight)
|
|
{
|
|
LLSelectMgr::getInstance()->setFSShowHideHighlight(FS_SHOW_HIDE_HIGHLIGHT_SHOW);
|
|
}
|
|
else
|
|
{
|
|
LLSelectMgr::getInstance()->setFSShowHideHighlight(FS_SHOW_HIDE_HIGHLIGHT_HIDE);
|
|
}
|
|
}
|
|
// </FS:KC>
|
|
|
|
|
|
// static
|
|
void LLFloaterTools::setObjectType( LLPCode pcode )
|
|
{
|
|
LLToolPlacer::setObjectType( pcode );
|
|
gSavedSettings.setBOOL("CreateToolCopySelection", FALSE);
|
|
// <FS:Ansariel> FIRE-7802: Grass and tree selection in build tool
|
|
gFloaterTools->buildTreeGrassCombo();
|
|
// </FS:Ansariel>
|
|
gFocusMgr.setMouseCapture(NULL);
|
|
}
|
|
|
|
void commit_grid_mode(LLUICtrl *ctrl)
|
|
{
|
|
LLComboBox* combo = (LLComboBox*)ctrl;
|
|
|
|
LLSelectMgr::getInstance()->setGridMode((EGridMode)combo->getCurrentIndex());
|
|
}
|
|
|
|
// static
|
|
void LLFloaterTools::setGridMode(S32 mode)
|
|
{
|
|
LLFloaterTools* tools_floater = LLFloaterReg::getTypedInstance<LLFloaterTools>("build");
|
|
if (!tools_floater || !tools_floater->mComboGridMode)
|
|
{
|
|
return;
|
|
}
|
|
|
|
tools_floater->mComboGridMode->setCurrentByIndex(mode);
|
|
}
|
|
|
|
void LLFloaterTools::onClickGridOptions()
|
|
{
|
|
LLFloater* floaterp = LLFloaterReg::showInstance("build_options");
|
|
// position floater next to build tools, not over
|
|
floaterp->setShape(gFloaterView->findNeighboringPosition(this, floaterp), true);
|
|
}
|
|
|
|
// static
|
|
void LLFloaterTools::setEditTool(void* tool_pointer)
|
|
{
|
|
LLTool *tool = (LLTool *)tool_pointer;
|
|
LLToolMgr::getInstance()->getCurrentToolset()->selectTool( tool );
|
|
}
|
|
|
|
void LLFloaterTools::setTool(const LLSD& user_data)
|
|
{
|
|
std::string control_name = user_data.asString();
|
|
if(control_name == "Focus")
|
|
LLToolMgr::getInstance()->getCurrentToolset()->selectTool((LLTool *) LLToolCamera::getInstance() );
|
|
else if (control_name == "Move" )
|
|
LLToolMgr::getInstance()->getCurrentToolset()->selectTool( (LLTool *)LLToolGrab::getInstance() );
|
|
else if (control_name == "Edit" )
|
|
LLToolMgr::getInstance()->getCurrentToolset()->selectTool( (LLTool *) LLToolCompTranslate::getInstance());
|
|
else if (control_name == "Create" )
|
|
LLToolMgr::getInstance()->getCurrentToolset()->selectTool( (LLTool *) LLToolCompCreate::getInstance());
|
|
else if (control_name == "Land" )
|
|
LLToolMgr::getInstance()->getCurrentToolset()->selectTool( (LLTool *) LLToolSelectLand::getInstance());
|
|
else
|
|
LL_WARNS()<<" no parameter name "<<control_name<<" found!! No Tool selected!!"<< LL_ENDL;
|
|
}
|
|
|
|
void LLFloaterTools::onFocusReceived()
|
|
{
|
|
LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset);
|
|
LLFloater::onFocusReceived();
|
|
}
|
|
|
|
void LLFloaterTools::updateLandImpacts()
|
|
{
|
|
LLParcel *parcel = mParcelSelection->getParcel();
|
|
if (!parcel)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// <FS:Ansariel> Bring back remaining capacity info
|
|
S32 rezzed_prims = parcel->getSimWidePrimCount();
|
|
S32 total_capacity = parcel->getSimWideMaxPrimCapacity();
|
|
LLViewerRegion* region = LLViewerParcelMgr::getInstance()->getSelectionRegion();
|
|
if (region)
|
|
{
|
|
S32 max_tasks_per_region = (S32)region->getMaxTasks();
|
|
total_capacity = llmin(total_capacity, max_tasks_per_region);
|
|
}
|
|
std::string remaining_capacity_str = "";
|
|
|
|
if (gMeshRepo.meshRezEnabled())
|
|
{
|
|
LLStringUtil::format_map_t remaining_capacity_args;
|
|
remaining_capacity_args["LAND_CAPACITY"] = llformat("%d", total_capacity - rezzed_prims);
|
|
remaining_capacity_str = getString("status_remaining_capacity", remaining_capacity_args);
|
|
}
|
|
|
|
childSetTextArg("more info label", "[CAPACITY_STRING]", remaining_capacity_str);
|
|
// </FS:Ansariel>
|
|
|
|
// Update land impacts info in the weights floater
|
|
LLFloaterObjectWeights* object_weights_floater = LLFloaterReg::findTypedInstance<LLFloaterObjectWeights>("object_weights");
|
|
if(object_weights_floater)
|
|
{
|
|
object_weights_floater->updateLandImpacts(parcel);
|
|
}
|
|
}
|
|
|
|
struct LLFloaterToolsCopyKeysFunctor : public LLSelectedObjectFunctor
|
|
{
|
|
LLFloaterToolsCopyKeysFunctor(std::string& strOut, std::string& strSep) : mOutput(strOut), mSep(strSep) {}
|
|
virtual bool apply(LLViewerObject* object)
|
|
{
|
|
if (!mOutput.empty())
|
|
mOutput.append(mSep);
|
|
|
|
mOutput.append(object->getID().asString());
|
|
|
|
return true;
|
|
}
|
|
private:
|
|
std::string& mOutput;
|
|
std::string& mSep;
|
|
};
|
|
|
|
void LLFloaterTools::onClickBtnCopyKeys()
|
|
{
|
|
std::string separator = gSavedSettings.getString("FSCopyObjKeySeparator");
|
|
std::string stringKeys;
|
|
MASK mask = gKeyboard->currentMask(FALSE);
|
|
LLFloaterToolsCopyKeysFunctor copy_keys(stringKeys, separator);
|
|
bool copied = false;
|
|
if (mask == MASK_SHIFT)
|
|
copied = LLSelectMgr::getInstance()->getSelection()->applyToObjects(©_keys);
|
|
else if (mCheckSelectIndividual && mCheckSelectIndividual->get())
|
|
copied = LLSelectMgr::getInstance()->getSelection()->applyToObjects(©_keys);
|
|
else
|
|
copied = LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(©_keys);
|
|
|
|
if (copied)
|
|
{
|
|
LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(stringKeys));
|
|
}
|
|
}
|
|
|
|
void LLFloaterTools::onClickExpand()
|
|
{
|
|
BOOL show_more = !gSavedSettings.getBOOL("FSToolboxExpanded");
|
|
gSavedSettings.setBOOL("FSToolboxExpanded", show_more);
|
|
|
|
LLButton* btnExpand = getChild<LLButton>("btnExpand");
|
|
if (show_more)
|
|
{
|
|
mTab->setVisible(TRUE);
|
|
reshape(getRect().getWidth(), mExpandedHeight);
|
|
translate(0, mCollapsedHeight - mExpandedHeight);
|
|
btnExpand->setImageOverlay("Arrow_Up", btnExpand->getImageOverlayHAlign());
|
|
}
|
|
else
|
|
{
|
|
mTab->setVisible(FALSE);
|
|
reshape(getRect().getWidth(), mCollapsedHeight);
|
|
translate(0, mExpandedHeight - mCollapsedHeight);
|
|
btnExpand->setImageOverlay("Arrow_Down", btnExpand->getImageOverlayHAlign());
|
|
}
|
|
}
|
|
|
|
// <FS:Ansariel> FIRE-7802: Grass and tree selection in build tool
|
|
template<class P>
|
|
void build_plant_combo(const std::map<U32, P*>& list, LLComboBox* combo)
|
|
{
|
|
if (!combo || list.empty()) return;
|
|
combo->removeall();
|
|
typename std::map<U32, P*>::const_iterator it = list.begin();
|
|
typename std::map<U32, P*>::const_iterator end = list.end();
|
|
for (; it != end; ++it)
|
|
{
|
|
P* plant = (*it).second;
|
|
if (plant) combo->addSimpleElement(plant->mName, ADD_BOTTOM);
|
|
}
|
|
}
|
|
|
|
void LLFloaterTools::buildTreeGrassCombo()
|
|
{
|
|
if (!mTreeGrassCombo) return;
|
|
|
|
// Rebuild the combo with the list we need, then select the last-known use
|
|
// TODO: rebuilding this list continuously is probably not the best way
|
|
LLPCode pcode = LLToolPlacer::getObjectType();
|
|
std::string type = LLStringUtil::null;
|
|
|
|
// LL_PCODE_TREE_NEW seems to be "new" as in "dodo"
|
|
switch (pcode)
|
|
{
|
|
case LL_PCODE_LEGACY_TREE:
|
|
case LL_PCODE_TREE_NEW:
|
|
build_plant_combo(LLVOTree::sSpeciesTable, mTreeGrassCombo);
|
|
mTreeGrassCombo->addSimpleElement("Random", ADD_TOP);
|
|
type = "Tree";
|
|
break;
|
|
case LL_PCODE_LEGACY_GRASS:
|
|
build_plant_combo(LLVOGrass::sSpeciesTable, mTreeGrassCombo);
|
|
mTreeGrassCombo->addSimpleElement("Random", ADD_TOP);
|
|
type = "Grass";
|
|
break;
|
|
default:
|
|
mTreeGrassCombo->setEnabled(false);
|
|
break;
|
|
}
|
|
|
|
// select last selected if exists
|
|
if (!type.empty())
|
|
{
|
|
// Enable the options
|
|
mTreeGrassCombo->setEnabled(true);
|
|
|
|
// Set the last selection, or "Random" (old default) if there isn't one
|
|
std::string last_selected = gSavedSettings.getString("LastSelected" + type);
|
|
if (last_selected.empty())
|
|
{
|
|
mTreeGrassCombo->selectByValue(LLSD(std::string("Random")));
|
|
}
|
|
else
|
|
{
|
|
mTreeGrassCombo->selectByValue(LLSD(last_selected));
|
|
}
|
|
}
|
|
}
|
|
|
|
void LLFloaterTools::onSelectTreeGrassCombo()
|
|
{
|
|
// Save the last-used selection
|
|
std::string last_selected = mTreeGrassCombo->getValue().asString();
|
|
LLPCode pcode = LLToolPlacer::getObjectType();
|
|
std::string type = "";
|
|
|
|
switch (pcode)
|
|
{
|
|
case LL_PCODE_LEGACY_GRASS:
|
|
type = "Grass";
|
|
break;
|
|
case LL_PCODE_LEGACY_TREE:
|
|
case LL_PCODE_TREE_NEW:
|
|
type = "Tree";
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (!type.empty())
|
|
{
|
|
// Should never be an empty string
|
|
gSavedSettings.setString("LastSelected" + type, last_selected);
|
|
}
|
|
}
|
|
// </FS:Ansariel>
|