2015-01-14 01:11:11 -08:00
|
|
|
/* Copyright (C) 2015 Wildfire Games.
|
2009-06-20 09:13:29 -07:00
|
|
|
* This file is part of 0 A.D.
|
|
|
|
|
*
|
|
|
|
|
* 0 A.D. is free software: you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
* the Free Software Foundation, either version 2 of the License, or
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* 0 A.D. 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 General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
*/
|
|
|
|
|
|
2007-06-05 11:35:05 -07:00
|
|
|
#include "precompiled.h"
|
2006-04-23 16:14:18 -07:00
|
|
|
|
2007-09-02 16:38:58 -07:00
|
|
|
#include "ScenarioEditor/ScenarioEditor.h"
|
2006-04-23 16:14:18 -07:00
|
|
|
#include "Common/Tools.h"
|
|
|
|
|
#include "Common/Brushes.h"
|
|
|
|
|
#include "Common/MiscState.h"
|
2006-05-30 22:27:02 -07:00
|
|
|
#include "Common/ObjectSettings.h"
|
2006-04-23 16:14:18 -07:00
|
|
|
#include "GameInterface/Messages.h"
|
2014-06-17 06:14:25 -07:00
|
|
|
#include <wx/clipbrd.h>
|
|
|
|
|
#include <wx/xml/xml.h>
|
|
|
|
|
#include <wx/sstream.h>
|
2014-06-17 12:32:33 -07:00
|
|
|
#include <wx/version.h>
|
2006-04-23 16:14:18 -07:00
|
|
|
|
|
|
|
|
using AtlasMessage::Position;
|
|
|
|
|
|
|
|
|
|
class TransformObject : public StateDrivenTool<TransformObject>
|
|
|
|
|
{
|
|
|
|
|
DECLARE_DYNAMIC_CLASS(TransformObject);
|
|
|
|
|
|
|
|
|
|
int m_dx, m_dy;
|
2012-02-26 21:32:35 -08:00
|
|
|
AtlasMessage::ObjectID m_lastSelected;
|
|
|
|
|
wxPoint m_startPoint;
|
2014-06-17 06:14:25 -07:00
|
|
|
Position m_entPosition;
|
2012-02-26 21:32:35 -08:00
|
|
|
|
|
|
|
|
// TODO: If we don't plan to change hotkeys, just replace with evt.ShiftDown(), etc.
|
|
|
|
|
static const wxKeyCode SELECTION_ADD_HOTKEY = WXK_SHIFT;
|
|
|
|
|
static const wxKeyCode SELECTION_REMOVE_HOTKEY = WXK_CONTROL; // COMMAND on Macs
|
|
|
|
|
static const wxKeyCode SELECTION_ACTORS_HOTKEY = WXK_ALT;
|
2006-04-23 16:14:18 -07:00
|
|
|
|
|
|
|
|
public:
|
2012-02-26 21:32:35 -08:00
|
|
|
TransformObject() : m_lastSelected(0)
|
2006-04-23 16:14:18 -07:00
|
|
|
{
|
|
|
|
|
SetState(&Waiting);
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-20 12:52:32 -08:00
|
|
|
virtual void OnCommand(const wxString& command, void* WXUNUSED(userData))
|
|
|
|
|
{
|
|
|
|
|
if (command == _T("copy"))
|
|
|
|
|
OnCopy();
|
|
|
|
|
else if (command == _T("paste"))
|
|
|
|
|
OnPasteStart();
|
|
|
|
|
}
|
|
|
|
|
|
2006-04-23 16:14:18 -07:00
|
|
|
void OnDisable()
|
|
|
|
|
{
|
2006-05-03 19:44:03 -07:00
|
|
|
g_SelectedObjects.clear();
|
|
|
|
|
g_SelectedObjects.NotifyObservers();
|
|
|
|
|
POST_MESSAGE(SetSelectionPreview, (g_SelectedObjects));
|
2006-04-23 16:14:18 -07:00
|
|
|
}
|
|
|
|
|
|
2014-11-20 12:52:32 -08:00
|
|
|
bool OnCopy() const
|
|
|
|
|
{
|
|
|
|
|
if (g_SelectedObjects.empty())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
AtlasMessage::qGetObjectMapSettings info(g_SelectedObjects);
|
|
|
|
|
info.Post();
|
|
|
|
|
|
|
|
|
|
if (wxTheClipboard->Open())
|
|
|
|
|
{
|
|
|
|
|
wxString text(info.xmldata.c_str());
|
|
|
|
|
wxTheClipboard->SetData(new wxTextDataObject(text));
|
|
|
|
|
wxTheClipboard->Close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-17 06:14:25 -07:00
|
|
|
void OnPasteStart()
|
|
|
|
|
{
|
|
|
|
|
wxString entities;
|
|
|
|
|
if (wxTheClipboard->Open())
|
|
|
|
|
{
|
|
|
|
|
if (wxTheClipboard->IsSupported(wxDF_TEXT))
|
|
|
|
|
{
|
|
|
|
|
wxTextDataObject data;
|
|
|
|
|
wxTheClipboard->GetData(data);
|
|
|
|
|
entities = data.GetText();
|
|
|
|
|
}
|
|
|
|
|
wxTheClipboard->Close();
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-20 12:52:32 -08:00
|
|
|
// First do we need to check if it is a correct xml string
|
2014-06-17 06:14:25 -07:00
|
|
|
wxInputStream* is = new wxStringInputStream(entities);
|
|
|
|
|
wxXmlDocument doc;
|
|
|
|
|
if (!doc.Load(*is))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// Entities, Entity(1.*)
|
|
|
|
|
wxXmlNode* root = doc.GetRoot();
|
|
|
|
|
if (root->GetName() != wxT("Entities"))
|
|
|
|
|
return;
|
|
|
|
|
|
2014-11-20 12:52:32 -08:00
|
|
|
// Template, position,orientation
|
2014-06-17 06:14:25 -07:00
|
|
|
const wxXmlNode* child = root->GetChildren();
|
|
|
|
|
|
|
|
|
|
while (child)
|
|
|
|
|
{
|
|
|
|
|
if (child->GetName() != wxT("Entity"))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
child = child->GetNext();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_SelectedObjects.clear();
|
|
|
|
|
POST_MESSAGE(SetSelectionPreview, (g_SelectedObjects));
|
|
|
|
|
|
|
|
|
|
// is the source code get here now you can add the objects to scene(preview)
|
|
|
|
|
// store id to move
|
|
|
|
|
child = root->GetChildren();
|
|
|
|
|
|
|
|
|
|
while (child)
|
|
|
|
|
{
|
|
|
|
|
wxString templateName;
|
|
|
|
|
Position entityPos;
|
2014-06-22 15:19:02 -07:00
|
|
|
long playerId = 0;
|
2014-06-17 06:14:25 -07:00
|
|
|
double orientation = 0;
|
2014-09-13 09:53:43 -07:00
|
|
|
unsigned int actorSeed = 0;
|
2014-06-17 06:14:25 -07:00
|
|
|
|
|
|
|
|
const wxXmlNode* xmlData = child->GetChildren();
|
|
|
|
|
|
|
|
|
|
while (xmlData)
|
|
|
|
|
{
|
|
|
|
|
if (xmlData->GetName() == wxT("Template"))
|
|
|
|
|
templateName = xmlData->GetNodeContent();
|
|
|
|
|
else if (xmlData->GetName() == wxT("Position"))
|
|
|
|
|
{
|
|
|
|
|
wxString x, z;
|
2014-06-17 12:32:33 -07:00
|
|
|
#if wxCHECK_VERSION(3, 0, 0)
|
2014-06-17 06:14:25 -07:00
|
|
|
xmlData->GetAttribute(wxT("x"), &x);
|
|
|
|
|
xmlData->GetAttribute(wxT("z"), &z);
|
2014-06-17 12:32:33 -07:00
|
|
|
#else
|
|
|
|
|
xmlData->GetPropVal(wxT("x"), &x);
|
|
|
|
|
xmlData->GetPropVal(wxT("z"), &z);
|
|
|
|
|
#endif
|
2014-06-17 06:14:25 -07:00
|
|
|
|
|
|
|
|
double aux, aux2;
|
|
|
|
|
x.ToDouble(&aux);
|
|
|
|
|
z.ToDouble(&aux2);
|
|
|
|
|
|
|
|
|
|
entityPos = Position(aux, 0, aux2);
|
|
|
|
|
}
|
|
|
|
|
else if (xmlData->GetName() == wxT("Orientation"))
|
|
|
|
|
{
|
|
|
|
|
wxString y;
|
2014-06-17 12:32:33 -07:00
|
|
|
#if wxCHECK_VERSION(3, 0, 0)
|
2014-06-17 06:14:25 -07:00
|
|
|
xmlData->GetAttribute(wxT("y"), &y);
|
2014-06-17 12:32:33 -07:00
|
|
|
#else
|
|
|
|
|
xmlData->GetPropVal(wxT("y"), &y);
|
|
|
|
|
#endif
|
2014-06-17 06:14:25 -07:00
|
|
|
y.ToDouble(&orientation);
|
|
|
|
|
}
|
|
|
|
|
else if (xmlData->GetName() == wxT("Player"))
|
|
|
|
|
{
|
2014-09-13 09:53:43 -07:00
|
|
|
wxString x(xmlData->GetNodeContent());
|
2014-06-17 06:14:25 -07:00
|
|
|
x.ToLong(&playerId);
|
|
|
|
|
}
|
2014-09-13 09:53:43 -07:00
|
|
|
else if (xmlData->GetName() == wxT("ActorSeed"))
|
|
|
|
|
{
|
|
|
|
|
wxString x(xmlData->GetNodeContent());
|
|
|
|
|
unsigned long xTmp = 0;
|
|
|
|
|
x.ToULong(&xTmp);
|
2014-09-24 07:11:13 -07:00
|
|
|
wxASSERT(xTmp <= (unsigned long)std::numeric_limits<unsigned int>::max());
|
2014-09-13 09:53:43 -07:00
|
|
|
actorSeed = xTmp;
|
|
|
|
|
}
|
2014-06-17 06:14:25 -07:00
|
|
|
|
|
|
|
|
xmlData = xmlData->GetNext();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Update current Ownership
|
|
|
|
|
this->GetScenarioEditor().GetObjectSettings().SetPlayerID(playerId);
|
|
|
|
|
this->GetScenarioEditor().GetObjectSettings().NotifyObservers();
|
|
|
|
|
|
2014-09-13 09:53:43 -07:00
|
|
|
POST_MESSAGE(ObjectPreview, ((std::wstring)templateName.c_str(), GetScenarioEditor().GetObjectSettings().GetSettings(), entityPos, false, Position(), orientation, actorSeed, false));
|
2014-06-17 06:14:25 -07:00
|
|
|
|
|
|
|
|
child = child->GetNext();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Set state paste for preview the new objects
|
|
|
|
|
this->SetState(&Pasting);
|
|
|
|
|
|
|
|
|
|
//Update the objects to current mouse position
|
|
|
|
|
OnMovingPaste();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OnMovingPaste()
|
|
|
|
|
{
|
|
|
|
|
//Move the preview(s) object(s)
|
|
|
|
|
POST_MESSAGE(MoveObjectPreview, ((m_entPosition)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OnPasteEnd(bool canceled)
|
|
|
|
|
{
|
|
|
|
|
if (canceled)
|
|
|
|
|
//delete previews objects
|
|
|
|
|
POST_MESSAGE(ObjectPreview, (_T(""), GetScenarioEditor().GetObjectSettings().GetSettings(), Position(), false, Position(), 0, 0, true));
|
|
|
|
|
else
|
|
|
|
|
{
|
2015-04-04 14:45:11 -07:00
|
|
|
ScenarioEditor::GetCommandProc().FinaliseLastCommand();
|
|
|
|
|
|
2014-06-17 06:14:25 -07:00
|
|
|
//Create new Objects and delete preview objects
|
|
|
|
|
POST_MESSAGE(ObjectPreviewToEntity, ());
|
|
|
|
|
|
|
|
|
|
AtlasMessage::qGetCurrentSelection currentSelection;
|
|
|
|
|
currentSelection.Post();
|
|
|
|
|
|
|
|
|
|
g_SelectedObjects = *currentSelection.ids;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//when all is done set default state
|
|
|
|
|
this->SetState(&Waiting);
|
|
|
|
|
}
|
2006-04-23 16:14:18 -07:00
|
|
|
|
|
|
|
|
// TODO: keys to rotate/move object?
|
|
|
|
|
|
|
|
|
|
struct sWaiting : public State
|
|
|
|
|
{
|
|
|
|
|
bool OnMouse(TransformObject* obj, wxMouseEvent& evt)
|
|
|
|
|
{
|
2012-02-26 21:32:35 -08:00
|
|
|
if (evt.LeftDClick() && AtlasMessage::ObjectIDIsValid(obj->m_lastSelected))
|
|
|
|
|
{
|
|
|
|
|
SET_STATE(SelectSimilar);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else if (evt.LeftDown())
|
2006-04-23 16:14:18 -07:00
|
|
|
{
|
2012-02-26 21:32:35 -08:00
|
|
|
bool selectionAdd = wxGetKeyState(SELECTION_ADD_HOTKEY);
|
|
|
|
|
bool selectionRemove = wxGetKeyState(SELECTION_REMOVE_HOTKEY);
|
|
|
|
|
bool selectionActors = wxGetKeyState(SELECTION_ACTORS_HOTKEY);
|
|
|
|
|
|
2006-05-30 22:27:02 -07:00
|
|
|
// New selection - never merge with movements of other objects
|
|
|
|
|
ScenarioEditor::GetCommandProc().FinaliseLastCommand();
|
|
|
|
|
|
|
|
|
|
// Select the object clicked on:
|
|
|
|
|
|
2012-02-26 21:32:35 -08:00
|
|
|
AtlasMessage::qPickObject qry(Position(evt.GetPosition()), selectionActors);
|
2006-04-23 16:14:18 -07:00
|
|
|
qry.Post();
|
2006-05-30 22:27:02 -07:00
|
|
|
|
|
|
|
|
// Check they actually clicked on a valid object
|
2006-04-23 16:14:18 -07:00
|
|
|
if (AtlasMessage::ObjectIDIsValid(qry.id))
|
|
|
|
|
{
|
2012-02-26 21:32:35 -08:00
|
|
|
std::vector<AtlasMessage::ObjectID>::iterator it = std::find(g_SelectedObjects.begin(), g_SelectedObjects.end(), qry.id);
|
|
|
|
|
bool objectIsSelected = (it != g_SelectedObjects.end());
|
|
|
|
|
|
|
|
|
|
if (selectionRemove)
|
|
|
|
|
{
|
|
|
|
|
// Remove from selection
|
|
|
|
|
if (objectIsSelected)
|
|
|
|
|
g_SelectedObjects.erase(it);
|
|
|
|
|
}
|
|
|
|
|
else if (!objectIsSelected)
|
|
|
|
|
{
|
|
|
|
|
// Add to selection
|
|
|
|
|
if (!selectionAdd)
|
|
|
|
|
g_SelectedObjects.clear();
|
|
|
|
|
|
|
|
|
|
g_SelectedObjects.push_back(qry.id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
obj->m_lastSelected = qry.id;
|
|
|
|
|
|
|
|
|
|
// If we're selecting the whole group
|
|
|
|
|
if (!selectionAdd && !selectionRemove && !g_SelectedObjects.empty())
|
|
|
|
|
{
|
|
|
|
|
// Remember the screen-space offset of the mouse from the
|
|
|
|
|
// object's centre, so we can add that back when moving it
|
|
|
|
|
// (instead of just moving the object's centre to directly
|
|
|
|
|
// beneath the mouse)
|
|
|
|
|
obj->m_dx = qry.offsetx;
|
|
|
|
|
obj->m_dy = qry.offsety;
|
|
|
|
|
SET_STATE(Dragging);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_SelectedObjects.NotifyObservers();
|
|
|
|
|
POST_MESSAGE(SetSelectionPreview, (g_SelectedObjects));
|
2006-04-23 16:14:18 -07:00
|
|
|
}
|
2012-02-26 21:32:35 -08:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Bandboxing
|
|
|
|
|
obj->m_lastSelected = 0;
|
|
|
|
|
obj->m_startPoint = evt.GetPosition();
|
|
|
|
|
SET_STATE(Bandboxing);
|
|
|
|
|
}
|
|
|
|
|
|
2006-04-23 16:14:18 -07:00
|
|
|
return true;
|
|
|
|
|
}
|
2015-02-06 14:23:50 -08:00
|
|
|
else if (!g_SelectedObjects.empty() && ((evt.Dragging() && evt.RightIsDown()) || evt.RightDown()))
|
2006-04-23 16:14:18 -07:00
|
|
|
{
|
2015-02-06 14:23:50 -08:00
|
|
|
SET_STATE(Rotating);
|
2006-04-23 16:14:18 -07:00
|
|
|
return true;
|
|
|
|
|
}
|
2012-02-26 21:32:35 -08:00
|
|
|
else if (evt.Moving())
|
|
|
|
|
{
|
2014-06-17 06:14:25 -07:00
|
|
|
//Save position for smooth paste position
|
|
|
|
|
obj->m_entPosition = Position(evt.GetPosition());
|
|
|
|
|
|
2012-02-26 21:32:35 -08:00
|
|
|
// Prevent certain events from reaching game UI in this mode
|
|
|
|
|
// to prevent selection ring confusion
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2006-04-23 16:14:18 -07:00
|
|
|
else
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2007-09-02 16:38:58 -07:00
|
|
|
bool OnKey(TransformObject* obj, wxKeyEvent& evt, KeyEventType type)
|
2006-04-23 16:14:18 -07:00
|
|
|
{
|
|
|
|
|
if (type == KEY_CHAR && evt.GetKeyCode() == WXK_DELETE)
|
|
|
|
|
{
|
2011-08-22 14:45:39 -07:00
|
|
|
POST_COMMAND(DeleteObjects, (g_SelectedObjects));
|
2006-05-30 22:27:02 -07:00
|
|
|
|
2006-05-03 19:44:03 -07:00
|
|
|
g_SelectedObjects.clear();
|
|
|
|
|
g_SelectedObjects.NotifyObservers();
|
2006-05-30 22:27:02 -07:00
|
|
|
|
2006-05-03 19:44:03 -07:00
|
|
|
POST_MESSAGE(SetSelectionPreview, (g_SelectedObjects));
|
2006-04-23 16:14:18 -07:00
|
|
|
return true;
|
|
|
|
|
}
|
2006-05-30 22:27:02 -07:00
|
|
|
else if (type == KEY_CHAR && (evt.GetKeyCode() >= '0' && evt.GetKeyCode() <= '9'))
|
|
|
|
|
{
|
|
|
|
|
int playerID = evt.GetKeyCode() - '0';
|
2007-09-02 16:38:58 -07:00
|
|
|
obj->GetScenarioEditor().GetObjectSettings().SetPlayerID(playerID);
|
|
|
|
|
obj->GetScenarioEditor().GetObjectSettings().NotifyObservers();
|
2006-05-30 22:27:02 -07:00
|
|
|
return true;
|
|
|
|
|
}
|
2014-06-17 06:14:25 -07:00
|
|
|
else if (evt.GetModifiers() == wxMOD_CONTROL)
|
|
|
|
|
{
|
|
|
|
|
if (evt.GetKeyCode() == 'C')
|
2014-11-20 12:52:32 -08:00
|
|
|
return obj->OnCopy();
|
2014-06-17 06:14:25 -07:00
|
|
|
else if (evt.GetKeyCode() == 'V')
|
|
|
|
|
{
|
|
|
|
|
obj->OnPasteStart();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
2006-04-23 16:14:18 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Waiting;
|
|
|
|
|
|
|
|
|
|
struct sDragging : public State
|
|
|
|
|
{
|
|
|
|
|
bool OnMouse(TransformObject* obj, wxMouseEvent& evt)
|
|
|
|
|
{
|
|
|
|
|
if (evt.LeftUp())
|
|
|
|
|
{
|
2015-01-14 01:11:11 -08:00
|
|
|
POST_MESSAGE(ResetSelectionColor, ());
|
2006-04-23 16:14:18 -07:00
|
|
|
SET_STATE(Waiting);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else if (evt.Dragging())
|
|
|
|
|
{
|
2014-06-17 06:14:25 -07:00
|
|
|
Position pos(evt.GetPosition() + wxPoint(obj->m_dx, obj->m_dy));
|
2012-02-26 21:32:35 -08:00
|
|
|
|
|
|
|
|
POST_COMMAND(MoveObjects, (g_SelectedObjects, obj->m_lastSelected, pos));
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool OnKey(TransformObject* obj, wxKeyEvent& evt, KeyEventType type)
|
|
|
|
|
{
|
|
|
|
|
if (type == KEY_UP && evt.GetKeyCode() == WXK_ESCAPE)
|
|
|
|
|
{
|
|
|
|
|
// Cancel move action
|
|
|
|
|
ScenarioEditor::GetCommandProc().FinaliseLastCommand();
|
|
|
|
|
ScenarioEditor::GetCommandProc().Undo();
|
|
|
|
|
SET_STATE(Waiting);
|
|
|
|
|
|
2006-04-23 16:14:18 -07:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Dragging;
|
2012-02-26 21:32:35 -08:00
|
|
|
|
|
|
|
|
struct sBandboxing : public State
|
|
|
|
|
{
|
|
|
|
|
bool OnMouse(TransformObject* obj, wxMouseEvent& evt)
|
|
|
|
|
{
|
|
|
|
|
if (evt.LeftIsDown() && evt.Dragging())
|
|
|
|
|
{
|
|
|
|
|
// Update bandbox overlay
|
|
|
|
|
POST_MESSAGE(SetBandbox, (true, obj->m_startPoint.x, obj->m_startPoint.y, evt.GetPosition().x, evt.GetPosition().y));
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else if (evt.LeftUp())
|
|
|
|
|
{
|
|
|
|
|
bool selectionAdd = wxGetKeyState(SELECTION_ADD_HOTKEY);
|
|
|
|
|
bool selectionRemove = wxGetKeyState(SELECTION_REMOVE_HOTKEY);
|
|
|
|
|
bool selectionActors = wxGetKeyState(SELECTION_ACTORS_HOTKEY);
|
|
|
|
|
|
|
|
|
|
// Now we have both corners of the box, pick objects
|
|
|
|
|
AtlasMessage::qPickObjectsInRect qry(Position(obj->m_startPoint), Position(evt.GetPosition()), selectionActors);
|
|
|
|
|
qry.Post();
|
|
|
|
|
|
|
|
|
|
std::vector<AtlasMessage::ObjectID> ids = *qry.ids;
|
|
|
|
|
|
|
|
|
|
if (!selectionAdd && !selectionRemove)
|
|
|
|
|
{
|
|
|
|
|
// Just copy new selections (clears list if no selections)
|
|
|
|
|
g_SelectedObjects = ids;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
for (size_t i = 0; i < ids.size(); ++i)
|
|
|
|
|
{
|
2014-06-17 06:14:25 -07:00
|
|
|
std::vector<AtlasMessage::ObjectID>::iterator it = std::find(g_SelectedObjects.begin(), g_SelectedObjects.end(), ids[i]);
|
2012-02-26 21:32:35 -08:00
|
|
|
bool objectIsSelected = (it != g_SelectedObjects.end());
|
|
|
|
|
if (selectionRemove)
|
|
|
|
|
{
|
|
|
|
|
// Remove from selection
|
|
|
|
|
if (objectIsSelected)
|
|
|
|
|
g_SelectedObjects.erase(it);
|
|
|
|
|
}
|
|
|
|
|
else if (!objectIsSelected)
|
|
|
|
|
{
|
|
|
|
|
// Add to selection
|
|
|
|
|
g_SelectedObjects.push_back(ids[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
POST_MESSAGE(SetBandbox, (false, 0, 0, 0, 0));
|
|
|
|
|
|
|
|
|
|
g_SelectedObjects.NotifyObservers();
|
|
|
|
|
POST_MESSAGE(SetSelectionPreview, (g_SelectedObjects));
|
|
|
|
|
|
|
|
|
|
SET_STATE(Waiting);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool OnKey(TransformObject* obj, wxKeyEvent& evt, KeyEventType type)
|
|
|
|
|
{
|
|
|
|
|
if (type == KEY_UP && evt.GetKeyCode() == WXK_ESCAPE)
|
|
|
|
|
{
|
|
|
|
|
// Clear bandbox and return to waiting state
|
|
|
|
|
POST_MESSAGE(SetBandbox, (false, 0, 0, 0, 0));
|
|
|
|
|
SET_STATE(Waiting);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Bandboxing;
|
|
|
|
|
|
|
|
|
|
struct sSelectSimilar : public State
|
|
|
|
|
{
|
|
|
|
|
bool OnMouse(TransformObject* obj, wxMouseEvent& evt)
|
|
|
|
|
{
|
|
|
|
|
if (evt.LeftUp())
|
|
|
|
|
{
|
|
|
|
|
bool selectionAdd = wxGetKeyState(SELECTION_ADD_HOTKEY);
|
|
|
|
|
bool selectionRemove = wxGetKeyState(SELECTION_REMOVE_HOTKEY);
|
|
|
|
|
|
|
|
|
|
// Select similar objects
|
|
|
|
|
AtlasMessage::qPickSimilarObjects qry(obj->m_lastSelected);
|
|
|
|
|
qry.Post();
|
|
|
|
|
|
|
|
|
|
std::vector<AtlasMessage::ObjectID> ids = *qry.ids;
|
2014-06-17 06:14:25 -07:00
|
|
|
|
2012-02-26 21:32:35 -08:00
|
|
|
if (!selectionAdd && !selectionRemove)
|
|
|
|
|
{
|
|
|
|
|
// Just copy new selections (clears list if no selections)
|
|
|
|
|
g_SelectedObjects = ids;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
for (size_t i = 0; i < ids.size(); ++i)
|
|
|
|
|
{
|
2014-06-17 06:14:25 -07:00
|
|
|
std::vector<AtlasMessage::ObjectID>::iterator it = std::find(g_SelectedObjects.begin(), g_SelectedObjects.end(), ids[i]);
|
2012-02-26 21:32:35 -08:00
|
|
|
bool objectIsSelected = (it != g_SelectedObjects.end());
|
|
|
|
|
if (selectionRemove)
|
|
|
|
|
{
|
|
|
|
|
// Remove from selection
|
|
|
|
|
if (objectIsSelected)
|
|
|
|
|
g_SelectedObjects.erase(it);
|
|
|
|
|
}
|
|
|
|
|
else if (!objectIsSelected)
|
|
|
|
|
{
|
|
|
|
|
// Add to selection
|
|
|
|
|
g_SelectedObjects.push_back(ids[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_SelectedObjects.NotifyObservers();
|
|
|
|
|
POST_MESSAGE(SetSelectionPreview, (g_SelectedObjects));
|
|
|
|
|
|
|
|
|
|
SET_STATE(Waiting);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
SelectSimilar;
|
2014-06-17 06:14:25 -07:00
|
|
|
|
|
|
|
|
struct sPasting : public State
|
|
|
|
|
{
|
|
|
|
|
bool OnMouse(TransformObject* obj, wxMouseEvent& evt)
|
|
|
|
|
{
|
|
|
|
|
if (evt.Moving())
|
|
|
|
|
{
|
|
|
|
|
//Move the object
|
|
|
|
|
obj->m_entPosition = Position(evt.GetPosition());
|
|
|
|
|
obj->OnMovingPaste();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else if (evt.LeftDown())
|
|
|
|
|
{
|
|
|
|
|
//Place the object and update
|
|
|
|
|
obj->OnPasteEnd(false);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
bool OnKey(TransformObject* obj, wxKeyEvent& evt, KeyEventType type)
|
|
|
|
|
{
|
|
|
|
|
if (type == KEY_CHAR && evt.GetKeyCode() == WXK_ESCAPE)
|
|
|
|
|
{
|
|
|
|
|
obj->OnPasteEnd(true);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Pasting;
|
2015-02-06 14:23:50 -08:00
|
|
|
|
|
|
|
|
struct sRotating : public State
|
|
|
|
|
{
|
|
|
|
|
bool fromCenterPoint;
|
|
|
|
|
|
|
|
|
|
void OnEnter(TransformObject* WXUNUSED(obj))
|
|
|
|
|
{
|
|
|
|
|
fromCenterPoint = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool OnMouse(TransformObject* obj, wxMouseEvent& evt)
|
|
|
|
|
{
|
|
|
|
|
if (evt.RightUp())
|
|
|
|
|
{
|
|
|
|
|
POST_MESSAGE(ResetSelectionColor, ());
|
|
|
|
|
SET_STATE(Waiting);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else if (evt.Dragging())
|
|
|
|
|
{
|
|
|
|
|
bool fromGlobalAndIndividualCenterPoints = !evt.ControlDown() && !evt.ShiftDown();
|
|
|
|
|
bool newFromCenterPoint = evt.ShiftDown() || fromGlobalAndIndividualCenterPoints;
|
|
|
|
|
if (newFromCenterPoint != fromCenterPoint)
|
|
|
|
|
{
|
|
|
|
|
ScenarioEditor::GetCommandProc().FinaliseLastCommand();
|
|
|
|
|
fromCenterPoint = newFromCenterPoint;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Position pos(evt.GetPosition());
|
|
|
|
|
|
|
|
|
|
if (fromCenterPoint)
|
|
|
|
|
POST_COMMAND(RotateObjectsFromCenterPoint, (g_SelectedObjects, pos, fromGlobalAndIndividualCenterPoints));
|
|
|
|
|
else
|
|
|
|
|
POST_COMMAND(RotateObject, (g_SelectedObjects, pos));
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool OnKey(TransformObject* obj, wxKeyEvent& evt, KeyEventType type)
|
|
|
|
|
{
|
|
|
|
|
if (type == KEY_UP && evt.GetKeyCode() == WXK_ESCAPE)
|
|
|
|
|
{
|
|
|
|
|
// Cancel move action
|
|
|
|
|
ScenarioEditor::GetCommandProc().FinaliseLastCommand();
|
|
|
|
|
ScenarioEditor::GetCommandProc().Undo();
|
|
|
|
|
SET_STATE(Waiting);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Rotating;
|
2006-04-23 16:14:18 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
IMPLEMENT_DYNAMIC_CLASS(TransformObject, StateDrivenTool<TransformObject>);
|