diff --git a/src/data/action/set.cpp b/src/data/action/set.cpp index 1f91ea8c..ef2c4d84 100644 --- a/src/data/action/set.cpp +++ b/src/data/action/set.cpp @@ -12,6 +12,8 @@ #include #include +DECLARE_TYPEOF_COLLECTION(IndexMap); + // ----------------------------------------------------------------------------- : Add card AddCardAction::AddCardAction(Set& set) @@ -91,13 +93,15 @@ void DisplayChangeAction::perform(bool to_undo) { ChangeCardStyleAction::ChangeCardStyleAction(const CardP& card, const StyleSheetP& stylesheet) - : card(card), stylesheet(stylesheet) + : card(card), stylesheet(stylesheet), has_styling(false) // styling_data(empty) {} String ChangeCardStyleAction::getName(bool to_undo) const { return _("Change style"); } void ChangeCardStyleAction::perform(bool to_undo) { - swap(card->stylesheet, stylesheet); + swap(card->stylesheet, stylesheet); + swap(card->has_styling, has_styling); + swap(card->styling_data, styling_data); } @@ -117,3 +121,21 @@ void ChangeSetStyleAction::perform(bool to_undo) { set.stylesheet = stylesheet; } } + +ChangeCardHasStylingAction::ChangeCardHasStylingAction(Set& set, const CardP& 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 + } +} +String ChangeCardHasStylingAction::getName(bool to_undo) const { + return _("Use custom style"); +} +void ChangeCardHasStylingAction::perform(bool to_undo) { + card->has_styling = !card->has_styling; + swap(card->styling_data, styling_data); +} diff --git a/src/data/action/set.hpp b/src/data/action/set.hpp index 2811655e..85fc05fc 100644 --- a/src/data/action/set.hpp +++ b/src/data/action/set.hpp @@ -20,6 +20,8 @@ class Set; DECLARE_POINTER_TYPE(Card); DECLARE_POINTER_TYPE(StyleSheet); +DECLARE_POINTER_TYPE(Field); +DECLARE_POINTER_TYPE(Value); // ----------------------------------------------------------------------------- : Add card @@ -93,8 +95,10 @@ class ChangeCardStyleAction : public DisplayChangeAction { virtual void perform(bool to_undo); //private: - CardP card; ///< The affected card - StyleSheetP stylesheet; ///< Its new stylesheet + CardP card; ///< The affected card + StyleSheetP stylesheet; ///< Its old stylesheet + bool has_styling; ///< Its old has_styling + IndexMap styling_data; ///< Its old styling data }; /// Changing the style of a set to that of a card @@ -111,5 +115,20 @@ class ChangeSetStyleAction : public DisplayChangeAction { StyleSheetP stylesheet; ///< The old stylesheet of the set }; +/// 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); + + //private: + Set& set; ///< The set to copy styling from + CardP card; ///< The affected card + IndexMap styling_data; ///< The old styling of the card +}; + // ----------------------------------------------------------------------------- : EOF #endif diff --git a/src/data/card.cpp b/src/data/card.cpp index 331fb717..e2ac23c0 100644 --- a/src/data/card.cpp +++ b/src/data/card.cpp @@ -19,14 +19,18 @@ DECLARE_TYPEOF_NO_REV(IndexMap); // ----------------------------------------------------------------------------- : Card -Card::Card() { +Card::Card() + : has_styling(false) +{ if (!game_for_reading()) { throw InternalError(_("game_for_reading not set")); } data.init(game_for_reading()->card_fields); } -Card::Card(const Game& game) { +Card::Card(const Game& game) + : has_styling(false) +{ data.init(game.card_fields); } @@ -55,6 +59,16 @@ void mark_dependency_member(const Card& card, const String& name, const Dependen IMPLEMENT_REFLECTION(Card) { REFLECT(stylesheet); + REFLECT(has_styling); + if (has_styling) { + if (stylesheet) { + REFLECT_IF_READING styling_data.init(stylesheet->styling_fields); + REFLECT(styling_data); + } else if (stylesheet_for_reading()) { + REFLECT_IF_READING styling_data.init(stylesheet_for_reading()->styling_fields); + REFLECT(styling_data); + } + } REFLECT(notes); REFLECT_NO_SCRIPT(extra_data); // don't allow scripts to depend on style specific data REFLECT_NAMELESS(data); diff --git a/src/data/card.hpp b/src/data/card.hpp index 6dd207fe..047b44f5 100644 --- a/src/data/card.hpp +++ b/src/data/card.hpp @@ -39,6 +39,11 @@ class Card : public IntrusivePtrVirtualBase { /// Alternative style to use for this card /** Optional; if not set use the card style from the set */ StyleSheetP stylesheet; + /// Alternative options to use for this card, for this card's stylesheet + /** Optional; if not set use the styling data from the set */ + IndexMap styling_data; + /// Is the styling_data set? + bool has_styling; /// Extra values for specitic stylesheets, indexed by stylesheet name DelayedIndexMaps extra_data; diff --git a/src/data/field.hpp b/src/data/field.hpp index 36c38354..8a7c5211 100644 --- a/src/data/field.hpp +++ b/src/data/field.hpp @@ -172,6 +172,9 @@ class Value : public IntrusivePtrVirtualBase { const FieldP fieldP; ///< Field this value is for, should have the right type! Age last_script_update; ///< When where the scripts last updated? (by calling update) + /// Get a copy of this value + virtual ValueP clone() const = 0; + /// Convert this value to a string for use in tables virtual String toString() const = 0; /// Apply scripts to this value, return true if the value has changed @@ -213,6 +216,9 @@ template <> ValueP read_new(Reader&); } \ StyleP Type ## Style::clone() const { \ return new_intrusive1(*this); \ + } \ + ValueP Type ## Value::clone() const { \ + return new_intrusive1(*this); \ } #define DECLARE_STYLE_TYPE(Type) \ diff --git a/src/data/field/boolean.hpp b/src/data/field/boolean.hpp index adb3a0a3..7f83bd54 100644 --- a/src/data/field/boolean.hpp +++ b/src/data/field/boolean.hpp @@ -52,6 +52,7 @@ class BooleanValue : public ChoiceValue { public: inline BooleanValue(const ChoiceFieldP& field) : ChoiceValue(field) {} DECLARE_HAS_FIELD(Boolean); + virtual ValueP clone() const; // no extra data diff --git a/src/data/field/choice.hpp b/src/data/field/choice.hpp index 07d580b4..b5ace5b2 100644 --- a/src/data/field/choice.hpp +++ b/src/data/field/choice.hpp @@ -177,6 +177,7 @@ class ChoiceValue : public Value { typedef Defaultable ValueType; ValueType value; /// The name of the selected choice + virtual ValueP clone() const; virtual String toString() const; virtual bool update(Context&); diff --git a/src/data/field/color.hpp b/src/data/field/color.hpp index 407761c3..3816b0db 100644 --- a/src/data/field/color.hpp +++ b/src/data/field/color.hpp @@ -83,6 +83,7 @@ class ColorValue : public Value { typedef Defaultable ValueType; ValueType value; ///< The value + virtual ValueP clone() const; virtual String toString() const; virtual bool update(Context&); diff --git a/src/data/field/image.hpp b/src/data/field/image.hpp index 6f17f38d..dcbe3616 100644 --- a/src/data/field/image.hpp +++ b/src/data/field/image.hpp @@ -58,6 +58,7 @@ class ImageValue : public Value { ValueType filename; ///< Filename of the image (in the current package), or "" Age last_update; ///< When was the image last changed? + virtual ValueP clone() const; virtual String toString() const; private: diff --git a/src/data/field/information.hpp b/src/data/field/information.hpp index 410e412d..0f91e53a 100644 --- a/src/data/field/information.hpp +++ b/src/data/field/information.hpp @@ -68,6 +68,7 @@ class InfoValue : public Value { String value; + virtual ValueP clone() const; virtual String toString() const; virtual bool update(Context&); diff --git a/src/data/field/multiple_choice.hpp b/src/data/field/multiple_choice.hpp index fc8952f9..cf0042ee 100644 --- a/src/data/field/multiple_choice.hpp +++ b/src/data/field/multiple_choice.hpp @@ -56,6 +56,7 @@ class MultipleChoiceValue : public ChoiceValue { public: inline MultipleChoiceValue(const MultipleChoiceFieldP& field) : ChoiceValue(field, false) {} DECLARE_HAS_FIELD(MultipleChoice); + virtual ValueP clone() const; String last_change; ///< Which of the choices was selected/deselected last? diff --git a/src/data/field/symbol.hpp b/src/data/field/symbol.hpp index 94d1becc..370e4dd2 100644 --- a/src/data/field/symbol.hpp +++ b/src/data/field/symbol.hpp @@ -69,6 +69,7 @@ class SymbolValue : public Value { ValueType filename; ///< Filename of the symbol (in the current package) Age last_update; ///< When was the symbol last changed? + virtual ValueP clone() const; virtual String toString() const; private: diff --git a/src/data/field/text.hpp b/src/data/field/text.hpp index 37b4caf4..d8446779 100644 --- a/src/data/field/text.hpp +++ b/src/data/field/text.hpp @@ -110,6 +110,7 @@ class TextValue : public Value { ValueType value; ///< The text of this value Age last_update; ///< When was the text last changed? + virtual ValueP clone() const; virtual String toString() const; virtual bool update(Context&); diff --git a/src/data/set.cpp b/src/data/set.cpp index bba4d11e..2d7c99e7 100644 --- a/src/data/set.cpp +++ b/src/data/set.cpp @@ -91,6 +91,14 @@ StyleSheetP Set::stylesheetForP(const CardP& card) { else return stylesheet; } +IndexMap& Set::stylingDataFor(const StyleSheet& stylesheet) { + return styling_data.get(stylesheet.name(), stylesheet.styling_fields); +} +IndexMap& Set::stylingDataFor(const CardP& card) { + if (card && card->has_styling) return card->styling_data; + else return stylingDataFor(stylesheetFor(card)); +} + String Set::typeName() const { return _("set"); } // fix values for versions < 0.2.7 @@ -144,6 +152,7 @@ IMPLEMENT_REFLECTION(Set) { } WITH_DYNAMIC_ARG(game_for_reading, game.get()); REFLECT(stylesheet); + WITH_DYNAMIC_ARG(stylesheet_for_reading, stylesheet.get()); REFLECT_N("set_info", data); if (stylesheet) { REFLECT_N("styling", styling_data); @@ -202,12 +211,6 @@ void Set::clearOrderCache() { order_cache.clear(); } -// ----------------------------------------------------------------------------- : Styling - -IndexMap& Set::stylingDataFor(const StyleSheet& stylesheet) { - return styling_data.get(stylesheet.name(), stylesheet.styling_fields); -} - // ----------------------------------------------------------------------------- : SetView SetView::SetView() {} diff --git a/src/data/set.hpp b/src/data/set.hpp index 3d014c1f..7ba794ff 100644 --- a/src/data/set.hpp +++ b/src/data/set.hpp @@ -86,6 +86,8 @@ class Set : public Packaged { /// Styling information for a particular stylesheet IndexMap& stylingDataFor(const StyleSheet&); + /// Styling information for a particular card + IndexMap& stylingDataFor(const CardP& card); /// Find a value in the data by name and type template T& value(const String& name) { diff --git a/src/data/stylesheet.cpp b/src/data/stylesheet.cpp index cc067c29..adc28c39 100644 --- a/src/data/stylesheet.cpp +++ b/src/data/stylesheet.cpp @@ -16,6 +16,8 @@ DECLARE_TYPEOF_COLLECTION(FieldP); // ----------------------------------------------------------------------------- : StyleSheet +IMPLEMENT_DYNAMIC_ARG(StyleSheet*, stylesheet_for_reading, nullptr); + StyleSheet::StyleSheet() : card_width(100), card_height(100) , card_dpi(96), card_background(*wxWHITE) diff --git a/src/data/stylesheet.hpp b/src/data/stylesheet.hpp index b2b1f90c..2f9f75c8 100644 --- a/src/data/stylesheet.hpp +++ b/src/data/stylesheet.hpp @@ -21,6 +21,9 @@ DECLARE_POINTER_TYPE(Style); // ----------------------------------------------------------------------------- : StyleSheet +/// Stylesheet of the set that is currently being read/written +DECLARE_DYNAMIC_ARG(StyleSheet*, stylesheet_for_reading); + /// A collection of style information for card and set fields class StyleSheet : public Packaged { public: diff --git a/src/gui/control/native_look_editor.cpp b/src/gui/control/native_look_editor.cpp index a2f208f0..38b100db 100644 --- a/src/gui/control/native_look_editor.cpp +++ b/src/gui/control/native_look_editor.cpp @@ -197,6 +197,11 @@ void StylingEditor::showStylesheet(const StyleSheetP& stylesheet) { setStyles(stylesheet, stylesheet->styling_style); setData(set->stylingDataFor(*stylesheet)); } +void StylingEditor::showCard(const CardP& card) { + StyleSheetP stylesheet = set->stylesheetForP(card); + setStyles(stylesheet, stylesheet->styling_style); + setData(set->stylingDataFor(card)); +} void StylingEditor::onChangeSet() { showStylesheet(set->stylesheet); diff --git a/src/gui/control/native_look_editor.hpp b/src/gui/control/native_look_editor.hpp index 037938b8..4f002276 100644 --- a/src/gui/control/native_look_editor.hpp +++ b/src/gui/control/native_look_editor.hpp @@ -68,8 +68,10 @@ class StylingEditor : public NativeLookEditor { public: StylingEditor(Window* parent, int id, long style = 0); - /// Show the styling for given stylesheet in the editor + /// Show the styling for given stylesheet in the editor void showStylesheet(const StyleSheetP& stylesheet); + /// Show the styling for given card + void showCard(const CardP& card); protected: virtual void onChangeSet(); diff --git a/src/gui/set/style_panel.cpp b/src/gui/set/style_panel.cpp index 65def130..8d58f084 100644 --- a/src/gui/set/style_panel.cpp +++ b/src/gui/set/style_panel.cpp @@ -23,10 +23,11 @@ StylePanel::StylePanel(Window* parent, int id) : SetWindowPanel(parent, id) { // init controls - preview = new CardViewer (this, wxID_ANY); - editor = new StylingEditor(this, wxID_ANY, wxNO_BORDER); - list = new PackageList (this, wxID_ANY); - use_for_all = new wxButton (this, ID_STYLE_USE_FOR_ALL, _BUTTON_("use for all cards")); + preview = new CardViewer (this, wxID_ANY); + editor = new StylingEditor(this, wxID_ANY, wxNO_BORDER); + list = new PackageList (this, wxID_ANY); + use_for_all = new wxButton (this, ID_STYLE_USE_FOR_ALL, _BUTTON_("use for all cards")); + use_custom_options = new wxCheckBox(this, ID_STYLE_USE_CUSTOM, _BUTTON_("use custom styling options")); // init sizer wxSizer* s = new wxBoxSizer(wxHORIZONTAL); s->Add(preview, 0, wxRIGHT, 2); @@ -34,7 +35,8 @@ StylePanel::StylePanel(Window* parent, int id) s2->Add(list, 0, wxEXPAND | wxBOTTOM, 4); s2->Add(use_for_all, 0, wxRIGHT | wxBOTTOM | wxALIGN_RIGHT, 4); wxSizer* s3 = new wxStaticBoxSizer(wxVERTICAL, this, _LABEL_("styling options")); - s3->Add(editor, 2, wxEXPAND, 0); + s3->Add(use_custom_options, 0, wxEXPAND, 0); + s3->Add(editor, 2, wxEXPAND, 0); s2->Add(s3, 1, wxEXPAND | wxALL, 2); s->Add(s2, 1, wxEXPAND, 8); s->SetSizeHints(this); @@ -53,15 +55,22 @@ void StylePanel::onChangeSet() { void StylePanel::onAction(const Action& action, bool undone) { TYPE_CASE_(action, ChangeSetStyleAction) { list->select(set->stylesheetFor(card).name(), false); - editor->showStylesheet(set->stylesheetForP(card)); + editor->showCard(card); } TYPE_CASE(action, ChangeCardStyleAction) { if (action.card == card) { list->select(set->stylesheetFor(card).name(), false); - editor->showStylesheet(set->stylesheetForP(card)); + editor->showCard(card); + } + } + TYPE_CASE(action, ChangeCardHasStylingAction) { + if (action.card == card) { + editor->showCard(card); } } use_for_all->Enable(card && card->stylesheet); + use_custom_options->Enable(card); + use_custom_options->SetValue(card->has_styling); } // ----------------------------------------------------------------------------- : Selection @@ -70,8 +79,11 @@ void StylePanel::selectCard(const CardP& card) { this->card = card; preview->setCard(card); editor->showStylesheet(set->stylesheetForP(card)); + editor->showCard(card); list->select(set->stylesheetFor(card).name(), false); use_for_all->Enable(card && card->stylesheet); + use_custom_options->Enable(card); + use_custom_options->SetValue(card->has_styling); } // ----------------------------------------------------------------------------- : Events @@ -93,7 +105,12 @@ void StylePanel::onUseForAll(wxCommandEvent&) { Layout(); } +void StylePanel::onUseCustom(wxCommandEvent&) { + set->actions.add(new ChangeCardHasStylingAction(*set, card)); +} + BEGIN_EVENT_TABLE(StylePanel, wxPanel) EVT_GALLERY_SELECT(wxID_ANY, StylePanel::onStyleSelect) EVT_BUTTON (ID_STYLE_USE_FOR_ALL, StylePanel::onUseForAll) + EVT_CHECKBOX (ID_STYLE_USE_CUSTOM, StylePanel::onUseCustom) END_EVENT_TABLE() diff --git a/src/gui/set/style_panel.hpp b/src/gui/set/style_panel.hpp index 8fc769a6..c0cc02fe 100644 --- a/src/gui/set/style_panel.hpp +++ b/src/gui/set/style_panel.hpp @@ -36,10 +36,12 @@ class StylePanel : public SetWindowPanel { PackageList* list; ///< List of stylesheets StylingEditor* editor; ///< Editor for styling information wxButton* use_for_all; + wxCheckBox* use_custom_options; CardP card; ///< Card we are working on void onStyleSelect(wxCommandEvent&); void onUseForAll(wxCommandEvent&); + void onUseCustom(wxCommandEvent&); }; // ----------------------------------------------------------------------------- : EOF diff --git a/src/script/script_manager.cpp b/src/script/script_manager.cpp index a8edfb15..742df548 100644 --- a/src/script/script_manager.cpp +++ b/src/script/script_manager.cpp @@ -72,11 +72,14 @@ Context& SetScriptContext::getContext(const StyleSheetP& stylesheet) { } } Context& SetScriptContext::getContext(const CardP& card) { - Context& ctx = getContext(set.stylesheetForP(card)); + StyleSheetP stylesheet = set.stylesheetForP(card); + Context& ctx = getContext(stylesheet); if (card) { ctx.setVariable(_("card"), to_script(card)); + ctx.setVariable(_("styling"), to_script(&set.stylingDataFor(card))); } else { ctx.setVariable(_("card"), ScriptValueP()); + ctx.setVariable(_("styling"), to_script(&set.stylingDataFor(*stylesheet))); } return ctx; } diff --git a/src/util/index_map.hpp b/src/util/index_map.hpp index 51b61429..7caa814a 100644 --- a/src/util/index_map.hpp +++ b/src/util/index_map.hpp @@ -114,10 +114,19 @@ class IndexMap : private vector { return end(); } + inline void swap(IndexMap& b) { + vector::swap(b); + } + private: using vector::operator []; }; +template +inline void swap(IndexMap& a, IndexMap& b) { + a.swap(b); +} + // ----------------------------------------------------------------------------- : DelayedIndexMaps diff --git a/src/util/locale.hpp b/src/util/locale.hpp index 7ccbe0db..6e8f2c84 100644 --- a/src/util/locale.hpp +++ b/src/util/locale.hpp @@ -92,6 +92,9 @@ String tr(const SymbolFont&, const String& key, const String& def); /// A localized string for tooltip text, with 1 argument (printf style) #define _TOOLTIP_1_(s,a) format_string(_TOOLTIP_(s), a) +/// A localized string for button text, with 1 argument (printf style) +#define _BUTTON_1_(s,a) format_string(_BUTTON_(s), a) + /// A localized string for error messages, with 1 argument (printf style) #define _ERROR_1_(s,a) format_string(_ERROR_(s), a) /// A localized string for error messages, with 2 argument (printf style) diff --git a/src/util/window_id.hpp b/src/util/window_id.hpp index 405ca3d6..847bf978 100644 --- a/src/util/window_id.hpp +++ b/src/util/window_id.hpp @@ -154,6 +154,7 @@ enum ChildMenuID { // Style panel , ID_STYLE_USE_FOR_ALL = 3011 +, ID_STYLE_USE_CUSTOM // Keywords panel , ID_KEYWORD_ADD_PARAM = 3021