Commit fe606b03 authored by twanvl's avatar twanvl

Fixed Actions for TextCtrl, actions used to apply to the wrong value.

Changed some TABs to spaces in macros, that should end the conflicts because we use different tab sizes (4 vs 8)
parent b787142d
......@@ -35,6 +35,7 @@ class SimpleValueAction : public ValueAction {
virtual void perform(bool to_undo) {
swap(static_cast<T&>(*valueP).*member, new_value);
valueP->onAction(*this, to_undo); // notify value
}
virtual bool merge(const Action& action) {
......@@ -54,9 +55,9 @@ class SimpleValueAction : public ValueAction {
typename T::ValueType T::*member;
};
ValueAction* value_action(const ChoiceValueP& value, const Defaultable<String>& new_value) { return new SimpleValueAction<ChoiceValue, true> (value, new_value, &ChoiceValue::value); }
ValueAction* value_action(const ChoiceValueP& value, const Defaultable<String>& new_value) { return new SimpleValueAction<ChoiceValue, true> (value, new_value, &ChoiceValue::value); }
ValueAction* value_action(const MultipleChoiceValueP& value, const Defaultable<String>& new_value) { return new SimpleValueAction<MultipleChoiceValue, false>(value, new_value, &MultipleChoiceValue::value); }
ValueAction* value_action(const ColorValueP& value, const Defaultable<Color>& new_value) { return new SimpleValueAction<ColorValue, true> (value, new_value, &ColorValue::value); }
ValueAction* value_action(const ColorValueP& value, const Defaultable<Color>& new_value) { return new SimpleValueAction<ColorValue, true> (value, new_value, &ColorValue::value); }
ValueAction* value_action(const ImageValueP& value, const FileName& new_value) { return new SimpleValueAction<ImageValue, false>(value, new_value, &ImageValue::filename); }
ValueAction* value_action(const SymbolValueP& value, const FileName& new_value) { return new SimpleValueAction<SymbolValue, false>(value, new_value, &SymbolValue::filename); }
......@@ -76,6 +77,7 @@ void TextValueAction::perform(bool to_undo) {
swap(value().value, new_value);
value().last_update.update();
swap(selection_end, new_selection_end);
valueP->onAction(*this, to_undo); // notify value
}
bool TextValueAction::merge(const Action& action) {
......
......@@ -127,10 +127,13 @@ Value::~Value() {}
IMPLEMENT_REFLECTION_NAMELESS(Value) {
}
bool Value::equals(const Value* that) {
return this == that;
}
void init_object(const FieldP& field, ValueP& value) {
if (!value) value = field->newValue(field);
}
template <> ValueP read_new<Value>(Reader&) {
throw InternalError(_("IndexMap contains nullptr ValueP the application should have crashed already"));
}
......@@ -21,6 +21,7 @@ DECLARE_POINTER_TYPE(Style);
DECLARE_POINTER_TYPE(Value);
class Context;
class Dependency;
class Action;
// for DataViewer/editor
class DataViewer; class DataEditor;
......@@ -134,6 +135,14 @@ class Value {
virtual String toString() const = 0;
/// Apply scripts to this value, return true if the value has changed
virtual bool update(Context&) { last_script_update.update(); return false; }
/// This value has been updated by an action
/** Does nothing for most Values, only FakeValues can update underlying data */
virtual void onAction(Action& a, bool undone) {}
/// Is this value the same as some other value (for the same field&card)
/** Has behaviour other than == for FakeTextValue.
* In that case, afterwards this becomes equal to that if they use the same underlying object.
*/
virtual bool equals(const Value* that);
private:
DECLARE_REFLECTION_VIRTUAL();
......
......@@ -105,3 +105,18 @@ bool TextValue::update(Context& ctx) {
IMPLEMENT_REFLECTION_NAMELESS(TextValue) {
if (fieldP->save_value || tag.scripting()) REFLECT_NAMELESS(value);
}
// ----------------------------------------------------------------------------- : FakeTextValue
void FakeTextValue::onAction(Action& a, bool undone) {
*underlying = value;
}
bool FakeTextValue::equals(const Value* that) {
if (this == that) return true;
const FakeTextValue* thatT = dynamic_cast<const FakeTextValue*>(that);
if (!thatT || underlying != thatT->underlying) return false;
// update the value
value = *underlying;
return true;
}
......@@ -98,5 +98,22 @@ class TextValue : public Value {
DECLARE_REFLECTION();
};
// ----------------------------------------------------------------------------- : TextValue
/// A 'fake' TextValue that is used to edit some other string
/** Used by TextCtrl */
class FakeTextValue : public TextValue {
public:
inline FakeTextValue(const TextFieldP& field, String* underlying)
: TextValue(field), underlying(underlying) {}
String* const underlying; ///< The underlying actual value
/// Update underlying data
virtual void onAction(Action& a, bool undone);
/// Editing the same underlying value?
virtual bool equals(const Value* that);
};
// ----------------------------------------------------------------------------- : EOF
#endif
......@@ -34,21 +34,21 @@ class Game : public Packaged {
public:
Game();
OptionalScript init_script; ///< Script of variables available to other scripts in this game
vector<FieldP> set_fields; ///< Fields for set information
IndexMap<FieldP,StyleP> default_set_style; ///< Default style for the set fields, because it is often the same
vector<FieldP> card_fields; ///< Fields on each card
vector<StatsDimensionP> statistics_dimensions; ///< (Additional) statistics dimensions
vector<StatsCategoryP> statistics_categories; ///< (Additional) statistics categories
OptionalScript init_script; ///< Script of variables available to other scripts in this game
vector<FieldP> set_fields; ///< Fields for set information
IndexMap<FieldP,StyleP> default_set_style; ///< Default style for the set fields, because it is often the same
vector<FieldP> card_fields; ///< Fields on each card
vector<StatsDimensionP> statistics_dimensions; ///< (Additional) statistics dimensions
vector<StatsCategoryP> statistics_categories; ///< (Additional) statistics categories
bool has_keywords; ///< Does this game use keywords?
vector<KeywordParamP> keyword_parameter_types;///< Types of keyword parameters
vector<KeywordModeP> keyword_modes; ///< Modes of keywords
vector<KeywordP> keywords; ///< Keywords for use in text
Dependencies dependent_scripts_cards; ///< scripts that depend on the card list
Dependencies dependent_scripts_keywords; ///< scripts that depend on the keywords
bool dependencies_initialized; ///< are the script dependencies comming from this game all initialized?
vector<KeywordP> keywords; ///< Keywords for use in text
Dependencies dependent_scripts_cards; ///< scripts that depend on the card list
Dependencies dependent_scripts_keywords; ///< scripts that depend on the keywords
bool dependencies_initialized; ///< are the script dependencies comming from this game all initialized?
/// Loads the game with a particular name, for example "magic"
static GameP byName(const String& name);
......
......@@ -59,6 +59,7 @@ class Keyword {
* captures 2,4,... capture the parameters
*/
wxRegEx matchRe;
bool fixed; ///< Is this keyword uneditable? (true for game keywods, false for set keywords)
/// Prepare the expansion: (re)generate matchRe and the list of parameters.
/** Throws when there is an error in the input
......
......@@ -119,7 +119,7 @@ Bitmap SymbolInFont::getBitmap(Context& ctx, Package& pkg, double size) {
actual_size = wxSize(img.GetWidth(), img.GetHeight());
// scale to match expected size
Image resampled_image((int) (actual_size.GetWidth() * size / img_size),
(int) (actual_size.GetHeight() * size / img_size), false);
(int) (actual_size.GetHeight() * size / img_size), false);
if (!resampled_image.Ok()) return Bitmap(1,1);
resample(img, resampled_image);
// convert to bitmap, store for later use
......
......@@ -10,6 +10,8 @@
#include <data/set.hpp>
#include <data/game.hpp>
#include <data/keyword.hpp>
#include <util/tagged_string.hpp>
#include <gfx/gfx.hpp>
DECLARE_TYPEOF_COLLECTION(KeywordP);
......@@ -23,7 +25,7 @@ KeywordList::KeywordList(Window* parent, int id, long additional_style)
: ItemList(parent, id, additional_style)
{
// Add columns
InsertColumn(0, _LABEL_("keyword"), wxLIST_FORMAT_LEFT, 100);
InsertColumn(0, _LABEL_("keyword"), wxLIST_FORMAT_LEFT, 0);
InsertColumn(1, _LABEL_("match"), wxLIST_FORMAT_LEFT, 200);
InsertColumn(2, _LABEL_("mode"), wxLIST_FORMAT_LEFT, 100);
InsertColumn(3, _LABEL_("uses"), wxLIST_FORMAT_RIGHT, 80);
......@@ -51,11 +53,21 @@ void KeywordList::onAction(const Action& action, bool undone) {
// ----------------------------------------------------------------------------- : KeywordListBase : for ItemList
String match_string(const Keyword& a) {
return untag(replace_all(replace_all(
a.match,
_("<param>"), _("")),
_("</param>"), _(""))
);
}
void KeywordList::getItems(vector<VoidP>& out) const {
FOR_EACH(k, set->keywords) {
k->fixed = false;
out.push_back(k);
}
FOR_EACH(k, set->game->keywords) {
k->fixed = true;
out.push_back(k);
}
}
......@@ -83,7 +95,7 @@ String KeywordList::OnGetItemText (long pos, long col) const {
const Keyword& kw = *getKeyword(pos);
switch(col) {
case 0: return kw.keyword;
case 1: return kw.match;
case 1: return match_string(kw);
case 2: return kw.mode;
case 3: return _("TODO");
case 4: return _("TODO");
......@@ -93,3 +105,11 @@ String KeywordList::OnGetItemText (long pos, long col) const {
int KeywordList::OnGetItemImage(long pos) const {
return -1;
}
wxListItemAttr* KeywordList::OnGetItemAttr(long pos) const {
// black for set keywords, grey for game keywords (uneditable)
const Keyword& kw = *getKeyword(pos);
if (!kw.fixed) return nullptr;
item_attr.SetTextColour(lerp(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW),wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT),0.5));
return &item_attr;
}
......@@ -68,9 +68,13 @@ class KeywordList : public ItemList, public SetView {
/// Get the image of an item, by default no image is used
/** Overrides a function from wxListCtrl */
virtual int OnGetItemImage(long pos) const;
/// Get the color for an item
virtual wxListItemAttr* OnGetItemAttr(long pos) const;
private:
void storeColumns();
mutable wxListItemAttr item_attr; // for OnGetItemAttr
};
// ----------------------------------------------------------------------------- : EOF
......
......@@ -37,7 +37,7 @@ void TextCtrl::setValue(String* value) {
// create a field, style and value
TextFieldP field(new TextField);
TextStyleP style(new TextStyle(field));
TextValueP value(new TextValue(field));
TextValueP value(new FakeTextValue(field, this->value));
// set stuff
field->index = 0;
field->multi_line = true;
......@@ -57,6 +57,11 @@ void TextCtrl::setValue(String* value) {
viewers.front()->getEditor()->determineSize(true);
// We don't wan to change the window size
//SetMinSize(RealSize(style->width + 6, style->height + 6));
} else if (value) {
// create a new value, for a different underlying actual value
ValueViewer& viewer = *viewers.front();
TextValueP new_value(new FakeTextValue(static_pointer_cast<TextField>(viewer.getField()), this->value));
viewer.setValue(new_value);
}
valueChanged();
}
......@@ -70,13 +75,15 @@ void TextCtrl::valueChanged() {
}
void TextCtrl::onAction(const Action& action, bool undone) {
DataEditor::onAction(action, undone);
/*
TYPE_CASE(action, TextValueAction) {
TextValue& tv = static_cast<TextValue&>(*viewers.front()->getValue());
if (&tv == action.valueP.get()) {
FakeTextValue& tv = static_cast<FakeTextValue&>(*viewers.front()->getValue());
if (tv.equals(action.valueP.get())) {
// the value has changed
if (value) *value = tv.value();
}
}
*/
}
void TextCtrl::onChangeSet() {
DataEditor::onChangeSet();
......
......@@ -8,8 +8,10 @@
#include <gui/set/keywords_panel.hpp>
#include <gui/control/keyword_list.hpp>
#include <gui/control/text_ctrl.hpp>
#include <data/keyword.hpp>
#include <wx/listctrl.h>
#include <wx/splitter.h>
// ----------------------------------------------------------------------------- : KeywordsPanel
......@@ -17,18 +19,44 @@ KeywordsPanel::KeywordsPanel(Window* parent, int id)
: SetWindowPanel(parent, id)
{
// init controls
list = new KeywordList(this, wxID_ANY);
Panel* panel;
splitter = new wxSplitterWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0);
list = new KeywordList(splitter, wxID_ANY);
panel = new Panel(splitter, wxID_ANY);
keyword = new TextCtrl(panel, wxID_ANY);
match = new TextCtrl(panel, wxID_ANY);
reminder = new TextCtrl(panel, wxID_ANY);
rules = new TextCtrl(panel, wxID_ANY);
// init sizer for panel
wxSizer* sp = new wxBoxSizer(wxVERTICAL);
sp->Add(new wxStaticText(panel, wxID_ANY, _("Keyword:")), 0, wxALL, 6);
sp->Add(keyword, 0, wxEXPAND | wxALL & ~wxTOP, 6);
wxSizer* s2 = new wxStaticBoxSizer(wxVERTICAL, panel, _("Match"));
s2->Add(new wxStaticText(panel, wxID_ANY, _("Keyword format:")), 0, wxALL, 6);
s2->Add(match, 0, wxEXPAND | wxALL & ~wxTOP, 6);
s2->Add(new wxStaticText(panel, wxID_ANY, _("Parameters:")), 0, wxALL, 6);
sp->Add(s2, 0, wxEXPAND | wxALL, 6);
sp->Add(new wxStaticText(panel, wxID_ANY, _("Reminder:")), 0, wxALL, 6);
sp->Add(reminder, 0, wxEXPAND | wxALL & ~wxTOP, 6);
sp->Add(new wxStaticText(panel, wxID_ANY, _("Rules:")), 0, wxALL, 6);
sp->Add(rules, 0, wxEXPAND | wxALL & ~wxTOP, 6);
panel->SetSizer(sp);
// init splitter
splitter->SetMinimumPaneSize(100);
splitter->SetSashGravity(0.5);
splitter->SplitVertically(list, panel, -200);
// init sizer
wxSizer* s = new wxBoxSizer(wxHORIZONTAL);
s->Add(list, 1, wxEXPAND);
s->Add(splitter, 1, wxEXPAND);
s->SetSizeHints(this);
SetSizer(s);
//s->Add(new wxStaticText(this, wxID_ANY, _("Sorry, no keywords for now"),wxDefaultPosition,wxDefaultSize,wxALIGN_CENTER), 1, wxALIGN_CENTER); // TODO: Remove
/* wxSizer* s2 = new wxBoxSizer(wxVERTICAL);
s2->Add(list_active, 1, wxEXPAND);
s2->Add(list_inactive, 1, wxEXPAND);*/
s->SetSizeHints(this);
SetSizer(s);
}
void KeywordsPanel::onChangeSet() {
list->setSet(set);
}
\ No newline at end of file
}
......@@ -12,6 +12,7 @@
#include <util/prec.hpp>
#include <gui/set/panel.hpp>
class wxSplitterWindow;
class KeywordList;
class TextCtrl;
......@@ -25,8 +26,13 @@ class KeywordsPanel : public SetWindowPanel {
virtual void onChangeSet();
private:
KeywordList* list;
TextCtrl* keyword;
// --------------------------------------------------- : Controls
wxSplitterWindow* splitter;
KeywordList* list;
TextCtrl* keyword;
TextCtrl* match;
TextCtrl* reminder;
TextCtrl* rules;
};
// ----------------------------------------------------------------------------- : EOF
......
......@@ -125,7 +125,7 @@ void DataViewer::onAction(const Action& action, bool undone) {
}
TYPE_CASE(action, ValueAction) {
FOR_EACH(v, viewers) {
if (v->getValue() == action.valueP) {
if (v->getValue()->equals( action.valueP.get() )) {
// refresh the viewer
v->onAction(action, undone);
onChange();
......
......@@ -79,16 +79,16 @@ class ValueViewer {
// ----------------------------------------------------------------------------- : Utility
#define DECLARE_VALUE_VIEWER(Type) \
protected: \
inline Type##Style& style() const { return static_cast< Type##Style&>(*ValueViewer::styleP); } \
inline const Type##Value& value() const { return static_cast<const Type##Value&>(*ValueViewer::valueP); } \
inline const Type##Field& field() const { return style().field(); } \
inline Type##StyleP styleP() const { return static_pointer_cast<Type##Style>(ValueViewer::styleP); } \
inline Type##ValueP valueP() const { return static_pointer_cast<Type##Value>(ValueViewer::valueP); } \
inline Type##FieldP fieldP() const { return static_pointer_cast<Type##Field>(style().fieldP); } \
public: \
Type##ValueViewer(DataViewer& parent, const Type ## StyleP& style)
#define DECLARE_VALUE_VIEWER(Type) \
protected: \
inline Type##Style& style() const { return static_cast< Type##Style&>(*ValueViewer::styleP); } \
inline const Type##Value& value() const { return static_cast<const Type##Value&>(*ValueViewer::valueP); } \
inline const Type##Field& field() const { return style().field(); } \
inline Type##StyleP styleP() const { return static_pointer_cast<Type##Style>(ValueViewer::styleP); } \
inline Type##ValueP valueP() const { return static_pointer_cast<Type##Value>(ValueViewer::valueP); } \
inline Type##FieldP fieldP() const { return static_pointer_cast<Type##Field>(style().fieldP); } \
public: \
Type##ValueViewer(DataViewer& parent, const Type ## StyleP& style)
// ----------------------------------------------------------------------------- : EOF
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment