mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-10 13:06:59 -04:00
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:
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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)"));
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user