1 // ----------------------------------------------------------------------------
2 //
3 // Copyright (C) 2008-2015 Fons Adriaensen <fons@linuxaudio.org>
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 //
18 // ----------------------------------------------------------------------------
19
20
21 #include <cairo/cairo.h>
22 #include <cairo/cairo-xlib.h>
23 #include <math.h>
24 #include "rotary.h"
25
26
27 cairo_t *RotaryCtl::_cairotype = 0;
28 cairo_surface_t *RotaryCtl::_cairosurf = 0;
29
30
31 int RotaryCtl::_wb_up = 4;
32 int RotaryCtl::_wb_dn = 5;
33 int RotaryCtl::_keymod = 0;
34 int RotaryCtl::_button = 0;
35 int RotaryCtl::_rcount = 0;
36 int RotaryCtl::_rx = 0;
37 int RotaryCtl::_ry = 0;
38
39
RotaryCtl(X_window * parent,X_callback * cbobj,int cbind,RotaryGeom * rgeom,int xp,int yp)40 RotaryCtl::RotaryCtl (X_window *parent,
41 X_callback *cbobj,
42 int cbind,
43 RotaryGeom *rgeom,
44 int xp,
45 int yp) :
46
47 X_window (parent,
48 rgeom->_x0 + xp, rgeom->_y0 + yp,
49 rgeom->_dx, rgeom->_dy,
50 rgeom->_backg->pixel),
51 _cbobj (cbobj),
52 _cbind (cbind),
53 _rgeom (rgeom),
54 _state (0),
55 _count (0),
56 _value (0),
57 _angle (0)
58 {
59 x_add_events ( ExposureMask
60 | Button1MotionMask | ButtonPressMask | ButtonReleaseMask);
61 }
62
63
~RotaryCtl(void)64 RotaryCtl::~RotaryCtl (void)
65 {
66 }
67
68
init(X_display * disp)69 void RotaryCtl::init (X_display *disp)
70 {
71 _cairosurf = cairo_xlib_surface_create (disp->dpy (), 0, disp->dvi (), 50, 50);
72 _cairotype = cairo_create (_cairosurf);
73 }
74
75
fini(void)76 void RotaryCtl::fini (void)
77 {
78 cairo_destroy (_cairotype);
79 cairo_surface_destroy (_cairosurf);
80 }
81
82
handle_event(XEvent * E)83 void RotaryCtl::handle_event (XEvent *E)
84 {
85 switch (E->type)
86 {
87 case Expose:
88 render ();
89 break;
90
91 case ButtonPress:
92 bpress ((XButtonEvent *) E);
93 break;
94
95 case ButtonRelease:
96 brelse ((XButtonEvent *) E);
97 break;
98
99 case MotionNotify:
100 motion ((XMotionEvent *) E);
101 break;
102
103 default:
104 fprintf (stderr, "RotaryCtl: event %d\n", E->type );
105 }
106 }
107
108
bpress(XButtonEvent * E)109 void RotaryCtl::bpress (XButtonEvent *E)
110 {
111 int r = 0;
112 double d;
113
114 d = hypot (E->x - _rgeom->_xref, E->y - _rgeom->_yref);
115 if (d > _rgeom->_rad + 3) return;
116 _keymod = E->state;
117 if (E->button < 4)
118 {
119 _rx = E->x;
120 _ry = E->y;
121 _button = E->button;
122 r = handle_button ();
123 _rcount = _count;
124 }
125 else if (_button) return;
126 else if ((int)E->button == _wb_up)
127 {
128 r = handle_mwheel (1);
129 }
130 else if ((int)E->button == _wb_dn)
131 {
132 r = handle_mwheel (-1);
133 }
134 if (r)
135 {
136 callback (r);
137 render ();
138 }
139 }
140
141
brelse(XButtonEvent * E)142 void RotaryCtl::brelse (XButtonEvent *E)
143 {
144 if (_button == (int)E->button)
145 {
146 _button = 0;
147 callback (RELSE);
148 }
149 }
150
151
motion(XMotionEvent * E)152 void RotaryCtl::motion (XMotionEvent *E)
153 {
154 int dx, dy, r;
155
156 if (_button)
157 {
158 _keymod = E->state;
159 dx = E->x - _rx;
160 dy = E->y - _ry;
161 r = handle_motion (dx, dy);
162 if (r)
163 {
164 callback (r);
165 render ();
166 }
167 }
168 }
169
170
set_state(int s)171 void RotaryCtl::set_state (int s)
172 {
173 if (_state != s)
174 {
175 _state = s;
176 render ();
177 }
178 }
179
180
render(void)181 void RotaryCtl::render (void)
182 {
183 double a, c, r, x, y;
184
185 // A very weird bugfix. Without this, the cairo line
186 // draw below fails if the line is exactly horizontal
187 // or vertical. No amount of XFlush(), cairo_surface_flush()
188 // or cairo_surface_mark_dirty() seems to help, but this
189 // XDrawline does.
190 XDrawLine (dpy (), win (), dgc (), 0, 0, 0, 0);
191
192 XPutImage (dpy (), win (), dgc (), _rgeom->_image [_state],
193 _rgeom->_x0, _rgeom->_y0, 0, 0, _rgeom->_dx, _rgeom->_dy);
194 XFlush (dpy ());
195 cairo_xlib_surface_set_drawable (_cairosurf, win(),_rgeom->_dx, _rgeom->_dy);
196 c = _rgeom->_lncol [_state] ? 1.0 : 0.0;
197 a = _angle * M_PI / 180;
198 r = _rgeom->_rad;
199 x = _rgeom->_xref;
200 y = _rgeom->_yref;
201 cairo_new_path (_cairotype);
202 cairo_move_to (_cairotype, x, y);
203 x += r * sin (a);
204 y -= r * cos (a);
205 cairo_line_to (_cairotype, x, y);
206 cairo_set_source_rgb (_cairotype, c, c, c);
207 cairo_set_line_width (_cairotype, c ? 2.2 : 1.8);
208 cairo_stroke (_cairotype);
209 cairo_surface_flush (_cairosurf);
210 }
211
212
213