Non reinvents the DAW. Powerful enough to form a complete studio, fast and light enough to run on low-end hardware like the eeePC or Raspberry Pi, and so reliable that it can be used live https://non.tuxfamily.org/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

342 lines
8.9KB

  1. /*******************************************************************************/
  2. /* Copyright (C) 2013 Jonathan Moore Liles */
  3. /* */
  4. /* This program is free software; you can redistribute it and/or modify it */
  5. /* under the terms of the GNU General Public License as published by the */
  6. /* Free Software Foundation; either version 2 of the License, or (at your */
  7. /* option) any later version. */
  8. /* */
  9. /* This program is distributed in the hope that it will be useful, but WITHOUT */
  10. /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
  11. /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for */
  12. /* more details. */
  13. /* */
  14. /* You should have received a copy of the GNU General Public License along */
  15. /* with This program; see the file COPYING. If not,write to the Free Software */
  16. /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
  17. /*******************************************************************************/
  18. #include "Fl_SliderX.H"
  19. #include <FL/Fl.H>
  20. #include <FL/fl_draw.H>
  21. #include <math.h>
  22. void
  23. Fl_SliderX::draw ( int X, int Y, int W, int H)
  24. {
  25. slider_size( horizontal() ? H / (float)W : W / (float)H );
  26. int act = active_r();
  27. if (damage()&FL_DAMAGE_ALL) draw_box();
  28. int ww = (horizontal() ? W : H);
  29. int hh = (horizontal() ? H : W);
  30. int xx, S;
  31. xx = slider_position( value(), ww );
  32. S = (horizontal() ? H : W );
  33. int xsl, ysl, wsl, hsl;
  34. if (horizontal()) {
  35. xsl = X+xx;
  36. wsl = S;
  37. ysl = Y + hh/2;
  38. hsl = hh/4;
  39. } else {
  40. ysl = Y+xx;
  41. hsl = S;
  42. xsl = X + hh/2;
  43. wsl = hh/4;
  44. }
  45. {
  46. fl_push_clip(X, Y, W, H);
  47. draw_box();
  48. fl_pop_clip();
  49. }
  50. //draw_bg(X, Y, W, H);
  51. fl_line_style( FL_SOLID, hh/6 );
  52. Fl_Color c = fl_darker(color());
  53. if ( !act )
  54. c = fl_inactive(c);
  55. fl_color(c);
  56. if ( horizontal() )
  57. fl_line ( X + S/2, Y + hh/2, X + W - S/2, Y + hh/2 );
  58. else
  59. fl_line ( X + hh/2, Y + S/2, X + hh/2, Y + H - S/2 );
  60. c = selection_color();
  61. if ( !act )
  62. c = fl_inactive(c);
  63. fl_color( c );
  64. if ( horizontal() )
  65. fl_line ( X + S/2, ysl, xsl + S/2, ysl );
  66. else
  67. fl_line ( X + S/2, Y + H - S/2, xsl, ysl + (S/2) );
  68. fl_line_style( FL_SOLID, 0 );
  69. if ( act )
  70. {
  71. fl_push_matrix();
  72. if ( horizontal() )
  73. fl_translate( xsl + (hh/2), ysl);
  74. else
  75. fl_translate( xsl, ysl + (hh/2) );
  76. fl_color( fl_color_add_alpha( FL_WHITE, 127 ));
  77. fl_begin_polygon(); fl_circle(0.0,0.0, hh/3); fl_end_polygon();
  78. fl_color( FL_WHITE );
  79. fl_begin_polygon(); fl_circle(0.0,0.0, hh/6); fl_end_polygon();
  80. fl_pop_matrix();
  81. }
  82. draw_label(xsl, ysl, wsl, hsl);
  83. if (Fl::focus() == this) {
  84. draw_focus();
  85. }
  86. /* draw(x()+Fl::box_dx(box()), */
  87. /* y()+Fl::box_dy(box()), */
  88. /* w()-Fl::box_dw(box()), */
  89. /* h()-Fl::box_dh(box())); */
  90. }
  91. /** return a value between 0.0 and 1.0 which represents the current slider position. */
  92. int
  93. Fl_SliderX::slider_position ( double value, int w )
  94. {
  95. double A = minimum();
  96. double B = maximum();
  97. if (B == A) return 0;
  98. bool flip = B < A;
  99. if (flip) {A = B; B = minimum();}
  100. // if (!horizontal()) flip = !flip;
  101. // if both are negative, make the range positive:
  102. if (B <= 0) {flip = !flip; double t = A; A = -B; B = -t; value = -value;}
  103. double fraction;
  104. if (!log()) {
  105. // linear slider
  106. fraction = (value-A)/(B-A);
  107. } else if (A > 0) {
  108. // logatithmic slider
  109. if (value <= A) fraction = 0;
  110. else fraction = (::log(value)-::log(A))/(::log(B)-::log(A));
  111. } else if (A == 0) {
  112. // squared slider
  113. if (value <= 0) fraction = 0;
  114. else fraction = sqrt(value/B);
  115. } else {
  116. // squared signed slider
  117. if (value < 0) fraction = (1-sqrt(value/A))*.5;
  118. else fraction = (1+sqrt(value/B))*.5;
  119. }
  120. if (flip) fraction = 1-fraction;
  121. w -= int(slider_size()*w+.5); if (w <= 0) return 0;
  122. if (fraction >= 1) return w;
  123. else if (fraction <= 0) return 0;
  124. else return int(fraction*w+.5);
  125. }
  126. double
  127. Fl_SliderX::slider_value ( int X, int w )
  128. {
  129. w -= int(slider_size()*w+.5); if (w <= 0) return minimum();
  130. double A = minimum();
  131. double B = maximum();
  132. bool flip = B < A;
  133. if (flip) {A = B; B = minimum();}
  134. // if (!horizontal()) flip = !flip;
  135. if (flip) X = w-X;
  136. double fraction = double(X)/w;
  137. if (fraction <= 0) return A;
  138. if (fraction >= 1) return B;
  139. // if both are negative, make the range positive:
  140. flip = (B <= 0);
  141. if (flip) {double t = A; A = -B; B = -t; fraction = 1-fraction;}
  142. double value;
  143. double derivative;
  144. if (!log()) {
  145. // linear slider
  146. value = fraction*(B-A)+A;
  147. derivative = (B-A)/w;
  148. } else if (A > 0) {
  149. // log slider
  150. double d = (::log(B)-::log(A));
  151. value = exp(fraction*d+::log(A));
  152. derivative = value*d/w;
  153. } else if (A == 0) {
  154. // squared slider
  155. value = fraction*fraction*B;
  156. derivative = 2*fraction*B/w;
  157. } else {
  158. // squared signed slider
  159. fraction = 2*fraction - 1;
  160. if (fraction < 0) B = A;
  161. value = fraction*fraction*B;
  162. derivative = 4*fraction*B/w;
  163. }
  164. // find nicest multiple of 10,5, or 2 of step() that is close to 1 pixel:
  165. if (step() && derivative > step()) {
  166. double w = log10(derivative);
  167. double l = ceil(w);
  168. int num = 1;
  169. int i; for (i = 0; i < l; i++) num *= 10;
  170. int denom = 1;
  171. for (i = -1; i >= l; i--) denom *= 10;
  172. if (l-w > 0.69897) denom *= 5;
  173. else if (l-w > 0.30103) denom *= 2;
  174. value = floor(value*denom/num+.5)*num/denom;
  175. }
  176. if (flip) return -value;
  177. return value;
  178. }
  179. int Fl_SliderX::handle(int event, int X, int Y, int W, int H) {
  180. // Fl_Widget_Tracker wp(this);
  181. switch (event) {
  182. case FL_PUSH: {
  183. Fl_Widget_Tracker wp(this);
  184. if (!Fl::event_inside(X, Y, W, H)) return 0;
  185. handle_push();
  186. if (wp.deleted()) return 1; }
  187. // fall through ...
  188. case FL_DRAG: {
  189. static int offcenter;
  190. int ww = (horizontal() ? W : H);
  191. if ( event == FL_PUSH )
  192. {
  193. int x = slider_position( value(), ww );
  194. offcenter = (horizontal() ? (Fl::event_x()-X) - x : (Fl::event_y()-Y) - x );
  195. }
  196. try_again:
  197. int mx = (horizontal() ? Fl::event_x()-X : Fl::event_y()-Y) - offcenter;
  198. double v = slider_value( mx, ww );
  199. if (event == FL_PUSH ) // && v == value()) {
  200. {
  201. int os = int(slider_size()*ww+0.5)/2;
  202. if ( abs( offcenter ) > os )
  203. {
  204. offcenter = os;
  205. event = FL_DRAG;
  206. goto try_again;
  207. }
  208. }
  209. handle_drag(clamp(v));
  210. } return 1;
  211. case FL_RELEASE:
  212. handle_release();
  213. return 1;
  214. case FL_KEYBOARD:
  215. { Fl_Widget_Tracker wp(this);
  216. switch (Fl::event_key()) {
  217. case FL_Up:
  218. if (horizontal()) return 0;
  219. handle_push();
  220. if (wp.deleted()) return 1;
  221. handle_drag(clamp(increment(value(),-1)));
  222. if (wp.deleted()) return 1;
  223. handle_release();
  224. return 1;
  225. case FL_Down:
  226. if (horizontal()) return 0;
  227. handle_push();
  228. if (wp.deleted()) return 1;
  229. handle_drag(clamp(increment(value(),1)));
  230. if (wp.deleted()) return 1;
  231. handle_release();
  232. return 1;
  233. case FL_Left:
  234. if (!horizontal()) return 0;
  235. handle_push();
  236. if (wp.deleted()) return 1;
  237. handle_drag(clamp(increment(value(),-1)));
  238. if (wp.deleted()) return 1;
  239. handle_release();
  240. return 1;
  241. case FL_Right:
  242. if (!horizontal()) return 0;
  243. handle_push();
  244. if (wp.deleted()) return 1;
  245. handle_drag(clamp(increment(value(),1)));
  246. if (wp.deleted()) return 1;
  247. handle_release();
  248. return 1;
  249. default:
  250. return 0;
  251. }
  252. }
  253. // break not required because of switch...
  254. case FL_FOCUS :
  255. case FL_UNFOCUS :
  256. if (Fl::visible_focus()) {
  257. redraw();
  258. return 1;
  259. } else return 0;
  260. case FL_ENTER :
  261. case FL_LEAVE :
  262. return 1;
  263. case FL_MOUSEWHEEL :
  264. {
  265. if ( this != Fl::belowmouse() )
  266. return 0;
  267. if (Fl::e_dy==0)
  268. return 0;
  269. const int steps = Fl::event_ctrl() ? 128 : 16;
  270. const float step = fabs( maximum() - minimum() ) / (float)steps;
  271. int dy = Fl::e_dy;
  272. /* slider is in 'upside down' configuration, invert meaning of mousewheel */
  273. if ( minimum() > maximum() )
  274. dy = 0 - dy;
  275. handle_drag(clamp(value() + step * dy));
  276. return 1;
  277. }
  278. default:
  279. return 0;
  280. }
  281. }
  282. int Fl_SliderX::handle(int event) {
  283. if (event == FL_PUSH && Fl::visible_focus()) {
  284. Fl::focus(this);
  285. redraw();
  286. }
  287. return handle(event,
  288. x()+Fl::box_dx(box()),
  289. y()+Fl::box_dy(box()),
  290. w()-Fl::box_dw(box()),
  291. h()-Fl::box_dh(box()));
  292. }