1 // Copyright (C) 2007, 2008 Ben Asselstine
3 // This program is free software; you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation; either version 3 of the License, or
6 // (at your option) any later version.
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 // GNU Library General Public License for more details.
13 // You should have received a copy of the GNU General Public License
14 // along with this program; if not, write to the Free Software
15 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 #include "line-chart.h"
19 #include "ucompose.hpp"
20 #include <cairomm/context.h>
22 LineChart::LineChart(std::list<std::list<unsigned int> > lines,
23 std::list<Gdk::Color> colours,
24 unsigned int max_height_value,
25 std::string x_axis_description,
26 std::string y_axis_description)
30 d_max_height_value = max_height_value;
31 d_x_axis_description = x_axis_description;
32 d_y_axis_description = y_axis_description;
36 LineChart::~LineChart()
40 bool LineChart::on_expose_event(GdkEventExpose* event)
42 // This is where we draw on the window
43 Glib::RefPtr<Gdk::Window> window = get_window();
46 Gtk::Allocation allocation = get_allocation();
47 const int width = allocation.get_width();
48 const int height = allocation.get_height();
50 // coordinates for the center of the window
55 int origin_y = height;
56 unsigned int hoffs = 30;
57 unsigned int voffs = 30;
59 Cairo::RefPtr<Cairo::Context> cr = window->create_cairo_context();
61 // clip to the area indicated by the expose event so that we only redraw
62 // the portion of the window that needs to be redrawn
63 cr->rectangle(event->area.x, event->area.y,
64 event->area.width, event->area.height);
66 cr->set_source_rgb (0.8, 0.8, 0.8);
67 cr->set_line_width(1000.0);
69 cr->line_to(width,height);
72 cr->set_line_width(1.0);
73 //loop through the outer list, and operate on the inner lists
74 unsigned int max_turn = 0;
75 std::list<std::list<unsigned int> >::iterator line = d_lines.begin();
76 for (; line!= d_lines.end(); line++)
78 if ((*line).size() > max_turn)
79 max_turn = (*line).size();
82 if (d_max_height_value == 0)
84 line = d_lines.begin();
85 for (; line!= d_lines.end(); line++)
87 std::list<unsigned int>::iterator it = (*line).begin();
88 for (; it != (*line).end(); it++)
90 if (*it > d_max_height_value)
91 d_max_height_value = *it;
96 // ensure the border is big enough for the label.
97 Glib::RefPtr<Pango::Layout> layout = Glib::wrap (pango_cairo_create_layout (cr->cobj ()));
98 std::string text_font = "Sans 8";
99 Pango::FontDescription font_desc (text_font);
100 layout->set_font_description (font_desc);
102 layout->set_text(String::ucompose("%1", d_max_height_value));
104 layout->get_pixel_size (w, h);
105 if (w * (hoffs / 4) > hoffs)
106 hoffs = w + (hoffs / 4);
108 std::list<Gdk::Color>::iterator cit = d_colours.begin();
109 line = d_lines.begin();
110 for (; line!= d_lines.end(), cit != d_colours.end(); line++, cit++)
112 //okay, here's my line and it's colour,
113 double red = (double)(*cit).get_red() /65535.0;
114 double green = (double)(*cit).get_green() /65535.0;
115 double blue = (double)(*cit).get_blue() /65535.0;
116 cr->set_source_rgb(red, green, blue);
117 std::list<unsigned int>::iterator it = (*line).begin();
118 unsigned int turn = 1;
119 cr->move_to(origin_x + hoffs, origin_y - voffs);
120 for (; it != (*line).end(); it++, turn++)
122 cr->line_to((((float)turn / (float)max_turn) *
123 (width - (hoffs * 2))) + hoffs,
124 height - (voffs * 2) -
125 (((float)*it / (float)d_max_height_value) *
126 (height - (voffs * 2.0))) + voffs);
131 //draw horizontal axis
132 cr->set_source_rgb(0.3, 0.3, 0.3);
133 cr->move_to(origin_x + hoffs, origin_y - voffs);
134 cr->line_to((width - (hoffs * 2)) + hoffs, origin_y - voffs);
137 //draw ticks on the horizontal axis
138 cr->set_source_rgb(0.3, 0.3, 0.3);
139 cr->move_to(origin_x + hoffs, origin_y - voffs + 1);
140 cr->line_to(origin_x + hoffs, origin_y - voffs + (voffs / 4) + 1);
143 cr->move_to((width - (hoffs * 2)) + hoffs - 1, origin_y - voffs + 1);
144 cr->line_to((width - (hoffs * 2)) + hoffs - 1,
145 origin_y - voffs + (voffs / 4) + 1);
149 cr->set_source_rgb(0.3, 0.3, 0.3);
150 cr->move_to(origin_x + hoffs, origin_y - voffs);
151 cr->line_to(origin_x + hoffs, voffs);
154 //draw ticks on the vertical axis
155 cr->move_to(origin_x + hoffs - 1, origin_y - voffs);
156 cr->line_to(origin_x + hoffs - (hoffs / 4) - 1, origin_y - voffs);
158 cr->move_to(origin_x + hoffs - 1, voffs + 1);
159 cr->line_to(origin_x + hoffs - (hoffs / 4) - 1, voffs + 1);
162 //draw the indicator line
163 if (d_x_indicator > -1 && (unsigned int) d_x_indicator <= max_turn)
165 //draw a line at turn x
166 cr->set_source_rgb(0.0, 0.0, 0.0);
167 cr->move_to((((float)d_x_indicator/ (float)max_turn) * (width - (hoffs * 2))) + hoffs, voffs);
168 cr->line_to((((float)d_x_indicator/ (float)max_turn) * (width - (hoffs * 2))) + hoffs, height - voffs);
172 // draw the labels on the horizontal axis
173 layout->set_font_description (font_desc);
174 layout->set_text("0");
175 layout->get_pixel_size (w, h);
176 cr->move_to(hoffs - (w / 2), origin_y - voffs + (voffs / 4));
177 cr->set_source_rgb (0.0, 0.0, 0.0);
178 cr->set_operator (Cairo::OPERATOR_ATOP);
179 pango_cairo_show_layout (cr->cobj (), layout->gobj ());
181 layout->set_text(String::ucompose("%1", max_turn));
182 layout->get_pixel_size (w, h);
183 cr->move_to((width - (hoffs * 2)) + hoffs - (w / 2),
184 origin_y - voffs + (voffs / 4) + 1);
185 cr->set_source_rgb (0.0, 0.0, 0.0);
186 cr->set_operator (Cairo::OPERATOR_ATOP);
187 pango_cairo_show_layout (cr->cobj (), layout->gobj ());
189 layout->set_text(d_y_axis_description);
190 layout->get_pixel_size (w, h);
191 cr->move_to((width / 2 - (hoffs * 1)) + hoffs - (w / 2),
192 origin_y - voffs + (voffs / 2) + 1);
193 cr->set_source_rgb (0.0, 0.0, 0.0);
194 cr->set_operator (Cairo::OPERATOR_ATOP);
195 pango_cairo_show_layout (cr->cobj (), layout->gobj ());
197 // draw the labels on the vertical axis
198 layout->set_font_description (font_desc);
199 layout->set_text("0");
200 layout->get_pixel_size (w, h);
201 cr->move_to(origin_x + hoffs - (hoffs / 4) - 1 - w, origin_y - voffs - (h/2));
202 cr->set_source_rgb (0.0, 0.0, 0.0);
203 cr->set_operator (Cairo::OPERATOR_ATOP);
204 pango_cairo_show_layout (cr->cobj (), layout->gobj ());
206 layout->set_text(String::ucompose("%1", d_max_height_value));
207 layout->get_pixel_size (w, h);
208 cr->move_to(origin_x + hoffs - (hoffs / 4) - 1 - w, voffs + 1 - (h/2));
209 cr->set_source_rgb (0.0, 0.0, 0.0);
210 cr->set_operator (Cairo::OPERATOR_ATOP);
211 pango_cairo_show_layout (cr->cobj (), layout->gobj ());
213 PangoContext *context;
214 PangoCairoFontMap *fontmap;
215 fontmap = (PangoCairoFontMap *) pango_cairo_font_map_get_default ();
216 context = pango_cairo_font_map_create_context (fontmap);
217 pango_context_set_base_gravity(context, PANGO_GRAVITY_EAST);
218 pango_context_set_gravity_hint(context, PANGO_GRAVITY_HINT_STRONG);
219 layout->context_changed();
221 layout->set_text(d_x_axis_description);
222 layout->get_pixel_size (w, h);
223 cr->move_to(0, height - (voffs * 2) -
224 (0.50 * (height - (voffs * 2.0))) + voffs + (w / 2));
225 cr->rotate(-90 / (180.0 / G_PI));
226 pango_cairo_show_layout (cr->cobj (), layout->gobj ());
233 void LineChart::set_x_indicator(int x)
236 Glib::RefPtr<Gdk::Window> window = get_window();
239 Gtk::Allocation allocation = get_allocation();
240 const int width = allocation.get_width();
241 const int height = allocation.get_height();
242 GdkEventExpose event;
245 event.area.height = height;
246 event.area.width = width;
247 on_expose_event(&event);