]> git.cworth.org Git - acre/blob - acre-x.c
Zoom and pan a bit less with each keypress
[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 left_code = XKeysymToKeycode (dpy, XStringToKeysym("Left"));
107         KeyCode right_code = XKeysymToKeycode (dpy, XStringToKeysym("Right"));
108         KeyCode plus_code = XKeysymToKeycode (dpy, XStringToKeysym("plus"));
109         KeyCode equal_code = XKeysymToKeycode (dpy, XStringToKeysym("equal"));
110         KeyCode minus_code = XKeysymToKeycode (dpy, XStringToKeysym("minus"));
111         KeyCode home_code = XKeysymToKeycode (dpy, XStringToKeysym("Home"));
112         KeyCode keycode;
113         bool need_redraw = false;
114         double x_min, x_max, shift;
115
116         acre_get_x_axis_data_range (acre, &x_min, &x_max);
117
118         while (1) {
119                 if (! XPending (dpy) && need_redraw)
120                         draw (dpy, window, visual, acre,
121                               width, height, x_min, x_max);
122
123 #define PAN  0.05
124 #define ZOOM PAN
125                 XNextEvent (dpy, &xev);
126                 switch (xev.type) {
127                 case KeyPress:
128                         keycode = xev.xkey.keycode;
129                         if (keycode == quit_code)
130                         {
131                                 return;
132                         }
133                         else if (keycode == left_code)
134                         {
135                                 shift = PAN * (x_max - x_min);
136                                 x_min += shift;
137                                 x_max += shift;
138                         }
139                         else if (keycode == right_code)
140                         {
141                                 shift = PAN * (x_max - x_min);
142                                 x_min -= shift;
143                                 x_max -= shift;
144                         }
145                         else if (keycode == plus_code ||
146                                    keycode == equal_code)
147                         {
148                                 shift = ZOOM * (x_max - x_min);
149                                 x_min += shift;
150                                 x_max -= shift;
151                         }
152                         else if (keycode == minus_code)
153                         {
154                                 shift = (1- 2*ZOOM) * (x_max - x_min);
155                                 x_min -= shift;
156                                 x_max += shift;
157                         }
158                         else if (keycode == home_code)
159                         {
160                                 acre_get_x_axis_data_range (acre, &x_min, &x_max);
161                         }
162                         need_redraw = 1;
163                         break;
164                 case ConfigureNotify:
165                         width = xev.xconfigure.width;
166                         height = xev.xconfigure.height;
167                         break;
168                 case Expose:
169                         if (xev.xexpose.count == 0)
170                                 need_redraw = 1;
171                         break;
172                 }
173         }
174 }
175
176 int
177 main (void)
178 {
179         Display *dpy;
180         Window window, root;
181         Visual *visual;
182         acre_t *acre;
183         XSetWindowAttributes window_attr;
184         Colormap colormap;
185         unsigned long window_mask, event_mask;
186         unsigned long white;
187
188         int width = 800;
189         int height = 600;
190
191         acre = load_chart ();
192
193         dpy = XOpenDisplay (NULL);
194
195         if (dpy == NULL) {
196                 fprintf(stderr, "Failed to open display %s\n",
197                         XDisplayName(NULL));
198                 return 1;
199         }
200
201         root = DefaultRootWindow (dpy);
202         white = WhitePixel (dpy, DefaultScreen (dpy));
203         visual = DefaultVisual (dpy, DefaultScreen (dpy));
204         colormap = XCreateColormap (dpy, root, visual, AllocNone);
205         event_mask = KeyPressMask | StructureNotifyMask | ExposureMask;
206
207         window_mask = 0;
208         window_mask |= CWBackPixel;     window_attr.background_pixel = white;
209         window_mask |= CWBorderPixel;   window_attr.border_pixel = white;
210         window_mask |= CWColormap;      window_attr.colormap = colormap;
211         window_mask |= CWEventMask;     window_attr.event_mask = event_mask;
212
213         window = XCreateWindow(dpy, root, 0, 0, width, height, 0,
214                                DefaultDepth (dpy, DefaultScreen (dpy)),
215                                InputOutput, visual,
216                                window_mask, &window_attr);
217
218         XMapWindow (dpy, window);
219
220         handle_events (dpy, window, visual, acre, width, height);
221
222         acre_destroy (acre);
223
224         XDestroyWindow (dpy, window);
225         XCloseDisplay (dpy);
226
227         return 0;
228 }