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