Use Display as background for LineGraph
[libprolooks.git] / src / Display.vala
blob7891293ed7f824b304e8e80891daa9c8850601b8
1 /*
2 Copyright 2009 by Hans Baier
3 License: LGPLv2+
4 */
6 using Gtk;
7 using Gdk;
9 namespace Prolooks {
11 public abstract class DisplayBase : DrawingArea {
12 private Cairo.Surface? cache_surface = null;
14 public int width {
15 get {
16 return _width;
20 public int height {
21 get {
22 return _height;
26 public double inner_x {
27 get {
28 return _show_glass_rim ? 7.5 : 3.5;
32 public double inner_y {
33 get {
34 return _show_glass_rim ? 6.5 : 3.5;
38 private bool _show_glass_rim = true;
39 public bool show_glass_rim {
40 get { return _show_glass_rim; }
41 set {
42 _show_glass_rim = value;
43 cache_surface = null;
44 queue_draw ();
48 public double inner_width {
49 get {
50 return _show_glass_rim ? (_width - 14) : (_width - 6);
54 public double inner_height {
55 get {
56 return _show_glass_rim ? (_height - 13) : (_height - 6);
60 protected int _width = 383;
61 protected int _height = 72;
63 private bool _show_matrix = true;
64 [Description(nick="show matrix", blurb="Whether a pixel matrix should be drawn in the display background (much faster if false)")]
65 public bool show_matrix {
66 get { return _show_matrix; }
67 set {
68 _show_matrix = value;
69 cache_surface = null;
70 queue_draw ();
74 construct {
75 add_events (Gdk.EventMask.BUTTON_PRESS_MASK
76 | Gdk.EventMask.BUTTON_RELEASE_MASK
77 | Gdk.EventMask.POINTER_MOTION_MASK);
78 draw.connect(on_draw);
81 public static void outer_rim_for_display(Cairo.Context cr, double x, double y, double w, double h, Color outside, double rounded_corner_radius = 5.0) {
82 Color inside;
83 Color inside_left;
84 Color inside_top;
85 Color inside_right;
86 Color inside_bottom;
88 Color.parse("#010101", out inside);
89 Color.parse("#525357", out inside_left);
90 Color.parse("#444444", out inside_top);
91 inside_right = outside;
92 inside_bottom = outside;
94 var horiz_rim_left_x = rounded_corner_radius - 1;
95 var horiz_rim_right_x = w - rounded_corner_radius + 2;
96 var top_rim_y = 1.5;
97 var bottom_rim_y = h - 1.5;
99 var vert_rim_top_y = rounded_corner_radius - 1;
100 var vert_rim_bottom_y = h - rounded_corner_radius + 1;
101 var right_rim_x = w - 0.5;
102 var left_rim_x = 1.5;
104 // inside background
105 rounded_rect (cr, 1, 1, w - 2, h - 2, rounded_corner_radius, rounded_corner_radius);
106 set_source_color(cr, inside);
107 cr.fill ();
109 // top rim
110 cr.move_to (horiz_rim_left_x, top_rim_y);
111 cr.line_to (horiz_rim_right_x, top_rim_y);
112 set_source_color(cr, inside_top);
113 cr.stroke ();
115 // right rim
116 cr.move_to (right_rim_x, vert_rim_top_y);
117 cr.line_to (right_rim_x, vert_rim_bottom_y);
118 set_source_color (cr, inside_right);
119 cr.stroke ();
121 // bottom rim
122 cr.move_to (horiz_rim_right_x, bottom_rim_y);
123 cr.line_to (horiz_rim_left_x, bottom_rim_y);
124 set_source_color (cr, inside_bottom);
125 cr.stroke();
127 // left rim
128 cr.move_to (left_rim_x, vert_rim_bottom_y);
129 cr.line_to (left_rim_x, vert_rim_top_y);
130 set_source_color (cr, inside_left);
131 cr.stroke();
134 public static const string matrix_dot_base_color = "#41403e";
135 public static Gdk.Color matrix_dot_color () {
136 return shade_color (color_from_string (matrix_dot_base_color), 0.5);
139 public static void dot_matrix(Cairo.Context cr, double x, double y, double w, double h, Gdk.Color color) {
140 cr.save();
141 set_source_color (cr, color);
142 for (double i = x + 1; i < x + w; i++) {
143 for (double j = y + 1; j < y + h; j++) {
144 if (((long)i % 2) == 0 && ((long)j % 2) == 1) {
145 cr.move_to (i - 0.5, j);
146 cr.line_to (i + 0.5, j);
147 cr.stroke();
151 cr.restore();
154 public static void inner_glass_rim(Cairo.Context cr, double x, double y, double w, double h, double radius = 4.0) {
155 Color rim_left_top1;
156 Color rim_left_bottom1;
157 Color rim_left_top2;
158 Color rim_left_bottom2;
159 Color rim_right_top;
160 Color rim_right_bottom;
161 Color rim_top1;
162 Color rim_top2;
163 Color rim_bottom;
165 Color.parse("#2a282d", out rim_left_top1);
166 Color.parse("#2b2c2e", out rim_left_bottom1);
167 Color.parse("#1b191c", out rim_left_top2);
168 Color.parse("#1d181f", out rim_left_bottom2);
169 Color.parse("#3d3b3c", out rim_right_top);
170 Color.parse("#3a4036", out rim_right_bottom);
171 Color.parse("#605b5f", out rim_top1);
172 Color.parse("#2f2e33", out rim_top2);
173 Color.parse("#3e403d", out rim_bottom);
175 Color test;
176 Color.parse("#ff0000", out test);
178 double ARC_TO_BEZIER = 0.55228475;
180 if (radius > w - radius)
181 radius = w / 2;
182 if (radius > h - radius)
183 radius = h / 2;
185 // approximate (quite close) the arc using a bezier curve
186 var c = ARC_TO_BEZIER * radius;
188 cr.set_line_width(1.0);
190 // rim_top1
191 cr.move_to ( x + radius, y);
192 cr.rel_line_to ( w - 2 * radius, 0.0);
193 set_source_color (cr, rim_top1);
194 cr.stroke ();
196 // rim top2
197 cr.move_to ( x + radius, y + 1);
198 cr.rel_line_to ( w - 2 * radius, 0.0);
199 set_source_color(cr, rim_top2);
200 cr.stroke ();
202 // right top corner
203 cr.move_to (x + w - radius, y);
204 cr.rel_curve_to ( c, 0.0, radius, c, radius, radius);
205 set_source_color (cr, rim_top1);
206 cr.stroke ();
208 // rim right
209 cr.move_to (x + w, y + radius);
210 var dy = h - 2 * radius;
211 cr.set_source (create_gradient(0, 0, 0, dy, rim_right_top, rim_right_bottom));
212 cr.rel_line_to (0, dy);
213 cr.stroke ();
215 // right bottom corner
216 cr.move_to (x + w, y + h - radius);
217 cr.rel_curve_to ( 0.0, c, c - radius, radius, -radius, radius);
218 set_source_color (cr, rim_right_bottom);
219 cr.stroke ();
221 // bottom line
222 cr.move_to (x + w - radius, y + h);
223 cr.rel_line_to (-w + 2 * radius, 0);
224 set_source_color (cr, rim_bottom);
225 cr.stroke ();
227 // bottom left corner
228 cr.move_to (x + radius, y + h);
229 cr.rel_curve_to ( -c, 0, -radius, -c, -radius, -radius);
230 set_source_color (cr, rim_left_bottom1);
231 cr.stroke ();
233 // rim left
234 cr.move_to (x, y + h - radius);
235 cr.set_source (create_gradient(0, 0, 0, y, rim_left_top1, rim_left_bottom1));
236 cr.rel_line_to (0, -h + 2 * radius);
237 cr.stroke ();
239 // rim left shadow
240 cr.move_to (x + 1, y + h - radius);
241 cr.set_source (create_gradient(0, 0, 0, y, rim_left_top2, rim_left_bottom2));
242 cr.rel_line_to (0, -h + 2 * radius);
243 cr.stroke ();
245 // top left corner
246 cr.move_to (x, y + radius);
247 cr.rel_curve_to (0.0, -c, radius - c, -radius, radius, -radius);
248 set_source_color (cr, rim_top1);
249 cr.stroke ();
251 // top left corner (adding thickness)
252 cr.move_to (x + 1, y + radius);
253 cr.rel_curve_to (0.0, -c, radius - c, -radius, radius, -radius + 1);
254 set_source_color (cr, rim_top1);
255 cr.stroke ();
259 public static const string text_color_default = "#9fc717";
261 public static void set_font (
262 Cairo.Context cr,
263 double size,
264 string family = "FreeSans",
265 Cairo.FontSlant slant = Cairo.FontSlant.NORMAL,
266 Cairo.FontWeight weight = Cairo.FontWeight.NORMAL) {
268 cr.select_font_face (family, slant, weight);
269 cr.set_font_size (size);
272 public static void text (Cairo.Context cr, string text, double x, double y, double size, string color = text_color_default) {
273 Color text_color;
274 Color.parse (color, out text_color);
275 set_source_color (cr, text_color);
276 set_font (cr, size);
278 cr.move_to (x, y);
279 cr.show_text (text);
282 public static void lcd(Cairo.Context cr, double w, double h, double radius = 5.0) {
283 Color green_rim_top;
284 Color green_rim_bottom;
285 Color.parse ("#2c4329", out green_rim_top);
286 Color.parse ("#101d09", out green_rim_bottom);
287 cr.set_source (create_gradient (0.0, 0.0, 0.0, h, green_rim_top, green_rim_bottom, 1.0, 1.0));
288 rounded_rect (cr, 0.0, 0.0, w, h, radius, radius);
289 cr.stroke ();
291 cr.set_source (create_gradient (0.0, 0.0, 0.0, h, green_rim_top, green_rim_bottom, 0.5, 0.5));
292 rounded_rect (cr, 0.0, 0.0, w, h, radius, radius);
293 cr.fill ();
296 public static void reflection(Cairo.Context cr, double w, double h, double reflection_start = -1) {
297 // reflection
298 if (reflection_start < 0)
299 reflection_start = h - 3;
301 cr.new_path ();
302 cr.move_to (0.0, 0.0);
303 cr.line_to (0.0, reflection_start);
304 cr.curve_to (w / 3.0, h / 3.0, w * 2.0 / 3.0, 17.0 * h / 59.0, w, 15.0 * h / 59.0);
305 cr.line_to (w, 0.0);
306 cr.close_path ();
307 cr.set_source_rgba(0.8, 0.9, 0.1, 0.06);
308 cr.fill ();
311 /* Widget is asked to draw itself */
312 public bool on_draw (Cairo.Context c) {
313 //Color test_color = color_from_string ("#ff0000");
314 Gtk.Allocation allocation;
315 get_allocation(out allocation);
317 if (_width != allocation.width || _height != allocation.height) {
318 _width = allocation.width;
319 _height = allocation.height;
320 cache_surface = null;
323 // Create a Cairo context
324 var cr = Gdk.cairo_create (this.get_window());
325 set_line_width_from_device (cr);
328 if (cache_surface == null) {
329 cache_surface = new Cairo.Surface.similar (cr.get_target (),
330 Cairo.Content.COLOR_ALPHA,
331 _width,
332 _height);
334 Cairo.Context cache_cr = new Cairo.Context ( cache_surface );
336 set_line_width_from_device (cache_cr);
338 DisplayBase.outer_rim_for_display (cache_cr, 0, 0, _width, _height, style.bg[(int)Gtk.StateType.NORMAL]);
340 if (show_glass_rim) {
341 cache_cr.translate (4.5, 3.5);
342 inner_glass_rim (cache_cr, 0, 0, _width - 8, _height - 9, 2);
345 cache_cr.translate (3.0, 3.0);
347 lcd(cache_cr, inner_width, inner_height, _height > 30 ? 5.0 : 3.0);
349 if (show_matrix) {
350 dot_matrix (cache_cr, _show_glass_rim ? 0 : 0.5, _show_glass_rim ? 0 : 0.5, inner_width, inner_height, matrix_dot_color ());
354 cr.set_source_surface (cache_surface, 0, 0);
355 cr.paint ();
357 cr.translate (inner_x, inner_y);
359 draw_contents(cr);
361 reflection(cr, inner_width, inner_height);
363 return true;
366 // Template method
367 protected abstract bool draw_contents(Cairo.Context cr);
370 } // namespace Prolooks