Added support for custom colors for graphs;

Moved 'choice colors' from styel to field, split into 'choice colors' and 'choice colors cardlist';
Added support for pie graphs (no gui to use them, though);
Fixed bugs caused by selecting a card before the set was changed on all panels.

git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@336 0fc631ac-6414-0410-93d0-97cfa31319b6
This commit is contained in:
twanvl
2007-05-11 14:10:29 +00:00
parent f9eade95eb
commit 3b6743b110
33 changed files with 634 additions and 186 deletions
+11 -12
View File
@@ -176,6 +176,7 @@ void CardListBase::rebuild() {
column_fields.clear();
selected_item_pos = -1;
onRebuild();
if (!set) return;
// determine column order
map<int,FieldP> new_column_fields;
FOR_EACH(f, set->game->card_fields) {
@@ -197,7 +198,7 @@ void CardListBase::rebuild() {
column_fields.push_back(f.second);
}
// find field that determines color
color_style = findColorStyle();
color_field = findColorField();
// determine sort settings
GameSettings& gs = settings.gameSettingsFor(*set->game);
sort_ascending = gs.sort_cards_ascending;
@@ -216,18 +217,16 @@ void CardListBase::rebuild() {
++i;
}
refreshList();
// select a card if possible
selectItemPos(0, true);
}
ChoiceStyleP CardListBase::findColorStyle() {
FOR_EACH(s, set->stylesheet->card_style) {
ChoiceStyleP cs = dynamic_pointer_cast<ChoiceStyle>(s);
if (cs && cs->colors_card_list) {
return cs;
ChoiceFieldP CardListBase::findColorField() {
FOR_EACH(s, set->game->card_fields) {
ChoiceFieldP cf = dynamic_pointer_cast<ChoiceField>(s);
if (cf && !cf->choice_colors_cardlist.empty()) {
return cf;
}
}
return ChoiceStyleP();
return ChoiceFieldP();
}
// ----------------------------------------------------------------------------- : CardListBase : Columns
@@ -270,10 +269,10 @@ int CardListBase::OnGetItemImage(long pos) const {
}
wxListItemAttr* CardListBase::OnGetItemAttr(long pos) const {
if (!color_style) return nullptr;
ChoiceValueP val = static_pointer_cast<ChoiceValue>( getCard(pos)->data[color_style->fieldP]);
if (!color_field) return nullptr;
ChoiceValueP val = static_pointer_cast<ChoiceValue>( getCard(pos)->data[color_field]);
assert(val);
item_attr.SetTextColour(color_style->choice_colors[val->value()]); // if it doesn't exist we get black
item_attr.SetTextColour(color_field->choice_colors_cardlist[val->value()]); // if it doesn't exist we get black
return &item_attr;
}
+3 -4
View File
@@ -13,7 +13,7 @@
#include <gui/control/item_list.hpp>
#include <data/set.hpp>
DECLARE_POINTER_TYPE(ChoiceStyle);
DECLARE_POINTER_TYPE(ChoiceField);
DECLARE_POINTER_TYPE(Field);
// ----------------------------------------------------------------------------- : Events
@@ -102,14 +102,13 @@ class CardListBase : public ItemList, public SetView {
// --------------------------------------------------- : Data
private:
// display stuff
ChoiceStyleP color_style; ///< Style (and field) to use for text color (optional)
ChoiceFieldP color_field; ///< Field to use for text color (optional)
vector<FieldP> column_fields; ///< The field to use for each column (by column index)
mutable wxListItemAttr item_attr; // for OnGetItemAttr
/// Find the field that determines the color, if any.
/** Note: Uses only fields from the set's default style */
ChoiceStyleP findColorStyle();
ChoiceFieldP findColorField();
/// Store the column sizes in the settings
void storeColumns();
+6
View File
@@ -21,6 +21,12 @@ void FilteredCardList::setFilter(const CardListFilterP& filter) {
rebuild();
}
void FilteredCardList::onChangeSet() {
// clear filter before changing set, the filter might not make sense for a different set
filter = CardListFilterP();
CardListBase::onChangeSet();
}
void FilteredCardList::getItems(vector<VoidP>& out) const {
if (filter) {
FOR_EACH(c, set->cards) {
+3 -1
View File
@@ -37,7 +37,9 @@ class FilteredCardList : public CardListBase {
protected:
/// Get only the subset of the cards
virtual void getItems(vector<VoidP>& out) const;
virtual void onChangeSet();
private:
CardListFilterP filter; ///< Filter with which this.cards is made
};
+210 -60
View File
@@ -14,9 +14,12 @@
DECLARE_TYPEOF_COLLECTION(GraphAxisP);
DECLARE_TYPEOF_COLLECTION(GraphElementP);
DECLARE_TYPEOF_COLLECTION(GraphGroup);
DECLARE_TYPEOF_COLLECTION(GraphP);
DECLARE_TYPEOF_COLLECTION(int);
DECLARE_TYPEOF(map<String COMMA UInt>);
template <typename T> inline T sgn(T v) { return v < 0 ? -1 : 1; }
// ----------------------------------------------------------------------------- : Events
DEFINE_EVENT_TYPE(EVENT_GRAPH_SELECT);
@@ -60,6 +63,7 @@ GraphData::GraphData(const GraphDataPre& d)
} else {
a->groups.push_back(GraphGroup(is, it->second));
a->max = max(a->max, it->second);
a->total += it->second;
left--;
}
if (i > 100) {
@@ -75,14 +79,26 @@ GraphData::GraphData(const GraphDataPre& d)
FOR_EACH(c, counts) {
a->groups.push_back(GraphGroup(c.first, c.second));
a->max = max(a->max, c.second);
a->total += c.second;
}
}
// find some nice colors for the groups
if (a->auto_color) {
// colors
if (a->auto_color == AUTO_COLOR_NO && a->colors) {
// use colors from the table
FOR_EACH(g, a->groups) {
map<String,Color>::const_iterator it = a->colors->find(g.name);
if (it != a->colors->end()) {
g.color = it->second;
}
}
} else {
// find some nice colors for the groups
double hue = 0.6; // start hue
bool first = true;
FOR_EACH(g, a->groups) {
double amount = double(g.size) / size; // amount this group takes
double amount = a->auto_color == AUTO_COLOR_EVEN
? 1. / a->groups.size()
: double(g.size) / a->total; // amount this group takes
if (!first) hue += amount/2;
g.color = hsl2rgb(hue, 1.0, 0.5);
hue += amount / 2;
@@ -118,8 +134,8 @@ GraphData::GraphData(const GraphDataPre& d)
// ----------------------------------------------------------------------------- : Graph1D
void Graph1D::draw(RotatedDC& dc, const vector<int>& current) const {
draw(dc, axis < current.size() ? current.at(axis) : -1);
void Graph1D::draw(RotatedDC& dc, const vector<int>& current, DrawLayer layer) const {
draw(dc, axis < current.size() ? current.at(axis) : -1, layer);
}
bool Graph1D::findItem(const RealPoint& pos, const RealRect& rect, vector<int>& out) const {
int i = findItem(pos, rect);
@@ -134,10 +150,10 @@ bool Graph1D::findItem(const RealPoint& pos, const RealRect& rect, vector<int>&
// ----------------------------------------------------------------------------- : Bar Graph
void BarGraph::draw(RotatedDC& dc, int current) const {
void BarGraph::draw(RotatedDC& dc, int current, DrawLayer layer) const {
if (!data) return;
// Rectangle for bars
RealRect rect = dc.getInternalRect().move(23, 8, -30, -28);
RealRect rect = dc.getInternalRect();
// Bar sizes
GraphAxis& axis = axis_data();
int count = int(axis.groups.size());
@@ -145,56 +161,39 @@ void BarGraph::draw(RotatedDC& dc, int current) const {
double width = width_space / 5 * 4;
double space = width_space / 5;
double step_height = rect.height / axis.max; // multiplier for bar height
// Highlight current column
Color bg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
Color fg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
if (current >= 0) {
double x = rect.x + width_space * current;
dc.SetPen(*wxTRANSPARENT_PEN);
dc.SetBrush(lerp(bg, axis.groups[current].color, 0.25));
dc.DrawRectangle(RealRect(x + space / 2 - 5, rect.bottom() + 1 + 15,
width + 10, -step_height * axis.groups[current].size - 1.999 - 20));
dc.SetBrush(lerp(bg, axis.groups[current].color, 0.5));
dc.DrawRectangle(RealRect(x + space / 2 - 2, rect.bottom() + 1 + 2,
width + 4, -step_height * axis.groups[current].size - 1.999 - 4));
}
// How many labels and lines to draw?
dc.SetFont(*wxNORMAL_FONT);
UInt label_step = UInt(max(1.0, (dc.GetCharHeight() + 1) / step_height));
// Draw backlines (horizontal) and value labels
dc.SetPen(lerp(bg, fg, 0.5));
for (UInt i = 0 ; i <= axis.max ; ++i) {
if (i % label_step == 0) {
int y = int(rect.bottom() - i * step_height);
dc.DrawLine(RealPoint(rect.left() - 2, y), RealPoint(rect.right(), y));
// draw label, aligned middle right
String label; label << i;
RealSize text_size = dc.GetTextExtent(label);
dc.DrawText(label, align_in_rect(ALIGN_MIDDLE_RIGHT, text_size, RealRect(rect.x - 4, y, 0, 0)));
if (layer == LAYER_SELECTION) {
// Highlight current column
Color bg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
if (current >= 0) {
double x = rect.x + width_space * current;
dc.SetPen(*wxTRANSPARENT_PEN);
dc.SetBrush(lerp(bg, axis.groups[current].color, 0.25));
dc.DrawRectangle(RealRect(x + space / 2 - 5, rect.y + 1 - 15 * sgn(step_height),
width + 10, step_height * axis.groups[current].size + (1.999 + 20) * sgn(step_height)));
dc.SetBrush(lerp(bg, axis.groups[current].color, 0.5));
dc.DrawRectangle(RealRect(x + space / 2 - 2, rect.y + 1 - 2 * sgn(step_height),
width + 4, step_height * axis.groups[current].size + (1.999 + 4) * sgn(step_height)));
}
} else if (layer == LAYER_VALUES) {
// Draw bars
Color fg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
dc.SetPen(fg);
double x = rect.x;
FOR_EACH_CONST(g, axis.groups) {
// draw bar
dc.SetBrush(g.color);
dc.DrawRectangle(RealRect(x + space / 2, rect.y - 1 * sgn(step_height), width, (int)(rect.y + step_height * g.size) - rect.y + 1 * sgn(step_height)));
// draw label, aligned bottom center
RealSize text_size = dc.GetTextExtent(g.name);
dc.SetClippingRegion(RealRect(x + 2, rect.y + 3, width_space - 4, text_size.height));
dc.DrawText(g.name, align_in_rect(ALIGN_TOP_CENTER, text_size, RealRect(x, rect.y + 3, width_space, 0)));
dc.DestroyClippingRegion();
x += width_space;
}
}
// Draw axes
dc.SetPen(fg);
dc.DrawLine(rect.bottomLeft() - RealSize(2,0), rect.bottomRight());
dc.DrawLine(rect.topLeft(), rect.bottomLeft());
// Draw bars
double x = rect.x;
FOR_EACH_CONST(g, axis.groups) {
// draw bar
dc.SetBrush(g.color);
dc.DrawRectangle(RealRect(x + space / 2, rect.bottom() + 1, width, (int)(rect.bottom() - step_height * g.size) - rect.bottom() - 1));
// draw label, aligned bottom center
RealSize text_size = dc.GetTextExtent(g.name);
dc.SetClippingRegion(RealRect(x + 2, rect.bottom() + 3, width_space - 4, text_size.height));
dc.DrawText(g.name, align_in_rect(ALIGN_TOP_CENTER, text_size, RealRect(x, rect.bottom() + 3, width_space, 0)));
dc.DestroyClippingRegion();
x += width_space;
}
}
int BarGraph::findItem(const RealPoint& pos, const RealRect& rect1) const {
int BarGraph::findItem(const RealPoint& pos, const RealRect& rect) const {
if (!data) return -1;
// Rectangle for bars
RealRect rect = rect1.move(23, 8, -30, -28);
// Bar sizes
GraphAxis& axis = axis_data();
int count = int(axis.groups.size());
@@ -203,10 +202,10 @@ int BarGraph::findItem(const RealPoint& pos, const RealRect& rect1) const {
// Find column in which this point could be located
int col = int((pos.x - rect.x) / width_space);
double in_col = (pos.x - rect.x) - col * width_space;
if (in_col < space / 2 || // left
in_col > width_space - space / 2 || // right
pos.y > rect.bottom() || // below
pos.y < rect.top()) { // above
if (in_col < space / 2 || // left
in_col > width_space - space / 2 || // right
pos.y > max(rect.top(), rect.bottom()) || // below
pos.y < min(rect.top(), rect.bottom())) { // above
return -1;
}
if (col < 0 || (size_t)col >= axis_data().groups.size()) {
@@ -218,18 +217,165 @@ int BarGraph::findItem(const RealPoint& pos, const RealRect& rect1) const {
// ----------------------------------------------------------------------------- : Pie Graph
// ----------------------------------------------------------------------------- : Scatter Graph
void PieGraph::draw(RotatedDC& dc, int current, DrawLayer layer) const {
if (!data) return;
// Rectangle for the pie
GraphAxis& axis = axis_data();
RealRect rect = dc.getInternalRect();
double size = min(rect.width, rect.height);
RealSize pie_size(size, size);
RealSize pie_size_large(size+20, size+20);
RealPoint pie_pos = rect.position() + rect.size() / 2;
//RealPoint pos = align_in_rect(ALIGN_MIDDLE_CENTER, RealSize(size,size), rect);
// draw items
if (layer == LAYER_VALUES) {
Color fg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
dc.SetPen(fg);
// draw pies
double angle = 0;
int i = 0;
FOR_EACH_CONST(g, axis.groups) {
// draw pie
dc.SetBrush(g.color);
if (g.size > 0) {
double end_angle = angle + 2 * M_PI * (double)g.size / axis.total;
dc.DrawEllipticArc(pie_pos, i == current ? pie_size_large : pie_size, angle, end_angle);
angle = end_angle;
}
++i;
}
// draw spokes
if (axis.groups.size() > 1) {
angle = 0;
FOR_EACH_CONST(g, axis.groups) {
if (g.size > 0) {
dc.DrawEllipticSpoke(pie_pos, pie_size, angle);
angle += 2 * M_PI * (double)g.size / axis.total;
}
}
}
}
}
int PieGraph::findItem(const RealPoint& pos, const RealRect& rect) const {
if (!data) return -1;
// Rectangle for the pie
GraphAxis& axis = axis_data();
double size = min(rect.width, rect.height);
RealPoint pie_pos = rect.position() + rect.size() / 2;
// position in circle
Vector2D delta = pos - pie_pos;
if (delta.lengthSqr() > size*size) {
return -1; // outside circle
}
double pos_angle = atan2(-delta.y, delta.x); // in range [-pi..pi]
if (pos_angle < 0) pos_angle += 2 * M_PI;
// find angle
double angle = 0;
int i = 0;
FOR_EACH_CONST(g, axis.groups) {
angle += 2 * M_PI * (double)g.size / axis.total;
if (angle > pos_angle) return i;
++i;
}
return -1; //should not happen
}
// ----------------------------------------------------------------------------- : Scatter Plot
// ----------------------------------------------------------------------------- : Graph Legend
// ----------------------------------------------------------------------------- : Graph value axis
void GraphValueAxis::draw(RotatedDC& dc, int current, DrawLayer layer) const {
if (layer != LAYER_AXES) return;
if (!data) return;
// How many labels and lines to draw?
RealRect rect = dc.getInternalRect();
GraphAxis& axis = axis_data();
double step_height = rect.height / axis.max; // height of a single value
dc.SetFont(*wxNORMAL_FONT);
UInt label_step = UInt(max(1.0, (dc.GetCharHeight() + 1) / step_height)); // values per labeled line
// Colors
Color bg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
Color fg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
// Draw backlines (horizontal) and value labels
dc.SetPen(lerp(bg, fg, 0.5));
for (UInt i = 0 ; i <= axis.max ; ++i) {
if (i % label_step == 0) {
int y = rect.top() + i * step_height;
dc.DrawLine(RealPoint(rect.left() - 2, y), RealPoint(rect.right(), y));
// draw label, aligned middle right
String label; label << i;
RealSize text_size = dc.GetTextExtent(label);
dc.DrawText(label, align_in_rect(ALIGN_MIDDLE_RIGHT, text_size, RealRect(rect.x - 4, y, 0, 0)));
}
}
// Draw axes
dc.SetPen(fg);
dc.DrawLine(rect.topLeft() - RealSize(2,0), rect.topRight());
dc.DrawLine(rect.topLeft(), rect.bottomLeft());
}
// ----------------------------------------------------------------------------- : Graph with margins
void GraphWithMargins::draw(RotatedDC& dc, const vector<int>& current, DrawLayer layer) const {
RealRect inner = dc.getInternalRect().move(margin_left, margin_top, - margin_left - margin_right, - margin_top - margin_bottom);
if (upside_down) { inner.y += inner.height; inner.height = -inner.height; }
Rotation new_size(0, inner);
Rotater rot(dc, new_size);
graph->draw(dc, current, layer);
}
bool GraphWithMargins::findItem(const RealPoint& pos, const RealRect& rect, vector<int>& out) const {
RealRect inner = rect.move(margin_left, margin_top, - margin_left - margin_right, - margin_top - margin_bottom);
if (upside_down) { inner.y += inner.height; inner.height = -inner.height; }
return graph->findItem(pos, inner, out);
}
void GraphWithMargins::setData(const GraphDataP& d) {
Graph::setData(d);
graph->setData(d);
}
// ----------------------------------------------------------------------------- : Graph Container
void GraphContainer::draw(RotatedDC& dc, const vector<int>& current, DrawLayer layer) const {
FOR_EACH_CONST(g, items) {
g->draw(dc, current, layer);
}
}
bool GraphContainer::findItem(const RealPoint& pos, const RealRect& rect, vector<int>& out) const {
FOR_EACH_CONST_REVERSE(g, items) {
if (g->findItem(pos, rect, out)) return true;
}
return false;
}
void GraphContainer::setData(const GraphDataP& d) {
Graph::setData(d);
FOR_EACH(g, items) {
g->setData(d);
}
}
void GraphContainer::add(const GraphP& graph) {
items.push_back(graph);
}
// ----------------------------------------------------------------------------- : GraphControl
GraphControl::GraphControl(Window* parent, int id)
: wxControl(parent, id)
{
graph = new_shared1<BarGraph>(0);
//*
shared_ptr<GraphContainer> combined(new GraphContainer());
combined->add(new_shared1<GraphValueAxis>(0));
combined->add(new_shared1<BarGraph>(0));
graph = new_shared6<GraphWithMargins>(combined, 23,8,7,20, true);
/*/
shared_ptr<GraphContainer> combined(new GraphContainer());
combined->add(new_shared1<PieGraph>(0));
graph = new_shared6<GraphWithMargins>(combined, 20,20,20,20, false);
//*/
}
void GraphControl::setData(const GraphDataPre& data) {
@@ -250,7 +396,11 @@ void GraphControl::onPaint(wxPaintEvent&) {
rdc.SetPen(*wxTRANSPARENT_PEN);
rdc.SetBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
rdc.DrawRectangle(rdc.getInternalRect());
if (graph) graph->draw(rdc, current_item);
if (graph) {
for (int layer = LAYER_BOTTOM ; layer < LAYER_COUNT ; ++layer) {
graph->draw(rdc, current_item, (DrawLayer)layer);
}
}
}
void GraphControl::onSize(wxSizeEvent&) {
+67 -12
View File
@@ -39,22 +39,33 @@ class GraphGroup {
UInt size; ///< Number of elements in this group
};
/// Automatic coloring mode
enum AutoColor
{ AUTO_COLOR_NO
, AUTO_COLOR_EVEN
, AUTO_COLOR_WEIGHTED
};
/// An axis in a graph, consists of a list of groups
/** The sum of groups.sum = sum of all elements in the data */
class GraphAxis {
public:
GraphAxis(const String& name, bool auto_color = true, bool numeric = false)
GraphAxis(const String& name, AutoColor auto_color = AUTO_COLOR_EVEN, bool numeric = false, const map<String,Color>* colors = nullptr)
: name(name)
, auto_color(auto_color)
, numeric(numeric)
, max(0)
, total(0)
, colors(colors)
{}
String name; ///< Name/label of this axis
bool auto_color; ///< Automatically assign colors to the groups on this axis
AutoColor auto_color; ///< Automatically assign colors to the groups on this axis
vector<GraphGroup> groups; ///< Groups along this axis
bool numeric; ///< Numeric axis?
UInt max; ///< Maximum size of the groups
UInt total; ///< Sum of the size of all groups
const map<String,Color>* colors; ///< Colors for each choice (optional
};
/// A single data point of a graph
@@ -87,13 +98,21 @@ class GraphData {
// ----------------------------------------------------------------------------- : Graph
enum DrawLayer
{ LAYER_BOTTOM = 0
, LAYER_SELECTION = 0
, LAYER_AXES
, LAYER_VALUES
, LAYER_COUNT
};
/// A type of graph
/** It is rendered into a sub-rectangle of the screen */
class Graph {
public:
virtual ~Graph() {}
/// Draw this graph, filling the internalRect() of the dc.
virtual void draw(RotatedDC& dc, const vector<int>& current) const = 0;
virtual void draw(RotatedDC& dc, const vector<int>& current, DrawLayer layer) const = 0;
/// Find the item at the given position, the rectangle gives the screen size
virtual bool findItem(const RealPoint& pos, const RealRect& rect, vector<int>& out) const { return false; }
/// Change the data
@@ -110,13 +129,13 @@ class Graph {
class Graph1D : public Graph {
public:
inline Graph1D(size_t axis) : axis(axis) {}
virtual void draw(RotatedDC& dc, const vector<int>& current) const;
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;
protected:
size_t axis;
/// Find an item, return the position along the axis, or -1 if not found
virtual int findItem(const RealPoint& pos, const RealRect& rect) const = 0;
virtual void draw(RotatedDC& dc, int current) const = 0;
virtual int findItem(const RealPoint& pos, const RealRect& rect) const { return -1; }
virtual void draw(RotatedDC& dc, int current, DrawLayer layer) const = 0;
inline GraphAxis& axis_data() const { return *data->axes.at(axis); }
};
@@ -124,7 +143,7 @@ class Graph1D : public Graph {
class BarGraph : public Graph1D {
public:
inline BarGraph(size_t axis) : Graph1D(axis) {}
virtual void draw(RotatedDC& dc, int current) const;
virtual void draw(RotatedDC& dc, int current, DrawLayer layer) const;
virtual int findItem(const RealPoint& pos, const RealRect& rect) const;
};
@@ -136,7 +155,7 @@ class BarGraph : public Graph1D {
class PieGraph : public Graph1D {
public:
inline PieGraph(size_t axis) : Graph1D(axis) {}
virtual void draw(RotatedDC& dc, int current) const;
virtual void draw(RotatedDC& dc, int current, DrawLayer layer) const;
virtual int findItem(const RealPoint& pos, const RealRect& rect) const;
};
@@ -144,7 +163,7 @@ class PieGraph : public Graph1D {
class GraphLegend : public Graph1D {
public:
inline GraphLegend(size_t axis) : Graph1D(axis) {}
virtual void draw(RotatedDC& dc, int current) const;
virtual void draw(RotatedDC& dc, int current, DrawLayer layer) const;
virtual int findItem(const RealPoint& pos, const RealRect& rect) const;
};
@@ -155,9 +174,43 @@ class GraphLegend : public Graph1D {
// virtual void draw(RotatedDC& dc) const;
//};
//class GraphValueAxis {
// virtual void draw(RotatedDC& dc) const;
//};
/// Draws an a vertical axis for counts
class GraphValueAxis : public Graph1D {
public:
inline GraphValueAxis(size_t axis) : Graph1D(axis) {}
virtual void draw(RotatedDC& dc, int current, DrawLayer layer) const;
};
/// A graph with margins
class GraphWithMargins : public Graph {
public:
inline GraphWithMargins(const GraphP& graph,
double margin_left, double margin_top, double margin_right, double margin_bottom,
bool upside_down = false)
: graph(graph)
, margin_left(margin_left), margin_top(margin_top), margin_right(margin_right), margin_bottom(margin_bottom)
, upside_down(upside_down)
{}
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;
virtual void setData(const GraphDataP& d);
private:
double margin_left, margin_top, margin_right, margin_bottom;
bool upside_down; // put the coordinate system upside down, since graphs are usually bottom-to-top
const GraphP graph;
};
/// A display containing multiple graphs
class GraphContainer : public Graph {
public:
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;
virtual void setData(const GraphDataP& d);
void add(const GraphP& graph);
private:
vector<GraphP> items;
};
// ----------------------------------------------------------------------------- : Graph control
@@ -167,6 +220,8 @@ class GraphControl : public wxControl {
/// Create a graph control
GraphControl(Window* parent, int id);
/// Set the type of graph used, from a number of predefined choices
void setLayout();
/// Update the data in the graph
void setData(const GraphDataPre& data);
/// Update the data in the graph
+4
View File
@@ -39,6 +39,10 @@ void ItemList::selectNext() {
assert(selected_item_pos + 1 < (long)sorted_list.size());
selectItemPos(selected_item_pos + 1, true);
}
void ItemList::selectFirst() {
assert(0 < (long)sorted_list.size());
selectItemPos(0, true);
}
// ----------------------------------------------------------------------------- : ItemList : Selection (private)
+2
View File
@@ -34,6 +34,8 @@ class ItemList : public wxListView {
void selectPrevious();
/// Move the selection to the next item (if possible)
void selectNext();
/// Move the selection to the first item (if possible)
void selectFirst();
// --------------------------------------------------- : Virtual interface
protected: