diff --git a/src/gui/set/stats_panel.cpp b/src/gui/set/stats_panel.cpp index d3eca0e6..7c672719 100644 --- a/src/gui/set/stats_panel.cpp +++ b/src/gui/set/stats_panel.cpp @@ -94,6 +94,90 @@ void StatCategoryList::drawItem(DC& dc, int x, int y, size_t item, bool selected dc.DrawText(str, (int)pos.x, (int)pos.y); } +// ----------------------------------------------------------------------------- : StatDimensionList + +/// A list of fields of which the statistics can be shown +class StatDimensionList : public GalleryList { + public: + StatDimensionList(Window* parent, int id, bool show_empty) + : GalleryList(parent, id, wxVERTICAL) + , show_empty(show_empty) + { + item_size = wxSize(150, 23); + } + + void show(const GameP&); + + /// The selected category + inline StatsDimensionP getSelection() { + if (show_empty && selection == 0) return StatsDimensionP(); + return dimensions.at(selection - show_empty); + } + + protected: + virtual size_t itemCount() const; + virtual void drawItem(DC& dc, int x, int y, size_t item, bool selected); + + private: + GameP game; + bool show_empty; + vector dimensions; ///< Dimensions, sorted by position_hint +}; + +struct ComparePositionHint2{ + inline bool operator () (const StatsDimensionP& a, const StatsDimensionP& b) { + return a->position_hint < b->position_hint; + } +}; + +void StatDimensionList::show(const GameP& game) { + this->game = game; + dimensions = game->statistics_dimensions; + stable_sort(dimensions.begin(), dimensions.end(), ComparePositionHint2()); + update(); + // select first item + selection = itemCount() > 0 ? 0 : NO_SELECTION; +} + +size_t StatDimensionList::itemCount() const { + return dimensions.size() + show_empty; +} + +void StatDimensionList::drawItem(DC& dc, int x, int y, size_t item, bool selected) { + if (show_empty && item == 0) { + RealRect rect(RealPoint(x + 24, y), RealSize(item_size.x - 30, item_size.y)); + String str = _("None"); + dc.SetFont(*wxNORMAL_FONT); + int w, h; + dc.GetTextExtent(str, &w, &h); + RealSize size = RealSize(w,h); + RealPoint pos = align_in_rect(ALIGN_MIDDLE_LEFT, size, rect); + dc.DrawText(str, (int)pos.x, (int)pos.y); + return; + } + StatsDimension& dim = *dimensions.at(item - show_empty); + // draw icon + if (!dim.icon_filename.empty() && !dim.icon.Ok()) { + InputStreamP file = game->openIn(dim.icon_filename); + Image img(*file); + Image resampled(21, 21); + resample_preserve_aspect(img, resampled); + if (img.Ok()) dim.icon = Bitmap(resampled); + } + if (dim.icon.Ok()) { + dc.DrawBitmap(dim.icon, x+1, y+1); + } + // draw name + RealRect rect(RealPoint(x + 24, y), RealSize(item_size.x - 30, item_size.y)); + String str = capitalize(dim.name); + dc.SetFont(*wxNORMAL_FONT); + int w, h; + dc.GetTextExtent(str, &w, &h); + RealSize size = RealSize(w,h); + RealPoint pos = align_in_rect(ALIGN_MIDDLE_LEFT, size, rect); + dc.DrawText(str, (int)pos.x, (int)pos.y); +} + // ----------------------------------------------------------------------------- : StatsPanel StatsPanel::StatsPanel(Window* parent, int id) @@ -102,7 +186,10 @@ StatsPanel::StatsPanel(Window* parent, int id) { // init controls wxSplitterWindow* splitter; - categories = new StatCategoryList(this, ID_FIELD_LIST); + //%categories = new StatCategoryList(this, ID_FIELD_LIST); + for (int i = 0 ; i < 3 ; ++i) { + dimensions[i] = new StatDimensionList(this, ID_FIELD_LIST, i > 0); + } splitter = new wxSplitterWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); graph = new GraphControl (splitter, wxID_ANY); card_list = new FilteredCardList(splitter, wxID_ANY); @@ -112,7 +199,12 @@ StatsPanel::StatsPanel(Window* parent, int id) splitter->SplitHorizontally(graph, card_list, -170); // init sizer wxSizer* s = new wxBoxSizer(wxHORIZONTAL); - s->Add(categories, 0, wxEXPAND | wxRIGHT, 2); + //%s->Add(categories, 0, wxEXPAND | wxRIGHT, 2); + wxSizer* s2 = new wxBoxSizer(wxVERTICAL); + s2->Add(dimensions[0], 1, wxBOTTOM, 2); + s2->Add(dimensions[1], 1, wxBOTTOM, 2); + s2->Add(dimensions[2], 1); + s->Add(s2, 0, wxEXPAND | wxRIGHT, 2); s->Add(splitter, 1, wxEXPAND); s->SetSizeHints(this); SetSizer(s); @@ -120,7 +212,8 @@ StatsPanel::StatsPanel(Window* parent, int id) void StatsPanel::onChangeSet() { card_list->setSet(set); - categories->show(set->game); + //%categories->show(set->game); + for (int i = 0 ; i < 3 ; ++i) dimensions[i]->show(set->game); onChange(); } @@ -183,6 +276,52 @@ void StatsPanel::onChange() { void StatsPanel::showCategory() { up_to_date = true; // change graph data + GraphDataPre d; + // create axes + vector dims; + for (int i = 0 ; i < 3 ; ++i) { + StatsDimensionP dim = dimensions[i]->getSelection(); + if (!dim) continue; + dims.push_back(dim); + d.axes.push_back(new_intrusive5( + dim->name, + dim->colors.empty() ? AUTO_COLOR_EVEN : AUTO_COLOR_NO, + dim->numeric, + &dim->colors, + dim->groups.empty() ? nullptr : &dim->groups + ) + ); + } + // find values + FOR_EACH(card, set->cards) { + Context& ctx = set->getContext(card); + GraphElementP e(new GraphElement); + bool show = true; + FOR_EACH(dim, dims) { + String value = untag(dim->script.invoke(ctx)->toString()); + e->values.push_back(value); + if (value.empty() && !dim->show_empty) { + // don't show this element + show = false; + break; + } + } + if (show) { + d.elements.push_back(e); + } + } + // split lists + size_t dim_id = 0; + FOR_EACH(dim, dims) { + if (dim->split_list) d.splitList(dim_id); + ++dim_id; + } + graph->setLayout(dims.size() == 1 ? GRAPH_TYPE_BAR + :dims.size() == 2 ? GRAPH_TYPE_STACK + : GRAPH_TYPE_SCATTER_PIE); + graph->setData(d); + filterCards(); + /* if (categories->hasSelection()) { StatsCategory& cat = categories->getSelection(); GraphDataPre d; @@ -226,13 +365,14 @@ void StatsPanel::showCategory() { graph->setData(d); filterCards(); } + */ } void StatsPanel::onGraphSelect(wxCommandEvent&) { filterCards(); } void StatsPanel::filterCards() { - if (!categories->hasSelection()) return; + /*if (!categories->hasSelection()) return; intrusive_ptr filter(new StatsFilter(*set)); StatsCategory& cat = categories->getSelection(); vector > values; @@ -244,6 +384,19 @@ void StatsPanel::filterCards() { i++; } card_list->setFilter(filter); + */ + intrusive_ptr filter(new StatsFilter(*set)); + int dims = 0; + for (int i = 0 ; i < 3 ; ++i) { + StatsDimensionP dim = dimensions[i]->getSelection(); + if (!dim) continue; + ++dims; + if (graph->hasSelection(i)) { + filter->values.push_back(make_pair(dim, graph->getSelection(i))); + } + } + if (dims == 0) return; + card_list->setFilter(filter); } BEGIN_EVENT_TABLE(StatsPanel, wxPanel) diff --git a/src/gui/set/stats_panel.hpp b/src/gui/set/stats_panel.hpp index 50ade1eb..6f9f4238 100644 --- a/src/gui/set/stats_panel.hpp +++ b/src/gui/set/stats_panel.hpp @@ -13,6 +13,7 @@ #include class StatCategoryList; +class StatDimensionList; class GraphControl; class FilteredCardList; @@ -41,6 +42,7 @@ class StatsPanel : public SetWindowPanel { DECLARE_EVENT_TABLE(); StatCategoryList* categories; + StatDimensionList* dimensions[3]; GraphControl* graph; FilteredCardList* card_list;