initial checkin of C++ port (in progress)

git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@2 0fc631ac-6414-0410-93d0-97cfa31319b6
This commit is contained in:
twanvl
2006-10-01 14:08:07 +00:00
parent f5c0071da6
commit ddfb1a5089
56 changed files with 8781 additions and 0 deletions
+108
View File
@@ -0,0 +1,108 @@
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
// ----------------------------------------------------------------------------- : Includes
#include <algorithm>
#include "action_stack.hpp"
#include "for_each.hpp"
// ----------------------------------------------------------------------------- : Action stack
DECLARE_TYPEOF_COLLECTION(Action*);
DECLARE_TYPEOF_COLLECTION(ActionListener*);
ActionStack::ActionStack()
: savePoint(nullptr)
{}
ActionStack::~ActionStack() {
// we own the actions, delete them
FOR_EACH(a, undoActions) delete a;
FOR_EACH(a, redoActions) delete a;
}
void ActionStack::add(Action* action, bool allowMerge) {
if (!action) return; // no action
action->perform(false); // TODO: delete action if perform throws
redoActions.clear();
tellListeners(*action);
// try to merge?
if (allowMerge && !undoActions.empty() && undoActions.back()->merge(action)) {
// merged with top undo action
delete action;
} else {
undoActions.push_back(action);
}
}
void ActionStack::undo() {
assert(canUndo());
Action* action = undoActions.back();
action->perform(true);
// move to redo stack
undoActions.pop_back();
redoActions.push_back(action);
}
void ActionStack::redo() {
assert(canRedo());
Action* action = redoActions.back();
action->perform(false);
// move to undo stack
redoActions.pop_back();
undoActions.push_back(action);
}
bool ActionStack::canUndo() const {
return !undoActions.empty();
}
bool ActionStack::canRedo() const {
return !redoActions.empty();
}
String ActionStack::undoName() const {
if (canUndo()) {
return _("Undo ") + capitalize(undoActions.back()->getName(true));
} else {
return _("Undo");
}
}
String ActionStack::redoName() const {
if (canRedo()) {
return _("Redo ") + capitalize(redoActions.back()->getName(false));
} else {
return _("Redo");
}
}
bool ActionStack::atSavePoint() const {
return (undoActions.empty() && savePoint == nullptr)
|| (undoActions.back() == savePoint);
}
void ActionStack::setSavePoint() {
if (undoActions.empty()) {
savePoint = nullptr;
} else {
savePoint = undoActions.back();
}
}
void ActionStack::addListener(ActionListener* listener) {
listeners.push_back(listener);
}
void ActionStack::removeListener(ActionListener* listener) {
listeners.erase(
std::remove(
listeners.begin(),
listeners.end(),
listener
),
listeners.end()
);
}
void ActionStack::tellListeners(const Action& action) {
FOR_EACH(l, listeners) l->onAction(action);
}
+136
View File
@@ -0,0 +1,136 @@
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
#ifndef HEADER_UTIL_ACTION_STACK
#define HEADER_UTIL_ACTION_STACK
// ----------------------------------------------------------------------------- : Includes
#include <vector>
#include "string.hpp"
// ----------------------------------------------------------------------------- : Action
/// Base class for actions that can be stored in an ActionStack.
/** An action is something that can be done to modify an object.
* It must store the necessary information to also undo the action.
*/
class Action {
public:
virtual ~Action() {};
/// Name of the action, for use in strings like "Undo <name>"
virtual String getName(bool toUndo) const = 0;
/// Perform the action
/// Must be implemented in derived class
/** Perform will only ever be called alternatingly with toUndo = true/false,
* the first time with toUndo = false
*/
/// @param toUndo if true, undo the action instead of doing it
virtual void perform(bool toUndo) = 0;
/// Try to merge another action to the end of this action.
/// Either: return false and do nothing
/// Or: return true and change this action to incorporate both actions
virtual bool merge(const Action* action) { return false; }
};
// ----------------------------------------------------------------------------- : Action listeners
/// Base class/interface for objects that listen to actions
class ActionListener {
public:
virtual void onAction(const Action& a) = 0;
};
// ----------------------------------------------------------------------------- : Action stack
/// A stack of actions that can be done and undone.
/** This class handles the undo and redo functionality of a particular object.
*
* This class also takes on the role of Observable, ActionListeners can register themselfs.
* They will be notified when an action is added.
*/
class ActionStack {
public:
ActionStack();
~ActionStack();
/// Add an action to the stack, and perform that action.
/// Tells all listeners about the action.
/// The ActionStack takes ownership of the action
void add(Action* action, bool allowMerge = true);
/// Undoes the last action that was (re)done
/// @pre canUndo()
void undo();
/// Redoes the last action that was undone
/// @pre canRedo()
void redo();
/// Is undoing possible?
bool canUndo() const;
/// Is redoing possible?
bool canRedo() const;
/// Name of the action that will be undone next, in the form "Undo <Action>"
/// If there is no action to undo returns "Undo"
String undoName() const;
/// Name of the action that will be redone next "Redo <Action>"
/// If there is no action to undo returns "Redo"
String redoName() const;
/// Is the file currently at a 'savepoint'?
/// This is the last point at which the file was saved
bool atSavePoint() const;
/// Indicate that the file is at a savepoint.
void setSavePoint();
/// Add an action listener
void addListener(ActionListener* listener);
/// Remove an action listener
void removeListener(ActionListener* listener);
/// Tell all listeners about an action
void tellListeners(const Action&);
private:
/// Actions to be undone
/// Owns the action objects!
vector<Action*> undoActions;
/// Actions to be redone
/// Owns the action objects!
vector<Action*> redoActions;
/// Point at which the file was saved, corresponds to the top of the undo stack at that point
Action* savePoint;
/// Objects that are listening to actions
vector<ActionListener*> listeners;
};
// ----------------------------------------------------------------------------- : Utilities
/// Tests if variable has the type Type
/** Uses dynamic cast, so Type must have a virtual function.
*/
#define TYPE_CASE_(variable, Type) \
if (dynamic_cast<const Type*>(&variable))
/// Tests if variable has the type Type. If this is the case, makes
/// variable have type Type inside the statement
/** Uses dynamic cast, so Type must have a virtual function.
*/
#define TYPE_CASE(variable, Type) \
pair<const Type*,bool> Type##variable \
(dynamic_cast<const Type*>(&variable), true); \
if (Type##variable.first) \
for (const Type& variable = *Type##variable.first ; \
Type##variable.second ; \
Type##variable.second = false)
// ----------------------------------------------------------------------------- : EOF
#endif
+21
View File
@@ -0,0 +1,21 @@
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
// ----------------------------------------------------------------------------- : Includes
#include <util/error.hpp>
// ----------------------------------------------------------------------------- : Error types
Error::Error(const String& message)
: message(message)
{}
Error::~Error() {}
String Error::what() const {
return message;
}
+60
View File
@@ -0,0 +1,60 @@
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
#ifndef HEADER_UTIL_ERROR
#define HEADER_UTIL_ERROR
// ----------------------------------------------------------------------------- : Includes
#include <util/prec.hpp>
/** @file util/error.hpp
*
* Classes and functions for handling errors/exceptions
*/
// ----------------------------------------------------------------------------- : Error types
/// Our own exception class
class Error {
public:
Error(const String& message);
virtual ~Error();
/// Return the error message
virtual String what() const;
private:
String message; //^ The error message
};
/// Internal errors
class InternalError : public Error {
public:
inline InternalError(const String& str)
: Error(_("An internal error occured, please contact the author:\n") + str)
{}
};
// ----------------------------------------------------------------------------- : File errors
// Errors related to packages
class PackageError : public Error {
public:
inline PackageError(const String& str) : Error(str) {}
};
// ----------------------------------------------------------------------------- : Parse errors
// Parse errors
class ParseError : public Error {
public:
inline ParseError(const String& str) : Error(str) {}
};
// ----------------------------------------------------------------------------- : EOF
#endif
+169
View File
@@ -0,0 +1,169 @@
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
#ifndef HEADER_UTIL_FOR_EACH
#define HEADER_UTIL_FOR_EACH
/** @file util/for_each.hpp
*
* Macros to simplify looping over collections.
* This header contains some evil template and macro hackery.
*/
// ----------------------------------------------------------------------------- : Includes
// ----------------------------------------------------------------------------- : Typeof magic
#ifdef __GNUC__
// GCC has a buildin typeof function, so it doesn't need (as much) hacks
#define DECLARE_TYPEOF(T)
#define DECLARE_TYPEOF_COLLECTION(T)
#define TYPEOF(Value) __typeof(Value)
#define TYPEOF_IT(Value) __typeof(Value.begin())
#define TYPEOF_CIT(Value) __typeof(Value.begin())
#define TYPEOF_RIT(Value) __typeof(Value.rbegin())
#define TYPEOF_REF(Value) __typeof(*Value.begin())&
#else
/// Helper for typeof tricks
template<const type_info &ref_type_info> struct TypeOf {};
/// The type of a value
#define TYPEOF(Value) TypeOf<typeid(Value)>::type
/// The type of an iterator
#define TYPEOF_IT(Value) TypeOf<typeid(Value)>::iterator
/// The type of a const iterator
#define TYPEOF_CIT(Value) TypeOf<typeid(Value)>::const_iterator
/// The type of a reverse iterator
#define TYPEOF_RIT(Value) TypeOf<typeid(Value)>::reverse_iterator
/// The type of a value
#define TYPEOF_REF(Value) TypeOf<typeid(Value)>::reference
/// Declare typeof magic for a specific type
#define DECLARE_TYPEOF(T) \
template<> struct TypeOf<typeid(T)> { \
typedef T type; \
typedef T::iterator iterator; \
typedef T::const_iterator const_iterator; \
typedef T::reverse_iterator reverse_iterator; \
typedef T::reference reference; \
}
/// Declare typeof magic for a specific type that doesn't support reverse iterators
#define DECLARE_TYPEOF_NO_REV(T) \
template<> struct TypeOf<typeid(T)> { \
typedef T type; \
typedef T::iterator iterator; \
typedef T::const_iterator const_iterator; \
typedef T::reference reference; \
}
/// Declare typeof magic for a specific type, using const iterators
#define DECLARE_TYPEOF_CONST(T) \
template<> struct TypeOf<typeid(T)> { \
typedef T type; \
typedef T::const_iterator iterator; \
typedef T::const_iterator const_iterator; \
typedef T::const_reverse_iterator reverse_iterator; \
typedef T::const_reference reference; \
}
/// Declare typeof magic for a specific std::vector type
#define DECLARE_TYPEOF_COLLECTION(T) DECLARE_TYPEOF(vector<T>); \
DECLARE_TYPEOF_CONST(set<T>)
#endif
// ----------------------------------------------------------------------------- : Looping macros with iterators
/// Iterate over a collection, using an iterator it of type Type
/// Usage: FOR_EACH_IT_T(Type,it,collect) { body-of-loop }
#define FOR_EACH_IT_T(Type,Iterator,Collection) \
for(Type Iterator = Collection.begin() ; \
Iterator != Collection.end() ; \
++Iterator)
/// Iterate over a collection whos type must be declared with DECLARE_TYPEOF
/// Usage: FOR_EACH_IT(it,collect) { body-of-loop }
#define FOR_EACH_IT(Iterator,Collection) \
FOR_EACH_IT_T(TYPEOF_IT(Collection), Iterator, Collection)
/// Iterate over a collection whos type must be declared with DECLARE_TYPEOF
/// Uses a const_iterator
/// Usage: FOR_EACH_IT(it,collect) { body-of-loop }
#define FOR_EACH_CONST_IT(Iterator,Collection) \
FOR_EACH_IT_T(TYPEOF_CIT(Collection), Iterator, Collection)
/// Iterate over a collection in whos type must be declared with DECLARE_TYPEOF
/// Iterates using a reverse_iterator
/// Usage: FOR_EACH_REVERSE_IT(it,collect) { body-of-loop }
#define FOR_EACH_REVERSE_IT(Iterator,Collection) \
for(TYPEOF_RIT(Collection) \
Iterator = Collection.rbegin() ; \
Iterator != Collection.rend() ; \
++Iterator)
// ----------------------------------------------------------------------------- : Looping macros
/// Iterate over a collection, with an iterator of type TypeIt, and elements of type TypeElem
/// Usage: FOR_EACH_T(TypeIt,TypeElem,e,collect) { body-of-loop }
/** We need a hack to be able to declare a local variable without needing braces.
* To do this we use a nested for loop that is only executed once, and which is optimized away.
* To terminate this loop we need an extra bool, which we set to false after the first iteration.
*/
#define FOR_EACH_T(TypeIt,TypeElem,Elem,Collection) \
for(std::pair<TypeIt,bool> Elem##_IT(Collection.begin(), true) ; \
Elem##_IT.first != Collection.end() ; \
++Elem##_IT.first, Elem##_IT.second = true) \
for(TypeElem Elem = *Elem##_IT.first ; \
Elem##_IT.second ; \
Elem##_IT.second = false)
/// Iterate over a collection whos type must be declared with DECLARE_TYPEOF
/// Usage: FOR_EACH(e,collect) { body-of-loop }
#define FOR_EACH(Elem,Collection) \
FOR_EACH_T(TYPEOF_IT(Collection), TYPEOF_REF(Collection), Elem, Collection)
/// Iterate over a collection whos type must be declared with DECLARE_TYPEOF
/// Iterates using a reverse_iterator
/// Usage: FOR_EACH_REVERSE(e,collect) { body-of-loop }
#define FOR_EACH_REVERSE(Elem,Collection) \
for(std::pair<TYPEOF_RIT(Collection),bool> Elem##_IT(Collection.rbegin(), true) ; \
Elem##_IT.first != Collection.rend() ; \
++Elem##_IT.first, Elem##_IT.second = true) \
for(TYPEOF_REF(Collection) Elem = *Elem##_IT.first ; \
Elem##_IT.second ; \
Elem##_IT.second = false)
/// Iterate over two collection in parallel
/// Usage: FOR_EACH_2_T(TypeIt1,TypeElem1,e1,collect1,TypeIt2,TypeElem2,e2,collect2) { body-of-loop }
/** Note: This has got to be one of the craziest pieces of code I have ever written :)
* It is just an extension of the idea of FOR_EACH_T.
*/
#define FOR_EACH_2_T(TypeIt1,TypeElem1,Elem1,Coll1,TypeIt2,TypeElem2,Elem2,Coll2) \
for(std::pair<std::pair<TypeIt1,TypeIt2>, bool> \
Elem1##_IT(make_pair(Coll1.begin(), Coll2.begin()), true) ; \
Elem1##_IT.first.first != Coll1.end() && \
Elem1##_IT.first.second != Coll2.end() ; \
++Elem1##_IT.first.first, ++Elem1##_IT.first.second, \
Elem1##_IT.second = true) \
for(TypeElem1 Elem1 = *Elem1##_IT.first.first ; \
Elem1##_IT.second ; \
Elem1##_IT.second = false) \
for(TypeElem2 Elem2 = *Elem1##_IT.first.second ; \
Elem1##_IT.second ; \
Elem1##_IT.second = false)
/// Iterate over two collections in parallel,
/// their type must be declared with DECLARE_TYPEOF.
/// Usage: FOR_EACH_2(e1,collect1, e2,collect2) { body-of-loop }
#define FOR_EACH_2(Elem1,Collection1, Elem2,Collection2) \
FOR_EACH_2_T(TYPEOF_IT(Collection1), TYPEOF_REF(Collection1), Elem1, Collection1, \
TYPEOF_IT(Collection2), TYPEOF_REF(Collection2), Elem2, Collection2)
// ----------------------------------------------------------------------------- : EOF
#endif
+73
View File
@@ -0,0 +1,73 @@
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
#ifndef HEADER_UTIL_INDEX_MAP
#define HEADER_UTIL_INDEX_MAP
// ----------------------------------------------------------------------------- : Includes
#include <vector>
// ----------------------------------------------------------------------------- : IndexMap
/// A kind of map of K->V, with the following properties:
/** - K must have a unique member ->index of type UInt
* - There must exist a function initObject(K, V&)
* that stores a new V object for a given key in v
* - O(1) inserts and lookups
*/
template <typename Key, typename Value>
class IndexMap : private vector<Value> {
public:
using vector<Value>::empty;
using vector<Value>::size;
using vector<Value>::iterator;
using vector<Value>::begin;
using vector<Value>::end;
/// Initialize this map with default values given a list of keys, has no effect if !empty()
/** Requires a function
* void initObject(Key, Value&)
*/
void init(const vector<Key>& keys) {
if (!this->empty()) return;
this->reserve(keys.size());
FOR_EACH(it, keys) {
Key& k = *it;
if (k->index >= this->size()) this->resize(k->index + 1);
initObject(k, (*this)[k->index]);
}
}
/// Retrieve a value given its key
inline Value operator [] (const Key& key) {
assert(key);
assert(this->size() > key->index);
return at(key->index);
}
/// Is a value contained in this index map?
/// requires a function Key Value::getKey()
inline bool contains(const Value& value) const {
assert(value);
size_t index = value->getKey()->index;
return index < this.size() && (*this)[index] == value
}
/// Is a key in the domain of this index map?
/// requires a function Key Value::getKey()
inline bool containsKey(const Key& key) const {
assert(key);
return key->index < this.size() && (*this)[key->index]->getKey() == key
}
private:
using vector<Value>::operator [];
};
// ----------------------------------------------------------------------------- : EOF
#endif
+127
View File
@@ -0,0 +1,127 @@
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
// ----------------------------------------------------------------------------- : Includes
#include "reader.hpp"
#include <util/vector2d.hpp>
#include <util/error.hpp>
// ----------------------------------------------------------------------------- : Reader
Reader::Reader(const InputStreamP& input, String filename)
: input(input), filename(filename), lineNumber(0)
, indent(0), expectedIndent(0), justOpened(false)
, stream(*input)
{
moveNext();
}
bool Reader::enterBlock(const Char* name) {
if (justOpened) moveNext(); // on the key of the parent block, first move inside it
if (indent != expectedIndent) return false; // not enough indentation
if (name == key) {
justOpened = true;
expectedIndent += 1; // the indent inside the block must be at least this much
return true;
} else {
return false;
}
}
void Reader::exitBlock() {
assert(expectedIndent > 0);
expectedIndent -= 1;
multiLineStr.clear();
if (justOpened) moveNext(); // leave this key
// Dump the remainder of the block
// TODO: issue warnings?
while (indent > expectedIndent) {
moveNext();
}
}
void Reader::moveNext() {
justOpened = false;
key.clear();
multiLineStr.clear();
indent = -1; // if no line is read it never has the expected indentation
// repeat until we have a good line
while (key.empty() && !input->Eof()) {
readLine();
}
// did we reach the end of the file?
if (key.empty() && input->Eof()) {
lineNumber += 1;
indent = -1;
}
}
void Reader::readLine() {
// fix UTF8 in ascii builds; skip BOM
line = decodeUTF8BOM(stream.ReadLine());
// read indentation
indent = 0;
while ((UInt)indent < line.size() && line.GetChar(indent) == _('\t')) {
indent += 1;
}
// read key / value
size_t pos = line.find_first_of(_(':'), indent);
key = trim(line.substr(indent, pos - indent));
value = pos == String::npos ? _("") : trimLeft(line.substr(pos+1));
// we read a line
lineNumber += 1;
// was it a comment?
if (!key.empty() && key.GetChar(0) == _('#')) {
key.clear();
}
}
// ----------------------------------------------------------------------------- : Handling basic types
template <> void Reader::handle(String& s) {
if (!multiLineStr.empty()) {
s = multiLineStr;
} else if (value.empty()) {
// a multiline string
bool first = true;
// read all lines that are indented enough
readLine();
while (indent >= expectedIndent) {
if (!first) value += '\n';
first = false;
multiLineStr += line.substr(expectedIndent); // strip expected indent
readLine();
}
// moveNext(), but without emptying multiLineStr
justOpened = false;
while (key.empty() && !input->Eof()) {
readLine();
}
s = multiLineStr;
} else {
s = value;
}
}
template <> void Reader::handle(int& i) {
long l = 0;
value.ToLong(&l);
i = l;
}
template <> void Reader::handle(double& d) {
value.ToDouble(&d);
}
template <> void Reader::handle(bool& b) {
b = (value==_("true") || value==_("1") || value==_("yes"));
}
// ----------------------------------------------------------------------------- : Handling less basic util types
template <> void Reader::handle(Vector2D& vec) {
if (!wxSscanf(value.c_str(), _("(%lf,%lf)"), &vec.x, &vec.y)) {
throw ParseError(_("Expected (x,y)"));
}
}
+165
View File
@@ -0,0 +1,165 @@
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
#ifndef HEADER_UTIL_IO_READER
#define HEADER_UTIL_IO_READER
// ----------------------------------------------------------------------------- : Includes
#include "../prec.hpp"
#include <wx/txtstrm.h>
// ----------------------------------------------------------------------------- : Reader
typedef wxInputStream InputStream;
typedef shared_ptr<wxInputStream> InputStreamP;
/// The Reader can be used for reading (deserializing) objects
/** This class makes use of the reflection functionality, in effect
* an object tells the Reader what fields it would like to read.
* The reader then sees if the requested field is currently available.
*
* The handle functions ensure that afterwards the reader is at the line after the
* object that was just read.
*/
class Reader {
public:
/// Construct a reader that reads from the given input stream
/** filename is used only for error messages
*/
Reader(const InputStreamP& input, String filename = _(""));
/// Construct a reader that reads a file in a package
Reader(String filename);
/// Tell the reflection code we are reading
inline bool reading() const { return true; }
// --------------------------------------------------- : Handling objects
/// Handle an object: read it if it's name matches
template <typename T>
void handle(const Char* name, T& object) {
if (enterBlock(name)) {
handle(object);
exitBlock();
}
}
/// Reads an object of type T from the input stream
template <typename T> void handle(T& object);
/// Reads a vector from the input stream
template <typename T> void handle(vector<T>& vector);
/// Reads a shared_ptr from the input stream
template <typename T> void handle(shared_ptr<T>& pointer);
/// Reads a map from the input stream
//template <typename K, typename V> void handle(map<K,V>& map);
private:
// --------------------------------------------------- : Data
/// The line we read
String line;
/// The key and value of the last line we read
String key, value;
/// A string spanning multiple lines
String multiLineStr;
/// Indentation of the last line we read
int indent;
/// Indentation of the block we are in
int expectedIndent;
/// Did we just open a block (i.e. not read any more lines of it)?
bool justOpened;
/// Filename for error messages
String filename;
/// Line number for error messages
UInt lineNumber;
/// Input stream we are reading from
InputStreamP input;
/// Text stream wrapping the input stream
wxTextInputStream stream;
// --------------------------------------------------- : Reading the stream
/// Is there a block with the given key under the current cursor?
bool enterBlock(const Char* name);
/// Leave the block we are in
void exitBlock();
/// Move to the next non empty line
void moveNext();
/// Reads the next line from the input, and stores it in line/key/value/indent
void readLine();
/// Issue a warning: "Unexpected key: $key"
void unexpected();
};
// ----------------------------------------------------------------------------- : Container types
template <typename T>
void Reader::handle(vector<T>& vector) {
String vectorKey = key;
while (key == vectorKey) { // TODO : check indent
moveNext(); // skip key
vector.resize(vector.size() + 1);
handle(vector.back());
}
}
template <typename T>
void Reader::handle(shared_ptr<T>& pointer) {
if (!pointer) pointer.reset(new T);
handle(*pointer);
}
// ----------------------------------------------------------------------------- : Reflection
/// Implement reflection as used by Reader
#define REFLECT_OBJECT_READER(Cls) \
template<> void Reader::handle<Cls>(Cls& object) { \
object.reflect(*this); \
}
// ----------------------------------------------------------------------------- : Reflection for enumerations
/// Implement enum reflection as used by Reader
#define REFLECT_ENUM_READER(Enum) \
template<> void Reader::handle<Enum>(Enum& enum_) { \
EnumReader reader(value); \
reflect_ ## Enum(enum_, reader); \
if (!reader.isDone()) { \
/* warning message */ \
} \
}
/// 'Tag' to be used when reflecting enumerations for Reader
class EnumReader {
public:
inline EnumReader(String read)
: read(read), first(true), done(false) {}
/// Handle a possible value for the enum, if the name matches the name in the input
template <typename Enum>
inline void handle(const Char* name, Enum value, Enum& enum_) {
if (!done && read == name) {
first = true;
enum_ = value;
} else if (first) {
first = false;
enum_ = value;
}
}
inline bool isDone() const { return done; }
private:
String read; //^ The string to match to a value name
bool first; //^ Has the first (default) value been matched?
bool done; //^ Was anything matched?
};
// ----------------------------------------------------------------------------- : EOF
#endif
+108
View File
@@ -0,0 +1,108 @@
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
// ----------------------------------------------------------------------------- : Includes
#include "writer.hpp"
#include <util/vector2d.hpp>
#include <util/error.hpp>
// ----------------------------------------------------------------------------- : Writer
Writer::Writer(const OutputStreamP& output)
: output(output)
, stream(*output)
, indentation(0)
, justOpened(false)
{
stream.WriteString(BYTE_ORDER_MARK);
}
void Writer::enterBlock(const Char* name) {
// indenting into a sub-block?
if (justOpened) {
writeKey();
stream.WriteString(_(":\n"));
}
// don't write the key yet
indentation += 1;
openedKey = name;
justOpened = true;
}
void Writer::exitBlock() {
assert(indentation > 0);
indentation -= 1;
justOpened = false;
}
void Writer::writeKey() {
writeIndentation();
writeUTF8(stream, openedKey);
}
void Writer::writeIndentation() {
for(int i = 1 ; i < indentation ; ++i) {
stream.PutChar(_('\t'));
}
}
// ----------------------------------------------------------------------------- : Handling basic types
void Writer::handle(const String& value) {
if (!justOpened) {
throw InternalError(_("Can only write a value in a key that was just opened"));
}
// write indentation and key
writeKey();
writeUTF8(stream, _(": "));
if (value.find_first_of(_('\n')) != String::npos) {
// multiline string
stream.PutChar(_('\n'));
indentation += 1;
// split lines, and write each line
size_t start = 0, end, size = value.size();
while (start < size) {
end = value.find_first_of(_("\n\r"), start); // until end of line
// write the line
writeIndentation();
writeUTF8(stream, value.substr(start, end - start));
stream.PutChar(_('\n'));
// Skip \r and \n
if (end == String::npos) break;
start = end + 1;
if (start < size) {
Char c1 = value.GetChar(start - 1);
Char c2 = value.GetChar(start);
// skip second character of \r\n or \n\r
if (c1 != c2 && (c2 == _('\r') || c2 == _('\n'))) start += 1;
}
}
indentation -= 1;
} else {
writeUTF8(stream, value);
}
stream.PutChar(_('\n'));
justOpened = false;
}
template <> void Writer::handle(const int& value) {
handle(String() << value);
}
template <> void Writer::handle(const double& value) {
handle(String() << value);
}
template <> void Writer::handle(const bool& value) {
handle(value ? _("true") : _("false"));
}
// ----------------------------------------------------------------------------- : Handling less basic util types
template <> void Writer::handle(const Vector2D& vec) {
String formated;
formated.Printf(_("(%.10lf,%.10lf)"), vec.x, vec.y);
handle(formated);
}
+131
View File
@@ -0,0 +1,131 @@
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
#ifndef HEADER_UTIL_IO_WRITER
#define HEADER_UTIL_IO_WRITER
// ----------------------------------------------------------------------------- : Includes
#include <util/prec.hpp>
#include <wx/txtstrm.h>
// ----------------------------------------------------------------------------- : Writer
typedef wxOutputStream OutputStream;
typedef shared_ptr<wxOutputStream> OutputStreamP;
/// The Writer can be used for writing (serializing) objects
class Writer {
public:
/// Construct a writer that writes to the given output stream
Writer(const OutputStreamP& output);
/// Tell the reflection code we are not reading
inline bool reading() const { return false; }
// --------------------------------------------------- : Handling objects
/// Handle an object: write it under the given name
template <typename T>
void handle(const Char* name, const T& object) {
enterBlock(name);
handle(object);
exitBlock();
}
/// Write a string to the output stream
void handle(const String& str);
void handle(const Char* str) { handle(String(str)); }
/// Write an object of type T to the output stream
template <typename T> void handle(const T& object);
/// Write a vector to the output stream
template <typename T> void handle(const vector<T>& vector);
/// Write a shared_ptr to the output stream
template <typename T> void handle(const shared_ptr<T>& pointer);
/// Write a map to the output stream
//template <typename K, typename V> void handle(map<K,V>& map);
private:
// --------------------------------------------------- : Data
/// Indentation of the current block
int indentation;
/// Did we just open a block (i.e. not written any lines of it)?
bool justOpened;
/// Last key opened
String openedKey;
/// Output stream we are writing to
OutputStreamP output;
/// Text stream wrapping the output stream
wxTextOutputStream stream;
// --------------------------------------------------- : Writing to the stream
/// Start a new block with the given name
void enterBlock(const Char* name);
/// Leave the block we are in
void exitBlock();
/// Write the openedKey and the required indentation
void writeKey();
/// Output some taps to represent the indentation level
void writeIndentation();
};
// ----------------------------------------------------------------------------- : Container types
template <typename T>
void Writer::handle(const vector<T>& vector) {
/*String vectorKey = key;
while (key == vectorKey) { // TODO : check indent
moveNext(); // skip key
vector.resize(vector.size() + 1);
handle(vector.back());
}*/
}
template <typename T>
void Writer::handle(const shared_ptr<T>& pointer) {
if (pointer) handle(*pointer);
}
// ----------------------------------------------------------------------------- : Reflection
/// Implement reflection as used by Writer
#define REFLECT_OBJECT_WRITER(Cls) \
template<> void Writer::handle<Cls>(const Cls& object) { \
const_cast<Cls&>(object).reflect(*this); \
}
// ----------------------------------------------------------------------------- : Reflection for enumerations
/// Implement enum reflection as used by Writer
#define REFLECT_ENUM_WRITER(Enum) \
template<> void Writer::handle<Enum>(const Enum& enum_) { \
EnumWriter writer(*this); \
reflect_ ## Enum(const_cast<Enum&>(enum_), writer); \
}
/// 'Tag' to be used when reflecting enumerations for Writer
class EnumWriter {
public:
inline EnumWriter(Writer& writer)
: writer(writer) {}
/// Handle a possible value for the enum, if the name matches the name in the input
template <typename Enum>
inline void handle(const Char* name, Enum value, Enum enum_) {
if (enum_ == value) {
writer.handle(name);
}
}
private:
Writer& writer; //^ The writer to write output to
};
// ----------------------------------------------------------------------------- : EOF
#endif
+68
View File
@@ -0,0 +1,68 @@
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
#ifndef HEADER_UTIL_PREC
#define HEADER_UTIL_PREC
/** @file util/prec.hpp
*
* Precompiled header, and aliasses for common types
*/
// ----------------------------------------------------------------------------- : Compiler specific
#ifdef _MSC_VER
# pragma warning (disable: 4100) // unreferenced formal parameter
# pragma warning (disable: 4800) // 'int' : forcing value to bool 'true' or 'false' (performance warning)
#endif
// ----------------------------------------------------------------------------- : Includes
// Wx headers
#include <wx/setup.h>
#include <wx/wxprec.h>
#include <wx/image.h>
#include <wx/datetime.h>
// Std headers
#include <vector>
#include <map>
#include <set>
using namespace std;
// MSE utility headers (ones unlikely to change and used everywhere)
#include "for_each.hpp"
#include "string.hpp"
#include "smart_ptr.hpp"
#include "index_map.hpp"
// ----------------------------------------------------------------------------- : Wx Aliasses
// Remove some of the wxUglyness
typedef wxPanel Panel;
typedef wxWindow Window;
typedef wxFrame Frame;
typedef wxBitmap Bitmap;
typedef wxImage Image;
typedef wxColour Color;
typedef wxDC DC;
typedef wxDateTime DateTime;
typedef wxOutputStream OutputStream;
// ----------------------------------------------------------------------------- : Other aliasses
typedef unsigned char Byte;
typedef unsigned int UInt;
/// Null pointer
#define nullptr 0
// ----------------------------------------------------------------------------- : EOF
#endif
+116
View File
@@ -0,0 +1,116 @@
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
#ifndef HEADER_UTIL_REAL_POINT
#define HEADER_UTIL_REAL_POINT
// ----------------------------------------------------------------------------- : Includes
#include <util/prec.hpp>
#include <util/vector2d.hpp>
// ----------------------------------------------------------------------------- : Point using doubles
/// A point using real (double) coordinates
typedef Vector2D RealPoint;
// ----------------------------------------------------------------------------- : Size using doubles
/// A size (width,height) using real (double) coordinates
class RealSize {
public:
double width;
double height;
inline RealSize()
: width(0), height(0)
{}
inline RealSize(double w, double h)
: width(w), height(h)
{}
inline RealSize(wxSize s)
: width(s.GetWidth()), height(s.GetHeight())
{}
/// Addition of two sizes
inline void operator += (const RealSize& s2) {
width += s2.width;
height += s2.height;
}
/// Addition of two sizes
inline RealSize operator + (const RealSize& s2) const {
return RealSize(width + s2.width, height + s2.height);
}
/// Difference of two sizes
inline void operator -= (const RealSize& s2){
width -= s2.width;
height -= s2.height;
}
/// Difference of two sizes
inline RealSize operator - (const RealSize& s2) const {
return RealSize(width - s2.width, height - s2.height);
}
/// Inversion of a size, inverts both components
inline RealSize operator - () const {
return RealSize(-width, -height);
}
/// Multiplying a size by a scalar r, multiplies both components
inline void operator *= (double r) {
width *= r;
height *= r;
}
/// Multiplying a size by a scalar r, multiplies both components
inline RealSize operator * (double r) const {
return RealSize(width * r, height * r);
}
/// Dividing a size by a scalar r, divides both components
inline RealSize operator / (double r) const {
return RealSize(width / r, height / r);
}
/// Can be converted to a wxSize, with integer components
inline operator wxSize() {
return wxSize(realRound(width), realRound(height));
}
};
// ----------------------------------------------------------------------------- : Rectangle using doubles
/// A rectangle (postion and size) using real (double) coordinats
class RealRect {
public:
/// Position of the top left corner
RealPoint position;
/// Size of the rectangle
RealSize size;
inline RealRect(const RealPoint& position, const RealSize& size)
: position(position), size(size)
{}
inline RealRect(double x, double y, double w, double h)
: position(x,y), size(w,h)
{}
};
// ----------------------------------------------------------------------------- : Operators
inline RealPoint operator + (const RealSize& s, const RealPoint& p) {
return RealPoint(p.x + s.width, p.y + s.height);
}
inline RealPoint operator + (const RealPoint& p, const RealSize& s) {
return RealPoint(p.x + s.width, p.y + s.height);
}
inline RealPoint operator - (const RealPoint& p, const RealSize& s) {
return RealPoint(p.x - s.width, p.y - s.height);
}
inline void operator += (RealPoint& p, const RealSize& s) {
p.x += s.width;
p.y += s.height;
}
// ----------------------------------------------------------------------------- : EOF
#endif
+111
View File
@@ -0,0 +1,111 @@
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
#ifndef HEADER_UTIL_REFLECT
#define HEADER_UTIL_REFLECT
/** @file util/reflect.hpp
*
* Reflection of classes, currently reflection is used for (de)serialization.
*/
// ----------------------------------------------------------------------------- : Includes
#include "io/reader.hpp"
#include "io/writer.hpp"
// ----------------------------------------------------------------------------- : Declaring reflection
/// Declare that a class supports reflection
/// Reflection allows the member variables of a class to be inspected at runtime.
#define DECLARE_REFLECTION() \
protected: \
template<class Tag> void reflect_impl(Tag& tag); \
friend class Reader; \
friend class Writer; \
void reflect(Reader& reader); \
void reflect(Writer& writer)
/// Declare that a class supports reflection, which can be overridden in derived classes
#define DECLARE_REFLECTION_VIRTUAL() \
protected: \
template<class Tag> void reflect_impl(Tag& tag); \
friend class Reader; \
friend class Writer; \
virtual void reflect(Reader& reader); \
virtual void reflect(Writer& writer)
// ----------------------------------------------------------------------------- : Implementing reflection
/// Implement the refelection of a class type Cls
/// Reflection allows the member variables of a class to be inspected at runtime.
///
/// Currently creates the methods:
/// - Reader::handle(Cls&)
/// - Writer::handle(Cls&)
/** Usage:
* \begincode
* IMPLEMENT_REFLECTION(MyClass) {
* REFLECT(a_variable_in_my_class);
* REFLECT(another_variable_in_my_class);
* }
* \endcode
*/
#define IMPLEMENT_REFLECTION(Cls) \
REFLECT_OBJECT_READER(Cls) \
REFLECT_OBJECT_WRITER(Cls) \
/* Extra level, so it can be declared virtual */ \
void Cls::reflect(Reader& reader) { \
reflect_impl(reader); \
} \
void Cls::reflect(Writer& writer) { \
reflect_impl(writer); \
} \
template <class Tag> \
void Cls::reflect_impl(Tag& tag)
/// Reflect a variable
#define REFLECT(var) tag.handle(_(#var), var)
/// Reflect a variable under the given name
#define REFLECT_N(name, var) tag.handle(_(name), var)
/// Declare that the variables of a base class should also be reflected
#define REFLECT_BASE(Base) Base::reflect_impl(tag)
// ----------------------------------------------------------------------------- : Reflecting enums
/// Implement the refelection of a enumeration type Enum
/** Usage:
* \begincode
* IMPLEMENT_REFLECTION_ENUM(MyEnum) {
* VALUE(value_of_enum_1);
* VALUE(value_of_enum_2);
* }
* \endcode
*
* When reading the first value declared is the default value
*
* Currently creates the methods:
* - Reader::handle(Enum&
* - Writer::handle(const Enum&)
*/
#define IMPLEMENT_REFLECTION_ENUM(Enum) \
template <class Tag> \
void reflect_ ## Enum (Enum& enum_, Tag& tag); \
REFLECT_ENUM_READER(Enum) \
REFLECT_ENUM_WRITER(Enum) \
template <class Tag> \
void reflect_ ## Enum (Enum& enum_, Tag& tag)
/// Declare a possible value of an enum
#define VALUE(val) tag.handle(_(#val), val, enum_)
/// Declare a possible value of an enum under the given name
#define VALUE_N(name, val) tag.handle(_(name), val, enum_)
// ----------------------------------------------------------------------------- : EOF
#endif
+56
View File
@@ -0,0 +1,56 @@
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
// ----------------------------------------------------------------------------- : Includes
#include <util/rotation.hpp>
// ----------------------------------------------------------------------------- : Rotation
Rotation::Rotation(int angle, const RealRect& rect, double zoom)
: angle(angle)
, size(rect.size)
, origin(rect.position)
, zoom(zoom)
{
// set origin
if (revX()) origin.x += size.width;
if (revY()) origin.x += size.height;
}
RealPoint Rotation::tr(const RealPoint& p) const {
return tr(RealSize(p.x, p.y)) + origin; // TODO : optimize?
}
RealSize Rotation::tr(const RealSize& s) const {
if (sideways()) {
return RealSize(negX(s.height), negY(s.width)) * zoom;
} else {
return RealSize(negX(s.width), negY(s.height)) * zoom;
}
}
RealRect Rotation::tr(const RealRect& r) const {
return RealRect(tr(r.position), tr(r.size));
}
RealSize Rotation::trNoNeg(const RealSize& s) const {
if (sideways()) {
return RealSize(s.height, s.width) * zoom;
} else {
return RealSize(s.width, s.height) * zoom;
}
}
RealRect Rotation::trNoNeg(const RealRect& r) const {
throw "TODO";
}
RealPoint Rotation::trInv(const RealPoint& p) const {
RealPoint p2 = (p - origin) / zoom;
if (sideways()) {
return RealPoint(negY(p2.y), negX(p2.x));
} else {
return RealPoint(negX(p2.x), negY(p2.y));
}
}
+123
View File
@@ -0,0 +1,123 @@
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
#ifndef HEADER_UTIL_ROTATION
#define HEADER_UTIL_ROTATION
// ----------------------------------------------------------------------------- : Includes
#include <util/prec.hpp>
#include <util/real_point.hpp>
#include <gfx/gfx.hpp>
// ----------------------------------------------------------------------------- : Rotation
/// An object that can rotate coordinates inside a specified rectangle
/** This class has lots of tr*** functions, they convert
* internal coordinates to external/screen coordinates.
* tr***inv do the opposite.
*/
class Rotation {
public:
/// Construct a rotation object with the given rectangle of external coordinates
/// and a given rotation angle and zoom factor
Rotation(int angle, const RealRect& rect, double zoom = 1.0);
/// Change the zoom factor
inline void setZoom(double z) { zoom = z; }
/// Change the angle
void setAngle(int a);
/// Translate a size or length
inline double trS(double s) const { return s * zoom; }
/// Translate a single point
RealPoint tr(const RealPoint& p) const;
/// Translate a single size, the result may be negative
RealSize tr(const RealSize& s) const;
/// Translate a rectangle, the size of the result may be negative
RealRect tr(const RealRect& r) const;
/// Translate a size, the result will never be negative
RealSize trNoNeg(const RealSize& s) const;
/// Translate a rectangle, the result will never have a negative size
RealRect trNoNeg(const RealRect& r) const;
/// Translate a size or length back to internal 'coordinates'
inline double trInvS(double s) const { return s / zoom; }
/// Translate a point back to internal coordinates
RealPoint trInv(const RealPoint& p) const;
private:
int angle; //^ The angle of rotation in degrees (counterclockwise)
RealSize size; //^ Size of the rectangle, in external coordinates
RealPoint origin; //^ tr(0,0)
double zoom; //^ Zoom factor, zoom = 2.0 means that 1 internal = 2 external
/// Is the rotation sideways (90 or 270 degrees)?
// Note: angle & 2 == 0 for angle in {0, 180} and != 0 for angle in {90, 270)
inline bool sideways() const { return (angle & 2) != 0; }
/// Is the x axis 'reversed' (after turning sideways)?
inline bool revX() const { return angle >= 180; }
/// Is the y axis 'reversed' (after turning sideways)?
inline bool revY() const { return angle == 90 || angle == 180; }
/// Negate if revX
inline double negX(double d) const { return revX() ? -d : d; }
/// Negate if revY
inline double negY(double d) const { return revY() ? -d : d; }
};
// ----------------------------------------------------------------------------- : Rotater
/// An object that changes a rotation RIIA style
/** Usage:
* \begincode
* Rotation a, b;
* Rotater(a,b);
* a.tr(x) // now acts as a.tr(b.tr(x))
* \endcode
*/
class Rotater {
/// Compose a rotation by onto the rotation rot
/** rot is restored when this object is destructed
*/
Rotater(Rotation& rot, const Rotation& by);
~Rotater();
};
// ----------------------------------------------------------------------------- : RotatedDC
/// A DC with rotation applied
/** All draw** functions take internal coordinates.
*/
class RotatedDC : public Rotation {
public:
RotatedDC(int angle, const RealRect& rect, double zoom = 1.0);
RotatedDC(const Rotation& rotation);
// ----------------------------- : Drawing
void DrawText (const String& text, const RealPoint& pos);
void DrawBitmap(const Bitmap& bitmap, const RealPoint& pos);
void DrawImage (const Image& image, const RealPoint& pos, ImageCombine combine = COMBINE_NORMAL);
void DrawLine (const RealPoint& p1, const RealPoint& p2);
void DrawRectangle(const RealRect& r);
void DrawRoundedRectangle(const RealRect& r, double radius);
// ----------------------------- : Forwarded properties
void SetPen(const wxPen&);
void SetBrush(const wxBrush&);
void SetTextForeground(const Color&);
void SetLogicalFunction(int function);
RealSize getTextExtent(const String& string);
};
// ----------------------------------------------------------------------------- : EOF
#endif
+62
View File
@@ -0,0 +1,62 @@
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
#ifndef HEADER_UTIL_SMART_PTR
#define HEADER_UTIL_SMART_PTR
/** @file util/shared_ptr.hpp
*
* Utilities related to boost smart pointers
*/
// ----------------------------------------------------------------------------- : Includes
#include <boost/shared_ptr.hpp>
using namespace boost;
// ----------------------------------------------------------------------------- : Declaring
/// Declares the type TypeP as a shared_ptr<Type>
#define DECLARE_POINTER_TYPE(Type) \
class Type; \
typedef shared_ptr<Type> Type##P
// ----------------------------------------------------------------------------- : Creating
/// Allocate a new shared-pointed object
template <typename T>
inline shared_ptr<T> new_shared() {
return shared_ptr<T>(new T());
}
/// Allocate a new shared-pointed object, given one argument to pass to the ctor of T
template <typename T, typename A0>
inline shared_ptr<T> new_shared1(const A0& a0) {
return shared_ptr<T>(new T(a0));
}
/// Allocate a new shared-pointed object, given two arguments to pass to the ctor of T
template <typename T, typename A0, typename A1>
inline shared_ptr<T> new_shared2(const A0& a0, const A1& a1) {
return shared_ptr<T>(new T(a0, a1));
}
/// Allocate a new shared-pointed object, given three arguments to pass to the ctor of T
template <typename T, typename A0, typename A1, typename A2>
inline shared_ptr<T> new_shared3(const A0& a0, const A1& a1, const A2& a2) {
return shared_ptr<T>(new T(a0, a1, a2));
}
/// Allocate a new shared-pointed object, given four arguments to pass to the ctor of T
template <typename T, typename A0, typename A1, typename A2, typename A3>
inline shared_ptr<T> new_shared4(const A0& a0, const A1& a1, const A2& a2, const A3& a3) {
return shared_ptr<T>(new T(a0, a1, a2, a3));
}
/// Allocate a new shared-pointed object, given seven arguments to pass to the ctor of T
template <typename T, typename A0, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6>
inline shared_ptr<T> new_shared7(const A0& a0, const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6) {
return shared_ptr<T>(new T(a0, a1, a2, a3, a4, a5, a6));
}
// ----------------------------------------------------------------------------- : EOF
#endif
+118
View File
@@ -0,0 +1,118 @@
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
// ----------------------------------------------------------------------------- : Includes
#include "string.hpp"
#include "for_each.hpp"
#include <wx/txtstrm.h>
// ----------------------------------------------------------------------------- : Unicode
String decodeUTF8BOM(const String& s) {
#ifdef UNICODE
if (!s.empty() && s.GetChar(0) == L'\xFEFF') {
// skip byte-order-mark
return s.substr(1);
} else {
return s;
}
#else
wxWCharBuffer buf = s.wc_str(wxConvUTF8);
if (buf && buf[size_t(0)] == L'\xFEFF') {
// skip byte-order-mark
return String(buf + 1, *wxConvCurrent);
} else {
return String(buf, *wxConvCurrent);
}
#endif
}
void writeUTF8(wxTextOutputStream& stream, const String& str) {
#ifdef UNICODE
stream.WriteString(str);
#else
wxWCharBuffer buf = str.wc_str(*wxConvCurrent);
stream.WriteString(wxString(buf, wxConvUTF8));
#endif
}
// ----------------------------------------------------------------------------- : String utilities
String trim(const String& s){
size_t start = s.find_first_not_of(_(" \t"));
size_t end = s.find_last_not_of( _(" \t"));
if (start == String::npos) {
return String();
} else {
return s.substr(start, end - start + 1);
}
}
String trimLeft(const String& s) {
size_t start = s.find_first_not_of(_(' '));
if (start == String::npos) {
return String();
} else {
return s.substr(start);
}
}
// ----------------------------------------------------------------------------- : Words
String lastWord(const String& s) {
size_t endLastWord = s.find_last_not_of(_(' '));
size_t startLastWord = s.find_last_of( _(' '), endLastWord);
if (endLastWord == String::npos) {
return String(); // empty string
} else if (startLastWord == String::npos) {
return s.substr(0, endLastWord + 1);// first word
} else {
return s.substr(startLastWord + 1, endLastWord - startLastWord);
}
}
String stripLastWord(const String& s) {
size_t endLastWord = s.find_last_not_of(_(' '));
size_t startLastWord = s.find_last_of(_(' '), endLastWord);
if (endLastWord == String::npos || startLastWord == String::npos) {
return String(); // single word or empty string
} else {
return s.substr(0, startLastWord + 1);
}
}
// ----------------------------------------------------------------------------- : Caseing
/// Quick check to see if the substring starting at the given iterator is equal
/// to some given string
bool is_substr(const String& s, String::iterator it, const Char* cmp) {
while (it != s.end() && *cmp != 0) {
if (*it++ != *cmp++) return false;
}
return *cmp == 0;
}
String capitalize(const String& s) {
String result = s;
bool afterSpace = true;
FOR_EACH_IT(it, result) {
if (*it == ' ') {
afterSpace = true;
} else if (afterSpace) {
afterSpace = false;
if (it != s.begin() &&
(is_substr(result,it,_("is ")) || is_substr(result,it,_("the ")) ||
is_substr(result,it,_("in ")) || is_substr(result,it,_("of ")) ||
is_substr(result,it,_("to ")) || is_substr(result,it,_("at ")) ||
is_substr(result,it,_("a " )))) {
// Short words are not capitalized, keep lower case
} else {
*it = toUpper(*it);
}
}
}
return result;
}
+108
View File
@@ -0,0 +1,108 @@
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
#ifndef HEADER_UTIL_STRING
#define HEADER_UTIL_STRING
/** @file util/string.hpp
*
* String and character utility functions and macros
*/
// ----------------------------------------------------------------------------- : Includes
#include "prec.hpp"
#include "for_each.hpp"
#include <ctype.h>
#include <boost/preprocessor/cat.hpp>
class wxTextOutputStream;
// ----------------------------------------------------------------------------- : String type
/// The string type used throughout MSE
typedef wxString String;
DECLARE_TYPEOF_NO_REV(String); // iterating over characters in a string
// ----------------------------------------------------------------------------- : Unicode
/// u if UNICODE is defined, a otherwise
#ifdef UNICODE
# define IF_UNICODE(u,a) u
#else
# define IF_UNICODE(u,a) a
#endif
#undef _
/// A string/character constant, correctly handled in unicode builds
#define _(S) IF_UNICODE(BOOST_PP_CAT(L,S), S)
/// The character type used
typedef IF_UNICODE(wchar_t, char) Char;
/// Decode a UTF8 string
/** In non-unicode builds the input is considered to be an incorrectly encoded utf8 string.
* In unicode builds it is a normal string, utf8 already decoded.
* Also removes a byte-order-mark from the start of the string if it is pressent
*/
String decodeUTF8BOM(const String& s);
/// UTF8 Byte order mark for writing at the start of files
/** In non-unicode builds it is UTF8 encoded \xFEFF
* In unicode builds it is a normal \xFEFF
*/
const Char BYTE_ORDER_MARK[] = IF_UNICODE(L"\xFEFF", "\xEF\xBB\xBF");
/// Writes a string to an output stream, encoded as UTF8
void writeUTF8(wxTextOutputStream& stream, const String& str);
// ----------------------------------------------------------------------------- : Char functions
// Character set tests
inline bool isSpace(Char c) { return IF_UNICODE( iswspace(c) , isspace(c) ); }
inline bool isAlpha(Char c) { return IF_UNICODE( iswalpha(c) , isalpha(c) ); }
inline bool isDigit(Char c) { return IF_UNICODE( iswdigit(c) , isdigit(c) ); }
inline bool isAlnum(Char c) { return IF_UNICODE( iswalnum(c) , isalnum(c) ); }
inline bool isUpper(Char c) { return IF_UNICODE( iswupper(c) , isupper(c) ); }
inline bool isLower(Char c) { return IF_UNICODE( iswlower(c) , islower(c) ); }
// Character conversions
inline Char toUpper(Char c) { return IF_UNICODE( towupper(c) , toupper(c) ); }
inline Char toLower(Char c) { return IF_UNICODE( towlower(c) , tolower(c) ); }
// ----------------------------------------------------------------------------- : String utilities
/// Remove whitespace from both ends of a string
String trim(const String&);
/// Remove whitespace from the start of a string
String trimLeft(const String&);
// ----------------------------------------------------------------------------- : Words
/// Returns the last word in a string
String lastWord(const String&);
/// Remove the last word from a string, leaves whitespace before that word
String stripLastWord(const String&);
// ----------------------------------------------------------------------------- : Caseing
/// Make each word in a string start with an upper case character.
/// for use in menus
String capitalize(const String&);
/// Make the first word in a string start with an upper case character.
/// for use in dialogs
String capitalizeSentence(const String&);
/// Convert a field name to cannocial form: lower case and ' ' instead of '_'
/// non alphanumeric characters are ignored
/// "camalCase" is converted to words "camel case"
String cannocialNameForm(const String&);
// ----------------------------------------------------------------------------- : EOF
#endif
+141
View File
@@ -0,0 +1,141 @@
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
#ifndef HEADER_UTIL_VECTOR2D
#define HEADER_UTIL_VECTOR2D
// ----------------------------------------------------------------------------- : Includes
#include <util/prec.hpp>
#include <limits>
// ----------------------------------------------------------------------------- : Rounding
// Rounding function for converting doubles to integers
inline int realRound(double d) {
return d > 0 ? d + 0.5 : d - 0.5;
}
// ----------------------------------------------------------------------------- : Vector2D
/// A simple 2d vector class
class Vector2D {
public:
/// Coordinates of this vector
double x, y;
/// Default contructor
inline Vector2D()
: x(0), y(0) {}
/// Contructor with given x and y values
inline Vector2D(double x, double y)
: x(x), y(y) {}
/// Addition of two vectors
inline Vector2D operator + (Vector2D p2) const {
return Vector2D(x + p2.x, y + p2.y);
}
/// Addition of two vectors
inline void operator += (Vector2D p2) {
x += p2.x; y += p2.y;
}
/// Subtract two vectors
inline Vector2D operator - (Vector2D p2) const {
return Vector2D(x - p2.x, y - p2.y);
}
/// Subtract two vectors
inline void operator -= (Vector2D p2) {
x -= p2.x; y -= p2.y;
}
/// Invert a vector
inline Vector2D operator - () const {
return Vector2D(-x, -y);
}
/// Multiply with a scalar
inline Vector2D operator * (double r) const {
return Vector2D(x * r, y * r);
}
/// Multiply with a scalar
inline void operator *= (double r) {
x *= r; y *= r;
}
/// Divide by a scalar
inline Vector2D operator / (double r) const {
return Vector2D(x / r, y / r);
}
/// Divide by a scalar
inline void operator /= (double r) {
x /= r; y /= r;
}
/// Inner product with another vector
inline double dot(Vector2D p2) const {
return (x * p2.x) + (y * p2.y);
}
/// Outer product with another vector
inline double cross(Vector2D p2) const {
return (x * p2.y) - (y * p2.x);
}
/// Piecewise multiplication
inline Vector2D mul(Vector2D p2) {
return Vector2D(x * p2.x, y * p2.y);
}
/// Piecewise division
inline Vector2D div(Vector2D p2) {
return Vector2D(x / p2.x, y / p2.y);
}
/// Apply a 'matrix' to this vector
inline Vector2D mul(Vector2D mx, Vector2D my) {
return Vector2D(dot(mx), dot(my));
}
/// Returns the square of the length of this vector
inline double lengthSqr() const {
return x*x + y*y;
}
/// Returns the length of this vector
inline double length() const {
return sqrt(lengthSqr());
}
/// Returns a normalized version of this vector
/// i.e. length() == 1
inline Vector2D normalized() const {
return *this / length();
}
inline operator wxPoint() const {
return wxPoint(realRound(x), realRound(y));
}
// Vector at infinity
static inline Vector2D infinity() {
double inf = numeric_limits<double>::infinity();
return Vector2D(inf, inf);
}
};
/// Piecewise minimum
inline Vector2D piecewise_min(Vector2D a, Vector2D b) {
return Vector2D(
a.x < b.x ? a.x : b.x,
a.y < b.y ? a.y : b.y
);
}
/// Piecewise maximum
inline Vector2D piecewise_max(Vector2D a, Vector2D b) {
return Vector2D(
a.x < b.x ? b.x : a.x,
a.y < b.y ? b.y : a.y
);
}
// ----------------------------------------------------------------------------- : EOF
#endif
+154
View File
@@ -0,0 +1,154 @@
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) 2001 - 2006 Twan van Laarhoven |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
#ifndef HEADER_UTIL_WINDOW_ID
#define HEADER_UTIL_WINDOW_ID
// ----------------------------------------------------------------------------- : Includes
// ----------------------------------------------------------------------------- : Menu ids
/// Window ids for menus and toolbars
enum MenuID {
ID_MENU_MIN = 0
, ID_MENU_MAX = 999
// File menu
, ID_FILE_NEW = wxID_NEW
, ID_FILE_OPEN = wxID_OPEN
, ID_FILE_SAVE = wxID_SAVE
, ID_FILE_SAVE_AS = wxID_SAVEAS
, ID_FILE_STORE = 1
, ID_FILE_EXIT = wxID_EXIT
, ID_FILE_EXPORT = 2
, ID_FILE_EXPORT_HTML = 3
, ID_FILE_EXPORT_IMAGE = 4
, ID_FILE_EXPORT_IMAGES = 5
, ID_FILE_EXPORT_APPR = 6
, ID_FILE_EXPORT_MWS = 7
, ID_FILE_PRINT = wxID_PRINT
, ID_FILE_PRINT_PREVIEW = wxID_PREVIEW
, ID_FILE_INSPECT = 8
, ID_FILE_RECENT = wxID_FILE1
, ID_FILE_RECENT_MAX = wxID_FILE9
// Edit menu
, ID_EDIT_UNDO = wxID_UNDO
, ID_EDIT_REDO = wxID_REDO
, ID_EDIT_CUT = wxID_CUT
, ID_EDIT_COPY = wxID_COPY
, ID_EDIT_PASTE = wxID_PASTE
, ID_EDIT_DELETE = 101
, ID_EDIT_DUPLICATE = 102
, ID_EDIT_FIND = wxID_FIND
, ID_EDIT_FIND_NEXT = 103
, ID_EDIT_REPLACE = wxID_REPLACE
, ID_EDIT_PREFERENCES = 104
// Window menu (MainWindow)
, ID_WINDOW_NEW = 201
, ID_WINDOW_MIN = 202
, ID_WINDOW_MAX = 220
// Help menu (MainWindow)
, ID_HELP_INDEX = 301
, ID_HELP_ABOUT
// Mode menu (SymbolWindow)
, ID_MODE_MIN = 401
, ID_MODE_SELECT = ID_MODE_MIN
, ID_MODE_ROTATE
, ID_MODE_POINTS
, ID_MODE_SHAPES
, ID_MODE_PAINT
, ID_MODE_MAX
};
// ----------------------------------------------------------------------------- : Child ids
/// Ids for menus on child panels (MainWindowPanel / SymbolEditorBase)
enum ChildMenuID {
ID_CHILD_MIN = 1000
, ID_CHILD_MAX = 2999
// Cards menu
, ID_CARD_ADD = 1001
, ID_CARD_ADD_MULT
, ID_CARD_REMOVE
, ID_CARD_PREV
, ID_CARD_NEXT
, ID_CARD_ROTATE
, ID_CARD_ROTATE_0
, ID_CARD_ROTATE_90
, ID_CARD_ROTATE_180
, ID_CARD_ROTATE_270
// Keyword menu
, ID_KEYWORD_ADD = 1101
, ID_KEYWORD_REMOVE
, ID_KEYWORD_PREV
, ID_KEYWORD_NEXT
// SymbolSelectEditor toolbar/menu
, ID_PART = 2001
, ID_PART_MERGE = ID_PART + PART_MERGE
, ID_PART_SUBTRACT = ID_PART + PART_SUBTRACT
, ID_PART_INTERSECTION = ID_PART + PART_INTERSECTION
, ID_PART_DIFFERENCE = ID_PART + PART_DIFFERENCE
, ID_PART_OVERLAP = ID_PART + PART_OVERLAP
, ID_PART_BORDER = ID_PART + PART_BORDER
, ID_PART_MAX
// SymbolPointEditor toolbar/menu
, ID_SEGMENT = 2101
, ID_SEGMENT_LINE = ID_SEGMENT + SEGMENT_LINE
, ID_SEGMENT_CURVE = ID_SEGMENT + SEGMENT_CURVE
, ID_SEGMENT_MAX
, ID_LOCK = 2151
, ID_LOCK_FREE = ID_LOCK + LOCK_FREE
, ID_LOCK_DIR = ID_LOCK + LOCK_DIR
, ID_LOCK_SIZE = ID_LOCK + LOCK_SIZE
, ID_LOCK_MAX
// SymbolBasicShapeEditor toolbar/menu
, ID_SHAPE = 2201
, ID_SHAPE_CIRCLE = ID_SHAPE
, ID_SHAPE_RECTANGLE
, ID_SHAPE_POLYGON
, ID_SHAPE_STAR
, ID_SHAPE_MAX
, ID_SIDES
};
// ----------------------------------------------------------------------------- : Control/window ids
/// Window ids for controls
enum ControlID {
ID_CONTROL_MIN = 6000
, ID_CONTROL_MAX = 6999
// Controls
, ID_VIEWER = 6001
, ID_EDITOR
, ID_CONTROL
, ID_CARD_LIST
, ID_PART_LIST
, ID_NOTES
, ID_KEYWORD
, ID_PARAMETER
, ID_SEPARATOR
, ID_REMINDER
, ID_RULES
};
// ----------------------------------------------------------------------------- : EOF
#endif