Flu_Spinner.cpp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. // $Id: Flu_Spinner.cpp,v 1.20 2004/10/22 16:17:45 jbryan Exp $
  2. /***************************************************************
  3. * FLU - FLTK Utility Widgets
  4. * Copyright (C) 2002 Ohio Supercomputer Center, Ohio State University
  5. *
  6. * This file and its content is protected by a software license.
  7. * You should have received a copy of this license with this file.
  8. * If not, please contact the Ohio Supercomputer Center immediately:
  9. * Attn: Jason Bryan Re: FLU 1224 Kinnear Rd, Columbus, Ohio 43212
  10. *
  11. ***************************************************************/
  12. #include <stdio.h>
  13. #include <string.h>
  14. #include <FL/Fl.H>
  15. #include <FL/fl_draw.H>
  16. #include <stdlib.h>
  17. #include <FL/math.h>
  18. #include "FLU/Flu_Spinner.H"
  19. #define ABS( x ) ( (x)>0 ? (x) : -(x) )
  20. Flu_Spinner :: NoTabInput :: NoTabInput( Flu_Spinner *s, int x, int y, int w, int h, const char *l )
  21. : Fl_Input( x, y, w, h, l )
  22. {
  23. spinner = s;
  24. }
  25. int Flu_Spinner :: NoTabInput :: handle( int event )
  26. {
  27. switch( event )
  28. {
  29. case FL_KEYDOWN:
  30. {
  31. switch( Fl::event_key() )
  32. {
  33. case FL_Tab:
  34. redraw();
  35. return 0;
  36. case FL_Enter:
  37. case FL_KP_Enter:
  38. Fl_Input::handle( event );
  39. spinner->value( spinner->clamp( atof( value() ) ) );
  40. spinner->do_callback();
  41. return 1;
  42. case FL_Down:
  43. case FL_Up:
  44. spinner->handle( event );
  45. return 1;
  46. }
  47. }
  48. break;
  49. case FL_FOCUS:
  50. case FL_UNFOCUS:
  51. redraw();
  52. break;
  53. }
  54. return Fl_Input::handle( event );
  55. }
  56. void Flu_Spinner :: NoTabInput :: draw()
  57. {
  58. if( spinner->active() )
  59. activate();
  60. else
  61. deactivate();
  62. if( spinner->_dragging )
  63. {
  64. if( (spinner->align() & FL_ALIGN_INSIDE) || !spinner->editable() )
  65. position( size() );
  66. else
  67. position( 0, size() );
  68. }
  69. Fl_Input::draw();
  70. if( Fl::focus() == this && ( (spinner->align() & FL_ALIGN_INSIDE) || !spinner->editable() ) )
  71. draw_focus( box(), x(), y(), w(), h() );
  72. }
  73. Flu_Spinner :: Flu_Spinner( int X, int Y, int W, int H, const char* l )
  74. : Fl_Valuator( X, Y, W, H, l ), _input( this, X, Y, W, H, 0 )
  75. {
  76. // we always want the buttons to be square and half the height of the widget
  77. int wid = W*15/100;
  78. if( wid < H/2 )
  79. wid = H/2;
  80. _wrapRange = false;
  81. _dragging = false;
  82. _editable = true;
  83. _totalTime = 0.0f;
  84. _initialDelay = 0.5f;
  85. _repeatTime[0] = 0.1f;
  86. _repeatTime[1] = 0.02f;
  87. _rapidDelay = 2.0f;
  88. _doRepeat = true;
  89. _pushed = false;
  90. _valbox[0] = _valbox[1] = FL_UP_BOX;
  91. box( FL_DOWN_BOX );
  92. align( FL_ALIGN_LEFT );
  93. when( FL_WHEN_CHANGED );
  94. precision( 2 );
  95. range( 0, 1 );
  96. value( 0 );
  97. {
  98. _input.callback(input_cb, this);
  99. _input.resize( X, Y, W-wid-1, H );
  100. _input.color( FL_WHITE, FL_SELECTION_COLOR );
  101. _input.textfont( FL_HELVETICA );
  102. _input.textsize( FL_NORMAL_SIZE );
  103. _input.textcolor( FL_FOREGROUND_COLOR );
  104. _input.type( FL_FLOAT_INPUT );
  105. value_damage();
  106. }
  107. }
  108. Flu_Spinner::~Flu_Spinner()
  109. {
  110. Fl::remove_timeout(repeat_callback, this);
  111. }
  112. // taken from Fl_Counter.cxx
  113. void Flu_Spinner :: input_cb( Fl_Widget*, void* v )
  114. {
  115. Flu_Spinner& t = *(Flu_Spinner*)v;
  116. if( t.align() & FL_ALIGN_INSIDE )
  117. return;
  118. double nv;
  119. if ((t.step() - floor(t.step()))>0.0 || t.step() == 0.0)
  120. nv = strtod(t._input.value(), 0);
  121. else
  122. nv = strtol(t._input.value(), 0, 0);
  123. if( nv != t.value() || t._input.when() & FL_WHEN_NOT_CHANGED)
  124. {
  125. if( nv < t.minimum() )
  126. {
  127. t.set_value(t.minimum());
  128. t.value_damage();
  129. }
  130. else if( nv > t.maximum() )
  131. {
  132. t.set_value(t.maximum());
  133. t.value_damage();
  134. }
  135. else
  136. t.set_value(nv);
  137. if( t.when() )
  138. {
  139. t.clear_changed();
  140. t.do_callback();
  141. }
  142. else
  143. {
  144. t.set_changed();
  145. }
  146. }
  147. t.value_damage();
  148. }
  149. void Flu_Spinner :: resize( int X, int Y, int W, int H )
  150. {
  151. // we always want the buttons to be square and half the height of the widget
  152. Fl_Valuator::resize( X, Y, W, H );
  153. }
  154. void Flu_Spinner :: value_damage()
  155. {
  156. char *buf;
  157. if( align() & FL_ALIGN_INSIDE )
  158. {
  159. int len = strlen(label());
  160. buf = (char*)malloc( len + 128 );
  161. sprintf( buf, "%s", label() );
  162. format( buf + len );
  163. }
  164. else
  165. {
  166. buf = (char*)malloc( 128 );
  167. format( buf );
  168. }
  169. _input.value(buf);
  170. if( align() == FL_ALIGN_INSIDE || !_editable )
  171. _input.position( _input.size() );
  172. else
  173. _input.position( 0, _input.size() );
  174. free( buf );
  175. }
  176. void Flu_Spinner::draw()
  177. {
  178. int W = w()*15/100;
  179. if( W < h()/2 )
  180. W = h()/2;
  181. int X = x()+w()-W, Y = y();
  182. // fltk 2.0 behavior
  183. bool refresh;
  184. if( step() >= 1.0 )
  185. {
  186. refresh = ( _input.type() != FL_INT_INPUT );
  187. _input.type( FL_INT_INPUT );
  188. }
  189. else
  190. {
  191. refresh = ( _input.type() != FL_FLOAT_INPUT );
  192. _input.type( FL_FLOAT_INPUT );
  193. }
  194. if( refresh )
  195. value_damage();
  196. // draw the up/down arrow buttons
  197. fl_draw_box( (Fl_Boxtype)_valbox[0], X, Y, W, h()/2, color() );
  198. fl_draw_box( (Fl_Boxtype)_valbox[1], X, Y+h()/2, W, h()/2, color() );
  199. fl_color( active_r() ? FL_FOREGROUND_COLOR : fl_inactive(FL_FOREGROUND_COLOR) );
  200. fl_polygon( X+4, Y+h()/2-4, X+W/2, Y+4, X+W-4, Y+h()/2-4 );
  201. Y += h()/2;
  202. fl_polygon( X+4, Y+4, X+W/2, Y+h()/2-4, X+W-4, Y+4 );
  203. _input.resize( x(), y(), w()-h()/2-1, h() );
  204. _input.redraw();
  205. }
  206. void Flu_Spinner :: increment_cb()
  207. {
  208. int oldWhen = when();
  209. int amt = Fl::event_state( FL_SHIFT | FL_CTRL | FL_ALT ) ? 10 : 1;
  210. if( _up )
  211. _setvalue(increment(value(),1*amt));
  212. else
  213. _setvalue(increment(value(),-1*amt));
  214. when( oldWhen );
  215. _lastValue = value();
  216. }
  217. void Flu_Spinner :: repeat_callback( void* arg )
  218. {
  219. Flu_Spinner* c = (Flu_Spinner*)arg;
  220. c->increment_cb();
  221. float delay = c->_repeatTime[0];
  222. if( c->_pushed && c->_totalTime >= c->_rapidDelay )
  223. delay = c->_repeatTime[1];
  224. c->_totalTime += delay;
  225. Fl::repeat_timeout( delay, repeat_callback, c );
  226. }
  227. int Flu_Spinner::handle(int event)
  228. {
  229. int W = w()*15/100;
  230. if( W < h()/2 )
  231. W = h()/2;
  232. int X = x()+w()-W, Y = y();
  233. if( (align() & FL_ALIGN_INSIDE) || !_editable )
  234. {
  235. _input.readonly( true );
  236. _input.cursor_color( FL_WHITE );
  237. }
  238. else
  239. {
  240. _input.readonly( false );
  241. _input.cursor_color( FL_BLACK );
  242. }
  243. switch( event )
  244. {
  245. case FL_PUSH:
  246. _dragging = true;
  247. if (Fl::visible_focus() && handle(FL_FOCUS)) Fl::focus(this);
  248. _lastValue = value();
  249. _lastY = Fl::event_y();
  250. Fl::remove_timeout( repeat_callback, this );
  251. if( Fl::event_inside( X, Y, W, h()/2 ) ) // up button
  252. {
  253. _pushed = true;
  254. _valbox[0] = FL_DOWN_BOX;
  255. _up = true;
  256. }
  257. if( Fl::event_inside( X, Y+h()/2, W, h()/2 ) ) // down button
  258. {
  259. _pushed = true;
  260. _valbox[1] = FL_DOWN_BOX;
  261. _up = false;
  262. }
  263. if( _pushed )
  264. {
  265. increment_cb();
  266. _totalTime = _initialDelay;
  267. if( _doRepeat )
  268. Fl::add_timeout( _initialDelay, repeat_callback, this);
  269. handle_push();
  270. take_focus();
  271. redraw();
  272. return 1;
  273. }
  274. break;
  275. case FL_DRAG:
  276. {
  277. // only do the dragging if the last Y differs from the current Y by more than 3 pixels
  278. if( ABS(_lastY-Fl::event_y()) < 3 )
  279. break;
  280. _dragging = true;
  281. _pushed = false;
  282. Fl::remove_timeout( repeat_callback, this );
  283. int oldWhen = when();
  284. _setvalue(increment(_lastValue,(_lastY-Fl::event_y())*(Fl::event_state(FL_SHIFT|FL_CTRL|FL_ALT)?10:1)));
  285. _valbox[0] = _valbox[1] = FL_DOWN_BOX;
  286. when( oldWhen );
  287. fl_cursor((Fl_Cursor)22);
  288. _input.redraw();
  289. redraw();
  290. }
  291. break;
  292. case FL_RELEASE:
  293. {
  294. bool doCB = ( ( when() & FL_WHEN_RELEASE ) || ( when() & FL_WHEN_RELEASE_ALWAYS ) ) &&
  295. ( _pushed || ( _valbox[0] == FL_DOWN_BOX ^ _valbox[1] == FL_DOWN_BOX ) );
  296. _pushed = false;
  297. _dragging = false;
  298. Fl::remove_timeout( repeat_callback, this );
  299. _valbox[0] = _valbox[1] = FL_UP_BOX;
  300. fl_cursor(FL_CURSOR_DEFAULT);
  301. redraw();
  302. handle_release();
  303. if( doCB )
  304. do_callback();
  305. _input.take_focus();
  306. }
  307. break;
  308. case FL_FOCUS:
  309. case FL_UNFOCUS:
  310. redraw();
  311. _input.take_focus();
  312. return 0;
  313. case FL_ENTER:
  314. if( Fl::event_inside( &_input ) )
  315. return _input.handle(event);
  316. else if( active_r() )
  317. {
  318. fl_cursor(FL_CURSOR_DEFAULT);
  319. return 1;
  320. }
  321. break;
  322. case FL_LEAVE:
  323. if( Fl::event_inside( &_input ) )
  324. return _input.handle(event);
  325. else if( active_r() )
  326. {
  327. fl_cursor(FL_CURSOR_DEFAULT);
  328. return 1;
  329. }
  330. break;
  331. case FL_KEYBOARD:
  332. switch( Fl::event_key() )
  333. {
  334. case FL_Down:
  335. {
  336. int oldWhen = when(); when( FL_WHEN_CHANGED );
  337. _setvalue(increment(value(),-1*(Fl::event_state(FL_SHIFT|FL_CTRL|FL_ALT)?10:1)));
  338. when( oldWhen );
  339. redraw();
  340. return 1;
  341. }
  342. case FL_Up:
  343. {
  344. int oldWhen = when(); when( FL_WHEN_CHANGED );
  345. _setvalue(increment(value(),1*(Fl::event_state(FL_SHIFT|FL_CTRL|FL_ALT)?10:1)));
  346. when( oldWhen );
  347. redraw();
  348. return 1;
  349. }
  350. }
  351. break;
  352. }
  353. return _input.handle(event);
  354. }
  355. void Flu_Spinner :: _setvalue( double v )
  356. {
  357. if( _wrapRange )
  358. {
  359. while( v > maximum() )
  360. v = minimum() + (v - maximum());
  361. while( v < minimum() )
  362. v = maximum() - (minimum() - v);
  363. }
  364. else
  365. {
  366. v = clamp(v);
  367. }
  368. handle_drag(v);
  369. }