]> git.cworth.org Git - acre/blob - acre-x.c
Add another dataset style: ACRE_STYLE_BARS
[acre] / acre-x.c
1 /* acre - A cairo-based library for creating plots and charts.
2  *
3  * Copyright © 2009 Carl Worth <cworth@cworth.org>
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
18  */
19
20 #include <stdbool.h>
21
22 #include <X11/Xlib.h>
23 #include <cairo-xlib.h>
24
25 #include "acre.h"
26 #include "math.h"
27
28 static acre_t *
29 load_chart (void)
30 {
31         acre_t *acre;
32         acre_data_t *data0, *data1, *data2;
33         int i;
34
35         acre = acre_create ();
36         acre_set_x_axis_label (acre, "X axis");
37         acre_set_y_axis_label (acre, "Y axis");
38
39         data0 = acre_data_create ();
40         data1 = acre_data_create ();
41         data2 = acre_data_create ();
42
43         acre_data_set_name (data0, "Data 0");
44         acre_data_set_name (data1, "Data 1");
45         acre_data_set_name (data2, "Data 2");
46
47         for (i = 0; i <= 100; i++) {
48                 acre_data_add_point_2d (data0, i,   0 - (i/3.0)*(i/3.0));
49         }
50
51         for (i = 0; i < 100; i++) {
52                 double t = 1.0 - (i / 100.0);
53                 acre_data_add_point_2d (data1, i, -1000 * (1.0 - t*t*t));
54         }
55         
56         for (i = 0; i <= 1000; i++) {
57                 double t, x, y;
58                 t = i/10.0 - 50;
59                 x = t + 50;
60                 if (t == 0.0)
61                         y = -200;
62                 else
63                         y = -1200 + 1000 * sin(t) / t;
64                 acre_data_add_point_2d (data2, x, y);
65         }
66
67         acre_add_data (acre, data0);
68         acre_add_data (acre, data1);
69         acre_add_data (acre, data2);
70
71         acre_set_title (acre, "All the data");
72
73         return acre;
74 }
75
76 static void
77 draw (Display *dpy, Window window, Visual *visual, acre_t *acre,
78       int width, int height, double x_min, double x_max)
79 {
80         cairo_t *cr;
81         cairo_surface_t *surface;
82
83         surface = cairo_xlib_surface_create (dpy, window, visual,
84                                              width, height);
85         cr = cairo_create (surface);
86
87         /* Erase to white */
88         cairo_set_source_rgb (cr, 1, 1, 1);
89         cairo_paint (cr);
90
91         acre_set_x_axis_range (acre, x_min, x_max);
92         acre_draw (acre, cr, width, height);
93
94         cairo_destroy (cr);
95
96         cairo_surface_destroy (surface);
97 }
98
99
100 static void
101 handle_events(Display *dpy, Window window, Visual *visual,
102               acre_t *acre, int width, int height)
103 {
104         XEvent xev;
105         KeyCode quit_code = XKeysymToKeycode (dpy, XStringToKeysym("Q"));
106         KeyCode escape_code = XKeysymToKeycode (dpy, XStringToKeysym("Escape"));
107         KeyCode left_code = XKeysymToKeycode (dpy, XStringToKeysym("Left"));
108         KeyCode right_code = XKeysymToKeycode (dpy, XStringToKeysym("Right"));
109         KeyCode plus_code = XKeysymToKeycode (dpy, XStringToKeysym("plus"));
110         KeyCode equal_code = XKeysymToKeycode (dpy, XStringToKeysym("equal"));
111         KeyCode minus_code = XKeysymToKeycode (dpy, XStringToKeysym("minus"));
112         KeyCode home_code = XKeysymToKeycode (dpy, XStringToKeysym("Home"));
113         KeyCode keycode;
114         bool need_redraw = false;
115         double x_min, x_max, shift;
116
117         acre_get_x_axis_data_range (acre, &x_min, &x_max);
118
119         while (1) {
120                 if (! XPending (dpy) && need_redraw)
121                         draw (dpy, window, visual, acre,
122                               width, height, x_min, x_max);
123
124 #define PAN  0.05
125 #define ZOOM PAN
126                 XNextEvent (dpy, &xev);
127                 switch (xev.type) {
128                 case KeyPress:
129                         need_redraw = true;
130                         keycode = xev.xkey.keycode;
131                         if (keycode == quit_code ||
132                             keycode == escape_code)
133                         {
134                                 return;
135                         }
136                         else if (keycode == left_code)
137                         {
138                                 shift = PAN * (x_max - x_min);
139                                 x_min += shift;
140                                 x_max += shift;
141                         }
142                         else if (keycode == right_code)
143                         {
144                                 shift = PAN * (x_max - x_min);
145                                 x_min -= shift;
146                                 x_max -= shift;
147                         }
148                         else if (keycode == plus_code ||
149                                    keycode == equal_code)
150                         {
151                                 shift = ZOOM * (x_max - x_min);
152                                 x_min += shift;
153                                 x_max -= shift;
154                         }
155                         else if (keycode == minus_code)
156                         {
157                                 shift = (ZOOM/(1 - 2 * ZOOM)) * (x_max - x_min);
158                                 x_min -= shift;
159                                 x_max += shift;
160                         }
161                         else if (keycode == home_code)
162                         {
163                                 acre_get_x_axis_data_range (acre, &x_min, &x_max);
164                         }
165                         else
166                         {
167                                 need_redraw = false;
168                         }
169                         break;
170                 case ConfigureNotify:
171                         width = xev.xconfigure.width;
172                         height = xev.xconfigure.height;
173                         break;
174                 case Expose:
175                         if (xev.xexpose.count == 0)
176                                 need_redraw = 1;
177                         break;
178                 }
179         }
180 }
181
182 int
183 main (void)
184 {
185         Display *dpy;
186         Window window, root;
187         Visual *visual;
188         acre_t *acre;
189         XSetWindowAttributes window_attr;
190         Colormap colormap;
191         unsigned long window_mask, event_mask;
192         unsigned long white;
193
194         int width = 800;
195         int height = 600;
196
197         acre = load_chart ();
198
199         dpy = XOpenDisplay (NULL);
200
201         if (dpy == NULL) {
202                 fprintf(stderr, "Failed to open display %s\n",
203                         XDisplayName(NULL));
204                 return 1;
205         }
206
207         root = DefaultRootWindow (dpy);
208         white = WhitePixel (dpy, DefaultScreen (dpy));
209         visual = DefaultVisual (dpy, DefaultScreen (dpy));
210         colormap = XCreateColormap (dpy, root, visual, AllocNone);
211         event_mask = KeyPressMask | StructureNotifyMask | ExposureMask;
212
213         window_mask = 0;
214         window_mask |= CWBackPixel;     window_attr.background_pixel = white;
215         window_mask |= CWBorderPixel;   window_attr.border_pixel = white;
216         window_mask |= CWColormap;      window_attr.colormap = colormap;
217         window_mask |= CWEventMask;     window_attr.event_mask = event_mask;
218
219         window = XCreateWindow(dpy, root, 0, 0, width, height, 0,
220                                DefaultDepth (dpy, DefaultScreen (dpy)),
221                                InputOutput, visual,
222                                window_mask, &window_attr);
223
224         XMapWindow (dpy, window);
225
226         handle_events (dpy, window, visual, acre, width, height);
227
228         acre_destroy (acre);
229
230         XDestroyWindow (dpy, window);
231         XCloseDisplay (dpy);
232
233         return 0;
234 }