1
0
forked from 0ad/0ad

Atlas: Incomplete object (entity+actor) placement code. +/- keys for zooming.

This was SVN commit r3184.
This commit is contained in:
Ykkrosh 2005-12-02 07:37:57 +00:00
parent 8f976e4b8a
commit 0a252de08c
19 changed files with 468 additions and 34 deletions

View File

@ -116,7 +116,7 @@ CUnit* CUnitManager::PickUnit(const CVector3D& origin,const CVector3D& dir) cons
///////////////////////////////////////////////////////////////////////////////
// CreateUnit: create a new unit and add it to the world
CUnit* CUnitManager::CreateUnit(CStr& actorName, CEntity* entity)
CUnit* CUnitManager::CreateUnit(const CStr& actorName, CEntity* entity)
{
CObjectEntry* obj = g_ObjMan.FindObject(actorName);

View File

@ -40,7 +40,7 @@ public:
void DeleteAll();
// creates a new unit and adds it to the world
CUnit* CreateUnit(CStr& actorName, CEntity* entity);
CUnit* CreateUnit(const CStr& actorName, CEntity* entity);
// return the units
const std::vector<CUnit*>& GetUnits() const { return m_Units; }

View File

@ -26,6 +26,7 @@ void ToolButton::OnClick(wxCommandEvent& WXUNUSED(evt))
{
if (g_Current)
g_Current->SetSelectedAppearance(false);
// TODO: set disabled when tool is changed via other (non-button) methods
// Toggle on/off
if (g_Current == this)

View File

@ -57,7 +57,7 @@ public:
case WXK_RIGHT: dir = AtlasMessage::eScrollConstantDir::RIGHT; break;
case WXK_UP: dir = AtlasMessage::eScrollConstantDir::FORWARDS; break;
case WXK_DOWN: dir = AtlasMessage::eScrollConstantDir::BACKWARDS; break;
case WXK_SHIFT: dir = -1; break;
case WXK_SHIFT: case WXK_CONTROL: dir = -1; break;
default: return false;
}
@ -86,24 +86,54 @@ public:
void OnKeyDown(wxKeyEvent& evt)
{
if (GetCurrentTool().OnKey(evt, ITool::KEY_DOWN))
{
// Key event has been handled by the tool, so don't try
// to use it for camera motion too
return;
}
if (KeyScroll(evt, true))
return;
GetCurrentTool().OnKey(evt, ITool::KEY_DOWN);
evt.Skip();
}
void OnKeyUp(wxKeyEvent& evt)
{
if (GetCurrentTool().OnKey(evt, ITool::KEY_UP))
return;
if (KeyScroll(evt, false))
return;
GetCurrentTool().OnKey(evt, ITool::KEY_UP);
evt.Skip();
}
void OnChar(wxKeyEvent& evt)
{
if (GetCurrentTool().OnKey(evt, ITool::KEY_CHAR))
return;
int dir = 0;
if (evt.GetKeyCode() == '-' || evt.GetKeyCode() == '_')
dir = -1;
else if (evt.GetKeyCode() == '+' || evt.GetKeyCode() == '=')
dir = +1;
// TODO: internationalisation (-/_ and +/= don't always share a key)
if (dir)
{
float speed = 16.f;
if (wxGetKeyState(WXK_SHIFT))
speed *= 4.f;
POST_MESSAGE(SmoothZoom(speed*dir));
}
else
evt.Skip();
}
void OnMouseCapture(wxMouseCaptureChangedEvent& WXUNUSED(evt))
{
if (m_MouseCaptured)
@ -160,11 +190,12 @@ public:
#ifndef UI_ONLY
GetCurrentTool().OnMouse(evt);
// TODO: if the tool responded to the mouse action, should we avoid moving
// the camera too? (This is mostly avoided by not sharing buttons between
// camera and tools, so maybe it's not a problem.)
if (GetCurrentTool().OnMouse(evt))
{
// Mouse event has been handled by the tool, so don't try
// to use it for camera motion too
return;
}
if (evt.GetWheelRotation())
{
@ -230,6 +261,7 @@ BEGIN_EVENT_TABLE(Canvas, wxGLCanvas)
EVT_SIZE (Canvas::OnResize)
EVT_KEY_DOWN (Canvas::OnKeyDown)
EVT_KEY_UP (Canvas::OnKeyUp)
EVT_CHAR (Canvas::OnChar)
EVT_LEFT_DOWN (Canvas::OnMouse)
EVT_LEFT_UP (Canvas::OnMouse)

View File

@ -6,6 +6,7 @@
#include "Sections/Map/Map.h"
#include "Sections/Terrain/Terrain.h"
#include "Sections/Object/Object.h"
//////////////////////////////////////////////////////////////////////////
@ -35,6 +36,9 @@ protected:
if (event.GetSelection() != -1)
newPage = wxDynamicCast(GetPage(event.GetSelection()), Sidebar);
if (newPage)
newPage->OnSwitchTo();
if (m_Splitter->IsSplit())
{
wxWindow* bottom;
@ -103,6 +107,7 @@ void SectionLayout::Build()
wxNotebook* sidebar = new SidebarNotebook(m_HorizSplitter, m_VertSplitter);
sidebar->AddPage(new MapSidebar(sidebar), _("Map"), false);
sidebar->AddPage(new TerrainSidebar(sidebar), _("Terrain"), false);
sidebar->AddPage(new ObjectSidebar(sidebar), _("Object"), false);
m_VertSplitter->SetDefaultSashPosition(-165);
m_VertSplitter->Initialize(m_Canvas);

View File

@ -5,7 +5,7 @@
IMPLEMENT_DYNAMIC_CLASS(Sidebar, wxPanel)
Sidebar::Sidebar(wxWindow* parent)
: wxPanel(parent)
: wxPanel(parent), m_AlreadyDisplayed(false)
{
m_MainSizer = new wxBoxSizer(wxVERTICAL);
SetSizer(m_MainSizer);
@ -15,3 +15,12 @@ wxWindow* Sidebar::GetBottomBar(wxWindow* WXUNUSED(parent))
{
return NULL;
}
void Sidebar::OnSwitchTo()
{
if (m_AlreadyDisplayed)
return;
m_AlreadyDisplayed = true;
OnFirstDisplay();
}

View File

@ -9,12 +9,21 @@ public:
Sidebar() {}
Sidebar(wxWindow* parent);
void OnSwitchTo();
virtual wxWindow* GetBottomBar(wxWindow* parent);
// called whenever the bottom bar is made visible; should usually be
// lazily constructed, then cached forever (to maximise responsiveness)
protected:
wxSizer* m_MainSizer; // vertical box sizer, used by most sidebars
virtual void OnFirstDisplay() {}
// should be overridden when sidebars need to do expensive construction,
// so it can be delayed until it is required
private:
bool m_AlreadyDisplayed;
};
#endif // SIDEBAR_H__

View File

@ -0,0 +1,71 @@
#include "stdafx.h"
#include "Object.h"
#include "Buttons/ActionButton.h"
#include "Buttons/ToolButton.h"
#include "ScenarioEditor/Tools/Common/Tools.h"
#include "GameInterface/Messages.h"
class ObjectSelectListBox : public wxListBox
{
public:
ObjectSelectListBox(wxWindow* parent)
: wxListBox(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, NULL, wxLB_SINGLE)
{
}
void OnSelect(wxCommandEvent& evt)
{
wxString id = static_cast<wxStringClientData*>(evt.GetClientObject())->GetData();
SetCurrentTool(_T("PlaceObject"), &id);
}
private:
DECLARE_EVENT_TABLE();
};
BEGIN_EVENT_TABLE(ObjectSelectListBox, wxListBox)
EVT_LISTBOX(wxID_ANY, ObjectSelectListBox::OnSelect)
END_EVENT_TABLE();
//////////////////////////////////////////////////////////////////////////
ObjectSidebar::ObjectSidebar(wxWindow* parent)
: Sidebar(parent), m_BottomBar(NULL)
{
m_ObjectListBox = new ObjectSelectListBox(this);
m_MainSizer->Add(m_ObjectListBox, wxSizerFlags().Proportion(1).Expand());
}
wxWindow* ObjectSidebar::GetBottomBar(wxWindow* parent)
{
if (m_BottomBar)
return m_BottomBar;
// m_BottomBar = new ObjectBottomBar(parent);
return m_BottomBar;
}
void ObjectSidebar::OnFirstDisplay()
{
AtlasMessage::qGetEntitiesList qry;
qry.Post();
for (std::vector<AtlasMessage::sEntitiesListItem>::iterator it = qry.entities.begin(); it != qry.entities.end(); ++it)
{
wxString name = it->name.c_str();
m_ObjectListBox->Append(name, new wxStringClientData(name));
}
}
//////////////////////////////////////////////////////////////////////////
//TerrainBottomBar::TerrainBottomBar(wxWindow* parent)
// : wxPanel(parent, wxID_ANY)
//{
// wxSizer* sizer = new wxBoxSizer(wxVERTICAL);
// wxNotebook* notebook = new TextureNotebook(this);
// sizer->Add(notebook, wxSizerFlags().Expand().Proportion(1));
// SetSizer(sizer);
//}

View File

@ -0,0 +1,22 @@
#include "../Common/Sidebar.h"
class ObjectSidebar : public Sidebar
{
public:
ObjectSidebar(wxWindow* parent);
wxWindow* GetBottomBar(wxWindow* parent);
protected:
void OnFirstDisplay();
private:
wxWindow* m_BottomBar;
wxListBox* m_ObjectListBox;
};
class ObjectBottomBar : public wxPanel
{
public:
ObjectBottomBar(wxWindow* parent);
private:
};

View File

@ -181,4 +181,4 @@ TerrainBottomBar::TerrainBottomBar(wxWindow* parent)
wxNotebook* notebook = new TextureNotebook(this);
sizer->Add(notebook, wxSizerFlags().Expand().Proportion(1));
SetSizer(sizer);
}
}

View File

@ -15,4 +15,4 @@ class TerrainBottomBar : public wxPanel
public:
TerrainBottomBar(wxWindow* parent);
private:
};
};

View File

@ -20,12 +20,12 @@ public:
}
void OnEnable(AlterElevation*)
void OnEnable()
{
g_Brush_Elevation.MakeActive();
}
void OnDisable(AlterElevation*)
void OnDisable()
{
POST_MESSAGE(BrushPreview(false, Position()));
}

View File

@ -5,9 +5,10 @@
class DummyTool : public ITool
{
void Init(void*) {}
void Shutdown() {}
void OnMouse(wxMouseEvent& evt) { evt.Skip(); }
void OnKey(wxKeyEvent& evt, KeyEventType) { evt.Skip(); }
bool OnMouse(wxMouseEvent& WXUNUSED(evt)) { return false; }
bool OnKey(wxKeyEvent& WXUNUSED(evt), KeyEventType) { return false; }
void OnTick(float) {}
} dummy;
@ -18,7 +19,7 @@ ITool& GetCurrentTool()
return *g_CurrentTool;
}
void SetCurrentTool(const wxString& name)
void SetCurrentTool(const wxString& name, void* initData)
{
if (g_CurrentTool != &dummy)
{
@ -31,6 +32,7 @@ void SetCurrentTool(const wxString& name)
{
tool = wxDynamicCast(wxCreateDynamicObject(name), ITool);
wxASSERT(tool);
tool->Init(initData);
}
if (tool == NULL)

View File

@ -12,16 +12,18 @@ class ITool : public wxObject
public:
enum KeyEventType { KEY_DOWN, KEY_UP, KEY_CHAR };
virtual void Init(void* initData) = 0;
virtual void Shutdown() = 0;
virtual void OnMouse(wxMouseEvent& evt) = 0;
virtual void OnKey(wxKeyEvent& evt, KeyEventType dir) = 0;
virtual bool OnMouse(wxMouseEvent& evt) = 0; // return true if handled
virtual bool OnKey(wxKeyEvent& evt, KeyEventType dir) = 0; // return true if handled
virtual void OnTick(float dt) = 0; // dt in seconds
virtual ~ITool() {};
};
extern ITool& GetCurrentTool();
extern void SetCurrentTool(const wxString& name); // should usually only be used by tool buttons
extern void SetCurrentTool(const wxString& name, void* initData = NULL);
// should usually only be used by tool buttons. (TODO: not true)
//////////////////////////////////////////////////////////////////////////
@ -58,6 +60,10 @@ public:
{
}
virtual void Init(void* WXUNUSED(initData))
{
}
virtual void Shutdown()
{
// This can't be done in the destructor, because ~StateDrivenTool
@ -69,8 +75,8 @@ public:
protected:
// Called when the tool is enabled/disabled; always called in zero or
// more enable-->disable pairs per object instance.
virtual void OnEnable(T* WXUNUSED(obj)) {}
virtual void OnDisable(T* WXUNUSED(obj)) {}
virtual void OnEnable() {}
virtual void OnDisable() {}
struct State
{
@ -87,8 +93,8 @@ protected:
struct sDisabled : public State
{
void OnEnter(T* obj) { obj->OnDisable(obj); }
void OnLeave(T* obj) { obj->OnEnable(obj); }
void OnEnter(T* obj) { obj->OnDisable(); }
void OnLeave(T* obj) { obj->OnEnable(); }
}
Disabled;
@ -103,14 +109,14 @@ protected:
private:
State* m_CurrentState;
virtual void OnMouse(wxMouseEvent& evt)
virtual bool OnMouse(wxMouseEvent& evt)
{
m_CurrentState->OnMouse(static_cast<T*>(this), evt);
return m_CurrentState->OnMouse(static_cast<T*>(this), evt);
}
virtual void OnKey(wxKeyEvent& evt, KeyEventType dir)
virtual bool OnKey(wxKeyEvent& evt, KeyEventType dir)
{
m_CurrentState->OnKey(static_cast<T*>(this), evt, dir);
return m_CurrentState->OnKey(static_cast<T*>(this), evt, dir);
}
virtual void OnTick(float dt)

View File

@ -20,13 +20,13 @@ public:
}
void OnEnable(PaintTerrain*)
void OnEnable()
{
// TODO: multiple independent brushes?
g_Brush_Elevation.MakeActive();
}
void OnDisable(PaintTerrain*)
void OnDisable()
{
POST_MESSAGE(BrushPreview(false, Position()));
}

View File

@ -0,0 +1,161 @@
#include "stdafx.h"
#include "Common/Tools.h"
#include "Common/Brushes.h"
#include "Common/MiscState.h"
#include "GameInterface/Messages.h"
using AtlasMessage::Position;
static float g_DefaultAngle = M_PI*3.0/4.0;
class PlaceObject : public StateDrivenTool<PlaceObject>
{
DECLARE_DYNAMIC_CLASS(PlaceObject);
Position m_ScreenPos, m_ObjPos, m_Target;
wxString m_ObjectName;
public:
PlaceObject()
{
SetState(&Waiting);
}
void SendPreviewCommand()
{
int dragDistSq =
(m_ScreenPos.type1.x-m_Target.type1.x)*(m_ScreenPos.type1.x-m_Target.type1.x)
+ (m_ScreenPos.type1.y-m_Target.type1.y)*(m_ScreenPos.type1.y-m_Target.type1.y);
bool useTarget = (dragDistSq >= 8*8);
POST_MESSAGE(EntityPreview(m_ObjectName.c_str(), m_ObjPos, useTarget, m_Target, g_DefaultAngle));
}
virtual void Init(void* initData)
{
wxASSERT(initData);
wxString& name = *static_cast<wxString*>(initData);
m_ObjectName = name;
SendPreviewCommand();
}
void OnEnable()
{
}
void OnDisable()
{
m_ObjectName = _T("");
SendPreviewCommand();
}
/*
Object placement:
* Select unit from list
* Move mouse around screen; preview of unit follows mouse
* Left mouse down -> remember position, fix preview to point
* Mouse move -> if moved > 8px, rotate unit to face mouse; else default orientation
* Left mouse release -> finalise placement of object on map
* Scroll wheel -> rotate default orientation
* Escape -> cancel placement tool
TOOD: what happens if somebody saves while the preview is active?
*/
bool OnMouseOverride(wxMouseEvent& evt)
{
if (evt.GetWheelRotation())
{
float speed = M_PI/36.f;
if (wxGetKeyState(WXK_SHIFT) && wxGetKeyState(WXK_CONTROL))
speed /= 64.f;
else if (wxGetKeyState(WXK_CONTROL))
speed /= 4.f;
else if (wxGetKeyState(WXK_SHIFT))
speed *= 4.f;
g_DefaultAngle += (evt.GetWheelRotation() * speed / evt.GetWheelDelta());
SendPreviewCommand();
return true;
}
else
return false;
}
bool OnKeyOverride(wxKeyEvent& evt, KeyEventType dir)
{
if (dir == KEY_CHAR && evt.GetKeyCode() == WXK_ESCAPE)
{
SetState(&Disabled);
return true;
}
// TODO: arrow keys for rotation?
else
return false;
}
struct sWaiting : public State
{
bool OnMouse(PlaceObject* obj, wxMouseEvent& evt)
{
if (obj->OnMouseOverride(evt))
return true;
else if (evt.LeftDown())
{
obj->m_ObjPos = obj->m_ScreenPos = obj->m_Target = Position(evt.GetPosition());
obj->SendPreviewCommand();
obj->m_ObjPos = Position::Unchanged(); // make sure object is stationary even if the camera moves
SET_STATE(Placing);
return true;
}
else if (evt.Moving())
{
obj->m_ObjPos = obj->m_ScreenPos = obj->m_Target = Position(evt.GetPosition());
obj->SendPreviewCommand();
return true;
}
else
return false;
}
bool OnKey(PlaceObject* obj, wxKeyEvent& evt, KeyEventType dir)
{
return obj->OnKeyOverride(evt, dir);
}
}
Waiting;
struct sPlacing : public State
{
bool OnMouse(PlaceObject* obj, wxMouseEvent& evt)
{
if (obj->OnMouseOverride(evt))
return true;
else if (evt.LeftUp())
{
obj->m_Target = Position(evt.GetPosition());
// TODO: createobject command, so you can actually place an object
SET_STATE(Waiting);
obj->m_ObjPos = obj->m_ScreenPos = obj->m_Target;
obj->SendPreviewCommand();
return true;
}
else if (evt.Moving())
{
obj->m_Target = Position(evt.GetPosition());
obj->SendPreviewCommand();
return true;
}
else
return false;
}
bool OnKey(PlaceObject* obj, wxKeyEvent& evt, KeyEventType dir)
{
return obj->OnKeyOverride(evt, dir);
}
}
Placing;
};
IMPLEMENT_DYNAMIC_CLASS(PlaceObject, StateDrivenTool<PlaceObject>);

View File

@ -1,3 +1,9 @@
wxWidgets:
* alt+f with notebook tab focussed
* wxLogTrace "%s" wxGetMessage (msw/window.cpp)
==============================
Colour tester:
==============================
@ -74,7 +80,6 @@ General and/or unsorted miscellany:
* Don't create a row when editing a blank one then removing focus without typing anything
======
Done: (newest at top)

View File

@ -0,0 +1,87 @@
#include "precompiled.h"
#include "MessageHandler.h"
#include "simulation/BaseEntityCollection.h"
#include "graphics/Unit.h"
#include "graphics/UnitManager.h"
#include "graphics/Model.h"
#include "maths/Matrix3D.h"
namespace AtlasMessage {
QUERYHANDLER(GetEntitiesList)
{
std::vector<CStrW> names;
g_EntityTemplateCollection.getBaseEntityNames(names);
for (std::vector<CStrW>::iterator it = names.begin(); it != names.end(); ++it)
{
sEntitiesListItem e;
e.name = *it;
msg->entities.push_back(e);
}
}
static CUnit* g_PreviewUnit = NULL;
static CStrW g_PreviewUnitName;
MESSAGEHANDLER(EntityPreview)
{
if (msg->name != g_PreviewUnitName)
{
// Delete old unit
if (g_PreviewUnit)
{
g_UnitMan.RemoveUnit(g_PreviewUnit);
delete g_PreviewUnit;
g_PreviewUnit = NULL;
}
if (msg->name.length())
{
// Create new unit
CBaseEntity* base = g_EntityTemplateCollection.getTemplate(msg->name);
if (base)
{
g_PreviewUnit = g_UnitMan.CreateUnit(base->m_actorName, 0);
// TODO: set player (for colour)
// TODO: variations
}
}
g_PreviewUnitName = msg->name;
}
// Position/orient unit
if (g_PreviewUnit)
{
static CVector3D pos;
msg->pos.GetWorldSpace(pos, pos); // if msg->pos is 'Unchanged', use the previous pos
float s, c;
/*
if (msg->usetarget)
{
// TODO
s=1; c=0;
}
else
*/
{
s = sin(msg->angle);
c = cos(msg->angle);
}
CMatrix3D m;
m._11 = -c; m._12 = 0.0f; m._13 = -s; m._14 = pos.X;
m._21 = 0.0f; m._22 = 1.0f; m._23 = 0.0f; m._24 = pos.Y;
m._31 = s; m._32 = 0.0f; m._33 = -c; m._34 = pos.Z;
m._41 = 0.0f; m._42 = 0.0f; m._43 = 0.0f; m._44 = 1.0f;
g_PreviewUnit->GetModel()->SetTransform(m);
}
}
}

View File

@ -3,6 +3,8 @@
#include "MessagesSetup.h"
// TODO: organisation, documentation, etc
//////////////////////////////////////////////////////////////////////////
MESSAGE(CommandString,
@ -83,6 +85,28 @@ QUERY(GetTerrainGroupPreviews,
);
//////////////////////////////////////////////////////////////////////////
struct sEntitiesListItem
{
std::wstring name;
// ...
};
QUERY(GetEntitiesList,
, // no inputs
((std::vector<sEntitiesListItem>, entities))
);
MESSAGE(EntityPreview,
((std::wstring, name)) // or empty string => disable
((Position, pos))
((bool, usetarget)) // true => use 'target' for orientation; false => use 'angle'
((Position, target))
((float, angle))
);
//////////////////////////////////////////////////////////////////////////
QUERY(Exit,,); // no inputs nor outputs
//////////////////////////////////////////////////////////////////////////