Flu_Combo_Box.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. // $Id: Flu_Combo_Box.cpp,v 1.20 2004/10/15 14:46:12 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 <FL/Fl.H>
  14. #include <FL/fl_draw.H>
  15. #include <string.h>
  16. #include <stdlib.h>
  17. #include <FL/math.h>
  18. #include "FLU/Flu_Combo_Box.H"
  19. Flu_Combo_Box::Flu_Combo_Box( int X, int Y, int W, int H, const char* l )
  20. : Fl_Group( X, Y, W, H, l ), input( X, Y, W, H )
  21. {
  22. box( FL_DOWN_BOX );
  23. align( FL_ALIGN_LEFT );
  24. pop_height( 100 );
  25. _cbox = NULL;
  26. _valbox = FL_UP_BOX;
  27. input_callback( NULL );
  28. input.box( FL_FLAT_BOX );
  29. input.callback( input_cb, this );
  30. input.when( FL_WHEN_ENTER_KEY_ALWAYS );
  31. input.color( FL_WHITE, selection_color());
  32. input.textfont( FL_HELVETICA );
  33. input.textsize( FL_NORMAL_SIZE );
  34. input.textcolor( FL_FOREGROUND_COLOR );
  35. input.resize( X+Fl::box_dx(box()), Y+Fl::box_dy(box()),
  36. W-18-Fl::box_dw(box()), H-Fl::box_dh(box()) );
  37. editable( true );
  38. end();
  39. }
  40. void Flu_Combo_Box::set_combo_widget( Fl_Widget *w )
  41. {
  42. _cbox = w;
  43. this->add( w );
  44. }
  45. void Flu_Combo_Box::input_cb( Fl_Widget*, void* v )
  46. {
  47. // taken from Fl_Counter.cxx
  48. Flu_Combo_Box& t = *(Flu_Combo_Box*)v;
  49. if( strcmp( t.input.value(), t.value() )!=0 || t.input.when() & FL_WHEN_NOT_CHANGED)
  50. {
  51. if( t.when() )
  52. {
  53. t.clear_changed();
  54. if( t._inputCB )
  55. t._inputCB( &t, t._inputCBD );
  56. else
  57. t.do_callback();
  58. }
  59. else
  60. {
  61. t.set_changed();
  62. }
  63. }
  64. }
  65. void Flu_Combo_Box::resize( int X, int Y, int W, int H )
  66. {
  67. Fl_Group::resize( X, Y, W, H );
  68. input.resize( X+Fl::box_dx(box()), Y+Fl::box_dy(box()),
  69. W-18-Fl::box_dw(box()), H-Fl::box_dh(box()) );
  70. }
  71. void Flu_Combo_Box::draw()
  72. {
  73. int W = 18, H = h()-4;
  74. int X = x()+w()-W-2, Y = y()+2;
  75. fl_draw_box( box(), x(), y(), w(), h(), color() );
  76. // draw the arrow button
  77. fl_draw_box( (Fl_Boxtype)_valbox, X, Y, W, H, color() );
  78. fl_color( active_r() ? FL_FOREGROUND_COLOR : fl_inactive(FL_FOREGROUND_COLOR) );
  79. fl_polygon( X+W/2-5, Y+H/2-2, X+W/2+3, Y+H/2-2, X+W/2-1, Y+H/2+2 );
  80. draw_child( input );
  81. if( Fl::focus() == this )
  82. draw_focus( FL_NO_BOX, input.x(), input.y(), input.w(), input.h() );
  83. }
  84. static int global_x( Fl_Widget *w )
  85. {
  86. int x = Fl::x()+w->x();
  87. Fl_Widget *o = w->parent();
  88. while( o )
  89. {
  90. if( o->type() >= FL_WINDOW ) x += o->x();
  91. o = o->parent();
  92. }
  93. return x;
  94. }
  95. static int global_y( Fl_Widget *w )
  96. {
  97. int y = Fl::y()+w->y();
  98. Fl_Widget *o = w->parent();
  99. while( o )
  100. {
  101. if( o->type() >= FL_WINDOW ) y += o->y();
  102. o = o->parent();
  103. }
  104. return y;
  105. }
  106. Flu_Combo_Box::Popup::Popup( Flu_Combo_Box *b, Fl_Widget *c, int H )
  107. : Fl_Double_Window( global_x(b)-2, //Fl::x()+b->window()->x()+b->x()-2,
  108. global_y(b)+b->h()-2, //Fl::y()+b->window()->y()+b->y()+b->h()-2,
  109. b->w()+4, H, 0 )
  110. {
  111. combo = b;
  112. dragging = false;
  113. selected = NULL;
  114. box( FL_BORDER_FRAME );
  115. border( 0 );
  116. add( c );
  117. end();
  118. //set_non_modal();
  119. set_modal();
  120. c->resize( 1, 1, w()-2, h()-2 );
  121. }
  122. Flu_Combo_Box::Popup::~Popup()
  123. {
  124. while( children() )
  125. remove( child(0) );
  126. }
  127. void Flu_Combo_Box::value( const char *v )
  128. {
  129. if( _value( v ) )
  130. input.value( v );
  131. }
  132. void Flu_Combo_Box::selected( const char *v )
  133. {
  134. bool value_changed = v && strcmp(v, input.value());
  135. if( value_changed )
  136. {
  137. input.value( v );
  138. input.set_changed2();
  139. }
  140. _popped = false;
  141. if(value_changed) do_callback();
  142. }
  143. int Flu_Combo_Box::Popup::handle( int event )
  144. {
  145. if( event == FL_MOVE )
  146. {
  147. // FL_MOVE is also generated while the window is moving
  148. // this attempts to keep the popup window moving with the enclosing window
  149. //position( combo->window()->x()+combo->x()-2, combo->window()->y()+combo->y()+combo->h()-2 );
  150. position( global_x(combo)-2, global_y(combo)+combo->h()-2 );
  151. // this lets the mouse move event also move the selected item
  152. combo->_hilight( Fl::event_x(), Fl::event_y() );
  153. }
  154. if( event == FL_DRAG )
  155. dragging = true;
  156. // if push outside the popup window, popdown
  157. if( event == FL_PUSH &&
  158. !Fl::event_inside( child(0) ) )
  159. {
  160. combo->_popped = false;
  161. return 0;
  162. }
  163. // if release after dragging outside the popup window, popdown
  164. if( event == FL_RELEASE && dragging &&
  165. !Fl::event_inside( child(0) ) )
  166. {
  167. combo->_popped = false;
  168. return 0;
  169. }
  170. if( event == FL_KEYDOWN )
  171. {
  172. if( Fl::event_key( FL_Escape ) )
  173. {
  174. combo->_popped = false;
  175. return 0;
  176. }
  177. else if( Fl::event_key( FL_Up ) )
  178. {
  179. const char *s = combo->_previous();
  180. if( s )
  181. selected = s;
  182. return 1;
  183. }
  184. else if( Fl::event_key( FL_Down ) )
  185. {
  186. const char *s = combo->_next();
  187. if( s )
  188. selected = s;
  189. return 1;
  190. }
  191. else if( Fl::event_key( FL_Enter ) || Fl::event_key( ' ' ) )
  192. {
  193. if( selected )
  194. {
  195. combo->value( selected );
  196. combo->selected( selected );
  197. }
  198. combo->_popped = false;
  199. return 1;
  200. }
  201. }
  202. return Fl_Double_Window::handle( event );
  203. }
  204. int Flu_Combo_Box::handle( int event )
  205. {
  206. if( event == FL_KEYDOWN && Fl::event_key( FL_Tab ) )
  207. return Fl_Group::handle( event );
  208. // is it time to popup?
  209. bool open = ( event == FL_PUSH ) &&
  210. (!Fl::event_inside( &input ) || ( !editable() && Fl::event_inside( &input ) ) );
  211. open |= ( event == FL_KEYDOWN ) && Fl::event_key( ' ' );
  212. if( open )
  213. {
  214. fl_cursor( FL_CURSOR_DEFAULT );
  215. _valbox = FL_THIN_DOWN_BOX;
  216. redraw();
  217. // remember old current group
  218. Fl_Group *c = Fl_Group::current();
  219. // set current group to 0 so this is a top level popup window
  220. Fl_Group::current( 0 );
  221. Popup *_popup = new Popup( this, _cbox, popHeight );
  222. // show it and make FLTK send all events there
  223. value( value() );
  224. _popup->show();
  225. Fl::grab( *_popup );
  226. Fl::focus( _cbox );
  227. _popped = true;
  228. Fl::pushed( _cbox );
  229. // wait for a selection to be made
  230. while( _popped )
  231. Fl::wait();
  232. // restore things and delete the popup
  233. _popup->hide();
  234. Fl::grab( 0 );
  235. delete _popup;
  236. Fl_Group::current( c );
  237. Fl::focus( this );
  238. _valbox = FL_UP_BOX;
  239. redraw();
  240. return 1;
  241. }
  242. if( input.handle(event) )
  243. {
  244. if( !editable() && ( event == FL_ENTER || event == FL_LEAVE ) )
  245. fl_cursor( FL_CURSOR_DEFAULT );
  246. return 1;
  247. }
  248. else
  249. return 0;
  250. }