mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-10 13:06:59 -04:00
Editing of keywords
git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@255 0fc631ac-6414-0410-93d0-97cfa31319b6
This commit is contained in:
@@ -10,6 +10,9 @@
|
||||
#include <data/keyword.hpp>
|
||||
#include <data/set.hpp>
|
||||
#include <data/game.hpp>
|
||||
#include <script/parser.hpp>
|
||||
#include <util/tagged_string.hpp>
|
||||
#include <util/error.hpp>
|
||||
|
||||
DECLARE_TYPEOF_COLLECTION(KeywordModeP);
|
||||
|
||||
@@ -69,3 +72,101 @@ void RemoveKeywordAction::perform(bool to_undo) {
|
||||
set.keywords.insert(set.keywords.begin() + keyword_id, keyword);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Changing keywords
|
||||
|
||||
KeywordReminderTextValue::KeywordReminderTextValue(const TextFieldP& field, Keyword* keyword, bool editable)
|
||||
: KeywordTextValue(field, keyword, &keyword->reminder.getUnparsed(), editable)
|
||||
{}
|
||||
|
||||
void KeywordReminderTextValue::store() {
|
||||
if (!editable) {
|
||||
retrieve();
|
||||
return;
|
||||
}
|
||||
// Re-highlight
|
||||
String new_value = untag(value);
|
||||
highlight(new_value);
|
||||
// Try to parse the script
|
||||
try {
|
||||
ScriptP new_script = parse(new_value, true);
|
||||
// parsed okay, assign
|
||||
errors.clear();
|
||||
keyword.reminder.getScriptP() = new_script;
|
||||
keyword.reminder.getUnparsed() = new_value;
|
||||
} catch (const Error& e) {
|
||||
// parse errors, report
|
||||
errors = e.what(); // TODO
|
||||
}
|
||||
}
|
||||
|
||||
void KeywordReminderTextValue::retrieve() {
|
||||
highlight(*underlying);
|
||||
}
|
||||
|
||||
void KeywordReminderTextValue::highlight(const String& code) {
|
||||
// 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;
|
||||
int in_brace = 0;
|
||||
bool in_string = true;
|
||||
for (size_t pos = 0 ; pos < code.size() ; ) {
|
||||
Char c = code.GetChar(pos);
|
||||
if (c == _('<')) {
|
||||
new_value += _('\1'); // escape
|
||||
++pos;
|
||||
} else if (c == _('{')) {
|
||||
in_brace++;
|
||||
if (in_brace == 1) new_value += _("<code>");
|
||||
if (in_string) in_string = false;
|
||||
new_value += c;
|
||||
++pos;
|
||||
} else if (c == _('}') && !in_string) {
|
||||
new_value += c;
|
||||
in_brace--;
|
||||
if (in_brace == 0) {
|
||||
new_value += _("</code>");
|
||||
in_string = true;
|
||||
}
|
||||
++pos;
|
||||
} else if (c == _('"')) {
|
||||
if (in_string) {
|
||||
in_string = false;
|
||||
new_value += _("\"<code-str>");
|
||||
} else {
|
||||
in_string = true;
|
||||
new_value += _("<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 += _("<") + param + _(">") + param + _("</") + param + _(">");
|
||||
pos = end;
|
||||
} else {
|
||||
new_value += c;
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
// set
|
||||
value = new_value;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#include <util/prec.hpp>
|
||||
#include <util/action_stack.hpp>
|
||||
#include <data/field/text.hpp>
|
||||
|
||||
class Set;
|
||||
DECLARE_POINTER_TYPE(Keyword);
|
||||
@@ -62,5 +63,38 @@ class RemoveKeywordAction : public KeywordListAction {
|
||||
|
||||
// ----------------------------------------------------------------------------- : Changing keywords
|
||||
|
||||
/// A FakeTextValue that is used to edit an aspect of a keyword
|
||||
/** These values can be seen in ValueActions.
|
||||
* Can edit one of:
|
||||
* - the keyword name
|
||||
* - the match string
|
||||
* - reminder text
|
||||
*/
|
||||
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
|
||||
};
|
||||
|
||||
/// A FakeTextValue that is used to edit reminder text scripts
|
||||
class KeywordReminderTextValue : public KeywordTextValue {
|
||||
public:
|
||||
KeywordReminderTextValue(const TextFieldP& field, Keyword* keyword, bool editable);
|
||||
|
||||
String errors; ///< Errors in the script
|
||||
|
||||
/// 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);
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : EOF
|
||||
#endif
|
||||
|
||||
+14
-7
@@ -109,18 +109,25 @@ IMPLEMENT_REFLECTION_NAMELESS(TextValue) {
|
||||
|
||||
// ----------------------------------------------------------------------------- : FakeTextValue
|
||||
|
||||
FakeTextValue::FakeTextValue(const TextFieldP& field, String* underlying, bool untagged)
|
||||
FakeTextValue::FakeTextValue(const TextFieldP& field, String* underlying, bool editable, bool untagged)
|
||||
: TextValue(field), underlying(underlying)
|
||||
, untagged(untagged)
|
||||
{
|
||||
if (underlying) {
|
||||
value.assign(untagged ? escape(*underlying) : *underlying);
|
||||
, editable(editable), untagged(untagged)
|
||||
{}
|
||||
|
||||
void FakeTextValue::store() {
|
||||
if (editable) {
|
||||
*underlying = untagged ? untag(value) : value;
|
||||
} else {
|
||||
retrieve();
|
||||
}
|
||||
}
|
||||
void FakeTextValue::retrieve() {
|
||||
value.assign(untagged ? escape(*underlying) : *underlying);
|
||||
}
|
||||
|
||||
void FakeTextValue::onAction(Action& a, bool undone) {
|
||||
if (underlying) {
|
||||
*underlying = untagged ? untag(value) : value;
|
||||
store();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,6 +137,6 @@ bool FakeTextValue::equals(const Value* that) {
|
||||
const FakeTextValue* thatT = dynamic_cast<const FakeTextValue*>(that);
|
||||
if (!thatT || underlying != thatT->underlying) return false;
|
||||
// update the value
|
||||
value.assign(untagged ? escape(*underlying) : *underlying);
|
||||
retrieve();
|
||||
return true;
|
||||
}
|
||||
|
||||
+10
-2
@@ -107,10 +107,18 @@ class FakeTextValue : public TextValue {
|
||||
public:
|
||||
/// Initialize the fake text value
|
||||
/** underlying can be nullptr, in that case there is no underlying value */
|
||||
FakeTextValue(const TextFieldP& field, String* underlying, bool untagged);
|
||||
FakeTextValue(const TextFieldP& field, String* underlying, bool editable, bool untagged);
|
||||
|
||||
String* const underlying; ///< The underlying actual value, can be null
|
||||
bool const untagged; ///< The underlying value is untagged
|
||||
bool const editable; ///< The underlying value can be edited
|
||||
bool const untagged; ///< The underlying value is untagged
|
||||
|
||||
/// Store the value in the underlying value.
|
||||
/** May be overloaded to do some transformation */
|
||||
virtual void store();
|
||||
/// Retrieve the value from the underlying value.
|
||||
/** May be overloaded to do some transformation */
|
||||
virtual void retrieve();
|
||||
|
||||
/// Update underlying data
|
||||
virtual void onAction(Action& a, bool undone);
|
||||
|
||||
+6
-1
@@ -27,7 +27,7 @@ void Font::initDependencies(Context& ctx, const Dependency& dep) const {
|
||||
shadow_color.initDependencies(ctx, dep);
|
||||
}
|
||||
|
||||
FontP Font::make(bool bold, bool italic, bool placeholder_color, Color* other_color) const {
|
||||
FontP Font::make(bool bold, bool italic, bool placeholder_color, bool code_color, Color* other_color) const {
|
||||
FontP f(new Font(*this));
|
||||
if (bold) f->font.SetWeight(wxBOLD);
|
||||
if (italic) {
|
||||
@@ -37,6 +37,11 @@ FontP Font::make(bool bold, bool italic, bool placeholder_color, Color* other_co
|
||||
f->font.SetWeight(wxBOLD);
|
||||
}
|
||||
}
|
||||
if (code_color) {
|
||||
f->color = Color(128,0,0);
|
||||
f->font.SetFamily(wxFONTFAMILY_TELETYPE);
|
||||
f->font.SetFaceName(_("Courier New"));
|
||||
}
|
||||
if (placeholder_color) {
|
||||
f->color = f->separator_color;
|
||||
f->shadow_displacement = RealSize(0,0); // no shadow
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@ class Font {
|
||||
inline bool hasShadow() { return shadow_displacement.width != 0 || shadow_displacement.height != 0; }
|
||||
|
||||
/// Make a bold/italic/placeholder version of this font
|
||||
FontP make(bool bold, bool italic, bool placeholder_color, Color* other_color) const;
|
||||
FontP make(bool bold, bool italic, bool placeholder_color, bool code_color, Color* other_color) const;
|
||||
|
||||
private:
|
||||
DECLARE_REFLECTION();
|
||||
|
||||
@@ -40,6 +40,8 @@ class KeywordParam {
|
||||
/// Information on when and how to use a keyword
|
||||
class KeywordMode {
|
||||
public:
|
||||
KeywordMode() : is_default(false) {}
|
||||
|
||||
String name; ///< Name of the mode
|
||||
String description; ///< Description of the type
|
||||
bool is_default; ///< This is the default mode for new keywords
|
||||
|
||||
Reference in New Issue
Block a user