Commit 0e337ff9 authored by twanvl's avatar twanvl

Support for 2d bar graphs;

separator_after for keywords;
Slightly more advanced english_plural/singular;
Windows uninstaller will remove app data
parent 986a6a2c
...@@ -518,6 +518,9 @@ error: ...@@ -518,6 +518,9 @@ error:
# Update checking # Update checking
checking updates failed: Checking updates failed. checking updates failed: Checking updates failed.
no updates: There are no available updates. no updates: There are no available updates.
# Stats panel
dimension not found: There is no statistics dimension '%s'
############################################################## Types used in scripts / shape names ############################################################## Types used in scripts / shape names
type: type:
......
...@@ -152,14 +152,20 @@ init script: ...@@ -152,14 +152,20 @@ init script:
}; };
# replaces — correctly # replaces — correctly
alternative_cost := replace_rule(match:"\\.$", replace:"") + replace_rule(match:"^[A-Z]", replace: { to_lower() })
add := "" # default is nothing add := "" # default is nothing
for_mana_costs := format_cost := { for_mana_costs := format_cost := {
if input.separator=="—" then if input.separator_before == "—" then
"<param-cost>{alternative_cost(input.param)}</param-cost>" "<param-cost>{input.param}</param-cost>"
else else
"<param-mana>{add}{input.param}</param-mana>" "<param-mana>{add}{input.param}</param-mana>"
} }
alternative_cost := replace_rule(match:"^[A-Z]", replace: { to_lower() })
format_alt_cost := {
if input.separator_before == "—" then
alternative_cost(input.param)
else
input.param
}
long_dash := replace_rule(match:"-", replace:"—") long_dash := replace_rule(match:"-", replace:"—")
# Utilities for keywords # Utilities for keywords
has_cc := { card.casting_cost != "" } has_cc := { card.casting_cost != "" }
...@@ -256,8 +262,11 @@ init script: ...@@ -256,8 +262,11 @@ init script:
replace: "Æ") + replace: "Æ") +
# step 2 : longdash for keywords # step 2 : longdash for keywords
replace_rule( replace_rule(
match: "--| - ", match: "--",
replace: "—") replace: "—") +
replace_rule(
match: " - ",
replace: " — ")
#character filter for copyright line #character filter for copyright line
copyright_filter := copyright_filter :=
...@@ -955,7 +964,7 @@ card field: ...@@ -955,7 +964,7 @@ card field:
############################################################## Statistics categories ############################################################## Statistics categories
statistics dimension: statistics dimension:
name: card color name: card color2
script: primary_card_color(card.card_color) script: primary_card_color(card.card_color)
icon: stats/card_color.png icon: stats/card_color.png
colors: colors:
...@@ -994,10 +1003,10 @@ statistics dimension: ...@@ -994,10 +1003,10 @@ statistics dimension:
# numeric: true # numeric: true
# icon: stats/toughness.png # icon: stats/toughness.png
#statistics category: statistics category:
# name: color / rarity name: color / rarity
# dimension: card_color dimension: card color2
# dimension: rarity dimension: rarity
#statistics category: #statistics category:
# name: power / toughness # name: power / toughness
...@@ -1095,6 +1104,7 @@ pack type: ...@@ -1095,6 +1104,7 @@ pack type:
has keywords: true has keywords: true
keyword match script: name_filter(value)
#keyword preview: {keyword} <i>({reminder})</i> #keyword preview: {keyword} <i>({reminder})</i>
keyword mode: keyword mode:
...@@ -1122,6 +1132,7 @@ keyword parameter type: ...@@ -1122,6 +1132,7 @@ keyword parameter type:
name: cost name: cost
match: [ ][STXYZ0-9WUBRG/|]*|[-—][^(\n]* match: [ ][STXYZ0-9WUBRG/|]*|[-—][^(\n]*
separator before is: [ —-] separator before is: [ —-]
separator after is: [.]
optional: false optional: false
# note: the separator is part of match # note: the separator is part of match
refer script: refer script:
...@@ -1136,6 +1147,7 @@ keyword parameter type: ...@@ -1136,6 +1147,7 @@ keyword parameter type:
name: add "pay " for mana costs name: add "pay " for mana costs
description: When using mana only costs, words the reminder text as "pay <cost>" description: When using mana only costs, words the reminder text as "pay <cost>"
script: \{for_mana_costs(add:"pay ",{input})\} script: \{for_mana_costs(add:"pay ",{input})\}
reminder script: format_alt_cost()
separator script: long_dash() separator script: long_dash()
keyword parameter type: keyword parameter type:
name: number name: number
...@@ -1161,7 +1173,7 @@ keyword parameter type: ...@@ -1161,7 +1173,7 @@ keyword parameter type:
match: [^(,\n]+ match: [^(,\n]+
keyword parameter type: keyword parameter type:
name: name name: name
match: [^(.,\n]+ match: [^(.,\n-—]+
keyword parameter type: keyword parameter type:
name: prefix name: prefix
description: Prefix for things like "<something>walk" description: Prefix for things like "<something>walk"
......
...@@ -38,6 +38,7 @@ IMPLEMENT_REFLECTION(KeywordParam) { ...@@ -38,6 +38,7 @@ IMPLEMENT_REFLECTION(KeywordParam) {
REFLECT(optional); REFLECT(optional);
REFLECT(match); REFLECT(match);
REFLECT(separator_before_is); REFLECT(separator_before_is);
REFLECT(separator_after_is);
REFLECT(eat_separator); REFLECT(eat_separator);
REFLECT(script); REFLECT(script);
REFLECT(reminder_script); REFLECT(reminder_script);
...@@ -119,12 +120,20 @@ String KeywordParam::make_separator_before() const { ...@@ -119,12 +120,20 @@ String KeywordParam::make_separator_before() const {
return ret; return ret;
}*/ }*/
void KeywordParam::compile() { void KeywordParam::compile() {
// compile separator_before
if (!separator_before_is.empty() && !separator_before_re.IsValid()) { if (!separator_before_is.empty() && !separator_before_re.IsValid()) {
separator_before_re.Compile(_("^") + separator_before_is, wxRE_ADVANCED); separator_before_re.Compile(_("^") + separator_before_is, wxRE_ADVANCED);
if (eat_separator) { if (eat_separator) {
separator_before_eat.Compile(separator_before_is + _("$"), wxRE_ADVANCED); separator_before_eat.Compile(separator_before_is + _("$"), wxRE_ADVANCED);
} }
} }
// compile separator_after
if (!separator_after_is.empty() && !separator_after_re.IsValid()) {
separator_after_re.Compile(separator_after_is + _("$"), wxRE_ADVANCED);
if (eat_separator) {
separator_after_eat.Compile(_("^") + separator_after_is, wxRE_ADVANCED);
}
}
} }
size_t Keyword::findMode(const vector<KeywordModeP>& modes) const { size_t Keyword::findMode(const vector<KeywordModeP>& modes) const {
...@@ -239,6 +248,12 @@ void Keyword::prepare(const vector<KeywordParamP>& param_types, bool force) { ...@@ -239,6 +248,12 @@ void Keyword::prepare(const vector<KeywordParamP>& param_types, bool force) {
// modify regex : match parameter // modify regex : match parameter
regex += _("(") + make_non_capturing(p->match) + (p->optional ? _(")?") : _(")")); regex += _("(") + make_non_capturing(p->match) + (p->optional ? _(")?") : _(")"));
i = skip_tag(match, end); i = skip_tag(match, end);
// eat separator_after?
if (p->separator_after_eat.IsValid() && p->separator_after_eat.Matches(match.substr(i))) {
size_t start, len;
p->separator_before_eat.GetMatch(&start, &len);
i += start + len;
}
} else { } else {
text += c; text += c;
i++; i++;
...@@ -347,22 +362,28 @@ void KeywordDatabase::add(const Keyword& kw) { ...@@ -347,22 +362,28 @@ void KeywordDatabase::add(const Keyword& kw) {
for (size_t i = 0 ; i < kw.match.size() ;) { for (size_t i = 0 ; i < kw.match.size() ;) {
Char c = kw.match.GetChar(i); Char c = kw.match.GetChar(i);
if (is_substr(kw.match, i, _("<atom-param"))) { if (is_substr(kw.match, i, _("<atom-param"))) {
i = match_close_tag_end(kw.match, i);
// parameter, is there a separator we should eat? // parameter, is there a separator we should eat?
if (param < kw.parameters.size()) { if (param < kw.parameters.size()) {
wxRegEx& sep = kw.parameters[param]->separator_before_eat; wxRegEx& sep_before = kw.parameters[param]->separator_before_eat;
if (sep.IsValid() && sep.Matches(text)) { wxRegEx& sep_after = kw.parameters[param]->separator_after_eat;
if (sep_before.IsValid() && sep_before.Matches(text)) {
// remove the separator from the text to prevent duplicates // remove the separator from the text to prevent duplicates
size_t start, len; size_t start, len;
sep.GetMatch(&start, &len); sep_before.GetMatch(&start, &len);
text = text.substr(0, start); text = text.substr(0, start);
} }
if (sep_after.IsValid() && sep_after.Matches(kw.match.substr(i))) {
size_t start, len;
sep_after.GetMatch(&start, &len);
i += start + len;
}
} }
++param; ++param;
// match anything // match anything
cur = cur->insert(text); cur = cur->insert(text);
text.clear(); text.clear();
cur = cur->insertAnyStar(); cur = cur->insertAnyStar();
i = match_close_tag_end(kw.match, i);
} else { } else {
text += c; text += c;
i++; i++;
...@@ -501,27 +522,40 @@ String KeywordDatabase::expand(const String& text, ...@@ -501,27 +522,40 @@ String KeywordDatabase::expand(const String& text,
// parameter // parameter
KeywordParam& kwp = *kw->parameters[j/2-1]; KeywordParam& kwp = *kw->parameters[j/2-1];
String param = untagged.substr(start_u, len_u); // untagged version String param = untagged.substr(start_u, len_u); // untagged version
// strip separator // strip separator_before
String separator; String separator_before, separator_after;
if (kwp.separator_before_re.IsValid()) { if (kwp.separator_before_re.IsValid() && kwp.separator_before_re.Matches(param)) {
if (kwp.separator_before_re.Matches(param)) { size_t s_start, s_len; // start should be 0
size_t s_start, s_len; // start should be 0 kwp.separator_before_re.GetMatch(&s_start, &s_len);
kwp.separator_before_re.GetMatch(&s_start, &s_len); separator_before = param.substr(0, s_start + s_len);
separator = param.substr(0, s_start + s_len); param = param.substr(s_start + s_len);
param = param.substr(s_start + s_len); // strip from tagged version
// strip from tagged version size_t end_t = untagged_to_index(part, s_start + s_len, false);
size_t end_t = untagged_to_index(part, s_start + s_len, false); part = get_tags(part, 0, end_t, true, true) + part.substr(end_t);
part = get_tags(part, 0, end_t, true, true) + part.substr(end_t); // transform?
// transform? if (kwp.separator_script) {
if (kwp.separator_script) { ctx.setVariable(_("input"), to_script(separator_before));
ctx.setVariable(_("input"), to_script(separator)); separator_before = kwp.separator_script.invoke(ctx)->toString();
separator = kwp.separator_script.invoke(ctx)->toString(); }
} }
// strip separator_after
if (kwp.separator_after_re.IsValid() && kwp.separator_after_re.Matches(param)) {
size_t s_start, s_len; // start + len should be param.size()
kwp.separator_after_re.GetMatch(&s_start, &s_len);
separator_after = param.substr(s_start);
param = param.substr(0, s_start);
// strip from tagged version
size_t start_t = untagged_to_index(part, s_start, false);
part = part.substr(0, start_t) + get_tags(part, start_t, part.size(), true, true);
// transform?
if (kwp.separator_script) {
ctx.setVariable(_("input"), to_script(separator_after));
separator_after = kwp.separator_script.invoke(ctx)->toString();
} }
} }
// to script // to script
KeywordParamValueP script_param(new KeywordParamValue(kwp.name, separator, param)); KeywordParamValueP script_param(new KeywordParamValue(kwp.name, separator_before, separator_after, param));
KeywordParamValueP script_part (new KeywordParamValue(kwp.name, separator, part)); KeywordParamValueP script_part (new KeywordParamValue(kwp.name, separator_before, separator_after, part));
// process param // process param
if (param.empty()) { if (param.empty()) {
// placeholder // placeholder
...@@ -538,7 +572,7 @@ String KeywordDatabase::expand(const String& text, ...@@ -538,7 +572,7 @@ String KeywordDatabase::expand(const String& text,
script_param->value = kwp.reminder_script.invoke(ctx)->toString(); script_param->value = kwp.reminder_script.invoke(ctx)->toString();
} }
} }
part = separator + script_part->toString(); part = separator_before + script_part->toString() + separator_after;
ctx.setVariable(String(_("param")) << (int)(j/2), script_param); ctx.setVariable(String(_("param")) << (int)(j/2), script_param);
} }
total += part; total += part;
...@@ -601,9 +635,10 @@ KeywordParamValue::operator String() const { ...@@ -601,9 +635,10 @@ KeywordParamValue::operator String() const {
return _("<param-") + safe_type + _(">") + value + _("</param-") + safe_type + _(">"); return _("<param-") + safe_type + _(">") + value + _("</param-") + safe_type + _(">");
} }
ScriptValueP KeywordParamValue::getMember(const String& name) const { ScriptValueP KeywordParamValue::getMember(const String& name) const {
if (name == _("type")) return to_script(type_name); if (name == _("type")) return to_script(type_name);
if (name == _("separator")) return to_script(separator); if (name == _("separator before")) return to_script(separator_before);
if (name == _("value")) return to_script(value); if (name == _("separator after")) return to_script(separator_after);
if (name == _("param")) return to_script(value); if (name == _("value")) return to_script(value);
if (name == _("param")) return to_script(value);
return ScriptValue::getMember(name); return ScriptValue::getMember(name);
} }
...@@ -42,6 +42,9 @@ class KeywordParam : public IntrusivePtrBase<KeywordParam> { ...@@ -42,6 +42,9 @@ class KeywordParam : public IntrusivePtrBase<KeywordParam> {
String separator_before_is; ///< Regular expression of separator before the param String separator_before_is; ///< Regular expression of separator before the param
wxRegEx separator_before_re; ///< Regular expression of separator before the param, compiled wxRegEx separator_before_re; ///< Regular expression of separator before the param, compiled
wxRegEx separator_before_eat;///< Regular expression of separator before the param, if eat_separator wxRegEx separator_before_eat;///< Regular expression of separator before the param, if eat_separator
String separator_after_is; ///< Regular expression of separator after the param
wxRegEx separator_after_re; ///< Regular expression of separator after the param, compiled
wxRegEx separator_after_eat; ///< Regular expression of separator after the param, if eat_separator
bool eat_separator; ///< Remove the separator from the match string if it also appears there (prevent duplicates) bool eat_separator; ///< Remove the separator from the match string if it also appears there (prevent duplicates)
OptionalScript script; ///< Transformation of the value for showing as the parameter OptionalScript script; ///< Transformation of the value for showing as the parameter
OptionalScript reminder_script; ///< Transformation of the value for showing in the reminder text OptionalScript reminder_script; ///< Transformation of the value for showing in the reminder text
...@@ -53,7 +56,7 @@ class KeywordParam : public IntrusivePtrBase<KeywordParam> { ...@@ -53,7 +56,7 @@ class KeywordParam : public IntrusivePtrBase<KeywordParam> {
//% /** This tries to decode the separator_before_is regex */ //% /** This tries to decode the separator_before_is regex */
//% String make_separator_before() const; //% String make_separator_before() const;
/// Compile regexes /// Compile regexes for separators
void compile(); void compile();
DECLARE_REFLECTION(); DECLARE_REFLECTION();
...@@ -150,11 +153,11 @@ class KeywordDatabase { ...@@ -150,11 +153,11 @@ class KeywordDatabase {
/// A script value containing the value of a keyword parameter /// A script value containing the value of a keyword parameter
class KeywordParamValue : public ScriptValue { class KeywordParamValue : public ScriptValue {
public: public:
KeywordParamValue(const String& type, const String& separator, const String& value) KeywordParamValue(const String& type, const String& separator_before, const String& separator_after, const String& value)
: type_name(type), separator(separator), value(value) : type_name(type), separator_before(separator_before), separator_after(separator_after), value(value)
{} {}
String type_name; String type_name;
String separator; String separator_before, separator_after;
String value; String value;
virtual ScriptType type() const; virtual ScriptType type() const;
......
...@@ -10,6 +10,9 @@ ...@@ -10,6 +10,9 @@
#include <data/field.hpp> #include <data/field.hpp>
#include <data/field/choice.hpp> #include <data/field/choice.hpp>
DECLARE_TYPEOF_COLLECTION(String);
DECLARE_TYPEOF_COLLECTION(StatsDimensionP);
// ----------------------------------------------------------------------------- : Statistics dimension // ----------------------------------------------------------------------------- : Statistics dimension
StatsDimension::StatsDimension() StatsDimension::StatsDimension()
...@@ -68,6 +71,7 @@ StatsCategory::StatsCategory(const StatsDimensionP& dim) ...@@ -68,6 +71,7 @@ StatsCategory::StatsCategory(const StatsDimensionP& dim)
IMPLEMENT_REFLECTION_ENUM(GraphType) { IMPLEMENT_REFLECTION_ENUM(GraphType) {
VALUE_N("bar", GRAPH_TYPE_BAR); VALUE_N("bar", GRAPH_TYPE_BAR);
VALUE_N("stack", GRAPH_TYPE_STACK);
VALUE_N("pie", GRAPH_TYPE_PIE); VALUE_N("pie", GRAPH_TYPE_PIE);
VALUE_N("scatter", GRAPH_TYPE_SCATTER); VALUE_N("scatter", GRAPH_TYPE_SCATTER);
} }
...@@ -78,6 +82,24 @@ IMPLEMENT_REFLECTION_NO_GET_MEMBER(StatsCategory) { ...@@ -78,6 +82,24 @@ IMPLEMENT_REFLECTION_NO_GET_MEMBER(StatsCategory) {
REFLECT(description); REFLECT(description);
REFLECT_N("icon", icon_filename); REFLECT_N("icon", icon_filename);
REFLECT(type); REFLECT(type);
REFLECT(dimensions); REFLECT_N("dimensions", dimension_names);
} }
} }
void StatsCategory::find_dimensions(const vector<StatsDimensionP>& available) {
if (!dimensions.empty()) return;
FOR_EACH_CONST(n, dimension_names) {
StatsDimensionP dim;
FOR_EACH_CONST(d, available) {
if (d->name == n) {
dim = d;
break;
}
}
if (!dim) {
handle_error(_ERROR_1_("dimension not found",dim),false);
} else {
dimensions.push_back(dim);
}
}
}
\ No newline at end of file
...@@ -43,6 +43,7 @@ class StatsDimension : public IntrusivePtrBase<StatsDimension> { ...@@ -43,6 +43,7 @@ class StatsDimension : public IntrusivePtrBase<StatsDimension> {
/// Types of graphs /// Types of graphs
enum GraphType enum GraphType
{ GRAPH_TYPE_BAR { GRAPH_TYPE_BAR
, GRAPH_TYPE_STACK
, GRAPH_TYPE_PIE , GRAPH_TYPE_PIE
, GRAPH_TYPE_SCATTER , GRAPH_TYPE_SCATTER
}; };
...@@ -59,9 +60,13 @@ class StatsCategory : public IntrusivePtrBase<StatsCategory> { ...@@ -59,9 +60,13 @@ class StatsCategory : public IntrusivePtrBase<StatsCategory> {
String description; ///< Description, used in status bar String description; ///< Description, used in status bar
String icon_filename; ///< Icon for lists String icon_filename; ///< Icon for lists
Bitmap icon; ///< The loaded icon (optional of course) Bitmap icon; ///< The loaded icon (optional of course)
vector<StatsDimensionP> dimensions; ///< The dimensions to use, higher dimensions may be null vector<String> dimension_names;///< Names of the dimensions to use
vector<StatsDimensionP> dimensions; ///< Actual dimensions
GraphType type; ///< Type of graph to use GraphType type; ///< Type of graph to use
/// Initialize dimensions from dimension_names
void find_dimensions(const vector<StatsDimensionP>& available);
DECLARE_REFLECTION(); DECLARE_REFLECTION();
}; };
......
This diff is collapsed.
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
// ----------------------------------------------------------------------------- : Includes // ----------------------------------------------------------------------------- : Includes
#include <util/prec.hpp> #include <util/prec.hpp>
#include <util/alignment.hpp>
#include <util/rotation.hpp> #include <util/rotation.hpp>
DECLARE_POINTER_TYPE(GraphAxis); DECLARE_POINTER_TYPE(GraphAxis);
...@@ -90,9 +91,12 @@ class GraphData : public IntrusivePtrBase<GraphData> { ...@@ -90,9 +91,12 @@ class GraphData : public IntrusivePtrBase<GraphData> {
public: public:
GraphData(const GraphDataPre&); GraphData(const GraphDataPre&);
vector<GraphAxisP> axes; ///< The axes in the data vector<GraphAxisP> axes; ///< The axes in the data
vector<UInt> values; ///< Multi dimensional (dim = axes.size()) array of values vector<vector<int> > values; ///< All elements, with the group number for each axis, or -1
UInt size; ///< Total number of elements UInt size; ///< Total number of elements
/// Create a cross table for two axes
void crossAxis(size_t axis1, size_t axis2, vector<UInt>& out) const;
}; };
...@@ -138,6 +142,18 @@ class Graph1D : public Graph { ...@@ -138,6 +142,18 @@ class Graph1D : public Graph {
inline GraphAxis& axis_data() const { return *data->axes.at(axis); } inline GraphAxis& axis_data() const { return *data->axes.at(axis); }
}; };
/// Base class for 2 dimensional graph components
class Graph2D : public Graph {
public:
inline Graph2D(size_t axis1, size_t axis2) : axis1(axis1), axis2(axis2) {}
virtual void setData(const GraphDataP& d);
protected:
size_t axis1, axis2;
vector<UInt> values; // axis1.size * axis2.size array
inline GraphAxis& axis1_data() const { return *data->axes.at(axis1); }
inline GraphAxis& axis2_data() const { return *data->axes.at(axis2); }
};
/// A bar graph /// A bar graph
class BarGraph : public Graph1D { class BarGraph : public Graph1D {
public: public:
...@@ -146,9 +162,13 @@ class BarGraph : public Graph1D { ...@@ -146,9 +162,13 @@ class BarGraph : public Graph1D {
virtual int findItem(const RealPoint& pos, const RealRect& rect) const; virtual int findItem(const RealPoint& pos, const RealRect& rect) const;
}; };
// TODO // A bar graph with stacked bars
//class BarGraph2D { class BarGraph2D : public Graph2D {
//}; public:
inline BarGraph2D(size_t axis_h, size_t axis_v) : Graph2D(axis_h, axis_v) {}
virtual void draw(RotatedDC& dc, const vector<int>& current, DrawLayer layer) const;
virtual bool findItem(const RealPoint& pos, const RealRect& rect, vector<int>& out) const;
};
/// A pie graph /// A pie graph
class PieGraph : public Graph1D { class PieGraph : public Graph1D {
...@@ -169,9 +189,20 @@ class GraphLegend : public Graph1D { ...@@ -169,9 +189,20 @@ class GraphLegend : public Graph1D {
//class GraphTable { //class GraphTable {
//}; //};
//class GraphAxis : public Graph1D { /// Draws a horizontal/vertical axis for group labels
// virtual void draw(RotatedDC& dc) const; class GraphLabelAxis : public Graph1D {
//}; public:
inline GraphLabelAxis(size_t axis, Direction direction, bool rotate = false, bool draw_lines = false)
: Graph1D(axis), direction(direction), rotate(rotate), draw_lines(draw_lines)
{}
virtual void draw(RotatedDC& dc, int current, DrawLayer layer) const;
virtual int findItem(const RealPoint& pos, const RealRect& rect) const;
private:
Direction direction;
int levels;
bool rotate;
bool draw_lines;
};
/// Draws an a vertical axis for counts /// Draws an a vertical axis for counts
class GraphValueAxis : public Graph1D { class GraphValueAxis : public Graph1D {
......
...@@ -147,6 +147,8 @@ void StatsPanel::onCategorySelect() { ...@@ -147,6 +147,8 @@ void StatsPanel::onCategorySelect() {
if (categories->hasSelection()) { if (categories->hasSelection()) {
StatsCategory& cat = categories->getSelection(); StatsCategory& cat = categories->getSelection();
GraphDataPre d; GraphDataPre d;
cat.find_dimensions(set->game->statistics_dimensions);
// create axes
FOR_EACH(dim, cat.dimensions) { FOR_EACH(dim, cat.dimensions) {
d.axes.push_back(new_intrusive4<GraphAxis>( d.axes.push_back(new_intrusive4<GraphAxis>(
dim->name, dim->name,
...@@ -156,6 +158,7 @@ void StatsPanel::onCategorySelect() { ...@@ -156,6 +158,7 @@ void StatsPanel::onCategorySelect() {
) )
); );
} }
// find values
FOR_EACH(card, set->cards) { FOR_EACH(card, set->cards) {
Context& ctx = set->getContext(card); Context& ctx = set->getContext(card);
GraphElementP e(new GraphElement); GraphElementP e(new GraphElement);
...@@ -173,6 +176,7 @@ void StatsPanel::onCategorySelect() { ...@@ -173,6 +176,7 @@ void StatsPanel::onCategorySelect() {
d.elements.push_back(e); d.elements.push_back(e);
} }
} }
// TODO graph->setLayout(cat.type)
graph->setData(d); graph->setData(d);
filterCards(); filterCards();
} }
......
...@@ -11,6 +11,16 @@ ...@@ -11,6 +11,16 @@
#include <util/tagged_string.hpp> #include <util/tagged_string.hpp>
#include <util/error.hpp> #include <util/error.hpp>
// ----------------------------------------------------------------------------- : Util
bool is_vowel(Char c) {
return c == _('a') || c == _('e') || c == _('i') || c == _('o') || c == _('u')
|| c == _('A') || c == _('E') || c == _('I') || c == _('O') || c == _('U');
}
inline bool is_constant(Char c) {
return !is_vowel(c);
}
// ----------------------------------------------------------------------------- : Numbers // ----------------------------------------------------------------------------- : Numbers
/// Write a number using words, for example 23 -> "twenty-three" /// Write a number using words, for example 23 -> "twenty-three"
...@@ -110,20 +120,41 @@ SCRIPT_FUNCTION(english_number_multiple) { ...@@ -110,20 +120,41 @@ SCRIPT_FUNCTION(english_number_multiple) {
String english_singular(const String& str) { String english_singular(const String& str) {
if (str.size() > 3 && is_substr(str, str.size()-3, _("ies"))) { if (str.size() > 3 && is_substr(str, str.size()-3, _("ies"))) {
return str.substr(0, str.size() - 3) + _("y"); return str.substr(0, str.size() - 3) + _("y");
} else if (str.size() > 3 && is_substr(str, str.size()-3, _("oes"))) {
return str.substr(0, str.size() - 2);
} else if (str.size() > 4 && is_substr(str, str.size()-4, _("ches"))) {
return str.substr(0, str.size() - 2);
} else if (str.size() > 4 && is_substr(str, str.size()-4, _("shes"))) {
return str.substr(0, str.size() - 2);
} else if (str.size() > 4 && is_substr(str, str.size()-4, _("sses"))) {
return str.substr(0, str.size() - 2);
} else if (str.size() > 5 && is_substr(str, str.size()-3, _("ves")) && (is_substr(str, str.size()-5, _("el")) || is_substr(str, str.size()-5, _("ar")) )) {
return str.substr(0, str.size() - 3) + _("f");
} else if (str.size() > 1 && str.GetChar(str.size() - 1) == _('s')) { } else if (str.size() > 1 && str.GetChar(str.size() - 1) == _('s')) {
return str.substr(0, str.size() - 1); return str.substr(0, str.size() - 1);
} else if (str.size() >= 3 && is_substr(str, str.size()-3, _("men"))) {
return str.substr(0, str.size() - 2) + _("an");
} else { } else {
return str; return str;
} }
} }
String english_plural(const String& str) { String english_plural(const String& str) {
if (str.size() > 1 && str.GetChar(str.size() - 1) == _('y')) { if (str.size() > 2) {
return str.substr(0, str.size() - 1) + _("ies"); Char a = str.GetChar(str.size() - 2);
} else if (str.size() > 1 && str.GetChar(str.size() - 1) == _('s')) { Char b = str.GetChar(str.size() - 1);
return str + _("es"); if (b == _('y') && is_constant(a)) {
} else { return str.substr(0, str.size() - 1) + _("ies");
return str + _("s"); } else if (b == _('o') && is_constant(a)) {
return str + _("es");
} else if ((a == _('s') || a == _('c')) && b == _('h')) {
return str + _("es");
} else if (b == _('s')) {
return str + _("es");
} else {
return str + _("s");
}
} }
return str + _("s");
} }
// script_english_singular/plural/singplur // script_english_singular/plural/singplur
...@@ -155,11 +186,6 @@ SCRIPT_FUNCTION(english_plural) { ...@@ -155,11 +186,6 @@ SCRIPT_FUNCTION(english_plural) {
// ----------------------------------------------------------------------------- : Hints // ----------------------------------------------------------------------------- : Hints
bool is_vowel(Char c) {
return c == _('a') || c == _('e') || c == _('i') || c == _('o') || c == _('u')
|| c == _('A') || c == _('E') || c == _('I') || c == _('O') || c == _('U');
}
/// Process english hints in the input string /// Process english hints in the input string
/** A hint is formed by /** A hint is formed by
* 1. an insertion of a parameter, <param-..>...</param->. * 1. an insertion of a parameter, <param-..>...</param->.
......
...@@ -57,7 +57,9 @@ RealPoint align_in_rect(Alignment align, const RealSize& to_align, const RealRec ...@@ -57,7 +57,9 @@ RealPoint align_in_rect(Alignment align, const RealSize& to_align, const RealRec
/// Direction to place something in /// Direction to place something in
enum Direction { enum Direction {
LEFT_TO_RIGHT, RIGHT_TO_LEFT, LEFT_TO_RIGHT, RIGHT_TO_LEFT,
TOP_TO_BOTTOM, BOTTOM_TO_TOP TOP_TO_BOTTOM, BOTTOM_TO_TOP,
HORIZONTAL = LEFT_TO_RIGHT,
VERTICAL = TOP_TO_BOTTOM
}; };
/// Move a point in a direction /// Move a point in a direction
......
...@@ -173,3 +173,8 @@ Root: HKCR; Subkey: "MagicSetEditor2Symbol\shell\open\command"; ValueType: strin ...@@ -173,3 +173,8 @@ Root: HKCR; Subkey: "MagicSetEditor2Symbol\shell\open\command"; ValueType: strin
[Run] [Run]
Filename: "{app}\mse.exe"; Description: "Start Magic Set Editor"; Flags: postinstall nowait skipifsilent unchecked Filename: "{app}\mse.exe"; Description: "Start Magic Set Editor"; Flags: postinstall nowait skipifsilent unchecked
; ------------------------------ : Uninstaller
[UninstallDelete]
Type: filesandordirs; Name: "{userappdata}\Magic Set Editor"
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment