mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-12 05:36:59 -04:00
Change tabs to two spaces.
This commit is contained in:
+61
-61
@@ -25,91 +25,91 @@ enum AddingOrRemoving {ADD, REMOVE};
|
||||
template <typename T>
|
||||
class GenericAddAction {
|
||||
public:
|
||||
GenericAddAction(AddingOrRemoving, const T& item, const vector<T>& container);
|
||||
GenericAddAction(AddingOrRemoving, const vector<T>& items, const vector<T>& container);
|
||||
|
||||
String getName() const;
|
||||
void perform(vector<T>& container, bool to_undo) const;
|
||||
|
||||
/// A step of removing/adding
|
||||
struct Step {
|
||||
inline Step(size_t pos, const T& item) : pos(pos), item(item) {}
|
||||
size_t pos;
|
||||
T item;
|
||||
};
|
||||
bool adding; ///< Were objects added? (as opposed to removed)
|
||||
vector<Step> steps; ///< Added/removed objects, sorted by ascending pos
|
||||
GenericAddAction(AddingOrRemoving, const T& item, const vector<T>& container);
|
||||
GenericAddAction(AddingOrRemoving, const vector<T>& items, const vector<T>& container);
|
||||
|
||||
String getName() const;
|
||||
void perform(vector<T>& container, bool to_undo) const;
|
||||
|
||||
/// A step of removing/adding
|
||||
struct Step {
|
||||
inline Step(size_t pos, const T& item) : pos(pos), item(item) {}
|
||||
size_t pos;
|
||||
T item;
|
||||
};
|
||||
bool adding; ///< Were objects added? (as opposed to removed)
|
||||
vector<Step> steps; ///< Added/removed objects, sorted by ascending pos
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : Implementation
|
||||
|
||||
template <typename T>
|
||||
bool contains(const vector<T>& items, const T& item) {
|
||||
return find(items.begin(), items.end(), item) != items.end();
|
||||
return find(items.begin(), items.end(), item) != items.end();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
GenericAddAction<T>::GenericAddAction(AddingOrRemoving ar, const T& item, const vector<T>& container)
|
||||
: adding(ar == ADD)
|
||||
: adding(ar == ADD)
|
||||
{
|
||||
if (ar == ADD) {
|
||||
size_t pos = container.size();
|
||||
steps.push_back(Step(pos, item));
|
||||
} else {
|
||||
for (size_t pos = 0 ; pos < container.size() ; ++pos) {
|
||||
if (container[pos] == item) {
|
||||
steps.push_back(Step(pos, item));
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw InternalError(_("Item to remove not found in container"));
|
||||
}
|
||||
if (ar == ADD) {
|
||||
size_t pos = container.size();
|
||||
steps.push_back(Step(pos, item));
|
||||
} else {
|
||||
for (size_t pos = 0 ; pos < container.size() ; ++pos) {
|
||||
if (container[pos] == item) {
|
||||
steps.push_back(Step(pos, item));
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw InternalError(_("Item to remove not found in container"));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
GenericAddAction<T>::GenericAddAction(AddingOrRemoving ar, const vector<T>& items, const vector<T>& container)
|
||||
: adding(ar == ADD)
|
||||
: adding(ar == ADD)
|
||||
{
|
||||
if (ar == ADD) {
|
||||
size_t pos = container.size();
|
||||
for (typename vector<T>::const_iterator it = items.begin() ; it != items.end() ; ++it) {
|
||||
steps.push_back(Step(pos++, *it));
|
||||
}
|
||||
} else {
|
||||
for (size_t pos = 0 ; pos < container.size() ; ++pos) {
|
||||
if (contains(items, container[pos])) {
|
||||
steps.push_back(Step(pos, container[pos]));
|
||||
}
|
||||
}
|
||||
if (steps.size() != items.size()) {
|
||||
throw InternalError(_("Item to remove not found in container"));
|
||||
}
|
||||
}
|
||||
if (ar == ADD) {
|
||||
size_t pos = container.size();
|
||||
for (typename vector<T>::const_iterator it = items.begin() ; it != items.end() ; ++it) {
|
||||
steps.push_back(Step(pos++, *it));
|
||||
}
|
||||
} else {
|
||||
for (size_t pos = 0 ; pos < container.size() ; ++pos) {
|
||||
if (contains(items, container[pos])) {
|
||||
steps.push_back(Step(pos, container[pos]));
|
||||
}
|
||||
}
|
||||
if (steps.size() != items.size()) {
|
||||
throw InternalError(_("Item to remove not found in container"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
String GenericAddAction<T>::getName() const {
|
||||
String type = type_name(steps.front().item) + (steps.size() == 1 ? _("") : _("s"));
|
||||
return adding ? _ACTION_1_("add item", type) : _ACTION_1_("remove item", type);
|
||||
String type = type_name(steps.front().item) + (steps.size() == 1 ? _("") : _("s"));
|
||||
return adding ? _ACTION_1_("add item", type) : _ACTION_1_("remove item", type);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void GenericAddAction<T>::perform(vector<T>& container, bool to_undo) const {
|
||||
if (adding != to_undo) {
|
||||
// (re)insert the items
|
||||
// ascending order, this is the reverse of removal
|
||||
FOR_EACH_CONST(s, steps) {
|
||||
assert(s.pos <= container.size());
|
||||
container.insert(container.begin() + s.pos, s.item);
|
||||
}
|
||||
} else {
|
||||
// remove the items
|
||||
// descending order, because earlier removals shift the rest of the vector
|
||||
FOR_EACH_CONST_REVERSE(s, steps) {
|
||||
assert(s.pos < container.size());
|
||||
container.erase(container.begin() + s.pos);
|
||||
}
|
||||
}
|
||||
if (adding != to_undo) {
|
||||
// (re)insert the items
|
||||
// ascending order, this is the reverse of removal
|
||||
FOR_EACH_CONST(s, steps) {
|
||||
assert(s.pos <= container.size());
|
||||
container.insert(container.begin() + s.pos, s.item);
|
||||
}
|
||||
} else {
|
||||
// remove the items
|
||||
// descending order, because earlier removals shift the rest of the vector
|
||||
FOR_EACH_CONST_REVERSE(s, steps) {
|
||||
assert(s.pos < container.size());
|
||||
container.erase(container.begin() + s.pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : EOF
|
||||
|
||||
+148
-148
@@ -20,191 +20,191 @@ DECLARE_TYPEOF_COLLECTION(KeywordModeP);
|
||||
// ----------------------------------------------------------------------------- : Add Keyword
|
||||
|
||||
AddKeywordAction::AddKeywordAction(Set& set)
|
||||
: KeywordListAction(set)
|
||||
, action(ADD, intrusive(new Keyword()), set.keywords)
|
||||
: KeywordListAction(set)
|
||||
, action(ADD, intrusive(new Keyword()), set.keywords)
|
||||
{
|
||||
Keyword& keyword = *action.steps.front().item;
|
||||
// find default mode
|
||||
FOR_EACH(mode, set.game->keyword_modes) {
|
||||
if (mode->is_default) {
|
||||
keyword.mode = mode->name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Keyword& keyword = *action.steps.front().item;
|
||||
// find default mode
|
||||
FOR_EACH(mode, set.game->keyword_modes) {
|
||||
if (mode->is_default) {
|
||||
keyword.mode = mode->name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
AddKeywordAction::AddKeywordAction(AddingOrRemoving ar, Set& set, const KeywordP& keyword)
|
||||
: KeywordListAction(set)
|
||||
, action(ar, keyword, set.keywords)
|
||||
: KeywordListAction(set)
|
||||
, action(ar, keyword, set.keywords)
|
||||
{}
|
||||
/*AddKeywordAction::AddKeywordAction(AddingOrRemoving ar, Set& set, const vector<KeywordP>& keyword)
|
||||
: KeywordListAction(set)
|
||||
, action(ar, keywords, set.keywords)
|
||||
: KeywordListAction(set)
|
||||
, action(ar, keywords, set.keywords)
|
||||
{}*/
|
||||
|
||||
String AddKeywordAction::getName(bool to_undo) const {
|
||||
return action.getName();
|
||||
return action.getName();
|
||||
}
|
||||
|
||||
void AddKeywordAction::perform(bool to_undo) {
|
||||
action.perform(set.keywords, to_undo);
|
||||
set.keyword_db.clear();
|
||||
action.perform(set.keywords, to_undo);
|
||||
set.keyword_db.clear();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Changing keywords
|
||||
|
||||
KeywordReminderTextValue::KeywordReminderTextValue(Set& set, const TextFieldP& field, Keyword* keyword, bool editable)
|
||||
: KeywordTextValue(field, keyword, &keyword->reminder.getMutableUnparsed(), editable)
|
||||
, set(set)
|
||||
, keyword(*keyword)
|
||||
: KeywordTextValue(field, keyword, &keyword->reminder.getMutableUnparsed(), editable)
|
||||
, set(set)
|
||||
, keyword(*keyword)
|
||||
{}
|
||||
|
||||
void KeywordReminderTextValue::store() {
|
||||
if (!editable) {
|
||||
retrieve();
|
||||
return;
|
||||
}
|
||||
// new value
|
||||
String new_value = untag(value);
|
||||
// Try to parse the script
|
||||
vector<ScriptParseError> parse_errors;
|
||||
ScriptP new_script = parse(new_value, nullptr, true, parse_errors);
|
||||
if (parse_errors.empty()) {
|
||||
// parsed okay
|
||||
if (checkScript(new_script)) {
|
||||
// also runs okay, assign
|
||||
keyword.reminder.setScriptP(new_script);
|
||||
keyword.reminder.setUnparsed(new_value);
|
||||
}
|
||||
} else {
|
||||
// parse errors, report
|
||||
errors = ScriptParseErrors(parse_errors).what();
|
||||
}
|
||||
// re-highlight input, show errors
|
||||
highlight(new_value, parse_errors);
|
||||
if (!editable) {
|
||||
retrieve();
|
||||
return;
|
||||
}
|
||||
// new value
|
||||
String new_value = untag(value);
|
||||
// Try to parse the script
|
||||
vector<ScriptParseError> parse_errors;
|
||||
ScriptP new_script = parse(new_value, nullptr, true, parse_errors);
|
||||
if (parse_errors.empty()) {
|
||||
// parsed okay
|
||||
if (checkScript(new_script)) {
|
||||
// also runs okay, assign
|
||||
keyword.reminder.setScriptP(new_script);
|
||||
keyword.reminder.setUnparsed(new_value);
|
||||
}
|
||||
} else {
|
||||
// parse errors, report
|
||||
errors = ScriptParseErrors(parse_errors).what();
|
||||
}
|
||||
// re-highlight input, show errors
|
||||
highlight(new_value, parse_errors);
|
||||
}
|
||||
|
||||
void KeywordReminderTextValue::retrieve() {
|
||||
vector<ScriptParseError> no_errors;
|
||||
highlight(*underlying, no_errors);
|
||||
vector<ScriptParseError> no_errors;
|
||||
highlight(*underlying, no_errors);
|
||||
}
|
||||
|
||||
void KeywordReminderTextValue::highlight(const String& code, const vector<ScriptParseError>& errors) {
|
||||
// Add tags to indicate code / syntax highlight
|
||||
// i.e. bla {if code "x" } bla
|
||||
// becomes:
|
||||
// bla <code>{<code-kw>if</code-kw> code "<code-string>x</code-string>" } bla
|
||||
String new_value;
|
||||
vector<int> in_brace; // types of braces we are in, 0 for code brace, 1 for string escapes
|
||||
bool in_string = true;
|
||||
vector<ScriptParseError>::const_iterator error = errors.begin();
|
||||
for (size_t pos = 0 ; pos < code.size() ; ) {
|
||||
// error underlining
|
||||
while (error != errors.end() && error->start == error->end) ++error;
|
||||
if (error != errors.end()) {
|
||||
if (error->start == pos) {
|
||||
new_value += _("<error>");
|
||||
}
|
||||
if (error->end == pos) {
|
||||
++error;
|
||||
if (error == errors.end() || error->start > pos) {
|
||||
new_value += _("</error>");
|
||||
} else {
|
||||
// immediatly open again
|
||||
}
|
||||
}
|
||||
}
|
||||
// process a character
|
||||
Char c = code.GetChar(pos);
|
||||
if (c == _('<')) {
|
||||
new_value += _('\1'); // escape
|
||||
++pos;
|
||||
} else if (c == _('{')) {
|
||||
if (in_string) {
|
||||
new_value += _("<code>");
|
||||
in_brace.push_back(1);
|
||||
in_string = false;
|
||||
} else {
|
||||
in_brace.push_back(0);
|
||||
}
|
||||
new_value += c;
|
||||
++pos;
|
||||
} else if (c == _('}') && !in_string) {
|
||||
new_value += c;
|
||||
if (!in_brace.empty() && in_brace.back() == 1) {
|
||||
new_value += _("</code>");
|
||||
in_string = true;
|
||||
}
|
||||
if (!in_brace.empty()) in_brace.pop_back();
|
||||
++pos;
|
||||
} else if (c == _('"')) {
|
||||
if (in_string) {
|
||||
in_string = false;
|
||||
new_value += _("\"</code-str><code>");
|
||||
} else {
|
||||
in_string = true;
|
||||
new_value += _("</code><code-str>\"");
|
||||
}
|
||||
++pos;
|
||||
} else if (c == _('\\') && in_string && pos + 1 < code.size()) {
|
||||
new_value += c + code.GetChar(pos + 1); // escape code
|
||||
pos += 2;
|
||||
} else if (is_substr(code, pos, _("if ")) && !in_string) {
|
||||
new_value += _("<code-kw>if</code-kw> ");
|
||||
pos += 3;
|
||||
} else if (is_substr(code, pos, _("then ")) && !in_string) {
|
||||
new_value += _("<code-kw>then</code-kw> ");
|
||||
pos += 5;
|
||||
} else if (is_substr(code, pos, _("else ")) && !in_string) {
|
||||
new_value += _("<code-kw>else</code-kw> ");
|
||||
pos += 5;
|
||||
} else if (is_substr(code, pos, _("for ")) && !in_string) {
|
||||
new_value += _("<code-kw>for</code-kw> ");
|
||||
pos += 4;
|
||||
} else if (is_substr(code, pos, _("param")) && !in_string) {
|
||||
// parameter reference
|
||||
size_t end = code.find_first_not_of(_("0123456789"), pos + 5);
|
||||
if (end == String::npos) end = code.size();
|
||||
String param = code.substr(pos, end-pos);
|
||||
new_value += _("<ref-") + param + _(">") + param + _("</ref-") + param + _(">");
|
||||
pos = end;
|
||||
} else {
|
||||
new_value += c;
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
// set
|
||||
value = new_value;
|
||||
// Add tags to indicate code / syntax highlight
|
||||
// i.e. bla {if code "x" } bla
|
||||
// becomes:
|
||||
// bla <code>{<code-kw>if</code-kw> code "<code-string>x</code-string>" } bla
|
||||
String new_value;
|
||||
vector<int> in_brace; // types of braces we are in, 0 for code brace, 1 for string escapes
|
||||
bool in_string = true;
|
||||
vector<ScriptParseError>::const_iterator error = errors.begin();
|
||||
for (size_t pos = 0 ; pos < code.size() ; ) {
|
||||
// error underlining
|
||||
while (error != errors.end() && error->start == error->end) ++error;
|
||||
if (error != errors.end()) {
|
||||
if (error->start == pos) {
|
||||
new_value += _("<error>");
|
||||
}
|
||||
if (error->end == pos) {
|
||||
++error;
|
||||
if (error == errors.end() || error->start > pos) {
|
||||
new_value += _("</error>");
|
||||
} else {
|
||||
// immediatly open again
|
||||
}
|
||||
}
|
||||
}
|
||||
// process a character
|
||||
Char c = code.GetChar(pos);
|
||||
if (c == _('<')) {
|
||||
new_value += _('\1'); // escape
|
||||
++pos;
|
||||
} else if (c == _('{')) {
|
||||
if (in_string) {
|
||||
new_value += _("<code>");
|
||||
in_brace.push_back(1);
|
||||
in_string = false;
|
||||
} else {
|
||||
in_brace.push_back(0);
|
||||
}
|
||||
new_value += c;
|
||||
++pos;
|
||||
} else if (c == _('}') && !in_string) {
|
||||
new_value += c;
|
||||
if (!in_brace.empty() && in_brace.back() == 1) {
|
||||
new_value += _("</code>");
|
||||
in_string = true;
|
||||
}
|
||||
if (!in_brace.empty()) in_brace.pop_back();
|
||||
++pos;
|
||||
} else if (c == _('"')) {
|
||||
if (in_string) {
|
||||
in_string = false;
|
||||
new_value += _("\"</code-str><code>");
|
||||
} else {
|
||||
in_string = true;
|
||||
new_value += _("</code><code-str>\"");
|
||||
}
|
||||
++pos;
|
||||
} else if (c == _('\\') && in_string && pos + 1 < code.size()) {
|
||||
new_value += c + code.GetChar(pos + 1); // escape code
|
||||
pos += 2;
|
||||
} else if (is_substr(code, pos, _("if ")) && !in_string) {
|
||||
new_value += _("<code-kw>if</code-kw> ");
|
||||
pos += 3;
|
||||
} else if (is_substr(code, pos, _("then ")) && !in_string) {
|
||||
new_value += _("<code-kw>then</code-kw> ");
|
||||
pos += 5;
|
||||
} else if (is_substr(code, pos, _("else ")) && !in_string) {
|
||||
new_value += _("<code-kw>else</code-kw> ");
|
||||
pos += 5;
|
||||
} else if (is_substr(code, pos, _("for ")) && !in_string) {
|
||||
new_value += _("<code-kw>for</code-kw> ");
|
||||
pos += 4;
|
||||
} else if (is_substr(code, pos, _("param")) && !in_string) {
|
||||
// parameter reference
|
||||
size_t end = code.find_first_not_of(_("0123456789"), pos + 5);
|
||||
if (end == String::npos) end = code.size();
|
||||
String param = code.substr(pos, end-pos);
|
||||
new_value += _("<ref-") + param + _(">") + param + _("</ref-") + param + _(">");
|
||||
pos = end;
|
||||
} else {
|
||||
new_value += c;
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
// set
|
||||
value = new_value;
|
||||
}
|
||||
|
||||
bool KeywordReminderTextValue::checkScript(const ScriptP& script) {
|
||||
try {
|
||||
Context& ctx = set.cards.empty() ? set.getContext() : set.getContext(set.cards.front());
|
||||
LocalScope scope(ctx);
|
||||
for (size_t i = 0 ; i < keyword.parameters.size() ; ++i) {
|
||||
const KeywordParam& kwp = *keyword.parameters[i];
|
||||
String param_name = String(_("param")) << (int)(i+1);
|
||||
String param_value = _("<atom-kwpph>") + (kwp.placeholder.empty() ? kwp.name : kwp.placeholder) + _("</atom-kwpph>");
|
||||
ctx.setVariable(param_name, intrusive(new KeywordParamValue(kwp.name, _(""), _(""), param_value)));
|
||||
}
|
||||
script->eval(ctx);
|
||||
errors.clear();
|
||||
return true;
|
||||
} catch (const Error& e) {
|
||||
errors = e.what();
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
Context& ctx = set.cards.empty() ? set.getContext() : set.getContext(set.cards.front());
|
||||
LocalScope scope(ctx);
|
||||
for (size_t i = 0 ; i < keyword.parameters.size() ; ++i) {
|
||||
const KeywordParam& kwp = *keyword.parameters[i];
|
||||
String param_name = String(_("param")) << (int)(i+1);
|
||||
String param_value = _("<atom-kwpph>") + (kwp.placeholder.empty() ? kwp.name : kwp.placeholder) + _("</atom-kwpph>");
|
||||
ctx.setVariable(param_name, intrusive(new KeywordParamValue(kwp.name, _(""), _(""), param_value)));
|
||||
}
|
||||
script->eval(ctx);
|
||||
errors.clear();
|
||||
return true;
|
||||
} catch (const Error& e) {
|
||||
errors = e.what();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Changing keywords : mode
|
||||
|
||||
ChangeKeywordModeAction::ChangeKeywordModeAction(Keyword& keyword, const String& new_mode)
|
||||
: keyword(keyword), mode(new_mode)
|
||||
: keyword(keyword), mode(new_mode)
|
||||
{}
|
||||
|
||||
String ChangeKeywordModeAction::getName(bool to_undo) const {
|
||||
return _("Keyword mode");
|
||||
return _("Keyword mode");
|
||||
}
|
||||
|
||||
void ChangeKeywordModeAction::perform(bool to_undo) {
|
||||
swap(keyword.mode, mode);
|
||||
swap(keyword.mode, mode);
|
||||
}
|
||||
|
||||
+40
-40
@@ -29,23 +29,23 @@ DECLARE_TYPEOF_COLLECTION(GenericAddAction<KeywordP>::Step);
|
||||
/// An Action the changes the keyword list of a set
|
||||
class KeywordListAction : public Action {
|
||||
public:
|
||||
inline KeywordListAction(Set& set) : set(set) {}
|
||||
|
||||
inline KeywordListAction(Set& set) : set(set) {}
|
||||
|
||||
protected:
|
||||
Set& set; // the set owns this action, so the set will not be destroyed before this
|
||||
// therefore we don't need a smart pointer
|
||||
Set& set; // the set owns this action, so the set will not be destroyed before this
|
||||
// therefore we don't need a smart pointer
|
||||
};
|
||||
|
||||
/// Adding or removing a keyword from a set
|
||||
class AddKeywordAction : public KeywordListAction {
|
||||
public:
|
||||
AddKeywordAction(Set& set);
|
||||
AddKeywordAction(AddingOrRemoving, Set& set, const KeywordP& keyword);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
const GenericAddAction<KeywordP> action;
|
||||
AddKeywordAction(Set& set);
|
||||
AddKeywordAction(AddingOrRemoving, Set& set, const KeywordP& keyword);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
const GenericAddAction<KeywordP> action;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : Changing keywords
|
||||
@@ -59,46 +59,46 @@ class AddKeywordAction : public KeywordListAction {
|
||||
*/
|
||||
class KeywordTextValue : public FakeTextValue {
|
||||
public:
|
||||
KeywordTextValue(const TextFieldP& field, Keyword* keyword, String* underlying, bool editable, bool untagged = false)
|
||||
: FakeTextValue(field, underlying, editable, untagged)
|
||||
, keyword(*keyword)
|
||||
{}
|
||||
|
||||
Keyword& keyword; ///< The keyword that is being edited
|
||||
KeywordTextValue(const TextFieldP& field, Keyword* keyword, String* underlying, bool editable, bool untagged = false)
|
||||
: FakeTextValue(field, underlying, editable, untagged)
|
||||
, keyword(*keyword)
|
||||
{}
|
||||
|
||||
Keyword& keyword; ///< The keyword that is being edited
|
||||
};
|
||||
|
||||
/// A FakeTextValue that is used to edit reminder text scripts
|
||||
class KeywordReminderTextValue : public KeywordTextValue {
|
||||
public:
|
||||
KeywordReminderTextValue(Set& set, const TextFieldP& field, Keyword* keyword, bool editable);
|
||||
|
||||
String errors; ///< Errors in the script
|
||||
Set& set; ///< Set this keyword is in (for script checking)
|
||||
Keyword& keyword; ///< The keyword we are the reminder text of
|
||||
|
||||
/// Try to compile the script
|
||||
virtual void store();
|
||||
/// Add some tags, so the script looks nice
|
||||
virtual void retrieve();
|
||||
|
||||
/// Syntax highlight, and store in value
|
||||
void highlight(const String& code, const vector<ScriptParseError>& errors);
|
||||
|
||||
/// Check the script for errors
|
||||
bool checkScript(const ScriptP& script);
|
||||
KeywordReminderTextValue(Set& set, const TextFieldP& field, Keyword* keyword, bool editable);
|
||||
|
||||
String errors; ///< Errors in the script
|
||||
Set& set; ///< Set this keyword is in (for script checking)
|
||||
Keyword& keyword; ///< The keyword we are the reminder text of
|
||||
|
||||
/// Try to compile the script
|
||||
virtual void store();
|
||||
/// Add some tags, so the script looks nice
|
||||
virtual void retrieve();
|
||||
|
||||
/// Syntax highlight, and store in value
|
||||
void highlight(const String& code, const vector<ScriptParseError>& errors);
|
||||
|
||||
/// Check the script for errors
|
||||
bool checkScript(const ScriptP& script);
|
||||
};
|
||||
|
||||
/// Changing the mode of a keyword
|
||||
class ChangeKeywordModeAction : public Action {
|
||||
public:
|
||||
ChangeKeywordModeAction(Keyword& keyword, const String& new_mode);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
ChangeKeywordModeAction(Keyword& keyword, const String& new_mode);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
//private:
|
||||
Keyword& keyword;
|
||||
String mode;
|
||||
Keyword& keyword;
|
||||
String mode;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : EOF
|
||||
|
||||
+67
-67
@@ -22,147 +22,147 @@ DECLARE_TYPEOF_COLLECTION(int);
|
||||
// ----------------------------------------------------------------------------- : Add card
|
||||
|
||||
AddCardAction::AddCardAction(Set& set)
|
||||
: CardListAction(set)
|
||||
, action(ADD, intrusive(new Card(*set.game)), set.cards)
|
||||
: CardListAction(set)
|
||||
, action(ADD, intrusive(new Card(*set.game)), set.cards)
|
||||
{}
|
||||
|
||||
AddCardAction::AddCardAction(AddingOrRemoving ar, Set& set, const CardP& card)
|
||||
: CardListAction(set)
|
||||
, action(ar, card, set.cards)
|
||||
: CardListAction(set)
|
||||
, action(ar, card, set.cards)
|
||||
{}
|
||||
|
||||
AddCardAction::AddCardAction(AddingOrRemoving ar, Set& set, const vector<CardP>& cards)
|
||||
: CardListAction(set)
|
||||
, action(ar, cards, set.cards)
|
||||
: CardListAction(set)
|
||||
, action(ar, cards, set.cards)
|
||||
{}
|
||||
|
||||
String AddCardAction::getName(bool to_undo) const {
|
||||
return action.getName();
|
||||
return action.getName();
|
||||
}
|
||||
|
||||
void AddCardAction::perform(bool to_undo) {
|
||||
action.perform(set.cards, to_undo);
|
||||
action.perform(set.cards, to_undo);
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------- : Reorder cards
|
||||
|
||||
ReorderCardsAction::ReorderCardsAction(Set& set, size_t card_id1, size_t card_id2)
|
||||
: CardListAction(set), card_id1(card_id1), card_id2(card_id2)
|
||||
: CardListAction(set), card_id1(card_id1), card_id2(card_id2)
|
||||
{}
|
||||
|
||||
String ReorderCardsAction::getName(bool to_undo) const {
|
||||
return _("Reorder cards");
|
||||
return _("Reorder cards");
|
||||
}
|
||||
|
||||
void ReorderCardsAction::perform(bool to_undo) {
|
||||
#ifdef _DEBUG
|
||||
assert(card_id1 < set.cards.size());
|
||||
assert(card_id2 < set.cards.size());
|
||||
#endif
|
||||
if (card_id1 >= set.cards.size() || card_id2 < set.cards.size()) {
|
||||
// TODO : Too lazy to fix this right now.
|
||||
return;
|
||||
}
|
||||
swap(set.cards[card_id1], set.cards[card_id2]);
|
||||
#ifdef _DEBUG
|
||||
assert(card_id1 < set.cards.size());
|
||||
assert(card_id2 < set.cards.size());
|
||||
#endif
|
||||
if (card_id1 >= set.cards.size() || card_id2 < set.cards.size()) {
|
||||
// TODO : Too lazy to fix this right now.
|
||||
return;
|
||||
}
|
||||
swap(set.cards[card_id1], set.cards[card_id2]);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Change stylesheet
|
||||
|
||||
String DisplayChangeAction::getName(bool to_undo) const {
|
||||
assert(false);
|
||||
return _("");
|
||||
assert(false);
|
||||
return _("");
|
||||
}
|
||||
void DisplayChangeAction::perform(bool to_undo) {
|
||||
assert(false);
|
||||
assert(false);
|
||||
}
|
||||
|
||||
|
||||
ChangeCardStyleAction::ChangeCardStyleAction(const CardP& card, const StyleSheetP& stylesheet)
|
||||
: card(card), stylesheet(stylesheet), has_styling(false) // styling_data(empty)
|
||||
: card(card), stylesheet(stylesheet), has_styling(false) // styling_data(empty)
|
||||
{}
|
||||
String ChangeCardStyleAction::getName(bool to_undo) const {
|
||||
return _("Change style");
|
||||
return _("Change style");
|
||||
}
|
||||
void ChangeCardStyleAction::perform(bool to_undo) {
|
||||
swap(card->stylesheet, stylesheet);
|
||||
swap(card->has_styling, has_styling);
|
||||
swap(card->styling_data, styling_data);
|
||||
swap(card->stylesheet, stylesheet);
|
||||
swap(card->has_styling, has_styling);
|
||||
swap(card->styling_data, styling_data);
|
||||
}
|
||||
|
||||
|
||||
ChangeSetStyleAction::ChangeSetStyleAction(Set& set, const CardP& card)
|
||||
: set(set), card(card)
|
||||
: set(set), card(card)
|
||||
{}
|
||||
String ChangeSetStyleAction::getName(bool to_undo) const {
|
||||
return _("Change style (all cards)");
|
||||
return _("Change style (all cards)");
|
||||
}
|
||||
void ChangeSetStyleAction::perform(bool to_undo) {
|
||||
if (!to_undo) {
|
||||
// backup has_styling
|
||||
has_styling.clear();
|
||||
FOR_EACH(card, set.cards) {
|
||||
has_styling.push_back(card->has_styling);
|
||||
if (!card->stylesheet) {
|
||||
card->has_styling = false; // this card has custom style options for the default stylesheet
|
||||
}
|
||||
}
|
||||
stylesheet = set.stylesheet;
|
||||
set.stylesheet = card->stylesheet;
|
||||
card->stylesheet = StyleSheetP();
|
||||
} else {
|
||||
card->stylesheet = set.stylesheet;
|
||||
set.stylesheet = stylesheet;
|
||||
// restore has_styling
|
||||
FOR_EACH_2(card, set.cards, has, has_styling) {
|
||||
card->has_styling = has;
|
||||
}
|
||||
}
|
||||
if (!to_undo) {
|
||||
// backup has_styling
|
||||
has_styling.clear();
|
||||
FOR_EACH(card, set.cards) {
|
||||
has_styling.push_back(card->has_styling);
|
||||
if (!card->stylesheet) {
|
||||
card->has_styling = false; // this card has custom style options for the default stylesheet
|
||||
}
|
||||
}
|
||||
stylesheet = set.stylesheet;
|
||||
set.stylesheet = card->stylesheet;
|
||||
card->stylesheet = StyleSheetP();
|
||||
} else {
|
||||
card->stylesheet = set.stylesheet;
|
||||
set.stylesheet = stylesheet;
|
||||
// restore has_styling
|
||||
FOR_EACH_2(card, set.cards, has, has_styling) {
|
||||
card->has_styling = has;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ChangeCardHasStylingAction::ChangeCardHasStylingAction(Set& set, const CardP& card)
|
||||
: set(set), card(card)
|
||||
: set(set), card(card)
|
||||
{
|
||||
if (!card->has_styling) {
|
||||
// copy of the set's styling data
|
||||
styling_data.cloneFrom( set.stylingDataFor(set.stylesheetFor(card)) );
|
||||
} else {
|
||||
// the new styling data is empty
|
||||
}
|
||||
if (!card->has_styling) {
|
||||
// copy of the set's styling data
|
||||
styling_data.cloneFrom( set.stylingDataFor(set.stylesheetFor(card)) );
|
||||
} else {
|
||||
// the new styling data is empty
|
||||
}
|
||||
}
|
||||
String ChangeCardHasStylingAction::getName(bool to_undo) const {
|
||||
return _("Use custom style");
|
||||
return _("Use custom style");
|
||||
}
|
||||
void ChangeCardHasStylingAction::perform(bool to_undo) {
|
||||
card->has_styling = !card->has_styling;
|
||||
swap(card->styling_data, styling_data);
|
||||
card->has_styling = !card->has_styling;
|
||||
swap(card->styling_data, styling_data);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Pack types
|
||||
|
||||
AddPackAction::AddPackAction(AddingOrRemoving ar, Set& set, const PackTypeP& pack)
|
||||
: PackTypesAction(set)
|
||||
, action(ar, pack, set.pack_types)
|
||||
: PackTypesAction(set)
|
||||
, action(ar, pack, set.pack_types)
|
||||
{}
|
||||
|
||||
String AddPackAction::getName(bool to_undo) const {
|
||||
return action.getName();
|
||||
return action.getName();
|
||||
}
|
||||
|
||||
void AddPackAction::perform(bool to_undo) {
|
||||
action.perform(set.pack_types, to_undo);
|
||||
action.perform(set.pack_types, to_undo);
|
||||
}
|
||||
|
||||
|
||||
ChangePackAction::ChangePackAction(Set& set, size_t pos, const PackTypeP& pack)
|
||||
: PackTypesAction(set)
|
||||
, pack(pack), pos(pos)
|
||||
: PackTypesAction(set)
|
||||
, pack(pack), pos(pos)
|
||||
{}
|
||||
|
||||
String ChangePackAction::getName(bool to_undo) const {
|
||||
return _ACTION_1_("change",type_name(pack));
|
||||
return _ACTION_1_("change",type_name(pack));
|
||||
}
|
||||
|
||||
void ChangePackAction::perform(bool to_undo) {
|
||||
swap(set.pack_types.at(pos), pack);
|
||||
swap(set.pack_types.at(pos), pack);
|
||||
}
|
||||
|
||||
+66
-66
@@ -32,25 +32,25 @@ DECLARE_TYPEOF_COLLECTION(GenericAddAction<PackTypeP>::Step);
|
||||
/// An Action the changes the card list of a set
|
||||
class CardListAction : public Action {
|
||||
public:
|
||||
inline CardListAction(Set& set) : set(set) {}
|
||||
|
||||
inline CardListAction(Set& set) : set(set) {}
|
||||
|
||||
protected:
|
||||
Set& set; // the set owns this action, so the set will not be destroyed before this
|
||||
// therefore we don't need a smart pointer
|
||||
Set& set; // the set owns this action, so the set will not be destroyed before this
|
||||
// therefore we don't need a smart pointer
|
||||
};
|
||||
|
||||
/// Adding a new card to a set
|
||||
class AddCardAction : public CardListAction {
|
||||
public:
|
||||
/// Add a newly allocated card
|
||||
AddCardAction(Set& set);
|
||||
AddCardAction(AddingOrRemoving, Set& set, const CardP& card);
|
||||
AddCardAction(AddingOrRemoving, Set& set, const vector<CardP>& cards);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
const GenericAddAction<CardP> action;
|
||||
/// Add a newly allocated card
|
||||
AddCardAction(Set& set);
|
||||
AddCardAction(AddingOrRemoving, Set& set, const CardP& card);
|
||||
AddCardAction(AddingOrRemoving, Set& set, const vector<CardP>& cards);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
const GenericAddAction<CardP> action;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : Reorder cards
|
||||
@@ -58,13 +58,13 @@ class AddCardAction : public CardListAction {
|
||||
/// Change the position of a card in the card list by swapping two cards
|
||||
class ReorderCardsAction : public CardListAction {
|
||||
public:
|
||||
ReorderCardsAction(Set& set, size_t card_id1, size_t card_id2);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
ReorderCardsAction(Set& set, size_t card_id1, size_t card_id2);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
//private:
|
||||
const size_t card_id1, card_id2; ///< Positions of the two cards to swap
|
||||
const size_t card_id1, card_id2; ///< Positions of the two cards to swap
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : Change stylesheet
|
||||
@@ -72,53 +72,53 @@ class ReorderCardsAction : public CardListAction {
|
||||
/// An action that affects the rendering/display/look of a set or cards in the set
|
||||
class DisplayChangeAction : public Action {
|
||||
public:
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
};
|
||||
|
||||
/// Changing the style of a a card
|
||||
class ChangeCardStyleAction : public DisplayChangeAction {
|
||||
public:
|
||||
ChangeCardStyleAction(const CardP& card, const StyleSheetP& stylesheet);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
ChangeCardStyleAction(const CardP& card, const StyleSheetP& stylesheet);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
//private:
|
||||
CardP card; ///< The affected card
|
||||
StyleSheetP stylesheet; ///< Its old stylesheet
|
||||
bool has_styling; ///< Its old has_styling
|
||||
IndexMap<FieldP,ValueP> styling_data; ///< Its old styling data
|
||||
CardP card; ///< The affected card
|
||||
StyleSheetP stylesheet; ///< Its old stylesheet
|
||||
bool has_styling; ///< Its old has_styling
|
||||
IndexMap<FieldP,ValueP> styling_data; ///< Its old styling data
|
||||
};
|
||||
|
||||
/// Changing the style of a set to that of a card
|
||||
class ChangeSetStyleAction : public DisplayChangeAction {
|
||||
public:
|
||||
ChangeSetStyleAction(Set& set, const CardP& card);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
ChangeSetStyleAction(Set& set, const CardP& card);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
private:
|
||||
Set& set; ///< The affected set
|
||||
CardP card; ///< The card whos stylesheet is copied to the set
|
||||
StyleSheetP stylesheet; ///< The old stylesheet of the set
|
||||
vector<int> has_styling; ///< The old has_styling values of all cards (vector<bool> is evil)
|
||||
Set& set; ///< The affected set
|
||||
CardP card; ///< The card whos stylesheet is copied to the set
|
||||
StyleSheetP stylesheet; ///< The old stylesheet of the set
|
||||
vector<int> has_styling; ///< The old has_styling values of all cards (vector<bool> is evil)
|
||||
};
|
||||
|
||||
/// Changing the styling of a card to become custom/non-custom
|
||||
/** i.e. toggle card->has_styling */
|
||||
class ChangeCardHasStylingAction : public DisplayChangeAction {
|
||||
public:
|
||||
ChangeCardHasStylingAction(Set& set, const CardP& card);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
ChangeCardHasStylingAction(Set& set, const CardP& card);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
//private:
|
||||
Set& set; ///< The set to copy styling from
|
||||
CardP card; ///< The affected card
|
||||
IndexMap<FieldP,ValueP> styling_data; ///< The old styling of the card
|
||||
Set& set; ///< The set to copy styling from
|
||||
CardP card; ///< The affected card
|
||||
IndexMap<FieldP,ValueP> styling_data; ///< The old styling of the card
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : Pack types
|
||||
@@ -126,37 +126,37 @@ class ChangeCardHasStylingAction : public DisplayChangeAction {
|
||||
/// An Action the changes the pack types of a set
|
||||
class PackTypesAction : public Action {
|
||||
public:
|
||||
inline PackTypesAction(Set& set) : set(set) {}
|
||||
|
||||
inline PackTypesAction(Set& set) : set(set) {}
|
||||
|
||||
protected:
|
||||
Set& set; // the set owns this action, so the set will not be destroyed before this
|
||||
// therefore we don't need a smart pointer
|
||||
Set& set; // the set owns this action, so the set will not be destroyed before this
|
||||
// therefore we don't need a smart pointer
|
||||
};
|
||||
|
||||
/// Adding/removing a pack from a Set
|
||||
class AddPackAction : public PackTypesAction {
|
||||
public:
|
||||
/// Add a newly allocated card
|
||||
AddPackAction(AddingOrRemoving, Set& set, const PackTypeP& pack);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
const GenericAddAction<PackTypeP> action;
|
||||
/// Add a newly allocated card
|
||||
AddPackAction(AddingOrRemoving, Set& set, const PackTypeP& pack);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
const GenericAddAction<PackTypeP> action;
|
||||
};
|
||||
|
||||
/// Updating a pack in a Set
|
||||
class ChangePackAction : public PackTypesAction {
|
||||
public:
|
||||
/// Add a newly allocated card
|
||||
ChangePackAction(Set& set, size_t pos, const PackTypeP& new_pack);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
/// Add a newly allocated card
|
||||
ChangePackAction(Set& set, size_t pos, const PackTypeP& new_pack);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
private:
|
||||
PackTypeP pack;
|
||||
size_t pos;
|
||||
PackTypeP pack;
|
||||
size_t pos;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : EOF
|
||||
|
||||
+334
-334
@@ -20,173 +20,173 @@ DECLARE_TYPEOF_COLLECTION(ControlPointP);
|
||||
// ----------------------------------------------------------------------------- : Utility
|
||||
|
||||
String action_name_for(const set<SymbolPartP>& parts, const String& action) {
|
||||
return format_string(action, parts.size() == 1 ? (*parts.begin())->name : _TYPE_("shapes"));
|
||||
return format_string(action, parts.size() == 1 ? (*parts.begin())->name : _TYPE_("shapes"));
|
||||
}
|
||||
|
||||
SymbolPartsAction::SymbolPartsAction(const set<SymbolPartP>& parts)
|
||||
: parts(parts)
|
||||
: parts(parts)
|
||||
{}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Moving symbol parts
|
||||
|
||||
SymbolPartMoveAction::SymbolPartMoveAction(const set<SymbolPartP>& parts, const Vector2D& delta)
|
||||
: SymbolPartsAction(parts)
|
||||
, delta(delta), moved(-delta)
|
||||
, constrain(false)
|
||||
, snap(0)
|
||||
: SymbolPartsAction(parts)
|
||||
, delta(delta), moved(-delta)
|
||||
, constrain(false)
|
||||
, snap(0)
|
||||
{
|
||||
// Determine min/max_pos
|
||||
FOR_EACH(p, parts) {
|
||||
bounds.update(p->bounds);
|
||||
}
|
||||
// Determine min/max_pos
|
||||
FOR_EACH(p, parts) {
|
||||
bounds.update(p->bounds);
|
||||
}
|
||||
}
|
||||
|
||||
String SymbolPartMoveAction::getName(bool to_undo) const {
|
||||
return action_name_for(parts, _ACTION_("move"));
|
||||
return action_name_for(parts, _ACTION_("move"));
|
||||
}
|
||||
|
||||
void SymbolPartMoveAction::perform(bool to_undo) {
|
||||
// move the points back
|
||||
FOR_EACH(p, parts) {
|
||||
movePart(*p);
|
||||
}
|
||||
moved = -moved;
|
||||
// move the points back
|
||||
FOR_EACH(p, parts) {
|
||||
movePart(*p);
|
||||
}
|
||||
moved = -moved;
|
||||
}
|
||||
void SymbolPartMoveAction::movePart(SymbolPart& part) {
|
||||
part.bounds.min -= moved;
|
||||
part.bounds.max -= moved;
|
||||
if (SymbolShape* s = part.isSymbolShape()) {
|
||||
FOR_EACH(pnt, s->points) {
|
||||
pnt->pos -= moved;
|
||||
}
|
||||
} else if (SymbolSymmetry* s = part.isSymbolSymmetry()) {
|
||||
s->center -= moved;
|
||||
}
|
||||
if (SymbolGroup* g = part.isSymbolGroup()) {
|
||||
FOR_EACH(p, g->parts) {
|
||||
movePart(*p);
|
||||
}
|
||||
}
|
||||
part.bounds.min -= moved;
|
||||
part.bounds.max -= moved;
|
||||
if (SymbolShape* s = part.isSymbolShape()) {
|
||||
FOR_EACH(pnt, s->points) {
|
||||
pnt->pos -= moved;
|
||||
}
|
||||
} else if (SymbolSymmetry* s = part.isSymbolSymmetry()) {
|
||||
s->center -= moved;
|
||||
}
|
||||
if (SymbolGroup* g = part.isSymbolGroup()) {
|
||||
FOR_EACH(p, g->parts) {
|
||||
movePart(*p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SymbolPartMoveAction::move(const Vector2D& deltaDelta) {
|
||||
delta += deltaDelta;
|
||||
// Determine actual delta, possibly constrained and snapped
|
||||
Vector2D d = constrain_snap_vector_offset(bounds.min, bounds.max, delta, constrain, snap);
|
||||
Vector2D dd = d - moved; // move this much more
|
||||
// Move each point by d
|
||||
moved = -dd;
|
||||
perform(false); // (ab)use perform to move by +dd
|
||||
moved = d;
|
||||
delta += deltaDelta;
|
||||
// Determine actual delta, possibly constrained and snapped
|
||||
Vector2D d = constrain_snap_vector_offset(bounds.min, bounds.max, delta, constrain, snap);
|
||||
Vector2D dd = d - moved; // move this much more
|
||||
// Move each point by d
|
||||
moved = -dd;
|
||||
perform(false); // (ab)use perform to move by +dd
|
||||
moved = d;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Rotating symbol parts
|
||||
|
||||
SymbolPartMatrixAction::SymbolPartMatrixAction(const set<SymbolPartP>& parts, const Vector2D& center)
|
||||
: SymbolPartsAction(parts)
|
||||
, center(center)
|
||||
: SymbolPartsAction(parts)
|
||||
, center(center)
|
||||
{}
|
||||
|
||||
void SymbolPartMatrixAction::transform(const Matrix2D& m) {
|
||||
// Transform each part
|
||||
FOR_EACH(p, parts) {
|
||||
transform(*p, m);
|
||||
p->updateBounds();
|
||||
}
|
||||
// Transform each part
|
||||
FOR_EACH(p, parts) {
|
||||
transform(*p, m);
|
||||
p->updateBounds();
|
||||
}
|
||||
}
|
||||
void SymbolPartMatrixAction::transform(SymbolPart& part, const Matrix2D& m) {
|
||||
if (SymbolShape* s = part.isSymbolShape()) {
|
||||
FOR_EACH(pnt, s->points) {
|
||||
pnt->pos = ((pnt->pos - center) * m) + center;
|
||||
pnt->delta_before = pnt->delta_before * m;
|
||||
pnt->delta_after = pnt->delta_after * m;
|
||||
}
|
||||
} else if (SymbolSymmetry* s = part.isSymbolSymmetry()) {
|
||||
s->center = (s->center - center) * m + center;
|
||||
s->handle = s->handle * m;
|
||||
}
|
||||
if (SymbolGroup* g = part.isSymbolGroup()) {
|
||||
FOR_EACH(p, g->parts) {
|
||||
transform(*p, m);
|
||||
}
|
||||
}
|
||||
if (SymbolShape* s = part.isSymbolShape()) {
|
||||
FOR_EACH(pnt, s->points) {
|
||||
pnt->pos = ((pnt->pos - center) * m) + center;
|
||||
pnt->delta_before = pnt->delta_before * m;
|
||||
pnt->delta_after = pnt->delta_after * m;
|
||||
}
|
||||
} else if (SymbolSymmetry* s = part.isSymbolSymmetry()) {
|
||||
s->center = (s->center - center) * m + center;
|
||||
s->handle = s->handle * m;
|
||||
}
|
||||
if (SymbolGroup* g = part.isSymbolGroup()) {
|
||||
FOR_EACH(p, g->parts) {
|
||||
transform(*p, m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SymbolPartRotateAction::SymbolPartRotateAction(const set<SymbolPartP>& parts, const Vector2D& center)
|
||||
: SymbolPartMatrixAction(parts, center)
|
||||
, angle(0)
|
||||
, constrain(false)
|
||||
: SymbolPartMatrixAction(parts, center)
|
||||
, angle(0)
|
||||
, constrain(false)
|
||||
{}
|
||||
|
||||
String SymbolPartRotateAction::getName(bool to_undo) const {
|
||||
return action_name_for(parts, _ACTION_("rotate"));
|
||||
return action_name_for(parts, _ACTION_("rotate"));
|
||||
}
|
||||
|
||||
void SymbolPartRotateAction::perform(bool to_undo) {
|
||||
// move the points back
|
||||
rotateBy(-angle);
|
||||
angle = -angle;
|
||||
// move the points back
|
||||
rotateBy(-angle);
|
||||
angle = -angle;
|
||||
}
|
||||
|
||||
void SymbolPartRotateAction::rotateTo(Radians newAngle) {
|
||||
Radians oldAngle = angle;
|
||||
angle = newAngle;
|
||||
// constrain?
|
||||
if (constrain) {
|
||||
// multiples of 2pi/24 i.e. 24 stops
|
||||
double mult = (2 * M_PI) / 24;
|
||||
angle = floor(angle / mult + 0.5) * mult;
|
||||
}
|
||||
if (oldAngle != angle) rotateBy(angle - oldAngle);
|
||||
Radians oldAngle = angle;
|
||||
angle = newAngle;
|
||||
// constrain?
|
||||
if (constrain) {
|
||||
// multiples of 2pi/24 i.e. 24 stops
|
||||
double mult = (2 * M_PI) / 24;
|
||||
angle = floor(angle / mult + 0.5) * mult;
|
||||
}
|
||||
if (oldAngle != angle) rotateBy(angle - oldAngle);
|
||||
}
|
||||
|
||||
void SymbolPartRotateAction::rotateBy(Radians deltaAngle) {
|
||||
// Rotation 'matrix'
|
||||
transform(
|
||||
Matrix2D(cos(deltaAngle), -sin(deltaAngle)
|
||||
,sin(deltaAngle), cos(deltaAngle))
|
||||
);
|
||||
// Rotation 'matrix'
|
||||
transform(
|
||||
Matrix2D(cos(deltaAngle), -sin(deltaAngle)
|
||||
,sin(deltaAngle), cos(deltaAngle))
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------- : Shearing symbol parts
|
||||
|
||||
SymbolPartShearAction::SymbolPartShearAction(const set<SymbolPartP>& parts, const Vector2D& center)
|
||||
: SymbolPartMatrixAction(parts, center)
|
||||
// , constrain(false)
|
||||
, snap(0)
|
||||
: SymbolPartMatrixAction(parts, center)
|
||||
// , constrain(false)
|
||||
, snap(0)
|
||||
{}
|
||||
|
||||
String SymbolPartShearAction::getName(bool to_undo) const {
|
||||
return action_name_for(parts, _ACTION_("shear"));
|
||||
return action_name_for(parts, _ACTION_("shear"));
|
||||
}
|
||||
|
||||
void SymbolPartShearAction::perform(bool to_undo) {
|
||||
// move the points back
|
||||
// the vector shear = (x,y) is used as:
|
||||
// <1 x>
|
||||
// <y 1>
|
||||
// inverse is:
|
||||
// <1 -x> /
|
||||
// <-y 1> / (1 - xy)
|
||||
// we have: xy = 0 => (1 - xy) = 1
|
||||
shearBy(-moved);
|
||||
// move the points back
|
||||
// the vector shear = (x,y) is used as:
|
||||
// <1 x>
|
||||
// <y 1>
|
||||
// inverse is:
|
||||
// <1 -x> /
|
||||
// <-y 1> / (1 - xy)
|
||||
// we have: xy = 0 => (1 - xy) = 1
|
||||
shearBy(-moved);
|
||||
}
|
||||
|
||||
void SymbolPartShearAction::move(const Vector2D& deltaShear) {
|
||||
shear += deltaShear;
|
||||
Vector2D d = snap_vector(shear - moved, snap);
|
||||
shearBy(d);
|
||||
moved += d;
|
||||
shear += deltaShear;
|
||||
Vector2D d = snap_vector(shear - moved, snap);
|
||||
shearBy(d);
|
||||
moved += d;
|
||||
}
|
||||
|
||||
void SymbolPartShearAction::shearBy(const Vector2D& shear) {
|
||||
// Shear 'matrix'
|
||||
transform(
|
||||
Matrix2D(1, shear.x
|
||||
,shear.y, 1)
|
||||
);
|
||||
// Shear 'matrix'
|
||||
transform(
|
||||
Matrix2D(1, shear.x
|
||||
,shear.y, 1)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -194,366 +194,366 @@ void SymbolPartShearAction::shearBy(const Vector2D& shear) {
|
||||
|
||||
|
||||
SymbolPartScaleAction::SymbolPartScaleAction(const set<SymbolPartP>& parts, int scaleX, int scaleY)
|
||||
: SymbolPartsAction(parts)
|
||||
, scaleX(scaleX), scaleY(scaleY)
|
||||
, constrain(false)
|
||||
, snap(0)
|
||||
: SymbolPartsAction(parts)
|
||||
, scaleX(scaleX), scaleY(scaleY)
|
||||
, constrain(false)
|
||||
, snap(0)
|
||||
{
|
||||
// Find min and max coordinates
|
||||
Bounds bounds;
|
||||
FOR_EACH(p, parts) {
|
||||
bounds.update(p->bounds);
|
||||
}
|
||||
// new == old
|
||||
new_min = new_real_min = old_min = bounds.min;
|
||||
new_size = new_real_size = old_size = bounds.max - bounds.min;
|
||||
// Find min and max coordinates
|
||||
Bounds bounds;
|
||||
FOR_EACH(p, parts) {
|
||||
bounds.update(p->bounds);
|
||||
}
|
||||
// new == old
|
||||
new_min = new_real_min = old_min = bounds.min;
|
||||
new_size = new_real_size = old_size = bounds.max - bounds.min;
|
||||
}
|
||||
|
||||
String SymbolPartScaleAction::getName(bool to_undo) const {
|
||||
return action_name_for(parts, _ACTION_("scale"));
|
||||
return action_name_for(parts, _ACTION_("scale"));
|
||||
}
|
||||
|
||||
void SymbolPartScaleAction::perform(bool to_undo) {
|
||||
swap(old_min, new_min);
|
||||
swap(old_size, new_size);
|
||||
transformAll();
|
||||
swap(old_min, new_min);
|
||||
swap(old_size, new_size);
|
||||
transformAll();
|
||||
}
|
||||
|
||||
void SymbolPartScaleAction::move(const Vector2D& delta_min, const Vector2D& delta_max) {
|
||||
new_real_min += delta_min;
|
||||
new_real_size += delta_max - delta_min;
|
||||
update();
|
||||
new_real_min += delta_min;
|
||||
new_real_size += delta_max - delta_min;
|
||||
update();
|
||||
}
|
||||
|
||||
void SymbolPartScaleAction::update() {
|
||||
// Move each point so the range [old_min...old_max] maps to [new_min...new_max]
|
||||
// we have already moved to the current [new_min...new_max]
|
||||
Vector2D tmp_min = old_min, tmp_size = old_size; // the size before any scaling
|
||||
old_min = new_min; old_size = new_size; // the size before this move
|
||||
// the size after the move
|
||||
new_min = new_real_min; new_size = new_real_size;
|
||||
if (constrain && scaleX != 0 && scaleY != 0) {
|
||||
Vector2D scale = new_size.div(tmp_size);
|
||||
scale = constrain_vector(scale, true, true);
|
||||
new_size = tmp_size.mul(scale);
|
||||
new_min += (new_real_size - new_size).mul(Vector2D(scaleX == -1 ? 1 : 0, scaleY == -1 ? 1 : 0));
|
||||
// TODO : snapping
|
||||
} else if (snap >= 0) {
|
||||
if (scaleX + scaleY < 0) {
|
||||
new_min = snap_vector(new_min, snap);
|
||||
new_size += new_real_min - new_min;
|
||||
} else {
|
||||
Vector2D new_max = snap_vector(new_min + new_size, snap);
|
||||
new_size = new_max - new_min;
|
||||
}
|
||||
}
|
||||
// now move all points
|
||||
transformAll();
|
||||
// restore old_min/size
|
||||
old_min = tmp_min; old_size = tmp_size;
|
||||
// Move each point so the range [old_min...old_max] maps to [new_min...new_max]
|
||||
// we have already moved to the current [new_min...new_max]
|
||||
Vector2D tmp_min = old_min, tmp_size = old_size; // the size before any scaling
|
||||
old_min = new_min; old_size = new_size; // the size before this move
|
||||
// the size after the move
|
||||
new_min = new_real_min; new_size = new_real_size;
|
||||
if (constrain && scaleX != 0 && scaleY != 0) {
|
||||
Vector2D scale = new_size.div(tmp_size);
|
||||
scale = constrain_vector(scale, true, true);
|
||||
new_size = tmp_size.mul(scale);
|
||||
new_min += (new_real_size - new_size).mul(Vector2D(scaleX == -1 ? 1 : 0, scaleY == -1 ? 1 : 0));
|
||||
// TODO : snapping
|
||||
} else if (snap >= 0) {
|
||||
if (scaleX + scaleY < 0) {
|
||||
new_min = snap_vector(new_min, snap);
|
||||
new_size += new_real_min - new_min;
|
||||
} else {
|
||||
Vector2D new_max = snap_vector(new_min + new_size, snap);
|
||||
new_size = new_max - new_min;
|
||||
}
|
||||
}
|
||||
// now move all points
|
||||
transformAll();
|
||||
// restore old_min/size
|
||||
old_min = tmp_min; old_size = tmp_size;
|
||||
}
|
||||
|
||||
void SymbolPartScaleAction::transformAll() {
|
||||
FOR_EACH(p, parts) {
|
||||
transformPart(*p);
|
||||
}
|
||||
FOR_EACH(p, parts) {
|
||||
transformPart(*p);
|
||||
}
|
||||
}
|
||||
void SymbolPartScaleAction::transformPart(SymbolPart& part) {
|
||||
// update bounds
|
||||
part.bounds.min = transform(part.bounds.min);
|
||||
part.bounds.max = transform(part.bounds.max);
|
||||
// make sure that max >= min
|
||||
if (part.bounds.min.x > part.bounds.max.x) swap(part.bounds.min.x, part.bounds.max.x);
|
||||
if (part.bounds.min.y > part.bounds.max.y) swap(part.bounds.min.y, part.bounds.max.y);
|
||||
if (SymbolShape* s = part.isSymbolShape()) {
|
||||
// scale all points
|
||||
Vector2D scale = new_size.div(old_size);
|
||||
FOR_EACH(pnt, s->points) {
|
||||
pnt->pos = transform(pnt->pos);
|
||||
// also scale handles
|
||||
pnt->delta_before = pnt->delta_before.mul(scale);
|
||||
pnt->delta_after = pnt->delta_after .mul(scale);
|
||||
}
|
||||
} else if (SymbolSymmetry* s = part.isSymbolSymmetry()) {
|
||||
transform(s->center);
|
||||
s->handle.mul(new_size.div(old_size));
|
||||
}
|
||||
if (SymbolGroup* g = part.isSymbolGroup()) {
|
||||
FOR_EACH(p, g->parts) {
|
||||
transformPart(*p);
|
||||
}
|
||||
}
|
||||
// update bounds
|
||||
part.bounds.min = transform(part.bounds.min);
|
||||
part.bounds.max = transform(part.bounds.max);
|
||||
// make sure that max >= min
|
||||
if (part.bounds.min.x > part.bounds.max.x) swap(part.bounds.min.x, part.bounds.max.x);
|
||||
if (part.bounds.min.y > part.bounds.max.y) swap(part.bounds.min.y, part.bounds.max.y);
|
||||
if (SymbolShape* s = part.isSymbolShape()) {
|
||||
// scale all points
|
||||
Vector2D scale = new_size.div(old_size);
|
||||
FOR_EACH(pnt, s->points) {
|
||||
pnt->pos = transform(pnt->pos);
|
||||
// also scale handles
|
||||
pnt->delta_before = pnt->delta_before.mul(scale);
|
||||
pnt->delta_after = pnt->delta_after .mul(scale);
|
||||
}
|
||||
} else if (SymbolSymmetry* s = part.isSymbolSymmetry()) {
|
||||
transform(s->center);
|
||||
s->handle.mul(new_size.div(old_size));
|
||||
}
|
||||
if (SymbolGroup* g = part.isSymbolGroup()) {
|
||||
FOR_EACH(p, g->parts) {
|
||||
transformPart(*p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vector2D SymbolPartScaleAction::transform(const Vector2D& v) {
|
||||
// TODO: prevent div by 0
|
||||
return (v - old_min).div(old_size).mul(new_size) + new_min;
|
||||
// TODO: prevent div by 0
|
||||
return (v - old_min).div(old_size).mul(new_size) + new_min;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Change combine mode
|
||||
|
||||
CombiningModeAction::CombiningModeAction(const set<SymbolPartP>& parts, SymbolShapeCombine mode)
|
||||
: SymbolPartsAction(parts)
|
||||
: SymbolPartsAction(parts)
|
||||
{
|
||||
FOR_EACH(p, parts) {
|
||||
add(p,mode);
|
||||
}
|
||||
FOR_EACH(p, parts) {
|
||||
add(p,mode);
|
||||
}
|
||||
}
|
||||
void CombiningModeAction::add(const SymbolPartP& part, SymbolShapeCombine mode) {
|
||||
if (part->isSymbolShape()) {
|
||||
this->parts.push_back(make_pair(static_pointer_cast<SymbolShape>(part),mode));
|
||||
} else if (SymbolGroup* g = part->isSymbolGroup()) {
|
||||
FOR_EACH(p, g->parts) add(p, mode);
|
||||
}
|
||||
if (part->isSymbolShape()) {
|
||||
this->parts.push_back(make_pair(static_pointer_cast<SymbolShape>(part),mode));
|
||||
} else if (SymbolGroup* g = part->isSymbolGroup()) {
|
||||
FOR_EACH(p, g->parts) add(p, mode);
|
||||
}
|
||||
}
|
||||
|
||||
String CombiningModeAction::getName(bool to_undo) const {
|
||||
return _ACTION_("change combine mode");
|
||||
return _ACTION_("change combine mode");
|
||||
}
|
||||
|
||||
void CombiningModeAction::perform(bool to_undo) {
|
||||
FOR_EACH(pm, parts) {
|
||||
swap(pm.first->combine, pm.second);
|
||||
}
|
||||
FOR_EACH(pm, parts) {
|
||||
swap(pm.first->combine, pm.second);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Change name
|
||||
|
||||
SymbolPartNameAction::SymbolPartNameAction(const SymbolPartP& part, const String& name, size_t old_cursor, size_t new_cursor)
|
||||
: part(part), part_name(name)
|
||||
, old_cursor(new_cursor), new_cursor(old_cursor) // will be swapped
|
||||
: part(part), part_name(name)
|
||||
, old_cursor(new_cursor), new_cursor(old_cursor) // will be swapped
|
||||
{}
|
||||
|
||||
String SymbolPartNameAction::getName(bool to_undo) const {
|
||||
return _ACTION_("change shape name");
|
||||
return _ACTION_("change shape name");
|
||||
}
|
||||
bool SymbolPartNameAction::merge(const Action& action) {
|
||||
TYPE_CASE(action, SymbolPartNameAction) {
|
||||
if (action.part == part) {
|
||||
// adjacent actions on the same part, discard the other one,
|
||||
// because it only keeps an intermediate value
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
TYPE_CASE(action, SymbolPartNameAction) {
|
||||
if (action.part == part) {
|
||||
// adjacent actions on the same part, discard the other one,
|
||||
// because it only keeps an intermediate value
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SymbolPartNameAction::perform(bool to_undo) {
|
||||
swap(part->name, part_name);
|
||||
swap(old_cursor, new_cursor);
|
||||
swap(part->name, part_name);
|
||||
swap(old_cursor, new_cursor);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Add symbol part
|
||||
|
||||
AddSymbolPartAction::AddSymbolPartAction(Symbol& symbol, const SymbolPartP& part)
|
||||
: symbol(symbol), part(part)
|
||||
: symbol(symbol), part(part)
|
||||
{}
|
||||
|
||||
String AddSymbolPartAction::getName(bool to_undo) const {
|
||||
return _ACTION_1_("add item", part->name);
|
||||
return _ACTION_1_("add item", part->name);
|
||||
}
|
||||
|
||||
void AddSymbolPartAction::perform(bool to_undo) {
|
||||
if (to_undo) {
|
||||
assert(!symbol.parts.empty());
|
||||
symbol.parts.erase (symbol.parts.begin());
|
||||
} else {
|
||||
symbol.parts.insert(symbol.parts.begin(), part);
|
||||
}
|
||||
if (to_undo) {
|
||||
assert(!symbol.parts.empty());
|
||||
symbol.parts.erase (symbol.parts.begin());
|
||||
} else {
|
||||
symbol.parts.insert(symbol.parts.begin(), part);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Remove symbol part
|
||||
|
||||
RemoveSymbolPartsAction::RemoveSymbolPartsAction(Symbol& symbol, const set<SymbolPartP>& parts)
|
||||
: symbol(symbol)
|
||||
: symbol(symbol)
|
||||
{
|
||||
check(symbol, parts);
|
||||
check(symbol, parts);
|
||||
}
|
||||
|
||||
void RemoveSymbolPartsAction::check(SymbolGroup& group, const set<SymbolPartP>& parts) {
|
||||
size_t index = 0;
|
||||
size_t removed = 0;
|
||||
FOR_EACH(p, group.parts) {
|
||||
if (parts.find(p) != parts.end()) {
|
||||
removals.push_back(Removal(group, index, p)); // remove this part
|
||||
++ removed;
|
||||
} else if (SymbolGroup* g = p->isSymbolGroup()) {
|
||||
check(*g, parts);
|
||||
}
|
||||
++index;
|
||||
}
|
||||
if (!group.isSymbolSymmetry() && &group != &symbol) {
|
||||
// remove empty groups
|
||||
// TODO
|
||||
}
|
||||
size_t index = 0;
|
||||
size_t removed = 0;
|
||||
FOR_EACH(p, group.parts) {
|
||||
if (parts.find(p) != parts.end()) {
|
||||
removals.push_back(Removal(group, index, p)); // remove this part
|
||||
++ removed;
|
||||
} else if (SymbolGroup* g = p->isSymbolGroup()) {
|
||||
check(*g, parts);
|
||||
}
|
||||
++index;
|
||||
}
|
||||
if (!group.isSymbolSymmetry() && &group != &symbol) {
|
||||
// remove empty groups
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
||||
String RemoveSymbolPartsAction::getName(bool to_undo) const {
|
||||
return _ACTION_1_("remove item", removals.size() == 1 ? _TYPE_("shape") : _TYPE_("shapes"));
|
||||
return _ACTION_1_("remove item", removals.size() == 1 ? _TYPE_("shape") : _TYPE_("shapes"));
|
||||
}
|
||||
|
||||
void RemoveSymbolPartsAction::perform(bool to_undo) {
|
||||
if (to_undo) {
|
||||
// reinsert the parts
|
||||
// ascending order, this is the reverse of removal
|
||||
FOR_EACH(r, removals) {
|
||||
assert(r.pos <= r.parent->parts.size());
|
||||
r.parent->parts.insert(r.parent->parts.begin() + r.pos, r.removed);
|
||||
}
|
||||
} else {
|
||||
// remove the parts
|
||||
// descending order, because earlier removals shift the rest of the vector
|
||||
FOR_EACH_REVERSE(r, removals) {
|
||||
assert(r.pos < r.parent->parts.size());
|
||||
r.parent->parts.erase(r.parent->parts.begin() + r.pos);
|
||||
}
|
||||
}
|
||||
if (to_undo) {
|
||||
// reinsert the parts
|
||||
// ascending order, this is the reverse of removal
|
||||
FOR_EACH(r, removals) {
|
||||
assert(r.pos <= r.parent->parts.size());
|
||||
r.parent->parts.insert(r.parent->parts.begin() + r.pos, r.removed);
|
||||
}
|
||||
} else {
|
||||
// remove the parts
|
||||
// descending order, because earlier removals shift the rest of the vector
|
||||
FOR_EACH_REVERSE(r, removals) {
|
||||
assert(r.pos < r.parent->parts.size());
|
||||
r.parent->parts.erase(r.parent->parts.begin() + r.pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Duplicate symbol parts
|
||||
|
||||
DuplicateSymbolPartsAction::DuplicateSymbolPartsAction(Symbol& symbol, const set<SymbolPartP>& parts)
|
||||
: symbol(symbol)
|
||||
: symbol(symbol)
|
||||
{
|
||||
UInt index = 0;
|
||||
FOR_EACH(p, symbol.parts) {
|
||||
index += 1;
|
||||
if (parts.find(p) != parts.end()) {
|
||||
// duplicate this part
|
||||
duplications.push_back(make_pair(p->clone(), index));
|
||||
index += 1; // the clone also takes up space on the vector
|
||||
}
|
||||
}
|
||||
UInt index = 0;
|
||||
FOR_EACH(p, symbol.parts) {
|
||||
index += 1;
|
||||
if (parts.find(p) != parts.end()) {
|
||||
// duplicate this part
|
||||
duplications.push_back(make_pair(p->clone(), index));
|
||||
index += 1; // the clone also takes up space on the vector
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String DuplicateSymbolPartsAction::getName(bool to_undo) const {
|
||||
return _ACTION_1_("duplicate", duplications.size() == 1 ? _TYPE_("shape") : _TYPE_("shapes"));
|
||||
return _ACTION_1_("duplicate", duplications.size() == 1 ? _TYPE_("shape") : _TYPE_("shapes"));
|
||||
}
|
||||
|
||||
void DuplicateSymbolPartsAction::perform(bool to_undo) {
|
||||
if (to_undo) {
|
||||
// remove the clones
|
||||
// walk in reverse order, otherwise we will shift the vector
|
||||
FOR_EACH_REVERSE(d, duplications) {
|
||||
assert(d.second < symbol.parts.size());
|
||||
symbol.parts.erase(symbol.parts.begin() + d.second);
|
||||
}
|
||||
} else {
|
||||
// insert the clones
|
||||
FOR_EACH(d, duplications) {
|
||||
assert(d.second <= symbol.parts.size());
|
||||
symbol.parts.insert(symbol.parts.begin() + d.second, d.first);
|
||||
}
|
||||
}
|
||||
if (to_undo) {
|
||||
// remove the clones
|
||||
// walk in reverse order, otherwise we will shift the vector
|
||||
FOR_EACH_REVERSE(d, duplications) {
|
||||
assert(d.second < symbol.parts.size());
|
||||
symbol.parts.erase(symbol.parts.begin() + d.second);
|
||||
}
|
||||
} else {
|
||||
// insert the clones
|
||||
FOR_EACH(d, duplications) {
|
||||
assert(d.second <= symbol.parts.size());
|
||||
symbol.parts.insert(symbol.parts.begin() + d.second, d.first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DuplicateSymbolPartsAction::getParts(set<SymbolPartP>& parts) {
|
||||
parts.clear();
|
||||
FOR_EACH(d, duplications) {
|
||||
parts.insert(d.first);
|
||||
}
|
||||
parts.clear();
|
||||
FOR_EACH(d, duplications) {
|
||||
parts.insert(d.first);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Reorder symbol parts
|
||||
|
||||
ReorderSymbolPartsAction::ReorderSymbolPartsAction(SymbolGroup& old_parent, size_t old_position, SymbolGroup& new_parent, size_t new_position)
|
||||
: old_parent(&old_parent), new_parent(&new_parent)
|
||||
, old_position(old_position), new_position(new_position)
|
||||
: old_parent(&old_parent), new_parent(&new_parent)
|
||||
, old_position(old_position), new_position(new_position)
|
||||
{}
|
||||
|
||||
String ReorderSymbolPartsAction::getName(bool to_undo) const {
|
||||
return _ACTION_("reorder parts");
|
||||
return _ACTION_("reorder parts");
|
||||
}
|
||||
|
||||
void ReorderSymbolPartsAction::perform(bool to_undo) {
|
||||
// remove from old
|
||||
assert(old_position < old_parent->parts.size());
|
||||
SymbolPartP part = old_parent->parts.at(old_position);
|
||||
old_parent->parts.erase( old_parent->parts.begin() + old_position);
|
||||
// add to new
|
||||
assert(new_position <= new_parent->parts.size());
|
||||
new_parent->parts.insert(new_parent->parts.begin() + new_position, part);
|
||||
// next time the other way around
|
||||
swap(old_parent, new_parent);
|
||||
swap(old_position, new_position);
|
||||
// remove from old
|
||||
assert(old_position < old_parent->parts.size());
|
||||
SymbolPartP part = old_parent->parts.at(old_position);
|
||||
old_parent->parts.erase( old_parent->parts.begin() + old_position);
|
||||
// add to new
|
||||
assert(new_position <= new_parent->parts.size());
|
||||
new_parent->parts.insert(new_parent->parts.begin() + new_position, part);
|
||||
// next time the other way around
|
||||
swap(old_parent, new_parent);
|
||||
swap(old_position, new_position);
|
||||
}
|
||||
|
||||
|
||||
UngroupReorderSymbolPartsAction::UngroupReorderSymbolPartsAction(SymbolGroup& group_parent, size_t group_pos, SymbolGroup& target_parent, size_t target_pos)
|
||||
: group_parent(group_parent), group_pos(group_pos)
|
||||
, target_parent(target_parent), target_pos(target_pos)
|
||||
: group_parent(group_parent), group_pos(group_pos)
|
||||
, target_parent(target_parent), target_pos(target_pos)
|
||||
{
|
||||
group = dynamic_pointer_cast<SymbolGroup>(group_parent.parts.at(group_pos));
|
||||
assert(group);
|
||||
group = dynamic_pointer_cast<SymbolGroup>(group_parent.parts.at(group_pos));
|
||||
assert(group);
|
||||
}
|
||||
|
||||
String UngroupReorderSymbolPartsAction::getName(bool to_undo) const {
|
||||
return _ACTION_("reorder parts");
|
||||
return _ACTION_("reorder parts");
|
||||
}
|
||||
|
||||
void UngroupReorderSymbolPartsAction::perform(bool to_undo) {
|
||||
if (!to_undo) {
|
||||
group_parent.parts.erase(group_parent.parts.begin() + group_pos);
|
||||
target_parent.parts.insert(target_parent.parts.begin() + target_pos, group->parts.begin(), group->parts.end());
|
||||
} else {
|
||||
target_parent.parts.erase(target_parent.parts.begin() + target_pos, target_parent.parts.begin() + target_pos + group->parts.size());
|
||||
group_parent.parts.insert(group_parent.parts.begin() + group_pos, group);
|
||||
}
|
||||
if (!to_undo) {
|
||||
group_parent.parts.erase(group_parent.parts.begin() + group_pos);
|
||||
target_parent.parts.insert(target_parent.parts.begin() + target_pos, group->parts.begin(), group->parts.end());
|
||||
} else {
|
||||
target_parent.parts.erase(target_parent.parts.begin() + target_pos, target_parent.parts.begin() + target_pos + group->parts.size());
|
||||
group_parent.parts.insert(group_parent.parts.begin() + group_pos, group);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------- : Group symbol parts
|
||||
|
||||
GroupSymbolPartsActionBase::GroupSymbolPartsActionBase(SymbolGroup& root)
|
||||
: root(root)
|
||||
: root(root)
|
||||
{}
|
||||
void GroupSymbolPartsActionBase::perform(bool to_undo) {
|
||||
swap(root.parts, old_part_list);
|
||||
swap(root.parts, old_part_list);
|
||||
}
|
||||
|
||||
GroupSymbolPartsAction::GroupSymbolPartsAction(SymbolGroup& root, const set<SymbolPartP>& parts, const SymbolGroupP& group)
|
||||
: GroupSymbolPartsActionBase(root)
|
||||
, group(group)
|
||||
: GroupSymbolPartsActionBase(root)
|
||||
, group(group)
|
||||
{
|
||||
// group parts in the old parts list
|
||||
bool done = false;
|
||||
FOR_EACH(p, root.parts) {
|
||||
assert(p != group);
|
||||
if (parts.find(p) != parts.end()) {
|
||||
// add to group instead
|
||||
group->parts.push_back(p);
|
||||
if (!done) {
|
||||
done = true;
|
||||
old_part_list.push_back(group);
|
||||
}
|
||||
} else {
|
||||
// not affected
|
||||
old_part_list.push_back(p);
|
||||
}
|
||||
}
|
||||
group->updateBounds();
|
||||
// group parts in the old parts list
|
||||
bool done = false;
|
||||
FOR_EACH(p, root.parts) {
|
||||
assert(p != group);
|
||||
if (parts.find(p) != parts.end()) {
|
||||
// add to group instead
|
||||
group->parts.push_back(p);
|
||||
if (!done) {
|
||||
done = true;
|
||||
old_part_list.push_back(group);
|
||||
}
|
||||
} else {
|
||||
// not affected
|
||||
old_part_list.push_back(p);
|
||||
}
|
||||
}
|
||||
group->updateBounds();
|
||||
}
|
||||
String GroupSymbolPartsAction::getName(bool to_undo) const {
|
||||
return group->isSymbolSymmetry() ? _ACTION_("add symmetry") : _ACTION_("group parts");
|
||||
return group->isSymbolSymmetry() ? _ACTION_("add symmetry") : _ACTION_("group parts");
|
||||
}
|
||||
|
||||
UngroupSymbolPartsAction::UngroupSymbolPartsAction(SymbolGroup& root, const set<SymbolPartP>& parts)
|
||||
: GroupSymbolPartsActionBase(root)
|
||||
: GroupSymbolPartsActionBase(root)
|
||||
{
|
||||
// break up the parts in the old parts list
|
||||
FOR_EACH(p, root.parts) {
|
||||
if (parts.find(p) != parts.end() && p->isSymbolGroup()) {
|
||||
// break up the group
|
||||
SymbolGroup* g = p->isSymbolGroup();
|
||||
FOR_EACH(p, g->parts) {
|
||||
old_part_list.push_back(p);
|
||||
}
|
||||
} else {
|
||||
// not affected
|
||||
old_part_list.push_back(p);
|
||||
}
|
||||
}
|
||||
// break up the parts in the old parts list
|
||||
FOR_EACH(p, root.parts) {
|
||||
if (parts.find(p) != parts.end() && p->isSymbolGroup()) {
|
||||
// break up the group
|
||||
SymbolGroup* g = p->isSymbolGroup();
|
||||
FOR_EACH(p, g->parts) {
|
||||
old_part_list.push_back(p);
|
||||
}
|
||||
} else {
|
||||
// not affected
|
||||
old_part_list.push_back(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
String UngroupSymbolPartsAction::getName(bool to_undo) const {
|
||||
return _ACTION_("ungroup parts");
|
||||
return _ACTION_("ungroup parts");
|
||||
}
|
||||
|
||||
+161
-161
@@ -26,9 +26,9 @@ class SymbolPartAction : public Action {};
|
||||
/// Anything that changes a set of parts
|
||||
class SymbolPartsAction : public SymbolPartAction {
|
||||
public:
|
||||
SymbolPartsAction(const set<SymbolPartP>& parts);
|
||||
|
||||
const set<SymbolPartP> parts; ///< Affected parts
|
||||
SymbolPartsAction(const set<SymbolPartP>& parts);
|
||||
|
||||
const set<SymbolPartP> parts; ///< Affected parts
|
||||
};
|
||||
|
||||
/// Anything that changes a part as displayed in the part list
|
||||
@@ -39,23 +39,23 @@ class SymbolPartListAction : public SymbolPartAction {};
|
||||
/// Move some symbol parts
|
||||
class SymbolPartMoveAction : public SymbolPartsAction {
|
||||
public:
|
||||
SymbolPartMoveAction(const set<SymbolPartP>& parts, const Vector2D& delta = Vector2D());
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
/// Update this action to move some more
|
||||
void move(const Vector2D& delta);
|
||||
|
||||
SymbolPartMoveAction(const set<SymbolPartP>& parts, const Vector2D& delta = Vector2D());
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
/// Update this action to move some more
|
||||
void move(const Vector2D& delta);
|
||||
|
||||
private:
|
||||
Vector2D delta; ///< How much to move
|
||||
Vector2D moved; ///< How much has been moved
|
||||
Bounds bounds; ///< Bounding box of the thing we are moving
|
||||
|
||||
void movePart(SymbolPart& part); ///< Move a single part
|
||||
Vector2D delta; ///< How much to move
|
||||
Vector2D moved; ///< How much has been moved
|
||||
Bounds bounds; ///< Bounding box of the thing we are moving
|
||||
|
||||
void movePart(SymbolPart& part); ///< Move a single part
|
||||
public:
|
||||
bool constrain; ///< Constrain movement?
|
||||
int snap; ///< Snap to grid?
|
||||
bool constrain; ///< Constrain movement?
|
||||
int snap; ///< Snap to grid?
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : Rotating symbol parts
|
||||
@@ -63,37 +63,37 @@ class SymbolPartMoveAction : public SymbolPartsAction {
|
||||
/// Transforming symbol parts using a matrix
|
||||
class SymbolPartMatrixAction : public SymbolPartsAction {
|
||||
public:
|
||||
SymbolPartMatrixAction(const set<SymbolPartP>& parts, const Vector2D& center);
|
||||
|
||||
/// Update this action to move some more
|
||||
void move(const Vector2D& delta);
|
||||
|
||||
SymbolPartMatrixAction(const set<SymbolPartP>& parts, const Vector2D& center);
|
||||
|
||||
/// Update this action to move some more
|
||||
void move(const Vector2D& delta);
|
||||
|
||||
protected:
|
||||
/// Perform the transformation using the given matrix
|
||||
void transform(const Matrix2D& m);
|
||||
void transform(SymbolPart& part, const Matrix2D& m);
|
||||
|
||||
Vector2D center; ///< Center to transform around
|
||||
/// Perform the transformation using the given matrix
|
||||
void transform(const Matrix2D& m);
|
||||
void transform(SymbolPart& part, const Matrix2D& m);
|
||||
|
||||
Vector2D center; ///< Center to transform around
|
||||
};
|
||||
|
||||
/// Rotate some symbol parts
|
||||
class SymbolPartRotateAction : public SymbolPartMatrixAction {
|
||||
public:
|
||||
SymbolPartRotateAction(const set<SymbolPartP>& parts, const Vector2D& center);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
/// Update this action to rotate to a different angle
|
||||
void rotateTo(Radians newAngle);
|
||||
|
||||
/// Update this action to rotate by a deltaAngle
|
||||
void rotateBy(Radians deltaAngle);
|
||||
|
||||
SymbolPartRotateAction(const set<SymbolPartP>& parts, const Vector2D& center);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
/// Update this action to rotate to a different angle
|
||||
void rotateTo(Radians newAngle);
|
||||
|
||||
/// Update this action to rotate by a deltaAngle
|
||||
void rotateBy(Radians deltaAngle);
|
||||
|
||||
private:
|
||||
Radians angle; ///< How much to rotate?
|
||||
Radians angle; ///< How much to rotate?
|
||||
public:
|
||||
bool constrain; ///< Constrain movement?
|
||||
bool constrain; ///< Constrain movement?
|
||||
};
|
||||
|
||||
|
||||
@@ -102,21 +102,21 @@ class SymbolPartRotateAction : public SymbolPartMatrixAction {
|
||||
/// Shear some symbol parts
|
||||
class SymbolPartShearAction : public SymbolPartMatrixAction {
|
||||
public:
|
||||
SymbolPartShearAction(const set<SymbolPartP>& parts, const Vector2D& center);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
/// Change shear by a given amount
|
||||
void move(const Vector2D& deltaShear);
|
||||
|
||||
SymbolPartShearAction(const set<SymbolPartP>& parts, const Vector2D& center);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
/// Change shear by a given amount
|
||||
void move(const Vector2D& deltaShear);
|
||||
|
||||
private:
|
||||
Vector2D shear; ///< Shearing, shear.x == 0 || shear.y == 0
|
||||
Vector2D moved;
|
||||
void shearBy(const Vector2D& shear);
|
||||
Vector2D shear; ///< Shearing, shear.x == 0 || shear.y == 0
|
||||
Vector2D moved;
|
||||
void shearBy(const Vector2D& shear);
|
||||
public:
|
||||
// bool constrain; ///< Constrain movement?
|
||||
int snap; ///< Snap to grid?
|
||||
// bool constrain; ///< Constrain movement?
|
||||
int snap; ///< Snap to grid?
|
||||
};
|
||||
|
||||
|
||||
@@ -125,29 +125,29 @@ class SymbolPartShearAction : public SymbolPartMatrixAction {
|
||||
/// Scale some symbol parts
|
||||
class SymbolPartScaleAction : public SymbolPartsAction {
|
||||
public:
|
||||
SymbolPartScaleAction(const set<SymbolPartP>& parts, int scaleX, int scaleY);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
/// Change min and max coordinates
|
||||
void move(const Vector2D& delta_min, const Vector2D& delta_max);
|
||||
/// Update the action's effect
|
||||
void update();
|
||||
|
||||
SymbolPartScaleAction(const set<SymbolPartP>& parts, int scaleX, int scaleY);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
/// Change min and max coordinates
|
||||
void move(const Vector2D& delta_min, const Vector2D& delta_max);
|
||||
/// Update the action's effect
|
||||
void update();
|
||||
|
||||
private:
|
||||
Vector2D old_min, old_size; ///< the original pos/size
|
||||
Vector2D new_real_min, new_real_size; ///< the target pos/sizevoid shearBy(const Vector2D& shear)
|
||||
Vector2D new_min, new_size; ///< the target pos/size after applying constrains
|
||||
int scaleX, scaleY; ///< to what corner are we attached?
|
||||
/// Transform everything in the parts
|
||||
void transformAll();
|
||||
void transformPart(SymbolPart&);
|
||||
/// Transform a single vector
|
||||
inline Vector2D transform(const Vector2D& v);
|
||||
Vector2D old_min, old_size; ///< the original pos/size
|
||||
Vector2D new_real_min, new_real_size; ///< the target pos/sizevoid shearBy(const Vector2D& shear)
|
||||
Vector2D new_min, new_size; ///< the target pos/size after applying constrains
|
||||
int scaleX, scaleY; ///< to what corner are we attached?
|
||||
/// Transform everything in the parts
|
||||
void transformAll();
|
||||
void transformPart(SymbolPart&);
|
||||
/// Transform a single vector
|
||||
inline Vector2D transform(const Vector2D& v);
|
||||
public:
|
||||
bool constrain; ///< Constrain movement?
|
||||
int snap; ///< Snap to grid?
|
||||
bool constrain; ///< Constrain movement?
|
||||
int snap; ///< Snap to grid?
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : Change combine mode
|
||||
@@ -155,15 +155,15 @@ class SymbolPartScaleAction : public SymbolPartsAction {
|
||||
/// Change the name of a symbol part
|
||||
class CombiningModeAction : public SymbolPartsAction {
|
||||
public:
|
||||
// All parts must be SymbolParts
|
||||
CombiningModeAction(const set<SymbolPartP>& parts, SymbolShapeCombine mode);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
// All parts must be SymbolParts
|
||||
CombiningModeAction(const set<SymbolPartP>& parts, SymbolShapeCombine mode);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
private:
|
||||
void add(const SymbolPartP&, SymbolShapeCombine mode);
|
||||
vector<pair<SymbolShapeP,SymbolShapeCombine> > parts; ///< Affected parts with new combining modes
|
||||
void add(const SymbolPartP&, SymbolShapeCombine mode);
|
||||
vector<pair<SymbolShapeP,SymbolShapeCombine> > parts; ///< Affected parts with new combining modes
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : Change name
|
||||
@@ -171,17 +171,17 @@ class CombiningModeAction : public SymbolPartsAction {
|
||||
/// Change the name of a symbol part
|
||||
class SymbolPartNameAction : public SymbolPartAction {
|
||||
public:
|
||||
SymbolPartNameAction(const SymbolPartP& part, const String& name, size_t old_cursor, size_t new_cursor);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
virtual bool merge(const Action& action);
|
||||
|
||||
SymbolPartNameAction(const SymbolPartP& part, const String& name, size_t old_cursor, size_t new_cursor);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
virtual bool merge(const Action& action);
|
||||
|
||||
public:
|
||||
SymbolPartP part; ///< Affected part
|
||||
String part_name; ///< New name
|
||||
size_t old_cursor; ///< Cursor position
|
||||
size_t new_cursor; ///< Cursor position
|
||||
SymbolPartP part; ///< Affected part
|
||||
String part_name; ///< New name
|
||||
size_t old_cursor; ///< Cursor position
|
||||
size_t new_cursor; ///< Cursor position
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : Add symbol part
|
||||
@@ -189,14 +189,14 @@ class SymbolPartNameAction : public SymbolPartAction {
|
||||
/// Adding a part to a symbol, added at the front of the list (drawn on top)
|
||||
class AddSymbolPartAction : public SymbolPartListAction {
|
||||
public:
|
||||
AddSymbolPartAction(Symbol& symbol, const SymbolPartP& part);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
AddSymbolPartAction(Symbol& symbol, const SymbolPartP& part);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
private:
|
||||
Symbol& symbol; ///< Symbol to add the part to
|
||||
SymbolPartP part; ///< Part to add
|
||||
Symbol& symbol; ///< Symbol to add the part to
|
||||
SymbolPartP part; ///< Part to add
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : Remove symbol part
|
||||
@@ -204,28 +204,28 @@ class AddSymbolPartAction : public SymbolPartListAction {
|
||||
/// Removing parts from a symbol
|
||||
class RemoveSymbolPartsAction : public SymbolPartListAction {
|
||||
public:
|
||||
RemoveSymbolPartsAction(Symbol& symbol, const set<SymbolPartP>& parts);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
RemoveSymbolPartsAction(Symbol& symbol, const set<SymbolPartP>& parts);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
private:
|
||||
Symbol& symbol;
|
||||
/// Check for removals in a group
|
||||
void check(SymbolGroup& group, const set<SymbolPartP>& parts);
|
||||
Symbol& symbol;
|
||||
/// Check for removals in a group
|
||||
void check(SymbolGroup& group, const set<SymbolPartP>& parts);
|
||||
public:
|
||||
/// A removal step
|
||||
struct Removal {
|
||||
inline Removal(SymbolGroup& parent, size_t pos, const SymbolPartP& removed)
|
||||
: parent(&parent), pos(pos), removed(removed)
|
||||
{}
|
||||
SymbolGroup* parent;
|
||||
size_t pos;
|
||||
SymbolPartP removed;
|
||||
};
|
||||
/// A removal step
|
||||
struct Removal {
|
||||
inline Removal(SymbolGroup& parent, size_t pos, const SymbolPartP& removed)
|
||||
: parent(&parent), pos(pos), removed(removed)
|
||||
{}
|
||||
SymbolGroup* parent;
|
||||
size_t pos;
|
||||
SymbolPartP removed;
|
||||
};
|
||||
private:
|
||||
/// Removed parts, sorted by ascending pos
|
||||
vector<Removal> removals;
|
||||
/// Removed parts, sorted by ascending pos
|
||||
vector<Removal> removals;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : Duplicate symbol parts
|
||||
@@ -233,18 +233,18 @@ class RemoveSymbolPartsAction : public SymbolPartListAction {
|
||||
/// Duplicating parts in a symbol
|
||||
class DuplicateSymbolPartsAction : public SymbolPartListAction {
|
||||
public:
|
||||
DuplicateSymbolPartsAction(Symbol& symbol, const set<SymbolPartP>& parts);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
/// Fill a set with all the new parts
|
||||
void getParts(set<SymbolPartP>& parts);
|
||||
|
||||
DuplicateSymbolPartsAction(Symbol& symbol, const set<SymbolPartP>& parts);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
/// Fill a set with all the new parts
|
||||
void getParts(set<SymbolPartP>& parts);
|
||||
|
||||
private:
|
||||
Symbol& symbol;
|
||||
/// Duplicates of parts and their positions, sorted by ascending pos
|
||||
vector<pair<SymbolPartP, size_t> > duplications;
|
||||
Symbol& symbol;
|
||||
/// Duplicates of parts and their positions, sorted by ascending pos
|
||||
vector<pair<SymbolPartP, size_t> > duplications;
|
||||
};
|
||||
|
||||
|
||||
@@ -253,32 +253,32 @@ class DuplicateSymbolPartsAction : public SymbolPartListAction {
|
||||
/// Change the position of a part in a symbol, by moving a part.
|
||||
class ReorderSymbolPartsAction : public SymbolPartListAction {
|
||||
public:
|
||||
ReorderSymbolPartsAction(SymbolGroup& old_parent, size_t old_position, SymbolGroup& new_parent, size_t new_position);
|
||||
ReorderSymbolPartsAction(SymbolGroup& old_parent, size_t old_position, SymbolGroup& new_parent, size_t new_position);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
private:
|
||||
SymbolGroup* old_parent, *new_parent;///< Parents to move from and to
|
||||
SymbolGroup* old_parent, *new_parent;///< Parents to move from and to
|
||||
public:
|
||||
size_t old_position, new_position; ///< Positions to move from and to
|
||||
size_t old_position, new_position; ///< Positions to move from and to
|
||||
};
|
||||
|
||||
/// Break up a single group, and put its contents at a specific position
|
||||
class UngroupReorderSymbolPartsAction : public SymbolPartListAction {
|
||||
public:
|
||||
/// Remove all the given groups
|
||||
UngroupReorderSymbolPartsAction(SymbolGroup& group_parent, size_t group_pos, SymbolGroup& target_parent, size_t target_pos);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
/// Remove all the given groups
|
||||
UngroupReorderSymbolPartsAction(SymbolGroup& group_parent, size_t group_pos, SymbolGroup& target_parent, size_t target_pos);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
private:
|
||||
SymbolGroup& group_parent;
|
||||
size_t group_pos;
|
||||
SymbolGroupP group; ///< Group to destroy
|
||||
SymbolGroup& target_parent;
|
||||
size_t target_pos;
|
||||
SymbolGroup& group_parent;
|
||||
size_t group_pos;
|
||||
SymbolGroupP group; ///< Group to destroy
|
||||
SymbolGroup& target_parent;
|
||||
size_t target_pos;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : Group symbol parts
|
||||
@@ -286,32 +286,32 @@ class UngroupReorderSymbolPartsAction : public SymbolPartListAction {
|
||||
/// Group multiple symbol parts together
|
||||
class GroupSymbolPartsActionBase : public SymbolPartListAction {
|
||||
public:
|
||||
GroupSymbolPartsActionBase(SymbolGroup& root);
|
||||
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
GroupSymbolPartsActionBase(SymbolGroup& root);
|
||||
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
protected:
|
||||
SymbolGroup& root; ///< Symbol or group to group stuff in
|
||||
vector<SymbolPartP> old_part_list; ///< Old part list of the symbol
|
||||
SymbolGroup& root; ///< Symbol or group to group stuff in
|
||||
vector<SymbolPartP> old_part_list; ///< Old part list of the symbol
|
||||
};
|
||||
|
||||
/// Group multiple symbol parts together
|
||||
class GroupSymbolPartsAction : public GroupSymbolPartsActionBase {
|
||||
public:
|
||||
GroupSymbolPartsAction(SymbolGroup& root, const set<SymbolPartP>& parts, const SymbolGroupP& group);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
GroupSymbolPartsAction(SymbolGroup& root, const set<SymbolPartP>& parts, const SymbolGroupP& group);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
private:
|
||||
SymbolGroupP group;
|
||||
SymbolGroupP group;
|
||||
};
|
||||
|
||||
/// Break up one or more SymbolGroups
|
||||
class UngroupSymbolPartsAction : public GroupSymbolPartsActionBase {
|
||||
public:
|
||||
/// Remove all the given groups
|
||||
UngroupSymbolPartsAction(SymbolGroup& root, const set<SymbolPartP>& groups);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
/// Remove all the given groups
|
||||
UngroupSymbolPartsAction(SymbolGroup& root, const set<SymbolPartP>& groups);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : EOF
|
||||
|
||||
+311
-311
@@ -18,270 +18,270 @@ DECLARE_TYPEOF_COLLECTION(ControlPointP);
|
||||
inline double sgn(double v) { return v > 0 ? 1 : -1; }
|
||||
|
||||
Vector2D constrain_vector(const Vector2D& v, bool constrain, bool only_diagonal) {
|
||||
if (!constrain) return v;
|
||||
double ax = fabs(v.x), ay = fabs(v.y);
|
||||
if (ax * 2 < ay && !only_diagonal) {
|
||||
return Vector2D(0, v.y); // vertical
|
||||
} else if(ay * 2 < ax && !only_diagonal) {
|
||||
return Vector2D(v.x, 0); // horizontal
|
||||
} else {
|
||||
return Vector2D( // diagonal
|
||||
sgn(v.x) * (ax + ay) / 2,
|
||||
sgn(v.y) * (ax + ay) / 2
|
||||
);
|
||||
}
|
||||
if (!constrain) return v;
|
||||
double ax = fabs(v.x), ay = fabs(v.y);
|
||||
if (ax * 2 < ay && !only_diagonal) {
|
||||
return Vector2D(0, v.y); // vertical
|
||||
} else if(ay * 2 < ax && !only_diagonal) {
|
||||
return Vector2D(v.x, 0); // horizontal
|
||||
} else {
|
||||
return Vector2D( // diagonal
|
||||
sgn(v.x) * (ax + ay) / 2,
|
||||
sgn(v.y) * (ax + ay) / 2
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
inline double snap(double x, int steps) {
|
||||
return steps <= 0 ? x : floor(x * steps + 0.5) / steps;
|
||||
return steps <= 0 ? x : floor(x * steps + 0.5) / steps;
|
||||
}
|
||||
|
||||
Vector2D snap_vector(const Vector2D& v, int steps) {
|
||||
return Vector2D(snap(v.x, steps), snap(v.y, steps));
|
||||
return Vector2D(snap(v.x, steps), snap(v.y, steps));
|
||||
}
|
||||
|
||||
Vector2D constrain_snap_vector(const Vector2D& v, const Vector2D& d, bool constrain, int steps) {
|
||||
if (!constrain) return snap_vector(v+d, steps);
|
||||
double ax = fabs(d.x), ay = fabs(d.y);
|
||||
if (ax * 2 < ay) {
|
||||
return Vector2D(v.x, snap(d.y + v.y, steps)); // vertical
|
||||
} else if(ay * 2 < ax) {
|
||||
return Vector2D(snap(d.x + v.x, steps), v.y); // horizontal
|
||||
} else {
|
||||
double dc = (ax + ay) / 2; // delta in both directions
|
||||
double dxs = snap(v.x + dc, steps) - v.x; // snapped to x
|
||||
double dys = snap(v.y + dc, steps) - v.y; // snapped to y
|
||||
if (fabs(dxs-dc) < fabs(dys-dc)) {
|
||||
// take the one that is closest to the unsnaped delta
|
||||
return Vector2D(v.x + sgn(d.x) * dxs, v.y + sgn(d.y) * dxs);
|
||||
} else {
|
||||
return Vector2D(v.x + sgn(d.x) * dys, v.y + sgn(d.y) * dys);
|
||||
}
|
||||
}
|
||||
if (!constrain) return snap_vector(v+d, steps);
|
||||
double ax = fabs(d.x), ay = fabs(d.y);
|
||||
if (ax * 2 < ay) {
|
||||
return Vector2D(v.x, snap(d.y + v.y, steps)); // vertical
|
||||
} else if(ay * 2 < ax) {
|
||||
return Vector2D(snap(d.x + v.x, steps), v.y); // horizontal
|
||||
} else {
|
||||
double dc = (ax + ay) / 2; // delta in both directions
|
||||
double dxs = snap(v.x + dc, steps) - v.x; // snapped to x
|
||||
double dys = snap(v.y + dc, steps) - v.y; // snapped to y
|
||||
if (fabs(dxs-dc) < fabs(dys-dc)) {
|
||||
// take the one that is closest to the unsnaped delta
|
||||
return Vector2D(v.x + sgn(d.x) * dxs, v.y + sgn(d.y) * dxs);
|
||||
} else {
|
||||
return Vector2D(v.x + sgn(d.x) * dys, v.y + sgn(d.y) * dys);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vector2D constrain_snap_vector_offset(const Vector2D& off1, const Vector2D& d, bool constrain, int steps) {
|
||||
return constrain_snap_vector(off1, d, constrain, steps) - off1;
|
||||
return constrain_snap_vector(off1, d, constrain, steps) - off1;
|
||||
}
|
||||
// calculate constrained delta for the given offset, store in output if it is better
|
||||
void constrain_snap_vector_offset_(const Vector2D& off, const Vector2D& d, bool constrain, int steps, Vector2D& best, double& best_length) {
|
||||
Vector2D d2 = constrain_snap_vector_offset(off, d, constrain, steps);
|
||||
double l2 = d2.lengthSqr();
|
||||
if (l2 < best_length) {
|
||||
best_length = l2;
|
||||
best = d2;
|
||||
}
|
||||
Vector2D d2 = constrain_snap_vector_offset(off, d, constrain, steps);
|
||||
double l2 = d2.lengthSqr();
|
||||
if (l2 < best_length) {
|
||||
best_length = l2;
|
||||
best = d2;
|
||||
}
|
||||
}
|
||||
Vector2D constrain_snap_vector_offset(const Vector2D& off1, const Vector2D& off2, const Vector2D& d, bool constrain, int steps) {
|
||||
Vector2D dd; double l = numeric_limits<double>::infinity();
|
||||
constrain_snap_vector_offset_(off1, d, constrain, steps, dd, l);
|
||||
constrain_snap_vector_offset_(off2, d, constrain, steps, dd, l);
|
||||
constrain_snap_vector_offset_(Vector2D(off1.x,off2.y), d, constrain, steps, dd, l);
|
||||
constrain_snap_vector_offset_(Vector2D(off2.x,off1.y), d, constrain, steps, dd, l);
|
||||
return dd;
|
||||
Vector2D dd; double l = numeric_limits<double>::infinity();
|
||||
constrain_snap_vector_offset_(off1, d, constrain, steps, dd, l);
|
||||
constrain_snap_vector_offset_(off2, d, constrain, steps, dd, l);
|
||||
constrain_snap_vector_offset_(Vector2D(off1.x,off2.y), d, constrain, steps, dd, l);
|
||||
constrain_snap_vector_offset_(Vector2D(off2.x,off1.y), d, constrain, steps, dd, l);
|
||||
return dd;
|
||||
}
|
||||
|
||||
String action_name_for(const set<ControlPointP>& points, const String& action) {
|
||||
return format_string(action, points.size() == 1 ? _TYPE_("point") : _TYPE_("points"));
|
||||
return format_string(action, points.size() == 1 ? _TYPE_("point") : _TYPE_("points"));
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------- : Move control point
|
||||
|
||||
ControlPointMoveAction::ControlPointMoveAction(const set<ControlPointP>& points)
|
||||
: points(points)
|
||||
, constrain(false)
|
||||
, snap(0)
|
||||
: points(points)
|
||||
, constrain(false)
|
||||
, snap(0)
|
||||
{
|
||||
oldValues.reserve(points.size());
|
||||
FOR_EACH(p, points) {
|
||||
oldValues.push_back(p->pos);
|
||||
}
|
||||
oldValues.reserve(points.size());
|
||||
FOR_EACH(p, points) {
|
||||
oldValues.push_back(p->pos);
|
||||
}
|
||||
}
|
||||
|
||||
String ControlPointMoveAction::getName(bool to_undo) const {
|
||||
return action_name_for(points, _ACTION_("move"));
|
||||
return action_name_for(points, _ACTION_("move"));
|
||||
}
|
||||
|
||||
void ControlPointMoveAction::perform(bool to_undo) {
|
||||
FOR_EACH_2(p,points, op,oldValues) {
|
||||
swap(p->pos, op);
|
||||
}
|
||||
FOR_EACH_2(p,points, op,oldValues) {
|
||||
swap(p->pos, op);
|
||||
}
|
||||
}
|
||||
|
||||
void ControlPointMoveAction::move (const Vector2D& deltaDelta) {
|
||||
delta += deltaDelta;
|
||||
// Move each point by delta, possibly constrained
|
||||
set<ControlPointP>::const_iterator it = points.begin();
|
||||
vector<Vector2D> ::iterator it2 = oldValues.begin();
|
||||
for( ; it != points.end() && it2 != oldValues.end() ; ++it, ++it2) {
|
||||
(*it)->pos = constrain_snap_vector(*it2, delta, constrain, snap);
|
||||
}
|
||||
delta += deltaDelta;
|
||||
// Move each point by delta, possibly constrained
|
||||
set<ControlPointP>::const_iterator it = points.begin();
|
||||
vector<Vector2D> ::iterator it2 = oldValues.begin();
|
||||
for( ; it != points.end() && it2 != oldValues.end() ; ++it, ++it2) {
|
||||
(*it)->pos = constrain_snap_vector(*it2, delta, constrain, snap);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------- : Move handle
|
||||
|
||||
HandleMoveAction::HandleMoveAction(const SelectedHandle& handle)
|
||||
: handle(handle)
|
||||
, old_handle(handle.getHandle())
|
||||
, old_other (handle.getOther())
|
||||
, constrain(false)
|
||||
, snap(0)
|
||||
: handle(handle)
|
||||
, old_handle(handle.getHandle())
|
||||
, old_other (handle.getOther())
|
||||
, constrain(false)
|
||||
, snap(0)
|
||||
{}
|
||||
|
||||
String HandleMoveAction::getName(bool to_undo) const {
|
||||
return _ACTION_("move handle");
|
||||
return _ACTION_("move handle");
|
||||
}
|
||||
|
||||
void HandleMoveAction::perform(bool to_undo) {
|
||||
swap(old_handle, handle.getHandle());
|
||||
swap(old_other, handle.getOther());
|
||||
swap(old_handle, handle.getHandle());
|
||||
swap(old_other, handle.getOther());
|
||||
}
|
||||
|
||||
void HandleMoveAction::move(const Vector2D& deltaDelta) {
|
||||
delta += deltaDelta;
|
||||
handle.getHandle() = constrain_snap_vector_offset(handle.point->pos, old_handle + delta, constrain, snap);
|
||||
handle.getOther() = old_other;
|
||||
handle.onUpdateHandle();
|
||||
delta += deltaDelta;
|
||||
handle.getHandle() = constrain_snap_vector_offset(handle.point->pos, old_handle + delta, constrain, snap);
|
||||
handle.getOther() = old_other;
|
||||
handle.onUpdateHandle();
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------- : Segment mode
|
||||
|
||||
ControlPointUpdate::ControlPointUpdate(const ControlPointP& pnt)
|
||||
: other(*pnt)
|
||||
, point(pnt)
|
||||
: other(*pnt)
|
||||
, point(pnt)
|
||||
{}
|
||||
|
||||
void ControlPointUpdate::perform() {
|
||||
swap(other, *point);
|
||||
swap(other, *point);
|
||||
}
|
||||
|
||||
|
||||
SegmentModeAction::SegmentModeAction(const ControlPointP& p1, const ControlPointP& p2, SegmentMode mode)
|
||||
: point1(p1), point2(p2)
|
||||
: point1(p1), point2(p2)
|
||||
{
|
||||
if (p1->segment_after == mode) return;
|
||||
point1.other.segment_after = point2.other.segment_before = mode;
|
||||
if (mode == SEGMENT_LINE) {
|
||||
point1.other.delta_after = Vector2D(0,0);
|
||||
point2.other.delta_before = Vector2D(0,0);
|
||||
point1.other.lock = LOCK_FREE;
|
||||
point2.other.lock = LOCK_FREE;
|
||||
} else if (mode == SEGMENT_CURVE) {
|
||||
point1.other.delta_after = (p2->pos - p1->pos) / 3.0f;
|
||||
point2.other.delta_before = (p1->pos - p2->pos) / 3.0f;
|
||||
}
|
||||
if (p1->segment_after == mode) return;
|
||||
point1.other.segment_after = point2.other.segment_before = mode;
|
||||
if (mode == SEGMENT_LINE) {
|
||||
point1.other.delta_after = Vector2D(0,0);
|
||||
point2.other.delta_before = Vector2D(0,0);
|
||||
point1.other.lock = LOCK_FREE;
|
||||
point2.other.lock = LOCK_FREE;
|
||||
} else if (mode == SEGMENT_CURVE) {
|
||||
point1.other.delta_after = (p2->pos - p1->pos) / 3.0f;
|
||||
point2.other.delta_before = (p1->pos - p2->pos) / 3.0f;
|
||||
}
|
||||
}
|
||||
String SegmentModeAction::getName(bool to_undo) const {
|
||||
SegmentMode mode = to_undo ? point1.point->segment_after : point1.other.segment_after;
|
||||
if (mode == SEGMENT_LINE) return _ACTION_("convert to line");
|
||||
else return _ACTION_("convert to curve");
|
||||
SegmentMode mode = to_undo ? point1.point->segment_after : point1.other.segment_after;
|
||||
if (mode == SEGMENT_LINE) return _ACTION_("convert to line");
|
||||
else return _ACTION_("convert to curve");
|
||||
}
|
||||
|
||||
void SegmentModeAction::perform(bool to_undo) {
|
||||
point1.perform();
|
||||
point2.perform();
|
||||
point1.perform();
|
||||
point2.perform();
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------- : Locking mode
|
||||
|
||||
LockModeAction::LockModeAction(const ControlPointP& p, LockMode lock)
|
||||
: point(p)
|
||||
: point(p)
|
||||
{
|
||||
point.other.lock = lock;
|
||||
point.other.onUpdateLock();
|
||||
point.other.lock = lock;
|
||||
point.other.onUpdateLock();
|
||||
}
|
||||
|
||||
String LockModeAction::getName(bool to_undo) const {
|
||||
return _ACTION_("lock point");
|
||||
return _ACTION_("lock point");
|
||||
}
|
||||
|
||||
void LockModeAction::perform(bool to_undo) {
|
||||
point.perform();
|
||||
point.perform();
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------- : Move curve
|
||||
|
||||
CurveDragAction::CurveDragAction(const ControlPointP& point1, const ControlPointP& point2)
|
||||
: SegmentModeAction(point1, point2, SEGMENT_CURVE)
|
||||
: SegmentModeAction(point1, point2, SEGMENT_CURVE)
|
||||
{}
|
||||
|
||||
String CurveDragAction::getName(bool to_undo) const {
|
||||
return _ACTION_("move curve");
|
||||
return _ACTION_("move curve");
|
||||
}
|
||||
|
||||
void CurveDragAction::perform(bool to_undo) {
|
||||
SegmentModeAction::perform(to_undo);
|
||||
SegmentModeAction::perform(to_undo);
|
||||
}
|
||||
|
||||
void CurveDragAction::move(const Vector2D& delta, double t) {
|
||||
// Logic:
|
||||
// Assuming old point is p, new point is p'
|
||||
// Point on old bezier curve is:
|
||||
// p = a t^3 + 3b (1-t) t^2 + 3c (1-t)^2 t + d (1-t)^2
|
||||
// Point on new bezier curve is:
|
||||
// p_(' = a t^3 + 3b') (1-t) t^2 + 3c' (1-t)^2 t + d (1-t)^2
|
||||
// We now want to change control points b and c, the closer we are to b (t close to 0)
|
||||
// the more effect we have on b, so we substitute:
|
||||
// b' = b + x t
|
||||
// c' = c + x (1-t)
|
||||
// Solving for x we get:
|
||||
// x = (p'-p) / ( t (1-t) ( t^2 + (1-t)^2) )
|
||||
// Naming:
|
||||
// delta = p' - p
|
||||
// pointDelta = x * t * (1-t)
|
||||
Vector2D pointDelta = delta / (3 * (t * t + (1-t) * (1-t)));
|
||||
point1.point->delta_after += pointDelta / t;
|
||||
point2.point->delta_before += pointDelta / (1-t);
|
||||
point1.point->onUpdateHandle(HANDLE_AFTER);
|
||||
point2.point->onUpdateHandle(HANDLE_BEFORE);
|
||||
// Logic:
|
||||
// Assuming old point is p, new point is p'
|
||||
// Point on old bezier curve is:
|
||||
// p = a t^3 + 3b (1-t) t^2 + 3c (1-t)^2 t + d (1-t)^2
|
||||
// Point on new bezier curve is:
|
||||
// p_(' = a t^3 + 3b') (1-t) t^2 + 3c' (1-t)^2 t + d (1-t)^2
|
||||
// We now want to change control points b and c, the closer we are to b (t close to 0)
|
||||
// the more effect we have on b, so we substitute:
|
||||
// b' = b + x t
|
||||
// c' = c + x (1-t)
|
||||
// Solving for x we get:
|
||||
// x = (p'-p) / ( t (1-t) ( t^2 + (1-t)^2) )
|
||||
// Naming:
|
||||
// delta = p' - p
|
||||
// pointDelta = x * t * (1-t)
|
||||
Vector2D pointDelta = delta / (3 * (t * t + (1-t) * (1-t)));
|
||||
point1.point->delta_after += pointDelta / t;
|
||||
point2.point->delta_before += pointDelta / (1-t);
|
||||
point1.point->onUpdateHandle(HANDLE_AFTER);
|
||||
point2.point->onUpdateHandle(HANDLE_BEFORE);
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------- : Add control point
|
||||
|
||||
ControlPointAddAction::ControlPointAddAction(const SymbolShapeP& shape, UInt insert_after, double t)
|
||||
: shape(shape)
|
||||
, new_point(new ControlPoint())
|
||||
, insert_after(insert_after)
|
||||
, point1(shape->getPoint(insert_after))
|
||||
, point2(shape->getPoint(insert_after + 1))
|
||||
: shape(shape)
|
||||
, new_point(new ControlPoint())
|
||||
, insert_after(insert_after)
|
||||
, point1(shape->getPoint(insert_after))
|
||||
, point2(shape->getPoint(insert_after + 1))
|
||||
{
|
||||
// calculate new point
|
||||
if (point1.other.segment_after == SEGMENT_CURVE) {
|
||||
// calculate new handles using de Casteljau's subdivision algorithm
|
||||
deCasteljau(point1.other, point2.other, t, *new_point);
|
||||
// unlock if needed
|
||||
if (point1.other.lock == LOCK_SIZE) point1.other.lock = LOCK_DIR;
|
||||
if (point2.other.lock == LOCK_SIZE) point2.other.lock = LOCK_DIR;
|
||||
new_point->lock = LOCK_DIR;
|
||||
new_point->segment_before = SEGMENT_CURVE;
|
||||
new_point->segment_after = SEGMENT_CURVE;
|
||||
} else {
|
||||
new_point->pos = point1.other.pos * (1 - t) + point2.other.pos * t;
|
||||
new_point->lock = LOCK_FREE;
|
||||
new_point->segment_before = SEGMENT_LINE;
|
||||
new_point->segment_after = SEGMENT_LINE;
|
||||
}
|
||||
// calculate new point
|
||||
if (point1.other.segment_after == SEGMENT_CURVE) {
|
||||
// calculate new handles using de Casteljau's subdivision algorithm
|
||||
deCasteljau(point1.other, point2.other, t, *new_point);
|
||||
// unlock if needed
|
||||
if (point1.other.lock == LOCK_SIZE) point1.other.lock = LOCK_DIR;
|
||||
if (point2.other.lock == LOCK_SIZE) point2.other.lock = LOCK_DIR;
|
||||
new_point->lock = LOCK_DIR;
|
||||
new_point->segment_before = SEGMENT_CURVE;
|
||||
new_point->segment_after = SEGMENT_CURVE;
|
||||
} else {
|
||||
new_point->pos = point1.other.pos * (1 - t) + point2.other.pos * t;
|
||||
new_point->lock = LOCK_FREE;
|
||||
new_point->segment_before = SEGMENT_LINE;
|
||||
new_point->segment_after = SEGMENT_LINE;
|
||||
}
|
||||
}
|
||||
|
||||
String ControlPointAddAction::getName(bool to_undo) const {
|
||||
return _ACTION_("add control point");
|
||||
return _ACTION_("add control point");
|
||||
}
|
||||
|
||||
void ControlPointAddAction::perform(bool to_undo) {
|
||||
if (to_undo) { // remove the point
|
||||
shape->points.erase( shape->points.begin() + insert_after + 1);
|
||||
} else {
|
||||
shape->points.insert(shape->points.begin() + insert_after + 1, new_point);
|
||||
}
|
||||
// update points before/after
|
||||
point1.perform();
|
||||
point2.perform();
|
||||
if (to_undo) { // remove the point
|
||||
shape->points.erase( shape->points.begin() + insert_after + 1);
|
||||
} else {
|
||||
shape->points.insert(shape->points.begin() + insert_after + 1, new_point);
|
||||
}
|
||||
// update points before/after
|
||||
point1.perform();
|
||||
point2.perform();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Remove control point
|
||||
@@ -289,89 +289,89 @@ void ControlPointAddAction::perform(bool to_undo) {
|
||||
/// Sqaure root that caries the sign over the root
|
||||
/// or formally: ssqrt(x) = Re<sqrt(x)> - Im<sqrt(x)> = x / sqrt(|x|)
|
||||
double ssqrt(double x) {
|
||||
if (x > 0) return sqrt(x);
|
||||
else return -sqrt(-x);
|
||||
if (x > 0) return sqrt(x);
|
||||
else return -sqrt(-x);
|
||||
}
|
||||
|
||||
// Remove a single control point
|
||||
class SinglePointRemoveAction : public Action, public IntrusivePtrBase<SinglePointRemoveAction> {
|
||||
public:
|
||||
SinglePointRemoveAction(const SymbolShapeP& shape, UInt position);
|
||||
|
||||
virtual String getName(bool to_undo) const { return _("Delete point"); }
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
SinglePointRemoveAction(const SymbolShapeP& shape, UInt position);
|
||||
|
||||
virtual String getName(bool to_undo) const { return _("Delete point"); }
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
private:
|
||||
SymbolShapeP shape;
|
||||
UInt position;
|
||||
ControlPointP point; ///< Removed point
|
||||
ControlPointUpdate point1, point2; ///< Points before/after
|
||||
SymbolShapeP shape;
|
||||
UInt position;
|
||||
ControlPointP point; ///< Removed point
|
||||
ControlPointUpdate point1, point2; ///< Points before/after
|
||||
};
|
||||
|
||||
SinglePointRemoveAction::SinglePointRemoveAction(const SymbolShapeP& shape, UInt position)
|
||||
: shape(shape)
|
||||
, position(position)
|
||||
, point (shape->getPoint(position))
|
||||
, point1(shape->getPoint(position - 1))
|
||||
, point2(shape->getPoint(position + 1))
|
||||
: shape(shape)
|
||||
, position(position)
|
||||
, point (shape->getPoint(position))
|
||||
, point1(shape->getPoint(position - 1))
|
||||
, point2(shape->getPoint(position + 1))
|
||||
{
|
||||
if (point1.other.segment_after == SEGMENT_CURVE || point2.other.segment_before == SEGMENT_CURVE) {
|
||||
// try to preserve curve
|
||||
Vector2D before = point->delta_before;
|
||||
Vector2D after = point->delta_after;
|
||||
|
||||
// convert both segments to curves first
|
||||
if (point1.other.segment_after != SEGMENT_CURVE) {
|
||||
before = (point1.other.pos - point->pos) / 3.0;
|
||||
point1.other.delta_after = -before;
|
||||
point1.other.segment_after = SEGMENT_CURVE;
|
||||
}
|
||||
if (point2.other.segment_before != SEGMENT_CURVE) {
|
||||
after = (point2.other.pos - point->pos) / 3.0;
|
||||
point2.other.delta_before = -after;
|
||||
point2.other.segment_before = SEGMENT_CURVE;
|
||||
}
|
||||
|
||||
// The inverse of adding a point, reconstruct the original handles
|
||||
// before being subdivided using de Casteljau's algorithm
|
||||
// length of handles
|
||||
double bl = before.length() + 0.00000001; // prevent division by 0
|
||||
double al = after .length() + 0.00000001;
|
||||
double totl = bl + al;
|
||||
// set new handle sizes
|
||||
point1.other.delta_after *= totl / bl;
|
||||
point2.other.delta_before *= totl / al;
|
||||
|
||||
// Also take in acount cases where the point does not correspond to a freshly added point.
|
||||
// distance from the point to the curve as it would be in the above case can be used,
|
||||
// in the case of a point just added this distance = 0
|
||||
BezierCurve c(point1.other, point2.other);
|
||||
double t = bl / totl;
|
||||
Vector2D p = c.pointAt(t);
|
||||
Vector2D distP = point->pos - p;
|
||||
// adjust handle sizes
|
||||
point1.other.delta_after *= ssqrt(dot(distP, point1.other.delta_after) /point1.other.delta_after.lengthSqr()) + 1;
|
||||
point2.other.delta_before *= ssqrt(dot(distP, point2.other.delta_before)/point2.other.delta_before.lengthSqr()) + 1;
|
||||
|
||||
// unlock if needed
|
||||
if (point1.other.lock == LOCK_SIZE) point1.other.lock = LOCK_DIR;
|
||||
if (point2.other.lock == LOCK_SIZE) point2.other.lock = LOCK_DIR;
|
||||
} else {
|
||||
// just lines, keep it that way
|
||||
}
|
||||
if (point1.other.segment_after == SEGMENT_CURVE || point2.other.segment_before == SEGMENT_CURVE) {
|
||||
// try to preserve curve
|
||||
Vector2D before = point->delta_before;
|
||||
Vector2D after = point->delta_after;
|
||||
|
||||
// convert both segments to curves first
|
||||
if (point1.other.segment_after != SEGMENT_CURVE) {
|
||||
before = (point1.other.pos - point->pos) / 3.0;
|
||||
point1.other.delta_after = -before;
|
||||
point1.other.segment_after = SEGMENT_CURVE;
|
||||
}
|
||||
if (point2.other.segment_before != SEGMENT_CURVE) {
|
||||
after = (point2.other.pos - point->pos) / 3.0;
|
||||
point2.other.delta_before = -after;
|
||||
point2.other.segment_before = SEGMENT_CURVE;
|
||||
}
|
||||
|
||||
// The inverse of adding a point, reconstruct the original handles
|
||||
// before being subdivided using de Casteljau's algorithm
|
||||
// length of handles
|
||||
double bl = before.length() + 0.00000001; // prevent division by 0
|
||||
double al = after .length() + 0.00000001;
|
||||
double totl = bl + al;
|
||||
// set new handle sizes
|
||||
point1.other.delta_after *= totl / bl;
|
||||
point2.other.delta_before *= totl / al;
|
||||
|
||||
// Also take in acount cases where the point does not correspond to a freshly added point.
|
||||
// distance from the point to the curve as it would be in the above case can be used,
|
||||
// in the case of a point just added this distance = 0
|
||||
BezierCurve c(point1.other, point2.other);
|
||||
double t = bl / totl;
|
||||
Vector2D p = c.pointAt(t);
|
||||
Vector2D distP = point->pos - p;
|
||||
// adjust handle sizes
|
||||
point1.other.delta_after *= ssqrt(dot(distP, point1.other.delta_after) /point1.other.delta_after.lengthSqr()) + 1;
|
||||
point2.other.delta_before *= ssqrt(dot(distP, point2.other.delta_before)/point2.other.delta_before.lengthSqr()) + 1;
|
||||
|
||||
// unlock if needed
|
||||
if (point1.other.lock == LOCK_SIZE) point1.other.lock = LOCK_DIR;
|
||||
if (point2.other.lock == LOCK_SIZE) point2.other.lock = LOCK_DIR;
|
||||
} else {
|
||||
// just lines, keep it that way
|
||||
}
|
||||
}
|
||||
|
||||
void SinglePointRemoveAction::perform(bool to_undo) {
|
||||
if (to_undo) {
|
||||
// reinsert the point
|
||||
shape->points.insert(shape->points.begin() + position, point);
|
||||
} else {
|
||||
// remove the point
|
||||
shape->points.erase( shape->points.begin() + position);
|
||||
}
|
||||
// update points around removed point
|
||||
point1.perform();
|
||||
point2.perform();
|
||||
if (to_undo) {
|
||||
// reinsert the point
|
||||
shape->points.insert(shape->points.begin() + position, point);
|
||||
} else {
|
||||
// remove the point
|
||||
shape->points.erase( shape->points.begin() + position);
|
||||
}
|
||||
// update points around removed point
|
||||
point1.perform();
|
||||
point2.perform();
|
||||
}
|
||||
|
||||
DECLARE_POINTER_TYPE(SinglePointRemoveAction);
|
||||
@@ -383,50 +383,50 @@ DECLARE_TYPEOF_COLLECTION(SinglePointRemoveActionP);
|
||||
// Not all points mat be removed, at least two points must remain.
|
||||
class ControlPointRemoveAction : public Action {
|
||||
public:
|
||||
ControlPointRemoveAction(const SymbolShapeP& shape, const set<ControlPointP>& to_delete);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
ControlPointRemoveAction(const SymbolShapeP& shape, const set<ControlPointP>& to_delete);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
private:
|
||||
vector<SinglePointRemoveActionP> removals;
|
||||
vector<SinglePointRemoveActionP> removals;
|
||||
};
|
||||
|
||||
ControlPointRemoveAction::ControlPointRemoveAction(const SymbolShapeP& shape, const set<ControlPointP>& to_delete) {
|
||||
int index = 0;
|
||||
// find points to remove, in reverse order
|
||||
FOR_EACH(point, shape->points) {
|
||||
if (to_delete.find(point) != to_delete.end()) {
|
||||
// remove this point
|
||||
removals.push_back(intrusive(new SinglePointRemoveAction(shape, index)));
|
||||
}
|
||||
++index;
|
||||
}
|
||||
int index = 0;
|
||||
// find points to remove, in reverse order
|
||||
FOR_EACH(point, shape->points) {
|
||||
if (to_delete.find(point) != to_delete.end()) {
|
||||
// remove this point
|
||||
removals.push_back(intrusive(new SinglePointRemoveAction(shape, index)));
|
||||
}
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
String ControlPointRemoveAction::getName(bool to_undo) const {
|
||||
return removals.size() == 1 ? _ACTION_("delete point") : _ACTION_("delete points");
|
||||
return removals.size() == 1 ? _ACTION_("delete point") : _ACTION_("delete points");
|
||||
}
|
||||
|
||||
void ControlPointRemoveAction::perform(bool to_undo) {
|
||||
if (to_undo) {
|
||||
FOR_EACH(r, removals) r->perform(to_undo);
|
||||
} else {
|
||||
// in reverse order, because positions of later points will
|
||||
// change after removal of earlier points.
|
||||
FOR_EACH_REVERSE(r, removals) r->perform(to_undo);
|
||||
}
|
||||
if (to_undo) {
|
||||
FOR_EACH(r, removals) r->perform(to_undo);
|
||||
} else {
|
||||
// in reverse order, because positions of later points will
|
||||
// change after removal of earlier points.
|
||||
FOR_EACH_REVERSE(r, removals) r->perform(to_undo);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Action* control_point_remove_action(const SymbolShapeP& shape, const set<ControlPointP>& to_delete) {
|
||||
if (shape->points.size() - to_delete.size() < 2) {
|
||||
// TODO : remove part?
|
||||
//intrusive(new ControlPointRemoveAllAction(part));
|
||||
return 0; // no action
|
||||
} else {
|
||||
return new ControlPointRemoveAction(shape, to_delete);
|
||||
}
|
||||
if (shape->points.size() - to_delete.size() < 2) {
|
||||
// TODO : remove part?
|
||||
//intrusive(new ControlPointRemoveAllAction(part));
|
||||
return 0; // no action
|
||||
} else {
|
||||
return new ControlPointRemoveAction(shape, to_delete);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -434,95 +434,95 @@ Action* control_point_remove_action(const SymbolShapeP& shape, const set<Control
|
||||
// ----------------------------------------------------------------------------- : Move symmetry center/handle
|
||||
|
||||
SymmetryMoveAction::SymmetryMoveAction(SymbolSymmetry& symmetry, bool is_handle)
|
||||
: symmetry(symmetry)
|
||||
, is_handle(is_handle)
|
||||
, original(is_handle ? symmetry.handle : symmetry.center)
|
||||
, constrain(false)
|
||||
, snap(0)
|
||||
: symmetry(symmetry)
|
||||
, is_handle(is_handle)
|
||||
, original(is_handle ? symmetry.handle : symmetry.center)
|
||||
, constrain(false)
|
||||
, snap(0)
|
||||
{}
|
||||
|
||||
String SymmetryMoveAction::getName(bool to_undo) const {
|
||||
return is_handle ? _ACTION_("move symmetry handle") : _ACTION_("move symmetry center");
|
||||
return is_handle ? _ACTION_("move symmetry handle") : _ACTION_("move symmetry center");
|
||||
}
|
||||
|
||||
void SymmetryMoveAction::perform(bool to_undo) {
|
||||
if (is_handle) {
|
||||
swap(symmetry.handle, original);
|
||||
} else {
|
||||
swap(symmetry.center, original);
|
||||
}
|
||||
if (is_handle) {
|
||||
swap(symmetry.handle, original);
|
||||
} else {
|
||||
swap(symmetry.center, original);
|
||||
}
|
||||
}
|
||||
|
||||
void SymmetryMoveAction::move(const Vector2D& deltaDelta) {
|
||||
delta += deltaDelta;
|
||||
if (is_handle) {
|
||||
symmetry.handle = snap_vector(symmetry.center + original + delta, snap) - symmetry.center;
|
||||
if (constrain) {
|
||||
// constrain to multiples of 2pi/24 i.e. 24 stops
|
||||
Radians angle = atan2(symmetry.handle.y, symmetry.handle.x);
|
||||
Radians mult = (2 * M_PI) / 24;
|
||||
angle = floor(angle / mult + 0.5) * mult;
|
||||
symmetry.handle = Vector2D(cos(angle), sin(angle)) * symmetry.handle.length();
|
||||
}
|
||||
} else {
|
||||
// Determine actual delta, possibly constrained and snapped
|
||||
symmetry.center = constrain_snap_vector(original, delta, constrain, snap);
|
||||
}
|
||||
delta += deltaDelta;
|
||||
if (is_handle) {
|
||||
symmetry.handle = snap_vector(symmetry.center + original + delta, snap) - symmetry.center;
|
||||
if (constrain) {
|
||||
// constrain to multiples of 2pi/24 i.e. 24 stops
|
||||
Radians angle = atan2(symmetry.handle.y, symmetry.handle.x);
|
||||
Radians mult = (2 * M_PI) / 24;
|
||||
angle = floor(angle / mult + 0.5) * mult;
|
||||
symmetry.handle = Vector2D(cos(angle), sin(angle)) * symmetry.handle.length();
|
||||
}
|
||||
} else {
|
||||
// Determine actual delta, possibly constrained and snapped
|
||||
symmetry.center = constrain_snap_vector(original, delta, constrain, snap);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Change symmetry kind
|
||||
|
||||
SymmetryTypeAction::SymmetryTypeAction(SymbolSymmetry& symmetry, SymbolSymmetryType type)
|
||||
: symmetry(symmetry), type(type)
|
||||
, old_name(symmetry.name)
|
||||
, copies(symmetry.copies)
|
||||
: symmetry(symmetry), type(type)
|
||||
, old_name(symmetry.name)
|
||||
, copies(symmetry.copies)
|
||||
{
|
||||
if (type == SYMMETRY_REFLECTION && symmetry.copies % 2 == 1) {
|
||||
// make sure it is a multiple of two
|
||||
copies = copies / 2 * 2;
|
||||
}
|
||||
// update name?
|
||||
if (old_name == symmetry.expectedName()) {
|
||||
swap(symmetry.kind, type);
|
||||
old_name = symmetry.expectedName();
|
||||
swap(symmetry.kind, type);
|
||||
}
|
||||
if (type == SYMMETRY_REFLECTION && symmetry.copies % 2 == 1) {
|
||||
// make sure it is a multiple of two
|
||||
copies = copies / 2 * 2;
|
||||
}
|
||||
// update name?
|
||||
if (old_name == symmetry.expectedName()) {
|
||||
swap(symmetry.kind, type);
|
||||
old_name = symmetry.expectedName();
|
||||
swap(symmetry.kind, type);
|
||||
}
|
||||
}
|
||||
|
||||
String SymmetryTypeAction::getName(bool to_undo) const {
|
||||
return _ACTION_("change symmetry type");
|
||||
return _ACTION_("change symmetry type");
|
||||
}
|
||||
|
||||
void SymmetryTypeAction::perform(bool to_undo) {
|
||||
swap(symmetry.kind, type);
|
||||
swap(symmetry.copies, copies);
|
||||
swap(symmetry.name, old_name);
|
||||
swap(symmetry.kind, type);
|
||||
swap(symmetry.copies, copies);
|
||||
swap(symmetry.name, old_name);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Change symmetry copies
|
||||
|
||||
SymmetryCopiesAction::SymmetryCopiesAction(SymbolSymmetry& symmetry, int copies_)
|
||||
: symmetry(symmetry), copies(copies_)
|
||||
, old_name(symmetry.name)
|
||||
: symmetry(symmetry), copies(copies_)
|
||||
, old_name(symmetry.name)
|
||||
{
|
||||
if (symmetry.kind == SYMMETRY_REFLECTION && copies % 2 == 1) {
|
||||
// make sure it is a multiple of two
|
||||
if (copies > symmetry.copies) copies++;
|
||||
else copies--;
|
||||
}
|
||||
// update name?
|
||||
if (old_name == symmetry.expectedName()) {
|
||||
swap(symmetry.copies, copies);
|
||||
old_name = symmetry.expectedName();
|
||||
swap(symmetry.copies, copies);
|
||||
}
|
||||
if (symmetry.kind == SYMMETRY_REFLECTION && copies % 2 == 1) {
|
||||
// make sure it is a multiple of two
|
||||
if (copies > symmetry.copies) copies++;
|
||||
else copies--;
|
||||
}
|
||||
// update name?
|
||||
if (old_name == symmetry.expectedName()) {
|
||||
swap(symmetry.copies, copies);
|
||||
old_name = symmetry.expectedName();
|
||||
swap(symmetry.copies, copies);
|
||||
}
|
||||
}
|
||||
|
||||
String SymmetryCopiesAction::getName(bool to_undo) const {
|
||||
return _ACTION_("change symmetry copies");
|
||||
return _ACTION_("change symmetry copies");
|
||||
}
|
||||
|
||||
void SymmetryCopiesAction::perform(bool to_undo) {
|
||||
swap(symmetry.copies, copies);
|
||||
swap(symmetry.name, old_name);
|
||||
swap(symmetry.copies, copies);
|
||||
swap(symmetry.name, old_name);
|
||||
}
|
||||
|
||||
@@ -45,21 +45,21 @@ Vector2D constrain_snap_vector_offset(const Vector2D& off1, const Vector2D& off2
|
||||
/// Moving a control point in a symbol
|
||||
class ControlPointMoveAction : public Action {
|
||||
public:
|
||||
ControlPointMoveAction(const set<ControlPointP>& points);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
/// Update this action to move some more
|
||||
void move(const Vector2D& delta);
|
||||
|
||||
ControlPointMoveAction(const set<ControlPointP>& points);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
/// Update this action to move some more
|
||||
void move(const Vector2D& delta);
|
||||
|
||||
private:
|
||||
set<ControlPointP> points; ///< Points to move
|
||||
vector<Vector2D> oldValues; ///< Their old positions
|
||||
Vector2D delta; ///< Amount we moved
|
||||
set<ControlPointP> points; ///< Points to move
|
||||
vector<Vector2D> oldValues; ///< Their old positions
|
||||
Vector2D delta; ///< Amount we moved
|
||||
public:
|
||||
bool constrain; ///< Constrain movement?
|
||||
int snap; ///< Snap to grid?
|
||||
bool constrain; ///< Constrain movement?
|
||||
int snap; ///< Snap to grid?
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : Move handle
|
||||
@@ -67,22 +67,22 @@ class ControlPointMoveAction : public Action {
|
||||
/// Moving a handle(before/after) of a control point in a symbol
|
||||
class HandleMoveAction : public Action {
|
||||
public:
|
||||
HandleMoveAction(const SelectedHandle& handle);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
/// Update this action to move some more
|
||||
void move(const Vector2D& delta);
|
||||
|
||||
HandleMoveAction(const SelectedHandle& handle);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
/// Update this action to move some more
|
||||
void move(const Vector2D& delta);
|
||||
|
||||
private:
|
||||
SelectedHandle handle; ///< The handle to move
|
||||
Vector2D old_handle; ///< Old value of this handle
|
||||
Vector2D old_other; ///< Old value of other handle, needed for contraints
|
||||
Vector2D delta; ///< Amount we moved
|
||||
SelectedHandle handle; ///< The handle to move
|
||||
Vector2D old_handle; ///< Old value of this handle
|
||||
Vector2D old_other; ///< Old value of other handle, needed for contraints
|
||||
Vector2D delta; ///< Amount we moved
|
||||
public:
|
||||
bool constrain; ///< Constrain movement?
|
||||
int snap; ///< Snap to grid?
|
||||
bool constrain; ///< Constrain movement?
|
||||
int snap; ///< Snap to grid?
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : Segment mode
|
||||
@@ -90,29 +90,29 @@ class HandleMoveAction : public Action {
|
||||
/// Utility class to update a control point
|
||||
class ControlPointUpdate {
|
||||
public:
|
||||
ControlPointUpdate(const ControlPointP& pnt);
|
||||
|
||||
/// Perform or undo an update on this control point
|
||||
void perform();
|
||||
|
||||
/// Other value that is swapped with the current one.
|
||||
/// Should be changed to make perform have an effect
|
||||
ControlPoint other;
|
||||
/// The point that is to be changed, should not be updated before perform()
|
||||
ControlPointP point;
|
||||
ControlPointUpdate(const ControlPointP& pnt);
|
||||
|
||||
/// Perform or undo an update on this control point
|
||||
void perform();
|
||||
|
||||
/// Other value that is swapped with the current one.
|
||||
/// Should be changed to make perform have an effect
|
||||
ControlPoint other;
|
||||
/// The point that is to be changed, should not be updated before perform()
|
||||
ControlPointP point;
|
||||
};
|
||||
|
||||
|
||||
/// Changing a line to a curve and vice versa
|
||||
class SegmentModeAction : public Action {
|
||||
public:
|
||||
SegmentModeAction(const ControlPointP& p1, const ControlPointP& p2, SegmentMode mode);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
SegmentModeAction(const ControlPointP& p1, const ControlPointP& p2, SegmentMode mode);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
protected:
|
||||
ControlPointUpdate point1, point2;
|
||||
ControlPointUpdate point1, point2;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : Locking mode
|
||||
@@ -120,13 +120,13 @@ class SegmentModeAction : public Action {
|
||||
/// Locking a control point
|
||||
class LockModeAction : public Action {
|
||||
public:
|
||||
LockModeAction(const ControlPointP& p, LockMode mode);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
LockModeAction(const ControlPointP& p, LockMode mode);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
private:
|
||||
ControlPointUpdate point; ///< The affected point
|
||||
ControlPointUpdate point; ///< The affected point
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : Move curve
|
||||
@@ -136,13 +136,13 @@ class LockModeAction : public Action {
|
||||
*/
|
||||
class CurveDragAction : public SegmentModeAction {
|
||||
public:
|
||||
CurveDragAction(const ControlPointP& point1, const ControlPointP& point2);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
// Move the curve by this much, it is grabbed at time t
|
||||
void move(const Vector2D& delta, double t);
|
||||
CurveDragAction(const ControlPointP& point1, const ControlPointP& point2);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
// Move the curve by this much, it is grabbed at time t
|
||||
void move(const Vector2D& delta, double t);
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : Add control point
|
||||
@@ -150,19 +150,19 @@ class CurveDragAction : public SegmentModeAction {
|
||||
/// Insert a new point in a symbol shape
|
||||
class ControlPointAddAction : public Action {
|
||||
public:
|
||||
/// Insert a new point in shape, after position insertAfter_, at the time t on the segment
|
||||
ControlPointAddAction(const SymbolShapeP& shape, UInt insert_after, double t);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
inline ControlPointP getNewPoint() const { return new_point; }
|
||||
|
||||
/// Insert a new point in shape, after position insertAfter_, at the time t on the segment
|
||||
ControlPointAddAction(const SymbolShapeP& shape, UInt insert_after, double t);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
inline ControlPointP getNewPoint() const { return new_point; }
|
||||
|
||||
private:
|
||||
SymbolShapeP shape; ///< SymbolShape we are in
|
||||
ControlPointP new_point; ///< The point to insert
|
||||
UInt insert_after; ///< Insert after index .. in the array
|
||||
ControlPointUpdate point1, point2; ///< Update the points around the new point
|
||||
SymbolShapeP shape; ///< SymbolShape we are in
|
||||
ControlPointP new_point; ///< The point to insert
|
||||
UInt insert_after; ///< Insert after index .. in the array
|
||||
ControlPointUpdate point1, point2; ///< Update the points around the new point
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : Remove control point
|
||||
@@ -179,22 +179,22 @@ Action* control_point_remove_action(const SymbolShapeP& shape, const set<Control
|
||||
/// Moving the handle or the center of a symbol symmetry
|
||||
class SymmetryMoveAction : public Action {
|
||||
public:
|
||||
SymmetryMoveAction(SymbolSymmetry& symmetry, bool is_handle);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
/// Update this action to move some more
|
||||
void move(const Vector2D& delta);
|
||||
|
||||
SymmetryMoveAction(SymbolSymmetry& symmetry, bool is_handle);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
/// Update this action to move some more
|
||||
void move(const Vector2D& delta);
|
||||
|
||||
private:
|
||||
SymbolSymmetry& symmetry; ///< Affected part
|
||||
bool is_handle; ///< Move the handle or the center?
|
||||
Vector2D delta; ///< Amount we moved
|
||||
Vector2D original; ///< Original value
|
||||
SymbolSymmetry& symmetry; ///< Affected part
|
||||
bool is_handle; ///< Move the handle or the center?
|
||||
Vector2D delta; ///< Amount we moved
|
||||
Vector2D original; ///< Original value
|
||||
public:
|
||||
bool constrain; ///< Constrain movement?
|
||||
int snap; ///< Snap to grid?
|
||||
bool constrain; ///< Constrain movement?
|
||||
int snap; ///< Snap to grid?
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : Change symmetry kind
|
||||
@@ -202,15 +202,15 @@ class SymmetryMoveAction : public Action {
|
||||
/// Change the type of symmetry
|
||||
class SymmetryTypeAction : public Action {
|
||||
public:
|
||||
SymmetryTypeAction(SymbolSymmetry& symmetry, SymbolSymmetryType type);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
SymmetryTypeAction(SymbolSymmetry& symmetry, SymbolSymmetryType type);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
private:
|
||||
SymbolSymmetry& symmetry;
|
||||
SymbolSymmetryType type;
|
||||
String old_name;
|
||||
int copies; /// may be changed to make it a multiple of two
|
||||
SymbolSymmetry& symmetry;
|
||||
SymbolSymmetryType type;
|
||||
String old_name;
|
||||
int copies; /// may be changed to make it a multiple of two
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : Change symmetry copies
|
||||
@@ -218,14 +218,14 @@ class SymmetryTypeAction : public Action {
|
||||
/// Change the number of copies of a symmetry
|
||||
class SymmetryCopiesAction : public Action {
|
||||
public:
|
||||
SymmetryCopiesAction(SymbolSymmetry& symmetry, int copies);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
SymmetryCopiesAction(SymbolSymmetry& symmetry, int copies);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
private:
|
||||
SymbolSymmetry& symmetry;
|
||||
int copies;
|
||||
String old_name;
|
||||
SymbolSymmetry& symmetry;
|
||||
int copies;
|
||||
String old_name;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : EOF
|
||||
|
||||
+136
-136
@@ -23,17 +23,17 @@
|
||||
// ----------------------------------------------------------------------------- : ValueAction
|
||||
|
||||
String ValueAction::getName(bool to_undo) const {
|
||||
return _ACTION_1_("change", valueP->fieldP->name);
|
||||
return _ACTION_1_("change", valueP->fieldP->name);
|
||||
}
|
||||
|
||||
void ValueAction::perform(bool to_undo) {
|
||||
if (card) {
|
||||
swap(const_cast<Card*>(card)->time_modified, old_time_modified);
|
||||
}
|
||||
if (card) {
|
||||
swap(const_cast<Card*>(card)->time_modified, old_time_modified);
|
||||
}
|
||||
}
|
||||
|
||||
void ValueAction::isOnCard(Card* card) {
|
||||
this->card = card;
|
||||
this->card = card;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Simple
|
||||
@@ -46,38 +46,38 @@ inline void swap_value(SymbolValue& a, SymbolValue ::ValueType& b
|
||||
inline void swap_value(TextValue& a, TextValue ::ValueType& b) { swap(a.value, b); a.last_update.update(); }
|
||||
inline void swap_value(PackageChoiceValue& a, PackageChoiceValue ::ValueType& b) { swap(a.package_name, b); }
|
||||
inline void swap_value(MultipleChoiceValue& a, MultipleChoiceValue::ValueType& b) {
|
||||
swap(a.value, b.value);
|
||||
swap(a.last_change, b.last_change);
|
||||
swap(a.value, b.value);
|
||||
swap(a.last_change, b.last_change);
|
||||
}
|
||||
|
||||
/// A ValueAction that swaps between old and new values
|
||||
template <typename T, bool ALLOW_MERGE>
|
||||
class SimpleValueAction : public ValueAction {
|
||||
public:
|
||||
inline SimpleValueAction(const intrusive_ptr<T>& value, const typename T::ValueType& new_value)
|
||||
: ValueAction(value), new_value(new_value)
|
||||
{}
|
||||
|
||||
virtual void perform(bool to_undo) {
|
||||
ValueAction::perform(to_undo);
|
||||
swap_value(static_cast<T&>(*valueP), new_value);
|
||||
valueP->onAction(*this, to_undo); // notify value
|
||||
}
|
||||
|
||||
virtual bool merge(const Action& action) {
|
||||
if (!ALLOW_MERGE) return false;
|
||||
TYPE_CASE(action, SimpleValueAction) {
|
||||
if (action.valueP == valueP) {
|
||||
// adjacent actions on the same value, discard the other one,
|
||||
// because it only keeps an intermediate value
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline SimpleValueAction(const intrusive_ptr<T>& value, const typename T::ValueType& new_value)
|
||||
: ValueAction(value), new_value(new_value)
|
||||
{}
|
||||
|
||||
virtual void perform(bool to_undo) {
|
||||
ValueAction::perform(to_undo);
|
||||
swap_value(static_cast<T&>(*valueP), new_value);
|
||||
valueP->onAction(*this, to_undo); // notify value
|
||||
}
|
||||
|
||||
virtual bool merge(const Action& action) {
|
||||
if (!ALLOW_MERGE) return false;
|
||||
TYPE_CASE(action, SimpleValueAction) {
|
||||
if (action.valueP == valueP) {
|
||||
// adjacent actions on the same value, discard the other one,
|
||||
// because it only keeps an intermediate value
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
typename T::ValueType new_value;
|
||||
typename T::ValueType new_value;
|
||||
};
|
||||
|
||||
ValueAction* value_action(const ChoiceValueP& value, const Defaultable<String>& new_value) { return new SimpleValueAction<ChoiceValue, true> (value, new_value); }
|
||||
@@ -86,171 +86,171 @@ ValueAction* value_action(const ImageValueP& value, const FileName&
|
||||
ValueAction* value_action(const SymbolValueP& value, const FileName& new_value) { return new SimpleValueAction<SymbolValue, false>(value, new_value); }
|
||||
ValueAction* value_action(const PackageChoiceValueP& value, const String& new_value) { return new SimpleValueAction<PackageChoiceValue, false>(value, new_value); }
|
||||
ValueAction* value_action(const MultipleChoiceValueP& value, const Defaultable<String>& new_value, const String& last_change) {
|
||||
MultipleChoiceValue::ValueType v = { new_value, last_change };
|
||||
return new SimpleValueAction<MultipleChoiceValue, false>(value, v);
|
||||
MultipleChoiceValue::ValueType v = { new_value, last_change };
|
||||
return new SimpleValueAction<MultipleChoiceValue, false>(value, v);
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------- : Text
|
||||
|
||||
TextValueAction::TextValueAction(const TextValueP& value, size_t start, size_t end, size_t new_end, const Defaultable<String>& new_value, const String& name)
|
||||
: ValueAction(value)
|
||||
, selection_start(start), selection_end(end), new_selection_end(new_end)
|
||||
, new_value(new_value)
|
||||
, name(name)
|
||||
: ValueAction(value)
|
||||
, selection_start(start), selection_end(end), new_selection_end(new_end)
|
||||
, new_value(new_value)
|
||||
, name(name)
|
||||
{}
|
||||
|
||||
String TextValueAction::getName(bool to_undo) const { return name; }
|
||||
|
||||
void TextValueAction::perform(bool to_undo) {
|
||||
ValueAction::perform(to_undo);
|
||||
swap_value(value(), new_value);
|
||||
swap(selection_end, new_selection_end);
|
||||
valueP->onAction(*this, to_undo); // notify value
|
||||
ValueAction::perform(to_undo);
|
||||
swap_value(value(), new_value);
|
||||
swap(selection_end, new_selection_end);
|
||||
valueP->onAction(*this, to_undo); // notify value
|
||||
}
|
||||
|
||||
bool TextValueAction::merge(const Action& action) {
|
||||
TYPE_CASE(action, TextValueAction) {
|
||||
if (&action.value() == &value() && action.name == name) {
|
||||
if (action.selection_start == selection_end) {
|
||||
// adjacent edits, keep old value of this, it is older
|
||||
selection_end = action.selection_end;
|
||||
return true;
|
||||
} else if (action.new_selection_end == selection_start && name == _ACTION_("backspace")) {
|
||||
// adjacent backspaces
|
||||
selection_start = action.selection_start;
|
||||
selection_end = action.selection_end;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
TYPE_CASE(action, TextValueAction) {
|
||||
if (&action.value() == &value() && action.name == name) {
|
||||
if (action.selection_start == selection_end) {
|
||||
// adjacent edits, keep old value of this, it is older
|
||||
selection_end = action.selection_end;
|
||||
return true;
|
||||
} else if (action.new_selection_end == selection_start && name == _ACTION_("backspace")) {
|
||||
// adjacent backspaces
|
||||
selection_start = action.selection_start;
|
||||
selection_end = action.selection_end;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
TextValue& TextValueAction::value() const {
|
||||
return static_cast<TextValue&>(*valueP);
|
||||
return static_cast<TextValue&>(*valueP);
|
||||
}
|
||||
|
||||
|
||||
TextValueAction* toggle_format_action(const TextValueP& value, const String& tag, size_t start_i, size_t end_i, size_t start, size_t end, const String& action_name) {
|
||||
if (start > end) {
|
||||
swap(start, end);
|
||||
swap(start_i, end_i);
|
||||
}
|
||||
String new_value;
|
||||
const String& str = value->value();
|
||||
// Are we inside the tag we are toggling?
|
||||
if (!is_in_tag(str, _("<") + tag, start_i, end_i)) {
|
||||
// we are not inside this tag, add it
|
||||
new_value = str.substr(0, start_i);
|
||||
new_value += _("<") + tag + _(">");
|
||||
new_value += str.substr(start_i, end_i - start_i);
|
||||
new_value += _("</") + tag + _(">");
|
||||
new_value += str.substr(end_i);
|
||||
} else {
|
||||
// we are inside this tag, 'remove' it
|
||||
new_value = str.substr(0, start_i);
|
||||
new_value += _("</") + tag + _(">");
|
||||
new_value += str.substr(start_i, end_i - start_i);
|
||||
new_value += _("<") + tag + _(">");
|
||||
new_value += str.substr(end_i);
|
||||
}
|
||||
// Build action
|
||||
if (start != end) {
|
||||
// don't simplify if start == end, this way we insert <b></b>, allowing the
|
||||
// user to press Ctrl+B and start typing bold text
|
||||
new_value = simplify_tagged(new_value);
|
||||
}
|
||||
if (value->value() == new_value) {
|
||||
return nullptr; // no changes
|
||||
} else {
|
||||
return new TextValueAction(value, start, end, end, new_value, action_name);
|
||||
}
|
||||
if (start > end) {
|
||||
swap(start, end);
|
||||
swap(start_i, end_i);
|
||||
}
|
||||
String new_value;
|
||||
const String& str = value->value();
|
||||
// Are we inside the tag we are toggling?
|
||||
if (!is_in_tag(str, _("<") + tag, start_i, end_i)) {
|
||||
// we are not inside this tag, add it
|
||||
new_value = str.substr(0, start_i);
|
||||
new_value += _("<") + tag + _(">");
|
||||
new_value += str.substr(start_i, end_i - start_i);
|
||||
new_value += _("</") + tag + _(">");
|
||||
new_value += str.substr(end_i);
|
||||
} else {
|
||||
// we are inside this tag, 'remove' it
|
||||
new_value = str.substr(0, start_i);
|
||||
new_value += _("</") + tag + _(">");
|
||||
new_value += str.substr(start_i, end_i - start_i);
|
||||
new_value += _("<") + tag + _(">");
|
||||
new_value += str.substr(end_i);
|
||||
}
|
||||
// Build action
|
||||
if (start != end) {
|
||||
// don't simplify if start == end, this way we insert <b></b>, allowing the
|
||||
// user to press Ctrl+B and start typing bold text
|
||||
new_value = simplify_tagged(new_value);
|
||||
}
|
||||
if (value->value() == new_value) {
|
||||
return nullptr; // no changes
|
||||
} else {
|
||||
return new TextValueAction(value, start, end, end, new_value, action_name);
|
||||
}
|
||||
}
|
||||
|
||||
TextValueAction* typing_action(const TextValueP& value, size_t start_i, size_t end_i, size_t start, size_t end, const String& replacement, const String& action_name) {
|
||||
bool reverse = start > end;
|
||||
if (reverse) {
|
||||
swap(start, end);
|
||||
swap(start_i, end_i);
|
||||
}
|
||||
String new_value = tagged_substr_replace(value->value(), start_i, end_i, replacement);
|
||||
if (value->value() == new_value) {
|
||||
// no change
|
||||
return nullptr;
|
||||
} else {
|
||||
if (reverse) {
|
||||
return new TextValueAction(value, end, start, start+untag(replacement).size(), new_value, action_name);
|
||||
} else {
|
||||
return new TextValueAction(value, start, end, start+untag(replacement).size(), new_value, action_name);
|
||||
}
|
||||
}
|
||||
bool reverse = start > end;
|
||||
if (reverse) {
|
||||
swap(start, end);
|
||||
swap(start_i, end_i);
|
||||
}
|
||||
String new_value = tagged_substr_replace(value->value(), start_i, end_i, replacement);
|
||||
if (value->value() == new_value) {
|
||||
// no change
|
||||
return nullptr;
|
||||
} else {
|
||||
if (reverse) {
|
||||
return new TextValueAction(value, end, start, start+untag(replacement).size(), new_value, action_name);
|
||||
} else {
|
||||
return new TextValueAction(value, start, end, start+untag(replacement).size(), new_value, action_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Reminder text
|
||||
|
||||
TextToggleReminderAction::TextToggleReminderAction(const TextValueP& value, size_t pos_in)
|
||||
: ValueAction(value)
|
||||
: ValueAction(value)
|
||||
{
|
||||
pos = in_tag(value->value(), _("<kw-"), pos_in, pos_in);
|
||||
if (pos == String::npos) {
|
||||
throw InternalError(_("TextToggleReminderAction: not in <kw- tag"));
|
||||
}
|
||||
Char c = value->value().GetChar(pos + 4);
|
||||
enable = !(c == _('1') || c == _('A')); // if it was not enabled, then enable it
|
||||
old = enable ? _('1') : _('0');
|
||||
pos = in_tag(value->value(), _("<kw-"), pos_in, pos_in);
|
||||
if (pos == String::npos) {
|
||||
throw InternalError(_("TextToggleReminderAction: not in <kw- tag"));
|
||||
}
|
||||
Char c = value->value().GetChar(pos + 4);
|
||||
enable = !(c == _('1') || c == _('A')); // if it was not enabled, then enable it
|
||||
old = enable ? _('1') : _('0');
|
||||
}
|
||||
String TextToggleReminderAction::getName(bool to_undo) const {
|
||||
return enable ? _("Show reminder text") : _("Hide reminder text");
|
||||
return enable ? _("Show reminder text") : _("Hide reminder text");
|
||||
}
|
||||
|
||||
void TextToggleReminderAction::perform(bool to_undo) {
|
||||
ValueAction::perform(to_undo);
|
||||
TextValue& value = static_cast<TextValue&>(*valueP);
|
||||
String& val = value.value.mutate();
|
||||
assert(pos + 4 < val.size());
|
||||
size_t end = match_close_tag(val, pos);
|
||||
Char& c = val[pos + 4];
|
||||
swap(c, old);
|
||||
if (end != String::npos && end + 5 < val.size()) {
|
||||
val[end + 5] = c; // </kw-c>
|
||||
}
|
||||
value.last_update.update();
|
||||
value.onAction(*this, to_undo); // notify value
|
||||
ValueAction::perform(to_undo);
|
||||
TextValue& value = static_cast<TextValue&>(*valueP);
|
||||
String& val = value.value.mutate();
|
||||
assert(pos + 4 < val.size());
|
||||
size_t end = match_close_tag(val, pos);
|
||||
Char& c = val[pos + 4];
|
||||
swap(c, old);
|
||||
if (end != String::npos && end + 5 < val.size()) {
|
||||
val[end + 5] = c; // </kw-c>
|
||||
}
|
||||
value.last_update.update();
|
||||
value.onAction(*this, to_undo); // notify value
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------- : Event
|
||||
|
||||
String ScriptValueEvent::getName(bool) const {
|
||||
assert(false); // this action is just an event, getName shouldn't be called
|
||||
throw InternalError(_("ScriptValueEvent::getName"));
|
||||
assert(false); // this action is just an event, getName shouldn't be called
|
||||
throw InternalError(_("ScriptValueEvent::getName"));
|
||||
}
|
||||
void ScriptValueEvent::perform(bool) {
|
||||
assert(false); // this action is just an event, it should not be performed
|
||||
assert(false); // this action is just an event, it should not be performed
|
||||
}
|
||||
|
||||
|
||||
String ScriptStyleEvent::getName(bool) const {
|
||||
assert(false); // this action is just an event, getName shouldn't be called
|
||||
throw InternalError(_("ScriptStyleEvent::getName"));
|
||||
assert(false); // this action is just an event, getName shouldn't be called
|
||||
throw InternalError(_("ScriptStyleEvent::getName"));
|
||||
}
|
||||
void ScriptStyleEvent::perform(bool) {
|
||||
assert(false); // this action is just an event, it should not be performed
|
||||
assert(false); // this action is just an event, it should not be performed
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Action performer
|
||||
|
||||
ValueActionPerformer::ValueActionPerformer(const ValueP& value, Card* card, const SetP& set)
|
||||
: value(value), card(card), set(set)
|
||||
: value(value), card(card), set(set)
|
||||
{}
|
||||
ValueActionPerformer::~ValueActionPerformer() {}
|
||||
|
||||
void ValueActionPerformer::addAction(ValueAction* action) {
|
||||
action->isOnCard(card);
|
||||
set->actions.addAction(action);
|
||||
action->isOnCard(card);
|
||||
set->actions.addAction(action);
|
||||
}
|
||||
|
||||
Package& ValueActionPerformer::getLocalPackage() {
|
||||
return *set;
|
||||
return *set;
|
||||
}
|
||||
|
||||
+72
-72
@@ -36,20 +36,20 @@ DECLARE_POINTER_TYPE(PackageChoiceValue);
|
||||
/// An Action the changes a Value
|
||||
class ValueAction : public Action {
|
||||
public:
|
||||
inline ValueAction(const ValueP& value)
|
||||
: valueP(value), card(nullptr), old_time_modified(wxDateTime::Now())
|
||||
{}
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
/// We know that the value is on the given card, add that information
|
||||
void isOnCard(Card* card);
|
||||
|
||||
const ValueP valueP; ///< The modified value
|
||||
const Card* card; ///< The card the value is on, or null if it is not a card value
|
||||
inline ValueAction(const ValueP& value)
|
||||
: valueP(value), card(nullptr), old_time_modified(wxDateTime::Now())
|
||||
{}
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
/// We know that the value is on the given card, add that information
|
||||
void isOnCard(Card* card);
|
||||
|
||||
const ValueP valueP; ///< The modified value
|
||||
const Card* card; ///< The card the value is on, or null if it is not a card value
|
||||
private:
|
||||
wxDateTime old_time_modified;
|
||||
wxDateTime old_time_modified;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : Simple
|
||||
@@ -67,22 +67,22 @@ ValueAction* value_action(const PackageChoiceValueP& value, const String&
|
||||
/// An action that changes a TextValue
|
||||
class TextValueAction : public ValueAction {
|
||||
public:
|
||||
TextValueAction(const TextValueP& value, size_t start, size_t end, size_t new_end, const Defaultable<String>& new_value, const String& name);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
virtual bool merge(const Action& action);
|
||||
|
||||
inline const String& newValue() const { return new_value(); }
|
||||
|
||||
/// The modified selection
|
||||
size_t selection_start, selection_end;
|
||||
TextValueAction(const TextValueP& value, size_t start, size_t end, size_t new_end, const Defaultable<String>& new_value, const String& name);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
virtual bool merge(const Action& action);
|
||||
|
||||
inline const String& newValue() const { return new_value(); }
|
||||
|
||||
/// The modified selection
|
||||
size_t selection_start, selection_end;
|
||||
private:
|
||||
inline TextValue& value() const;
|
||||
|
||||
size_t new_selection_end;
|
||||
Defaultable<String> new_value;
|
||||
String name;
|
||||
inline TextValue& value() const;
|
||||
|
||||
size_t new_selection_end;
|
||||
Defaultable<String> new_value;
|
||||
String name;
|
||||
};
|
||||
|
||||
/// Action for toggling some formating tag on or off in some range
|
||||
@@ -97,15 +97,15 @@ TextValueAction* typing_action(const TextValueP& value, size_t start_i, size_t e
|
||||
/// Toggle reminder text for a keyword on or off
|
||||
class TextToggleReminderAction : public ValueAction {
|
||||
public:
|
||||
TextToggleReminderAction(const TextValueP& value, size_t pos);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
private:
|
||||
size_t pos; ///< Position of "<kw-"
|
||||
bool enable; ///< Should the reminder text be turned on or off?
|
||||
Char old; ///< Old value of the <kw- tag
|
||||
TextToggleReminderAction(const TextValueP& value, size_t pos);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
private:
|
||||
size_t pos; ///< Position of "<kw-"
|
||||
bool enable; ///< Should the reminder text be turned on or off?
|
||||
Char old; ///< Old value of the <kw- tag
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : Replace all
|
||||
@@ -113,22 +113,22 @@ class TextToggleReminderAction : public ValueAction {
|
||||
/// A TextValueAction without the start and end stuff
|
||||
class SimpleTextValueAction : public ValueAction {
|
||||
public:
|
||||
SimpleTextValueAction(const Card* card, const TextValueP& value, const Defaultable<String>& new_value);
|
||||
virtual void perform(bool to_undo);
|
||||
bool merge(const SimpleTextValueAction& action);
|
||||
SimpleTextValueAction(const Card* card, const TextValueP& value, const Defaultable<String>& new_value);
|
||||
virtual void perform(bool to_undo);
|
||||
bool merge(const SimpleTextValueAction& action);
|
||||
private:
|
||||
Defaultable<String> new_value;
|
||||
Defaultable<String> new_value;
|
||||
};
|
||||
|
||||
/// An action from "Replace All"; just a bunch of value actions performed in sequence
|
||||
class ReplaceAllAction : public Action {
|
||||
public:
|
||||
~ReplaceAllAction();
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
vector<SimpleTextValueAction> actions;
|
||||
~ReplaceAllAction();
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
vector<SimpleTextValueAction> actions;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : Event
|
||||
@@ -136,27 +136,27 @@ class ReplaceAllAction : public Action {
|
||||
/// Notification that a script caused a value to change
|
||||
class ScriptValueEvent : public Action {
|
||||
public:
|
||||
inline ScriptValueEvent(const Card* card, const Value* value) : card(card), value(value) {}
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
const Card* card; ///< Card the value is on
|
||||
const Value* value; ///< The modified value
|
||||
inline ScriptValueEvent(const Card* card, const Value* value) : card(card), value(value) {}
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
const Card* card; ///< Card the value is on
|
||||
const Value* value; ///< The modified value
|
||||
};
|
||||
|
||||
/// Notification that a script caused a style to change
|
||||
class ScriptStyleEvent : public Action {
|
||||
public:
|
||||
inline ScriptStyleEvent(const StyleSheet* stylesheet, const Style* style)
|
||||
: stylesheet(stylesheet), style(style)
|
||||
{}
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
const StyleSheet* stylesheet; ///< StyleSheet the style is for
|
||||
const Style* style; ///< The modified style
|
||||
inline ScriptStyleEvent(const StyleSheet* stylesheet, const Style* style)
|
||||
: stylesheet(stylesheet), style(style)
|
||||
{}
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
virtual void perform(bool to_undo);
|
||||
|
||||
const StyleSheet* stylesheet; ///< StyleSheet the style is for
|
||||
const Style* style; ///< The modified style
|
||||
};
|
||||
|
||||
|
||||
@@ -166,16 +166,16 @@ class ScriptStyleEvent : public Action {
|
||||
/** Used to reduce coupling */
|
||||
class ValueActionPerformer {
|
||||
public:
|
||||
ValueActionPerformer(const ValueP& value, Card* card, const SetP& set);
|
||||
~ValueActionPerformer();
|
||||
/// Perform an action. The performer takes ownerwhip of the action.
|
||||
void addAction(ValueAction* action);
|
||||
|
||||
const ValueP value; ///< The value
|
||||
Package& getLocalPackage();
|
||||
ValueActionPerformer(const ValueP& value, Card* card, const SetP& set);
|
||||
~ValueActionPerformer();
|
||||
/// Perform an action. The performer takes ownerwhip of the action.
|
||||
void addAction(ValueAction* action);
|
||||
|
||||
const ValueP value; ///< The value
|
||||
Package& getLocalPackage();
|
||||
private:
|
||||
Card* card; ///< Card the value is on (if any)
|
||||
SetP set; ///< Set for the actions
|
||||
Card* card; ///< Card the value is on (if any)
|
||||
SetP set; ///< Set for the actions
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : EOF
|
||||
|
||||
Reference in New Issue
Block a user