mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-12 05:36:59 -04:00
Keyword usage can now be used for statistics
git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@517 0fc631ac-6414-0410-93d0-97cfa31319b6
This commit is contained in:
@@ -23,6 +23,7 @@ StatsDimension::StatsDimension()
|
|||||||
, position_hint(0)
|
, position_hint(0)
|
||||||
, numeric (false)
|
, numeric (false)
|
||||||
, show_empty (false)
|
, show_empty (false)
|
||||||
|
, split_list (false)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
StatsDimension::StatsDimension(const Field& field)
|
StatsDimension::StatsDimension(const Field& field)
|
||||||
@@ -33,6 +34,7 @@ StatsDimension::StatsDimension(const Field& field)
|
|||||||
, icon_filename(field.icon_filename)
|
, icon_filename(field.icon_filename)
|
||||||
, numeric (false)
|
, numeric (false)
|
||||||
, show_empty (false)
|
, show_empty (false)
|
||||||
|
, split_list (false)
|
||||||
{
|
{
|
||||||
// choice field?
|
// choice field?
|
||||||
const ChoiceField* choice_field = dynamic_cast<const ChoiceField*>(&field);
|
const ChoiceField* choice_field = dynamic_cast<const ChoiceField*>(&field);
|
||||||
@@ -72,6 +74,7 @@ IMPLEMENT_REFLECTION_NO_GET_MEMBER(StatsDimension) {
|
|||||||
REFLECT(script);
|
REFLECT(script);
|
||||||
REFLECT(numeric);
|
REFLECT(numeric);
|
||||||
REFLECT(show_empty);
|
REFLECT(show_empty);
|
||||||
|
REFLECT(split_list);
|
||||||
REFLECT(colors);
|
REFLECT(colors);
|
||||||
REFLECT(groups);
|
REFLECT(groups);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ class StatsDimension : public IntrusivePtrBase<StatsDimension> {
|
|||||||
OptionalScript script; ///< Script that determines the value(s)
|
OptionalScript script; ///< Script that determines the value(s)
|
||||||
bool numeric; ///< Are the values numeric? If so, they require special sorting
|
bool numeric; ///< Are the values numeric? If so, they require special sorting
|
||||||
bool show_empty; ///< Should "" be shown?
|
bool show_empty; ///< Should "" be shown?
|
||||||
|
bool split_list; ///< Split values into multiple ones separated by commas
|
||||||
map<String,Color> colors; ///< Colors for the categories
|
map<String,Color> colors; ///< Colors for the categories
|
||||||
vector<String> groups; ///< Order of the items
|
vector<String> groups; ///< Order of the items
|
||||||
|
|
||||||
|
|||||||
+30
-10
@@ -37,6 +37,24 @@ GraphElement::GraphElement(const String& v1, const String& v2) {
|
|||||||
values.push_back(v2);
|
values.push_back(v2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GraphDataPre::splitList(size_t axis) {
|
||||||
|
size_t count = elements.size(); // only the elements that were already there
|
||||||
|
for (size_t i = 0 ; i < count ; ++i) {
|
||||||
|
GraphElement& e = *elements[i];
|
||||||
|
String& v = e.values[axis];
|
||||||
|
size_t comma = v.find_first_of(_(','));
|
||||||
|
while (comma != String::npos) {
|
||||||
|
// split
|
||||||
|
GraphElementP e2(new GraphElement(e));
|
||||||
|
e2->values[axis] = v.substr(0,comma);
|
||||||
|
elements.push_back(e2);
|
||||||
|
if (is_substr(v, comma, _(", "))) ++comma; // skip space after it
|
||||||
|
v = v.substr(comma + 1);
|
||||||
|
comma = v.find_first_of(_(','));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
GraphData::GraphData(const GraphDataPre& d)
|
GraphData::GraphData(const GraphDataPre& d)
|
||||||
: axes(d.axes)
|
: axes(d.axes)
|
||||||
@@ -50,13 +68,12 @@ GraphData::GraphData(const GraphDataPre& d)
|
|||||||
FOR_EACH_CONST(e, d.elements) {
|
FOR_EACH_CONST(e, d.elements) {
|
||||||
counts[e->values[i]] += 1;
|
counts[e->values[i]] += 1;
|
||||||
}
|
}
|
||||||
// TODO: allow some ordering in the groups
|
|
||||||
if (a->numeric) {
|
if (a->numeric) {
|
||||||
// TODO: start at something other than 0?
|
// TODO: start at something other than 0?
|
||||||
// TODO: support fractions?
|
// TODO: support fractions?
|
||||||
size_t left = counts.size();
|
size_t left = counts.size();
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while (left) {
|
while (!counts.empty() && i < 100) {
|
||||||
String is = String() << i++;
|
String is = String() << i++;
|
||||||
map<String,UInt>::const_iterator it = counts.find(is);
|
map<String,UInt>::const_iterator it = counts.find(is);
|
||||||
if (it == counts.end()) {
|
if (it == counts.end()) {
|
||||||
@@ -66,16 +83,19 @@ GraphData::GraphData(const GraphDataPre& d)
|
|||||||
a->groups.push_back(GraphGroup(is, it->second));
|
a->groups.push_back(GraphGroup(is, it->second));
|
||||||
a->max = max(a->max, it->second);
|
a->max = max(a->max, it->second);
|
||||||
a->total += it->second;
|
a->total += it->second;
|
||||||
|
counts.erase(is);
|
||||||
left--;
|
left--;
|
||||||
}
|
}
|
||||||
if (i > 100) {
|
}
|
||||||
// prevent infinite loops if there are non-numeric entries
|
// Also keep non-numeric entries
|
||||||
// drop empty tail
|
FOR_EACH(c, counts) {
|
||||||
while (a->groups.size() > 1 && a->groups.back().size == 0) {
|
a->groups.push_back(GraphGroup(c.first, c.second));
|
||||||
a->groups.pop_back();
|
a->max = max(a->max, c.second);
|
||||||
}
|
a->total += c.second;
|
||||||
break;
|
}
|
||||||
}
|
// drop empty tail
|
||||||
|
while (a->groups.size() > 1 && a->groups.back().size == 0) {
|
||||||
|
a->groups.pop_back();
|
||||||
}
|
}
|
||||||
} else if (a->order) {
|
} else if (a->order) {
|
||||||
// specific group order
|
// specific group order
|
||||||
|
|||||||
@@ -87,6 +87,8 @@ class GraphDataPre {
|
|||||||
public:
|
public:
|
||||||
vector<GraphAxisP> axes;
|
vector<GraphAxisP> axes;
|
||||||
vector<GraphElementP> elements;
|
vector<GraphElementP> elements;
|
||||||
|
/// Split compound elements, "a,b,c" -> "a" and "b" and "c"
|
||||||
|
void splitList(size_t axis);
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Data to be displayed in a graph
|
/// Data to be displayed in a graph
|
||||||
|
|||||||
@@ -147,6 +147,8 @@ void StatsPanel::onCommand(int id) {
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Filtering card list
|
// ----------------------------------------------------------------------------- : Filtering card list
|
||||||
|
|
||||||
|
bool chosen(const String& choice, const String& input);
|
||||||
|
|
||||||
class StatsFilter : public CardListFilter {
|
class StatsFilter : public CardListFilter {
|
||||||
public:
|
public:
|
||||||
StatsFilter(Set& set)
|
StatsFilter(Set& set)
|
||||||
@@ -155,7 +157,13 @@ class StatsFilter : public CardListFilter {
|
|||||||
virtual bool keep(const CardP& card) {
|
virtual bool keep(const CardP& card) {
|
||||||
Context& ctx = set.getContext(card);
|
Context& ctx = set.getContext(card);
|
||||||
FOR_EACH(v, values) {
|
FOR_EACH(v, values) {
|
||||||
if (v.first->script.invoke(ctx)->toString() != v.second) return false;
|
StatsDimension& dim = *v.first;
|
||||||
|
String value = dim.script.invoke(ctx)->toString();
|
||||||
|
if (dim.split_list) {
|
||||||
|
if (!chosen(v.second, value)) return false;
|
||||||
|
} else {
|
||||||
|
if (value != v.second) return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -208,6 +216,12 @@ void StatsPanel::showCategory() {
|
|||||||
d.elements.push_back(e);
|
d.elements.push_back(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// split lists
|
||||||
|
size_t dim_id = 0;
|
||||||
|
FOR_EACH(dim, cat.dimensions) {
|
||||||
|
if (dim->split_list) d.splitList(dim_id);
|
||||||
|
++dim_id;
|
||||||
|
}
|
||||||
graph->setLayout(cat.type);
|
graph->setLayout(cat.type);
|
||||||
graph->setData(d);
|
graph->setData(d);
|
||||||
filterCards();
|
filterCards();
|
||||||
|
|||||||
@@ -297,6 +297,30 @@ SCRIPT_RULE_2_DEPENDENCIES(expand_keywords) {
|
|||||||
SCRIPT_RETURN(_(""));
|
SCRIPT_RETURN(_(""));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SCRIPT_FUNCTION(keyword_usage) {
|
||||||
|
SCRIPT_PARAM(CardP, card);
|
||||||
|
SCRIPT_OPTIONAL_PARAM_(bool, unique);
|
||||||
|
// make a list "kw1, kw2, kw3" of keywords used on card
|
||||||
|
String ret;
|
||||||
|
for (KeywordUsageStatistics::const_iterator it = card->keyword_usage.begin() ; it != card->keyword_usage.end() ; ++it) {
|
||||||
|
bool keep = true;
|
||||||
|
if (unique) {
|
||||||
|
// prevent duplicates
|
||||||
|
for (KeywordUsageStatistics::const_iterator it2 = card->keyword_usage.begin() ; it != it2 ; ++it2) {
|
||||||
|
if (it->second == it2->second) {
|
||||||
|
keep = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (keep) {
|
||||||
|
if (!ret.empty()) ret += _(", ");
|
||||||
|
ret += it->second->keyword;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SCRIPT_RETURN(ret);
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Rules : regex replace
|
// ----------------------------------------------------------------------------- : Rules : regex replace
|
||||||
|
|
||||||
class ScriptReplaceRule : public ScriptValue {
|
class ScriptReplaceRule : public ScriptValue {
|
||||||
@@ -677,6 +701,7 @@ void init_script_basic_functions(Context& ctx) {
|
|||||||
// keyword
|
// keyword
|
||||||
ctx.setVariable(_("expand keywords"), script_expand_keywords);
|
ctx.setVariable(_("expand keywords"), script_expand_keywords);
|
||||||
ctx.setVariable(_("expand keywords rule"), script_expand_keywords_rule);
|
ctx.setVariable(_("expand keywords rule"), script_expand_keywords_rule);
|
||||||
|
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"), script_filter);
|
||||||
|
|||||||
Reference in New Issue
Block a user