2
0

Flu_Wrap_Group.cpp 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  1. // $Id: Flu_Wrap_Group.cpp,v 1.8 2004/01/27 21:44:24 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 "FLU/Flu_Wrap_Group.H"
  13. #include <string.h>
  14. #include <stdio.h>
  15. #define MAX( x, y ) ( (x)>(y) ? (x) : (y) )
  16. #define SCROLL_SIZE 15
  17. Flu_Wrap_Group :: Scrollbar :: Scrollbar( int x, int y, int w, int h, const char *l )
  18. : Fl_Scrollbar( x, y, w, h, l )
  19. {
  20. }
  21. int Flu_Wrap_Group :: Scrollbar :: handle( int event )
  22. {
  23. if( event == FL_MOUSEWHEEL )
  24. {
  25. handle_drag( clamp( value() + linesize() * Fl::e_dy ) );
  26. return 1;
  27. }
  28. else
  29. return Fl_Scrollbar::handle( event );
  30. }
  31. Flu_Wrap_Group :: Flu_Wrap_Group( int x, int y, int w, int h, const char *l )
  32. : Fl_Group( x, y, w, h, l ), scrollbar( x+w-SCROLL_SIZE, y, SCROLL_SIZE, h ), group( x, y, w-SCROLL_SIZE, h )
  33. {
  34. offset( 0, 0 );
  35. spacing( 0, 0 );
  36. _type = FL_VERTICAL;
  37. scrollTo = NULL;
  38. Fl_Group::add( &scrollbar );
  39. scrollbar.callback( _scrollCB, this );
  40. scrollbar.linesize( 10 );
  41. scrollbar.range( 0, 100 );
  42. scrollbar.show();
  43. Fl_Group::add( &group );
  44. Fl_Group::resizable( group );
  45. Fl_Group::end();
  46. group.begin();
  47. }
  48. void Flu_Wrap_Group :: resize( int x, int y, int w, int h )
  49. {
  50. group.resizable( NULL );
  51. Fl_Group::resize( x, y, w, h );
  52. if( type() == FL_VERTICAL )
  53. {
  54. scrollbar.resize( x+w-SCROLL_SIZE-Fl::box_dx(box()), y+Fl::box_dy(box()), SCROLL_SIZE, h-Fl::box_dh(box()) );
  55. group.resize( x, y, w-SCROLL_SIZE-Fl::box_dx(box()), h );
  56. }
  57. else
  58. {
  59. scrollbar.resize( x+Fl::box_dx(box()), y+h-SCROLL_SIZE-Fl::box_dy(box()), w-Fl::box_dw(box()), SCROLL_SIZE );
  60. group.resize( x, y, w, h-SCROLL_SIZE-Fl::box_dh(box()) );
  61. }
  62. Fl_Group::init_sizes();
  63. redraw();
  64. }
  65. void Flu_Wrap_Group :: scroll_to( const Fl_Widget *w )
  66. {
  67. scrollTo = w;
  68. redraw();
  69. }
  70. void Flu_Wrap_Group :: scroll_to_beginning()
  71. {
  72. ((Fl_Valuator*)&scrollbar)->value( scrollbar.minimum() );
  73. }
  74. void Flu_Wrap_Group :: scroll_to_end()
  75. {
  76. ((Fl_Valuator*)&scrollbar)->value( scrollbar.maximum() );
  77. }
  78. void Flu_Wrap_Group :: type( int t )
  79. {
  80. _type = t;
  81. resize( x(), y(), w(), h() );
  82. }
  83. Fl_Widget* Flu_Wrap_Group :: next( Fl_Widget* w )
  84. {
  85. for( int i = 0; i < group.children()-1; i++ )
  86. {
  87. if( w == group.child(i) )
  88. return group.child(i+1);
  89. }
  90. return NULL;
  91. }
  92. Fl_Widget* Flu_Wrap_Group :: previous( Fl_Widget* w )
  93. {
  94. for( int i = 1; i < group.children(); i++ )
  95. {
  96. if( w == group.child(i) )
  97. return group.child(i-1);
  98. }
  99. return NULL;
  100. }
  101. Fl_Widget* Flu_Wrap_Group :: above( Fl_Widget* w )
  102. {
  103. for( int i = 0; i < group.children(); i++ )
  104. {
  105. if( w == group.child(i) )
  106. {
  107. int measure[2];
  108. measure[0] = w->x() + w->w()/2;
  109. measure[1] = w->y() - _spacing[1];
  110. int index = layout( scrollbar.visible(), false, measure );
  111. if( index >= 0 )
  112. return group.child(index);
  113. else
  114. return group.child(0);
  115. }
  116. }
  117. return NULL;
  118. }
  119. Fl_Widget* Flu_Wrap_Group :: below( Fl_Widget* w )
  120. {
  121. for( int i = 0; i < group.children(); i++ )
  122. {
  123. if( w == group.child(i) )
  124. {
  125. int measure[2];
  126. measure[0] = w->x() + w->w()/2;
  127. measure[1] = w->y() + w->h() + _spacing[1];
  128. int index = layout( scrollbar.visible(), false, measure );
  129. if( index >= 0 )
  130. return group.child(index);
  131. else
  132. return group.child(group.children()-1);
  133. }
  134. }
  135. return NULL;
  136. }
  137. Fl_Widget* Flu_Wrap_Group :: left( Fl_Widget* w )
  138. {
  139. for( int i = 0; i < group.children(); i++ )
  140. {
  141. if( w == group.child(i) )
  142. {
  143. int measure[2];
  144. measure[0] = w->x() - _spacing[0];
  145. measure[1] = w->y() + w->h()/2;
  146. int index = layout( scrollbar.visible(), false, measure );
  147. if( index >= 0 )
  148. return group.child(index);
  149. else
  150. return group.child(0);
  151. }
  152. }
  153. return NULL;
  154. }
  155. Fl_Widget* Flu_Wrap_Group :: right( Fl_Widget* w )
  156. {
  157. for( int i = 0; i < group.children(); i++ )
  158. {
  159. if( w == group.child(i) )
  160. {
  161. int measure[2];
  162. measure[0] = w->x() + w->w() + _spacing[0] + 1;
  163. measure[1] = w->y() + w->h()/2;
  164. int index = layout( scrollbar.visible(), false, measure );
  165. if( index >= 0 )
  166. return group.child(index);
  167. else
  168. return group.child(group.children()-1);
  169. }
  170. }
  171. return NULL;
  172. }
  173. int Flu_Wrap_Group :: layout( bool sbVisible, bool doScrollTo, int *measure )
  174. {
  175. int xx = x()+Fl::box_dx(box()), yy = y()+Fl::box_dy(box()),
  176. ww = w()-Fl::box_dw(box()), hh = h()-Fl::box_dh(box());
  177. if( type() == FL_VERTICAL )
  178. {
  179. int i, X, Y, maxH, H, col, row, maxW, scrollY;
  180. Fl_Widget *c;
  181. scrollbar.type( FL_VERTICAL );
  182. BEGIN_H:
  183. X = xx+_offset[0];
  184. Y = yy+_offset[1] - (sbVisible ? scrollbar.value() : 0);
  185. maxH = _offset[1];
  186. H = 0;
  187. col = 0;
  188. row = 0;
  189. scrollY = 0;
  190. maxW = xx + ww - (sbVisible ? scrollbar.w() : 0);
  191. for( i = 0; i < group.children(); i++ )
  192. {
  193. c = group.child(i);
  194. if( !c->visible() )
  195. continue;
  196. H = MAX( H, c->h() );
  197. if( col == 0 )
  198. maxH += H + _spacing[1];
  199. if( ( X + c->w() ) > maxW )
  200. {
  201. Y += H + _spacing[1];
  202. scrollY += H + _spacing[1];
  203. if( i == group.children()-1 )
  204. maxH += H + _spacing[1];
  205. if( measure )
  206. {
  207. if( xx+_offset[0] <= measure[0] && measure[0] <= xx+c->w()+_offset[0]+_spacing[0] &&
  208. Y <= measure[1] && measure[1] <= Y+c->h()+_spacing[1] )
  209. return i;
  210. }
  211. else
  212. c->position( xx+_offset[0], Y );
  213. col = 0;
  214. row++;
  215. H = 0;
  216. X = xx+c->w() + _offset[0] + _spacing[0];
  217. }
  218. else
  219. {
  220. if( measure )
  221. {
  222. if( X <= measure[0] && measure[0] <= X+c->w()+_spacing[0] &&
  223. Y <= measure[1] && measure[1] <= Y+c->h()+_spacing[1] )
  224. return i;
  225. }
  226. else
  227. c->position( X, Y );
  228. X += c->w() + _spacing[0];
  229. col++;
  230. }
  231. if( doScrollTo && (c == scrollTo) )
  232. {
  233. if( scrollY > scrollbar.maximum() )
  234. scrollY = (int)scrollbar.maximum();
  235. ((Fl_Valuator*)&scrollbar)->value( scrollY );
  236. scrollTo = NULL;
  237. goto BEGIN_H;
  238. }
  239. // if we exceed the height and the scrollbar is not visible,
  240. // then it will soon become visible so we don't need to process anymore
  241. if( !measure && !sbVisible && maxH > hh )
  242. return 1;
  243. }
  244. if( measure )
  245. return -1;
  246. else if( maxH > hh )
  247. {
  248. scrollbar.range( 0, maxH-hh );
  249. scrollbar.slider_size( MAX( float(scrollbar.h()-(maxH-hh))/float(scrollbar.h()), 0.08f ) );
  250. return 1;
  251. }
  252. else
  253. return 0;
  254. }
  255. else
  256. {
  257. int i, X, Y, W, maxW, maxH, col, row, scrollX;
  258. Fl_Widget *c;
  259. scrollbar.type( FL_HORIZONTAL );
  260. BEGIN_W:
  261. X = xx+_offset[0] - (sbVisible ? scrollbar.value() : 0);
  262. Y = yy+_offset[1];
  263. maxW = _offset[0];
  264. W = 0;
  265. col = 0;
  266. row = 0;
  267. scrollX = 0;
  268. maxH = yy + hh - (sbVisible ? scrollbar.h() : 0);
  269. for( i = 0; i < group.children(); i++ )
  270. {
  271. c = group.child(i);
  272. if( !c->visible() )
  273. continue;
  274. W = MAX( W, c->w() );
  275. if( row == 0 )
  276. maxW += W + _spacing[0];
  277. if( ( Y + c->h() ) > maxH )
  278. {
  279. X += W + _spacing[0];
  280. scrollX += W + _spacing[0];
  281. if( i == group.children()-1 )
  282. maxW += W + _spacing[0];
  283. if( measure )
  284. {
  285. if( X <= measure[0] && measure[0] <= X+c->w()+_spacing[0] &&
  286. yy+_offset[1] <= measure[1] && measure[1] <= yy+c->h()+_offset[1]+_spacing[1] )
  287. return i;
  288. }
  289. else
  290. c->position( X, yy+_offset[1] );
  291. row = 0;
  292. col++;
  293. W = 0;
  294. Y = yy+c->h() + _offset[1] + _spacing[1];
  295. }
  296. else
  297. {
  298. if( measure )
  299. {
  300. if( X <= measure[0] && measure[0] <= X+c->w()+_spacing[0] &&
  301. Y <= measure[1] && measure[1] <= Y+c->h()+_spacing[1] )
  302. return i;
  303. }
  304. else
  305. c->position( X, Y );
  306. Y += c->h() + _spacing[1];
  307. row++;
  308. }
  309. if( doScrollTo && (c == scrollTo) )
  310. {
  311. if( scrollX > scrollbar.maximum() )
  312. scrollX = (int)scrollbar.maximum();
  313. ((Fl_Valuator*)&scrollbar)->value( scrollX );
  314. scrollTo = NULL;
  315. goto BEGIN_W;
  316. }
  317. // if we exceed the width and the scrollbar is not visible,
  318. // then it will soon become visible so we don't need to process anymore
  319. if( !measure && !sbVisible && maxW > ww )
  320. return 1;
  321. }
  322. if( measure )
  323. return -1;
  324. else if( maxW > ww )
  325. {
  326. scrollbar.range( 0, maxW-ww );
  327. scrollbar.slider_size( MAX( float(scrollbar.w()-(maxW-ww))/float(scrollbar.w()), 0.08f ) );
  328. return 1;
  329. }
  330. else
  331. return 0;
  332. }
  333. }
  334. void Flu_Wrap_Group :: draw()
  335. {
  336. // we first try to fit all children assuming no scrollbar. if they do not all fit,
  337. // we have to turn the scrollbar on and try again
  338. if( layout( false, false ) )
  339. {
  340. scrollbar.show();
  341. layout( true, false );
  342. }
  343. else
  344. scrollbar.hide();
  345. // hack to look right when resizing smaller
  346. if( scrollbar.value() > scrollbar.maximum() )
  347. {
  348. ((Fl_Valuator*)&scrollbar)->value( scrollbar.maximum() );
  349. layout( scrollbar.visible(), scrollTo!=NULL );
  350. }
  351. else if( scrollTo )
  352. layout( scrollbar.visible(), true );
  353. scrollTo = NULL;
  354. if( damage() & ~FL_DAMAGE_CHILD)
  355. {
  356. draw_box();
  357. draw_label();
  358. }
  359. fl_push_clip( x()+Fl::box_dx(box()), y()+Fl::box_dy(box()),
  360. w()-Fl::box_dw(box()), h()-Fl::box_dh(box()) );
  361. draw_children();
  362. fl_pop_clip();
  363. }