diff --git a/src/data/field/choice.hpp b/src/data/field/choice.hpp index 3b8ec152..384a56e3 100644 --- a/src/data/field/choice.hpp +++ b/src/data/field/choice.hpp @@ -60,7 +60,7 @@ class ChoiceField::Choice : public IntrusivePtrBase { * The top level group has first_id 0. */ int first_id; - + /// Is this a group? bool isGroup() const; /// Can this Choice itself be chosen? diff --git a/src/data/statistics.cpp b/src/data/statistics.cpp index 7a894ca2..5dbff95f 100644 --- a/src/data/statistics.cpp +++ b/src/data/statistics.cpp @@ -12,6 +12,7 @@ DECLARE_TYPEOF_COLLECTION(String); DECLARE_TYPEOF_COLLECTION(StatsDimensionP); +DECLARE_TYPEOF_COLLECTION(ChoiceField::ChoiceP); // ----------------------------------------------------------------------------- : Statistics dimension @@ -33,16 +34,29 @@ StatsDimension::StatsDimension(const Field& field) const ChoiceField* choice_field = dynamic_cast(&field); if (choice_field) { colors = choice_field->choice_colors; - int count = choice_field->choices->lastId(); + /*int count = choice_field->choices->lastId(); for (int i = 0 ; i < count ; ++i) { groups.push_back(choice_field->choices->choiceName(i)); + }*/ + // only top level choices + FOR_EACH_CONST(g, choice_field->choices->choices) { + groups.push_back(g->name); } + // initialize script, primary_choice(card.{field_name}) + Script& s = script.getScript(); + s.addInstruction(I_GET_VAR, string_to_variable(_("primary choice"))); + s.addInstruction(I_GET_VAR, string_to_variable(_("card"))); + s.addInstruction(I_MEMBER_C, field.name); + s.addInstruction(I_CALL, 1); + s.addInstruction(I_NOP, string_to_variable(_("input"))); + s.addInstruction(I_RET); + } else { + // initialize script, card.{field_name} + Script& s = script.getScript(); + s.addInstruction(I_GET_VAR, string_to_variable(_("card"))); + s.addInstruction(I_MEMBER_C, field.name); + s.addInstruction(I_RET); } - // initialize script, card.{field_name} - Script& s = script.getScript(); - s.addInstruction(I_GET_VAR, string_to_variable(_("card"))); - s.addInstruction(I_MEMBER_C, field.name); - s.addInstruction(I_RET); } IMPLEMENT_REFLECTION_NO_GET_MEMBER(StatsDimension) { diff --git a/src/gui/control/graph.cpp b/src/gui/control/graph.cpp index 99584744..c8811f4a 100644 --- a/src/gui/control/graph.cpp +++ b/src/gui/control/graph.cpp @@ -427,7 +427,7 @@ void GraphLabelAxis::draw(RotatedDC& dc, int current, DrawLayer layer) const { Color fg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT); if (draw_lines) { dc.SetPen(lerp(bg, fg, 0.5)); - for (int i = 0 ; i < count ; ++i) { + for (int i = 1 ; i <= count ; ++i) { dc.DrawLine(RealPoint(rect.x + i*width, rect.top()), RealPoint(rect.x + i*width, rect.bottom())); } } @@ -436,6 +436,29 @@ void GraphLabelAxis::draw(RotatedDC& dc, int current, DrawLayer layer) const { dc.DrawLine(rect.topLeft(), rect.bottomLeft()); } else { // TODO + double height = rect.height / count; // width of an item + // Draw labels + double y = rect.bottom(); + FOR_EACH_CONST(g, axis.groups) { + // draw label, aligned bottom center + RealSize text_size = dc.GetTextExtent(g.name); + //dc.SetClippingRegion(RealRect(x + 2, rect.bottom() + 3, width - 4, text_size.height)); + dc.DrawText(g.name, align_in_rect(ALIGN_MIDDLE_RIGHT, text_size, RealRect(-3, y, 0, -height))); + //dc.DestroyClippingRegion(); + y -= height; + } + // Draw lines + Color bg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); + Color fg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT); + if (draw_lines) { + dc.SetPen(lerp(bg, fg, 0.5)); + for (int i = 1 ; i <= count ; ++i) { + dc.DrawLine(RealPoint(rect.left(), rect.bottom() - i*height), RealPoint(rect.right(), rect.bottom() - i*height)); + } + } + // always draw axis line + dc.SetPen(fg); + dc.DrawLine(rect.bottomLeft(), rect.bottomRight()); } } } @@ -560,6 +583,12 @@ void GraphControl::setLayout(GraphType type) { break; } case GRAPH_TYPE_SCATTER: { // TODO + intrusive_ptr combined(new GraphContainer()); + combined->add(new_intrusive4(0, HORIZONTAL, false, true)); + combined->add(new_intrusive4(1, VERTICAL, false, true)); + //combined->add(new_intrusive2(0,1)); + graph = new_intrusive5(combined, 23,8,7,20); + break; } default: graph = GraphP(); } @@ -574,8 +603,8 @@ void GraphControl::setData(const GraphDataP& data) { if (graph) { graph->setData(data); current_item.clear(); // TODO : preserve selection - Refresh(false); } + Refresh(false); } void GraphControl::onPaint(wxPaintEvent&) { diff --git a/src/script/functions/editor.cpp b/src/script/functions/editor.cpp index a2bfd2cf..c9072d0b 100644 --- a/src/script/functions/editor.cpp +++ b/src/script/functions/editor.cpp @@ -12,10 +12,12 @@ #include #include #include +#include DECLARE_TYPEOF_COLLECTION(FieldP); DECLARE_TYPEOF_COLLECTION(TextValue*); DECLARE_TYPEOF_COLLECTION(String); +DECLARE_TYPEOF_COLLECTION(ChoiceField::ChoiceP); // ----------------------------------------------------------------------------- : Combined editor @@ -131,9 +133,31 @@ SCRIPT_FUNCTION_DEPENDENCIES(combined_editor) { return dependency_dummy; } +// ----------------------------------------------------------------------------- : Choice values + +// convert a full choice name into the name of the top level group it is in +SCRIPT_FUNCTION(primary_choice) { + SCRIPT_PARAM(ValueP,input); + ChoiceValueP value = dynamic_pointer_cast(input); + if (!value) { + throw ScriptError(_("Argument to 'primary_choice' should be a choice field")); + } + // determine choice + int id = value->field().choices->choiceId(value->value); + // find the last group that still contains id + const vector& choices = value->field().choices->choices; + FOR_EACH_CONST_REVERSE(c, choices) { + if (id >= c->first_id) { + SCRIPT_RETURN(c->name); + } + } + SCRIPT_RETURN(_("")); +} + // ----------------------------------------------------------------------------- : Init void init_script_editor_functions(Context& ctx) { ctx.setVariable(_("forward editor"), script_combined_editor); // combatability ctx.setVariable(_("combined editor"), script_combined_editor); + ctx.setVariable(_("primary choice"), script_primary_choice); } diff --git a/src/script/parser.cpp b/src/script/parser.cpp index c8c8410d..95fa6b2d 100644 --- a/src/script/parser.cpp +++ b/src/script/parser.cpp @@ -13,7 +13,7 @@ #include // for "include file" semi hack #include -DECLARE_TYPEOF_COLLECTION(int); +DECLARE_TYPEOF_COLLECTION(Variable); #ifdef __WXMSW__ #define TokenType TokenType_ // some stupid windows header uses our name @@ -546,7 +546,7 @@ void parseOper(TokenIterator& input, Script& script, Precedence minPrec, Instruc expectToken(input, _("]")); } else if (minPrec <= PREC_FUN && token==_("(")) { // function call, read arguments - vector arguments; + vector arguments; Token t = input.peek(); while (t != _(")") && t != TOK_EOF) { if (input.peek(2) == _(":")) { diff --git a/src/script/script.cpp b/src/script/script.cpp index 0f6d5a19..a9bdf6d1 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -13,7 +13,7 @@ // ----------------------------------------------------------------------------- : Variables -typedef map Variables; +typedef map Variables; Variables variables; DECLARE_TYPEOF(Variables); #ifdef _DEBUG @@ -21,13 +21,13 @@ DECLARE_TYPEOF(Variables); #endif /// Return a unique name for a variable to allow for faster loopups -unsigned int string_to_variable(const String& s) { +Variable string_to_variable(const String& s) { map::iterator it = variables.find(s); if (it == variables.end()) { #ifdef _DEBUG variable_names.push_back(s); #endif - unsigned int v = (unsigned int)variables.size(); + Variable v = (Variable)variables.size(); variables.insert(make_pair(s,v)); return v; } else { @@ -38,7 +38,7 @@ unsigned int string_to_variable(const String& s) { /// Get the name of a vaiable /** Warning: this function is slow, it should only be used for error messages and such. */ -String variable_to_string(unsigned int v) { +String variable_to_string(Variable v) { FOR_EACH(vi, variables) { if (vi.second == v) return vi.first; } diff --git a/src/script/script.hpp b/src/script/script.hpp index 99399728..3ada5aeb 100644 --- a/src/script/script.hpp +++ b/src/script/script.hpp @@ -92,13 +92,15 @@ struct Instruction { // ----------------------------------------------------------------------------- : Variables +typedef unsigned int Variable; + /// Return a unique name for a variable to allow for faster loopups -unsigned int string_to_variable(const String& s); +Variable string_to_variable(const String& s); /// Get the name of a vaiable /** Warning: this function is slow, it should only be used for error messages and such. */ -String variable_to_string(unsigned int v); +String variable_to_string(Variable v); // ----------------------------------------------------------------------------- : Script