mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-13 14:07:01 -04:00
Added 'filter' support to position function; Made sure sort script can depend on the value of the field itself.
Cleaned up some things, why is a blank image not thread safe? git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@548 0fc631ac-6414-0410-93d0-97cfa31319b6
This commit is contained in:
+77
-74
@@ -1,4 +1,4 @@
|
|||||||
mse version: 0.3.4
|
mse version: 0.3.4
|
||||||
short name: Magic
|
short name: Magic
|
||||||
full name: Magic the Gathering
|
full name: Magic the Gathering
|
||||||
icon: card-back.png
|
icon: card-back.png
|
||||||
@@ -126,72 +126,15 @@ init script:
|
|||||||
else "land, multicolor"
|
else "land, multicolor"
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
# Index for sorting, white cards are first, so white->A, blue->B, .. ,
|
|
||||||
# multi->F, hybrid->G, splits -> H, arti->I, land->K, basic land->J
|
|
||||||
is_multicolor := { chosen(choice: "multicolor") and input != "artifact, multicolor" }
|
|
||||||
is_hybrid := { chosen(choice: "hybrid") }
|
|
||||||
is_land := { chosen(choice: "land") }
|
|
||||||
is_multicolor_cost := {
|
|
||||||
colors := color_filter()
|
|
||||||
count := number_of_items(in: colors)
|
|
||||||
if count >= 2 then "yes"
|
|
||||||
else "no"
|
|
||||||
}
|
|
||||||
is_null_cost := {
|
|
||||||
input == "" or input == "0"
|
|
||||||
};
|
|
||||||
is_color := {
|
|
||||||
name := color_name();
|
|
||||||
contains(object.casting_cost, match:input) or (chosen(choice: name, object.card_color) and is_null_cost(object.casting_cost))
|
|
||||||
};
|
|
||||||
monocolor_sort := {
|
|
||||||
if is_color(object:input, "W") then "A"
|
|
||||||
else if is_color(object:input, "U") then "B"
|
|
||||||
else if is_color(object:input, "B") then "C"
|
|
||||||
else if is_color(object:input, "R") then "D"
|
|
||||||
else if is_color(object:input, "G") then "E"
|
|
||||||
else false
|
|
||||||
};
|
|
||||||
|
|
||||||
sort_index := {
|
|
||||||
if input.casting_cost_2 != "" and input.card_color != input.card_color_2 then "H" # multicolor splits
|
|
||||||
else if is_land (input.card_color) then (if input.rarity != "basic land" then "J" else "K") # lands, both basic and non-basic
|
|
||||||
else if contains(input.casting_cost, match:"/") then "G" # generic multicolor cards
|
|
||||||
else if is_multicolor_cost(input.casting_cost) == "yes" then "F" # multicolors (including artifacts)
|
|
||||||
else if is_multicolor(input.card_color) and is_null_cost(input.casting_cost) then "F" # costless multicolor cards
|
|
||||||
else if is_hybrid (input.card_color) and is_null_cost(input.casting_cost) then "G" # costless hybrid cards
|
|
||||||
else if monocolor_sort() != false then monocolor_sort() # regular monocolor cards
|
|
||||||
};
|
|
||||||
rarity_sort := {
|
|
||||||
if set.special_rarity_sort == "normally" or input.rarity != "special" then sort_index()
|
|
||||||
else "Z" + sort_index()
|
|
||||||
};
|
|
||||||
collation_set := {
|
|
||||||
if set.special_rarity_sort != "separate numbering" then filter := { true }
|
|
||||||
else if card.rarity == "special" then filter := { input.rarity == "special" }
|
|
||||||
else filter := {input.rarity != "special"}
|
|
||||||
filter_list (set, filter: filter)
|
|
||||||
};
|
|
||||||
|
|
||||||
card_number := {
|
|
||||||
sort_set := sort_list (collation_set(), order_by: {rarity_sort() + input.name} )
|
|
||||||
position (
|
|
||||||
of: card
|
|
||||||
in: sort_set
|
|
||||||
) + 1
|
|
||||||
+ "/" +
|
|
||||||
number_of_items(in: sort_set)
|
|
||||||
};
|
|
||||||
|
|
||||||
# The color of a card
|
# The color of a card
|
||||||
is_artifact := match_rule(match: "(?i)Artifact")
|
is_artifact := match_rule(match: "(?i)Artifact")
|
||||||
is_land := match_rule(match: "(?i)Land")
|
is_land := match_rule(match: "(?i)Land")
|
||||||
card_color := {
|
card_color := {
|
||||||
# usually the color of mana
|
# usually the color of mana
|
||||||
mana_color := mana_to_color(casting_cost);
|
mana_color := mana_to_color(casting_cost);
|
||||||
if mana_color == "colorless" and is_land (input: card.super_type) then land_to_color()
|
if mana_color == "colorless" and is_land (card.super_type) then land_to_color()
|
||||||
else if mana_color == "colorless" and is_artifact(input: card.super_type) then "artifact"
|
else if mana_color == "colorless" and is_artifact(card.super_type) then "artifact"
|
||||||
else mana_color
|
else mana_color
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -218,6 +161,66 @@ init script:
|
|||||||
# needed by all style files anyway
|
# needed by all style files anyway
|
||||||
include file: /magic-blends.mse-include/new-blends
|
include file: /magic-blends.mse-include/new-blends
|
||||||
|
|
||||||
|
############################################################## Card number
|
||||||
|
|
||||||
|
# Index for sorting, white cards are first, so white->A, blue->B, .. ,
|
||||||
|
# multi->F, hybrid->G, splits -> H, arti->I, land->K, basic land->J
|
||||||
|
is_multicolor := { chosen(choice: "multicolor") and input != "artifact, multicolor" }
|
||||||
|
is_null_cost := { input == "" or input == "0" }
|
||||||
|
sort_index := {
|
||||||
|
card_color := card.card_color
|
||||||
|
casting_cost := card.casting_cost
|
||||||
|
if card.casting_cost_2 != "" and
|
||||||
|
card_color != card.card_color_2 then "H" # multicolor splits
|
||||||
|
else if chosen(choice: "land", card_color) then (
|
||||||
|
# land
|
||||||
|
if card.rarity != "basic land" then "J" # basic land
|
||||||
|
else "K" # non-basic land
|
||||||
|
) else if is_null_cost(casting_cost) then (
|
||||||
|
# no casting cost; use frame
|
||||||
|
if chosen(choice: "hybrid", card_color) then "G" # Hybrid frame
|
||||||
|
else if is_multicolor(card_color) then "F" # Multicolor frame
|
||||||
|
else if chosen(choice:"white", card_color) then "A" # White
|
||||||
|
else if chosen(choice:"blue", card_color) then "B" # Blue
|
||||||
|
else if chosen(choice:"black", card_color) then "C" # Black
|
||||||
|
else if chosen(choice:"red", card_color) then "D" # Red
|
||||||
|
else if chosen(choice:"white", card_color) then "E" # Green
|
||||||
|
else "I" # Non of the above = Colorless/artifact
|
||||||
|
) else (
|
||||||
|
# use the casting cost
|
||||||
|
colors := sort_rule(casting_cost, order: "<WUBRG>")
|
||||||
|
if colors == "" then "I" # Colorless
|
||||||
|
else if contains(casting_cost, match:"/") then "G" # Hybrid cost
|
||||||
|
else if casting_cost == "W" then "A" # White
|
||||||
|
else if casting_cost == "U" then "B" # Blue
|
||||||
|
else if casting_cost == "B" then "C" # Black
|
||||||
|
else if casting_cost == "R" then "D" # Red
|
||||||
|
else if casting_cost == "G" then "E" # Green
|
||||||
|
else "F" # non of the above = multicolor
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
rarity_sort := {
|
||||||
|
if set.sort_special_rarity == "with the rest" or card.rarity != "special" then "A" else "Z"
|
||||||
|
}
|
||||||
|
set_filter := {
|
||||||
|
if set.sort_special_rarity != "separate numbering" then nil
|
||||||
|
else if card.rarity == "special" then { card.rarity == "special" }
|
||||||
|
else { card.rarity != "special" }
|
||||||
|
}
|
||||||
|
|
||||||
|
card_number := {
|
||||||
|
position (
|
||||||
|
of: card
|
||||||
|
in: set
|
||||||
|
order_by: { rarity_sort() + sort_index() + card.name }
|
||||||
|
filter: set_filter()
|
||||||
|
) + 1
|
||||||
|
}
|
||||||
|
card_count := {
|
||||||
|
number_of_items(in: set, filter: set_filter())
|
||||||
|
}
|
||||||
|
|
||||||
############################################################## Utilities for keywords
|
############################################################## Utilities for keywords
|
||||||
|
|
||||||
# replaces — correctly
|
# replaces — correctly
|
||||||
@@ -529,6 +532,14 @@ set field:
|
|||||||
type: boolean
|
type: boolean
|
||||||
name: automatic card numbers
|
name: automatic card numbers
|
||||||
description: Should card numbers be shown on the cards?
|
description: Should card numbers be shown on the cards?
|
||||||
|
set field:
|
||||||
|
type: choice
|
||||||
|
name: sort special rarity
|
||||||
|
description: Determines how cards with special rarity are sorted.
|
||||||
|
choice: with the rest
|
||||||
|
choice: after other cards
|
||||||
|
choice: separate numbering
|
||||||
|
initial: after other cards
|
||||||
set field:
|
set field:
|
||||||
type: boolean
|
type: boolean
|
||||||
name: mark errors
|
name: mark errors
|
||||||
@@ -541,14 +552,6 @@ set field:
|
|||||||
choice: no
|
choice: no
|
||||||
description: Use gradients on multicolor cards by default, you can always change it be clicking on the card border.
|
description: Use gradients on multicolor cards by default, you can always change it be clicking on the card border.
|
||||||
initial: no
|
initial: no
|
||||||
set field:
|
|
||||||
type: choice
|
|
||||||
name: special rarity sort
|
|
||||||
description: Determines how cards with special rarity are sorted.
|
|
||||||
choice: normally
|
|
||||||
choice: last
|
|
||||||
choice: separate numbering
|
|
||||||
initial: last
|
|
||||||
|
|
||||||
############################# Default style
|
############################# Default style
|
||||||
|
|
||||||
@@ -561,12 +564,14 @@ default set style:
|
|||||||
variation:
|
variation:
|
||||||
name: common
|
name: common
|
||||||
border radius: 0.10
|
border radius: 0.10
|
||||||
|
#max aspect ratio: 2.5
|
||||||
fill type: solid
|
fill type: solid
|
||||||
fill color: rgb(0,0,0)
|
fill color: rgb(0,0,0)
|
||||||
border color: rgb(255,255,255)
|
border color: rgb(255,255,255)
|
||||||
variation:
|
variation:
|
||||||
name: uncommon
|
name: uncommon
|
||||||
border radius: 0.05
|
border radius: 0.05
|
||||||
|
#max aspect ratio: 2.5
|
||||||
fill type: linear gradient
|
fill type: linear gradient
|
||||||
fill color 1: rgb(224,224,224)
|
fill color 1: rgb(224,224,224)
|
||||||
fill color 2: rgb(84, 84, 84)
|
fill color 2: rgb(84, 84, 84)
|
||||||
@@ -826,10 +831,8 @@ card field:
|
|||||||
type: text
|
type: text
|
||||||
name: card number
|
name: card number
|
||||||
save value: false
|
save value: false
|
||||||
script:
|
script: card_number() + "/" + card_count()
|
||||||
card_number()
|
sort script: rarity_sort() + card.card_number
|
||||||
sort script:
|
|
||||||
rarity_sort(card) + card.name
|
|
||||||
card list visible: true
|
card list visible: true
|
||||||
card list column: 10
|
card list column: 10
|
||||||
card list width: 50
|
card list width: 50
|
||||||
@@ -1415,7 +1418,7 @@ keyword parameter type:
|
|||||||
name: prefix
|
name: prefix
|
||||||
description: Prefix for things like "<something>walk"
|
description: Prefix for things like "<something>walk"
|
||||||
optional: false
|
optional: false
|
||||||
match: [A-Z,a-z][A-Z,a-z ]*
|
match: [A-Z][a-z, ]*([A-Z][a-z, ]*\xEB00)
|
||||||
example: Forest
|
example: Forest
|
||||||
|
|
||||||
############################# All Magic keywords
|
############################# All Magic keywords
|
||||||
|
|||||||
@@ -37,6 +37,10 @@ Field::Field()
|
|||||||
|
|
||||||
Field::~Field() {}
|
Field::~Field() {}
|
||||||
|
|
||||||
|
void Field::initDependencies(Context& ctx, const Dependency& dep) const {
|
||||||
|
sort_script.initDependencies(ctx, dep);
|
||||||
|
}
|
||||||
|
|
||||||
IMPLEMENT_REFLECTION(Field) {
|
IMPLEMENT_REFLECTION(Field) {
|
||||||
REFLECT_IF_NOT_READING {
|
REFLECT_IF_NOT_READING {
|
||||||
String type = typeName();
|
String type = typeName();
|
||||||
@@ -215,6 +219,18 @@ bool Value::equals(const Value* that) {
|
|||||||
return this == that;
|
return this == that;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Value::update(Context& ctx) {
|
||||||
|
updateAge();
|
||||||
|
updateSortValue(ctx);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
void Value::updateAge() {
|
||||||
|
last_script_update.update();
|
||||||
|
}
|
||||||
|
void Value::updateSortValue(Context& ctx) {
|
||||||
|
sort_value = fieldP->sort_script.invoke(ctx)->toString();
|
||||||
|
}
|
||||||
|
|
||||||
void init_object(const FieldP& field, ValueP& value) {
|
void init_object(const FieldP& field, ValueP& value) {
|
||||||
if (!value)
|
if (!value)
|
||||||
value = field->newValue(field);
|
value = field->newValue(field);
|
||||||
|
|||||||
+12
-12
@@ -68,9 +68,7 @@ class Field : public IntrusivePtrVirtualBase {
|
|||||||
virtual String typeName() const = 0;
|
virtual String typeName() const = 0;
|
||||||
|
|
||||||
/// Add the given dependency to the dependet_scripts list for the variables this field depends on
|
/// Add the given dependency to the dependet_scripts list for the variables this field depends on
|
||||||
inline virtual void initDependencies(Context& ctx, const Dependency& dep) const {
|
virtual void initDependencies(Context& ctx, const Dependency& dep) const;
|
||||||
sort_script.initDependencies(ctx, dep);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DECLARE_REFLECTION_VIRTUAL();
|
DECLARE_REFLECTION_VIRTUAL();
|
||||||
@@ -186,7 +184,7 @@ class Value : public IntrusivePtrVirtualBase {
|
|||||||
|
|
||||||
const FieldP fieldP; ///< Field this value is for, should have the right type!
|
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)
|
Age last_script_update; ///< When where the scripts last updated? (by calling update)
|
||||||
ScriptValueP sortValue; ///< How this should be sorted.
|
String sort_value; ///< How this should be sorted.
|
||||||
|
|
||||||
/// Get a copy of this value
|
/// Get a copy of this value
|
||||||
virtual ValueP clone() const = 0;
|
virtual ValueP clone() const = 0;
|
||||||
@@ -194,11 +192,7 @@ class Value : public IntrusivePtrVirtualBase {
|
|||||||
/// Convert this value to a string for use in tables
|
/// Convert this value to a string for use in tables
|
||||||
virtual String toString() const = 0;
|
virtual String toString() const = 0;
|
||||||
/// Apply scripts to this value, return true if the value has changed
|
/// Apply scripts to this value, return true if the value has changed
|
||||||
inline virtual bool update(Context& ctx) {
|
virtual bool update(Context& ctx);
|
||||||
sortValue = fieldP->sort_script.invoke(ctx);
|
|
||||||
last_script_update.update();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
/// This value has been updated by an action
|
/// This value has been updated by an action
|
||||||
/** Does nothing for most Values, only FakeValues can update underlying data */
|
/** Does nothing for most Values, only FakeValues can update underlying data */
|
||||||
virtual void onAction(Action& a, bool undone) {}
|
virtual void onAction(Action& a, bool undone) {}
|
||||||
@@ -208,11 +202,17 @@ class Value : public IntrusivePtrVirtualBase {
|
|||||||
*/
|
*/
|
||||||
virtual bool equals(const Value* that);
|
virtual bool equals(const Value* that);
|
||||||
|
|
||||||
/// Get the sort key for this value.
|
/// Get the key to use for sorting this value
|
||||||
inline String getSortKey () const {
|
inline String getSortKey() const {
|
||||||
return sortValue == script_nil ? *sortValue : toString();
|
return fieldP->sort_script ? sort_value : toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/// update() split into two functions;.
|
||||||
|
/** Derived classes should put their stuff in between if they need the age in scripts */
|
||||||
|
void updateAge();
|
||||||
|
void updateSortValue(Context& ctx);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DECLARE_REFLECTION_VIRTUAL();
|
DECLARE_REFLECTION_VIRTUAL();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
#include <data/field/choice.hpp>
|
#include <data/field/choice.hpp>
|
||||||
#include <util/io/package.hpp>
|
#include <util/io/package.hpp>
|
||||||
#include <wx/spinctrl.h>
|
|
||||||
#include <wx/imaglist.h>
|
#include <wx/imaglist.h>
|
||||||
|
|
||||||
DECLARE_TYPEOF_COLLECTION(ChoiceField::ChoiceP);
|
DECLARE_TYPEOF_COLLECTION(ChoiceField::ChoiceP);
|
||||||
@@ -312,9 +311,10 @@ String ChoiceValue::toString() const {
|
|||||||
return value();
|
return value();
|
||||||
}
|
}
|
||||||
bool ChoiceValue::update(Context& ctx) {
|
bool ChoiceValue::update(Context& ctx) {
|
||||||
|
bool change = field().default_script.invokeOnDefault(ctx, value)
|
||||||
|
| field(). script.invokeOn(ctx, value);
|
||||||
Value::update(ctx);
|
Value::update(ctx);
|
||||||
return field().default_script.invokeOnDefault(ctx, value)
|
return change;
|
||||||
| field(). script.invokeOn(ctx, value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IMPLEMENT_REFLECTION_NAMELESS(ChoiceValue) {
|
IMPLEMENT_REFLECTION_NAMELESS(ChoiceValue) {
|
||||||
|
|||||||
@@ -91,9 +91,10 @@ String ColorValue::toString() const {
|
|||||||
return _("<color>");
|
return _("<color>");
|
||||||
}
|
}
|
||||||
bool ColorValue::update(Context& ctx) {
|
bool ColorValue::update(Context& ctx) {
|
||||||
|
bool change = field().default_script.invokeOnDefault(ctx, value)
|
||||||
|
| field(). script.invokeOn(ctx, value);
|
||||||
Value::update(ctx);
|
Value::update(ctx);
|
||||||
return field().default_script.invokeOnDefault(ctx, value)
|
return change;
|
||||||
| field(). script.invokeOn(ctx, value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IMPLEMENT_REFLECTION_NAMELESS(ColorValue) {
|
IMPLEMENT_REFLECTION_NAMELESS(ColorValue) {
|
||||||
|
|||||||
@@ -66,9 +66,10 @@ String InfoValue::toString() const {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
bool InfoValue::update(Context& ctx) {
|
bool InfoValue::update(Context& ctx) {
|
||||||
Value::update(ctx);
|
|
||||||
if (value.empty()) value = field().name;
|
if (value.empty()) value = field().name;
|
||||||
return field().script.invokeOn(ctx, value);
|
bool change = field().script.invokeOn(ctx, value);
|
||||||
|
Value::update(ctx);
|
||||||
|
return change;
|
||||||
}
|
}
|
||||||
|
|
||||||
IMPLEMENT_REFLECTION_NAMELESS(InfoValue) {
|
IMPLEMENT_REFLECTION_NAMELESS(InfoValue) {
|
||||||
|
|||||||
@@ -127,12 +127,13 @@ String TextValue::toString() const {
|
|||||||
return untag_hide_sep(value());
|
return untag_hide_sep(value());
|
||||||
}
|
}
|
||||||
bool TextValue::update(Context& ctx) {
|
bool TextValue::update(Context& ctx) {
|
||||||
Value::update(ctx);
|
updateAge();
|
||||||
WITH_DYNAMIC_ARG(last_update_age, last_update.get());
|
WITH_DYNAMIC_ARG(last_update_age, last_update.get());
|
||||||
WITH_DYNAMIC_ARG(value_being_updated, this);
|
WITH_DYNAMIC_ARG(value_being_updated, this);
|
||||||
bool change = field().default_script.invokeOnDefault(ctx, value)
|
bool change = field().default_script.invokeOnDefault(ctx, value)
|
||||||
| field(). script.invokeOn(ctx, value);
|
| field(). script.invokeOn(ctx, value);
|
||||||
if (change) last_update.update();
|
if (change) last_update.update();
|
||||||
|
updateSortValue(ctx);
|
||||||
return change;
|
return change;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+25
-5
@@ -208,23 +208,43 @@ void reflect_set_info_get_member(GetMember& tag, const IndexMap<FieldP, ValueP>&
|
|||||||
REFLECT_NAMELESS(data);
|
REFLECT_NAMELESS(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Set::positionOfCard(const CardP& card, const ScriptValueP& order_by) {
|
int Set::positionOfCard(const CardP& card, const ScriptValueP& order_by, const ScriptValueP& filter) {
|
||||||
// TODO : Lock the map?
|
// TODO : Lock the map?
|
||||||
assert(order_by);
|
assert(order_by);
|
||||||
OrderCacheP& order = order_cache[order_by];
|
OrderCacheP& order = order_cache[make_pair(order_by,filter)];
|
||||||
if (!order) {
|
if (!order) {
|
||||||
// 1. make a list of the order value for each card
|
// 1. make a list of the order value for each card
|
||||||
vector<String> values; values.reserve(cards.size());
|
vector<String> values; values.reserve(cards.size());
|
||||||
|
vector<int> keep; if(filter) keep.reserve(cards.size());
|
||||||
FOR_EACH_CONST(c, cards) {
|
FOR_EACH_CONST(c, cards) {
|
||||||
values.push_back(*order_by->eval(getContext(c)));
|
Context& ctx = getContext(c);
|
||||||
|
values.push_back(*order_by->eval(ctx));
|
||||||
|
if (filter) {
|
||||||
|
keep.push_back(*filter->eval(ctx));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// 2. initialize order cache
|
// 3. initialize order cache
|
||||||
order = new_intrusive2<OrderCache<CardP> >(cards, values);
|
order = new_intrusive3<OrderCache<CardP> >(cards, values, filter ? &keep : nullptr);
|
||||||
}
|
}
|
||||||
return order->find(card);
|
return order->find(card);
|
||||||
}
|
}
|
||||||
|
int Set::numberOfCards(const ScriptValueP& filter) {
|
||||||
|
if (!filter) return (int)cards.size();
|
||||||
|
map<ScriptValueP,int>::const_iterator it = filter_cache.find(filter);
|
||||||
|
if (it !=filter_cache.end()) {
|
||||||
|
return it->second;
|
||||||
|
} else {
|
||||||
|
int n = 0;
|
||||||
|
FOR_EACH_CONST(c, cards) {
|
||||||
|
if (*filter->eval(getContext(c))) ++n;
|
||||||
|
}
|
||||||
|
filter_cache.insert(make_pair(filter,n));
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
}
|
||||||
void Set::clearOrderCache() {
|
void Set::clearOrderCache() {
|
||||||
order_cache.clear();
|
order_cache.clear();
|
||||||
|
filter_cache.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : SetView
|
// ----------------------------------------------------------------------------- : SetView
|
||||||
|
|||||||
+5
-2
@@ -106,7 +106,9 @@ class Set : public Packaged {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Find the position of a card in this set, when the card list is sorted using the given cirterium
|
/// Find the position of a card in this set, when the card list is sorted using the given cirterium
|
||||||
int positionOfCard(const CardP& card, const ScriptValueP& order_by);
|
int positionOfCard(const CardP& card, const ScriptValueP& order_by, const ScriptValueP& filter);
|
||||||
|
/// Find the number of cards that match the given filter
|
||||||
|
int numberOfCards(const ScriptValueP& filter);
|
||||||
/// Clear the order_cache used by positionOfCard
|
/// Clear the order_cache used by positionOfCard
|
||||||
void clearOrderCache();
|
void clearOrderCache();
|
||||||
|
|
||||||
@@ -122,7 +124,8 @@ class Set : public Packaged {
|
|||||||
/// Object for executing scripts from the thumbnail thread
|
/// Object for executing scripts from the thumbnail thread
|
||||||
scoped_ptr<SetScriptContext> thumbnail_script_context;
|
scoped_ptr<SetScriptContext> thumbnail_script_context;
|
||||||
/// Cache of cards ordered by some criterion
|
/// Cache of cards ordered by some criterion
|
||||||
map<ScriptValueP,OrderCacheP> order_cache;
|
map<pair<ScriptValueP,ScriptValueP>,OrderCacheP> order_cache;
|
||||||
|
map<ScriptValueP,int> filter_cache;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline String type_name(const Set&) {
|
inline String type_name(const Set&) {
|
||||||
|
|||||||
@@ -65,7 +65,11 @@ class BlankImage : public GeneratedImage {
|
|||||||
public:
|
public:
|
||||||
virtual Image generate(const Options&) const;
|
virtual Image generate(const Options&) const;
|
||||||
virtual bool operator == (const GeneratedImage& that) const;
|
virtual bool operator == (const GeneratedImage& that) const;
|
||||||
virtual bool threadSafe() const { return false; };
|
|
||||||
|
// Why is this not thread safe? What is GTK smoking?
|
||||||
|
#ifdef __WXGTK__
|
||||||
|
virtual bool threadSafe() const { return false; }
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : LinearBlendImage
|
// ----------------------------------------------------------------------------- : LinearBlendImage
|
||||||
|
|||||||
@@ -11,8 +11,8 @@
|
|||||||
|
|
||||||
#include <util/prec.hpp>
|
#include <util/prec.hpp>
|
||||||
#include <gui/symbol/editor.hpp>
|
#include <gui/symbol/editor.hpp>
|
||||||
#include <wx/spinctrl.h>
|
|
||||||
|
|
||||||
|
class wxSpinCtrl;
|
||||||
class SymmetryMoveAction;
|
class SymmetryMoveAction;
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : SymbolSymmetryEditor
|
// ----------------------------------------------------------------------------- : SymbolSymmetryEditor
|
||||||
|
|||||||
@@ -50,7 +50,11 @@ typedef shared_ptr<wxMemoryDC> MemoryDCP;
|
|||||||
// Return a temporary DC with the same size as the parameter
|
// Return a temporary DC with the same size as the parameter
|
||||||
MemoryDCP getTempDC(DC& dc) {
|
MemoryDCP getTempDC(DC& dc) {
|
||||||
wxSize s = dc.GetSize();
|
wxSize s = dc.GetSize();
|
||||||
Bitmap buffer(s.GetWidth(), s.GetHeight(), 24);
|
#ifdef __WXMSW__
|
||||||
|
Bitmap buffer(s.GetWidth(), s.GetHeight(), 1);
|
||||||
|
#else
|
||||||
|
Bitmap buffer(s.GetWidth(), s.GetHeight(), 24);
|
||||||
|
#endif
|
||||||
MemoryDCP newDC(new wxMemoryDC);
|
MemoryDCP newDC(new wxMemoryDC);
|
||||||
newDC->SelectObject(buffer);
|
newDC->SelectObject(buffer);
|
||||||
clearDC(*newDC, *wxBLACK_BRUSH);
|
clearDC(*newDC, *wxBLACK_BRUSH);
|
||||||
@@ -161,10 +165,10 @@ void SymbolViewer::combineSymbolPart(DC& dc, const SymbolPart& part, bool& paint
|
|||||||
// Matrix2D rot(cos(a),-sin(a), sin(a),cos(a));
|
// Matrix2D rot(cos(a),-sin(a), sin(a),cos(a));
|
||||||
//
|
//
|
||||||
// ref * rot
|
// ref * rot
|
||||||
// /cos b sin b\ /cos a -sin a\;
|
// [ cos b sin b ! [ cos a -sin a !
|
||||||
// = \sin b -cos b/ \sin a cos a/;s
|
// = ! sin b -cos b ] ! sin a cos a ]
|
||||||
// = /cos(a+b) sin(a+b)\;
|
// = [ cos(a+b) sin(a+b) !
|
||||||
// \sin(a+b) -cos(a+b)/;
|
// ! sin(a+b) -cos(a+b) ]
|
||||||
Matrix2D rot(cos(a+b),sin(a+b), sin(a+b),-cos(a+b));
|
Matrix2D rot(cos(a+b),sin(a+b), sin(a+b),-cos(a+b));
|
||||||
multiply.mx = rot.mx * old_m;
|
multiply.mx = rot.mx * old_m;
|
||||||
multiply.my = rot.my * old_m;
|
multiply.my = rot.my * old_m;
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ struct TextElementsFromString {
|
|||||||
// ignore other tags
|
// ignore other tags
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (c == _('\1')) c = _('<'); // unescape
|
c = untag_char(c); // unescape
|
||||||
// A character of normal text, add to the last text element (if possible)
|
// A character of normal text, add to the last text element (if possible)
|
||||||
SimpleTextElement* e = nullptr;
|
SimpleTextElement* e = nullptr;
|
||||||
if (!te.elements.empty()) e = dynamic_cast<SimpleTextElement*>(te.elements.back().get());
|
if (!te.elements.empty()) e = dynamic_cast<SimpleTextElement*>(te.elements.back().get());
|
||||||
|
|||||||
@@ -173,18 +173,18 @@ bool equal(const ScriptValue& a, const ScriptValue& b) {
|
|||||||
|
|
||||||
/// position of some element in a vector
|
/// position of some element in a vector
|
||||||
/** 0 based index, -1 if not found */
|
/** 0 based index, -1 if not found */
|
||||||
int position_in_vector(const ScriptValueP& of, const ScriptValueP& in, const ScriptValueP& order_by) {
|
int position_in_vector(const ScriptValueP& of, const ScriptValueP& in, const ScriptValueP& order_by, const ScriptValueP& filter) {
|
||||||
ScriptType of_t = of->type(), in_t = in->type();
|
ScriptType of_t = of->type(), in_t = in->type();
|
||||||
if (of_t == SCRIPT_STRING || in_t == SCRIPT_STRING) {
|
if (of_t == SCRIPT_STRING || in_t == SCRIPT_STRING) {
|
||||||
// string finding
|
// string finding
|
||||||
return (int)of->toString().find(in->toString()); // (int)npos == -1
|
return (int)of->toString().find(in->toString()); // (int)npos == -1
|
||||||
} else if (order_by) {
|
} else if (order_by || filter) {
|
||||||
ScriptObject<Set*>* s = dynamic_cast<ScriptObject<Set*>* >(in.get());
|
ScriptObject<Set*>* s = dynamic_cast<ScriptObject<Set*>* >(in.get());
|
||||||
ScriptObject<CardP>* c = dynamic_cast<ScriptObject<CardP>*>(of.get());
|
ScriptObject<CardP>* c = dynamic_cast<ScriptObject<CardP>*>(of.get());
|
||||||
if (s && c) {
|
if (s && c) {
|
||||||
return s->getValue()->positionOfCard(c->getValue(), order_by);
|
return s->getValue()->positionOfCard(c->getValue(), order_by, filter);
|
||||||
} else {
|
} else {
|
||||||
throw ScriptError(_("position: using 'order_by' is only supported for finding cards in the set"));
|
throw ScriptError(_("position: using 'order_by' or 'filter' is only supported for finding cards in the set"));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// unordered position
|
// unordered position
|
||||||
@@ -231,12 +231,15 @@ SCRIPT_FUNCTION_WITH_DEP(position_of) {
|
|||||||
ScriptValueP of = ctx.getVariable(_("of"));
|
ScriptValueP of = ctx.getVariable(_("of"));
|
||||||
ScriptValueP in = ctx.getVariable(_("in"));
|
ScriptValueP in = ctx.getVariable(_("in"));
|
||||||
ScriptValueP order_by = ctx.getVariableOpt(_("order by"));
|
ScriptValueP order_by = ctx.getVariableOpt(_("order by"));
|
||||||
SCRIPT_RETURN(position_in_vector(of, in, order_by));
|
ScriptValueP filter = ctx.getVariableOpt(_("filter"));
|
||||||
|
if (filter == script_nil) filter = ScriptValueP();
|
||||||
|
SCRIPT_RETURN(position_in_vector(of, in, order_by, filter));
|
||||||
}
|
}
|
||||||
SCRIPT_FUNCTION_DEPENDENCIES(position_of) {
|
SCRIPT_FUNCTION_DEPENDENCIES(position_of) {
|
||||||
ScriptValueP of = ctx.getVariable(_("of"));
|
ScriptValueP of = ctx.getVariable(_("of"));
|
||||||
ScriptValueP in = ctx.getVariable(_("in"));
|
ScriptValueP in = ctx.getVariable(_("in"));
|
||||||
ScriptValueP order_by = ctx.getVariableOpt(_("order by"));
|
ScriptValueP order_by = ctx.getVariableOpt(_("order by"));
|
||||||
|
ScriptValueP filter = ctx.getVariableOpt(_("filter"));
|
||||||
ScriptObject<Set*>* s = dynamic_cast<ScriptObject<Set*>* >(in.get());
|
ScriptObject<Set*>* s = dynamic_cast<ScriptObject<Set*>* >(in.get());
|
||||||
ScriptObject<CardP>* c = dynamic_cast<ScriptObject<CardP>*>(of.get());
|
ScriptObject<CardP>* c = dynamic_cast<ScriptObject<CardP>*>(of.get());
|
||||||
if (s && c) {
|
if (s && c) {
|
||||||
@@ -246,13 +249,25 @@ SCRIPT_FUNCTION_DEPENDENCIES(position_of) {
|
|||||||
// dependency on order_by function
|
// dependency on order_by function
|
||||||
order_by->dependencies(ctx, dep.makeCardIndependend());
|
order_by->dependencies(ctx, dep.makeCardIndependend());
|
||||||
}
|
}
|
||||||
|
if (filter && filter != script_nil) {
|
||||||
|
// dependency on filter function
|
||||||
|
filter->dependencies(ctx, dep.makeCardIndependend());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return dependency_dummy;
|
return dependency_dummy;
|
||||||
};
|
};
|
||||||
|
|
||||||
// finding sizes
|
// finding sizes
|
||||||
SCRIPT_FUNCTION(number_of_items) {
|
SCRIPT_FUNCTION(number_of_items) {
|
||||||
SCRIPT_RETURN(ctx.getVariable(_("in"))->itemCount());
|
SCRIPT_PARAM(ScriptValueP, in);
|
||||||
|
if (ScriptObject<Set*>* setobj = dynamic_cast<ScriptObject<Set*>*>(in.get())) {
|
||||||
|
Set* set = setobj->getValue();
|
||||||
|
SCRIPT_OPTIONAL_PARAM_(ScriptValueP, filter);
|
||||||
|
if (filter == script_nil) filter = ScriptValueP();
|
||||||
|
SCRIPT_RETURN(set->numberOfCards(filter));
|
||||||
|
} else {
|
||||||
|
SCRIPT_RETURN(in->itemCount());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// filtering items from a list
|
// filtering items from a list
|
||||||
@@ -465,7 +480,7 @@ ScriptValueP filter_rule(Context& ctx) {
|
|||||||
SCRIPT_FUNCTION(filter_rule) {
|
SCRIPT_FUNCTION(filter_rule) {
|
||||||
return filter_rule(ctx);
|
return filter_rule(ctx);
|
||||||
}
|
}
|
||||||
SCRIPT_FUNCTION(filter) {
|
SCRIPT_FUNCTION(filter_text) {
|
||||||
return filter_rule(ctx)->eval(ctx);
|
return filter_rule(ctx)->eval(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -704,7 +719,7 @@ void init_script_basic_functions(Context& ctx) {
|
|||||||
ctx.setVariable(_("keyword usage"), script_keyword_usage);
|
ctx.setVariable(_("keyword usage"), script_keyword_usage);
|
||||||
// advanced string rules
|
// advanced string rules
|
||||||
ctx.setVariable(_("replace"), script_replace);
|
ctx.setVariable(_("replace"), script_replace);
|
||||||
ctx.setVariable(_("filter"), script_filter);
|
ctx.setVariable(_("filter text"), script_filter_text);
|
||||||
ctx.setVariable(_("match"), script_match);
|
ctx.setVariable(_("match"), script_match);
|
||||||
ctx.setVariable(_("sort"), script_sort);
|
ctx.setVariable(_("sort"), script_sort);
|
||||||
ctx.setVariable(_("sort list"), script_sort);
|
ctx.setVariable(_("sort list"), script_sort);
|
||||||
|
|||||||
@@ -225,7 +225,8 @@ String to_html(const String& str_in, const SymbolFontP& symbol_font, double symb
|
|||||||
if (symbol.opened > 0 && symbol_font) {
|
if (symbol.opened > 0 && symbol_font) {
|
||||||
symbols += c; // write as symbols instead
|
symbols += c; // write as symbols instead
|
||||||
} else {
|
} else {
|
||||||
if (c == _('\1')) { // escape <
|
c = untag_char(c);
|
||||||
|
if (c == _('<')) { // escape <
|
||||||
ret += _("<");
|
ret += _("<");
|
||||||
} else if (c == _('&')) { // escape &
|
} else if (c == _('&')) { // escape &
|
||||||
ret += _("&");
|
ret += _("&");
|
||||||
@@ -314,11 +315,7 @@ String to_bbcode(const String& str_in) {
|
|||||||
// if (symbol.opened > 0 && symbol_font) {
|
// if (symbol.opened > 0 && symbol_font) {
|
||||||
// symbols += c; // write as symbols instead
|
// symbols += c; // write as symbols instead
|
||||||
// } else {
|
// } else {
|
||||||
if (c == _('\1')) { // unescape <
|
ret += untag_char(c);
|
||||||
ret += _("<");
|
|
||||||
} else {
|
|
||||||
ret += c;
|
|
||||||
}
|
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -229,7 +229,8 @@ void SetScriptManager::updateStyles(Context& ctx, const IndexMap<FieldP,StyleP>&
|
|||||||
s->tellListeners(only_content_dependent);
|
s->tellListeners(only_content_dependent);
|
||||||
}
|
}
|
||||||
} catch (const ScriptError& e) {
|
} catch (const ScriptError& e) {
|
||||||
handle_error(ScriptError(e.what() + _("\n while updating styles for '") + s->fieldP->name + _("'")));
|
// NOTE: don't handle errors now, we are likely in an onPaint handler
|
||||||
|
handle_error(ScriptError(e.what() + _("\n while updating styles for '") + s->fieldP->name + _("'")), false, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -267,7 +268,7 @@ void SetScriptManager::updateAll() {
|
|||||||
try {
|
try {
|
||||||
v->update(ctx);
|
v->update(ctx);
|
||||||
} catch (const ScriptError& e) {
|
} catch (const ScriptError& e) {
|
||||||
handle_error(ScriptError(e.what() + _("\n while updating set value '") + v->fieldP->name + _("'")));
|
handle_error(ScriptError(e.what() + _("\n while updating set value '") + v->fieldP->name + _("'")), false, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// update card data of all cards
|
// update card data of all cards
|
||||||
@@ -277,7 +278,7 @@ void SetScriptManager::updateAll() {
|
|||||||
try {
|
try {
|
||||||
v->update(ctx);
|
v->update(ctx);
|
||||||
} catch (const ScriptError& e) {
|
} catch (const ScriptError& e) {
|
||||||
handle_error(ScriptError(e.what() + _("\n while updating card value '") + v->fieldP->name + _("'")));
|
handle_error(ScriptError(e.what() + _("\n while updating card value '") + v->fieldP->name + _("'")), false, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -307,11 +308,11 @@ void SetScriptManager::updateToUpdate(const ToUpdate& u, deque<ToUpdate>& to_upd
|
|||||||
Age age = u.value->last_script_update;
|
Age age = u.value->last_script_update;
|
||||||
if (starting_age < age) return; // this value was already updated
|
if (starting_age < age) return; // this value was already updated
|
||||||
Context& ctx = getContext(u.card);
|
Context& ctx = getContext(u.card);
|
||||||
bool changes;
|
bool changes = false;
|
||||||
try {
|
try {
|
||||||
changes = u.value->update(ctx);
|
changes = u.value->update(ctx);
|
||||||
} catch (const ScriptError& e) {
|
} catch (const ScriptError& e) {
|
||||||
handle_error(ScriptError(e.what() + _("\n while updating value '") + u.value->fieldP->name + _("'")));
|
handle_error(ScriptError(e.what() + _("\n while updating value '") + u.value->fieldP->name + _("'")), false, true);
|
||||||
}
|
}
|
||||||
if (changes) {
|
if (changes) {
|
||||||
// changed, send event
|
// changed, send event
|
||||||
|
|||||||
@@ -19,8 +19,10 @@ template <typename T>
|
|||||||
class OrderCache : public IntrusivePtrBase<OrderCache<T> > {
|
class OrderCache : public IntrusivePtrBase<OrderCache<T> > {
|
||||||
public:
|
public:
|
||||||
/// Initialize the order cache, ordering the keys by their string values from the other vector
|
/// Initialize the order cache, ordering the keys by their string values from the other vector
|
||||||
/** @pre keys.size() == values.size() */
|
/** Optionally filter the list using a vector of booleans of items to keep (note: vector<bool> is evil)
|
||||||
OrderCache(const vector<T>& keys, const vector<String>& values);
|
* @pre keys.size() == values.size()
|
||||||
|
*/
|
||||||
|
OrderCache(const vector<T>& keys, const vector<String>& values, vector<int>* keep = nullptr);
|
||||||
|
|
||||||
/// Find the position of the given key in the cache, returns -1 if not found
|
/// Find the position of the given key in the cache, returns -1 if not found
|
||||||
int find(const T& key) const;
|
int find(const T& key) const;
|
||||||
@@ -52,13 +54,16 @@ struct OrderCache<T>::CompareValues {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
OrderCache<T>::OrderCache(const vector<T>& keys, const vector<String>& values) {
|
OrderCache<T>::OrderCache(const vector<T>& keys, const vector<String>& values, vector<int>* keep) {
|
||||||
assert(keys.size() == values.size());
|
assert(keys.size() == values.size());
|
||||||
|
assert(!keep || keep->size() == keys.size());
|
||||||
// initialize positions, use pos to point back to the values vector
|
// initialize positions, use pos to point back to the values vector
|
||||||
positions.reserve(keys.size());
|
positions.reserve(keys.size());
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (typename vector<T>::const_iterator it = keys.begin() ; it != keys.end() ; ++it, ++i) {
|
for (typename vector<T>::const_iterator it = keys.begin() ; it != keys.end() ; ++it, ++i) {
|
||||||
positions.push_back(KV(&**it, i));
|
if (!keep || (*keep)[i]) {
|
||||||
|
positions.push_back(KV(&**it, i));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// sort the KVs by the values
|
// sort the KVs by the values
|
||||||
sort(positions.begin(), positions.end(), CompareValues(values));
|
sort(positions.begin(), positions.end(), CompareValues(values));
|
||||||
|
|||||||
+9
-7
@@ -68,6 +68,7 @@ void writeUTF8(wxTextOutputStream& stream, const String& str);
|
|||||||
#define RIGHT_SINGLE_QUOTE _('\x2019')
|
#define RIGHT_SINGLE_QUOTE _('\x2019')
|
||||||
#define LEFT_DOUBLE_QUOTE _('\x201C')
|
#define LEFT_DOUBLE_QUOTE _('\x201C')
|
||||||
#define RIGHT_DOUBLE_QUOTE _('\x201D')
|
#define RIGHT_DOUBLE_QUOTE _('\x201D')
|
||||||
|
#define CONNECTION_SPACE _('\xEB00') // in private use are, untags to ' '
|
||||||
#else
|
#else
|
||||||
#define LEFT_ANGLE_BRACKET _("<")
|
#define LEFT_ANGLE_BRACKET _("<")
|
||||||
#define RIGHT_ANGLE_BRACKET _(">")
|
#define RIGHT_ANGLE_BRACKET _(">")
|
||||||
@@ -75,18 +76,19 @@ void writeUTF8(wxTextOutputStream& stream, const String& str);
|
|||||||
#define RIGHT_SINGLE_QUOTE _('\'')
|
#define RIGHT_SINGLE_QUOTE _('\'')
|
||||||
#define LEFT_DOUBLE_QUOTE _('\"')
|
#define LEFT_DOUBLE_QUOTE _('\"')
|
||||||
#define RIGHT_DOUBLE_QUOTE _('\"')
|
#define RIGHT_DOUBLE_QUOTE _('\"')
|
||||||
|
#define CONNECTION_SPACE _(' ') // too bad
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Char functions
|
// ----------------------------------------------------------------------------- : Char functions
|
||||||
|
|
||||||
// Character set tests
|
// Character set tests
|
||||||
inline bool isSpace(Char c) { return IF_UNICODE( iswspace(c) , isspace(c) ); }
|
inline bool isSpace(Char c) { return IF_UNICODE( iswspace(c) , isspace((unsigned char)c) ) || c == CONNECTION_SPACE; }
|
||||||
inline bool isAlpha(Char c) { return IF_UNICODE( iswalpha(c) , isalpha(c) ); }
|
inline bool isAlpha(Char c) { return IF_UNICODE( iswalpha(c) , isalpha((unsigned char)c) ); }
|
||||||
inline bool isDigit(Char c) { return IF_UNICODE( iswdigit(c) , isdigit(c) ); }
|
inline bool isDigit(Char c) { return IF_UNICODE( iswdigit(c) , isdigit((unsigned char)c) ); }
|
||||||
inline bool isAlnum(Char c) { return IF_UNICODE( iswalnum(c) , isalnum(c) ); }
|
inline bool isAlnum(Char c) { return IF_UNICODE( iswalnum(c) , isalnum((unsigned char)c) ); }
|
||||||
inline bool isUpper(Char c) { return IF_UNICODE( iswupper(c) , isupper(c) ); }
|
inline bool isUpper(Char c) { return IF_UNICODE( iswupper(c) , isupper((unsigned char)c) ); }
|
||||||
inline bool isLower(Char c) { return IF_UNICODE( iswlower(c) , islower(c) ); }
|
inline bool isLower(Char c) { return IF_UNICODE( iswlower(c) , islower((unsigned char)c) ); }
|
||||||
inline bool isPunct(Char c) { return IF_UNICODE( iswpunct(c) , ispunct(c) ); }
|
inline bool isPunct(Char c) { return IF_UNICODE( iswpunct(c) , ispunct((unsigned char)c) ); }
|
||||||
// Character conversions
|
// Character conversions
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#define CHAR_FUNCTIONS_ARE_SLOW
|
#define CHAR_FUNCTIONS_ARE_SLOW
|
||||||
|
|||||||
@@ -11,12 +11,24 @@
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Conversion to/from normal string
|
// ----------------------------------------------------------------------------- : Conversion to/from normal string
|
||||||
|
|
||||||
|
Char untag_char(Char c) {
|
||||||
|
if (c == _('\1')) return _('<');
|
||||||
|
else if (c == CONNECTION_SPACE) return _(' ');
|
||||||
|
else return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
Char tag_char(Char c) {
|
||||||
|
if (c == _('<')) return _('\1');
|
||||||
|
else return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
String untag(const String& str) {
|
String untag(const String& str) {
|
||||||
bool intag = false;
|
bool intag = false;
|
||||||
String ret; ret.reserve(str.size());
|
String ret; ret.reserve(str.size());
|
||||||
FOR_EACH_CONST(c, str) {
|
FOR_EACH_CONST(c, str) {
|
||||||
if (c==_('<')) intag = true;
|
if (c==_('<')) intag = true;
|
||||||
if (!intag) ret += c==_('\1') ? _('<') : c;
|
if (!intag) ret += untag_char(c);
|
||||||
if (c==_('>')) intag = false;
|
if (c==_('>')) intag = false;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
@@ -40,8 +52,7 @@ String untag_hide_sep(const String& str) {
|
|||||||
String escape(const String& str) {
|
String escape(const String& str) {
|
||||||
String ret; ret.reserve(str.size());
|
String ret; ret.reserve(str.size());
|
||||||
FOR_EACH_CONST(c, str) {
|
FOR_EACH_CONST(c, str) {
|
||||||
if (c==_('<')) ret += _('\1');
|
ret += tag_char(c);
|
||||||
else ret += c;
|
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,9 @@
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Conversion to/from normal string
|
// ----------------------------------------------------------------------------- : Conversion to/from normal string
|
||||||
|
|
||||||
|
Char untag_char(Char c);
|
||||||
|
Char tag_char(Char c);
|
||||||
|
|
||||||
/// Remove all tags from a string and convert escaped '<' back to normal '<'
|
/// Remove all tags from a string and convert escaped '<' back to normal '<'
|
||||||
/** e.g. "<sym>R</> something <i>(note)</>"
|
/** e.g. "<sym>R</> something <i>(note)</>"
|
||||||
* becomes "R something (note)"
|
* becomes "R something (note)"
|
||||||
|
|||||||
Reference in New Issue
Block a user