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 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 64 RotaryCtl::~RotaryCtl (void) 65 { 66 } 67 68 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 76 void RotaryCtl::fini (void) 77 { 78 cairo_destroy (_cairotype); 79 cairo_surface_destroy (_cairosurf); 80 } 81 82 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 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 142 void RotaryCtl::brelse (XButtonEvent *E) 143 { 144 if (_button == (int)E->button) 145 { 146 _button = 0; 147 callback (RELSE); 148 } 149 } 150 151 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 171 void RotaryCtl::set_state (int s) 172 { 173 if (_state != s) 174 { 175 _state = s; 176 render (); 177 } 178 } 179 180 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