1
0
forked from 0ad/0ad

Initial Actor Editor code

This was SVN commit r2025.
This commit is contained in:
Ykkrosh 2005-03-19 22:29:32 +00:00
parent 2091822e16
commit d0146135c4
43 changed files with 2833 additions and 0 deletions

View File

@ -0,0 +1,30 @@
Microsoft Visual Studio Solution File, Format Version 8.00
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AtlasUI", "AtlasUI\AtlasUI.vcproj", "{E99BA969-D540-4F23-822E-37C499E8F704}"
ProjectSection(ProjectDependencies) = postProject
{228B468D-3C2E-45BF-9833-C626E1A35B04} = {228B468D-3C2E-45BF-9833-C626E1A35B04}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AtlasObject", "AtlasObject\AtlasObject.vcproj", "{228B468D-3C2E-45BF-9833-C626E1A35B04}"
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfiguration) = preSolution
Debug = Debug
Release = Release
EndGlobalSection
GlobalSection(ProjectConfiguration) = postSolution
{E99BA969-D540-4F23-822E-37C499E8F704}.Debug.ActiveCfg = Debug|Win32
{E99BA969-D540-4F23-822E-37C499E8F704}.Debug.Build.0 = Debug|Win32
{E99BA969-D540-4F23-822E-37C499E8F704}.Release.ActiveCfg = Release|Win32
{E99BA969-D540-4F23-822E-37C499E8F704}.Release.Build.0 = Release|Win32
{228B468D-3C2E-45BF-9833-C626E1A35B04}.Debug.ActiveCfg = Debug|Win32
{228B468D-3C2E-45BF-9833-C626E1A35B04}.Debug.Build.0 = Debug|Win32
{228B468D-3C2E-45BF-9833-C626E1A35B04}.Release.ActiveCfg = Release|Win32
{228B468D-3C2E-45BF-9833-C626E1A35B04}.Release.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
EndGlobalSection
GlobalSection(ExtensibilityAddIns) = postSolution
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,137 @@
// Public interface to almost all of AtlasObject.
// (See AtlasObjectText for the rest of it).
//
// Tries to include as few headers as possible, to minimise its impact
// on compile times.
#ifndef ATLASOBJECT_H__
#define ATLASOBJECT_H__
#include <wchar.h> // for wchar_t
//////////////////////////////////////////////////////////////////////////
// Mostly-private bits:
// Simple reference-counted pointer. class T must contain a reference count,
// initialised to 0. An external implementation (in AtlasObjectImpl.cpp)
// provides the inc_ref and dec_ref methods, so that this header file doesn't
// need to know their implementations.
template<class T> class AtSmartPtr
{
public:
// Constructors
AtSmartPtr() : ptr(NULL) {}
explicit AtSmartPtr(T* p) : ptr(p) { inc_ref(); }
// Copy constructor
AtSmartPtr(const AtSmartPtr<T>& r) : ptr(r.ptr) { inc_ref(); }
// Assignment operators
AtSmartPtr<T>& operator=(T* p) { dec_ref(); ptr = p; inc_ref(); return *this; }
AtSmartPtr<T>& operator=(const AtSmartPtr<T>& r) { dec_ref(); ptr = r.ptr; inc_ref(); return *this; }
// Destructor
~AtSmartPtr() { dec_ref(); }
// Allow conversion from non-const T* to const T*
operator AtSmartPtr<const T> () { return AtSmartPtr<const T>(ptr); }
// Override ->
T* operator->() const { return ptr; }
// Test whether the pointer is pointing to anything
operator bool() const { return ptr!=NULL; }
bool operator!() const { return ptr==NULL; }
private:
void inc_ref();
void dec_ref();
T* ptr;
};
// A few required declarations
class AtObj;
class AtNode;
class AtIterImpl;
//////////////////////////////////////////////////////////////////////////
// Public bits:
// AtIter is an iterator over AtObjs - use it like:
//
// for (AtIter thing = whatever["thing"]; thing.defined(); ++thing)
// DoStuff(thing);
//
// to handle XML data like:
//
// <whatever>
// <thing>Stuff 1</thing>
// <thing>Stuff 2</thing>
// </whatever>
class AtIter
{
public:
// Increment the iterator; or make it undefined, if there weren't any
// AtObjs left to iterate over
AtIter& operator ++ ();
// Return whether this iterator has an AtObj to point to
bool defined() const;
// Return an iterator to the children matching 'key'. (That is, children
// of the AtObj currently pointed to by this iterator)
const AtIter operator [] (const char* key) const;
// Return the AtObj currently pointed to by this iterator
operator const AtObj () const;
// Return the string value of the AtObj currently pointed to by this iterator
operator const wchar_t* () const;
#ifdef __WXWINDOWS__
// Wrapper function around 'operator wchar_t*', for convenience in wx programs
operator const wxString () const { return (const wchar_t*)*this; }
#endif
// Private implementation. (But not 'private:', because it's a waste of time
// adding loads of friend functions)
AtSmartPtr<AtIterImpl> p;
};
class AtObj
{
public:
AtObj() {}
AtObj(const AtObj& r) : p(r.p) {}
// Return an iterator to the children matching 'key'
const AtIter operator [] (const char* key) const;
// Return the string value of this object
operator const wchar_t* () const;
// Check whether the object contains anything (even if those things are empty)
bool isNull() const { return !p; }
// Check recursively whether there's actually any non-empty data in the object
bool isContentless() const;
// Add or set a child. The wchar_t* versions create a new AtObj with
// the appropriate string value, then use that as the child.
//
// These alter the AtObj's internal pointer, and the pointed-to data is
// never actually altered. Copies of this AtObj (including copies stored
// inside other AtObjs) will not be affected.
void add(const char* key, const wchar_t* value);
void add(const char* key, AtObj& data);
void set(const char* key, const wchar_t* value);
void set(const char* key, AtObj& data);
AtSmartPtr<const AtNode> p;
};
// Miscellaneous utility functions:
namespace AtlasObject
{
void LoadFromXML(AtObj& obj, const wchar_t* filename);
void SaveToXML(AtObj& obj, const wchar_t* filename);
};
#endif // ATLASOBJECT_H__

View File

@ -0,0 +1,127 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="AtlasObject"
ProjectGUID="{228B468D-3C2E-45BF-9833-C626E1A35B04}"
Keyword="Win32Proj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
IntermediateDirectory="Debug"
ConfigurationType="4"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="../../../../libraries/xerces/include"
PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
MinimalRebuild="TRUE"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLibrarianTool"
OutputFile="$(OutDir)/AtlasObject.lib"
AdditionalLibraryDirectories="E:\0ad\svnc\trunk\libraries\xerces\lib"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="Release"
IntermediateDirectory="Release"
ConfigurationType="4"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="1"
AdditionalIncludeDirectories="../../../../libraries/xerces/include"
PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
RuntimeLibrary="2"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="3"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLibrarianTool"
OutputFile="$(OutDir)/AtlasObject.lib"
AdditionalLibraryDirectories="E:\0ad\svnc\trunk\libraries\xerces\lib"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
<File
RelativePath=".\AtlasObject.h">
</File>
<File
RelativePath=".\AtlasObjectImpl.cpp">
</File>
<File
RelativePath=".\AtlasObjectImpl.h">
</File>
<File
RelativePath=".\AtlasObjectText.cpp">
</File>
<File
RelativePath=".\AtlasObjectText.h">
</File>
<File
RelativePath=".\AtlasObjectXML.cpp">
</File>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@ -0,0 +1,190 @@
#include "AtlasObject.h"
#include "AtlasObjectImpl.h"
#include <sstream>
#include <stdlib.h>
#include <assert.h>
#define ATSMARTPTR_IMPL(T) \
template<> void AtSmartPtr<T>::inc_ref() \
{ \
if (ptr) ++ptr->refcount; \
} \
\
template<> void AtSmartPtr<T>::dec_ref() \
{ \
if (ptr && --ptr->refcount == 0) \
delete ptr; \
} // (Don't set ptr=NULL, since it should never be possible for an
// unreferenced pointer to exist; I would rather see it die in debug
// mode if that ever happens, instead of just silently ignoring the error.)
ATSMARTPTR_IMPL(AtNode);
ATSMARTPTR_IMPL(const AtNode);
ATSMARTPTR_IMPL(AtIterImpl);
//////////////////////////////////////////////////////////////////////////
const AtIter AtIter::operator [] (const char* key) const
{
if (p)
return p->iter->second->getChild(key);
else
return AtIter();
}
AtIter::operator const wchar_t* () const
{
if (p)
return p->iter->second->value.c_str();
else
return L"";
}
AtIter::operator const AtObj () const
{
if (p)
{
AtObj ret;
ret.p = p->iter->second;
return ret;
}
else
return AtObj();
}
AtIter& AtIter::operator ++ ()
{
assert(p);
// Increment the internal iterator, and stop if we've run out children
// to iterate over.
if (p && ++p->iter == p->iter_upperbound)
p = NULL;
return *this;
}
bool AtIter::defined() const
{
return (p != NULL);
}
//////////////////////////////////////////////////////////////////////////
const AtIter AtObj::operator [] (const char* key) const
{
if (p)
return p->getChild(key);
else
// This object doesn't exist, so return another object that doesn't exist
return AtIter();
}
AtObj::operator const wchar_t* () const
{
if (p)
return p->value.c_str();
else
return L"";
}
void AtObj::add(const char* key, AtObj& data)
{
if (!p)
p = new AtNode();
p = p->addChild(key, data.p);
}
void AtObj::add(const char* key, const wchar_t* value)
{
const AtNode* o = new AtNode(value);
if (!p)
p = new AtNode();
p = p->addChild(key, AtNode::Ptr(o));
}
void AtObj::set(const char* key, AtObj& data)
{
if (!p)
p = new AtNode();
p = p->setChild(key, data.p);
}
void AtObj::set(const char* key, const wchar_t* value)
{
const AtNode* o = new AtNode(value);
if (!p)
p = new AtNode();
p = p->setChild(key, AtNode::Ptr(o));
}
bool AtObj::isContentless() const
{
if (! p)
return true;
return ! p->hasContent();
}
//////////////////////////////////////////////////////////////////////////
const AtIter AtNode::getChild(const char* key) const
{
// Find the range of matching children
AtNode::child_maptype::const_iterator it = children.lower_bound(key);
AtNode::child_maptype::const_iterator it_upper = children.upper_bound(key);
if (it == it_upper) // No match found
return AtIter();
AtIter obj;
obj.p = new AtIterImpl(it, it_upper);
return obj;
}
bool AtNode::hasContent() const
{
if (value.length())
return true;
for (child_maptype::const_iterator it = children.begin(); it != children.end(); ++it)
if (it->second->hasContent())
return true;
return false;
}
const AtNode::Ptr AtNode::setValue(const wchar_t* value) const
{
AtNode* newNode = new AtNode();
newNode->children = children;
newNode->value = value;
return AtNode::Ptr(newNode);
}
const AtNode::Ptr AtNode::setChild(const char* key, const AtNode::Ptr &data) const
{
AtNode* newNode = new AtNode(this);
newNode->children.erase(key);
newNode->children.insert(AtNode::child_pairtype(key, data));
return AtNode::Ptr(newNode);
}
const AtNode::Ptr AtNode::addChild(const char* key, const AtNode::Ptr &data) const
{
AtNode* newNode = new AtNode(this);
newNode->children.insert(AtNode::child_pairtype(key, data));
return AtNode::Ptr(newNode);
}

View File

@ -0,0 +1,58 @@
#include "AtlasObject.h"
#include <string>
#include <map>
// AtNode is an immutable tree node, with a string and and multimap of children.
class AtNode
{
friend class AtSmartPtr<AtNode>;
friend class AtSmartPtr<const AtNode>;
public:
typedef AtSmartPtr<const AtNode> Ptr;
AtNode() : refcount(0) {}
explicit AtNode(const AtNode* n) { *this = *n; refcount = 0; }
explicit AtNode(const wchar_t* text) : refcount(0), value(text) {}
// Create a new AtNode (since AtNodes are immutable, so it's not possible
// to just change this one), with the relevant alterations to its content.
const AtNode::Ptr setValue(const wchar_t* value) const;
const AtNode::Ptr addChild(const char* key, const AtNode::Ptr &data) const;
const AtNode::Ptr setChild(const char* key, const AtNode::Ptr &data) const;
const AtIter getChild(const char* key) const;
// Check recursively for any 'value' data
bool hasContent() const;
//private: // (but not actually private, since I'm still too lazy to waste
// time with dozens of friends)
std::wstring value;
typedef std::multimap<const std::string, const AtNode::Ptr> child_maptype;
typedef std::pair<const std::string, const AtNode::Ptr> child_pairtype;
child_maptype children;
private:
mutable unsigned int refcount;
};
// Implementation of AtIter
class AtIterImpl
{
friend class AtSmartPtr<AtIterImpl>;
public:
AtIterImpl() : refcount(0) {}
AtIterImpl(AtNode::child_maptype::const_iterator it, AtNode::child_maptype::const_iterator up)
: refcount(0), iter(it), iter_upperbound(up) {}
AtNode::child_maptype::const_iterator iter, iter_upperbound;
private:
mutable unsigned int refcount;
};

View File

@ -0,0 +1,56 @@
#include "AtlasObjectText.h"
#include "AtlasObjectImpl.h"
#include "AtlasObject.h"
static std::wstring ConvertRecursive(const AtNode::Ptr obj, bool use_brackets = true)
{
// Convert (1, ()) into "1"
// Convert (3, (d: (...), e: (...))) into "3 (conv(...), conv(...))"
// etc
// resulting in data-loss [because of the key names], and a rather arbitrary
// [alphabetical by key] ordering of children, but at least it's fairly readable
if (! obj)
return L"";
std::wstring result;
bool has_value = (obj->value.length() != 0);
bool has_children = (obj->children.size() != 0);
if (has_value && has_children)
result = obj->value + L" ";
else if (has_value)
result = obj->value;
// else no value; result = L""
if (has_children)
{
if (use_brackets)
result += L"(";
bool first_child = true; // so we can add ", " in appropriate places
for (AtNode::child_maptype::const_iterator it = obj->children.begin();
it != obj->children.end();
++it)
{
if (! first_child)
result += L", ";
else
first_child = false;
result += ConvertRecursive(it->second);
}
if (use_brackets)
result += L")";
}
return result;
}
std::wstring AtlasObject::ConvertToString(const AtObj& obj)
{
return ConvertRecursive(obj.p, false);
}

View File

@ -0,0 +1,22 @@
// Public interface to text-related functions that make use of std::wstring
//
// (This is done in order to avoid forcing inclusion of all the
// STL headers when they're not needed)
#ifdef new // HACK: to make the STL headers happy with a redefined 'new'
# undef new
# include <string>
# define new new(_NORMAL_BLOCK ,__FILE__, __LINE__)
#else
# include <string>
#endif
class AtObj;
namespace AtlasObject
{
// Generate a human-readable string representation of the AtObj,
// as an easy way of visualising the data (without any horridly ugly
// XML junk)
std::wstring ConvertToString(const AtObj& obj);
}

View File

@ -0,0 +1,177 @@
#include "AtlasObject.h"
#include "AtlasObjectImpl.h"
#include <assert.h>
#ifdef _MSC_VER
# ifndef NDEBUG
# pragma comment(lib, "xerces-c_2D.lib")
# else
# pragma comment(lib, "xerces-c_2.lib")
# endif
#endif
#include <xercesc/parsers/XercesDOMParser.hpp>
#include <xercesc/dom/DOM.hpp>
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/util/XMLString.hpp>
#include <xercesc/framework/LocalFileFormatTarget.hpp>
XERCES_CPP_NAMESPACE_USE
static AtSmartPtr<AtNode> ConvertNode(DOMElement* element);
void AtlasObject::LoadFromXML(AtObj& obj, const wchar_t* filename)
{
// TODO: Convert wchar_t* to XMLCh* when running under GCC
assert(sizeof(wchar_t) == sizeof(XMLCh));
XMLPlatformUtils::Initialize();
XercesDOMParser* parser = new XercesDOMParser();
parser->setValidationScheme(XercesDOMParser::Val_Never);
parser->setCreateEntityReferenceNodes(false);
parser->parse((XMLCh*)filename);
if (parser->getErrorCount() != 0)
{
assert(! "Error while loading XML - invalid XML data?");
return;
}
DOMDocument* doc = parser->getDocument();
DOMElement* root = doc->getDocumentElement();
obj.p = ConvertNode(root);
// TODO: Initialise/terminate properly
// XMLPlatformUtils::Terminate();
}
// Convert from a DOMElement to an AtNode
static AtSmartPtr<AtNode> ConvertNode(DOMElement* element)
{
AtSmartPtr<AtNode> obj (new AtNode());
// Loop through all child elements
DOMNodeList* children = element->getChildNodes();
XMLSize_t len = children->getLength();
for (XMLSize_t i = 0; i < len; ++i)
{
DOMNode* node = children->item(i);
short type = node->getNodeType();
if (type == DOMNode::ELEMENT_NODE)
{
// Sub-element.
// Use its name for the AtNode key
char* name = XMLString::transcode(node->getNodeName());
const std::string namestr (name);
// Recursively convert the sub-element, and add it into this node
AtNode::child_pairtype n (
namestr, ConvertNode((DOMElement*)node)
);
obj->children.insert(n);
// Free memory
XMLString::release(&name);
}
else if (type == DOMNode::TEXT_NODE)
{
// Text inside the element. Append it to the current node's string.
// TODO: Make this work on GCC, where wchar_t != XMLCh
std::wstring value_wstr (node->getNodeValue());
obj->value += value_wstr;
}
}
// Trim whitespace surrounding the string value
const std::wstring whitespace = L" \t\r\n";
size_t first = obj->value.find_first_not_of(whitespace);
if (first == std::wstring::npos)
obj->value = L"";
else
{
size_t last = obj->value.find_last_not_of(whitespace);
obj->value = obj->value.substr(first, 1+last-first);
}
return obj;
}
// Build a DOM node from a given AtNode
static DOMNode* BuildDOM(DOMDocument* doc, const XMLCh* name, AtNode::Ptr p)
{
DOMElement* node = doc->createElement(name);
if (p)
{
// TODO: make this work on GCC
node->setTextContent(p->value.c_str());
XMLCh tempStr[256]; // urgh, nasty fixed-size buffer
for (AtNode::child_maptype::const_iterator it = p->children.begin(); it != p->children.end(); ++it)
{
XMLString::transcode(it->first.c_str(), tempStr, 255);
node->appendChild(BuildDOM(doc, tempStr, it->second));
}
}
return node;
}
void AtlasObject::SaveToXML(AtObj& obj, const wchar_t* filename)
{
// TODO: Convert wchar_t* to XMLCh* when running under GCC
assert(sizeof(wchar_t) == sizeof(XMLCh));
XMLPlatformUtils::Initialize();
// Why does it take so much work just to create a DOMWriter? :-(
XMLCh tempStr[100];
XMLString::transcode("LS", tempStr, 99);
DOMImplementation* impl = DOMImplementationRegistry::getDOMImplementation(tempStr);
DOMWriter* writer = ((DOMImplementationLS*)impl)->createDOMWriter();
if (writer->canSetFeature(XMLUni::fgDOMWRTDiscardDefaultContent, true))
writer->setFeature(XMLUni::fgDOMWRTDiscardDefaultContent, true);
if (writer->canSetFeature(XMLUni::fgDOMWRTFormatPrettyPrint, true))
writer->setFeature(XMLUni::fgDOMWRTFormatPrettyPrint, true);
DOMDocument* doc = impl->createDocument();
doc->appendChild(BuildDOM(doc, L"actor", obj.p)); // TODO: this is stupid
try
{
XMLFormatTarget* FormatTarget = new LocalFileFormatTarget((XMLCh*)filename);
writer->writeNode(FormatTarget, *doc);
delete FormatTarget;
}
catch (const XMLException& e) {
char* message = XMLString::transcode(e.getMessage());
assert(! "XML exception - maybe failed while writing the file");
XMLString::release(&message);
XMLPlatformUtils::Terminate();
return;
}
catch (const DOMException& e) {
char* message = XMLString::transcode(e.msg);
assert(! "DOM exception");
XMLString::release(&message);
XMLPlatformUtils::Terminate();
return;
}
writer->release();
// XMLPlatformUtils::Terminate();
}

View File

@ -0,0 +1,88 @@
#include "stdafx.h"
#include "ActorEditor.h"
#include "ActorEditorListCtrl.h"
#include "AtlasObject/AtlasObject.h"
#include "wx/panel.h"
#include "wx/sizer.h"
ActorEditor::ActorEditor(wxWindow* parent)
: AtlasWindow(parent, _("Actor Editor"), wxSize(1024, 450))
{
wxPanel* mainPanel = new wxPanel(this);
m_ActorEditorListCtrl = new ActorEditorListCtrl(mainPanel);
wxBoxSizer* vertSizer = new wxBoxSizer(wxVERTICAL);
mainPanel->SetSizer(vertSizer);
wxBoxSizer* topSizer = new wxBoxSizer(wxHORIZONTAL);
vertSizer->Add(topSizer,
wxSizerFlags().Border(wxLEFT|wxRIGHT, 5));
vertSizer->Add(
m_ActorEditorListCtrl,
wxSizerFlags().Proportion(1).Expand().Border(wxALL, 10));
//////////////////////////////////////////////////////////////////////////
// Properties panel:
wxPanel* propertiesPanel = new wxPanel(mainPanel);
topSizer->Add(propertiesPanel, wxSizerFlags().Expand().Border(wxLEFT|wxRIGHT, 5));
wxSizer* propertiesSizer = new wxStaticBoxSizer(
new wxStaticBox(propertiesPanel, wxID_ANY, _("Actor properties")),
wxHORIZONTAL);
propertiesPanel->SetSizer(propertiesSizer);
m_CastShadows = new wxCheckBox(propertiesPanel, wxID_ANY, _("Cast shadow"));
propertiesSizer->Add(m_CastShadows, wxSizerFlags().Border(wxALL, 5));
// TODO: Orientation property.
//////////////////////////////////////////////////////////////////////////
// Materials box:
wxPanel* materialsPanel = new wxPanel(mainPanel);
topSizer->Add(materialsPanel, wxSizerFlags().Expand().Border(wxLEFT|wxRIGHT, 5));
wxSizer* materialsSizer = new wxStaticBoxSizer(
new wxStaticBox(materialsPanel, wxID_ANY, _("Material")),
wxHORIZONTAL);
materialsPanel->SetSizer(materialsSizer);
m_Material = new wxTextCtrl(materialsPanel, wxID_ANY, _T(""));
materialsSizer->Add(m_Material, wxSizerFlags().Border(wxALL, 2));
//////////////////////////////////////////////////////////////////////////
}
void ActorEditor::Import(AtObj& in)
{
m_ActorEditorListCtrl->Import(in);
if (in["castshadow"].defined())
m_CastShadows->SetValue(true);
else
m_CastShadows->SetValue(false);
m_Material->SetValue(in["material"]);
}
void ActorEditor::Export(AtObj& out)
{
m_ActorEditorListCtrl->Export(out);
if (m_CastShadows->IsChecked())
out.set("castshadow", L"true");
out.set("material", m_Material->GetValue().c_str());
}

View File

@ -0,0 +1,19 @@
#include "AtlasWindow.h"
class ActorEditorListCtrl;
class ActorEditor : public AtlasWindow
{
public:
ActorEditor(wxWindow* parent);
protected:
void Import(AtObj& in);
void Export(AtObj& out);
private:
ActorEditorListCtrl* m_ActorEditorListCtrl;
wxCheckBox* m_CastShadows;
wxTextCtrl* m_Material;
};

View File

@ -0,0 +1,57 @@
#include "stdafx.h"
#include "ActorEditorListCtrl.h"
#include "AtlasObject/AtlasObject.h"
#include "FieldEditCtrl.h"
ActorEditorListCtrl::ActorEditorListCtrl(wxWindow* parent)
: DraggableListCtrl(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize,
wxLC_REPORT | wxLC_HRULES | wxLC_VRULES | wxLC_SINGLE_SEL)
{
AddColumnType(_("Variant"), 100, "name", new FieldEditCtrl_Text());
AddColumnType(_("Freq"), 50, "frequency", new FieldEditCtrl_Text());
AddColumnType(_("Model"), 160, "mesh", new FieldEditCtrl_Text());
AddColumnType(_("Texture"), 160, "texture", new FieldEditCtrl_Text());
AddColumnType(_("Animations"), 250, "animations", new FieldEditCtrl_Dialog(_T("AnimListEditor")));
AddColumnType(_("Props"), 250, "props", new FieldEditCtrl_Dialog(_T("PropListEditor")));
}
void ActorEditorListCtrl::Import(AtObj& in)
{
DeleteData();
for (AtIter group = in["group"]; group.defined(); ++group)
{
for (AtIter variant = group["variant"]; variant.defined(); ++variant)
AddRow(variant);
AtObj blank;
AddRow(blank);
}
UpdateDisplay();
}
void ActorEditorListCtrl::Export(AtObj& out)
{
AtObj group;
for (size_t i = 0; i < m_ListData.size(); ++i)
{
if (IsRowBlank((int)i))
{
if (! group.isNull())
out.add("group", group);
group = AtObj();
}
else
{
AtObj variant = m_ListData[i];
group.add("variant", variant);
}
}
if (! group.isNull())
out.add("group", group);
}

View File

@ -0,0 +1,19 @@
#include "DraggableListCtrl.h"
#include "IAtlasExporter.h"
class ActorEditor;
class ActorEditorListCtrl : public DraggableListCtrl, public IAtlasExporter
{
friend class ActorEditor;
public:
ActorEditorListCtrl(wxWindow* parent);
void OnUpdate(wxCommandEvent& event);
private:
void Import(AtObj& in);
void Export(AtObj& out);
};

View File

@ -0,0 +1,57 @@
#include "stdafx.h"
#include "AnimListEditor.h"
#include "FieldEditCtrl.h"
#include "AtlasObject/AtlasObject.h"
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_DYNAMIC_CLASS(AnimListEditor, AtlasDialog);
AnimListEditor::AnimListEditor()
: AtlasDialog(NULL, _("Animation editor"))
{
m_MainListBox = new AnimListEditorListCtrl(m_MainPanel);
wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
sizer->Add(m_MainListBox,
wxSizerFlags().Proportion(1).Expand().Border(wxALL, 5));
m_MainPanel->SetSizer(sizer);
}
void AnimListEditor::Import(AtObj& in)
{
m_MainListBox->Import(in);
}
void AnimListEditor::Export(AtObj& out)
{
m_MainListBox->Export(out);
}
//////////////////////////////////////////////////////////////////////////
AnimListEditorListCtrl::AnimListEditorListCtrl(wxWindow* parent)
: DraggableListCtrl(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize,
wxLC_REPORT | wxLC_HRULES | wxLC_VRULES | wxLC_SINGLE_SEL)
{
AddColumnType(_("Anim name"), 100, "name", new FieldEditCtrl_Text());
AddColumnType(_("File"), 200, "file", new FieldEditCtrl_Text());
AddColumnType(_("Speed"), 50, "speed", new FieldEditCtrl_Text());
}
void AnimListEditorListCtrl::Import(AtObj& in)
{
for (AtIter prop = in["animation"]; prop.defined(); ++prop)
AddRow(prop);
UpdateDisplay();
}
void AnimListEditorListCtrl::Export(AtObj& out)
{
for (size_t i = 0; i < m_ListData.size(); ++i)
out.add("animation", m_ListData[i]);
}

View File

@ -0,0 +1,38 @@
#include "AtlasDialog.h"
#include "DraggableListCtrl.h"
#include "IAtlasExporter.h"
class AnimListEditorListCtrl;
//////////////////////////////////////////////////////////////////////////
class AnimListEditor : public AtlasDialog
{
DECLARE_DYNAMIC_CLASS(AnimListEditor);
public:
AnimListEditor();
protected:
void Import(AtObj& in);
void Export(AtObj& out);
private:
AnimListEditorListCtrl* m_MainListBox;
};
//////////////////////////////////////////////////////////////////////////
class AnimListEditorListCtrl : public DraggableListCtrl, public IAtlasExporter
{
friend class AnimListEditor;
public:
AnimListEditorListCtrl(wxWindow* parent);
void OnUpdate(wxCommandEvent& event);
void Import(AtObj& in);
void Export(AtObj& out);
};

View File

@ -0,0 +1,56 @@
#include "stdafx.h"
#include "PropListEditor.h"
#include "FieldEditCtrl.h"
#include "AtlasObject/AtlasObject.h"
//////////////////////////////////////////////////////////////////////////
IMPLEMENT_DYNAMIC_CLASS(PropListEditor, AtlasDialog);
PropListEditor::PropListEditor()
: AtlasDialog(NULL, _("Prop editor"))
{
m_MainListBox = new PropListEditorListCtrl(m_MainPanel);
wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
sizer->Add(m_MainListBox,
wxSizerFlags().Proportion(1).Expand().Border(wxALL, 5));
m_MainPanel->SetSizer(sizer);
}
void PropListEditor::Import(AtObj& in)
{
m_MainListBox->Import(in);
}
void PropListEditor::Export(AtObj& out)
{
m_MainListBox->Export(out);
}
//////////////////////////////////////////////////////////////////////////
PropListEditorListCtrl::PropListEditorListCtrl(wxWindow* parent)
: DraggableListCtrl(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize,
wxLC_REPORT | wxLC_HRULES | wxLC_VRULES | wxLC_SINGLE_SEL)
{
AddColumnType(_("Attachment point"), 100, "attachpoint", new FieldEditCtrl_Text());
AddColumnType(_("Prop model"), 200, "model", new FieldEditCtrl_Text());
}
void PropListEditorListCtrl::Import(AtObj& in)
{
for (AtIter prop = in["prop"]; prop.defined(); ++prop)
AddRow(prop);
UpdateDisplay();
}
void PropListEditorListCtrl::Export(AtObj& out)
{
for (size_t i = 0; i < m_ListData.size(); ++i)
out.add("prop", m_ListData[i]);
}

View File

@ -0,0 +1,38 @@
#include "AtlasDialog.h"
#include "DraggableListCtrl.h"
#include "IAtlasExporter.h"
class PropListEditorListCtrl;
//////////////////////////////////////////////////////////////////////////
class PropListEditor : public AtlasDialog
{
DECLARE_DYNAMIC_CLASS(PropListEditor);
public:
PropListEditor();
protected:
void Import(AtObj& in);
void Export(AtObj& out);
private:
PropListEditorListCtrl* m_MainListBox;
};
//////////////////////////////////////////////////////////////////////////
class PropListEditorListCtrl : public DraggableListCtrl, public IAtlasExporter
{
friend class PropListEditor;
public:
PropListEditorListCtrl(wxWindow* parent);
void OnUpdate(wxCommandEvent& event);
void Import(AtObj& in);
void Export(AtObj& out);
};

View File

@ -0,0 +1,270 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="AtlasUI"
ProjectGUID="{E99BA969-D540-4F23-822E-37C499E8F704}"
Keyword="Win32Proj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
IntermediateDirectory="Debug"
ConfigurationType="1"
CharacterSet="1">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories=".;..;.\General;.\CustomControls\EditableListCtrl;.\CustomControls\DraggableListCtrl;.\CustomControls\Windows;.\Misc;E:\wx\wxWidgets\include;E:\wx\wxWidgets\include\msvc"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS"
MinimalRebuild="TRUE"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="3"
WarningLevel="4"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="comctl32.lib rpcrt4.lib"
OutputFile="$(OutDir)/actored.exe"
LinkIncremental="2"
AdditionalLibraryDirectories="E:\wx\wxWidgets\lib\vc_lib;E:\0ad\svnc\trunk\libraries\xerces\lib"
GenerateDebugInformation="TRUE"
ProgramDatabaseFile="$(OutDir)/actored.pdb"
SubSystem="2"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="Release"
IntermediateDirectory="Release"
ConfigurationType="1"
CharacterSet="1">
<Tool
Name="VCCLCompilerTool"
Optimization="1"
AdditionalIncludeDirectories=".;..;.\General;.\CustomControls\EditableListCtrl;.\CustomControls\DraggableListCtrl;.\CustomControls\Windows;.\Misc;E:\wx\wxWidgets\include;E:\wx\wxWidgets\include\msvc"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
StringPooling="TRUE"
RuntimeLibrary="2"
UsePrecompiledHeader="3"
WarningLevel="4"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="3"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="comctl32.lib rpcrt4.lib"
OutputFile="$(OutDir)/actored.exe"
LinkIncremental="1"
AdditionalLibraryDirectories="E:\wx\wxWidgets\lib\vc_lib;E:\0ad\svnc\trunk\libraries\xerces\lib"
GenerateDebugInformation="FALSE"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
OptimizeForWindows98="1"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
<Filter
Name="General"
Filter="">
<File
RelativePath=".\General\AtlasWindowCommand.cpp">
</File>
<File
RelativePath=".\General\AtlasWindowCommand.h">
</File>
<File
RelativePath=".\General\AtlasWindowCommandProc.cpp">
</File>
<File
RelativePath=".\General\AtlasWindowCommandProc.h">
</File>
<File
RelativePath=".\General\IAtlasExporter.h">
</File>
</Filter>
<Filter
Name="CustomControls"
Filter="">
<Filter
Name="EditableListCtrl"
Filter="">
<File
RelativePath=".\CustomControls\EditableListCtrl\EditableListCtrl.cpp">
</File>
<File
RelativePath=".\CustomControls\EditableListCtrl\EditableListCtrl.h">
</File>
<File
RelativePath=".\CustomControls\EditableListCtrl\FieldEditCtrl.cpp">
</File>
<File
RelativePath=".\CustomControls\EditableListCtrl\FieldEditCtrl.h">
</File>
<File
RelativePath=".\CustomControls\EditableListCtrl\ListCtrlValidator.cpp">
</File>
<File
RelativePath=".\CustomControls\EditableListCtrl\ListCtrlValidator.h">
</File>
<File
RelativePath=".\CustomControls\EditableListCtrl\QuickTextCtrl.cpp">
</File>
<File
RelativePath=".\CustomControls\EditableListCtrl\QuickTextCtrl.h">
</File>
</Filter>
<Filter
Name="DraggableListCtrl"
Filter="">
<File
RelativePath=".\CustomControls\DraggableListCtrl\DraggableListCtrl.cpp">
</File>
<File
RelativePath=".\CustomControls\DraggableListCtrl\DraggableListCtrl.h">
</File>
<File
RelativePath=".\CustomControls\DraggableListCtrl\DraggableListCtrlCommands.cpp">
</File>
<File
RelativePath=".\CustomControls\DraggableListCtrl\DraggableListCtrlCommands.h">
</File>
</Filter>
<Filter
Name="Windows"
Filter="">
<File
RelativePath=".\CustomControls\Windows\AtlasDialog.cpp">
</File>
<File
RelativePath=".\CustomControls\Windows\AtlasDialog.h">
</File>
<File
RelativePath=".\CustomControls\Windows\AtlasWindow.cpp">
</File>
<File
RelativePath=".\CustomControls\Windows\AtlasWindow.h">
</File>
</Filter>
</Filter>
<Filter
Name="ActorEditor"
Filter="">
<File
RelativePath=".\ActorEditor\ActorEditor.cpp">
</File>
<File
RelativePath=".\ActorEditor\ActorEditor.h">
</File>
<File
RelativePath=".\ActorEditor\ActorEditorListCtrl.cpp">
</File>
<File
RelativePath=".\ActorEditor\ActorEditorListCtrl.h">
</File>
<File
RelativePath=".\ActorEditor\AnimListEditor.cpp">
</File>
<File
RelativePath=".\ActorEditor\AnimListEditor.h">
</File>
<File
RelativePath=".\ActorEditor\PropListEditor.cpp">
</File>
<File
RelativePath=".\ActorEditor\PropListEditor.h">
</File>
</Filter>
<Filter
Name="Misc"
Filter="">
<File
RelativePath=".\Misc\actored.cpp">
</File>
<File
RelativePath=".\Misc\actored.h">
</File>
<File
RelativePath=".\Misc\stdafx.cpp">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"/>
</FileConfiguration>
</File>
<File
RelativePath=".\Misc\stdafx.h">
</File>
</Filter>
</Filter>
<File
RelativePath=".\TODO.txt">
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@ -0,0 +1,143 @@
#include "stdafx.h"
#include "DraggableListCtrl.h"
#include "AtlasWindowCommandProc.h"
#include "DraggableListCtrlCommands.h"
//DEFINE_EVENT_TYPE(wxEVT_LISTCTRL_UPDATED);
const int ScrollSpeed = 8; // when dragging off the top or bottom of the control
DraggableListCtrl::DraggableListCtrl(wxWindow *parent,
wxWindowID id,
const wxPoint& pos,
const wxSize& size,
long style,
const wxValidator& validator,
const wxString& name)
: EditableListCtrl(parent, id, pos, size, style, validator, name)
, m_DragSource(0)
{
}
// TODO:
// * Dragging of multiple selections?
void DraggableListCtrl::OnBeginDrag(wxListEvent& WXUNUSED(event))
{
CaptureMouse();
SetFocus();
}
void DraggableListCtrl::OnEndDrag()
{
AtlasWindowCommandProc* commandProc = AtlasWindowCommandProc::GetFromParentFrame(this);
commandProc->FinaliseLastCommand();
SetSelection(m_DragSource);
//commandProc->Store(new DragCommand(this, m_InitialDragSource, m_DragSource));
}
void DraggableListCtrl::OnItemSelected(wxListEvent& event)
{
// Don't respond while in drag-mode - only the initial selection
// (when starting the drag operation) should be handled
if (! HasCapture())
{
// Remember which item is being dragged
m_DragSource = event.GetIndex();
// Make sure this listctrl is in focus
SetFocus();
}
}
void DraggableListCtrl::OnMouseCaptureChanged(wxMouseCaptureChangedEvent& WXUNUSED(event))
{
OnEndDrag();
}
void DraggableListCtrl::OnMouseEvent(wxMouseEvent& event)
{
// Only care when in drag-mode
if (! HasCapture())
{
event.Skip();
return;
}
if (event.LeftUp())
{
// Finished dragging; stop responding to mouse motion
ReleaseMouse();
}
else if (event.Dragging())
{
// Find which item the mouse is now over
int flags;
long dragTarget = HitTest(event.GetPosition(), flags);
if (dragTarget == wxNOT_FOUND)
{
// Not over an item. Scroll the view up/down if the mouse is
// outside the listctrl.
if (flags & wxLIST_HITTEST_ABOVE)
ScrollList(0, -ScrollSpeed);
else if (flags & wxLIST_HITTEST_BELOW)
ScrollList(0, ScrollSpeed);
}
else
if (flags & wxLIST_HITTEST_ONITEM && dragTarget != m_DragSource)
{
// Move the source item to the location under the mouse
AtlasWindowCommandProc* commandProc = AtlasWindowCommandProc::GetFromParentFrame(this);
commandProc->Submit(new DragCommand(this, m_DragSource, dragTarget));
// and remember that the source item is now in a different place
m_DragSource = dragTarget;
}
}
else
// Some other kind of event which we're not interested in - ignore it
event.Skip();
}
void DraggableListCtrl::OnChar(wxKeyEvent& event)
{
// Don't respond to the keyboard if the user is dragging things (else
// the undo system might get slightly confused)
if (HasCapture())
return;
if (event.GetKeyCode() == WXK_DELETE)
{
long item = GetNextItem(-1,
wxLIST_NEXT_ALL,
wxLIST_STATE_SELECTED);
if (item != -1)
{
AtlasWindowCommandProc::GetFromParentFrame(this)->Submit(
new DeleteCommand(this, item)
);
UpdateDisplay();
}
}
else
{
event.Skip();
}
}
BEGIN_EVENT_TABLE(DraggableListCtrl, EditableListCtrl)
EVT_LIST_BEGIN_DRAG(wxID_ANY, DraggableListCtrl::OnBeginDrag)
EVT_LIST_ITEM_SELECTED(wxID_ANY, DraggableListCtrl::OnItemSelected)
EVT_MOTION(DraggableListCtrl::OnMouseEvent)
EVT_LEFT_UP(DraggableListCtrl::OnMouseEvent)
EVT_CHAR(DraggableListCtrl::OnChar)
EVT_MOUSE_CAPTURE_CHANGED(DraggableListCtrl::OnMouseCaptureChanged)
END_EVENT_TABLE()

View File

@ -0,0 +1,37 @@
/*
DraggableListCtrl
Based on wxListCtrl, but items can be reordered by dragging them around.
Use just like a normal listctrl.
*/
#include "EditableListCtrl.h"
class DragCommand;
class DraggableListCtrl : public EditableListCtrl
{
friend class DragCommand;
public:
DraggableListCtrl(wxWindow *parent,
wxWindowID id = wxID_ANY,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
long style = wxLC_ICON,
const wxValidator& validator = wxDefaultValidator,
const wxString& name = wxListCtrlNameStr);
void OnBeginDrag(wxListEvent& event);
void OnEndDrag();
void OnItemSelected(wxListEvent& event);
void OnMouseEvent(wxMouseEvent& event);
void OnChar(wxKeyEvent& event);
void OnMouseCaptureChanged(wxMouseCaptureChangedEvent& event);
private:
long m_DragSource;
DECLARE_EVENT_TABLE();
};

View File

@ -0,0 +1,109 @@
#include "stdafx.h"
#include "DraggableListCtrlCommands.h"
#include "DraggableListCtrl.h"
#include "EditableListCtrl.h"
IMPLEMENT_CLASS(DragCommand, AtlasWindowCommand);
DragCommand::DragCommand(DraggableListCtrl* ctrl, long src, long tgt)
: AtlasWindowCommand(true, _("Drag")), m_Ctrl(ctrl), m_Src(src), m_Tgt(tgt)
{
}
bool DragCommand::Do()
{
wxASSERT(m_Tgt >= 0 && m_Src >= 0);
m_Ctrl->CloneListData(m_OldData);
m_Ctrl->MakeSizeAtLeast(m_Src+1);
m_Ctrl->MakeSizeAtLeast(m_Tgt+1);
// data[src] will be inserted just before data[tgt].
// If tgt>src, (src+1)..tgt will be shifted down by 1.
// If tgt<src, tgt..(src-1) will be shifted up by 1.
AtObj srcData = m_Ctrl->m_ListData.at(m_Src);
if (m_Tgt > m_Src)
std::copy(
m_Ctrl->m_ListData.begin()+m_Src+1,
m_Ctrl->m_ListData.begin()+m_Tgt+1,
m_Ctrl->m_ListData.begin()+m_Src);
else if (m_Tgt < m_Src)
std::copy_backward(
m_Ctrl->m_ListData.begin()+m_Tgt,
m_Ctrl->m_ListData.begin()+m_Src,
m_Ctrl->m_ListData.begin()+m_Src+1);
else // m_Tgt == m_Src
; // do nothing - this item was just dragged onto itself
m_Ctrl->m_ListData.at(m_Tgt) = srcData;
m_Ctrl->UpdateDisplay();
m_Ctrl->SetSelection(m_Tgt);
return true;
}
bool DragCommand::Undo()
{
m_Ctrl->SetListData(m_OldData);
m_Ctrl->UpdateDisplay();
m_Ctrl->SetSelection(m_Src);
return true;
}
bool DragCommand::Merge(AtlasWindowCommand* command)
{
DragCommand* nextCommand = wxDynamicCast(command, DragCommand);
if (! nextCommand)
return false;
if (nextCommand->m_Src != m_Tgt)
return false;
m_Tgt = nextCommand->m_Tgt;
return true;
}
DeleteCommand::DeleteCommand(DraggableListCtrl* ctrl, long itemID)
: wxCommand(true, _("Delete")), m_Ctrl(ctrl), m_ItemID(itemID)
{
}
bool DeleteCommand::Do()
{
wxASSERT(m_ItemID >= 0);
// If we're asked to delete one of the blank rows off the end of the
// list, don't do anything
if (m_ItemID >= (long)m_Ctrl->m_ListData.size())
return true;
m_Ctrl->CloneListData(m_OldData);
m_Ctrl->m_ListData.erase(m_Ctrl->m_ListData.begin()+m_ItemID);
m_Ctrl->UpdateDisplay();
m_Ctrl->SetSelection(m_ItemID);
return true;
}
bool DeleteCommand::Undo()
{
m_Ctrl->SetListData(m_OldData);
m_Ctrl->UpdateDisplay();
m_Ctrl->SetSelection(m_ItemID);
return true;
}

View File

@ -0,0 +1,41 @@
#include "AtlasWindowCommand.h"
#include "wx/arrstr.h"
#include "AtlasObject/AtlasObject.h"
//#include "RefcntPtr.h"
class DraggableListCtrl;
class DragCommand : public AtlasWindowCommand
{
DECLARE_CLASS(DragCommand)
public:
DragCommand(DraggableListCtrl* ctrl, long src, long tgt);
bool Do();
bool Undo();
private:
bool Merge(AtlasWindowCommand* command);
DraggableListCtrl* m_Ctrl;
long m_Src, m_Tgt;
std::vector<AtObj> m_OldData;
};
class DeleteCommand : public wxCommand
{
public:
DeleteCommand(DraggableListCtrl* ctrl, long itemID);
bool Do();
bool Undo();
private:
DraggableListCtrl* m_Ctrl;
//wxArrayString m_Texts;
long m_ItemID;
//RefcntPtr<AtObj> m_ItemData;
std::vector<AtObj> m_OldData;
};

View File

@ -0,0 +1,238 @@
#include "stdafx.h"
#include "EditableListCtrl.h"
#include "FieldEditCtrl.h"
#include "AtlasObject/AtlasObject.h"
#include "AtlasObject/AtlasObjectText.h"
const int BlanksAtEnd = 2;
EditableListCtrl::EditableListCtrl(wxWindow *parent,
wxWindowID id,
const wxPoint& pos,
const wxSize& size,
long style,
const wxValidator& validator,
const wxString& name)
: wxListCtrl(parent, id, pos, size, style | wxLC_VIRTUAL, validator, name)
{
wxASSERT_MSG(style & wxLC_REPORT, _T("EditableListCtrl must be LC_REPORT"));
UpdateDisplay();
}
EditableListCtrl::~EditableListCtrl()
{
size_t count = m_ColumnTypes.size();
for (size_t n = 0; n < count; ++n)
delete (FieldEditCtrl*)m_ColumnTypes[n].ctrl;
m_ColumnTypes.clear();
}
void EditableListCtrl::AddColumnType(const wxString& title, int width, const char* objectkey, FieldEditCtrl* ctrl)
{
int n = GetColumnCount();
wxASSERT(m_ColumnTypes.size() == (size_t) n); // check internal consistency
InsertColumn(n, title, wxLIST_FORMAT_LEFT, width);
m_ColumnTypes.push_back(ColumnData(objectkey, ctrl));
}
void EditableListCtrl::OnMouseEvent(wxMouseEvent& event)
{
// Double-clicking on a cell lets the user edit it. The editing method
// depends on what column the cell is in.
if (event.LeftDClick())
{
// Work out what cell was clicked on:
wxPoint pt = event.GetPosition();
int col = GetColumnAtPosition(pt);
wxCHECK2(col >= 0 && col < (int)m_ColumnTypes.size(), return);
int flags;
long row = HitTest(pt, flags);
if (row != wxNOT_FOUND && (flags & wxLIST_HITTEST_ONITEM))
{
// Calculate the exact positioning of the clicked cell
wxRect rect;
GetCellRect(row, col, rect);
// Execute the appropriate FieldEditCtrl
FieldEditCtrl* editor = (FieldEditCtrl*)m_ColumnTypes[col].ctrl;
editor->StartEdit(this, rect, row, col);
}
}
}
int EditableListCtrl::GetColumnAtPosition(wxPoint& pos)
{
// Find the column which pos is in.
// Get the origin of the table, in case it's scrolled horizontally
wxRect rect;
GetItemRect(0, rect);
int x = rect.GetX();
// Loop through each column
int numCols = GetColumnCount();
for (int i = 0; i < numCols; ++i)
{
// Calculate the position of this column's right-hand edge
x += GetColumnWidth(i);
// Test if pos was within this column (and assume it wasn't in an earlier one)
if (pos.x <= x)
return i;
}
// Point is outside the table's right edge
return -1;
}
void EditableListCtrl::GetCellRect(long row, int col, wxRect& rect)
{
wxASSERT(col >= 0 && col < GetColumnCount());
wxASSERT(row >= 0 && row < GetItemCount());
GetItemRect(row, rect);
for (int i = 0; i < col; ++i)
rect.x += GetColumnWidth(i);
rect.width = GetColumnWidth(col);
}
bool EditableListCtrl::IsRowBlank(int n)
{
return m_ListData[n].isContentless();
}
void EditableListCtrl::TrimBlankEnds()
{
while (m_ListData.size() && m_ListData.back().isNull())
m_ListData.pop_back();
}
void EditableListCtrl::SetSelection(long item)
{
SetItemState(item, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED);
}
long EditableListCtrl::GetSelection()
{
for (long item = 0; item < GetItemCount(); ++item)
if (GetItemState(item, wxLIST_STATE_SELECTED))
return item;
return 0;
}
void EditableListCtrl::MakeSizeAtLeast(int n)
{
if ((int)m_ListData.size() < n)
m_ListData.resize(n);
}
void EditableListCtrl::AddRow(AtObj& obj)
{
m_ListData.push_back(obj);
}
void EditableListCtrl::AddRow(AtIter& iter)
{
AtObj obj = iter;
AddRow(obj);
}
void EditableListCtrl::UpdateDisplay()
{
TrimBlankEnds();
SetItemCount((int)m_ListData.size() + BlanksAtEnd);
Refresh();
}
void EditableListCtrl::CloneListData(std::vector<AtObj>& out)
{
out = m_ListData;
}
void EditableListCtrl::SetListData(std::vector<AtObj>& in)
{
m_ListData = in;
}
void EditableListCtrl::DeleteData()
{
m_ListData.clear();
}
wxString EditableListCtrl::GetCellString(long item, long column) const
{
wxCHECK(item >= 0 && column >= 0 && column < (int)m_ColumnTypes.size(), _T(""));
if (item >= (int)m_ListData.size())
return _T("");
AtObj cell = m_ListData[item][m_ColumnTypes[column].key];
return AtlasObject::ConvertToString(cell).c_str();
}
AtObj EditableListCtrl::GetCellObject(long item, long column) const
{
wxCHECK(item >= 0 && column >= 0 && column < (int)m_ColumnTypes.size(), AtObj());
if (item >= (int)m_ListData.size())
return AtObj();
return m_ListData[item][m_ColumnTypes[column].key];
}
void EditableListCtrl::SetCellString(long item, long column, wxString& str)
{
wxCHECK(item >= 0 && column >= 0 && column < (int)m_ColumnTypes.size(), );
MakeSizeAtLeast(item+1);
m_ListData[item].set(m_ColumnTypes[column].key, str.c_str());
}
void EditableListCtrl::SetCellObject(long item, long column, AtObj& obj)
{
wxCHECK(item >= 0 && column >= 0 && column < (int)m_ColumnTypes.size(), );
MakeSizeAtLeast(item+1);
m_ListData[item].set(m_ColumnTypes[column].key, obj);
}
wxString EditableListCtrl::OnGetItemText(long item, long column) const
{
return GetCellString(item, column);
}
wxListItemAttr* EditableListCtrl::OnGetItemAttr(long WXUNUSED(item)) const
{
// if (item > (int)m_ListData.size()-BlanksAtEnd)
// {
// static wxListItemAttr attr;
// static int attr_init = 0;
// if (attr_init++ == 0)
// attr.SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT));
//
// return &attr;
// }
// else
return NULL;
}
BEGIN_EVENT_TABLE(EditableListCtrl, wxListCtrl)
EVT_LEFT_DCLICK(EditableListCtrl::OnMouseEvent)
END_EVENT_TABLE()

View File

@ -0,0 +1,82 @@
#ifndef EDITABLELISTCTRL_H__
#define EDITABLELISTCTRL_H__
#include "wx/listctrl.h"
#include "wx/arrstr.h"
#include <vector>
class FieldEditCtrl;
class AtObj;
class AtIter;
class EditableListCtrl : public wxListCtrl
{
friend class DeleteCommand;
friend class DragCommand;
public:
EditableListCtrl(wxWindow *parent,
wxWindowID id = wxID_ANY,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
long style = wxLC_ICON,
const wxValidator& validator = wxDefaultValidator,
const wxString& name = wxListCtrlNameStr);
~EditableListCtrl();
void OnMouseEvent(wxMouseEvent& event);
void MakeSizeAtLeast(int n);
long GetSelection();
void SetSelection(long item);
void UpdateDisplay();
wxString GetCellString(long item, long column) const;
AtObj GetCellObject(long item, long column) const;
void SetCellString(long item, long column, wxString& str);
void SetCellObject(long item, long column, AtObj& obj);
struct ColumnData
{
ColumnData(const char* k, const FieldEditCtrl* c) : key(k), ctrl(c) {}
const char* key;
const FieldEditCtrl* ctrl;
};
std::vector<ColumnData> m_ColumnTypes;
void CloneListData(std::vector<AtObj>& out);
void SetListData(std::vector<AtObj>& in);
void DeleteData();
private:
int GetColumnAtPosition(wxPoint& pos);
void GetCellRect(long row, int col, wxRect& rect);
void TrimBlankEnds();
wxString OnGetItemText(long item, long column) const;
wxListItemAttr* OnGetItemAttr(long item) const;
protected:
std::vector<AtObj> m_ListData;
// objectkey must remain in existence for as long as this list control
// exists (so you really don't want to be dynamically allocating it;
// just use static constant strings)
void AddColumnType(const wxString& title, int width, const char* objectkey, FieldEditCtrl* ctrl);
void AddRow(AtObj& obj);
void AddRow(AtIter& iter);
bool IsRowBlank(int n);
DECLARE_EVENT_TABLE();
};
#endif // EDITABLELISTCTRL_H__

View File

@ -0,0 +1,92 @@
#include "stdafx.h"
#include "FieldEditCtrl.h"
#include "ListCtrlValidator.h"
#include "QuickTextCtrl.h"
#include "AtlasDialog.h"
#include "EditableListCtrl.h"
#include "AtlasObject/AtlasObject.h"
#include "AtlasObject/AtlasObjectText.h"
#include <string>
void FieldEditCtrl_Text::StartEdit(wxWindow* parent, wxRect rect, long row, int col)
{
new QuickTextCtrl(parent, rect, ListCtrlValidator((EditableListCtrl*)parent, row, col));
}
//////////////////////////////////////////////////////////////////////////
class EditCommand_Dialog : public wxCommand
{
public:
EditCommand_Dialog(EditableListCtrl* ctrl, long row, int col, AtObj& newData)
: wxCommand(true, _("Edit")), m_Ctrl(ctrl), m_Row(row), m_Col(col), m_NewData(newData)
{
}
bool Do()
{
m_Ctrl->CloneListData(m_OldData);
m_Ctrl->MakeSizeAtLeast(m_Row+1);
m_Ctrl->SetCellObject(m_Row, m_Col, m_NewData);
m_Ctrl->UpdateDisplay();
m_Ctrl->SetSelection(m_Row);
return true;
}
bool Undo()
{
m_Ctrl->SetListData(m_OldData);
m_Ctrl->UpdateDisplay();
m_Ctrl->SetSelection(m_Row);
return true;
}
private:
EditableListCtrl* m_Ctrl;
long m_Row;
int m_Col;
AtObj m_NewData;
std::vector<AtObj> m_OldData;
};
FieldEditCtrl_Dialog::FieldEditCtrl_Dialog(wxString dialogType)
: m_DialogType(dialogType)
{
}
void FieldEditCtrl_Dialog::StartEdit(wxWindow* parent, wxRect WXUNUSED(rect), long row, int col)
{
AtlasDialog* dialog = wxDynamicCast(wxCreateDynamicObject(m_DialogType), AtlasDialog);
wxCHECK2(dialog, return);
dialog->SetParent(parent);
EditableListCtrl* editCtrl = (EditableListCtrl*)parent;
AtObj in (editCtrl->GetCellObject(row, col));
dialog->Import(in);
int ret = dialog->ShowModal();
if (ret == wxID_OK)
{
AtObj out;
dialog->Export(out);
AtlasWindowCommandProc::GetFromParentFrame(parent)->Submit(
new EditCommand_Dialog(editCtrl, row, col, out)
);
}
delete dialog;
}

View File

@ -0,0 +1,35 @@
class EditableListCtrl;
class FieldEditCtrl
{
friend class EditableListCtrl;
public:
virtual ~FieldEditCtrl() {};
protected:
virtual void StartEdit(wxWindow* parent, wxRect rect, long row, int col)=0;
};
//////////////////////////////////////////////////////////////////////////
class FieldEditCtrl_Text : public FieldEditCtrl
{
protected:
void StartEdit(wxWindow* parent, wxRect rect, long row, int col);
};
//////////////////////////////////////////////////////////////////////////
class FieldEditCtrl_Dialog : public FieldEditCtrl
{
public:
FieldEditCtrl_Dialog(wxString dialogType);
protected:
void StartEdit(wxWindow* parent, wxRect rect, long row, int col);
private:
wxString m_DialogType;
};

View File

@ -0,0 +1,94 @@
#include "stdafx.h"
#include "ListCtrlValidator.h"
#include "AtlasWindowCommandProc.h"
#include "EditableListCtrl.h"
#include "AtlasObject/AtlasObject.h"
#include "AtlasObject/AtlasObjectText.h"
class EditCommand_Text : public wxCommand
{
public:
EditCommand_Text(EditableListCtrl* ctrl, long row, int col, wxString newText)
: wxCommand(true, _("Edit")), m_Ctrl(ctrl), m_Row(row), m_Col(col), m_NewText(newText)
{
}
bool Do()
{
m_Ctrl->CloneListData(m_OldData);
m_Ctrl->MakeSizeAtLeast(m_Row+1);
m_Ctrl->SetCellString(m_Row, m_Col, m_NewText);
m_Ctrl->UpdateDisplay();
m_Ctrl->SetSelection(m_Row);
return true;
}
bool Undo()
{
m_Ctrl->SetListData(m_OldData);
m_Ctrl->UpdateDisplay();
m_Ctrl->SetSelection(m_Row);
return true;
}
private:
EditableListCtrl* m_Ctrl;
long m_Row;
int m_Col;
wxString m_NewText;
std::vector<AtObj> m_OldData;
};
ListCtrlValidator::ListCtrlValidator()
: m_listCtrl(NULL)
{
}
ListCtrlValidator::ListCtrlValidator(EditableListCtrl* listCtrl, long row, int col)
: m_listCtrl(listCtrl), m_Row(row), m_Col(col)
{
}
wxObject* ListCtrlValidator::Clone() const
{
return new ListCtrlValidator(m_listCtrl, m_Row, m_Col);
}
bool ListCtrlValidator::TransferToWindow()
{
wxTextCtrl* textCtrl = wxDynamicCast(GetWindow(), wxTextCtrl);
wxString text (m_listCtrl->GetCellString(m_Row, m_Col));
textCtrl->SetValue(text);
return true;
}
bool ListCtrlValidator::TransferFromWindow()
{
wxTextCtrl* textCtrl = wxDynamicCast(GetWindow(), wxTextCtrl);
wxString newText = textCtrl->GetValue();
AtlasWindowCommandProc::GetFromParentFrame(m_listCtrl)->Submit(
new EditCommand_Text(m_listCtrl, m_Row, m_Col, newText)
);
return true;
}
bool ListCtrlValidator::Validate(wxWindow* WXUNUSED(parent))
{
return true;
}

View File

@ -0,0 +1,22 @@
#include "wx/validate.h"
#include "wx/listctrl.h"
class EditableListCtrl;
class ListCtrlValidator : public wxValidator
{
public:
ListCtrlValidator();
ListCtrlValidator(EditableListCtrl* listCtrl, long row, int col);
wxObject* Clone() const;
bool TransferToWindow();
bool TransferFromWindow();
bool Validate(wxWindow *parent);
private:
EditableListCtrl* m_listCtrl;
long m_Row;
int m_Col;
};

View File

@ -0,0 +1,43 @@
#include "stdafx.h"
#include "QuickTextCtrl.h"
const int verticalPadding = 2;
QuickTextCtrl::QuickTextCtrl(wxWindow* parent,
wxRect& location,
const wxValidator& validator)
: wxTextCtrl(parent, wxID_ANY, wxEmptyString,
location.GetPosition()-wxPoint(0,verticalPadding),
location.GetSize()+wxSize(0,verticalPadding*2),
wxSUNKEN_BORDER | wxTE_PROCESS_TAB | wxTE_PROCESS_ENTER,
validator)
{
GetValidator()->TransferToWindow();
SetFocus();
SetSelection(-1, -1);
}
void QuickTextCtrl::OnKillFocus(wxFocusEvent& WXUNUSED(event))
{
GetValidator()->TransferFromWindow();
Destroy();
}
void QuickTextCtrl::OnChar(wxKeyEvent& event)
{
if (event.GetKeyCode() == WXK_RETURN)
GetParent()->SetFocus();
else if (event.GetKeyCode() == WXK_ESCAPE)
Destroy();
else
event.Skip();
}
BEGIN_EVENT_TABLE(QuickTextCtrl, wxTextCtrl)
EVT_KILL_FOCUS(QuickTextCtrl::OnKillFocus)
EVT_CHAR(QuickTextCtrl::OnChar)
END_EVENT_TABLE()

View File

@ -0,0 +1,13 @@
#include "wx/textctrl.h"
class QuickTextCtrl : public wxTextCtrl
{
public:
QuickTextCtrl(wxWindow* parent, wxRect& location, const wxValidator& validator = wxDefaultValidator);
void OnKillFocus(wxFocusEvent& event);
void OnChar(wxKeyEvent& event);
private:
DECLARE_EVENT_TABLE();
};

View File

@ -0,0 +1,63 @@
#include "stdafx.h"
#include "AtlasDialog.h"
#include "wx/statline.h"
IMPLEMENT_CLASS(AtlasDialog, wxDialog);
BEGIN_EVENT_TABLE(AtlasDialog, wxDialog)
EVT_MENU(wxID_UNDO, AtlasDialog::OnUndo)
EVT_MENU(wxID_REDO, AtlasDialog::OnRedo)
END_EVENT_TABLE()
AtlasDialog::AtlasDialog(wxWindow* parent, const wxString& title)
: wxDialog(parent, -1, title, wxDefaultPosition, wxDefaultSize,
wxCAPTION | wxRESIZE_BORDER | wxSYSTEM_MENU | wxCLOSE_BOX)
{
// Create generic dialog box, with OK/Cancel buttons, some horizontal
// dividing lines, and a wxPanel in the middle:
wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
SetSizer(mainSizer);
// -------------------------------------------------------------------------
mainSizer->Add(new wxStaticLine(this, -1), wxSizerFlags().Expand().Border(wxALL, 5));
m_MainPanel = new wxPanel(this);
mainSizer->Add(m_MainPanel, wxSizerFlags().Proportion(1).Expand().Border(wxLEFT|wxRIGHT, 5));
// -------------------------------------------------------------------------
mainSizer->Add(new wxStaticLine(this, -1), wxSizerFlags().Expand().Border(wxALL, 5));
wxBoxSizer* buttonSizer = new wxBoxSizer(wxHORIZONTAL);
mainSizer->Add(buttonSizer, wxSizerFlags().Expand().Align(wxALIGN_RIGHT).Border(wxALL, 5));
buttonSizer->Add(new wxButton(this, wxID_OK, _("OK")), wxSizerFlags().Border(wxRIGHT, 25));
buttonSizer->Add(new wxButton(this, wxID_CANCEL, _("Cancel")), wxSizerFlags().Border(wxRIGHT, 5));
//////////////////////////////////////////////////////////////////////////
// Set up handlers for Ctrl+Z, Ctrl+Y (undo/redo), since dialogs don't
// have any menu entries for them (since they don't have menus at all).
wxAcceleratorEntry entries[2];
entries[0].Set(wxACCEL_CTRL, 'Z', wxID_UNDO);
entries[1].Set(wxACCEL_CTRL, 'Y', wxID_REDO);
wxAcceleratorTable accel(2, entries);
SetAcceleratorTable(accel);
m_CommandProc.Initialize();
}
void AtlasDialog::OnUndo(wxCommandEvent& WXUNUSED(event))
{
m_CommandProc.Undo();
}
void AtlasDialog::OnRedo(wxCommandEvent& WXUNUSED(event))
{
m_CommandProc.Redo();
}

View File

@ -0,0 +1,29 @@
#include "wx/dialog.h"
#include "AtlasWindowCommandProc.h"
#include "IAtlasExporter.h"
class FieldEditCtrl_Dialog;
class AtlasDialog : public wxDialog, public IAtlasExporter
{
friend class FieldEditCtrl_Dialog;
friend class AtlasWindowCommandProc;
DECLARE_CLASS(AtlasDialog);
public:
AtlasDialog(wxWindow* parent, const wxString& title);
virtual ~AtlasDialog() {}
void OnUndo(wxCommandEvent& event);
void OnRedo(wxCommandEvent& event);
protected:
wxPanel* m_MainPanel;
private:
AtlasWindowCommandProc m_CommandProc;
DECLARE_EVENT_TABLE()
};

View File

@ -0,0 +1,119 @@
#include "stdafx.h"
#include "AtlasWindow.h"
#include "AtlasObject/AtlasObject.h"
#include "wx/intl.h"
#include "wx/menu.h"
IMPLEMENT_CLASS(AtlasWindow, wxFrame);
enum
{
ID_Quit = 1,
ID_Import,
ID_Export
};
BEGIN_EVENT_TABLE(AtlasWindow, wxFrame)
EVT_MENU(ID_Quit, AtlasWindow::OnQuit)
EVT_MENU(ID_Import, AtlasWindow::OnImport)
EVT_MENU(ID_Export, AtlasWindow::OnExport)
EVT_MENU(wxID_UNDO, AtlasWindow::OnUndo)
EVT_MENU(wxID_REDO, AtlasWindow::OnRedo)
END_EVENT_TABLE()
AtlasWindow::AtlasWindow(wxWindow* parent, const wxString& title, const wxSize& size)
: wxFrame(parent, wxID_ANY, _T(""), wxDefaultPosition, size)
, m_WindowTitle(title)
{
wxMenuBar *menuBar = new wxMenuBar;
SetMenuBar(menuBar);
wxMenu *menuFile = new wxMenu;
menuBar->Append(menuFile, _("&File"));
{
menuFile->Append(ID_Import, _("&Import..."));
menuFile->Append(ID_Export, _("&Export..."));
menuFile->AppendSeparator();//-----------
menuFile->Append(ID_Quit, _("E&xit"));
}
wxMenu *menuEdit = new wxMenu;
menuBar->Append(menuEdit, _("&Edit"));
{
menuEdit->Append(wxID_UNDO, _("&Undo"));
menuEdit->Append(wxID_REDO, _("&Redo"));
}
m_CommandProc.SetEditMenu(menuEdit);
m_CommandProc.Initialize();
CreateStatusBar();
//SetStatusText(_("Welcome to wxWidgets!"));
SetDisplayedFilename(_T(""));
}
void AtlasWindow::OnQuit(wxCommandEvent& WXUNUSED(event))
{
Close();
}
void AtlasWindow::OnUndo(wxCommandEvent& WXUNUSED(event))
{
m_CommandProc.Undo();
}
void AtlasWindow::OnRedo(wxCommandEvent& WXUNUSED(event))
{
m_CommandProc.Redo();
}
void AtlasWindow::OnImport(wxCommandEvent& WXUNUSED(event))
{
wxFileDialog dlg (this, _T("Select XML file to import"), _T(""), _T(""), _T("XML files (*.xml)|*.xml"), wxOPEN);
if (dlg.ShowModal() != wxID_OK)
return;
wxString filename = dlg.GetPath();
AtObj file;
AtlasObject::LoadFromXML(file, filename.c_str());
Import(file);
SetDisplayedFilename(dlg.GetFilename());
}
void AtlasWindow::OnExport(wxCommandEvent& WXUNUSED(event))
{
wxFileDialog dlg (this, _T("Select XML file to export"), _T(""), _T(""), _T("XML files (*.xml)|*.xml"), wxSAVE | wxOVERWRITE_PROMPT);
if (dlg.ShowModal() != wxID_OK)
return;
wxString filename = dlg.GetPath();
AtObj file;
Export(file);
AtlasObject::SaveToXML(file, filename.c_str());
SetDisplayedFilename(dlg.GetFilename());
}
void AtlasWindow::SetDisplayedFilename(wxString filename)
{
if (filename == _T(""))
m_DisplayedFilename = _("Unnamed file");
else
m_DisplayedFilename = filename;
SetTitle(m_WindowTitle + _T(" - ") + m_DisplayedFilename);
}

View File

@ -0,0 +1,38 @@
#include "AtlasWindowCommandProc.h"
#include "IAtlasExporter.h"
#include "wx/frame.h"
class AtObj;
class AtlasWindow : public wxFrame, public IAtlasExporter
{
friend class AtlasWindowCommandProc;
DECLARE_CLASS(AtlasWindow);
public:
AtlasWindow(wxWindow* parent, const wxString& title, const wxSize& size);
void OnQuit(wxCommandEvent& event);
void OnImport(wxCommandEvent& event);
void OnExport(wxCommandEvent& event);
void OnUndo(wxCommandEvent& event);
void OnRedo(wxCommandEvent& event);
protected:
// Call with the name of the currently opened file, or with the
// empty string for new unnamed documents
void SetDisplayedFilename(wxString filename);
private:
AtlasWindowCommandProc m_CommandProc;
wxString m_DisplayedFilename;
wxString m_WindowTitle;
DECLARE_EVENT_TABLE();
};

View File

@ -0,0 +1,5 @@
#include "stdafx.h"
#include "AtlasWindowCommand.h"
IMPLEMENT_ABSTRACT_CLASS(AtlasWindowCommand, wxCommand);

View File

@ -0,0 +1,19 @@
#include "wx/cmdproc.h"
class AtlasWindowCommand : public wxCommand
{
DECLARE_ABSTRACT_CLASS(AtlasWindowCommand);
friend class AtlasWindowCommandProc;
public:
AtlasWindowCommand(bool canUndoIt, const wxString& name)
: wxCommand(canUndoIt, name), m_Finalized(false) {}
private:
// Control merging of this command with a future one (so they
// can be undone in a single step)
virtual bool Merge(AtlasWindowCommand* command)=0;
bool m_Finalized;
};

View File

@ -0,0 +1,66 @@
#include "stdafx.h"
#include "AtlasWindow.h"
#include "AtlasWindowCommand.h"
#include "AtlasDialog.h"
AtlasWindowCommandProc* AtlasWindowCommandProc::GetFromParentFrame(wxWindow* object)
{
wxWindow* win = object;
while (win)
{
{
AtlasWindow* tgt = wxDynamicCast(win, AtlasWindow);
if (tgt)
return &tgt->m_CommandProc;
}
{
AtlasDialog* tgt = wxDynamicCast(win, AtlasDialog);
if (tgt)
return &tgt->m_CommandProc;
}
win = win->GetParent();
}
wxASSERT_MSG(0, _T("Couldn't find command processor"));
return NULL;
}
bool AtlasWindowCommandProc::Submit(wxCommand *command, bool storeIt)
{
wxCHECK_MSG(command, false, _T("no command in wxCommandProcessor::Submit"));
AtlasWindowCommand* previousCommand = wxDynamicCast(GetCurrentCommand(), AtlasWindowCommand);
if (! DoCommand(*command))
{
delete command;
return false;
}
if (storeIt)
{
AtlasWindowCommand* currentCommand = wxDynamicCast(command, AtlasWindowCommand);
if (currentCommand && previousCommand
&& !previousCommand->m_Finalized
&& previousCommand->Merge(currentCommand))
{
delete command;
}
else
Store(command);
}
else
delete command;
return true;
}
void AtlasWindowCommandProc::FinaliseLastCommand()
{
AtlasWindowCommand* previousCommand = wxDynamicCast(GetCurrentCommand(), AtlasWindowCommand);
if (previousCommand)
previousCommand->m_Finalized = true;
}

View File

@ -0,0 +1,19 @@
#ifndef ATLASWINDOWCOMMANDPROC_H__
#define ATLASWINDOWCOMMANDPROC_H__
#include "wx/cmdproc.h"
#include "wx/window.h"
class AtlasWindowCommandProc : public wxCommandProcessor
{
public:
bool Submit(wxCommand *command, bool storeIt = true);
// Mark the most recent command as finalized, so it won't be
// merged with any subsequent ones
void FinaliseLastCommand();
static AtlasWindowCommandProc* GetFromParentFrame(wxWindow* object);
};
#endif // ATLASWINDOWCOMMANDPROC_H__

View File

@ -0,0 +1,13 @@
#ifndef IATLASEXPORTER_H__
#define IATLASEXPORTER_H__
class AtObj;
class IAtlasExporter // and also importer, but I can't think of a nice concise name
{
public:
virtual void Import(AtObj& in)=0;
virtual void Export(AtObj& out)=0;
};
#endif // IATLASEXPORTER_H__

View File

@ -0,0 +1,26 @@
// Just a boring app that creates an ActorEditor window
#include "stdafx.h"
#include "ActorEditor/ActorEditor.h"
#include "wx/app.h"
class MyApp: public wxApp
{
bool OnInit();
};
IMPLEMENT_APP(MyApp)
#include <crtdbg.h>
bool MyApp::OnInit()
{
// _CrtSetBreakAlloc(1358);
// MyFrame *frame = new MyFrame("Hello World");
wxFrame *frame = new ActorEditor(NULL);
frame->Show();
SetTopWindow(frame);
return true;
}

View File

@ -0,0 +1 @@
#include "stdafx.h"

View File

@ -0,0 +1,24 @@
// Precompiled headers:
#ifdef _WIN32
# define HAVE_PCH
#endif
#ifdef HAVE_PCH
// Exclude rarely-used stuff from Windows headers
#define WIN32_LEAN_AND_MEAN
// Include useful wx headers
#include "wx/wxprec.h"
#include "wx/listctrl.h"
#include <vector>
// Nicer memory-leak detection:
#ifdef _DEBUG
#include <crtdbg.h>
#define new new(_NORMAL_BLOCK ,__FILE__, __LINE__)
#endif
#endif // HAVE_PCH

View File

@ -0,0 +1,23 @@
* Copy and paste
* s/PropListEditor/PropListEditor/
* Rearrange directory structure
* Don't hardcode "actor" in XML files (urgh)
* Document lots
* Make import undoable
* wxListItemAttr* OnGetItemAttr(long item) >>>const<<< - wx documentation??
* Better widths
* Combo boxes for prop/anim names, loaded from file
* Input validation?
* Better input controls (=> export nicely, support undo, etc)
* Handle undo correctly after importing