Change tabs to two spaces.

This commit is contained in:
Lymia Aluysia
2017-01-18 08:43:21 -06:00
parent d7f5f0dc3b
commit d2c635f739
329 changed files with 41307 additions and 41496 deletions
+61 -61
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);
}
+97 -97
View File
@@ -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
View File
@@ -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
View File
@@ -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