mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-10 21:06:59 -04:00
Implement unique IDs and card linking
This commit is contained in:
+83
-2
@@ -13,6 +13,7 @@
|
||||
#include <data/pack.hpp>
|
||||
#include <data/stylesheet.hpp>
|
||||
#include <util/error.hpp>
|
||||
#include <util/uid.hpp>
|
||||
|
||||
// ----------------------------------------------------------------------------- : Add card
|
||||
|
||||
@@ -36,10 +37,53 @@ String AddCardAction::getName(bool to_undo) const {
|
||||
}
|
||||
|
||||
void AddCardAction::perform(bool to_undo) {
|
||||
// If we are adding cards, resolve any uid conflicts
|
||||
// (If we are re-adding cards, from a remove undo, there shouldn't be any uid conflicts)
|
||||
// We always assume uid conflicts occur because a card was copy-pasted into the same set,
|
||||
// and never because two different cards randomly got assigned the same uid
|
||||
if (action.adding && !to_undo) {
|
||||
// Tally existing unique ids
|
||||
unordered_map<String, CardP> all_existing_uids;
|
||||
FOR_EACH(card, set.cards) {
|
||||
all_existing_uids.insert({ card->uid, card });
|
||||
}
|
||||
// Tally added unique ids
|
||||
unordered_map<String, CardP> all_added_uids;
|
||||
for (size_t pos = 0; pos < action.steps.size(); ++pos) {
|
||||
CardP card = action.steps[pos].item;
|
||||
all_added_uids.insert({ card->uid, card });
|
||||
}
|
||||
FOR_EACH(added_pair, all_added_uids) {
|
||||
String old_uid = added_pair.first;
|
||||
CardP added_card = added_pair.second;
|
||||
// Assign new unique ids
|
||||
if (all_existing_uids.find(old_uid) != all_existing_uids.end()) {
|
||||
String new_uid = generate_uid();
|
||||
added_card->uid = new_uid;
|
||||
all_added_uids.insert({ new_uid, added_card });
|
||||
// Update links on linked cards
|
||||
OTHER_LINKED_PAIRS(linked_pairs, added_card);
|
||||
FOR_EACH(linked_pair, linked_pairs) {
|
||||
String& linked_uid = linked_pair.first.get();
|
||||
String& linked_relation = linked_pair.second.get();
|
||||
if (linked_uid == wxEmptyString) continue;
|
||||
// If it's an added card, replace the link
|
||||
if (all_added_uids.find(linked_uid) != all_added_uids.end()) {
|
||||
all_added_uids.at(linked_uid)->updateLink(old_uid, new_uid);
|
||||
}
|
||||
// Otherwise, if it's an existing card, copy the link
|
||||
else if (all_existing_uids.find(linked_uid) != all_existing_uids.end()) {
|
||||
all_existing_uids.at(linked_uid)->copyLink(set, old_uid, new_uid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add or remove cards
|
||||
action.perform(set.cards, to_undo);
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------- : Reorder cards
|
||||
|
||||
ReorderCardsAction::ReorderCardsAction(Set& set, size_t card_id1, size_t card_id2)
|
||||
@@ -55,13 +99,50 @@ void ReorderCardsAction::perform(bool to_undo) {
|
||||
assert(card_id1 < set.cards.size());
|
||||
assert(card_id2 < set.cards.size());
|
||||
#endif
|
||||
if (card_id1 >= set.cards.size() || card_id2 < set.cards.size()) {
|
||||
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]);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Link cards
|
||||
|
||||
LinkCardsAction::LinkCardsAction(Set& set, const CardP& selected_card, vector<CardP>& linked_cards, const String& selected_relation, const String& linked_relation)
|
||||
: CardListAction(set), selected_card(selected_card), linked_cards(linked_cards), selected_relation(selected_relation), linked_relation(linked_relation)
|
||||
{}
|
||||
|
||||
String LinkCardsAction::getName(bool to_undo) const {
|
||||
return _("Link cards");
|
||||
}
|
||||
|
||||
void LinkCardsAction::perform(bool to_undo) {
|
||||
if (!to_undo) {
|
||||
selected_card->link(set, linked_cards, selected_relation, linked_relation);
|
||||
} else {
|
||||
selected_card->unlink(linked_cards);
|
||||
}
|
||||
}
|
||||
|
||||
UnlinkCardsAction::UnlinkCardsAction(Set& set, const CardP& selected_card, CardP& unlinked_card)
|
||||
: CardListAction(set), selected_card(selected_card), unlinked_card(unlinked_card)
|
||||
{}
|
||||
|
||||
String UnlinkCardsAction::getName(bool to_undo) const {
|
||||
return _("Unlink card");
|
||||
}
|
||||
|
||||
void UnlinkCardsAction::perform(bool to_undo) {
|
||||
if (!to_undo) {
|
||||
pair<String, String> relations = selected_card->unlink(unlinked_card);
|
||||
selected_relation = relations.first;
|
||||
unlinked_relation = relations.second;
|
||||
}
|
||||
else {
|
||||
selected_card->link(set, unlinked_card, selected_relation, unlinked_relation);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Change stylesheet
|
||||
|
||||
String DisplayChangeAction::getName(bool to_undo) const {
|
||||
|
||||
@@ -64,6 +64,37 @@ public:
|
||||
const size_t card_id1, card_id2; ///< Positions of the two cards to swap
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : Link cards
|
||||
|
||||
/// Add a link between two or more cards
|
||||
class LinkCardsAction : public CardListAction {
|
||||
public:
|
||||
LinkCardsAction(Set& set, const CardP& selected_card, vector<CardP>& linked_cards, const String& selected_relation, const String& linked_relation);
|
||||
|
||||
String getName(bool to_undo) const override;
|
||||
void perform(bool to_undo) override;
|
||||
|
||||
//private:
|
||||
CardP selected_card; ///< The card currently selected in the cards tab
|
||||
vector<CardP> linked_cards; ///< The cards that will be linked to the selected card
|
||||
String selected_relation; ///< The nature of the relation of the selected card
|
||||
String linked_relation; ///< The nature of the relation of the linked cards
|
||||
};
|
||||
/// Remove a link between two cards
|
||||
class UnlinkCardsAction : public CardListAction {
|
||||
public:
|
||||
UnlinkCardsAction(Set& set, const CardP& selected_card, CardP& unlinked_card);
|
||||
|
||||
String getName(bool to_undo) const override;
|
||||
void perform(bool to_undo) override;
|
||||
|
||||
//private:
|
||||
CardP selected_card; ///< The card currently selected in the cards tab
|
||||
CardP unlinked_card; ///< The card that will be unlinked from the selected card
|
||||
String selected_relation; ///< The nature of the relation of the selected card
|
||||
String unlinked_relation; ///< The nature of the relation of the unlinked card
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------- : Change stylesheet
|
||||
|
||||
/// An action that affects the rendering/display/look of a set or cards in the set
|
||||
|
||||
+231
-1
@@ -8,19 +8,23 @@
|
||||
|
||||
#include <util/prec.hpp>
|
||||
#include <data/card.hpp>
|
||||
#include <data/set.hpp>
|
||||
#include <data/game.hpp>
|
||||
#include <data/stylesheet.hpp>
|
||||
#include <data/field.hpp>
|
||||
#include <util/error.hpp>
|
||||
#include <util/reflect.hpp>
|
||||
#include <util/delayed_index_maps.hpp>
|
||||
#include <util/uid.hpp>
|
||||
#include <unordered_set>
|
||||
|
||||
// ----------------------------------------------------------------------------- : Card
|
||||
|
||||
Card::Card()
|
||||
// for files made before we saved these times, set the time to 'yesterday'
|
||||
// for files made before we saved these, set the time to 'yesterday', generate a uid
|
||||
: time_created (wxDateTime::Now().Subtract(wxDateSpan::Day()).ResetTime())
|
||||
, time_modified(wxDateTime::Now().Subtract(wxDateSpan::Day()).ResetTime())
|
||||
, uid(generate_uid())
|
||||
, has_styling(false)
|
||||
{
|
||||
if (!game_for_reading()) {
|
||||
@@ -32,6 +36,7 @@ Card::Card()
|
||||
Card::Card(const Game& game)
|
||||
: time_created (wxDateTime::Now())
|
||||
, time_modified(wxDateTime::Now())
|
||||
, uid(generate_uid())
|
||||
, has_styling(false)
|
||||
{
|
||||
data.init(game.card_fields);
|
||||
@@ -60,6 +65,222 @@ bool Card::contains(QuickFilterPart const& query) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void Card::link(const Set& set, const vector<CardP>& linked_cards, const String& selected_relation, const String& linked_relation)
|
||||
{
|
||||
unlink(linked_cards);
|
||||
|
||||
unordered_set<String> all_existing_uids;
|
||||
FOR_EACH(card, set.cards) {
|
||||
all_existing_uids.insert(card->uid);
|
||||
}
|
||||
int free_link_count = 0;
|
||||
THIS_LINKED_PAIRS(this_linked_pairs);
|
||||
FOR_EACH(this_linked_pair, this_linked_pairs) {
|
||||
String& this_linked_uid = this_linked_pair.first.get();
|
||||
if (
|
||||
this_linked_uid == wxEmptyString || // Not a reference
|
||||
all_existing_uids.find(this_linked_uid) == all_existing_uids.end() // Reference to nonexistent card
|
||||
) free_link_count++;
|
||||
}
|
||||
if (free_link_count < linked_cards.size()) {
|
||||
queue_message(MESSAGE_WARNING, _ERROR_("not enough free links"));
|
||||
return;
|
||||
}
|
||||
|
||||
vector<CardP> all_missed_cards;
|
||||
FOR_EACH(linked_card, linked_cards) {
|
||||
bool written = false;
|
||||
// Try to write to a free spot
|
||||
FOR_EACH(this_linked_pair, this_linked_pairs) {
|
||||
String& this_linked_uid = this_linked_pair.first.get();
|
||||
String& this_linked_relation = this_linked_pair.second.get();
|
||||
if (this_linked_uid == wxEmptyString) {
|
||||
this_linked_uid = linked_card->uid;
|
||||
this_linked_relation = linked_relation;
|
||||
written = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Try to write to an erasable spot
|
||||
if (!written) {
|
||||
FOR_EACH(this_linked_pair, this_linked_pairs) {
|
||||
String& this_linked_uid = this_linked_pair.first.get();
|
||||
String& this_linked_relation = this_linked_pair.second.get();
|
||||
if (all_existing_uids.find(this_linked_uid) == all_existing_uids.end()) {
|
||||
this_linked_uid = linked_card->uid;
|
||||
this_linked_relation = linked_relation;
|
||||
written = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!written) {
|
||||
// Should be impossible to end up here?
|
||||
}
|
||||
|
||||
OTHER_LINKED_PAIRS(linked_pairs, linked_card);
|
||||
written = false;
|
||||
// Try to write to a free spot
|
||||
FOR_EACH(linked_pair, linked_pairs) {
|
||||
String& linked_uid = linked_pair.first.get();
|
||||
String& linked_relation = linked_pair.second.get();
|
||||
if (linked_uid == wxEmptyString) {
|
||||
linked_uid = uid;
|
||||
linked_relation = selected_relation;
|
||||
written = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Try to write to an erasable spot
|
||||
if (!written) {
|
||||
FOR_EACH(linked_pair, linked_pairs) {
|
||||
String& linked_uid = linked_pair.first.get();
|
||||
String& linked_relation = linked_pair.second.get();
|
||||
if (all_existing_uids.find(linked_uid) == all_existing_uids.end()) {
|
||||
linked_uid = uid;
|
||||
linked_relation = selected_relation;
|
||||
written = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Notify we couldn't write
|
||||
if (!written) {
|
||||
all_missed_cards.push_back(linked_card);
|
||||
}
|
||||
}
|
||||
if (all_missed_cards.size() > 0) {
|
||||
std::stringstream ss;
|
||||
ss << _ERROR_("could not link");
|
||||
for (size_t pos = 0; pos < all_missed_cards.size(); ++pos) {
|
||||
ss << all_missed_cards[pos]->identification();
|
||||
if (pos < all_missed_cards.size() - 1) ss << ", ";
|
||||
};
|
||||
String wxString(ss.str().c_str(), wxConvUTF8);
|
||||
queue_message(MESSAGE_WARNING, wxString);
|
||||
}
|
||||
}
|
||||
|
||||
void Card::link(const Set& set, CardP& linked_card, const String& selected_relation, const String& linked_relation)
|
||||
{
|
||||
vector<CardP> linked_cards { linked_card };
|
||||
link(set, linked_cards, selected_relation, linked_relation);
|
||||
}
|
||||
|
||||
void Card::unlink(const vector<CardP>& unlinked_cards)
|
||||
{
|
||||
for (size_t pos = 0; pos < unlinked_cards.size(); ++pos) {
|
||||
CardP unlinked_card = unlinked_cards[pos];
|
||||
unlink(unlinked_card);
|
||||
}
|
||||
}
|
||||
|
||||
pair<String, String> Card::unlink(CardP& unlinked_card)
|
||||
{
|
||||
String old_selected_relation = wxEmptyString;
|
||||
THIS_LINKED_PAIRS(this_linked_pairs);
|
||||
FOR_EACH(this_linked_pair, this_linked_pairs) {
|
||||
String& this_linked_uid = this_linked_pair.first.get();
|
||||
String& this_linked_relation = this_linked_pair.second.get();
|
||||
if (this_linked_uid == unlinked_card->uid) {
|
||||
old_selected_relation = this_linked_relation;
|
||||
this_linked_uid = wxEmptyString;
|
||||
this_linked_relation = wxEmptyString;
|
||||
}
|
||||
}
|
||||
String old_unlinked_relation = wxEmptyString;
|
||||
OTHER_LINKED_PAIRS(unlinked_pairs, unlinked_card);
|
||||
FOR_EACH(unlinked_pair, unlinked_pairs) {
|
||||
String& unlinked_uid = unlinked_pair.first.get();
|
||||
String& unlinked_relation = unlinked_pair.second.get();
|
||||
if (unlinked_uid == uid) {
|
||||
old_unlinked_relation = unlinked_relation;
|
||||
unlinked_uid = wxEmptyString;
|
||||
unlinked_relation = wxEmptyString;
|
||||
}
|
||||
}
|
||||
return make_pair(old_selected_relation, old_unlinked_relation);
|
||||
}
|
||||
|
||||
void Card::copyLink(const Set& set, String old_uid, String new_uid) {
|
||||
// Find what relation we need to copy
|
||||
String relation_copy = wxEmptyString;
|
||||
THIS_LINKED_PAIRS(this_linked_pairs);
|
||||
FOR_EACH(this_linked_pair, this_linked_pairs) {
|
||||
String& this_linked_uid = this_linked_pair.first.get();
|
||||
String& this_linked_relation = this_linked_pair.second.get();
|
||||
if (this_linked_uid == old_uid) {
|
||||
relation_copy = this_linked_relation;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Nothing to copy
|
||||
if (relation_copy == wxEmptyString) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to copy to a free spot
|
||||
bool written = false;
|
||||
FOR_EACH(this_linked_pair, this_linked_pairs) {
|
||||
String& this_linked_uid = this_linked_pair.first.get();
|
||||
String& this_linked_relation = this_linked_pair.second.get();
|
||||
if (this_linked_uid == wxEmptyString) {
|
||||
this_linked_uid = new_uid;
|
||||
this_linked_relation = relation_copy;
|
||||
written = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Try to copy to an erasable spot
|
||||
if (!written) {
|
||||
unordered_set<String> all_existing_uids;
|
||||
FOR_EACH(card, set.cards) {
|
||||
all_existing_uids.insert(card->uid);
|
||||
}
|
||||
FOR_EACH(this_linked_pair, this_linked_pairs) {
|
||||
String& this_linked_uid = this_linked_pair.first.get();
|
||||
String& this_linked_relation = this_linked_pair.second.get();
|
||||
if (all_existing_uids.find(this_linked_uid) == all_existing_uids.end()) {
|
||||
this_linked_uid = new_uid;
|
||||
this_linked_relation = relation_copy;
|
||||
written = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Notify we couldn't copy
|
||||
if (!written) {
|
||||
queue_message(MESSAGE_WARNING, _ERROR_("not enough free links for copy"));
|
||||
}
|
||||
}
|
||||
|
||||
void Card::updateLink(String old_uid, String new_uid) {
|
||||
THIS_LINKED_PAIRS(this_linked_pairs);
|
||||
FOR_EACH(this_linked_pair, this_linked_pairs) {
|
||||
String& this_linked_uid = this_linked_pair.first.get();
|
||||
if (this_linked_uid == old_uid) {
|
||||
this_linked_uid = new_uid;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vector<pair<CardP, String>> Card::getLinkedCards(const Set& set) {
|
||||
unordered_map<String, String> links{
|
||||
{ linked_card_1, linked_relation_1 },
|
||||
{ linked_card_2, linked_relation_2 },
|
||||
{ linked_card_3, linked_relation_3 },
|
||||
{ linked_card_4, linked_relation_4 }
|
||||
};
|
||||
vector<pair<CardP, String>> linked_cards;
|
||||
FOR_EACH(other_card, set.cards) {
|
||||
if (links.find(other_card->uid) != links.end()) {
|
||||
linked_cards.push_back(make_pair(other_card, links.at(other_card->uid)));
|
||||
}
|
||||
}
|
||||
return linked_cards;
|
||||
}
|
||||
|
||||
IndexMap<FieldP, ValueP>& Card::extraDataFor(const StyleSheet& stylesheet) {
|
||||
return extra_data.get(stylesheet.name(), stylesheet.extra_card_fields);
|
||||
}
|
||||
@@ -89,6 +310,15 @@ IMPLEMENT_REFLECTION(Card) {
|
||||
}
|
||||
}
|
||||
REFLECT(notes);
|
||||
REFLECT(uid);
|
||||
REFLECT(linked_card_1);
|
||||
REFLECT(linked_card_2);
|
||||
REFLECT(linked_card_3);
|
||||
REFLECT(linked_card_4);
|
||||
REFLECT(linked_relation_1);
|
||||
REFLECT(linked_relation_2);
|
||||
REFLECT(linked_relation_3);
|
||||
REFLECT(linked_relation_4);
|
||||
REFLECT(time_created);
|
||||
REFLECT(time_modified);
|
||||
REFLECT(extra_data); // don't allow scripts to depend on style specific data
|
||||
|
||||
@@ -17,11 +17,15 @@
|
||||
class Game;
|
||||
class Dependency;
|
||||
class Keyword;
|
||||
DECLARE_POINTER_TYPE(Set);
|
||||
DECLARE_POINTER_TYPE(Card);
|
||||
DECLARE_POINTER_TYPE(Field);
|
||||
DECLARE_POINTER_TYPE(Value);
|
||||
DECLARE_POINTER_TYPE(StyleSheet);
|
||||
|
||||
#define THIS_LINKED_PAIRS(var) vector<pair<reference_wrapper<String>, reference_wrapper<String>>> var { make_pair(ref(linked_card_1), ref(linked_relation_1)), make_pair(ref(linked_card_2), ref(linked_relation_2)), make_pair(ref(linked_card_3), ref(linked_relation_3)), make_pair(ref(linked_card_4), ref(linked_relation_4)) }
|
||||
#define OTHER_LINKED_PAIRS(var, other_card) vector<pair<reference_wrapper<String>, reference_wrapper<String>>> var { make_pair(ref(other_card->linked_card_1), ref(other_card->linked_relation_1)), make_pair(ref(other_card->linked_card_2), ref(other_card->linked_relation_2)), make_pair(ref(other_card->linked_card_3), ref(other_card->linked_relation_3)), make_pair(ref(other_card->linked_card_4), ref(other_card->linked_relation_4)) }
|
||||
|
||||
// ----------------------------------------------------------------------------- : Card
|
||||
|
||||
/// A card from a card Set
|
||||
@@ -37,6 +41,18 @@ public:
|
||||
IndexMap<FieldP, ValueP> data;
|
||||
/// Notes for this card
|
||||
String notes;
|
||||
/// Unique identifier for this card, so other cards can refer to it, and be linked to it
|
||||
String uid;
|
||||
/// Up to four uid of other cards, to encode relations such as front face/back face, or generator/token, etc...
|
||||
String linked_card_1;
|
||||
String linked_card_2;
|
||||
String linked_card_3;
|
||||
String linked_card_4;
|
||||
/// Nature of the relatation with the respective linked card, such as back face, or token, etc...
|
||||
String linked_relation_1;
|
||||
String linked_relation_2;
|
||||
String linked_relation_3;
|
||||
String linked_relation_4;
|
||||
/// Time the card was created/last modified
|
||||
wxDateTime time_created, time_modified;
|
||||
/// Alternative style to use for this card
|
||||
@@ -64,6 +80,17 @@ public:
|
||||
/// Does any field contains the given query string?
|
||||
bool contains(QuickFilterPart const& query) const;
|
||||
|
||||
/// Link or unlink other cards to this card
|
||||
void link(const Set& set, const vector<CardP>& linked_cards, const String& selected_relation, const String& linked_relation);
|
||||
void link(const Set& set, CardP& linked_card, const String& selected_relation, const String& linked_relation);
|
||||
void unlink(const vector<CardP>& linked_cards);
|
||||
pair<String, String> unlink(CardP& unlinked_card); // Returns the relations that were deleted, so we can undo
|
||||
|
||||
void copyLink(const Set& set, String old_uid, String new_uid);
|
||||
void updateLink(String old_uid, String new_uid);
|
||||
|
||||
vector<pair<CardP, String>> getLinkedCards(const Set& set);
|
||||
|
||||
/// Find a value in the data by name and type
|
||||
template <typename T> T& value(const String& name) {
|
||||
for(IndexMap<FieldP, ValueP>::iterator it = data.begin() ; it != data.end() ; ++it) {
|
||||
|
||||
+36
-6
@@ -68,14 +68,14 @@ IMPLEMENT_REFLECTION(Field) {
|
||||
}
|
||||
|
||||
void Field::after_reading(Version ver) {
|
||||
name = canonical_name_form(name);
|
||||
if(caption.default_.empty()) caption.default_ = tr(package_relative_filename, name, name_to_caption);
|
||||
name = canonical_name_form(name);
|
||||
if(caption.default_.empty()) caption.default_ = tr(package_relative_filename, name, name_to_caption);
|
||||
if(card_list_name.default_.empty()) card_list_name.default_ = tr(package_relative_filename, caption.default_, capitalize);
|
||||
}
|
||||
|
||||
template <>
|
||||
intrusive_ptr<Field> read_new<Field>(Reader& reader) {
|
||||
intrusive_ptr<Field> field;
|
||||
intrusive_ptr<Field> field;
|
||||
// there must be a type specified
|
||||
String type;
|
||||
reader.handle(_("type"), type);
|
||||
@@ -95,7 +95,7 @@ intrusive_ptr<Field> read_new<Field>(Reader& reader) {
|
||||
} else {
|
||||
reader.warning(_ERROR_1_("unsupported field type", type));
|
||||
throw ParseError(_ERROR_("aborting parsing"));
|
||||
}
|
||||
}
|
||||
field->package_relative_filename = reader.getPackage()->relativeFilename().Clone();
|
||||
return field;
|
||||
}
|
||||
@@ -222,8 +222,38 @@ void Style::checkContentDependencies(Context& ctx, const Dependency& dep) const
|
||||
|
||||
void Style::markDependencyMember(const String& name, const Dependency& dep) const {
|
||||
// mark dependencies on content
|
||||
if (dep.type == DEP_DUMMY && dep.index == false && (starts_with(name, _("content")) || name == "layout") ) {
|
||||
// anything that starts with "content_" is a content property
|
||||
if (
|
||||
dep.type == DEP_DUMMY && dep.index == false && (
|
||||
starts_with(name, _("content")) ||
|
||||
name == "layout" ||
|
||||
name == "lines" ||
|
||||
name == "paragraphs" ||
|
||||
name == "blocks" ||
|
||||
name == "separators" ||
|
||||
name == "font" ||
|
||||
name == "symbol_font" ||
|
||||
name == "always_symbol" ||
|
||||
name == "allow_formating" ||
|
||||
name == "alignment" ||
|
||||
name == "padding_left" ||
|
||||
name == "padding_right" ||
|
||||
name == "padding_top" ||
|
||||
name == "padding_bottom" ||
|
||||
name == "padding_left_min" ||
|
||||
name == "padding_right_min" ||
|
||||
name == "padding_top_min" ||
|
||||
name == "padding_bottom_min" ||
|
||||
name == "line_height_soft" ||
|
||||
name == "line_height_hard" ||
|
||||
name == "line_height_line" ||
|
||||
name == "line_height_soft_max" ||
|
||||
name == "line_height_hard_max" ||
|
||||
name == "line_height_line_max" ||
|
||||
name == "paragraph_height" ||
|
||||
name == "block_height_min" ||
|
||||
name == "direction"
|
||||
)
|
||||
) {
|
||||
const_cast<Dependency&>(dep).index = true;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -61,7 +61,7 @@ public:
|
||||
Alignment card_list_align; ///< Alignment of the card list colummn.
|
||||
OptionalScript sort_script; ///< The script to use when sorting this, if not the value.
|
||||
OptionalScript import_script; ///< The script to apply to the supplied value, when creating a new card.
|
||||
Dependencies dependent_scripts; ///< Scripts that depend on values of this field
|
||||
Dependencies dependent_scripts; ///< Scripts that depend on values of this field
|
||||
String package_relative_filename;
|
||||
|
||||
/// Creates a new Value corresponding to this Field
|
||||
|
||||
+50
-50
@@ -8,10 +8,10 @@
|
||||
|
||||
#include <util/prec.hpp>
|
||||
#include <data/font.hpp>
|
||||
#include <wx/stdpaths.h>
|
||||
#include <wx/dir.h>
|
||||
#include <wx/font.h>
|
||||
|
||||
#include <wx/stdpaths.h>
|
||||
#include <wx/dir.h>
|
||||
#include <wx/font.h>
|
||||
|
||||
// ----------------------------------------------------------------------------- : Font
|
||||
|
||||
Font::Font()
|
||||
@@ -27,59 +27,59 @@ Font::Font()
|
||||
, separator_color(Color(0,0,0,128))
|
||||
, flags(FONT_NORMAL)
|
||||
{}
|
||||
|
||||
bool Font::PreloadResourceFonts(bool recursive) {
|
||||
#if wxUSE_PRIVATE_FONTS
|
||||
String pathSeparator(wxFileName::GetPathSeparator());
|
||||
String appPath(wxFileName(wxStandardPaths::Get().GetExecutablePath()).GetPath());
|
||||
wxDir appDir(appPath);
|
||||
if (!appDir.IsOpened()) return true;
|
||||
|
||||
bool preloadHadErrors = false;
|
||||
bool Font::PreloadResourceFonts(bool recursive) {
|
||||
#if wxUSE_PRIVATE_FONTS
|
||||
String pathSeparator(wxFileName::GetPathSeparator());
|
||||
String appPath(wxFileName(wxStandardPaths::Get().GetExecutablePath()).GetPath());
|
||||
wxDir appDir(appPath);
|
||||
if (!appDir.IsOpened()) return true;
|
||||
|
||||
bool preloadHadErrors = false;
|
||||
wxString folder;
|
||||
bool cont = appDir.GetFirst(&folder, wxEmptyString, wxDIR_DIRS);
|
||||
while (cont)
|
||||
{
|
||||
{
|
||||
if (folder.Lower().Contains("fonts")) {
|
||||
String folderPath = appPath + pathSeparator + folder + pathSeparator;
|
||||
|
||||
// tally fonts
|
||||
vector<String> fontFilePaths;
|
||||
TallyResourceFonts(folderPath, fontFilePaths, recursive);
|
||||
|
||||
// load fonts
|
||||
for (const String& fontFilePath : fontFilePaths) {
|
||||
if (!wxFont::AddPrivateFont(fontFilePath)) {
|
||||
preloadHadErrors = true;
|
||||
}
|
||||
String folderPath = appPath + pathSeparator + folder + pathSeparator;
|
||||
|
||||
// tally fonts
|
||||
vector<String> fontFilePaths;
|
||||
TallyResourceFonts(folderPath, fontFilePaths, recursive);
|
||||
|
||||
// load fonts
|
||||
for (const String& fontFilePath : fontFilePaths) {
|
||||
if (!wxFont::AddPrivateFont(fontFilePath)) {
|
||||
preloadHadErrors = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cont = appDir.GetNext(&folder);
|
||||
}
|
||||
|
||||
return preloadHadErrors;
|
||||
|
||||
#endif // wxUSE_PRIVATE_FONTS
|
||||
return false;
|
||||
}
|
||||
|
||||
void Font::TallyResourceFonts(String fontsDirectoryPath, vector<String>& fontFilePaths, bool recursive) {
|
||||
wxDir fontsDirectory(fontsDirectoryPath);
|
||||
String fontFileName = wxEmptyString;
|
||||
bool hasNext = fontsDirectory.GetFirst(&fontFileName);
|
||||
while (hasNext) {
|
||||
String fontFilePath = fontsDirectoryPath + fontFileName;
|
||||
if (wxDirExists(fontFilePath)) {
|
||||
if (recursive) {
|
||||
TallyResourceFonts(fontFilePath + wxFileName::GetPathSeparator(), fontFilePaths, true);
|
||||
}
|
||||
}
|
||||
else if (fontFilePath.EndsWith(_(".ttf")) || fontFilePath.EndsWith(_(".otf"))) {
|
||||
fontFilePaths.push_back(fontFilePath);
|
||||
}
|
||||
hasNext = fontsDirectory.GetNext(&fontFileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return preloadHadErrors;
|
||||
|
||||
#endif // wxUSE_PRIVATE_FONTS
|
||||
return false;
|
||||
}
|
||||
|
||||
void Font::TallyResourceFonts(String fontsDirectoryPath, vector<String>& fontFilePaths, bool recursive) {
|
||||
wxDir fontsDirectory(fontsDirectoryPath);
|
||||
String fontFileName = wxEmptyString;
|
||||
bool hasNext = fontsDirectory.GetFirst(&fontFileName);
|
||||
while (hasNext) {
|
||||
String fontFilePath = fontsDirectoryPath + fontFileName;
|
||||
if (wxDirExists(fontFilePath)) {
|
||||
if (recursive) {
|
||||
TallyResourceFonts(fontFilePath + wxFileName::GetPathSeparator(), fontFilePaths, true);
|
||||
}
|
||||
}
|
||||
else if (fontFilePath.EndsWith(_(".ttf")) || fontFilePath.EndsWith(_(".otf"))) {
|
||||
fontFilePaths.push_back(fontFilePath);
|
||||
}
|
||||
hasNext = fontsDirectory.GetNext(&fontFileName);
|
||||
}
|
||||
}
|
||||
|
||||
bool Font::update(Context& ctx) {
|
||||
bool changes = false;
|
||||
|
||||
+10
-9
@@ -46,15 +46,16 @@ public:
|
||||
Scriptable<double> shadow_displacement_y;///< Position of the shadow
|
||||
Scriptable<double> shadow_blur; ///< Blur radius of the shadow
|
||||
Color separator_color; ///< Color for <sep> text
|
||||
int flags; ///< FontFlags for this font
|
||||
|
||||
int flags; ///< FontFlags for this font
|
||||
|
||||
Font();
|
||||
|
||||
/// Load fonts (.ttf or .otf) from all directories in the app directory that contain "fonts" in their names,
|
||||
/// and optionaly their subdirectories, returns true if there were errors
|
||||
static bool PreloadResourceFonts(bool recursive);
|
||||
/// Adds font file paths from the given directory into fontFilePaths
|
||||
static void TallyResourceFonts(String fontsDirectoryPath, vector<String>& fontFilePaths, bool recursive);
|
||||
|
||||
/// Load fonts (.ttf or .otf) from all directories in the app directory that contain "fonts" in their names,
|
||||
/// and optionaly their subdirectories, returns true if there were errors
|
||||
static bool PreloadResourceFonts(bool recursive);
|
||||
/// Adds font file paths from the given directory into fontFilePaths
|
||||
static void TallyResourceFonts(String fontsDirectoryPath, vector<String>& fontFilePaths, bool recursive);
|
||||
|
||||
/// Update the scritables, returns true if there is a change
|
||||
bool update(Context& ctx);
|
||||
/// Add the given dependency to the dependent_scripts list for the variables this font depends on
|
||||
@@ -70,7 +71,7 @@ public:
|
||||
|
||||
/// Convert this font to a wxFont
|
||||
wxFont toWxFont(double scale) const;
|
||||
|
||||
|
||||
private:
|
||||
DECLARE_REFLECTION();
|
||||
};
|
||||
|
||||
@@ -147,6 +147,9 @@ CardsOnClipboard::CardsOnClipboard(const SetP& set, const vector<CardP>& cards)
|
||||
if (cards.size() == 1) {
|
||||
Add(new wxBitmapDataObject(export_bitmap(set, cards[0])));
|
||||
}
|
||||
else if (cards.size() < 6) {
|
||||
Add(new wxBitmapDataObject(export_bitmap(set, cards, true, 0, 1.0, 0.0)));
|
||||
}
|
||||
// Conversion to serialized card format
|
||||
Add(new CardsDataObject(set, cards), true);
|
||||
}
|
||||
|
||||
@@ -99,11 +99,12 @@ void export_images(const SetP& set, const vector<CardP>& cards,
|
||||
void export_image(const SetP& set, const CardP& card, const String& filename);
|
||||
|
||||
/// Generate a bitmap image of a card
|
||||
Bitmap export_bitmap(const SetP& set, const CardP& card);
|
||||
Bitmap export_bitmap(const SetP& set, const CardP& card);
|
||||
Bitmap export_bitmap(const SetP& set, const CardP& card, const double zoom, const Radians angle_radians);
|
||||
Bitmap export_bitmap(const SetP& set, const vector<CardP>& cards, bool scale_to_lowest_dpi, int padding, const double zoom, const Radians angle_radians);
|
||||
|
||||
/// Export a set to Magic Workstation format
|
||||
void export_mws(Window* parent, const SetP& set);
|
||||
|
||||
/// Export a set to Apprentice
|
||||
void export_apprentice(Window* parent, const SetP& set);
|
||||
void export_apprentice(Window* parent, const SetP& set);
|
||||
|
||||
+87
-35
@@ -13,6 +13,7 @@
|
||||
#include <data/card.hpp>
|
||||
#include <data/stylesheet.hpp>
|
||||
#include <data/settings.hpp>
|
||||
#include <gui/util.hpp>
|
||||
#include <render/card/viewer.hpp>
|
||||
#include <wx/filename.h>
|
||||
|
||||
@@ -25,47 +26,47 @@ void export_image(const SetP& set, const CardP& card, const String& filename) {
|
||||
}
|
||||
|
||||
class UnzoomedDataViewer : public DataViewer {
|
||||
public:
|
||||
UnzoomedDataViewer();
|
||||
public:
|
||||
UnzoomedDataViewer();
|
||||
UnzoomedDataViewer(double zoom, double angle);
|
||||
virtual ~UnzoomedDataViewer() {};
|
||||
Rotation getRotation() const override;
|
||||
private:
|
||||
private:
|
||||
double zoom;
|
||||
double angle;
|
||||
double angle;
|
||||
bool declared_values;
|
||||
};
|
||||
|
||||
UnzoomedDataViewer::UnzoomedDataViewer()
|
||||
: zoom(1.0)
|
||||
, angle(0.0)
|
||||
, declared_values(false)
|
||||
{}
|
||||
|
||||
UnzoomedDataViewer::UnzoomedDataViewer(const double zoom, const Radians angle = 0.0)
|
||||
: zoom(zoom)
|
||||
, angle(angle)
|
||||
, declared_values(true)
|
||||
};
|
||||
|
||||
UnzoomedDataViewer::UnzoomedDataViewer()
|
||||
: zoom(1.0)
|
||||
, angle(0.0)
|
||||
, declared_values(false)
|
||||
{}
|
||||
|
||||
UnzoomedDataViewer::UnzoomedDataViewer(const double zoom, const Radians angle = 0.0)
|
||||
: zoom(zoom)
|
||||
, angle(angle)
|
||||
, declared_values(true)
|
||||
{}
|
||||
|
||||
Rotation UnzoomedDataViewer::getRotation() const {
|
||||
if (!stylesheet) stylesheet = set->stylesheet;
|
||||
if (declared_values) {
|
||||
return Rotation(angle, stylesheet->getCardRect(), zoom, 1.0, ROTATION_ATTACH_TOP_LEFT);
|
||||
}
|
||||
if (!stylesheet) stylesheet = set->stylesheet;
|
||||
if (declared_values) {
|
||||
return Rotation(angle, stylesheet->getCardRect(), zoom, 1.0, ROTATION_ATTACH_TOP_LEFT);
|
||||
}
|
||||
|
||||
double export_zoom = settings.stylesheetSettingsFor(set->stylesheetFor(card)).export_zoom();
|
||||
bool use_viewer_rotation = !settings.stylesheetSettingsFor(set->stylesheetFor(card)).card_normal_export();
|
||||
|
||||
if (use_viewer_rotation) {
|
||||
double export_zoom = settings.stylesheetSettingsFor(set->stylesheetFor(card)).export_zoom();
|
||||
bool use_viewer_rotation = !settings.stylesheetSettingsFor(set->stylesheetFor(card)).card_normal_export();
|
||||
|
||||
if (use_viewer_rotation) {
|
||||
return Rotation(DataViewer::getRotation().getAngle(), stylesheet->getCardRect(), export_zoom, 1.0, ROTATION_ATTACH_TOP_LEFT);
|
||||
} else {
|
||||
return Rotation(angle, stylesheet->getCardRect(), export_zoom, 1.0, ROTATION_ATTACH_TOP_LEFT);
|
||||
}
|
||||
}
|
||||
|
||||
Bitmap export_bitmap(const SetP& set, const CardP& card) {
|
||||
if (!set) throw Error(_("no set"));
|
||||
}
|
||||
|
||||
Bitmap export_bitmap(const SetP& set, const CardP& card) {
|
||||
if (!set) throw Error(_("no set"));
|
||||
UnzoomedDataViewer viewer = UnzoomedDataViewer();
|
||||
viewer.setSet(set);
|
||||
viewer.setCard(card);
|
||||
@@ -79,11 +80,11 @@ Bitmap export_bitmap(const SetP& set, const CardP& card) {
|
||||
// draw
|
||||
viewer.draw(dc);
|
||||
dc.SelectObject(wxNullBitmap);
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
Bitmap export_bitmap(const SetP& set, const CardP& card, const double zoom, const Radians angle = 0.0) {
|
||||
if (!set) throw Error(_("no set"));
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
Bitmap export_bitmap(const SetP& set, const CardP& card, const double zoom, const Radians angle = 0.0) {
|
||||
if (!set) throw Error(_("no set"));
|
||||
UnzoomedDataViewer viewer = UnzoomedDataViewer(zoom, angle);
|
||||
viewer.setSet(set);
|
||||
viewer.setCard(card);
|
||||
@@ -97,8 +98,59 @@ Bitmap export_bitmap(const SetP& set, const CardP& card, const double zoom, cons
|
||||
// draw
|
||||
viewer.draw(dc);
|
||||
dc.SelectObject(wxNullBitmap);
|
||||
return bitmap;
|
||||
}
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
// put multiple card images into one bitmap
|
||||
Bitmap export_bitmap(const SetP& set, const vector<CardP>& cards, bool scale_to_lowest_dpi, int padding, const double zoom, const Radians angle = 0.0) {
|
||||
if (!set) throw Error(_("no set"));
|
||||
vector<Bitmap> bitmaps;
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
double lowest_dpi = 1200.0;
|
||||
if (scale_to_lowest_dpi) {
|
||||
FOR_EACH(card, cards) {
|
||||
lowest_dpi = min(lowest_dpi, set->stylesheetFor(card).card_dpi);
|
||||
}
|
||||
lowest_dpi = max(lowest_dpi, 150.0);
|
||||
}
|
||||
// Draw card bitmaps
|
||||
FOR_EACH(card, cards) {
|
||||
double scaled_zoom = zoom;
|
||||
if (scale_to_lowest_dpi) {
|
||||
double dpi = max(set->stylesheetFor(card).card_dpi, 150.0);
|
||||
scaled_zoom *= lowest_dpi / dpi;
|
||||
}
|
||||
UnzoomedDataViewer viewer = UnzoomedDataViewer(scaled_zoom, angle);
|
||||
viewer.setSet(set);
|
||||
viewer.setCard(card);
|
||||
RealSize size = viewer.getRotation().getExternalSize();
|
||||
Bitmap bitmap((int)size.width, (int)size.height);
|
||||
if (!bitmap.Ok()) throw InternalError(_("Unable to create bitmap"));
|
||||
wxMemoryDC bufferDC;
|
||||
bufferDC.SelectObject(bitmap);
|
||||
clearDC(bufferDC, *wxWHITE_BRUSH);
|
||||
viewer.draw(bufferDC);
|
||||
bufferDC.SelectObject(wxNullBitmap);
|
||||
width += (int)size.width;
|
||||
height = max(height, (int)size.height);
|
||||
bitmaps.push_back(bitmap);
|
||||
}
|
||||
// Draw global bitmap
|
||||
Bitmap global_bitmap(width + (bitmaps.size()-1) * padding, height);
|
||||
if (!global_bitmap.Ok()) throw InternalError(_("Unable to create bitmap"));
|
||||
wxMemoryDC globalDC;
|
||||
globalDC.SelectObject(global_bitmap);
|
||||
clearDC(globalDC, *wxWHITE_BRUSH);
|
||||
int offset = 0;
|
||||
FOR_EACH(bitmap, bitmaps) {
|
||||
globalDC.SetDeviceOrigin(offset, 0);
|
||||
globalDC.DrawBitmap(bitmap, 0, 0);
|
||||
offset += bitmap.GetWidth() + padding;
|
||||
}
|
||||
globalDC.SelectObject(wxNullBitmap);
|
||||
return global_bitmap;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Multiple card export
|
||||
|
||||
|
||||
+21
-20
@@ -48,6 +48,7 @@ IMPLEMENT_REFLECTION(Game) {
|
||||
}
|
||||
REFLECT_NO_SCRIPT(default_set_style);
|
||||
REFLECT_NO_SCRIPT(card_fields);
|
||||
REFLECT_NO_SCRIPT(card_links);
|
||||
REFLECT_NO_SCRIPT(card_list_color_script);
|
||||
REFLECT_NO_SCRIPT(import_script);
|
||||
REFLECT_NO_SCRIPT(json_paths);
|
||||
@@ -95,26 +96,26 @@ void Game::validate(Version v) {
|
||||
pack->filter = OptionalScript(_("true"));
|
||||
pack->select = SELECT_NO_REPLACE;
|
||||
pack_types.push_back(pack);
|
||||
}
|
||||
// alternate card field names map
|
||||
}
|
||||
// alternate card field names map
|
||||
for (auto it = card_fields.begin(); it != card_fields.end(); ++it) {
|
||||
FieldP field = *it;
|
||||
String unified_name = unified_form(field->name);
|
||||
if (card_fields_alt_names.count(unified_name)) {
|
||||
queue_message(MESSAGE_WARNING, _("Duplicate alternate card field name: ") + unified_name);
|
||||
}
|
||||
else {
|
||||
card_fields_alt_names.emplace(unified_name, field->name);
|
||||
}
|
||||
//String column_name = field->card_list_name.get();
|
||||
//card_fields_alt_names.emplace(unified_form(column_name), field->name);
|
||||
for (auto it2 = field->alt_names.begin(); it2 != field->alt_names.end(); ++it2) {
|
||||
unified_name = unified_form(*it2);
|
||||
if (card_fields_alt_names.count(unified_name)) {
|
||||
queue_message(MESSAGE_WARNING, _("Duplicate alternate card field name: ") + unified_name);
|
||||
}
|
||||
else {
|
||||
card_fields_alt_names.emplace(unified_name, field->name);
|
||||
FieldP field = *it;
|
||||
String unified_name = unified_form(field->name);
|
||||
if (card_fields_alt_names.count(unified_name)) {
|
||||
queue_message(MESSAGE_WARNING, _("Duplicate alternate card field name: ") + unified_name);
|
||||
}
|
||||
else {
|
||||
card_fields_alt_names.emplace(unified_name, field->name);
|
||||
}
|
||||
//String column_name = field->card_list_name.get();
|
||||
//card_fields_alt_names.emplace(unified_form(column_name), field->name);
|
||||
for (auto it2 = field->alt_names.begin(); it2 != field->alt_names.end(); ++it2) {
|
||||
unified_name = unified_form(*it2);
|
||||
if (card_fields_alt_names.count(unified_name)) {
|
||||
queue_message(MESSAGE_WARNING, _("Duplicate alternate card field name: ") + unified_name);
|
||||
}
|
||||
else {
|
||||
card_fields_alt_names.emplace(unified_name, field->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -138,7 +139,7 @@ void Game::initCardListColorScript() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// special behaviour of reading/writing GamePs: only read/write the name
|
||||
|
||||
|
||||
+3
-3
@@ -12,7 +12,7 @@
|
||||
#include <util/io/package.hpp>
|
||||
#include <script/scriptable.hpp>
|
||||
#include <script/dependency.hpp>
|
||||
#include <util/dynamic_arg.hpp>
|
||||
#include <util/dynamic_arg.hpp>
|
||||
|
||||
DECLARE_POINTER_TYPE(Field);
|
||||
DECLARE_POINTER_TYPE(Style);
|
||||
@@ -41,6 +41,7 @@ public:
|
||||
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<String> card_links; ///< Possible links between cards
|
||||
OptionalScript card_list_color_script; ///< Script that determines the color of items in the card list
|
||||
OptionalScript import_script; ///< Script applied as the last step of the new_card function
|
||||
vector<String> json_paths; ///< Paths inside JSON files to find the card array
|
||||
@@ -50,8 +51,7 @@ public:
|
||||
vector<WordListP> word_lists; ///< Word lists for editing with a drop down list
|
||||
vector<AddCardsScriptP> add_cards_scripts; ///< Scripts for adding multiple cards to the set
|
||||
vector<AutoReplaceP> auto_replaces; ///< Things to autoreplace in textboxes
|
||||
map<String,String> card_fields_alt_names; ///< Other names that fields might go by, for example in CSV files
|
||||
|
||||
map<String,String> card_fields_alt_names; ///< Other names that fields might go by, for example in CSV files
|
||||
bool has_keywords; ///< Does this game use keywords?
|
||||
OptionalScript keyword_match_script; ///< For the keyword editor
|
||||
vector<KeywordParamP> keyword_parameter_types;///< Types of keyword parameters
|
||||
|
||||
+4
-4
@@ -118,8 +118,8 @@ String tr(const Package& pkg, const String& subcat, const String& key, DefaultLo
|
||||
loc = find_wildcard_and_set(the_locale->package_translations, pkg.relativeFilename());
|
||||
}
|
||||
return loc->tr(subcat, key, def);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
String tr(const String& pkg_relative_filename, const String& key, DefaultLocaleFun def) {
|
||||
if (!the_locale) return def(key);
|
||||
SubLocaleP loc = the_locale->package_translations[pkg_relative_filename];
|
||||
@@ -127,8 +127,8 @@ String tr(const String& pkg_relative_filename, const String& key, DefaultLocaleF
|
||||
loc = find_wildcard_and_set(the_locale->package_translations, pkg_relative_filename);
|
||||
}
|
||||
return loc->tr(key, def);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
String tr(const String& pkg_relative_filename, const String& subcat, const String& key, DefaultLocaleFun def) {
|
||||
if (!the_locale) return def(key);
|
||||
SubLocaleP loc = the_locale->package_translations[pkg_relative_filename];
|
||||
|
||||
@@ -126,7 +126,7 @@ StyleSheetSettings::StyleSheetSettings()
|
||||
, card_angle (0, true)
|
||||
, card_anti_alias (true, true)
|
||||
, card_borders (true, true)
|
||||
, card_draw_editing (true, true)
|
||||
, card_draw_editing (true, true)
|
||||
, card_normal_export (true, true)
|
||||
, card_spellcheck_enabled(true, true)
|
||||
{}
|
||||
@@ -137,7 +137,7 @@ void StyleSheetSettings::useDefault(const StyleSheetSettings& ss) {
|
||||
if (card_angle .isDefault()) card_angle .assignDefault(ss.card_angle);
|
||||
if (card_anti_alias .isDefault()) card_anti_alias .assignDefault(ss.card_anti_alias);
|
||||
if (card_borders .isDefault()) card_borders .assignDefault(ss.card_borders);
|
||||
if (card_draw_editing .isDefault()) card_draw_editing .assignDefault(ss.card_draw_editing);
|
||||
if (card_draw_editing .isDefault()) card_draw_editing .assignDefault(ss.card_draw_editing);
|
||||
if (card_normal_export .isDefault()) card_normal_export .assignDefault(ss.card_normal_export);
|
||||
if (card_spellcheck_enabled.isDefault()) card_spellcheck_enabled.assignDefault(ss.card_spellcheck_enabled);
|
||||
}
|
||||
@@ -148,7 +148,7 @@ IMPLEMENT_REFLECTION_NO_SCRIPT(StyleSheetSettings) {
|
||||
REFLECT(card_angle);
|
||||
REFLECT(card_anti_alias);
|
||||
REFLECT(card_borders);
|
||||
REFLECT(card_draw_editing);
|
||||
REFLECT(card_draw_editing);
|
||||
REFLECT(card_normal_export);
|
||||
REFLECT(card_spellcheck_enabled);
|
||||
}
|
||||
@@ -225,8 +225,8 @@ ColumnSettings& Settings::columnSettingsFor(const Game& game, const Field& field
|
||||
}
|
||||
return cs;
|
||||
}
|
||||
StyleSheetSettings& Settings::stylesheetSettingsFor(const StyleSheet& stylesheet) {
|
||||
// Use the canonical form here since the stylesheet name will be used as a stored key.
|
||||
StyleSheetSettings& Settings::stylesheetSettingsFor(const StyleSheet& stylesheet) {
|
||||
// Use the canonical form here since the stylesheet name will be used as a stored key.
|
||||
// This does introduce the possibility of collision if two stylesheets return the same value canonically, but I think that's just a necessary risk.
|
||||
StyleSheetSettingsP& ss = stylesheet_settings[canonical_name_form(stylesheet.name())];
|
||||
if (!ss) ss = make_intrusive<StyleSheetSettings>();
|
||||
|
||||
@@ -195,10 +195,10 @@ public:
|
||||
|
||||
// --------------------------------------------------- : Special game stuff
|
||||
String apprentice_location;
|
||||
|
||||
// --------------------------------------------------- : Internal settings
|
||||
double internal_scale;
|
||||
bool internal_image_extension;
|
||||
|
||||
// --------------------------------------------------- : Internal settings
|
||||
double internal_scale;
|
||||
bool internal_image_extension;
|
||||
|
||||
// --------------------------------------------------- : Update checking
|
||||
#if USE_OLD_STYLE_UPDATE_CHECKER
|
||||
|
||||
+6
-11
@@ -38,13 +38,13 @@ StyleSheetP StyleSheet::byGameAndName(const Game& game, const String& name) {
|
||||
}
|
||||
} catch (PackageNotFoundError& e) {
|
||||
queue_message(MESSAGE_ERROR, _("Missing stylesheet: ") + full_name);
|
||||
|
||||
// This causes a freeze when the set contains two cards that use the same missing StyleSheet, and the second one has styling_data
|
||||
// Also, it's probably better to ask the user for an alternative for each missing StyleSheet individually
|
||||
|
||||
// This causes a freeze when the set contains two cards that use the same missing StyleSheet, and the second one has styling_data
|
||||
// Also, it's probably better to ask the user for an alternative for each missing StyleSheet individually
|
||||
//if (stylesheet_for_reading()) {
|
||||
// // we already have a stylesheet higher up, so just return a null pointer
|
||||
// return StyleSheetP();
|
||||
//}
|
||||
//}
|
||||
|
||||
// load an alternative stylesheet
|
||||
StyleSheetP ss = select_stylesheet(game, name);
|
||||
@@ -103,7 +103,7 @@ IMPLEMENT_REFLECTION(StyleSheet) {
|
||||
REFLECT(card_width);
|
||||
REFLECT(card_height);
|
||||
REFLECT(card_dpi);
|
||||
REFLECT(card_background);
|
||||
REFLECT(card_background);
|
||||
REFLECT(card_regions);
|
||||
REFLECT(init_script);
|
||||
// styling
|
||||
@@ -122,12 +122,7 @@ IMPLEMENT_REFLECTION(StyleSheet) {
|
||||
// extra card fields
|
||||
REFLECT(extra_card_fields);
|
||||
REFLECT_IF_READING {
|
||||
if (extra_card_style.init(extra_card_fields)) {
|
||||
// if a value is not editable, don't save it
|
||||
FOR_EACH(f, extra_card_fields) {
|
||||
if (!f->editable) f->save_value = false;
|
||||
}
|
||||
}
|
||||
extra_card_style.init(extra_card_fields);
|
||||
}
|
||||
REFLECT(extra_card_style);
|
||||
}
|
||||
|
||||
@@ -11,16 +11,16 @@
|
||||
#include <util/prec.hpp>
|
||||
#include <util/io/package.hpp>
|
||||
#include <util/real_point.hpp>
|
||||
#include <script/scriptable.hpp>
|
||||
// This isn't strictly needed for this file,
|
||||
// but CardRegion needs to be referenced from _somewhere_ in the codebase for compilation reasons.
|
||||
// Eventually if somewhere else is using the type then this can be removed.
|
||||
#include <script/scriptable.hpp>
|
||||
// This isn't strictly needed for this file,
|
||||
// but CardRegion needs to be referenced from _somewhere_ in the codebase for compilation reasons.
|
||||
// Eventually if somewhere else is using the type then this can be removed.
|
||||
#include <data/card_region.hpp>
|
||||
|
||||
DECLARE_POINTER_TYPE(Game);
|
||||
DECLARE_POINTER_TYPE(StyleSheet);
|
||||
DECLARE_POINTER_TYPE(Field);
|
||||
DECLARE_POINTER_TYPE(Style);
|
||||
DECLARE_POINTER_TYPE(Style);
|
||||
DECLARE_POINTER_TYPE(CardRegion);
|
||||
|
||||
// ----------------------------------------------------------------------------- : StyleSheet
|
||||
@@ -38,7 +38,7 @@ public:
|
||||
double card_width; ///< The width of a card in pixels
|
||||
double card_height; ///< The height of a card in pixels
|
||||
double card_dpi; ///< The resolution of a card in dots per inch
|
||||
Color card_background; ///< The background color of cards
|
||||
Color card_background; ///< The background color of cards
|
||||
vector<CardRegionP> card_regions;
|
||||
/// The styling for card fields
|
||||
/** The indices should correspond to the card_fields in the Game */
|
||||
|
||||
@@ -394,7 +394,7 @@ void SymbolFont::getCharInfo(RotatedDC& dc, double font_size, const SplitSymbols
|
||||
|
||||
RealSize SymbolFont::symbolSize(double font_size, const DrawableSymbol& sym) {
|
||||
if (sym.symbol) {
|
||||
return add_diagonal(sym.symbol->size(*this, font_size), spacing);
|
||||
return add_diagonal(sym.symbol->size(*this, font_size), spacingSize(font_size));
|
||||
} else {
|
||||
return defaultSymbolSize(font_size);
|
||||
}
|
||||
@@ -403,12 +403,15 @@ RealSize SymbolFont::symbolSize(double font_size, const DrawableSymbol& sym) {
|
||||
RealSize SymbolFont::defaultSymbolSize(double font_size) {
|
||||
SymbolInFont* def = defaultSymbol();
|
||||
if (def) {
|
||||
return add_diagonal(def->size(*this, font_size), spacing);
|
||||
return add_diagonal(def->size(*this, font_size), spacingSize(font_size));
|
||||
} else {
|
||||
return add_diagonal(RealSize(1,1), spacing);
|
||||
return add_diagonal(RealSize(1,1), spacingSize(font_size));
|
||||
}
|
||||
}
|
||||
|
||||
RealSize SymbolFont::spacingSize(double font_size) {
|
||||
return RealSize(spacing.width * font_size / 15.0, spacing.height * font_size / 15.0);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : InsertSymbolMenu
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ public:
|
||||
|
||||
private:
|
||||
double img_size; ///< Font size that the images use
|
||||
RealSize spacing; ///< Spacing between sybmols (for the default font size)
|
||||
RealSize spacing; ///< Spacing between sybmols, in pixels, for a font size of 15
|
||||
// writing text
|
||||
bool scale_text; ///< Should text be scaled down to fit in a symbol?
|
||||
InsertSymbolMenuP insert_symbol_menu;
|
||||
@@ -107,6 +107,9 @@ public:
|
||||
/// The default size of symbols, including spacing
|
||||
RealSize defaultSymbolSize(double font_size);
|
||||
|
||||
/// The spacing between symbols, accounting for font size
|
||||
RealSize SymbolFont::spacingSize(double font_size);
|
||||
|
||||
DECLARE_REFLECTION();
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user