mirror of
https://github.com/copyrighttxt/watrbx-game-engine.git
synced 2026-09-04 20:57:49 +00:00
1309 lines
35 KiB
C++
1309 lines
35 KiB
C++
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
|
#include "stdafx.h"
|
|
|
|
#include "V8DataModel/Commands.h"
|
|
#include "V8DataModel/Workspace.h"
|
|
#include "V8DataModel/PartInstance.h"
|
|
#include "V8DataModel/Camera.h"
|
|
#include "V8DataModel/Backpack.h"
|
|
#include "V8DataModel/Feature.h"
|
|
#include "V8DataModel/changehistory.h"
|
|
#include "V8DataModel/MegaCluster.h"
|
|
#include "V8DataModel/ToolsModel.h"
|
|
#include "Humanoid/Humanoid.h"
|
|
#include "Network/Players.h"
|
|
#include "Tool/MegaDragger.h"
|
|
#include "V8World/World.h"
|
|
#include "V8Xml/Serializer.h"
|
|
#include "V8Xml/SerializerBinary.h"
|
|
#include "Util/SoundService.h"
|
|
#include "Util/profiling.h"
|
|
#include "V8World/ContactManager.h"
|
|
#include "V8DataModel/CSGDictionaryService.h"
|
|
#include "Script/LuaSourceContainer.h"
|
|
|
|
FASTFLAG(DebugDisplayFPS)
|
|
|
|
FASTFLAG(UserAllCamerasInLua)
|
|
|
|
namespace RBX {
|
|
|
|
BoolPropertyVerb::BoolPropertyVerb(
|
|
const std::string& name,
|
|
DataModel* dataModel,
|
|
const char* propertyName ) :
|
|
EditSelectionVerb(name, dataModel),
|
|
propertyName(Name::declare(propertyName))
|
|
{}
|
|
|
|
|
|
static bool HasTrueProperty(const char* propertyName, shared_ptr<Instance> instance)
|
|
{
|
|
if (Reflection::PropertyDescriptor* desc = instance->findPropertyDescriptor(propertyName))
|
|
{
|
|
Reflection::Property prop(*desc, instance.get());
|
|
if (prop.isValueType<bool>())
|
|
if (prop.getValue<bool>())
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
bool BoolPropertyVerb::isChecked() const
|
|
{
|
|
return std::find_if(
|
|
selection->begin(),
|
|
selection->end(),
|
|
boost::bind(&HasTrueProperty, propertyName.c_str(), _1)
|
|
)!=selection->end();
|
|
}
|
|
|
|
|
|
|
|
class BoolPropertyVerbSetIt
|
|
{
|
|
const Name& propertyName;
|
|
bool newState;
|
|
public:
|
|
BoolPropertyVerbSetIt(const Name& propertyName, bool newState)
|
|
: propertyName(propertyName)
|
|
, newState(newState)
|
|
{}
|
|
void operator()(shared_ptr<Instance> instance)
|
|
{
|
|
if (Reflection::PropertyDescriptor* desc = instance->findPropertyDescriptor(propertyName.c_str()))
|
|
{
|
|
Reflection::Property prop(*desc, instance.get());
|
|
if (prop.isValueType<bool>() && prop.getValue<bool>()!=newState)
|
|
{
|
|
prop.setValue(newState);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
|
|
void BoolPropertyVerb::doIt(IDataState* dataState)
|
|
{
|
|
// TODO: refactor using boost::bind
|
|
BoolPropertyVerbSetIt setIt(propertyName, !isChecked());
|
|
std::for_each(selection->begin(), selection->end(), setIt);
|
|
|
|
{
|
|
DataModel::LegacyLock lock(dataModel, DataModelJob::Write);
|
|
ChangeHistoryService::requestWaypoint(propertyName.c_str(), dataModel);
|
|
}
|
|
|
|
dataState->setDirty(true);
|
|
}
|
|
|
|
CameraCenterCommand::CameraCenterCommand(Workspace* workspace) : CameraVerb("CameraCenter", workspace)
|
|
{
|
|
// Force creation here, so that we don't create a service in isEnabled
|
|
ServiceProvider::create< FilteredSelection<PVInstance> >(workspace);
|
|
}
|
|
|
|
// TODO:: consolidate this with other camera enabled stuff
|
|
bool CameraCenterCommand::isEnabled() const
|
|
{
|
|
if (ServiceClient< FilteredSelection<PVInstance> >(workspace)->size() >= 1) {
|
|
const Camera* worldCamera = workspace->getConstCamera();
|
|
RBXASSERT(worldCamera);
|
|
if (worldCamera) {
|
|
if (worldCamera->getCameraType() == Camera::FIXED_CAMERA) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
void CameraCenterCommand::doIt(IDataState* dataState)
|
|
{
|
|
FASTLOG(FLog::Verbs, "Gui:CameraCenter");
|
|
|
|
RBXASSERT(isEnabled());
|
|
|
|
Vector3 center;
|
|
|
|
ServiceClient< FilteredSelection<PVInstance> > sel(workspace);
|
|
bool hasFocalObject = sel->size() >= 1;
|
|
|
|
if (hasFocalObject) {
|
|
const std::vector<PVInstance*>& items(sel->items());
|
|
Extents extents = items[0]->computeExtentsWorld();
|
|
for (size_t i = 1; i < items.size(); ++i) {
|
|
extents.unionWith(items[i]->computeExtentsWorld());
|
|
}
|
|
center = extents.center();
|
|
}
|
|
else {
|
|
center = Vector3::zero();
|
|
}
|
|
|
|
workspace->getCamera()->setCameraType(Camera::FIXED_CAMERA);
|
|
workspace->getCamera()->setCameraFocusAndMaintainFocus(center, hasFocalObject);
|
|
CameraVerb::doIt(dataState);
|
|
|
|
// TODO: Undo/Redo
|
|
dataState->setDirty(true);
|
|
}
|
|
|
|
|
|
void SelectAllCommand::doIt(IDataState* dataState)
|
|
{
|
|
FASTLOG(FLog::Verbs, "Gui:SelectAll");
|
|
|
|
dataModel->getWorkspace()->selectAllTopLevelRenderable();
|
|
}
|
|
|
|
void AllCanSelectCommand::doIt(IDataState* dataState)
|
|
{
|
|
Workspace* workspace = dataModel->getWorkspace();
|
|
PartInstance::setLocked(workspace, false); // complete traversal
|
|
|
|
// TODO: Undo/Redo
|
|
{
|
|
DataModel::LegacyLock lock(dataModel, DataModelJob::Write);
|
|
ChangeHistoryService::requestWaypoint(getName().c_str(), workspace);
|
|
}
|
|
|
|
dataState->setDirty(true);
|
|
}
|
|
|
|
static void SetCanNotSelect(shared_ptr<Instance> pv)
|
|
{
|
|
PartInstance::setLocked(pv.get(), true);
|
|
}
|
|
|
|
void CanNotSelectCommand::doIt(IDataState* dataState)
|
|
{
|
|
FilteredSelection<PVInstance>* sel = ServiceProvider::create< FilteredSelection<PVInstance> >(dataModel);
|
|
std::for_each(selection->begin(), selection->end(), SetCanNotSelect);
|
|
|
|
sel->clearSelection();
|
|
|
|
// TODO: Undo/Redo
|
|
{
|
|
DataModel::LegacyLock lock(dataModel, DataModelJob::Write);
|
|
ChangeHistoryService::requestWaypoint(getName().c_str(), workspace.get());
|
|
}
|
|
|
|
dataState->setDirty(true);
|
|
}
|
|
|
|
std::string ChatMenuCommand::getChatString(int menu1, int menu2, int menu3)
|
|
{
|
|
return "Chat_" + StringConverter<int>::convertToString(menu1)
|
|
+ "_" + StringConverter<int>::convertToString(menu2)
|
|
+ "_" + StringConverter<int>::convertToString(menu3);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////
|
|
|
|
FirstPersonCommand::FirstPersonCommand(DataModel* dataModel)
|
|
: Verb(dataModel, "FirstPersonIndicator")
|
|
, dataModel(dataModel)
|
|
{
|
|
}
|
|
|
|
bool FirstPersonCommand::isEnabled() const
|
|
{
|
|
if (Humanoid* h = Humanoid::getLocalHumanoidFromContext(dataModel)) {
|
|
return h->isFirstPerson();
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
ToggleViewMode::ToggleViewMode(RBX::DataModel* dm)
|
|
: Verb(dm, "ToggleViewMode")
|
|
, dataModel(dm)
|
|
{
|
|
}
|
|
|
|
bool ToggleViewMode::isChecked() const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool ToggleViewMode::isEnabled() const
|
|
{
|
|
return dataModel->getNumPlayers() > 0;
|
|
}
|
|
|
|
bool ToggleViewMode::isSelected() const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
void ToggleViewMode::doIt(RBX::IDataState* dataState)
|
|
{
|
|
FASTLOG(FLog::Verbs, "Gui:ToggleViewMode");
|
|
}
|
|
|
|
/////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////
|
|
|
|
StatsCommand::StatsCommand(DataModel* dataModel) :
|
|
Verb(dataModel, "Stats"),
|
|
dataModel(dataModel)
|
|
{}
|
|
|
|
|
|
void StatsCommand::doIt(IDataState* dataState)
|
|
{
|
|
dataModel->getGuiBuilder().toggleGeneralStats();
|
|
}
|
|
|
|
bool StatsCommand::isEnabled() const
|
|
{
|
|
GuiRoot* guiRoot = dataModel->getGuiRoot();
|
|
return Instance::fastDynamicCast<TopMenuBar>(guiRoot->findFirstChildByName("StatsHud1"))!=NULL;
|
|
}
|
|
|
|
bool StatsCommand::isChecked() const
|
|
{
|
|
GuiRoot* guiRoot = dataModel->getGuiRoot();
|
|
const TopMenuBar* statsMenu = Instance::fastDynamicCast<TopMenuBar>(guiRoot->findFirstChildByName("StatsHud1"));
|
|
return statsMenu!=NULL && statsMenu->isVisible();
|
|
}
|
|
|
|
|
|
RenderStatsCommand::RenderStatsCommand(DataModel* dataModel) :
|
|
Verb(dataModel, "RenderStats"),
|
|
dataModel(dataModel)
|
|
{}
|
|
|
|
|
|
void RenderStatsCommand::doIt(IDataState* dataState)
|
|
{
|
|
dataModel->getGuiBuilder().toggleRenderStats();
|
|
}
|
|
|
|
bool RenderStatsCommand::isEnabled() const
|
|
{
|
|
GuiRoot* guiRoot = dataModel->getGuiRoot();
|
|
return Instance::fastDynamicCast<TopMenuBar>(guiRoot->findFirstChildByName("StatsHud1"))!=NULL;
|
|
}
|
|
|
|
bool RenderStatsCommand::isChecked() const
|
|
{
|
|
GuiRoot* guiRoot = dataModel->getGuiRoot();
|
|
const TopMenuBar* statsMenu = Instance::fastDynamicCast<TopMenuBar>(guiRoot->findFirstChildByName("RenderStats"));
|
|
return statsMenu!=NULL && statsMenu->isVisible();
|
|
}
|
|
|
|
|
|
SummaryStatsCommand::SummaryStatsCommand(DataModel* dataModel) :
|
|
Verb(dataModel, "SummaryStats"),
|
|
dataModel(dataModel)
|
|
{}
|
|
|
|
void SummaryStatsCommand::doIt(IDataState* dataState)
|
|
{
|
|
dataModel->getGuiBuilder().toggleSummaryStats();
|
|
}
|
|
|
|
bool SummaryStatsCommand::isEnabled() const
|
|
{
|
|
GuiRoot* guiRoot = dataModel->getGuiRoot();
|
|
return Instance::fastDynamicCast<TopMenuBar>(guiRoot->findFirstChildByName("SummaryStats"))!=NULL;
|
|
}
|
|
|
|
bool SummaryStatsCommand::isChecked() const
|
|
{
|
|
GuiRoot* guiRoot = dataModel->getGuiRoot();
|
|
const TopMenuBar* statsMenu = Instance::fastDynamicCast<TopMenuBar>(guiRoot->findFirstChildByName("SummaryStats"));
|
|
return statsMenu!=NULL && statsMenu->isVisible();
|
|
}
|
|
|
|
|
|
CustomStatsCommand::CustomStatsCommand(DataModel* dataModel) :
|
|
Verb(dataModel, "CustomStats"),
|
|
dataModel(dataModel)
|
|
{}
|
|
|
|
void CustomStatsCommand::doIt(IDataState* dataState)
|
|
{
|
|
dataModel->getGuiBuilder().toggleCustomStats();
|
|
}
|
|
|
|
bool CustomStatsCommand::isEnabled() const
|
|
{
|
|
GuiRoot* guiRoot = dataModel->getGuiRoot();
|
|
return Instance::fastDynamicCast<TopMenuBar>(guiRoot->findFirstChildByName("CustomStats"))!=NULL;
|
|
}
|
|
|
|
bool CustomStatsCommand::isChecked() const
|
|
{
|
|
GuiRoot* guiRoot = dataModel->getGuiRoot();
|
|
const TopMenuBar* statsMenu = Instance::fastDynamicCast<TopMenuBar>(guiRoot->findFirstChildByName("CustomStats"));
|
|
return statsMenu!=NULL && statsMenu->isVisible();
|
|
}
|
|
|
|
|
|
NetworkStatsCommand::NetworkStatsCommand(DataModel* dataModel) :
|
|
Verb(dataModel, "NetworkStats"),
|
|
dataModel(dataModel)
|
|
{
|
|
}
|
|
|
|
|
|
void NetworkStatsCommand::doIt(IDataState* dataState)
|
|
{
|
|
dataModel->getGuiBuilder().toggleNetworkStats();
|
|
}
|
|
|
|
bool NetworkStatsCommand::isEnabled() const
|
|
{
|
|
GuiRoot* guiRoot = dataModel->getGuiRoot();
|
|
return Instance::fastDynamicCast<TopMenuBar>(guiRoot->findFirstChildByName("NetworkStats"))!=NULL;
|
|
}
|
|
|
|
bool NetworkStatsCommand::isChecked() const
|
|
{
|
|
GuiRoot* guiRoot = dataModel->getGuiRoot();
|
|
const TopMenuBar* statsMenu = Instance::fastDynamicCast<TopMenuBar>(guiRoot->findFirstChildByName("NetworkStats"));
|
|
return statsMenu!=NULL && statsMenu->isVisible();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
PhysicsStatsCommand::PhysicsStatsCommand(DataModel* dataModel) :
|
|
Verb(dataModel, "PhysicsStats"),
|
|
dataModel(dataModel)
|
|
{}
|
|
|
|
void PhysicsStatsCommand::doIt(IDataState* dataState)
|
|
{
|
|
dataModel->getGuiBuilder().togglePhysicsStats();
|
|
}
|
|
|
|
bool PhysicsStatsCommand::isEnabled() const
|
|
{
|
|
GuiRoot* guiRoot = dataModel->getGuiRoot();
|
|
return Instance::fastDynamicCast<TopMenuBar>(guiRoot->findFirstChildByName("PhysicsStats")) != NULL ||
|
|
Instance::fastDynamicCast<TopMenuBar>(guiRoot->findFirstChildByName("PhysicsStats2")) != NULL;
|
|
}
|
|
|
|
bool PhysicsStatsCommand::isChecked() const
|
|
{
|
|
GuiRoot* guiRoot = dataModel->getGuiRoot();
|
|
const TopMenuBar* statsMenu = Instance::fastDynamicCast<TopMenuBar>(guiRoot->findFirstChildByName("PhysicsStats"));
|
|
if ( statsMenu != NULL && statsMenu->isVisible() )
|
|
return true;
|
|
|
|
statsMenu = Instance::fastDynamicCast<TopMenuBar>(guiRoot->findFirstChildByName("PhysicsStats2"));
|
|
if ( statsMenu != NULL && statsMenu->isVisible() )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
EngineStatsCommand::EngineStatsCommand(DataModel* dataModel) :
|
|
Verb(dataModel, "EngineStats")
|
|
, dataModel(dataModel)
|
|
{}
|
|
|
|
|
|
void EngineStatsCommand::doIt(IDataState* dataState)
|
|
{
|
|
FASTLOG(FLog::Verbs, "Gui:EngineStats");
|
|
|
|
// dataModel->getWorkspace()->getWorld()->getContactManager().getSpatialHash().doStats();
|
|
dataModel->getWorkspace()->getWorld()->getContactManager()->doStats();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
JoinCommand::JoinCommand(DataModel* dataModel)
|
|
: Verb(dataModel, "JoinCommand")
|
|
, dataModel(dataModel)
|
|
{}
|
|
|
|
bool JoinCommand::isEnabled() const
|
|
{
|
|
Selection* sel = ServiceProvider::find< Selection >(dataModel);
|
|
if (sel && sel->size() == 2)
|
|
{
|
|
shared_ptr<Instance> i0 = sel->front();
|
|
shared_ptr<Instance> i1 = sel->back();
|
|
if (MotorFeature::canJoin(i0.get(), i1.get()))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void JoinCommand::doIt(IDataState* dataState)
|
|
{
|
|
FASTLOG(FLog::Verbs, "Gui:JoinCommand");
|
|
|
|
Selection* sel = ServiceProvider::create< Selection >(dataModel);
|
|
if (sel->size() == 2)
|
|
{
|
|
shared_ptr<Instance> i0 = sel->front();
|
|
shared_ptr<Instance> i1 = sel->back();
|
|
MotorFeature::join(i0.get(), i1.get());
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
RunStateVerb::RunStateVerb(std::string name, DataModel* dataModel, bool blacklisted) :
|
|
Verb(dataModel, name, blacklisted),
|
|
dataModel(dataModel),
|
|
runService(dataModel)
|
|
{
|
|
}
|
|
|
|
RunStateVerb::~RunStateVerb()
|
|
{
|
|
}
|
|
|
|
void RunStateVerb::playActionSound()
|
|
{
|
|
}
|
|
|
|
bool RunCommand::isEnabled() const
|
|
{
|
|
RunState runState = runService->getRunState();
|
|
bool clientIsPresent = RBX::Network::Players::clientIsPresent(dataModel);
|
|
|
|
return (!clientIsPresent && (runState != RS_RUNNING));
|
|
}
|
|
|
|
void RunCommand::doIt(IDataState* dataState)
|
|
{
|
|
FASTLOG(FLog::Verbs, "Gui:Run");
|
|
|
|
RBXASSERT(isEnabled());
|
|
runService->run();
|
|
}
|
|
|
|
bool StopCommand::isEnabled() const
|
|
{
|
|
RunState runState = runService->getRunState();
|
|
return (runState == RS_RUNNING);
|
|
}
|
|
|
|
void StopCommand::doIt(IDataState* dataState)
|
|
{
|
|
FASTLOG(FLog::Verbs, "Gui:Stop");
|
|
|
|
RBXASSERT(isEnabled());
|
|
runService->pause();
|
|
}
|
|
|
|
bool ResetCommand::isEnabled() const
|
|
{
|
|
RunState runState = runService->getRunState();
|
|
|
|
return ( (runState == RS_RUNNING || runState == RS_PAUSED)
|
|
&& !RBX::Network::Players::findLocalPlayer(dataModel) );
|
|
}
|
|
|
|
void ResetCommand::doIt(IDataState* dataState)
|
|
{
|
|
FASTLOG(FLog::Verbs, "Gui:Reset");
|
|
|
|
RBXASSERT(isEnabled());
|
|
runService->stop();
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////
|
|
|
|
EditSelectionVerb::EditSelectionVerb(std::string name, DataModel* dataModel)
|
|
:Verb(dataModel, name)
|
|
,dataModel(dataModel)
|
|
,workspace(shared_from(dataModel->getWorkspace()))
|
|
,selection(dataModel)
|
|
{
|
|
}
|
|
|
|
EditSelectionVerb::EditSelectionVerb(VerbContainer* container, std::string name, DataModel* dataModel)
|
|
:Verb(container, name)
|
|
,dataModel(dataModel)
|
|
,workspace(shared_from(ServiceProvider::find<Workspace>(dataModel)))
|
|
,selection(dataModel)
|
|
{
|
|
RBXASSERT(workspace!=NULL);
|
|
}
|
|
|
|
EditSelectionVerb::~EditSelectionVerb()
|
|
{
|
|
}
|
|
|
|
bool EditSelectionVerb::isEnabled() const
|
|
{
|
|
return selection->size()>0;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
template<SurfaceType from, SurfaceType to>
|
|
static void SurfaceSwap(shared_ptr<Instance> instance)
|
|
{
|
|
if (PartInstance* part = Instance::fastDynamicCast<PartInstance>(instance.get())) {
|
|
for (int i = 0; i < 6; ++i) {
|
|
if (part->getSurfaceType(NormalId(i)) == from) {
|
|
part->setSurfaceType(NormalId(i), to);
|
|
}
|
|
}
|
|
}
|
|
if (instance->getChildren())
|
|
std::for_each(
|
|
instance->getChildren()->begin(),
|
|
instance->getChildren()->end(),
|
|
boost::bind(&SurfaceSwap<from, to>, _1)
|
|
);
|
|
}
|
|
|
|
SnapSelectionVerb::SnapSelectionVerb(DataModel* dataModel) :
|
|
EditSelectionVerb("SnapSelection", dataModel)
|
|
{;}
|
|
|
|
|
|
bool SnapSelectionVerb::isEnabled() const
|
|
{
|
|
if (!Super::isEnabled())
|
|
return false;
|
|
Selection* sel = ServiceProvider::find< Selection >(dataModel);
|
|
return (sel && sel->size() > 0);
|
|
}
|
|
|
|
void SnapSelectionVerb::doIt(IDataState* dataState)
|
|
{
|
|
FASTLOG(FLog::Verbs, "Gui:SnapSelection");
|
|
|
|
ServiceProvider::create< Selection >(dataModel);
|
|
std::for_each(selection->begin(), selection->end(), boost::bind(&SurfaceSwap<WELD, STUDS>, _1));
|
|
|
|
// TODO: Undo/Redo...
|
|
{
|
|
DataModel::LegacyLock lock(dataModel, DataModelJob::Write);
|
|
ChangeHistoryService::requestWaypoint(getName().c_str(), workspace.get());
|
|
}
|
|
|
|
dataState->setDirty(true);
|
|
}
|
|
|
|
void UnlockAllVerb::doIt(IDataState* dataState)
|
|
{
|
|
Workspace* workspace = dataModel->getWorkspace();
|
|
PartInstance::setLocked(workspace, false); // complete traversal
|
|
|
|
// TODO: Undo/Redo
|
|
{
|
|
DataModel::LegacyLock lock(dataModel, DataModelJob::Write);
|
|
ChangeHistoryService::requestWaypoint(getName().c_str(), workspace);
|
|
}
|
|
|
|
dataState->setDirty(true);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////
|
|
|
|
SelectChildrenVerb::SelectChildrenVerb(DataModel* dataModel) :
|
|
EditSelectionVerb("SelectChildrenOfSelection", dataModel)
|
|
{
|
|
ServiceProvider::create<FilteredSelection<Instance> >(dataModel);
|
|
}
|
|
|
|
bool hasChildren(Instance* wInstance)
|
|
{
|
|
return (wInstance->numChildren() > 0);
|
|
}
|
|
|
|
bool SelectChildrenVerb::isEnabled() const
|
|
{
|
|
if(!Super::isEnabled())
|
|
return false;
|
|
|
|
FilteredSelection<Instance>* selection = ServiceProvider::find<FilteredSelection<Instance> >(dataModel);
|
|
return selection && selection->find_if(hasChildren)!=NULL;
|
|
}
|
|
|
|
void SelectChildrenVerb::doIt(IDataState *dataState)
|
|
{
|
|
FASTLOG(FLog::Verbs, "Gui:SelectChildrenOfSelection");
|
|
|
|
Selection* selection = ServiceProvider::find<Selection>(dataModel);
|
|
|
|
shared_ptr<RBX::Instances> childItems(new Instances);
|
|
|
|
if (shared_ptr<const Instances> parentItems = selection->getSelection2())
|
|
for (std::vector<shared_ptr<Instance> >::const_iterator parentIterator = parentItems->begin(); parentIterator != parentItems->end(); ++parentIterator)
|
|
if (shared_ptr<const Instances> children = (*parentIterator)->getChildren2())
|
|
for (Instances::const_iterator childIterator = children->begin(); childIterator != children->end(); ++childIterator)
|
|
childItems->push_back(*childIterator);
|
|
|
|
if(childItems->size() > 0)
|
|
selection->setSelection(childItems);
|
|
else
|
|
debugAssertM(0, "Calling SelectChildrenOfSelection command without checking is-enabled");
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
///////////////////////////////////////////////////////////////
|
|
|
|
void AddChildToRoot(XmlElement* root, shared_ptr<Instance> wsi, const boost::function<bool(Instance*)>& isInScope, RBX::CreatorRole creatorRole)
|
|
{
|
|
if (XmlElement* child = wsi->writeXml(isInScope, creatorRole))
|
|
root->addChild(child);
|
|
}
|
|
|
|
static bool isInScope(shared_ptr<Instance> selectedItem, Instance* child)
|
|
{
|
|
if (selectedItem.get() == child)
|
|
return true;
|
|
return selectedItem->isAncestorOf(child);
|
|
}
|
|
|
|
static bool isContainedInSelection(Selection* sel, Instance* instance)
|
|
{
|
|
return std::find_if(
|
|
sel->begin(), sel->end(),
|
|
boost::bind(isInScope, _1, instance))
|
|
!= sel->end();
|
|
}
|
|
|
|
void AddSelectionToRoot(XmlElement* root, Selection* selection, RBX::CreatorRole creatorRole)
|
|
{
|
|
boost::function<bool(Instance*)> scopeFunction = boost::bind(isContainedInSelection, selection, _1);
|
|
std::for_each(selection->begin(), selection->end(), boost::bind(&AddChildToRoot, root, _1, scopeFunction, creatorRole));
|
|
}
|
|
|
|
DeleteBase::DeleteBase(VerbContainer* verbContainer, DataModel* dataModel, std::string name)
|
|
: EditSelectionVerb(verbContainer, name, dataModel)
|
|
, rewardHopper(false)
|
|
{}
|
|
|
|
DeleteBase::DeleteBase(DataModel* dataModel, std::string name, bool rewardHopper)
|
|
: EditSelectionVerb(name, dataModel)
|
|
, rewardHopper(rewardHopper)
|
|
{}
|
|
|
|
static void checkForLockedScript(const shared_ptr<Instance>& descendant)
|
|
{
|
|
if (const shared_ptr<LuaSourceContainer> lsc =
|
|
Instance::fastSharedDynamicCast<LuaSourceContainer>(descendant))
|
|
{
|
|
if (Instance* editor = lsc->getCurrentEditor())
|
|
{
|
|
throw std::runtime_error(format("Cannot perform operation: %s is currently being edited by %s",
|
|
lsc->getFullName().c_str(), editor->getName().c_str()));
|
|
}
|
|
}
|
|
}
|
|
|
|
void DeleteBase::doIt(IDataState* dataState)
|
|
{
|
|
FASTLOG(FLog::Verbs, "Gui:DeleteBase");
|
|
|
|
Selection* sel = ServiceProvider::create< Selection >(dataModel);
|
|
|
|
bool isCloudEdit = Network::Players::isCloudEdit(dataModel);
|
|
|
|
if (sel->size() > 0)
|
|
{
|
|
shared_ptr<const Instances> selectionRead = sel->getSelection().read();
|
|
|
|
if (selectionRead)
|
|
{
|
|
// Check for locked scripts that would be deleted, and skip the delete if they are present
|
|
if (isCloudEdit)
|
|
{
|
|
for (const auto& instance : *selectionRead)
|
|
{
|
|
checkForLockedScript(instance);
|
|
instance->visitDescendants(boost::bind(&checkForLockedScript, _1));
|
|
}
|
|
}
|
|
sel->setSelection(shared_ptr<const Instances>());
|
|
|
|
for (Instances::const_iterator it = selectionRead->begin(); it != selectionRead->end(); ++it)
|
|
{
|
|
shared_ptr<Instance> instance = *it;
|
|
Instance* iPtr = instance.get();
|
|
if (iPtr)
|
|
{
|
|
if (!iPtr->fastDynamicCast<Workspace>() && !iPtr->fastDynamicCast<Network::Players>() && !dynamic_cast<Service*>(iPtr)
|
|
&& (!isCloudEdit || !iPtr->fastDynamicCast<Network::Player>())) {
|
|
instance->setParent(NULL);
|
|
//if camera is getting deleted then create new camera here itself (instead of Workspace::onHeartbeat) to correctly record change history
|
|
if (iPtr->fastDynamicCast<RBX::Camera>())
|
|
dataModel->getWorkspace()->replenishCamera();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
DataModel::LegacyLock lock(dataModel, DataModelJob::Write);
|
|
ChangeHistoryService::requestWaypoint(getName().c_str(), workspace.get());
|
|
}
|
|
|
|
dataState->setDirty(true);
|
|
}
|
|
}
|
|
|
|
// TODO: validate that group, followed by ungroup is completely consistent.....
|
|
void RotateAxisCommand::rotateAboutAxis(const G3D::Matrix3& rotMatrix, const std::vector<PVInstance*>& selectedInstances)
|
|
{
|
|
if (selectedInstances.empty()) {
|
|
debugAssertM(0, "Command should be disabled here");
|
|
return;
|
|
}
|
|
else {
|
|
MegaDragger megaDragger(NULL, selectedInstances, workspace.get());
|
|
megaDragger.startDragging();
|
|
megaDragger.safeRotate(rotMatrix);
|
|
megaDragger.finishDragging();
|
|
}
|
|
}
|
|
|
|
|
|
RotateSelectionVerb::RotateSelectionVerb(DataModel* dataModel) :
|
|
RotateAxisCommand("SelectionRotate", dataModel)
|
|
{;}
|
|
|
|
void RotateAxisCommand::doIt(IDataState* dataState)
|
|
{
|
|
FASTLOG(FLog::Verbs, "Gui:RotateAxis");
|
|
|
|
FilteredSelection<PVInstance>* sel = ServiceProvider::create< FilteredSelection<PVInstance> >(dataModel);
|
|
|
|
rotateAboutAxis(getRotationAxis(), sel->items());
|
|
|
|
{
|
|
DataModel::LegacyLock lock(dataModel, DataModelJob::Write);
|
|
ChangeHistoryService::requestWaypoint(getName().c_str(), dataModel);
|
|
}
|
|
|
|
dataState->setDirty(true);
|
|
}
|
|
|
|
G3D::Matrix3 RotateSelectionVerb::getRotationAxis()
|
|
{
|
|
return Math::matrixRotateY();
|
|
}
|
|
|
|
TiltSelectionVerb::TiltSelectionVerb(DataModel* dataModel) :
|
|
RotateAxisCommand("SelectionTilt", dataModel)
|
|
{;}
|
|
|
|
G3D::Matrix3 TiltSelectionVerb::getRotationAxis()
|
|
{
|
|
int currentQuadrant = Math::toYAxisQuadrant(workspace->getConstCamera()->coordinateFrame());
|
|
|
|
return Math::matrixTiltQuadrant(currentQuadrant);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
void MoveUpSelectionVerb::doIt(IDataState* dataState)
|
|
{
|
|
FASTLOG(FLog::Verbs, "Gui:MoveUpSelection");
|
|
|
|
FilteredSelection<PVInstance>* sel = ServiceProvider::create< FilteredSelection<PVInstance> >(dataModel);
|
|
|
|
if (sel->size()>0) {
|
|
MegaDragger megaDragger(NULL, sel->items(), workspace.get());
|
|
megaDragger.startDragging();
|
|
megaDragger.safeMoveNoDrop(Vector3(0.0f, moveUpHeight, 0.0f));
|
|
megaDragger.finishDragging();
|
|
|
|
{
|
|
DataModel::LegacyLock lock(dataModel, DataModelJob::Write);
|
|
ChangeHistoryService::requestWaypoint(getName().c_str(), workspace.get());
|
|
}
|
|
|
|
dataState->setDirty(true);
|
|
}
|
|
}
|
|
|
|
MoveDownSelectionVerb::MoveDownSelectionVerb(DataModel* dataModel) :
|
|
EditSelectionVerb("SelectionDown", dataModel)
|
|
{;}
|
|
|
|
void MoveDownSelectionVerb::doIt(IDataState* dataState)
|
|
{
|
|
FASTLOG(FLog::Verbs, "Gui:MoveDownSelection");
|
|
|
|
FilteredSelection<PVInstance>* sel = ServiceProvider::create< FilteredSelection<PVInstance> >(dataModel);
|
|
|
|
if (sel->size()>0) {
|
|
MegaDragger megaDragger(NULL, sel->items(), workspace.get());
|
|
megaDragger.startDragging();
|
|
megaDragger.safeMoveNoDrop(Vector3(0.0f, -1.2f, 0.0f));
|
|
megaDragger.finishDragging();
|
|
|
|
{
|
|
DataModel::LegacyLock lock(dataModel, DataModelJob::Write);
|
|
ChangeHistoryService::requestWaypoint(getName().c_str(), workspace.get());
|
|
}
|
|
|
|
dataState->setDirty(true);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
bool CharacterCommand::isEnabled() const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////
|
|
// CAMERA
|
|
|
|
CameraVerb::CameraVerb(std::string name, Workspace* _workspace)
|
|
: Verb(_workspace, name)
|
|
, workspace(_workspace)
|
|
, selection(_workspace)
|
|
{}
|
|
|
|
|
|
Camera* CameraVerb::getCamera()
|
|
{
|
|
return workspace->getCamera();
|
|
}
|
|
|
|
const Camera* CameraVerb::getCamera() const
|
|
{
|
|
return workspace->getConstCamera();
|
|
}
|
|
|
|
void CameraVerb::doIt(IDataState* dataState)
|
|
{
|
|
RBXASSERT(dataState!=NULL);
|
|
|
|
dataState->setDirty(true);
|
|
}
|
|
|
|
bool CameraPanLeftCommand::isEnabled() const {return true;}
|
|
void CameraPanLeftCommand::doIt(IDataState* dataState) {FASTLOG(FLog::Verbs, "Gui:CameraPanLeft"); getCamera()->panUnits(-1); CameraVerb::doIt(dataState);}
|
|
|
|
bool CameraPanRightCommand::isEnabled() const {return true;}
|
|
void CameraPanRightCommand::doIt(IDataState* dataState) {FASTLOG(FLog::Verbs, "Gui:CameraPanRight"); getCamera()->panUnits(1); CameraVerb::doIt(dataState);}
|
|
|
|
bool CameraTiltUpCommand::isEnabled() const {return getCamera()->canTilt(-1);}
|
|
void CameraTiltUpCommand::doIt(IDataState* dataState) {FASTLOG(FLog::Verbs, "Gui:CameraTiltUp"); if (getCamera()->tiltUnits(-1)) CameraVerb::doIt(dataState);}
|
|
|
|
bool CameraTiltDownCommand::isEnabled() const {return getCamera()->canTilt(1);}
|
|
void CameraTiltDownCommand::doIt(IDataState* dataState) {FASTLOG(FLog::Verbs, "Gui:CameraTildDown"); if (getCamera()->tiltUnits(1)) CameraVerb::doIt(dataState);}
|
|
|
|
bool CameraZoomInCommand::isEnabled() const {return getCamera()->canZoom(true);}
|
|
void CameraZoomInCommand::doIt(IDataState* dataState)
|
|
{
|
|
FASTLOG(FLog::Verbs, "Gui:CameraZoomIn");
|
|
if (getCamera()->zoom(1))
|
|
CameraVerb::doIt(dataState);
|
|
}
|
|
|
|
bool CameraZoomOutCommand::isEnabled() const {return getCamera()->canZoom(false);}
|
|
void CameraZoomOutCommand::doIt(IDataState* dataState)
|
|
{
|
|
FASTLOG(FLog::Verbs, "Gui:CameraZoomOut");
|
|
if (getCamera()->zoom(-1))
|
|
CameraVerb::doIt(dataState);
|
|
}
|
|
|
|
CameraZoomExtentsCommand::CameraZoomExtentsCommand(Workspace* workspace) : CameraVerb("CameraZoomExtents", workspace)
|
|
{
|
|
// Force creation here, so that we don't create a service in isEnabled
|
|
ServiceProvider::create< FilteredSelection<PVInstance> >(workspace);
|
|
}
|
|
|
|
// TODO:: consolidate this with other camera enabled stuff
|
|
bool CameraZoomExtentsCommand::isEnabled() const
|
|
{
|
|
|
|
if (ServiceClient< FilteredSelection<PVInstance> >(workspace)->size() >= 1)
|
|
{
|
|
const Camera* worldCamera = workspace->getConstCamera();
|
|
RBXASSERT(worldCamera);
|
|
|
|
if (!worldCamera)
|
|
return false;
|
|
|
|
if (FFlag::UserAllCamerasInLua && worldCamera->hasClientPlayer())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
RBX::Network::Players* players = ServiceProvider::create<Network::Players>(worldCamera);
|
|
|
|
// If there is a local player not in fixed camera mode, dont allow zoom extents
|
|
// Otherwise, do
|
|
if (players && !(players->getLocalPlayer() && worldCamera->getCameraType() != Camera::FIXED_CAMERA))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
void CameraZoomExtentsCommand::doIt(IDataState* dataState )
|
|
{
|
|
FASTLOG(FLog::Verbs, "Gui:CameraZoomExtents");
|
|
RBXASSERT(isEnabled());
|
|
|
|
ServiceClient< FilteredSelection<PVInstance> > sel(workspace);
|
|
|
|
Extents extents(Vector3(0,0,0), Vector3(0,0,0));
|
|
|
|
if (sel->size() >= 1)
|
|
{
|
|
const std::vector<PVInstance*>& items(sel->items());
|
|
|
|
if(MegaClusterInstance* terrain = Instance::fastDynamicCast<MegaClusterInstance>(items[0]))
|
|
{
|
|
if(terrain->getNonEmptyCellCount() > 0)
|
|
extents = items[0]->computeExtentsWorld();
|
|
}
|
|
else
|
|
extents = items[0]->computeExtentsWorld();
|
|
|
|
for (size_t i = 1; i < items.size(); ++i)
|
|
{
|
|
if(MegaClusterInstance* terrain = Instance::fastDynamicCast<MegaClusterInstance>(items[i]))
|
|
{
|
|
if(terrain->getNonEmptyCellCount() > 0)
|
|
extents.unionWith(items[i]->computeExtentsWorld());
|
|
}
|
|
else
|
|
extents.unionWith(items[i]->computeExtentsWorld());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// no selection, use old behavior
|
|
getCamera()->zoomExtents();
|
|
CameraVerb::doIt(dataState);
|
|
return;
|
|
}
|
|
|
|
if(extents != Extents(Vector3(0,0,0), Vector3(0,0,0)))
|
|
{
|
|
workspace->getCamera()->setCameraType(Camera::FIXED_CAMERA);
|
|
workspace->getCamera()->zoomExtents(extents, Camera::ZOOM_IN_OR_OUT);
|
|
CameraVerb::doIt(dataState);
|
|
|
|
ChangeHistoryService::requestWaypoint(getName().c_str(), workspace);
|
|
dataState->setDirty(true);
|
|
}
|
|
}
|
|
|
|
|
|
// Video recording code moved to GUI
|
|
|
|
|
|
TurnOnManualJointCreation::TurnOnManualJointCreation(DataModel* dataModel)
|
|
: Verb(dataModel, "TurnOnManualJointCreation")
|
|
, dataModel(dataModel)
|
|
{
|
|
}
|
|
|
|
void TurnOnManualJointCreation::doIt(IDataState* dataState)
|
|
{
|
|
if(AdvArrowTool::advManualJointMode)
|
|
{
|
|
FASTLOG(FLog::Verbs, "Gui:TurnOffManualJointCreation");
|
|
AdvArrowTool::advManualJointMode = false;
|
|
}
|
|
else
|
|
{
|
|
FASTLOG(FLog::Verbs, "Gui:TurnOnManualJointCreation");
|
|
AdvArrowTool::advManualJointMode = true;
|
|
}
|
|
|
|
AdvArrowTool::advCreateJointsMode = true;
|
|
}
|
|
|
|
SetDragGridToOne::SetDragGridToOne(DataModel* dataModel)
|
|
: Verb(dataModel, "SetDragGridToOne")
|
|
, dataModel(dataModel)
|
|
{
|
|
}
|
|
|
|
SetDragGridToOneFifth::SetDragGridToOneFifth(DataModel* dataModel)
|
|
: Verb(dataModel, "SetDragGridToOneFifth")
|
|
, dataModel(dataModel)
|
|
{
|
|
}
|
|
|
|
SetDragGridToOff::SetDragGridToOff(DataModel* dataModel)
|
|
: Verb(dataModel, "SetDragGridToOff")
|
|
, dataModel(dataModel)
|
|
{
|
|
}
|
|
|
|
SetGridSizeToTwo::SetGridSizeToTwo(DataModel* dataModel)
|
|
: Verb(dataModel, "SetGridSizeToTwo")
|
|
, workspace(dataModel->getWorkspace())
|
|
{
|
|
}
|
|
|
|
SetGridSizeToFour::SetGridSizeToFour(DataModel* dataModel)
|
|
: Verb(dataModel, "SetGridSizeToFour")
|
|
, workspace(dataModel->getWorkspace())
|
|
{
|
|
}
|
|
|
|
SetGridSizeToSixteen::SetGridSizeToSixteen(DataModel* dataModel)
|
|
: Verb(dataModel, "SetGridSizeToSixteen")
|
|
, workspace(dataModel->getWorkspace())
|
|
{
|
|
}
|
|
|
|
SetManualJointToWeak::SetManualJointToWeak(DataModel* dataModel)
|
|
: Verb(dataModel, "SetManualJointToWeak")
|
|
, dataModel(dataModel)
|
|
{
|
|
}
|
|
|
|
SetManualJointToStrong::SetManualJointToStrong(DataModel* dataModel)
|
|
: Verb(dataModel, "SetManualJointToStrong")
|
|
, dataModel(dataModel)
|
|
{
|
|
}
|
|
|
|
SetManualJointToInfinite::SetManualJointToInfinite(DataModel* dataModel)
|
|
: Verb(dataModel, "SetManualJointToInfinite")
|
|
, dataModel(dataModel)
|
|
{
|
|
}
|
|
|
|
bool applyColor(Instance* instance, RBX::BrickColor color)
|
|
{
|
|
bool applied = false;
|
|
if (PartInstance* pInstance = dynamic_cast<PartInstance*>(instance))
|
|
{
|
|
pInstance->setColor(color);
|
|
applied = true;
|
|
}
|
|
else if (ModelInstance* pModelInstance = dynamic_cast<ModelInstance*>(instance))
|
|
{
|
|
std::vector<PartInstance*> childParts = pModelInstance->getDescendantPartInstances();
|
|
for (std::vector<PartInstance*>::const_iterator iter = childParts.begin(); iter != childParts.end(); ++iter)
|
|
{
|
|
applied |= applyColor(*iter, color);
|
|
}
|
|
}
|
|
return applied;
|
|
}
|
|
|
|
RBX::BrickColor ColorVerb::m_currentColor = RBX::BrickColor::brick_194;
|
|
void ColorVerb::doIt( IDataState* dataState )
|
|
{
|
|
bool applied = false;
|
|
FilteredSelection<Instance>* sel = ServiceProvider::create< FilteredSelection<Instance> >(dataModel);
|
|
for (std::vector<Instance*>::const_iterator iter = sel->begin(); iter != sel->end(); ++iter)
|
|
applied |= applyColor(*iter, ColorVerb::getCurrentColor());
|
|
|
|
{
|
|
DataModel::LegacyLock lock(dataModel, DataModelJob::Write);
|
|
ChangeHistoryService::requestWaypoint(getName().c_str(), workspace.get());
|
|
}
|
|
|
|
dataState->setDirty(true);
|
|
}
|
|
|
|
bool applyMaterial(Instance* instance, PartMaterial material)
|
|
{
|
|
bool applied = false;
|
|
if (PartInstance* pInstance = dynamic_cast<PartInstance*>(instance))
|
|
{
|
|
pInstance->setRenderMaterial(material);
|
|
applied = true;
|
|
}
|
|
else if (ModelInstance* pModelInstance = dynamic_cast<ModelInstance*>(instance))
|
|
{
|
|
std::vector<PartInstance*> childParts = pModelInstance->getDescendantPartInstances();
|
|
for (std::vector<PartInstance*>::const_iterator iter = childParts.begin(); iter != childParts.end(); ++iter)
|
|
{
|
|
applied |= applyMaterial(*iter, material);
|
|
}
|
|
}
|
|
return applied;
|
|
}
|
|
PartMaterial MaterialVerb::m_currentMaterial = PLASTIC_MATERIAL;
|
|
void MaterialVerb::doIt( IDataState* dataState )
|
|
{
|
|
bool applied = false;
|
|
FilteredSelection<Instance>* sel = ServiceProvider::create< FilteredSelection<Instance> >(dataModel);
|
|
for (std::vector<Instance*>::const_iterator iter = sel->begin(); iter != sel->end(); ++iter)
|
|
applied |= applyMaterial(*iter, MaterialVerb::getCurrentMaterial());
|
|
|
|
{
|
|
DataModel::LegacyLock lock(dataModel, DataModelJob::Write);
|
|
ChangeHistoryService::requestWaypoint(getName().c_str(), workspace.get());
|
|
}
|
|
|
|
dataState->setDirty(true);
|
|
}
|
|
|
|
PartMaterial MaterialVerb::parseMaterial(const std::string materialString)
|
|
{
|
|
if(materialString == "Plastic")
|
|
{
|
|
return RBX::PLASTIC_MATERIAL;
|
|
}
|
|
else if(materialString == "Slate")
|
|
{
|
|
return RBX::SLATE_MATERIAL;
|
|
}
|
|
else if(materialString == "Wood")
|
|
{
|
|
return RBX::WOOD_MATERIAL;
|
|
}
|
|
else if(materialString == "Concrete")
|
|
{
|
|
return RBX::CONCRETE_MATERIAL;
|
|
}
|
|
else if(materialString =="CorrodedMetal")
|
|
{
|
|
return RBX::RUST_MATERIAL;
|
|
}
|
|
else if(materialString == "DiamondPlate")
|
|
{
|
|
return RBX::DIAMONDPLATE_MATERIAL;
|
|
}
|
|
else if(materialString == "Foil")
|
|
{
|
|
return RBX::ALUMINUM_MATERIAL;
|
|
}
|
|
else if(materialString == "Grass")
|
|
{
|
|
return RBX::GRASS_MATERIAL;
|
|
}
|
|
else if(materialString =="Ice")
|
|
{
|
|
return RBX::ICE_MATERIAL;
|
|
}
|
|
else if(materialString == "Brick")
|
|
{
|
|
return RBX::BRICK_MATERIAL;
|
|
}
|
|
else if(materialString == "Sand")
|
|
{
|
|
return RBX::SAND_MATERIAL;
|
|
}
|
|
else if(materialString == "Fabric")
|
|
{
|
|
return RBX::FABRIC_MATERIAL;
|
|
}
|
|
else if(materialString == "Granite")
|
|
{
|
|
return RBX::GRANITE_MATERIAL;
|
|
}
|
|
else if(materialString == "Marble")
|
|
{
|
|
return RBX::MARBLE_MATERIAL;
|
|
}
|
|
else if(materialString == "Pebble")
|
|
{
|
|
return RBX::PEBBLE_MATERIAL;
|
|
}
|
|
else if(materialString == "SmoothPlastic")
|
|
{
|
|
return RBX::SMOOTH_PLASTIC_MATERIAL;
|
|
}
|
|
else if(materialString == "Neon")
|
|
{
|
|
return NEON_MATERIAL;
|
|
}
|
|
else if(materialString == "WoodPlanks")
|
|
{
|
|
return RBX::WOODPLANKS_MATERIAL;
|
|
}
|
|
else if(materialString == "Cobblestone")
|
|
{
|
|
return RBX::COBBLESTONE_MATERIAL;
|
|
}
|
|
else if(materialString == "Metal")
|
|
{
|
|
return RBX::METAL_MATERIAL;
|
|
}
|
|
else
|
|
return RBX::PLASTIC_MATERIAL;
|
|
}
|
|
|
|
bool applyAnchor(Instance* instance, bool anchor)
|
|
{
|
|
bool applied = false;
|
|
if (PartInstance* pInstance = dynamic_cast<PartInstance*>(instance))
|
|
{
|
|
pInstance->setAnchored(anchor);
|
|
applied = true;
|
|
}
|
|
else if (ModelInstance* pModelInstance = dynamic_cast<ModelInstance*>(instance))
|
|
{
|
|
std::vector<PartInstance*> childParts = pModelInstance->getDescendantPartInstances();
|
|
for (std::vector<PartInstance*>::const_iterator iter = childParts.begin(); iter != childParts.end(); ++iter)
|
|
{
|
|
applied |= applyAnchor(*iter, anchor);
|
|
}
|
|
}
|
|
return applied;
|
|
}
|
|
void AnchorVerb::doIt( IDataState* dataState )
|
|
{
|
|
if (m_selection->size() > 0)
|
|
{
|
|
bool setAnchored = !isChecked(), applied = false;
|
|
for (std::vector<Instance*>::const_iterator iter = m_selection->begin(); iter != m_selection->end(); ++iter)
|
|
applied |= applyAnchor(*iter, setAnchored);
|
|
|
|
{
|
|
DataModel::LegacyLock lock(dataModel, DataModelJob::Write);
|
|
ChangeHistoryService::requestWaypoint(getName().c_str(), workspace.get());
|
|
}
|
|
|
|
dataState->setDirty(true);
|
|
}
|
|
}
|
|
|
|
bool AnchorVerb::isChecked() const
|
|
{
|
|
if (!dataModel)
|
|
return false;
|
|
|
|
bool hasUnanchoredInstance = false;
|
|
|
|
for (std::vector<Instance*>::const_iterator iter = m_selection->begin(); iter != m_selection->end(); ++iter)
|
|
{
|
|
if (!RBX::AnchorTool::allChildrenAnchored(*iter))
|
|
{
|
|
hasUnanchoredInstance = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return !hasUnanchoredInstance;
|
|
}
|
|
|
|
AnchorVerb::AnchorVerb( DataModel* dataModel )
|
|
: EditSelectionVerb("AnchorVerb", dataModel)
|
|
{
|
|
// Put this here to avoid requiring edit lock on isChecked
|
|
m_selection = ServiceProvider::create< FilteredSelection<RBX::Instance> >(dataModel);
|
|
}
|
|
} // namespace
|