~ubuntu-branches/debian/squeeze/gmsh/squeeze

« back to all changes in this revision

Viewing changes to contrib/TreeBrowser/Flu_Tree_Browser.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Christophe Prud'homme, Christophe Prud'homme
  • Date: 2009-09-02 18:12:15 UTC
  • mfrom: (1.2.8 upstream)
  • Revision ID: james.westby@ubuntu.com-20090902181215-yla8zvcas2ucvkm9
[Christophe Prud'homme]
* New upstream release
  + fixed surface mesh orientation bug introduced in 2.4.0;
  + mesh and graphics code refactoring;
  + small usability enhancements and bug fixes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// This is a (fairly heavily) modified version of Jason Bryan's
2
 
// Flu_Tree_Browser, for inclusion in Gmsh.
3
 
//
4
 
// The following changes have been made:
5
 
//
6
 
// * Removed drag-and-drop code
7
 
// * Added pixmaps in the .cpp file
8
 
// * Removed IntStack (replaced by std::vector)
9
 
// * Removed FluSimpleString (replaced by std::string)
10
 
// * Removed animation code
11
 
// * Removed the "find" pass when adding a new node (cf. "CG") 
12
 
//   to improve speed (WARNING: this fundamentally changes the 
13
 
//   way the tree works: calling add("/a/b") followed by add("/a/c")
14
 
//   will create two "a" branches. This is the desired behaviour
15
 
//   for Gmsh; probably not for you)
16
 
// 
17
 
 
18
 
/***************************************************************
19
 
 *                FLU - FLTK Utility Widgets 
20
 
 *  Copyright (C) 2002 Ohio Supercomputer Center, Ohio State University
21
 
 *
22
 
 * This file and its content is protected by a software license.
23
 
 * You should have received a copy of this license with this file.
24
 
 * If not, please contact the Ohio Supercomputer Center immediately:
25
 
 * Attn: Jason Bryan Re: FLU 1224 Kinnear Rd, Columbus, Ohio 43212
26
 
 * 
27
 
 ***************************************************************/
28
 
 
29
 
#include <math.h>
30
 
#include <FL/fl_draw.H>
31
 
#include "Flu_Tree_Browser.h"
32
 
 
33
 
static char * plus_xpm[] = {
34
 
"15 15 4 1",
35
 
"       c None",
36
 
".      c #444444",
37
 
"+      c #FFFFFF",
38
 
"@      c #000000",
39
 
"               ",
40
 
"               ",
41
 
"  ...........  ",
42
 
"  .+++++++++.  ",
43
 
"  .++++@++++.  ",
44
 
"  .++++@++++.  ",
45
 
"  .++++@++++.  ",
46
 
"  .+@@@@@@@+.  ",
47
 
"  .++++@++++.  ",
48
 
"  .++++@++++.  ",
49
 
"  .++++@++++.  ",
50
 
"  .+++++++++.  ",
51
 
"  ...........  ",
52
 
"               ",
53
 
"               "};
54
 
 
55
 
static char * minus_xpm[] = {
56
 
"15 15 4 1",
57
 
"       c None",
58
 
".      c #444444",
59
 
"+      c #FFFFFF",
60
 
"@      c #000000",
61
 
"               ",
62
 
"               ",
63
 
"  ...........  ",
64
 
"  .+++++++++.  ",
65
 
"  .+++++++++.  ",
66
 
"  .+++++++++.  ",
67
 
"  .+++++++++.  ",
68
 
"  .+@@@@@@@+.  ",
69
 
"  .+++++++++.  ",
70
 
"  .+++++++++.  ",
71
 
"  .+++++++++.  ",
72
 
"  .+++++++++.  ",
73
 
"  ...........  ",
74
 
"               ",
75
 
"               "};
76
 
 
77
 
static char * folder_closed_xpm[] = {
78
 
"20 16 44 1",
79
 
"       c None",
80
 
".      c #A68A5E",
81
 
"+      c #54452F",
82
 
"@      c #FEE89E",
83
 
"#      c #FEE59B",
84
 
"$      c #FEE298",
85
 
"%      c #FEDE95",
86
 
"&      c #FEDB93",
87
 
"*      c #CEAB75",
88
 
"=      c #FEF6A9",
89
 
"-      c #FEF2A7",
90
 
";      c #FEEFA4",
91
 
">      c #FEECA1",
92
 
",      c #FEE99E",
93
 
"'      c #FEE69C",
94
 
")      c #FEE399",
95
 
"!      c #FEDF96",
96
 
"~      c #FEDC93",
97
 
"{      c #FED991",
98
 
"]      c #FED68E",
99
 
"^      c #FEF3A7",
100
 
"/      c #FEF0A4",
101
 
"(      c #FEEDA2",
102
 
"_      c #FEE99F",
103
 
":      c #FEE097",
104
 
"<      c #FEDD94",
105
 
"[      c #FEDA91",
106
 
"}      c #FED78E",
107
 
"|      c #FEF0A5",
108
 
"1      c #FEEA9F",
109
 
"2      c #FEE79D",
110
 
"3      c #FEE49A",
111
 
"4      c #FEE197",
112
 
"5      c #FEDA92",
113
 
"6      c #FED78F",
114
 
"7      c #FEEEA3",
115
 
"8      c #FEEAA0",
116
 
"9      c #FEE198",
117
 
"0      c #FEDB92",
118
 
"a      c #FED88F",
119
 
"b      c #FEEBA0",
120
 
"c      c #FED890",
121
 
"d      c #FEE299",
122
 
"e      c #FED990",
123
 
"                    ",
124
 
"          .....+    ",
125
 
"         .@#$%&.+   ",
126
 
"   ......*******.   ",
127
 
"   .=-;>,')!~{]].+  ",
128
 
"   .^/(_'):<[}]].+  ",
129
 
"   .|(1234<56]]].+  ",
130
 
"   .78239%0a]]]].+  ",
131
 
"   .b@#$%&c]]]]].+  ",
132
 
"   .@#d!~e]]]]]].+  ",
133
 
"   .')!~{]]]]]]].+  ",
134
 
"   .):<[}]]]]]]].+  ",
135
 
"   ..............+  ",
136
 
"    ++++++++++++++  ",
137
 
"                    ",
138
 
"                    "};
139
 
 
140
 
static char * folder_open_xpm[] = {
141
 
"20 16 34 1",
142
 
"       c None",
143
 
".      c #A68A5E",
144
 
"+      c #FEF3A7",
145
 
"@      c #FEECA1",
146
 
"#      c #FEE49A",
147
 
"$      c #FEDD94",
148
 
"%      c #FED68E",
149
 
"&      c #FEF6A9",
150
 
"*      c #FEEEA3",
151
 
"=      c #FEE79D",
152
 
"-      c #FEDF96",
153
 
";      c #FED890",
154
 
">      c #FEF1A5",
155
 
",      c #FEE99F",
156
 
"'      c #FEE298",
157
 
")      c #FEDA92",
158
 
"!      c #FEF0A5",
159
 
"~      c #FEEBA1",
160
 
"{      c #FEE69C",
161
 
"]      c #FEE198",
162
 
"^      c #FEDC93",
163
 
"/      c #FED78F",
164
 
"(      c #54452F",
165
 
"_      c #FEF2A6",
166
 
":      c #FEEDA2",
167
 
"<      c #FEE299",
168
 
"[      c #FEE99E",
169
 
"}      c #FEDE95",
170
 
"|      c #FED991",
171
 
"1      c #FEEFA4",
172
 
"2      c #FEEA9F",
173
 
"3      c #FEE59B",
174
 
"4      c #FEE096",
175
 
"5      c #FEDB92",
176
 
"                    ",
177
 
"          .....     ",
178
 
"         .+@#$%.    ",
179
 
"   ......&*=-;%%.   ",
180
 
"   .&&&&&>,')%%%.   ",
181
 
"   .&&&&+@#$%%%%.   ",
182
 
"   .&&............  ",
183
 
"   .&&.&!~{]^/%%%.( ",
184
 
"   .&&._:=<$;%%%%.( ",
185
 
"   .&.+*[#}|%%%%.(  ",
186
 
"   .&.12345%%%%%.(  ",
187
 
"    .!~{]^/%%%%.(   ",
188
 
"    ............(   ",
189
 
"    ((((((((((((    ",
190
 
"                    ",
191
 
"                    "};
192
 
 
193
 
#define MAX( x, y ) ( (x)>(y) ? (x) : (y) )
194
 
#define MIN( x, y ) ( (x)<(y) ? (x) : (y) )
195
 
 
196
 
bool Flu_Tree_Browser::USE_FLU_WIDGET_CALLBACK = false;
197
 
 
198
 
Flu_Tree_Browser :: NodeList :: NodeList()
199
 
{
200
 
  _nodes = NULL;
201
 
  _nNodes = _size = 0;
202
 
}
203
 
 
204
 
Flu_Tree_Browser :: NodeList :: ~NodeList()
205
 
{
206
 
  clear();
207
 
}
208
 
 
209
 
typedef Flu_Tree_Browser::Node* NodeP;
210
 
 
211
 
bool Flu_Tree_Browser :: NodeList :: search( const char *n, int &index )
212
 
{
213
 
  index = _nNodes;
214
 
  if( _nNodes == 0 )
215
 
    return false;
216
 
 
217
 
  // we know we have at least one node. so use it to get the RData struct to find out what
218
 
  // the insertion mode is
219
 
  int iMode = _nodes[0]->tree->insertion_mode();
220
 
 
221
 
  if( iMode == FLU_INSERT_SORTED || iMode == FLU_INSERT_SORTED_REVERSE )
222
 
    return( binSearch( n, index ) );
223
 
  else
224
 
    return( linSearch( n, index ) );
225
 
}
226
 
 
227
 
bool Flu_Tree_Browser :: NodeList :: search( Node *n, int &index )
228
 
{
229
 
  index = _nNodes;
230
 
  if( _nNodes == 0 )
231
 
    return false;
232
 
 
233
 
  // we know we have at least one node. so use it to get the RData struct to find out what
234
 
  // the insertion mode is
235
 
  int iMode = _nodes[0]->tree->insertion_mode();
236
 
 
237
 
  if( iMode == FLU_INSERT_SORTED || iMode == FLU_INSERT_SORTED_REVERSE )
238
 
    return( binSearch( n, index ) );
239
 
  else
240
 
    return( linSearch( n, index ) );
241
 
}
242
 
 
243
 
bool Flu_Tree_Browser :: NodeList :: linSearch( const char *n, int &index )
244
 
{
245
 
  index = _nNodes;
246
 
  for( int i = 0; i < _nNodes; i++ )
247
 
    {
248
 
      if( strcmp( n, _nodes[i]->label() ) == 0 )
249
 
        {
250
 
          index = i;
251
 
          return true;
252
 
        }
253
 
    }
254
 
  return false;
255
 
}
256
 
 
257
 
bool Flu_Tree_Browser :: NodeList :: linSearch( Node *n, int &index )
258
 
{
259
 
  index = _nNodes;
260
 
  for( int i = 0; i < _nNodes; i++ )
261
 
    {
262
 
      if( n == _nodes[i] )
263
 
        {
264
 
          index = i;
265
 
          return true;
266
 
        }
267
 
    }
268
 
  return false;
269
 
}
270
 
 
271
 
bool Flu_Tree_Browser :: NodeList :: binSearch( Node *n, int &index )
272
 
{
273
 
  if( binSearch( n->label(), index ) )
274
 
    {
275
 
      // the search found the first node with the label. since there are identical entries
276
 
      // allowed, it may not be the actual node we want. therefore search forward until we find it
277
 
      for( ; index < _nNodes; index++ )
278
 
        if( _nodes[index] == n )
279
 
          return true;
280
 
      return false;
281
 
    }
282
 
  else
283
 
    return false;
284
 
}
285
 
 
286
 
bool Flu_Tree_Browser :: NodeList :: binSearch( const char *n, int &index )
287
 
{
288
 
  // do a binary search for a child with name == "n"
289
 
  // return true if the child is found, and store its index in "index"
290
 
  // return false if the child is not found, and store the index it would
291
 
  // be in in "index"
292
 
 
293
 
  // special case: no nodes
294
 
  if( _nNodes == 0 )
295
 
    {
296
 
      index = 0;
297
 
      return false;
298
 
    }
299
 
 
300
 
  // we know we have at least one node. so use it to get the RData struct to find out what
301
 
  // the insertion mode is
302
 
  int iMode = _nodes[0]->tree->insertion_mode();
303
 
 
304
 
  // special case: 1 node
305
 
  if( _nNodes == 1 )
306
 
    {
307
 
      int val = strcmp( n, _nodes[0]->label() );
308
 
      if( iMode == FLU_INSERT_SORTED_REVERSE )
309
 
        val *= -1;
310
 
      if( val == 0 )
311
 
        {
312
 
          index = 0;
313
 
          return true;
314
 
        }
315
 
      else if( val < 0 )
316
 
        index = 0;
317
 
      else
318
 
        index = 1;
319
 
      return false;
320
 
    }
321
 
 
322
 
  int first = 0, last = _nNodes - 1;
323
 
  int val1, val2, mVal;
324
 
  for(;;)
325
 
    {
326
 
      // the range is down to 2 nodes
327
 
      if( last == first + 1 )
328
 
        {
329
 
          val1 = strcmp( n, _nodes[first]->label() );
330
 
          if( iMode == FLU_INSERT_SORTED_REVERSE )
331
 
            val1 = -val1;
332
 
          if( val1 < 0 )
333
 
            {
334
 
              index = first;
335
 
              return false;
336
 
            }
337
 
          else if( val1 == 0 )
338
 
            {
339
 
              index = first;
340
 
              break;
341
 
            }
342
 
          val2 = strcmp( n, _nodes[last]->label() );
343
 
          if( iMode == FLU_INSERT_SORTED_REVERSE )
344
 
            val2 = -val2;
345
 
          if( val2 < 0 )
346
 
            {
347
 
              index = last;
348
 
              return false;
349
 
            }
350
 
          else if( val2 == 0 )
351
 
            {
352
 
              index = last;
353
 
              break;
354
 
            }
355
 
          else
356
 
            {
357
 
              index = last+1;
358
 
              return false;
359
 
            }
360
 
        }
361
 
 
362
 
      // pick which half of the array to search next
363
 
      int midpoint = first + ((last-first)>>1);
364
 
      mVal = strcmp( n, _nodes[midpoint]->label() );
365
 
      if( iMode == FLU_INSERT_SORTED_REVERSE )
366
 
        mVal = -mVal;
367
 
      if( mVal < 0 )
368
 
        last = midpoint;
369
 
      else if( mVal > 0 )
370
 
        first = midpoint;
371
 
      else
372
 
        {
373
 
          index = midpoint;
374
 
          break;
375
 
        }
376
 
    }
377
 
 
378
 
  // we found *a* node equal to "n", now find the first node equal to "n"
379
 
  // by searching until we hit a node not equal to "n"
380
 
  for( first = index; first > 0; first-- )
381
 
    if( strcmp( n, _nodes[first-1]->label() ) != 0 )
382
 
      break;
383
 
  index = first;
384
 
 
385
 
  return true;
386
 
}
387
 
 
388
 
int Flu_Tree_Browser :: NodeList :: compareNodes( const void *arg1, const void* arg2 )
389
 
{
390
 
  Flu_Tree_Browser::Node *n1 = *((Flu_Tree_Browser::Node**)arg1), *n2 = *((Flu_Tree_Browser::Node**)arg2);
391
 
  return strcmp( n1->text.c_str(), n2->text.c_str() );
392
 
}
393
 
 
394
 
int Flu_Tree_Browser :: NodeList :: reverseCompareNodes( const void *arg1, const void* arg2 )
395
 
{
396
 
  Flu_Tree_Browser::Node *n1 = *((Flu_Tree_Browser::Node**)arg1), *n2 = *((Flu_Tree_Browser::Node**)arg2);
397
 
  return( -strcmp( n1->text.c_str(), n2->text.c_str() ) );
398
 
}
399
 
 
400
 
void Flu_Tree_Browser :: NodeList :: sort()
401
 
{
402
 
  if( _nNodes )
403
 
    {
404
 
      // we know we have at least one node. so use it to get the RData struct to find out what
405
 
      // the insertion mode is
406
 
      int iMode = _nodes[0]->tree->insertion_mode();
407
 
      if( iMode == FLU_INSERT_SORTED )
408
 
        qsort( _nodes, _nNodes, sizeof(Node*), compareNodes );
409
 
      else if( iMode == FLU_INSERT_SORTED_REVERSE )
410
 
        qsort( _nodes, _nNodes, sizeof(Node*), reverseCompareNodes );
411
 
    }
412
 
}
413
 
 
414
 
Flu_Tree_Browser::Node* Flu_Tree_Browser :: Node :: insert( const char* fullpath, int pos )
415
 
{
416
 
  // insert the new node at the back of the tree
417
 
  int imode = tree->insertion_mode();
418
 
  tree->insertion_mode( FLU_INSERT_BACK );
419
 
  Node *n = add( fullpath );
420
 
  tree->insertion_mode( imode );
421
 
  if( !n ) return NULL;
422
 
  // find the node at position "pos" and
423
 
  // move the new node before it, so it takes over position "pos"
424
 
  if( pos < 0 ) pos = 0;
425
 
  if( pos >= children() ) pos = children()-1;
426
 
  move( n, MOVE_BEFORE, child(pos) );
427
 
  return n;
428
 
}
429
 
 
430
 
Flu_Tree_Browser::Node* Flu_Tree_Browser :: Node :: insert_branch( const char* fullpath, int pos )
431
 
{
432
 
  std::string p( fullpath );
433
 
  if( p.size() && p[p.size()-1] != '/' && p[p.size()-1] != '\\' ) p += "/";
434
 
  return insert( p.c_str(), pos );
435
 
}
436
 
 
437
 
Flu_Tree_Browser::Node* Flu_Tree_Browser :: Node :: insert_leaf( const char* fullpath, int pos )
438
 
{
439
 
  std::string p( fullpath );
440
 
  if( p.size() && ( p[p.size()-1] == '/' || p[p.size()-1] == '\\' ) ) p[p.size()-1] = '\0';
441
 
  return insert( p.c_str(), pos );
442
 
}
443
 
 
444
 
bool Flu_Tree_Browser :: Node :: move( int pos )
445
 
{
446
 
  // get this node's position
447
 
  int i = index();
448
 
  if( i == -1 ) return false;
449
 
  // get the node in our parent at index "pos"
450
 
  if( !parent() ) return false;
451
 
  if( pos < 0 ) pos = 0;
452
 
  if( pos >= parent()->children() ) pos = parent()->children()-1;
453
 
  Node *n = parent()->child( pos );
454
 
  // move this node to be before its sibling, so it takes over position "pos"
455
 
  return move( this, MOVE_BEFORE, n );
456
 
}
457
 
 
458
 
bool Flu_Tree_Browser :: Node :: swap( Node* n1, Node* n2 )
459
 
{
460
 
  if( n1->tree != n2->tree ) return false;
461
 
  Node *p1 = n1->parent(), *p2 = n2->parent();
462
 
  if( !p1 || !p2 ) return false;
463
 
  int i, index1 = -1, index2 = -1;
464
 
  for( i = 0; i < p1->children(); i++ )
465
 
    {
466
 
      if( p1->child(i) == n1 )
467
 
        {
468
 
          index1 = i;
469
 
          break;
470
 
        }
471
 
    }
472
 
  if( index1 == -1 ) return false;
473
 
  for( i = 0; i < p2->children(); i++ )
474
 
    {
475
 
      if( p2->child(i) == n2 )
476
 
        {
477
 
          index2 = i;
478
 
          break;
479
 
        }
480
 
    }
481
 
  if( index2 == -1 ) return false;
482
 
  p1->_children._nodes[index1] = n2;
483
 
  p2->_children._nodes[index2] = n1;
484
 
  return true;
485
 
}
486
 
 
487
 
bool Flu_Tree_Browser :: Node :: move( Node* n1, int where, Node* n2 )
488
 
{
489
 
  if( isMoveValid( n1, where, n2 ) )
490
 
    return( NodeList::move( n1, where, n2 ) );
491
 
  else
492
 
    return false;
493
 
}
494
 
 
495
 
void Flu_Tree_Browser :: Node :: sort()
496
 
{
497
 
  _children.sort();
498
 
  for( int i = 0; i < _children.size(); i++ )
499
 
    _children.child(i)->sort();
500
 
}
501
 
 
502
 
bool Flu_Tree_Browser :: Node :: is_ancestor( Node* n )
503
 
{
504
 
  Node *p = parent();
505
 
  while( p )
506
 
    {
507
 
      if( p == n )
508
 
        return true;
509
 
      else
510
 
        p = p->parent();
511
 
    }
512
 
  return false;
513
 
}
514
 
 
515
 
bool Flu_Tree_Browser :: Node :: is_descendent( Node* n )
516
 
{
517
 
  return n->is_ancestor( this );
518
 
}
519
 
 
520
 
bool Flu_Tree_Browser :: NodeList :: move( Node* n1, int where, Node* n2 )
521
 
{
522
 
  if( !n1 || !n2 )
523
 
    return false;
524
 
 
525
 
  if( n1->tree )
526
 
    n1->tree->redraw();
527
 
  if( n2->tree )
528
 
    n2->tree->redraw();
529
 
 
530
 
  // try to move n1 to the first child position of n2
531
 
  if( where == MOVE_INSIDE )
532
 
    {
533
 
      if( !n2->is_branch() )
534
 
        return false;
535
 
      // get the parent of n1
536
 
      Node* p1 = n1->parent();
537
 
      if( p1 )
538
 
        // remove n1 from its parent's list
539
 
        p1->_children.erase( n1 );
540
 
      // insert into n2
541
 
      int iMode = n1->tree->insertion_mode();
542
 
      if( iMode == FLU_INSERT_SORTED || iMode == FLU_INSERT_SORTED_REVERSE )
543
 
        n2->_children.add( n1 );
544
 
      else
545
 
        n2->_children.add( n1, 0 );
546
 
      // update the parent of n1
547
 
      n1->_parent = n2;
548
 
      return true;
549
 
    }
550
 
 
551
 
  // find the position of n2 in its parent's list
552
 
  Node* p2 = n2->parent();
553
 
  if( !p2 )
554
 
    return false;
555
 
  int index = 0, removed = -1;
556
 
  if( p2->_children.search( n2, index ) )
557
 
    {
558
 
      // get the parent of n1
559
 
      Node* p1 = n1->parent();
560
 
      if( p1 )
561
 
        // remove n1 from its parent's list. remember the position it was removed from
562
 
        removed = p1->_children.erase( n1 );
563
 
 
564
 
      // if n1 and n2 have the same parent, and if n1 came before the spot where
565
 
      // n2 will be inserted, then our indexing is off by one because n1 has been removed
566
 
      if( p1 == p2 && removed <= index )
567
 
        index--;
568
 
 
569
 
      if( where == MOVE_AFTER )
570
 
       index++;
571
 
 
572
 
      // insert n1 at the proper position
573
 
      p2->_children.add( n1, index );
574
 
 
575
 
      // update the parent of n1
576
 
      n1->_parent = p2;
577
 
    }
578
 
 
579
 
  return true;
580
 
}
581
 
 
582
 
void Flu_Tree_Browser :: NodeList :: add( Node* n, int position )
583
 
{
584
 
  int i, index;
585
 
  int mode = n->tree->insertion_mode();
586
 
 
587
 
  // if the list is out of room, allocate a new one that's bigger
588
 
  if( _nNodes == _size )
589
 
    {
590
 
      int newSize = ( _size == 0 ) ? 1 : _size*2; // double the size of the old list (same behavior as STL vector)
591
 
      // allocate the new list
592
 
      Node** newNodes = new NodeP[ newSize ];
593
 
      // copy the old list to the new list
594
 
      memcpy( newNodes, _nodes, _nNodes*sizeof(Node*) );
595
 
      // delete the old list and replace it with the new list
596
 
      delete[] _nodes;
597
 
      //n->tree->rdata.cbNode = NULL;
598
 
      _nodes = newNodes;
599
 
      _size = newSize;
600
 
    }
601
 
 
602
 
  if( position >= 0 )
603
 
    {
604
 
      if( position > _nNodes )
605
 
        index = _nNodes;
606
 
      else
607
 
        index = position;
608
 
    }
609
 
  else if( mode == FLU_INSERT_SORTED || mode == FLU_INSERT_SORTED_REVERSE )
610
 
    {
611
 
      // search through the list until we find where to insert the node
612
 
      binSearch( n->label(), index );
613
 
    }
614
 
  else if( mode == FLU_INSERT_FRONT )
615
 
    {
616
 
      index = 0;
617
 
    }
618
 
  else if( mode == FLU_INSERT_BACK )
619
 
    {
620
 
      index = _nNodes;
621
 
    }
622
 
  else
623
 
    return;
624
 
 
625
 
  // shift all entries from the new insertion point down one spot
626
 
  // to make room for the new node
627
 
  for( i = _nNodes - 1; i >= index; i-- )
628
 
    _nodes[i+1] = _nodes[i];
629
 
 
630
 
  // add the new node
631
 
  _nodes[index] = n;
632
 
 
633
 
  _nNodes++;
634
 
}
635
 
 
636
 
int Flu_Tree_Browser :: NodeList :: erase( Node *n )
637
 
{
638
 
  if( n == NULL )
639
 
    return -1;
640
 
 
641
 
  int index;
642
 
  if( search( n, index ) )
643
 
    {
644
 
      // move all the others down one spot to remove the node
645
 
      for( int i = index; i < _nNodes-1; i++ )
646
 
        _nodes[i] = _nodes[i+1];
647
 
      _nNodes--;
648
 
 
649
 
      return index;
650
 
    }
651
 
  return -1;
652
 
}
653
 
 
654
 
int Flu_Tree_Browser :: NodeList :: erase( const char* n )
655
 
{
656
 
  if( _nNodes == 0 )
657
 
    return -1;
658
 
 
659
 
  int index;
660
 
  if( search( n, index ) )
661
 
    {
662
 
      // move all the others down one spot to remove the node
663
 
      for( int i = index; i < _nNodes-1; i++ )
664
 
        _nodes[i] = _nodes[i+1];
665
 
      _nNodes--;
666
 
      return index;
667
 
    }
668
 
  return -1;
669
 
}
670
 
 
671
 
void Flu_Tree_Browser :: NodeList :: erase( int n )
672
 
{
673
 
  // make sure n is in range
674
 
  if( ( n < 0 ) || ( n >= _nNodes ) )
675
 
    return;
676
 
 
677
 
  // move all the others down one spot to remove the node
678
 
  for( int i = n; i < _nNodes-1; i++ )
679
 
    _nodes[i] = _nodes[i+1];
680
 
 
681
 
  _nNodes--;
682
 
}
683
 
 
684
 
void Flu_Tree_Browser :: NodeList :: clear()
685
 
{
686
 
  if( _nodes )
687
 
    {
688
 
      //if( _nNodes )
689
 
      //if( _nodes[0] )
690
 
      //  _nodes[0]->tree->rdata.cbNode = NULL;
691
 
      delete[] _nodes;
692
 
    }
693
 
  _nodes = NULL;
694
 
  _nNodes = _size = 0;
695
 
}
696
 
 
697
 
int Flu_Tree_Browser :: NodeList :: findNum( const char *n )
698
 
{
699
 
  if( ( _nNodes == 0 ) || ( n == 0 ) )
700
 
    return 0;
701
 
 
702
 
  // see if there is a first node equal to "n"
703
 
  int index, last;
704
 
  if( !search( n, index ) )
705
 
    return 0;
706
 
 
707
 
  // now search forward until we hit a node not equal to "n"
708
 
  for( last = index; last < _nNodes-1; last++ )
709
 
    if( strcmp( n, _nodes[last+1]->label() ) != 0 )
710
 
      break;
711
 
 
712
 
  return last - index + 1;
713
 
}
714
 
 
715
 
Flu_Tree_Browser::Node* Flu_Tree_Browser :: NodeList :: find( const char* n, int which )
716
 
{
717
 
  if( ( _nNodes == 0 ) || ( n == 0 ) || ( which == 0 ) )
718
 
    return NULL;
719
 
 
720
 
  // see if there is a first node equal to "n"
721
 
  int index, first;
722
 
  if( !search( n, first ) )
723
 
    return NULL;
724
 
 
725
 
  // now search forward and try to find the which'th node named "n"
726
 
  int total = 0;
727
 
  for( index = first; index < _nNodes; index++ )
728
 
    {
729
 
      if( strcmp( n, _nodes[index]->label() ) == 0 )
730
 
        {
731
 
          total++;
732
 
          if( total == which )
733
 
            break;
734
 
        }
735
 
      else
736
 
        break;
737
 
    }
738
 
  if( total != which )
739
 
    return NULL;
740
 
 
741
 
  return _nodes[index];
742
 
}
743
 
 
744
 
#define SCROLL_SIZE 15
745
 
 
746
 
Flu_Tree_Browser :: Flu_Tree_Browser( int x, int y, int w, int h, const char *l )
747
 
  : Fl_Group( x, y, w, h )
748
 
{
749
 
  // add some widgets
750
 
  _box = new Fl_Group( x, y, w-SCROLL_SIZE, h-SCROLL_SIZE );
751
 
  _box->resizable( NULL );
752
 
  _box->end();
753
 
  //_box->set_output();
754
 
  scrollV = new Fl_Scrollbar( x+w-SCROLL_SIZE, y, SCROLL_SIZE, h-SCROLL_SIZE );
755
 
  scrollV->type( FL_VERTICAL );
756
 
  scrollV->callback( _scrollCB, this );
757
 
  scrollV->value( 0, 1, 0, 0 );
758
 
  scrollH = new Fl_Scrollbar( x, y+h-SCROLL_SIZE, w-SCROLL_SIZE, SCROLL_SIZE );
759
 
  scrollH->type( FL_HORIZONTAL );
760
 
  scrollH->callback( _scrollCB, this );
761
 
  scrollH->value( 0, 1, 0, 0 );
762
 
  scrollBox = new Fl_Group( x+w-SCROLL_SIZE, y+h-SCROLL_SIZE, SCROLL_SIZE, SCROLL_SIZE );
763
 
  scrollBox->box( FL_UP_BOX );
764
 
  scrollBox->end();
765
 
  resizable( _box );
766
 
 
767
 
  // set up the recursive data structure
768
 
  memset( &rdata, 0, sizeof(rdata) );
769
 
  rdata.root = &root;
770
 
  root.tree = this;
771
 
  rdata.cbNode = NULL;
772
 
  rdata.cbReason = FLU_NOTHING;
773
 
  rdata.tree = this;
774
 
  rdata.dragging = false;
775
 
  rdata.forceResize = true;
776
 
  rdata.shiftSelect = false;
777
 
  rdata.shiftSelectAll = false;
778
 
  rdata.nextId = 1;
779
 
  rdata.searchIndex = 1;
780
 
  rdata.defaultCollapseIcons[0] = new Fl_Pixmap( (char*const*)plus_xpm );
781
 
  rdata.defaultCollapseIcons[1] = new Fl_Pixmap( (char*const*)minus_xpm );
782
 
  rdata.defaultBranchIcons[0] = new Fl_Pixmap( (char*const*)folder_closed_xpm );
783
 
  rdata.defaultBranchIcons[1] = new Fl_Pixmap( (char*const*)folder_open_xpm );
784
 
 
785
 
  end();
786
 
 
787
 
  // set the default values for the tree
788
 
  selection_follows_hilight( false );
789
 
  select_under_mouse( false );
790
 
  open_without_children( true );
791
 
  auto_branches( false );
792
 
  double_click_opens( true );
793
 
  move_only_same_group( false );
794
 
  allow_leaf_duplication( true );
795
 
  shaded_entry_colors( FL_WHITE, FL_WHITE );
796
 
  collapse_icons( NULL, NULL );
797
 
  //branch_icons( NULL, NULL );
798
 
  rdata.branchIcons[0] = rdata.defaultBranchIcons[0];
799
 
  rdata.branchIcons[1] = rdata.defaultBranchIcons[1];
800
 
  leaf_icon( NULL );
801
 
  branch_text( FL_BLACK, FL_HELVETICA_BOLD, 12 );
802
 
  leaf_text( FL_BLACK, FL_HELVETICA, 12 );
803
 
  //callback( NULL );
804
 
  when( FL_WHEN_CHANGED );
805
 
  color( FL_WHITE );
806
 
  selection_color( FL_SELECTION_COLOR );
807
 
  box( FL_FLAT_BOX );
808
 
  connector_style( FL_DARK2, FL_DOT );
809
 
  selection_mode( FLU_MULTI_SELECT );
810
 
  selection_drag_mode( FLU_DRAG_TO_SELECT );
811
 
  insertion_mode( FLU_INSERT_SORTED );
812
 
  show_connectors( true );
813
 
  show_root( true );
814
 
  show_leaves( true );
815
 
  show_branches( true );
816
 
  open_on_select( false );
817
 
  //root_always_open( false );
818
 
  horizontal_gap( 2 );
819
 
  vertical_gap( 0 );
820
 
  widget_gap( 2 );
821
 
  set_root( l );
822
 
 
823
 
  resize( x, y, w, h );
824
 
}
825
 
 
826
 
Flu_Tree_Browser :: ~Flu_Tree_Browser()
827
 
{
828
 
  delete rdata.defaultCollapseIcons[0];
829
 
  delete rdata.defaultCollapseIcons[1];
830
 
 
831
 
  delete rdata.defaultBranchIcons[0];
832
 
  delete rdata.defaultBranchIcons[1];
833
 
}
834
 
 
835
 
void Flu_Tree_Browser :: auto_branches( bool b )
836
 
{
837
 
  rdata.autoBranches = b;
838
 
}
839
 
 
840
 
void Flu_Tree_Browser :: collapse_icons( Fl_Image *closed, Fl_Image *open )
841
 
{
842
 
  if( closed )
843
 
    rdata.collapseIcons[0] = closed;
844
 
  else
845
 
    rdata.collapseIcons[0] = rdata.defaultCollapseIcons[0];
846
 
 
847
 
  if( open )
848
 
    rdata.collapseIcons[1] = open;
849
 
  else
850
 
    rdata.collapseIcons[1] = rdata.defaultCollapseIcons[1];
851
 
}
852
 
 
853
 
void Flu_Tree_Browser :: branch_icons( Fl_Image *closed, Fl_Image *open )
854
 
{
855
 
  //if( closed )
856
 
  rdata.branchIcons[0] = closed;
857
 
  //else
858
 
  //rdata.branchIcons[0] = rdata.defaultBranchIcons[0];
859
 
 
860
 
  //if( open )
861
 
  rdata.branchIcons[1] = open;
862
 
  //else
863
 
  //rdata.branchIcons[1] = rdata.defaultBranchIcons[1];
864
 
}
865
 
 
866
 
void Flu_Tree_Browser :: set_default_branch_icons()
867
 
{
868
 
  rdata.branchIcons[0] = rdata.defaultBranchIcons[0];
869
 
  rdata.branchIcons[1] = rdata.defaultBranchIcons[1];
870
 
}
871
 
 
872
 
void Flu_Tree_Browser :: leaf_icon( Fl_Image *icon )
873
 
{
874
 
  rdata.leafIcon = icon;
875
 
}
876
 
 
877
 
bool Flu_Tree_Browser :: inside_entry_area( int x, int y )
878
 
{
879
 
  if( scrollH->visible() && scrollV->visible() )
880
 
    return( x > _box->x() && y > _box->y() &&
881
 
            x < (_box->x()+_box->w()-scrollV->w()) &&
882
 
            y < (_box->y()+_box->h()-scrollH->h()) );
883
 
  else if( !scrollH->visible() && !scrollV->visible() )
884
 
    return( x > _box->x() && y > _box->y() &&
885
 
            x < (_box->x()+_box->w()) &&
886
 
            y < (_box->y()+_box->h()) );
887
 
  else if( scrollH->visible() )
888
 
    return( x > _box->x() && y > _box->y() &&
889
 
            x < (_box->x()+_box->w()) &&
890
 
            y < (_box->y()+_box->h()-scrollH->h()) );
891
 
  else
892
 
    return( x > _box->x() && y > _box->y() &&
893
 
            x < (_box->x()+_box->w()-scrollV->w()) &&
894
 
            y < (_box->y()+_box->h()) );
895
 
}
896
 
 
897
 
void Flu_Tree_Browser :: resize( int X, int Y, int W, int H )
898
 
{
899
 
  Fl_Group::resize( X, Y, W, H );
900
 
 
901
 
  int dx = Fl::box_dx(box()), dy = Fl::box_dy(box()), dw = Fl::box_dw(box()), dh = Fl::box_dh(box());
902
 
 
903
 
  rdata.x = X+dx; rdata.y = Y+dy; rdata.totalW = rdata.x;
904
 
  root.recurse( rdata, Node::MEASURE );
905
 
  rdata.totalW -= X-dx;
906
 
  rdata.totalH = rdata.y - Y-dy;
907
 
 
908
 
  // if the size of the tree is bigger than the window, turn on the scrollbars
909
 
  bool hOn = false, vOn = false;
910
 
  if( rdata.totalW > W-dw )
911
 
    hOn = true;
912
 
  if( rdata.totalH > H-dh )
913
 
    vOn = true;
914
 
 
915
 
  // check if turning on one scrollbar actually forces the other to turn on
916
 
  if( hOn && ( rdata.totalH > H-SCROLL_SIZE ) )
917
 
    vOn = true;
918
 
  if( vOn && ( rdata.totalW > W-SCROLL_SIZE ) )
919
 
    hOn = true;
920
 
 
921
 
  // now resize the other kids depending on the state of the scrollbars
922
 
 
923
 
  _box->resize( X, Y, W, H );
924
 
  if( hOn && vOn )  // both scrollbars on
925
 
    {
926
 
      scrollH->resize( X+dx, Y+H-SCROLL_SIZE-dy, W-SCROLL_SIZE-dw, SCROLL_SIZE );
927
 
      scrollH->show();
928
 
      scrollV->resize( X+W-SCROLL_SIZE-dx, Y+dy, SCROLL_SIZE, H-SCROLL_SIZE-dh );
929
 
      scrollV->show();
930
 
      scrollBox->resize( X+W-SCROLL_SIZE-dx, Y+H-SCROLL_SIZE-dy, SCROLL_SIZE, SCROLL_SIZE );
931
 
      scrollBox->show();
932
 
 
933
 
      // set the scrollbar sizes and values
934
 
      int hDelta = rdata.totalW - W+dw + SCROLL_SIZE, scrollHW = scrollH->w()-SCROLL_SIZE-SCROLL_SIZE;
935
 
      hDelta = MAX( hDelta, 0 );
936
 
      scrollH->value( MIN( scrollH->value(), hDelta ), 1, 0, hDelta );
937
 
      scrollH->slider_size( MAX( (float)SCROLL_SIZE/float(scrollHW), float(scrollHW-hDelta)/float(scrollHW) ) );
938
 
 
939
 
      int vDelta = rdata.totalH - H+dh + SCROLL_SIZE, scrollVH = scrollV->h()-SCROLL_SIZE-SCROLL_SIZE;
940
 
      vDelta = MAX( vDelta, 0 );
941
 
      scrollV->value( MIN( scrollV->value(), vDelta ), 1, 0, vDelta );
942
 
      scrollV->slider_size( MAX( (float)SCROLL_SIZE/float(scrollVH), float(scrollVH-vDelta)/float(scrollVH) ) );
943
 
      _box->resize( X, Y, W-SCROLL_SIZE, H-SCROLL_SIZE );
944
 
    }
945
 
  else if( !hOn && !vOn )  // neither on
946
 
    {
947
 
      scrollH->hide();
948
 
      scrollV->hide();
949
 
      scrollBox->hide();
950
 
    }
951
 
  else if( hOn )  // just horizontal on
952
 
    {
953
 
      scrollH->resize( X+dx, Y+H-SCROLL_SIZE-dy, W-dw, SCROLL_SIZE );
954
 
      scrollH->show();
955
 
      scrollV->hide();
956
 
      scrollBox->hide();
957
 
 
958
 
      // set the scrollbar size and value
959
 
      int hDelta = rdata.totalW - W+dw, scrollHW = scrollH->w()-SCROLL_SIZE-SCROLL_SIZE;
960
 
      hDelta = MAX( hDelta, 0 );
961
 
      scrollH->value( MIN( scrollH->value(), hDelta ), 1, 0, hDelta );
962
 
      scrollH->slider_size( MAX( (float)SCROLL_SIZE/float(scrollHW), float(scrollHW-hDelta)/float(scrollHW) ) );
963
 
      _box->resize( X, Y, W, H-SCROLL_SIZE );
964
 
    }
965
 
  else if( vOn )  // just vertical on
966
 
    {
967
 
      scrollH->hide();
968
 
      scrollV->resize( X+W-SCROLL_SIZE-dx, Y+dy, SCROLL_SIZE, H-dh );
969
 
      scrollV->show();
970
 
      scrollBox->hide();
971
 
 
972
 
      // set the scrollbar size and value
973
 
      int vDelta = rdata.totalH - H+dh, scrollVH = scrollV->h()-SCROLL_SIZE-SCROLL_SIZE;
974
 
      vDelta = MAX( vDelta, 0 );
975
 
      scrollV->value( MIN( scrollV->value(), vDelta ), 1, 0, vDelta );
976
 
      scrollV->slider_size( MAX( (float)SCROLL_SIZE/float(scrollVH), float(scrollVH-vDelta)/float(scrollVH) ) );
977
 
      _box->resize( X, Y, W-SCROLL_SIZE, H );
978
 
    }
979
 
 
980
 
  rdata.browserX = _box->x() + dx;
981
 
  rdata.browserY = _box->y() + dy;
982
 
  rdata.browserW = _box->w() - dw;
983
 
  rdata.browserH = _box->h() - dh;
984
 
 
985
 
  redraw();
986
 
 
987
 
  rdata.forceResize = true;  // weird hack to get the scrollbars to turn on right the first time
988
 
}
989
 
 
990
 
int Flu_Tree_Browser :: handle( int event )
991
 
{
992
 
  if( event == FL_NO_EVENT )//|| event == FL_MOVE )
993
 
    return 0;
994
 
 
995
 
  if( event == FL_FOCUS )//&& rdata.lastHilighted )
996
 
    {
997
 
      //set_hilighted( rdata.lastHilighted );
998
 
      //lastEvent = event;
999
 
      //Fl_Group::handle( event );
1000
 
      redraw();
1001
 
      return 1;
1002
 
    }
1003
 
 
1004
 
  if( event == FL_UNFOCUS )
1005
 
    {
1006
 
      //if( lastEvent != FL_LEAVE )
1007
 
      //{
1008
 
          //rdata.lastHilighted = rdata.hilighted;
1009
 
      //}
1010
 
      //set_hilighted( NULL );
1011
 
      //lastEvent = event;
1012
 
      Fl_Group::handle( event );
1013
 
      redraw();
1014
 
      return 1;
1015
 
    }
1016
 
 
1017
 
  if( !rdata.dragging && !( event == FL_MOVE && rdata.selectUnderMouse ) )
1018
 
    {
1019
 
      if( ! (event == FL_MOVE || event == FL_ENTER || event == FL_LEAVE ) )
1020
 
        _box->redraw();
1021
 
 
1022
 
      if( Fl_Group::handle( event ) )
1023
 
        {
1024
 
          //if( event == FL_KEYDOWN || event == FL_KEYUP )
1025
 
          // redraw();
1026
 
          return 1;
1027
 
        }
1028
 
      //if (scrollV && Fl::event_inside(scrollV) && scrollV->handle(event)) return 1;
1029
 
      //if (scrollH && Fl::event_inside(scrollH) && scrollH->handle(event)) return 1;
1030
 
    }
1031
 
 
1032
 
  if( event == FL_RELEASE )
1033
 
    {
1034
 
      //Fl::focus(this);
1035
 
      rdata.dragging = false;
1036
 
      rdata.grabbed = 0;
1037
 
      rdata.dragNode = 0;
1038
 
      //redraw();
1039
 
    }
1040
 
 
1041
 
  int dx = Fl::box_dx(box()), dy = Fl::box_dy(box());
1042
 
 
1043
 
  // set some initial values for the recursive data structure
1044
 
  // account for the scrollbar positions
1045
 
  rdata.x = x()+dx; rdata.y = y()+dy;
1046
 
  if( scrollH->visible() )
1047
 
    rdata.x -= scrollH->value();
1048
 
  if( scrollV->visible() )
1049
 
    rdata.y -= scrollV->value();
1050
 
 
1051
 
  rdata.previous = NULL;
1052
 
  rdata.delta = 0;
1053
 
  rdata.visibilityChanged = false;
1054
 
 
1055
 
  // catch cursor keys for moving the hilighted entry or selecting all entries
1056
 
  if( event == FL_KEYDOWN )
1057
 
    {
1058
 
      // move hilighted entry up
1059
 
      if( Fl::event_key() == FL_Up )
1060
 
        {
1061
 
          rdata.delta = -1;
1062
 
          Fl::focus(this);
1063
 
          redraw();
1064
 
        }
1065
 
 
1066
 
      // move hilighted entry down
1067
 
      else if( Fl::event_key() == FL_Down )
1068
 
        {
1069
 
          rdata.delta = 1;
1070
 
          Fl::focus(this);
1071
 
          redraw();
1072
 
        }
1073
 
 
1074
 
      // select all
1075
 
      else if( Fl::event_state(FL_CTRL) && Fl::event_key() == 'a' )
1076
 
        {
1077
 
          select_all();
1078
 
          Fl::focus(this);
1079
 
          redraw();
1080
 
          return 1;
1081
 
        }
1082
 
 
1083
 
      // check for the Home key
1084
 
      else if( Fl::event_key() == FL_Home )
1085
 
        {
1086
 
          // set the hilighted entry to be the first entry
1087
 
          if( rdata.showRoot || ( rdata.root->_children.size() == 0 ) )
1088
 
            set_hilighted( rdata.root );
1089
 
          else if( rdata.root->_children.size() > 0 )
1090
 
            set_hilighted( rdata.root->_children.child(0) );
1091
 
          redraw();
1092
 
        }
1093
 
 
1094
 
      // check for the End key
1095
 
      else if( Fl::event_key() == FL_End )
1096
 
        {
1097
 
          // set the hilighted entry to be the last visible entry
1098
 
          if( rdata.showRoot && ( rdata.root->_children.size() == 0 ) )
1099
 
            set_hilighted( rdata.root );
1100
 
          else
1101
 
            {
1102
 
              // find the last node by repeatedly looking for the last child until there are no more branches
1103
 
              Node *n = &root;
1104
 
              while( n->_children.size() && n->open() )
1105
 
                n = n->_children.child( n->_children.size()-1 );
1106
 
              set_hilighted( n );
1107
 
            }
1108
 
          redraw();
1109
 
        }
1110
 
    }
1111
 
 
1112
 
  // pass the event down the tree
1113
 
  int val = root.recurse( rdata, Node::HANDLE, event );
1114
 
  if( val )
1115
 
    {
1116
 
      //redraw();
1117
 
      if( rdata.visibilityChanged )
1118
 
        root.determineVisibility();
1119
 
      if( val == 1 )
1120
 
        return 1;
1121
 
    }
1122
 
  // special case: if multi-select or single-select and user clicks on no items, unselect all items
1123
 
  else if( (rdata.selectionMode != FLU_NO_SELECT) && (event == FL_PUSH) && (!Fl::event_state(FL_CTRL)) )
1124
 
    {
1125
 
      unselect_all();
1126
 
      set_hilighted( NULL );
1127
 
      rdata.forceResize = true;
1128
 
      redraw();
1129
 
 
1130
 
      return 1;
1131
 
    }
1132
 
 
1133
 
  if( event == FL_SHOW || event == FL_HIDE )
1134
 
    root.determineVisibility();
1135
 
 
1136
 
  return Fl_Group::handle( event );
1137
 
  //return 0;
1138
 
}
1139
 
 
1140
 
void Flu_Tree_Browser :: insertion_mode( int m )
1141
 
{
1142
 
  rdata.insertionMode = m;
1143
 
  root.sort();
1144
 
}
1145
 
 
1146
 
void Flu_Tree_Browser :: set_hilighted( Flu_Tree_Browser::Node* n )
1147
 
{
1148
 
  if( rdata.hilighted == n  &&  when() != FL_WHEN_NOT_CHANGED )
1149
 
    return;
1150
 
 
1151
 
  if( rdata.hilighted )
1152
 
    rdata.hilighted->do_callback( FLU_UNHILIGHTED );
1153
 
  rdata.hilighted = n;
1154
 
  if( rdata.hilighted )
1155
 
    rdata.hilighted->do_callback( FLU_HILIGHTED );
1156
 
 
1157
 
  if( rdata.hilighted )
1158
 
    {
1159
 
      if( rdata.selectionFollowsHilight )
1160
 
        {
1161
 
          if( rdata.selectionMode == FLU_SINGLE_SELECT )
1162
 
            unselect_all();
1163
 
          rdata.hilighted->select( true );
1164
 
        }
1165
 
 
1166
 
      int extraH = scrollH->visible() ? scrollH->h() : 0;
1167
 
 
1168
 
      // if the hilighted entry is below the visible bounds of the browser, move the vertical scrollbar
1169
 
      // so the hilighted entry is the last visible entry
1170
 
      if( rdata.hilighted->currentY-y()+rdata.hilighted->currentH > scrollV->value()+h()-extraH )
1171
 
        ((Fl_Valuator*)scrollV)->value( rdata.hilighted->currentY-y() - h()+extraH + rdata.hilighted->currentH );
1172
 
 
1173
 
      // if the hilighted entry is above the visible bounds of the browser, move the vertical scrollbar
1174
 
      // so the hilighted entry is the first visible entry
1175
 
      if( rdata.hilighted->currentY-y() < scrollV->value() )
1176
 
        ((Fl_Valuator*)scrollV)->value( rdata.hilighted->currentY-y() );
1177
 
    }
1178
 
  redraw();
1179
 
}
1180
 
 
1181
 
int Flu_Tree_Browser :: num_selected()
1182
 
{
1183
 
  return root.recurse( rdata, Node::COUNT_SELECTED );
1184
 
}
1185
 
 
1186
 
int Flu_Tree_Browser :: Node :: num_selected()
1187
 
{
1188
 
  return recurse( tree->rdata, COUNT_SELECTED );
1189
 
}
1190
 
 
1191
 
Flu_Tree_Browser::Node* Flu_Tree_Browser :: get_selected( int index )
1192
 
{
1193
 
  return root.get_selected( index );
1194
 
}
1195
 
 
1196
 
Flu_Tree_Browser::Node* Flu_Tree_Browser :: Node :: get_selected( int index )
1197
 
{
1198
 
  tree->rdata.counter = 0;
1199
 
  tree->rdata.searchIndex = index;
1200
 
  Node *n = modify( 0, GET_SELECTED, tree->rdata );
1201
 
  tree->rdata.searchIndex = 1;
1202
 
  return n;
1203
 
}
1204
 
 
1205
 
Flu_Tree_Browser :: Node :: Node( const char *lbl )
1206
 
{
1207
 
  flags = 0;
1208
 
  userData = 0;
1209
 
  _parent = 0;
1210
 
  _widget = 0;
1211
 
  _group = 0;
1212
 
  SET(ACTIVE);
1213
 
  CLEAR(LEAF);
1214
 
  _id = 0;
1215
 
  CLEAR(ALWAYS_OPEN);
1216
 
  SET(COLLAPSED);
1217
 
  SET(MOVABLE);
1218
 
  SET(DROPPABLE);
1219
 
  currentY = currentH = 0;
1220
 
  CLEAR(SELECTED);
1221
 
  CLEAR(EXPAND_TO_WIDTH);
1222
 
  SET(SHOW_LABEL);
1223
 
  if( lbl == 0 )
1224
 
    text = "";
1225
 
  else
1226
 
    text = lbl;
1227
 
 
1228
 
  cIcon[0] = cIcon[1] = bIcon[0] = bIcon[1] = lIcon = 0;
1229
 
}
1230
 
 
1231
 
Flu_Tree_Browser :: Node :: Node( bool l, const char* n, Node *p, RData &rdata, Fl_Widget *w, bool showLbl )
1232
 
{
1233
 
  _group = 0;
1234
 
  flags = 0;
1235
 
  userData = 0;
1236
 
  SET(LEAF,l);
1237
 
  text = n;
1238
 
  _id = 0;
1239
 
  SET(ACTIVE);
1240
 
  _parent = p;
1241
 
  CLEAR(ALWAYS_OPEN);
1242
 
  SET(COLLAPSED);
1243
 
  CLEAR(SELECTED);
1244
 
  CLEAR(EXPAND_TO_WIDTH);
1245
 
  SET(MOVABLE);
1246
 
  SET(DROPPABLE);
1247
 
  _widget = 0;
1248
 
  currentY = currentH = 0;
1249
 
  cIcon[0] = cIcon[1] = bIcon[0] = bIcon[1] = lIcon = 0;
1250
 
  SET( SHOW_LABEL, showLbl );
1251
 
  tree = rdata.tree;
1252
 
 
1253
 
  initType();
1254
 
 
1255
 
  _id = rdata.nextId++;
1256
 
  widget( w );
1257
 
}
1258
 
 
1259
 
void Flu_Tree_Browser :: Node :: initType()
1260
 
{
1261
 
  if( is_leaf() )
1262
 
    {
1263
 
      lIcon = tree->rdata.leafIcon;
1264
 
      textColor = tree->rdata.defLeafColor;
1265
 
      textFont = tree->rdata.defLeafFont;
1266
 
      textSize = tree->rdata.defLeafSize;
1267
 
    }
1268
 
  else
1269
 
    {
1270
 
      cIcon[0] = tree->rdata.collapseIcons[0];
1271
 
      cIcon[1] = tree->rdata.collapseIcons[1];
1272
 
      bIcon[0] = tree->rdata.branchIcons[0];
1273
 
      bIcon[1] = tree->rdata.branchIcons[1];
1274
 
      textColor = tree->rdata.defBranchColor;
1275
 
      textFont = tree->rdata.defBranchFont;
1276
 
      textSize = tree->rdata.defBranchSize;
1277
 
    }
1278
 
}
1279
 
 
1280
 
Flu_Tree_Browser :: Node :: ~Node()
1281
 
{
1282
 
  // if this node is in a tree, make sure it isn't holding a reference to us
1283
 
  if( tree )
1284
 
    {
1285
 
      if( tree->rdata.hilighted == this ) tree->rdata.hilighted = NULL;
1286
 
      //if( tree->rdata.lastHilighted == this ) tree->rdata.lastHilighted = NULL;
1287
 
      if( tree->rdata.grabbed == this ) tree->rdata.grabbed = NULL;
1288
 
      if( tree->rdata.dragNode == this ) tree->rdata.dragNode = NULL;
1289
 
    }
1290
 
  clear();
1291
 
}
1292
 
 
1293
 
Flu_Tree_Browser::Node* Flu_Tree_Browser :: Node :: first()
1294
 
{
1295
 
  return this;
1296
 
}
1297
 
 
1298
 
Flu_Tree_Browser::Node* Flu_Tree_Browser :: Node :: first_branch()
1299
 
{
1300
 
  Node *n = first();
1301
 
  while( n )
1302
 
    {
1303
 
      if( n->is_branch() )
1304
 
        return n;
1305
 
      else
1306
 
        n = n->next();
1307
 
    }
1308
 
  return NULL;
1309
 
}
1310
 
 
1311
 
Flu_Tree_Browser::Node* Flu_Tree_Browser :: Node :: first_leaf()
1312
 
{
1313
 
  Node *n = first();
1314
 
  while( n )
1315
 
    {
1316
 
      if( n->is_leaf() )
1317
 
        return n;
1318
 
      else
1319
 
        n = n->next();
1320
 
    }
1321
 
  return NULL;
1322
 
}
1323
 
 
1324
 
Flu_Tree_Browser::Node* Flu_Tree_Browser :: Node :: last()
1325
 
{
1326
 
  if( children() == 0 )
1327
 
    return this;
1328
 
  else
1329
 
    return( child( children() - 1 )->last() );
1330
 
}
1331
 
 
1332
 
Flu_Tree_Browser::Node* Flu_Tree_Browser :: Node :: last_branch()
1333
 
{
1334
 
  Node *n = last();
1335
 
  while( n )
1336
 
    {
1337
 
      if( n->is_branch() )
1338
 
        return n;
1339
 
      else
1340
 
        n = n->previous();
1341
 
    }
1342
 
  return NULL;
1343
 
}
1344
 
 
1345
 
Flu_Tree_Browser::Node* Flu_Tree_Browser :: Node :: last_leaf()
1346
 
{
1347
 
  Node *n = last();
1348
 
  while( n )
1349
 
    {
1350
 
      if( n->is_leaf() )
1351
 
        return n;
1352
 
      else
1353
 
        n = n->previous();
1354
 
    }
1355
 
  return NULL;
1356
 
}
1357
 
 
1358
 
Flu_Tree_Browser::Node* Flu_Tree_Browser :: Node :: next_sibling()
1359
 
{
1360
 
  if( is_root() )
1361
 
    return NULL;
1362
 
  int index;
1363
 
  for( index = 0; index < _parent->children(); index++ )
1364
 
    if( _parent->child(index) == this )
1365
 
      break;
1366
 
  // if we are the last child of our parent, then we have no next sibling
1367
 
  if( index == _parent->children()-1 )
1368
 
    return NULL;
1369
 
  // otherwise return our next sibling
1370
 
  else
1371
 
    return( _parent->child(index+1) );
1372
 
}
1373
 
 
1374
 
Flu_Tree_Browser::Node* Flu_Tree_Browser :: Node :: previous_sibling()
1375
 
{
1376
 
  if( is_root() )
1377
 
    return NULL;
1378
 
  int index;
1379
 
  for( index = 0; index < _parent->children(); index++ )
1380
 
    if( _parent->child(index) == this )
1381
 
      break;
1382
 
  // if we are the first child of our parent, then we have no previous sibling
1383
 
  if( index == 0 )
1384
 
    return NULL;
1385
 
  // otherwise return our previous sibling
1386
 
  else
1387
 
    return( _parent->child(index-1) );
1388
 
}
1389
 
 
1390
 
int Flu_Tree_Browser :: Node :: index() const
1391
 
{
1392
 
  if( is_root() )
1393
 
    return -1;
1394
 
  int index;
1395
 
  for( index = 0; index < _parent->children(); index++ )
1396
 
    if( _parent->child(index) == this )
1397
 
      return index;
1398
 
  return -1;
1399
 
}
1400
 
 
1401
 
Flu_Tree_Browser::Node* Flu_Tree_Browser :: Node :: next()
1402
 
{
1403
 
  // take care of the root node as a special case
1404
 
  if( is_root() )
1405
 
    {
1406
 
      if( children() )
1407
 
        return child(0);
1408
 
      else
1409
 
        return NULL;
1410
 
    }
1411
 
 
1412
 
  // if we are a branch, then the next node is our first child, unless we don't have any children
1413
 
  if( is_branch() && _children.size() )
1414
 
    return _children.child(0);
1415
 
  else
1416
 
    {
1417
 
      // otherwise, the next node is our next sibling. if there is no next sibling (because we
1418
 
      // are the last child of our parent), then the next node is the next sibling of our parent (and so on...)
1419
 
      Node *p = parent(), *n = next_sibling();
1420
 
      while( p )
1421
 
        {
1422
 
          if( n )
1423
 
            return n;
1424
 
          else
1425
 
            {
1426
 
              n = p->next_sibling();
1427
 
              p = p->parent();
1428
 
            }
1429
 
        }
1430
 
      return NULL;
1431
 
    }
1432
 
}
1433
 
 
1434
 
Flu_Tree_Browser::Node* Flu_Tree_Browser :: Node :: next_branch()
1435
 
{
1436
 
  Node *n = next();
1437
 
  while( n )
1438
 
    {
1439
 
      if( n->is_branch() )
1440
 
        return n;
1441
 
      else
1442
 
        n = n->next();
1443
 
    }
1444
 
  return NULL;
1445
 
}
1446
 
 
1447
 
Flu_Tree_Browser::Node* Flu_Tree_Browser :: Node :: next_leaf()
1448
 
{
1449
 
  Node *n = next();
1450
 
  while( n )
1451
 
    {
1452
 
      if( n->is_leaf() )
1453
 
        return n;
1454
 
      else
1455
 
        n = n->next();
1456
 
    }
1457
 
  return NULL;
1458
 
}
1459
 
 
1460
 
Flu_Tree_Browser::Node* Flu_Tree_Browser :: Node :: previous()
1461
 
{
1462
 
  // take care of the root node as a special case
1463
 
  if( is_root() )
1464
 
    return NULL;
1465
 
 
1466
 
  // the previous node is either our parent's
1467
 
  // previous sibling (if that sibling exists and is a leaf or a branch with no children),
1468
 
  // or the last child of our parent's previous sibling (if that sibling exists and is
1469
 
  // a branch with children). if there is no previous sibling, then the previous node
1470
 
  // is our parent
1471
 
  Node *n = previous_sibling();
1472
 
  if( !n )
1473
 
    return _parent;
1474
 
  else
1475
 
    {
1476
 
      if( n->is_leaf() )  // is leaf, so that is the previous node
1477
 
        return n;
1478
 
      else if( n->children() )  // is branch with some children, so previous node is last child
1479
 
        return( n->last() );
1480
 
      else  // is branch with no children, so that is the previous node
1481
 
        return n;
1482
 
    }
1483
 
}
1484
 
 
1485
 
Flu_Tree_Browser::Node* Flu_Tree_Browser :: Node :: previous_branch()
1486
 
{
1487
 
  Node *n = previous();
1488
 
  while( n )
1489
 
    {
1490
 
      if( n->is_branch() )
1491
 
        return n;
1492
 
      else
1493
 
        n = n->previous();
1494
 
    }
1495
 
  return NULL;
1496
 
}
1497
 
 
1498
 
Flu_Tree_Browser::Node* Flu_Tree_Browser :: Node :: previous_leaf()
1499
 
{
1500
 
  Node *n = previous();
1501
 
  while( n )
1502
 
    {
1503
 
      if( n->is_leaf() )
1504
 
        return n;
1505
 
      else
1506
 
        n = n->previous();
1507
 
    }
1508
 
  return NULL;
1509
 
}
1510
 
 
1511
 
void Flu_Tree_Browser :: Node :: determineVisibility( bool parentVisible )
1512
 
{
1513
 
  if( _widget )
1514
 
    {
1515
 
      if( parentVisible )
1516
 
        _widget->w->show();
1517
 
      else
1518
 
        _widget->w->hide();
1519
 
    }
1520
 
  for( int i = 0; i < _children.size(); i++ )
1521
 
    _children.child(i)->determineVisibility( parentVisible && open() );
1522
 
}
1523
 
 
1524
 
Flu_Tree_Browser::Node* Flu_Tree_Browser :: Node :: child( int i ) const
1525
 
{
1526
 
  if( i < 0 || i >= _children.size() )
1527
 
    return 0;
1528
 
  else
1529
 
    return _children.child(i);
1530
 
}
1531
 
 
1532
 
void Flu_Tree_Browser :: Node :: clear()
1533
 
{
1534
 
  widget(NULL);
1535
 
  for( int i = 0; i < _children.size(); i++ )
1536
 
    {
1537
 
      //if( tree->rdata.cbNode == _children.child(i) )
1538
 
      //tree->rdata.cbNode = NULL;
1539
 
      delete _children.child(i);
1540
 
    }
1541
 
  _children.clear();
1542
 
  if( _group )
1543
 
    {
1544
 
      if( _group->parent() )
1545
 
        _group->parent()->remove( *_group );
1546
 
      while( _group->children() )
1547
 
        _group->remove( *_group->child(0) );
1548
 
      delete _group;
1549
 
      _group = NULL;
1550
 
    }
1551
 
}
1552
 
 
1553
 
void Flu_Tree_Browser :: Node :: print( int spaces )
1554
 
{
1555
 
  for( int s = 0; s < spaces; s++ )
1556
 
    printf( " " );
1557
 
  if( is_leaf() )
1558
 
    printf( "  %s\n", text.c_str() );
1559
 
  else
1560
 
    printf( "[%s]\n", text.c_str() );
1561
 
 
1562
 
  for( int i = 0; i < _children.size(); i++ )
1563
 
    _children.child(i)->print( spaces+2 );
1564
 
}
1565
 
 
1566
 
void Flu_Tree_Browser :: draw()
1567
 
{
1568
 
  if( rdata.forceResize )
1569
 
    {
1570
 
      resize( x(), y(), w(), h() );
1571
 
      rdata.forceResize = false;
1572
 
    }
1573
 
 
1574
 
  // draw the background color
1575
 
  //fl_draw_box( _box->box(), _box->x(), _box->y(), _box->w(), _box->h(), _box->color() );
1576
 
  fl_draw_box( box(), x(), y(), w(), h(), color() );
1577
 
 
1578
 
  int dx = Fl::box_dx(box()), dy = Fl::box_dy(box()),
1579
 
    dw = Fl::box_dw(box()), dh = Fl::box_dh(box());
1580
 
 
1581
 
  // set up the recursive data structure
1582
 
  rdata.x = x()+dx; rdata.y = y()+dy;
1583
 
  // account for the positions of the scrollbars
1584
 
  if( scrollH->visible() )
1585
 
    rdata.x -= scrollH->value();
1586
 
  if( scrollV->visible() )
1587
 
    rdata.y -= scrollV->value();
1588
 
 
1589
 
  rdata.last = true;
1590
 
  rdata.bgColor = _box->color();
1591
 
  rdata.shadedIndex = 0;
1592
 
 
1593
 
  // pick the connector line and selection colors depending on the active state
1594
 
  if( active() )
1595
 
    {
1596
 
      rdata.lineColor = rdata.defLineColor;
1597
 
      rdata.selectionColor = rdata.defSelectionColor;
1598
 
    }
1599
 
  else
1600
 
    {
1601
 
      rdata.lineColor = fl_inactive( rdata.defLineColor );
1602
 
      rdata.selectionColor = fl_inactive( rdata.defSelectionColor );
1603
 
    }
1604
 
 
1605
 
  // draw the tree
1606
 
  fl_push_clip( x()+dx, y()+dy, w()-dw, h()-dh );
1607
 
  root.recurse( rdata, Node::DRAW );
1608
 
 
1609
 
  fl_pop_clip();
1610
 
 
1611
 
  // draw the kids
1612
 
  draw_child( *scrollBox );
1613
 
  draw_child( *scrollH );
1614
 
  draw_child( *scrollV );
1615
 
 
1616
 
  // draw the box last so it's on top
1617
 
  //fl_draw_box( _box->box(), _box->x(), _box->y(), _box->w(), _box->h(), _box->color() );
1618
 
}
1619
 
 
1620
 
inline void draw_T( int x, int y, int w, int h )
1621
 
{
1622
 
  int w2 = w >> 1;
1623
 
  int h2 = h >> 1;
1624
 
  fl_line( x+w2, y, x+w2, y+h );
1625
 
  fl_line( x+w2, y+h2, x+w, y+h2 );
1626
 
}
1627
 
 
1628
 
inline void draw_L( int x, int y, int w, int h )
1629
 
{
1630
 
  int w2 = w >> 1;
1631
 
  int h2 = h >> 1;
1632
 
  fl_line( x+w2, y, x+w2, y+h2 );
1633
 
  fl_line( x+w2, y+h2, x+w, y+h2 );
1634
 
}
1635
 
 
1636
 
inline void draw_Lflip( int x, int y, int w, int h )
1637
 
{
1638
 
  int w2 = w >> 1;
1639
 
  int h2 = h >> 1;
1640
 
  fl_line( x+w2, y+h, x+w2, y+h2 );
1641
 
  fl_line( x+w2, y+h2, x, y+h2 );
1642
 
}
1643
 
 
1644
 
inline void draw_Lflop( int x, int y, int w, int h )
1645
 
{
1646
 
  int w2 = w >> 1;
1647
 
  int h2 = h >> 1;
1648
 
  fl_line( x+w2, y+h, x+w2, y+h2 );
1649
 
  fl_line( x+w2, y+h2, x+w, y+h2 );
1650
 
}
1651
 
 
1652
 
inline void draw_Ldash( int x, int y, int w, int h )
1653
 
{
1654
 
  w = w >> 1;
1655
 
  h = h >> 1;
1656
 
  fl_line( x, y+h, x+w, y+h );
1657
 
}
1658
 
 
1659
 
inline void draw_vert_dash( int x, int y, int w, int h )
1660
 
{
1661
 
  w = w >> 1;
1662
 
  fl_line( x+w, y+(h>>1), x+w, y+h );
1663
 
}
1664
 
 
1665
 
inline void draw_Rdash( int x, int y, int w, int h )
1666
 
{
1667
 
  h = h >> 1;
1668
 
  fl_line( x+w, y+h, x+(w>>1), y+h );
1669
 
}
1670
 
 
1671
 
void Flu_Tree_Browser :: Node :: draw( RData &rdata, bool measure )
1672
 
{
1673
 
  int which = open(); // i.e. which icon: open or closed?
1674
 
  bool skipCollapser = is_root() && rdata.showRoot && ( CHECK(ALWAYS_OPEN) || rdata.allBranchesAlwaysOpen );
1675
 
  int halfHGap = rdata.hGap >> 1, halfVGap = rdata.vGap >> 1;
1676
 
  bool doDraw = !measure;
1677
 
 
1678
 
  int X = rdata.x;
1679
 
  int Y = rdata.y;
1680
 
 
1681
 
  Fl_Color bgColor = rdata.shadedColors[rdata.shadedIndex], tColor = textColor, hilightColor = rdata.selectionColor;
1682
 
 
1683
 
  // pick the text color depending on the active state
1684
 
  if( !rdata.tree->active() || !CHECK(ACTIVE))
1685
 
    tColor = fl_inactive( tColor );
1686
 
 
1687
 
  if( doDraw )
1688
 
    {
1689
 
      // draw the background for the entry using the entry background color
1690
 
      fl_draw_box( FL_FLAT_BOX, rdata.browserX, Y, rdata.browserW, currentH, bgColor );
1691
 
 
1692
 
      // if dragging to the inside of a branch, hilight that branch
1693
 
      if( CHECK(SELECTED) )
1694
 
        {
1695
 
          bgColor = rdata.selectionColor;
1696
 
          tColor = fl_contrast( tColor, bgColor );
1697
 
          hilightColor = rdata.bgColor;
1698
 
          fl_draw_box( FL_FLAT_BOX, rdata.browserX, Y, rdata.browserW, currentH, bgColor );
1699
 
        }
1700
 
 
1701
 
      fl_color( rdata.lineColor );
1702
 
      fl_line_style( rdata.lineStyle, rdata.lineWidth );
1703
 
    }
1704
 
 
1705
 
  if( is_leaf() ) // draw leaves one way...
1706
 
    {
1707
 
      // draw the connectors
1708
 
      if( doDraw && rdata.showConnectors && rdata.showBranches )
1709
 
        {
1710
 
          if( parent()->is_root() && !rdata.showRoot && rdata.first )
1711
 
            {
1712
 
              if( rdata.last )
1713
 
                draw_Rdash( X-halfHGap, Y-halfVGap, rdata.branchIconW+rdata.hGap, currentH+rdata.vGap );
1714
 
              else
1715
 
                draw_Lflop( X-halfHGap, Y-halfVGap, rdata.branchIconW+rdata.hGap, currentH+rdata.vGap );
1716
 
            }
1717
 
          else if( rdata.last )
1718
 
            draw_L( X-halfHGap, Y-halfVGap, rdata.branchIconW+rdata.hGap, currentH+rdata.vGap );
1719
 
          else
1720
 
            draw_T( X-halfHGap, Y-halfVGap, rdata.branchIconW+rdata.hGap, currentH+rdata.vGap );
1721
 
        }
1722
 
 
1723
 
      // account for leaf icon spacing
1724
 
      if( rdata.showBranches )
1725
 
        {
1726
 
          if( lIcon )
1727
 
            X += rdata.collapseIcons[which]->w() + rdata.hGap;
1728
 
          else
1729
 
            X += rdata.collapseIcons[which]->w() + rdata.wGap;
1730
 
        }
1731
 
      else 
1732
 
        X += rdata.wGap;
1733
 
 
1734
 
      // draw some more connectors
1735
 
      if( doDraw && rdata.showConnectors && lIcon && rdata.showBranches )
1736
 
        draw_Ldash( X-halfHGap, Y-halfVGap, lIcon->w()+rdata.hGap, currentH+rdata.vGap );
1737
 
 
1738
 
      // draw the leaf icon
1739
 
      if( lIcon && !CHECK(ICON_AT_END) )
1740
 
        {
1741
 
          if( doDraw )
1742
 
            lIcon->draw( X, Y+(currentH>>1)-(lIcon->h()>>1) );
1743
 
          X += lIcon->w() + rdata.wGap;
1744
 
        }
1745
 
    }
1746
 
  else // ...and branches another
1747
 
    {
1748
 
      // force the root to the left if it has no visible children
1749
 
      if( is_root() && !CHECK(SOME_VISIBLE_CHILDREN) )
1750
 
        {
1751
 
          skipCollapser = true;
1752
 
          which = 0;
1753
 
        }
1754
 
 
1755
 
      if( !CHECK(SOME_VISIBLE_CHILDREN) && !rdata.showLeaves )
1756
 
        which = 0;
1757
 
 
1758
 
      // draw the connectors
1759
 
      if( doDraw && !skipCollapser && rdata.showConnectors && rdata.showBranches )
1760
 
        {
1761
 
          if( is_root() )
1762
 
            {
1763
 
              if( CHECK(SOME_VISIBLE_CHILDREN) )
1764
 
                draw_Rdash( X-halfHGap, Y-halfVGap, rdata.collapseIcons[which]->w()+4+rdata.hGap, currentH+rdata.vGap );
1765
 
            }
1766
 
          else if( parent()->is_root() && !rdata.showRoot && rdata.first )
1767
 
            {
1768
 
              if( rdata.last )
1769
 
                draw_Rdash( X-halfHGap, Y-halfVGap, rdata.branchIconW+rdata.hGap, currentH+rdata.vGap );
1770
 
              else
1771
 
                draw_Lflop( X-halfHGap, Y-halfVGap, rdata.branchIconW+rdata.hGap, currentH+rdata.vGap );
1772
 
            }
1773
 
          else if( rdata.last )
1774
 
            draw_L( X-halfHGap, Y-halfVGap, rdata.branchIconW+rdata.hGap, currentH+rdata.vGap );
1775
 
          else
1776
 
            draw_T( X-halfHGap, Y-halfVGap, rdata.branchIconW+rdata.hGap, currentH+rdata.vGap );
1777
 
        }
1778
 
 
1779
 
      // draw the collapsed icons
1780
 
      if( doDraw && !skipCollapser && !CHECK(ALWAYS_OPEN) && !rdata.allBranchesAlwaysOpen )
1781
 
        {
1782
 
          if( CHECK(SOME_VISIBLE_CHILDREN) || rdata.showLeaves )
1783
 
            {
1784
 
              if( !rdata.openWOChildren && !CHECK(SOME_VISIBLE_CHILDREN) )
1785
 
                which = 0;
1786
 
              if( rdata.openWOChildren || CHECK(SOME_VISIBLE_CHILDREN) )
1787
 
                {
1788
 
                  if( _parent==0 )
1789
 
                    cIcon[which]->draw( X, Y+(currentH>>1)-(cIcon[which]->h()>>1) );
1790
 
                  else
1791
 
                    cIcon[which]->draw( X+(rdata.branchIconW>>1)-(cIcon[which]->w()>>1), Y+(currentH>>1)-(cIcon[which]->h()>>1) );
1792
 
                }
1793
 
            }
1794
 
        }
1795
 
 
1796
 
      if( !skipCollapser )
1797
 
        {
1798
 
          X += cIcon[which]->w();
1799
 
          if( bIcon[which] )
1800
 
            X += rdata.hGap;
1801
 
          else
1802
 
            X += rdata.wGap;
1803
 
        }
1804
 
 
1805
 
      // draw some more connectors
1806
 
      if( doDraw && rdata.showConnectors && rdata.showBranches )
1807
 
        {
1808
 
          int hGap = rdata.hGap;
1809
 
          if( bIcon[which] )
1810
 
            hGap += bIcon[which]->w();
1811
 
          if( skipCollapser && CHECK(SOME_VISIBLE_CHILDREN) )
1812
 
            draw_vert_dash( X-halfHGap, Y-halfVGap, hGap, currentH+rdata.vGap );
1813
 
          else if( !which || !CHECK(SOME_VISIBLE_CHILDREN) )
1814
 
            draw_Ldash( X-halfHGap, Y-halfVGap, hGap, currentH+rdata.vGap );
1815
 
          else
1816
 
            draw_Lflip( X-halfHGap, Y-halfVGap, hGap, currentH+rdata.vGap );
1817
 
        }
1818
 
 
1819
 
      // draw the branch icon
1820
 
      if( bIcon[which] )
1821
 
        {
1822
 
          if( doDraw )
1823
 
            bIcon[which]->draw( X, Y+(currentH>>1)-(bIcon[which]->h()>>1) );
1824
 
          X += bIcon[which]->w() + rdata.wGap;
1825
 
        }
1826
 
      else
1827
 
        X += rdata.wGap;
1828
 
    }
1829
 
 
1830
 
  if( doDraw )
1831
 
    fl_line_style( 0 );
1832
 
 
1833
 
  // draw the entry
1834
 
  if( CHECK(SHOW_LABEL) && !CHECK(SWAP_LABEL_AND_WIDGET) )
1835
 
    {
1836
 
      if( doDraw )
1837
 
        {
1838
 
          fl_draw_box( FL_FLAT_BOX, X, Y+(currentH>>1)-(textH>>1), textW, textH, bgColor );
1839
 
          fl_color( tColor );
1840
 
          fl_font( textFont, textSize );
1841
 
          fl_draw( text.c_str(), X, Y+(currentH>>1)-(textH>>1), textW, textH, FL_ALIGN_LEFT );
1842
 
        }
1843
 
      X += textW;
1844
 
    }
1845
 
 
1846
 
  if( _widget )
1847
 
    {
1848
 
      int widgetW = _widget->w->w();
1849
 
      int widgetH = _widget->w->h();
1850
 
      if( doDraw )
1851
 
        {
1852
 
          if( CHECK(AUTO_COLOR) )
1853
 
            _widget->w->color( bgColor );
1854
 
          if( CHECK(AUTO_LABEL_COLOR) )
1855
 
            _widget->w->labelcolor( tColor );
1856
 
          if( CHECK(AUTO_LABEL) )
1857
 
            _widget->w->label( text.c_str() );
1858
 
          _widget->w->redraw();
1859
 
          _widget->w->position( X, Y+(currentH>>1)-(widgetH>>1) );
1860
 
          if( CHECK(EXPAND_TO_WIDTH) )
1861
 
            _widget->w->size( MAX( _widget->defaultW, rdata.browserW - (X-rdata.browserX) ), _widget->w->h() );
1862
 
          _widget->w->draw();
1863
 
        }
1864
 
      if( CHECK(EXPAND_TO_WIDTH) )
1865
 
        {
1866
 
          if( _widget->w->w() == _widget->defaultW )
1867
 
            X += _widget->defaultW;
1868
 
        }
1869
 
      else
1870
 
        X += widgetW;
1871
 
    }
1872
 
 
1873
 
  if( CHECK(SHOW_LABEL) && CHECK(SWAP_LABEL_AND_WIDGET) )
1874
 
    {
1875
 
      if( doDraw )
1876
 
        {
1877
 
          fl_draw_box( FL_FLAT_BOX, X, Y+(currentH>>1)-(textH>>1), textW, textH, bgColor );
1878
 
          fl_color( tColor );
1879
 
          fl_font( textFont, textSize );
1880
 
          fl_draw( text.c_str(), X, Y+(currentH>>1)-(textH>>1), textW, textH, FL_ALIGN_LEFT );
1881
 
        }
1882
 
      X += textW;
1883
 
    }
1884
 
 
1885
 
  // draw the leaf icon to the right of the label and widget
1886
 
  if( is_leaf() && lIcon && CHECK(ICON_AT_END) )
1887
 
    {
1888
 
      if( doDraw )
1889
 
        lIcon->draw( X, Y+(currentH>>1)-(lIcon->h()>>1) );
1890
 
      X += lIcon->w() + rdata.wGap;
1891
 
    }
1892
 
 
1893
 
  // if hilighted, draw a box outlining the entry
1894
 
  if( Fl::focus() == tree && rdata.hilighted == this && doDraw )
1895
 
    {
1896
 
      fl_color( hilightColor );
1897
 
      fl_line_style( FL_DOT, 1 );
1898
 
      fl_rect( rdata.browserX, Y, rdata.browserW, currentH, hilightColor );
1899
 
      fl_line_style( 0 );
1900
 
    }
1901
 
 
1902
 
  rdata.totalW = MAX( rdata.totalW, X );
1903
 
}
1904
 
 
1905
 
void Flu_Tree_Browser :: Node :: select( bool b )
1906
 
{
1907
 
  if( (CHECK(SELECTED)==b) && (tree->when() != FL_WHEN_NOT_CHANGED) )
1908
 
    return;
1909
 
  SET(SELECTED,b);
1910
 
  tree->redraw();
1911
 
  if( tree->when() == FL_WHEN_RELEASE )
1912
 
    return;
1913
 
  if( b )
1914
 
    do_callback( FLU_SELECTED );
1915
 
  else
1916
 
    do_callback( FLU_UNSELECTED );
1917
 
}
1918
 
 
1919
 
void Flu_Tree_Browser :: Node :: open( bool b )
1920
 
{
1921
 
  if( is_leaf() )
1922
 
    return;
1923
 
 
1924
 
  if( CHECK(ALWAYS_OPEN) || tree->rdata.allBranchesAlwaysOpen )
1925
 
    return;
1926
 
 
1927
 
  if( (open() == b) && (tree->when() != FL_WHEN_NOT_CHANGED) )
1928
 
    return;
1929
 
 
1930
 
  tree->rdata.justOpenedClosed = true;
1931
 
 
1932
 
  SET(COLLAPSED,!b);
1933
 
 
1934
 
  if( open() && (_parent != 0) ) // root node doesn't count as a single open branch
1935
 
    {
1936
 
      if( ( tree->rdata.lastOpenBranch != this ) && tree->rdata.singleBranchOpen )
1937
 
        tree->rdata.lastOpenBranch->close();
1938
 
      tree->rdata.lastOpenBranch = this;
1939
 
    }
1940
 
 
1941
 
  tree->rdata.forceResize = true;
1942
 
  tree->rdata.visibilityChanged = true;
1943
 
  if( b )
1944
 
    do_callback( FLU_OPENED );
1945
 
  else
1946
 
    do_callback( FLU_CLOSED );
1947
 
}
1948
 
 
1949
 
void Flu_Tree_Browser :: Node :: active( bool b )
1950
 
{
1951
 
  if( CHECK(ACTIVE) == b  &&  tree->when() != FL_WHEN_NOT_CHANGED )
1952
 
    return;
1953
 
  SET( ACTIVE, b );
1954
 
  if( _widget )
1955
 
    {
1956
 
      if( b )
1957
 
        _widget->w->activate();
1958
 
      else
1959
 
        _widget->w->deactivate();
1960
 
    }
1961
 
  if( !CHECK(ACTIVE) )
1962
 
    {
1963
 
      if( tree->rdata.hilighted == this )
1964
 
        tree->set_hilighted( NULL );
1965
 
      select( false );
1966
 
      open( false );
1967
 
    }
1968
 
}
1969
 
 
1970
 
void Flu_Tree_Browser :: Node :: unselect_all( Node* except )
1971
 
{
1972
 
  if( this != except )
1973
 
    select( false );
1974
 
  for( int i = 0; i < _children.size(); i++ )
1975
 
    _children.child(i)->unselect_all( except );
1976
 
}
1977
 
 
1978
 
void Flu_Tree_Browser :: Node :: select_all()
1979
 
{
1980
 
  select( true );
1981
 
  for( int i = 0; i < _children.size(); i++ )
1982
 
    _children.child(i)->select_all();
1983
 
}
1984
 
 
1985
 
bool Flu_Tree_Browser :: Node :: isMoveValid( Node* &n1, int &where, Node* &n2 )
1986
 
{
1987
 
  // if n1 is NULL, then check it as if it were a node being moved from another tree
1988
 
 
1989
 
  if( n2 == NULL )
1990
 
    return false;
1991
 
 
1992
 
  // check the validity of the move:
1993
 
  // 1) the source and destination nodes can't be the same
1994
 
  // 2) you can't move before the root node
1995
 
  // 3) you can't move an unmovable node or move a branch node such that it would become a descendent of itself
1996
 
  // 4) if moving only within the same group, check that the parents are the same
1997
 
  // 5) if moving into a sorted tree, the destination node MUST be a branch
1998
 
  // 6) a move AFTER an OPEN branch is a move BEFORE its first child
1999
 
  // 7) you can't move a node into a non-droppable branch node
2000
 
 
2001
 
  if( n1 == n2 )
2002
 
    return false;
2003
 
 
2004
 
  if( where==MOVE_BEFORE && n2->is_root() )
2005
 
    return false;
2006
 
 
2007
 
  if( n1 )
2008
 
    {
2009
 
      if( !n1->movable() )
2010
 
        return false;
2011
 
      if( n1->is_branch() )
2012
 
        if( n1->is_descendent( n2 ) )
2013
 
          return false;
2014
 
    }
2015
 
 
2016
 
  bool sameGroup = n2->tree->move_only_same_group();
2017
 
  if( sameGroup && n1 )
2018
 
    {
2019
 
      if( n1->parent() != n2->parent() || where==MOVE_INSIDE )
2020
 
        return false;
2021
 
    }
2022
 
 
2023
 
  int iMode = n2->tree->insertion_mode();
2024
 
  if( iMode == FLU_INSERT_SORTED || iMode == FLU_INSERT_SORTED_REVERSE )
2025
 
    {
2026
 
      if( n2->is_branch() )
2027
 
        {
2028
 
          where = MOVE_INSIDE;
2029
 
          return true;
2030
 
        }
2031
 
      else
2032
 
        return false;
2033
 
    }
2034
 
 
2035
 
  if( where==MOVE_AFTER && n2->is_branch() && n2->open() )
2036
 
    {
2037
 
      // can't move inside a branch if within the same group, unless the first node is dragged 
2038
 
      // from outside the tree (in which case n1 is NULL)
2039
 
      if( sameGroup && n1 )
2040
 
        {
2041
 
          if( n2->_children.size() > 0 )
2042
 
            return false;
2043
 
        }
2044
 
      else if( n2->_children.size() > 0 )
2045
 
        {
2046
 
          where = MOVE_BEFORE;
2047
 
          n2 = n2->_children.child(0);
2048
 
        }
2049
 
      else
2050
 
        where = MOVE_INSIDE;
2051
 
    }
2052
 
 
2053
 
  if( where==MOVE_INSIDE )
2054
 
    {
2055
 
      if( !n2->droppable() )
2056
 
        return false;
2057
 
    }
2058
 
  else if( n2->parent() )
2059
 
    if( !n2->parent()->droppable() )
2060
 
      return false;
2061
 
 
2062
 
  return true;
2063
 
}
2064
 
 
2065
 
int Flu_Tree_Browser :: Node :: recurse( RData &rdata, int type, int event )
2066
 
{
2067
 
  int i;
2068
 
 
2069
 
  if( is_root() )
2070
 
    rdata.first = true;
2071
 
 
2072
 
  if( type == COUNT_SELECTED )
2073
 
    {
2074
 
      if( is_leaf() )
2075
 
        return (int)CHECK(SELECTED);
2076
 
      else
2077
 
        {
2078
 
          int total = (int)CHECK(SELECTED);
2079
 
          for( i = 0; i < _children.size(); i++ )
2080
 
            total += _children.child(i)->recurse( rdata, type, event );
2081
 
          return total;
2082
 
        }
2083
 
    }
2084
 
 
2085
 
  // see if this entry is even visible
2086
 
  if( rdata.y > rdata.browserY+rdata.browserH )
2087
 
    {
2088
 
      if( type == DRAW )
2089
 
        return 1;
2090
 
      else if( type == HANDLE )
2091
 
        return 0;
2092
 
    }
2093
 
 
2094
 
  int which = open();
2095
 
  bool skipEntry = ( is_root() && !rdata.showRoot ) || ( is_leaf() && !rdata.showLeaves ) || ( is_branch() && !rdata.showBranches );
2096
 
  bool skipCollapser = is_root() && rdata.showRoot && ( CHECK(ALWAYS_OPEN) || rdata.allBranchesAlwaysOpen );
2097
 
 
2098
 
  // find the size of the entry label
2099
 
  if( (type == MEASURE) || (type == MEASURE_THIS_OPEN) )
2100
 
    {
2101
 
      if( CHECK(SHOW_LABEL) )
2102
 
        {
2103
 
          int W = 0, H;
2104
 
          fl_font( textFont, textSize );
2105
 
          fl_measure( text.c_str(), W, H );
2106
 
          W += 4; H += 4;  // hack - it looks better
2107
 
          textW = W;
2108
 
          textH = H;
2109
 
        }
2110
 
      else
2111
 
        {
2112
 
          textW = textH = 0;
2113
 
        }
2114
 
 
2115
 
      // remember vertically where this node is w.r.t the browser
2116
 
      currentY = rdata.y;
2117
 
 
2118
 
      currentH = textH;
2119
 
 
2120
 
      // find the total size of the entry, depending on if there's a widget
2121
 
      if( _widget )
2122
 
        currentH = MAX( _widget->w->h(), currentH );
2123
 
 
2124
 
      // find the total height of this entry by taking the max height of the entry and icons
2125
 
      if( is_leaf() )
2126
 
        {
2127
 
          if( lIcon )
2128
 
            currentH = MAX( currentH, lIcon->h() );
2129
 
        }
2130
 
      else
2131
 
        {
2132
 
          currentH = MAX( currentH, cIcon[which]->h() );
2133
 
          if( bIcon[which] )
2134
 
            currentH = MAX( currentH, bIcon[which]->h() );
2135
 
        }
2136
 
    }
2137
 
 
2138
 
  bool skipAhead = (rdata.y + currentH) < rdata.browserY;
2139
 
 
2140
 
  // process the entry
2141
 
  switch( type )
2142
 
    {
2143
 
    case DRAW:
2144
 
      {
2145
 
        if( skipEntry || skipAhead ) break;
2146
 
 
2147
 
        draw( rdata, false );
2148
 
 
2149
 
        // draw any vertical connectors connecting our parents, grandparents, etc.,
2150
 
        if( rdata.showBranches )
2151
 
          {
2152
 
            int d = depth()-1;
2153
 
            for( i = 0; i < rdata.branchConnectors.size(); i++ )
2154
 
              {
2155
 
                if( i != d )
2156
 
                  {
2157
 
                    fl_color( rdata.lineColor );
2158
 
                    fl_line_style( rdata.lineStyle, rdata.lineWidth );
2159
 
                    fl_line( rdata.branchConnectors[i], rdata.y, rdata.branchConnectors[i], rdata.y+currentH );
2160
 
                    fl_line_style( 0 );
2161
 
                  }
2162
 
              }
2163
 
          }
2164
 
 
2165
 
        rdata.shadedIndex = 1 - rdata.shadedIndex;  // toggle the even/odd entry for shading
2166
 
      }
2167
 
      break;
2168
 
 
2169
 
    case MEASURE:
2170
 
      if( is_leaf() )
2171
 
        CLEAR( SOME_VISIBLE_CHILDREN );
2172
 
      else
2173
 
        {
2174
 
          // find out whether the branch has any children that could be visible
2175
 
          bool someVisibleChildren = rdata.showLeaves && ( _children.size() > 0 );
2176
 
          for( i = 0; i < _children.size(); i++ )
2177
 
            {
2178
 
              if( _children.child(i)->is_branch() )
2179
 
                {
2180
 
                  someVisibleChildren = true;
2181
 
                  break;
2182
 
                }
2183
 
            }
2184
 
          SET( SOME_VISIBLE_CHILDREN, someVisibleChildren );
2185
 
        }
2186
 
 
2187
 
    case MEASURE_THIS_OPEN:
2188
 
      if( skipEntry ) break;
2189
 
      draw( rdata, true );
2190
 
      break;
2191
 
 
2192
 
    case HANDLE:
2193
 
      {
2194
 
        if( skipEntry || skipAhead || !CHECK(ACTIVE) ) break;
2195
 
 
2196
 
        if( event != FL_DRAG && event != FL_NO_EVENT )
2197
 
          rdata.justOpenedClosed = false;
2198
 
 
2199
 
        // if we are trying to select all entries between 2 widgets due to a shift-select...
2200
 
        if( rdata.shiftSelect )
2201
 
          {
2202
 
            if( (rdata.hilighted == this) || (rdata.grabbed == this) )
2203
 
              {
2204
 
                if( !rdata.shiftSelectAll )
2205
 
                  {
2206
 
                    rdata.shiftSelectAll = true;
2207
 
                    select( true );
2208
 
                    if( is_branch() && rdata.openOnSelect )
2209
 
                      {
2210
 
                        open( true );
2211
 
                      }
2212
 
                  }
2213
 
                else
2214
 
                  {
2215
 
                    rdata.shiftSelect = false;
2216
 
                    rdata.shiftSelectAll = false;
2217
 
                    rdata.grabbed = 0;
2218
 
                    select( true );
2219
 
                    if( is_branch() && rdata.openOnSelect )
2220
 
                      {
2221
 
                        open( true );
2222
 
                      }
2223
 
                  }
2224
 
              }
2225
 
            else if( rdata.shiftSelectAll )
2226
 
              {
2227
 
                select( true );
2228
 
                if( is_branch() && rdata.openOnSelect )
2229
 
                  {
2230
 
                    open( true );
2231
 
                  }
2232
 
              }
2233
 
            break;
2234
 
          }
2235
 
 
2236
 
        // check for the keyboard event
2237
 
        if( event == FL_KEYDOWN )
2238
 
          {
2239
 
            // check for the spacebar selecting this entry
2240
 
            if( Fl::event_key() == ' ' && rdata.hilighted == this )
2241
 
              {
2242
 
                if( Fl::event_state(FL_CTRL) )
2243
 
                  select( !CHECK(SELECTED) );
2244
 
                else
2245
 
                  {
2246
 
                    rdata.root->unselect_all( this );
2247
 
                    select( true );
2248
 
                  }
2249
 
                if( is_branch() && rdata.openOnSelect )
2250
 
                  {
2251
 
                    open( true );
2252
 
                  }
2253
 
                return 1;               
2254
 
              }
2255
 
 
2256
 
            // check for the enter key opening/closing this entry
2257
 
            else if( (Fl::event_key() == FL_Enter) && (rdata.hilighted == this) )
2258
 
              {
2259
 
                open( !open() );
2260
 
                return 1;
2261
 
              }
2262
 
 
2263
 
            // check for the left/right cursor keys opening/closing this entry
2264
 
            else if( (Fl::event_key() == FL_Left) && (rdata.hilighted == this) )
2265
 
              {
2266
 
                open( false );
2267
 
                return 1;
2268
 
              }
2269
 
            else if( (Fl::event_key() == FL_Right) && (rdata.hilighted == this) )
2270
 
              {
2271
 
                open( true );
2272
 
                return 1;
2273
 
              }
2274
 
          }
2275
 
 
2276
 
        // check for the "up" cursor key moving the hilighted entry
2277
 
        if( rdata.delta == -1 && rdata.hilighted == this && rdata.previous != NULL )
2278
 
          {
2279
 
            tree->set_hilighted( rdata.previous );
2280
 
            rdata.delta = 0;
2281
 
            return 1;
2282
 
          }
2283
 
 
2284
 
        // check for the "down" cursor key moving the hilighted entry
2285
 
        if( rdata.delta == 1 && rdata.hilighted == rdata.previous )
2286
 
          {
2287
 
            tree->set_hilighted( this );
2288
 
            rdata.delta = 0;
2289
 
            return 1;
2290
 
          }
2291
 
 
2292
 
        rdata.previous = this;
2293
 
 
2294
 
        // the event is not ours to use
2295
 
        //if( _widget && !rdata.dragging )
2296
 
        //if( Fl::event_inside( _widget->w ) )
2297
 
        //  return 2;
2298
 
 
2299
 
        bool inExpander = false;
2300
 
        if( is_branch() )
2301
 
          {
2302
 
            int which = open();
2303
 
            if( _parent==0 )
2304
 
              inExpander = Fl::event_inside( rdata.x, rdata.y+(currentH>>1)-(cIcon[which]->h()>>1),
2305
 
                                             cIcon[which]->w(), cIcon[which]->h() );
2306
 
            else
2307
 
              inExpander = Fl::event_inside( rdata.x+(rdata.branchIconW>>1)-(cIcon[which]->w()>>1),
2308
 
                                             rdata.y+(currentH>>1)-(cIcon[which]->h()>>1),
2309
 
                                             cIcon[which]->w(), cIcon[which]->h() );
2310
 
          }
2311
 
 
2312
 
        if( event == FL_PUSH )
2313
 
          {     
2314
 
            // check for expand/collapse
2315
 
            if( Fl::event_button() == FL_LEFT_MOUSE && inExpander )
2316
 
              {
2317
 
                if( rdata.openWOChildren || CHECK(SOME_VISIBLE_CHILDREN) )
2318
 
                  {
2319
 
                    open( !open() );
2320
 
                    rdata.dragging = false;
2321
 
                    rdata.dragNode = 0;
2322
 
                    return 1;
2323
 
                  }
2324
 
              }
2325
 
          }
2326
 
 
2327
 
        if( event == FL_DRAG && rdata.justOpenedClosed )
2328
 
          return 0;
2329
 
 
2330
 
        // if no selections, return
2331
 
        if( rdata.selectionMode == FLU_NO_SELECT )
2332
 
          break;
2333
 
 
2334
 
        // if the event is not inside us, return
2335
 
        if( !Fl::event_inside( rdata.browserX, rdata.y, rdata.browserW, currentH ) )
2336
 
          break;
2337
 
 
2338
 
        // single selection
2339
 
        if( rdata.selectionMode == FLU_SINGLE_SELECT )
2340
 
          {
2341
 
            if( event == FL_MOVE && rdata.selectUnderMouse )
2342
 
              {
2343
 
                //select_only();
2344
 
                rdata.root->unselect_all( this );
2345
 
                SET(SELECTED,true);
2346
 
                tree->redraw();
2347
 
              }
2348
 
            else if( event == FL_PUSH )
2349
 
              {
2350
 
                //rdata.dragging = true;
2351
 
                rdata.grabbed = this;
2352
 
 
2353
 
                if( rdata.selectUnderMouse )
2354
 
                  rdata.root->unselect_all();
2355
 
                else
2356
 
                  rdata.root->unselect_all( this );
2357
 
                tree->set_hilighted( this );
2358
 
                if( Fl::event_state(FL_CTRL) )
2359
 
                  select( !CHECK(SELECTED) );
2360
 
                else
2361
 
                  select( true );
2362
 
 
2363
 
                if( is_leaf() )
2364
 
                  {
2365
 
                    if( Fl::event_clicks() > 0 )
2366
 
                      {
2367
 
                        Fl::event_clicks(0);
2368
 
                        do_callback( FLU_DOUBLE_CLICK );
2369
 
                      }
2370
 
                  }
2371
 
                else
2372
 
                  {
2373
 
                    if( Fl::event_clicks() > 0 )
2374
 
                      {
2375
 
                        Fl::event_clicks(0);
2376
 
                        if( rdata.doubleClickToOpen )
2377
 
                          {
2378
 
                            if( rdata.openWOChildren || CHECK(SOME_VISIBLE_CHILDREN) )
2379
 
                              open( !open() );
2380
 
                          }
2381
 
                        else
2382
 
                          do_callback( FLU_DOUBLE_CLICK );
2383
 
                      }
2384
 
                    else if( rdata.openOnSelect )
2385
 
                      {
2386
 
                        open( true );
2387
 
                      }
2388
 
                  }
2389
 
                Fl::focus(tree);
2390
 
                return 1;
2391
 
              }
2392
 
            else if( event == FL_DRAG )
2393
 
              {
2394
 
                if( rdata.selectionDragMode == FLU_DRAG_IGNORE )
2395
 
                  return 1;
2396
 
                rdata.dragging = true;
2397
 
                //if( ( rdata.selectionDragMode == FLU_DRAG_IGNORE || rdata.selectionDragMode == FLU_DRAG_TO_MOVE) && ( tree->insertion_mode() == FLU_INSERT_FRONT || tree->insertion_mode() == FLU_INSERT_BACK ) )
2398
 
                //return 1;
2399
 
                rdata.root->unselect_all( this );
2400
 
                tree->set_hilighted( this );
2401
 
                select( true );
2402
 
                return 1;
2403
 
              }
2404
 
            else if( event == FL_RELEASE && tree->when() == FL_WHEN_RELEASE && selected() && !inExpander )
2405
 
              {
2406
 
                do_callback( FLU_SELECTED );
2407
 
                return 1;
2408
 
              }
2409
 
          }
2410
 
 
2411
 
        // multiple selection
2412
 
        else if( rdata.selectionMode == FLU_MULTI_SELECT )
2413
 
          {
2414
 
            if( event == FL_PUSH )
2415
 
              {
2416
 
                //rdata.dragging = true;
2417
 
                rdata.grabbed = this;
2418
 
 
2419
 
                if( Fl::event_state(FL_CTRL) )
2420
 
                  {
2421
 
                    select( !CHECK(SELECTED) );
2422
 
                    tree->set_hilighted( this );
2423
 
                  }
2424
 
                else if( Fl::event_state(FL_SHIFT) )
2425
 
                  {
2426
 
                    // select everything from the last selected entry to this one
2427
 
                    if( rdata.hilighted == this )
2428
 
                      {
2429
 
                        select( true );
2430
 
                        if( is_branch() )
2431
 
                          {
2432
 
                            if( Fl::event_clicks() > 0 )
2433
 
                              {
2434
 
                                Fl::event_clicks(0);
2435
 
                                if( rdata.doubleClickToOpen )
2436
 
                                  {
2437
 
                                    if( rdata.openWOChildren || CHECK(SOME_VISIBLE_CHILDREN) )
2438
 
                                      open( !open() );
2439
 
                                  }
2440
 
                                else
2441
 
                                  do_callback( FLU_DOUBLE_CLICK );
2442
 
                              }
2443
 
                            else if( rdata.openOnSelect )
2444
 
                              {
2445
 
                                open( !open() );
2446
 
                              }
2447
 
                          }
2448
 
                      }
2449
 
                    else
2450
 
                      {
2451
 
                        rdata.shiftSelectAll = false;
2452
 
                        rdata.shiftSelect = true;
2453
 
                        rdata.grabbed = this;
2454
 
                        rdata.root->recurse( rdata, HANDLE, 0 );
2455
 
                        tree->set_hilighted( this );
2456
 
                      }
2457
 
                  }
2458
 
                else
2459
 
                  {
2460
 
                    rdata.root->unselect_all( this );
2461
 
                    select( true );
2462
 
                    if( is_leaf() )
2463
 
                      {
2464
 
                        if( Fl::event_clicks() > 0 )
2465
 
                          {
2466
 
                            Fl::event_clicks(0);
2467
 
                            do_callback( FLU_DOUBLE_CLICK );
2468
 
                          }
2469
 
                      }
2470
 
                    else
2471
 
                      {
2472
 
                        if( Fl::event_clicks() > 0 )
2473
 
                          {
2474
 
                            Fl::event_clicks(0);
2475
 
                            if( rdata.doubleClickToOpen )
2476
 
                              {
2477
 
                                if( rdata.openWOChildren || CHECK(SOME_VISIBLE_CHILDREN) )
2478
 
                                  open( !open() );
2479
 
                              }
2480
 
                            else
2481
 
                              do_callback( FLU_DOUBLE_CLICK );
2482
 
                          }
2483
 
                        else if( rdata.openOnSelect )
2484
 
                          {
2485
 
                            open( true );
2486
 
                          }
2487
 
                      }
2488
 
                    tree->set_hilighted( this );
2489
 
                  }
2490
 
                Fl::focus(tree);
2491
 
                return 1;
2492
 
              }
2493
 
            else if( event == FL_DRAG )
2494
 
              {
2495
 
                if( rdata.selectionDragMode == FLU_DRAG_IGNORE )
2496
 
                  return 1;
2497
 
                rdata.dragging = true;
2498
 
                //if( ( rdata.selectionDragMode == FLU_DRAG_IGNORE || rdata.selectionDragMode == FLU_DRAG_TO_MOVE) && ( tree->insertion_mode() == FLU_INSERT_FRONT || tree->insertion_mode() == FLU_INSERT_BACK ) )
2499
 
                //return 1;
2500
 
                select( true );
2501
 
                tree->set_hilighted( this );
2502
 
                return 1;
2503
 
              }
2504
 
            else if( event == FL_RELEASE && tree->when() == FL_WHEN_RELEASE && selected() && !inExpander )
2505
 
              {
2506
 
                do_callback( FLU_SELECTED );
2507
 
                return 1;
2508
 
              }
2509
 
          }
2510
 
      }
2511
 
      break;
2512
 
    }
2513
 
 
2514
 
  // advance the counters vertically to the next entry
2515
 
  if( !skipEntry )
2516
 
    rdata.y += currentH + rdata.vGap;
2517
 
 
2518
 
  if( !is_root() && rdata.first && !skipEntry )
2519
 
    rdata.first = false;
2520
 
 
2521
 
  // if we're a leaf, no need to process further
2522
 
  if( is_leaf() )
2523
 
    return 0;
2524
 
 
2525
 
  // should we bail out already if we're done processing?
2526
 
  if( closed() && !skipEntry && !skipCollapser && ( type != MEASURE_THIS_OPEN ) )
2527
 
    return 0;
2528
 
 
2529
 
  if( !CHECK(SOME_VISIBLE_CHILDREN) )
2530
 
    return 0;
2531
 
 
2532
 
  // advance the counters horizontally to the next entry
2533
 
  if( rdata.showBranches )
2534
 
    {
2535
 
      if( !skipEntry && !skipCollapser )
2536
 
        rdata.x += cIcon[which]->w() + rdata.hGap;
2537
 
    }
2538
 
  rdata.totalW = MAX( rdata.totalW, rdata.x );
2539
 
 
2540
 
  // the branchIconW is the width of the branch icon at this level
2541
 
  // it is used to center all children icons under the branch icon
2542
 
  int lastBranchIconW = rdata.branchIconW;
2543
 
  if( rdata.showBranches )
2544
 
    {
2545
 
      if( bIcon[which] )
2546
 
        rdata.branchIconW = bIcon[which]->w();
2547
 
      else
2548
 
        rdata.branchIconW = cIcon[which]->w();
2549
 
    }
2550
 
  else
2551
 
    rdata.branchIconW = 0;
2552
 
 
2553
 
  // process all children
2554
 
  int val;
2555
 
  int tempW = rdata.branchIconW >> 1;
2556
 
  for( i = 0; i < _children.size(); i++ )
2557
 
    {
2558
 
      // prepare the recursive data structure for the next level
2559
 
      if( i == 0 )
2560
 
        rdata.first = true;
2561
 
      rdata.last = (i == _children.size()-1 );
2562
 
 
2563
 
      // if child "i" is not the last child,
2564
 
      // then there is a long connector that needs drawn between this node and the last child.
2565
 
      // push the horizontal position of the connector onto the stack
2566
 
      if( (type == DRAW) && rdata.showConnectors && ( i < _children.size()-1 ) )
2567
 
        {
2568
 
          rdata.branchConnectors.push_back( rdata.x+tempW );
2569
 
          val = _children.child(i)->recurse( rdata, type, event );
2570
 
          rdata.branchConnectors.pop_back();
2571
 
        }
2572
 
      else
2573
 
        val = _children.child(i)->recurse( rdata, type, event );
2574
 
 
2575
 
      if( val )
2576
 
        return val;
2577
 
    }
2578
 
 
2579
 
  // set the branch icon width back to what it was before we changed it
2580
 
  rdata.branchIconW = lastBranchIconW;
2581
 
 
2582
 
  // move back horizontally from the last entry
2583
 
  if( rdata.showBranches )
2584
 
    {
2585
 
      if( !skipEntry && !skipCollapser )
2586
 
        rdata.x -= cIcon[which]->w() + rdata.hGap;
2587
 
    }
2588
 
 
2589
 
  return 0;
2590
 
}
2591
 
 
2592
 
void Flu_Tree_Browser :: print()
2593
 
{
2594
 
  root.print();
2595
 
}
2596
 
 
2597
 
void Flu_Tree_Browser :: clear()
2598
 
{
2599
 
  root.clear();
2600
 
  root.text = "";
2601
 
 
2602
 
  while( _box->children() )
2603
 
    _box->remove( *_box->child(0) );
2604
 
 
2605
 
  rdata.cbNode = NULL;
2606
 
  rdata.cbReason = FLU_NOTHING;
2607
 
  rdata.hilighted = NULL;
2608
 
  rdata.dragging = false;
2609
 
  rdata.forceResize = true;
2610
 
  rdata.lastOpenBranch = NULL;
2611
 
  rdata.shiftSelect = false;
2612
 
  rdata.shiftSelectAll = false;
2613
 
  rdata.nextId = 1;
2614
 
  rdata.searchIndex = 1;
2615
 
}
2616
 
 
2617
 
Flu_Tree_Browser::Node* Flu_Tree_Browser :: set_root( const char *label, Fl_Widget *w, bool showLabel )
2618
 
{
2619
 
  if( label == 0 )
2620
 
    label = "";
2621
 
  root.text = label;
2622
 
  root.widget( w );
2623
 
  root.SET(Node::SHOW_LABEL,showLabel);
2624
 
  root.cIcon[0] = rdata.collapseIcons[0];
2625
 
  root.cIcon[1] = rdata.collapseIcons[1];
2626
 
  root.bIcon[0] = rdata.branchIcons[0];
2627
 
  root.bIcon[1] = rdata.branchIcons[1];
2628
 
  root.textColor = rdata.defBranchColor;
2629
 
  root.textFont = rdata.defBranchFont;
2630
 
  root.textSize = rdata.defBranchSize;
2631
 
  rdata.forceResize = true;
2632
 
 
2633
 
  return &root;
2634
 
}
2635
 
 
2636
 
Flu_Tree_Browser::Node* Flu_Tree_Browser :: add( const char* fullpath, Fl_Widget *w, bool showLabel )
2637
 
{
2638
 
  return( root.modify( fullpath, Node::ADD, rdata, w, showLabel ) );
2639
 
}
2640
 
 
2641
 
Flu_Tree_Browser::Node* Flu_Tree_Browser :: add( const char* path, const char* text, Fl_Widget *w, bool showLabel )
2642
 
{
2643
 
  // if the path does not end in '/', add it
2644
 
  std::string s = path;
2645
 
  if( path[strlen(path)-1] != '/' )
2646
 
    s += "/";
2647
 
  s += text;
2648
 
 
2649
 
  return add( s.c_str(), w, showLabel );
2650
 
}
2651
 
 
2652
 
Flu_Tree_Browser::Node* Flu_Tree_Browser :: add_branch( const char* fullpath, Fl_Widget *w, bool showLabel )
2653
 
{
2654
 
  std::string p( fullpath );
2655
 
  if( p.size() && p[p.size()-1] != '/' && p[p.size()-1] != '\\' ) p += "/";
2656
 
  return add( p.c_str(), w, showLabel );
2657
 
}
2658
 
 
2659
 
Flu_Tree_Browser::Node* Flu_Tree_Browser :: add_branch( const char* path, const char* name, Fl_Widget *w, bool showLabel )
2660
 
{
2661
 
  std::string p( name );
2662
 
  if( p.size() && p[p.size()-1] != '/' && p[p.size()-1] != '\\' ) p += "/";
2663
 
  return add( path, p.c_str(), w, showLabel );
2664
 
}
2665
 
 
2666
 
Flu_Tree_Browser::Node* Flu_Tree_Browser :: add_leaf( const char* fullpath, Fl_Widget *w, bool showLabel )
2667
 
{
2668
 
  std::string p( fullpath );
2669
 
  if( p.size() && ( p[p.size()-1] == '/' || p[p.size()-1] == '\\' ) ) p[p.size()-1] = '\0';
2670
 
  return add( p.c_str(), w, showLabel );
2671
 
}
2672
 
 
2673
 
Flu_Tree_Browser::Node* Flu_Tree_Browser :: add_leaf( const char* path, const char* name, Fl_Widget *w, bool showLabel )
2674
 
{
2675
 
  std::string p( name );
2676
 
  if( p.size() && ( p[p.size()-1] == '/' || p[p.size()-1] == '\\' ) ) p[p.size()-1] = '\0';
2677
 
  return add( path, p.c_str(), w, showLabel );
2678
 
}
2679
 
 
2680
 
size_t Flu_Tree_Browser :: remove( const char *fullpath )
2681
 
{
2682
 
  return( (size_t)root.modify( fullpath, Node::REMOVE, rdata ) );
2683
 
}
2684
 
 
2685
 
size_t Flu_Tree_Browser :: remove( const char *path, const char *text )
2686
 
{
2687
 
  // if the path does not end in '/', add it
2688
 
  std::string s = path;
2689
 
  if( path[strlen(path)-1] != '/' )
2690
 
    s += "/";
2691
 
  s += text;
2692
 
  return remove( s.c_str() );
2693
 
}
2694
 
 
2695
 
size_t Flu_Tree_Browser :: remove( size_t id )
2696
 
{
2697
 
  return root.remove( id );
2698
 
}
2699
 
 
2700
 
size_t Flu_Tree_Browser :: Node :: remove( size_t id )
2701
 
{
2702
 
  if( id == 0 )
2703
 
    return 0;
2704
 
 
2705
 
  for( int i = 0; i < _children.size(); i++ )
2706
 
    {
2707
 
      Node *n = _children.child(i);
2708
 
      if( n->id() == id )
2709
 
        {
2710
 
          _children.erase( i );
2711
 
          tree->rdata.forceResize = true;
2712
 
          //if( tree->rdata.cbNode == n )
2713
 
          //tree->rdata.cbNode = NULL;
2714
 
          delete n;
2715
 
          if( tree->rdata.autoBranches )
2716
 
            initType();
2717
 
          tree->redraw();
2718
 
          return id;
2719
 
        }
2720
 
      else if( n->remove( id ) )
2721
 
        return id;
2722
 
    }
2723
 
 
2724
 
  return 0;
2725
 
}
2726
 
 
2727
 
size_t Flu_Tree_Browser :: remove( Fl_Widget *w )
2728
 
{
2729
 
  return root.remove( w );
2730
 
}
2731
 
 
2732
 
size_t Flu_Tree_Browser :: Node :: remove( Fl_Widget *w )
2733
 
{
2734
 
  if( !w )
2735
 
    return 0;
2736
 
  for( int i = 0; i < _children.size(); i++ )
2737
 
    {
2738
 
      Node *n = _children.child(i);
2739
 
      if( n->_widget )
2740
 
        {
2741
 
          if( n->_widget->w == w )
2742
 
            {
2743
 
              int id = n->id();
2744
 
              _children.erase( i );
2745
 
              tree->rdata.forceResize = true;
2746
 
              //if( tree->rdata.cbNode == n )
2747
 
              //tree->rdata.cbNode = NULL;
2748
 
              delete n;
2749
 
              if( tree->rdata.autoBranches )
2750
 
                initType();
2751
 
              tree->redraw();
2752
 
              return id;
2753
 
            }
2754
 
        }
2755
 
 
2756
 
      int id = n->remove( w );
2757
 
      if( id )
2758
 
        return id;
2759
 
    }
2760
 
 
2761
 
  return 0;
2762
 
}
2763
 
 
2764
 
int Flu_Tree_Browser :: find_number( const char *fullpath )
2765
 
{
2766
 
  rdata.counter = 0;
2767
 
  root.modify( fullpath, Node::FIND_NUMBER, rdata );
2768
 
  return rdata.counter;
2769
 
}
2770
 
 
2771
 
int Flu_Tree_Browser :: find_number( const char *path, const char *text )
2772
 
{
2773
 
  // if the path does not end in '/', add it
2774
 
  std::string s = path;
2775
 
  if( path[strlen(path)-1] != '/' )
2776
 
    s += "/";
2777
 
  s += text;
2778
 
  return find_number( s.c_str() );
2779
 
}
2780
 
 
2781
 
Flu_Tree_Browser::Node* Flu_Tree_Browser :: find_next( const char *fullpath, Node* startNode )
2782
 
{
2783
 
  // degenerate case: root node
2784
 
  if( strcmp( fullpath, "/" ) == 0 )
2785
 
    return &root;
2786
 
  rdata.previous = startNode;
2787
 
  return( root.modify( fullpath, Node::FIND, rdata ) );
2788
 
}
2789
 
 
2790
 
Flu_Tree_Browser::Node* Flu_Tree_Browser :: find_next( const char *path, const char *text )
2791
 
{
2792
 
  // if the path does not end in '/', add it
2793
 
  std::string s = path;
2794
 
  if( path[strlen(path)-1] != '/' )
2795
 
    s += "/";
2796
 
  s += text;
2797
 
  return find_next( s.c_str() );
2798
 
}
2799
 
 
2800
 
Flu_Tree_Browser::Node* Flu_Tree_Browser :: find( const char *path, const char *text )
2801
 
{
2802
 
  // if the path does not end in '/', add it
2803
 
  std::string s = path;
2804
 
  if( path[strlen(path)-1] != '/' )
2805
 
    s += "/";
2806
 
  s += text;
2807
 
  return find( s.c_str() );
2808
 
}
2809
 
 
2810
 
Flu_Tree_Browser::Node* Flu_Tree_Browser :: find( size_t id )
2811
 
{
2812
 
  return root.find( id );
2813
 
}
2814
 
 
2815
 
Flu_Tree_Browser::Node* Flu_Tree_Browser :: Node :: find( size_t id )
2816
 
{
2817
 
  if( id == 0 )
2818
 
    return NULL;
2819
 
 
2820
 
  if( _id == id )
2821
 
    return this;
2822
 
 
2823
 
  for( int i = 0; i < _children.size(); i++ )
2824
 
    {
2825
 
      Node *n = _children.child(i)->find( id );
2826
 
      if( n )
2827
 
        return n;
2828
 
    }
2829
 
 
2830
 
  return NULL;
2831
 
}
2832
 
 
2833
 
Flu_Tree_Browser::Node* Flu_Tree_Browser :: find( Fl_Widget *w )
2834
 
{
2835
 
  return root.find( w );
2836
 
}
2837
 
 
2838
 
Flu_Tree_Browser::Node* Flu_Tree_Browser :: Node :: find( Fl_Widget *w )
2839
 
{
2840
 
  if( _widget )
2841
 
    if( _widget->w == w )
2842
 
      return this;
2843
 
 
2844
 
  for( int i = 0; i < _children.size(); i++ )
2845
 
    {
2846
 
      Node *n = _children.child(i)->find( w );
2847
 
      if( n )
2848
 
        return n;
2849
 
    }
2850
 
 
2851
 
  return NULL;
2852
 
}
2853
 
 
2854
 
 
2855
 
bool Flu_Tree_Browser :: Node :: findPath( size_t id, RData &rdata )
2856
 
{
2857
 
  if( _id == id )
2858
 
    {
2859
 
      if( is_leaf() )
2860
 
        rdata.path += text;
2861
 
      else
2862
 
        {
2863
 
          rdata.path += text;
2864
 
          rdata.path += "/";
2865
 
        }
2866
 
      return true;
2867
 
    }
2868
 
 
2869
 
  if( is_leaf() )
2870
 
    return false;
2871
 
 
2872
 
  std::string oldPath = rdata.path;
2873
 
  if( _parent != 0 )
2874
 
    {
2875
 
      rdata.path += text;
2876
 
      rdata.path += "/";
2877
 
    }
2878
 
 
2879
 
  for( int i = 0; i < _children.size(); i++ )
2880
 
    {
2881
 
      if( _children.child(i)->findPath( id, rdata ) )
2882
 
        {
2883
 
          return true;
2884
 
        }
2885
 
    }
2886
 
 
2887
 
  rdata.path = oldPath;
2888
 
  return false;
2889
 
}
2890
 
 
2891
 
bool Flu_Tree_Browser :: Node :: findPath( Fl_Widget *w, RData &rdata )
2892
 
{
2893
 
  if( _widget )
2894
 
    if( _widget->w == w )
2895
 
      {
2896
 
        if( is_leaf() )
2897
 
          rdata.path += text;
2898
 
        else
2899
 
          {
2900
 
            rdata.path += text;
2901
 
            rdata.path += "/";
2902
 
          }
2903
 
        return true;
2904
 
      }
2905
 
 
2906
 
  if( is_leaf() )
2907
 
    return false;
2908
 
 
2909
 
  std::string oldPath = rdata.path;
2910
 
  if( _parent != 0 )
2911
 
    {
2912
 
      rdata.path += text;
2913
 
      rdata.path += "/";
2914
 
    }
2915
 
 
2916
 
  for( int i = 0; i < _children.size(); i++ )
2917
 
    {
2918
 
      if( _children.child(i)->findPath( w, rdata ) )
2919
 
        {
2920
 
          return true;
2921
 
        }
2922
 
    }
2923
 
 
2924
 
  rdata.path = oldPath;
2925
 
 
2926
 
  return false;
2927
 
}
2928
 
 
2929
 
const char* Flu_Tree_Browser :: find_path( size_t id )
2930
 
{
2931
 
  // degenerate case: the root is always id==0
2932
 
  if( id == 0 )
2933
 
    return "/";
2934
 
  rdata.path = "/";
2935
 
  if( root.findPath( id, rdata ) )
2936
 
    return rdata.path.c_str();
2937
 
  else
2938
 
    return "";
2939
 
}
2940
 
 
2941
 
const char* Flu_Tree_Browser :: find_path( Fl_Widget *w )
2942
 
{
2943
 
  rdata.path = "/";
2944
 
  if( root.findPath( w, rdata ) )
2945
 
    return rdata.path.c_str();
2946
 
  else
2947
 
    return "";
2948
 
}
2949
 
 
2950
 
static std::string remove_escape_chars( const char *str )
2951
 
{
2952
 
  // remove any escape characters
2953
 
  std::string text(str);
2954
 
  int tIndex = 0;
2955
 
  for( int pIndex = 0; pIndex < (int)strlen( str ); pIndex++ )
2956
 
    {
2957
 
      if( str[pIndex] != '\\' )
2958
 
        text[tIndex++] = str[pIndex];
2959
 
    }
2960
 
  text.resize(tIndex);
2961
 
  return text;
2962
 
}
2963
 
 
2964
 
void Flu_Tree_Browser :: Node :: do_callback( int reason )
2965
 
{
2966
 
  //if( tree->rdata.when == FL_WHEN_NEVER )
2967
 
  if( tree->when() == FL_WHEN_NEVER )
2968
 
    return;
2969
 
  //if( tree->rdata.cb )
2970
 
    {
2971
 
      tree->rdata.cbReason = reason;
2972
 
      tree->rdata.cbNode = this;
2973
 
      //tree->rdata.cb( tree, tree->rdata.cbd );
2974
 
      ((Fl_Widget*)tree)->do_callback();
2975
 
    }
2976
 
}
2977
 
 
2978
 
unsigned short Flu_Tree_Browser :: Node :: depth() const
2979
 
{
2980
 
  int d = 0;
2981
 
  Node *p = _parent;
2982
 
  while( p )
2983
 
    {
2984
 
      d++;
2985
 
      p = p->_parent;
2986
 
    }
2987
 
  return d;
2988
 
}
2989
 
 
2990
 
Flu_Tree_Browser::Node* Flu_Tree_Browser :: Node :: add_branch( const char* fullpath, Fl_Widget *w, bool showLabel )
2991
 
{
2992
 
  std::string p( fullpath );
2993
 
  if( p.size() && p[p.size()-1] != '/' && p[p.size()-1] != '\\' ) p += "/";
2994
 
  return add( p.c_str(), w, showLabel );
2995
 
}
2996
 
 
2997
 
Flu_Tree_Browser::Node* Flu_Tree_Browser :: Node :: add_leaf( const char* fullpath, Fl_Widget *w, bool showLabel )
2998
 
{
2999
 
  std::string p( fullpath );
3000
 
  if( p.size() && ( p[p.size()-1] == '/' || p[p.size()-1] == '\\' ) ) p[p.size()-1] = '\0';
3001
 
  return add( p.c_str(), w, showLabel );
3002
 
}
3003
 
 
3004
 
Flu_Tree_Browser::Node* Flu_Tree_Browser :: Node :: add( const char* path, const char* name, Fl_Widget *w, bool showLabel )
3005
 
{
3006
 
  std::string p( path );
3007
 
  if( p.size() && p[p.size()-1] != '/' && p[p.size()-1] != '\\' ) p += "/";
3008
 
  p += name;
3009
 
  return add( p.c_str(), w, showLabel );
3010
 
}
3011
 
 
3012
 
Flu_Tree_Browser::Node* Flu_Tree_Browser :: Node :: add_branch( const char* path, const char* name, Fl_Widget *w, bool showLabel )
3013
 
{
3014
 
  std::string p( path );
3015
 
  if( p.size() && p[p.size()-1] != '/' && p[p.size()-1] != '\\' ) p += "/";
3016
 
  p += name;
3017
 
  return add_branch( p.c_str(), w, showLabel );
3018
 
}
3019
 
 
3020
 
Flu_Tree_Browser::Node* Flu_Tree_Browser :: Node :: add_leaf( const char* path, const char* name, Fl_Widget *w, bool showLabel )
3021
 
{
3022
 
  std::string p( path );
3023
 
  if( p.size() && p[p.size()-1] != '/' && p[p.size()-1] != '\\' ) p += "/";
3024
 
  p += name;
3025
 
  return add_leaf( p.c_str(), w, showLabel );
3026
 
}
3027
 
 
3028
 
Flu_Tree_Browser::Node* Flu_Tree_Browser :: Node :: modify( const char* path, int what, RData &rdata, Fl_Widget *w, bool showLabel )
3029
 
{
3030
 
  // find the selected entry at rdata.searchIndex among all selected entries
3031
 
  if( what == GET_SELECTED )
3032
 
    {
3033
 
      if( CHECK(SELECTED) )
3034
 
        {
3035
 
          rdata.counter++;
3036
 
          if( rdata.counter == rdata.searchIndex )
3037
 
            return this;
3038
 
        }
3039
 
      for( int i = 0; i < _children.size(); i++ )
3040
 
        {
3041
 
          Node *n = _children.child(i)->modify( path, what, rdata, w );
3042
 
          if( n )
3043
 
            return n;
3044
 
        }
3045
 
      return NULL;
3046
 
    }
3047
 
 
3048
 
  // trivial test for a bogus empty path
3049
 
  if( path == 0 )
3050
 
    return NULL;
3051
 
 
3052
 
  // if the path starts with '/', skip the '/'
3053
 
  if( path[0] == '/' )
3054
 
    path++;
3055
 
 
3056
 
  // trivial test for a bogus empty path
3057
 
  if( path[0] == '\0' )
3058
 
    return NULL;
3059
 
 
3060
 
  const char *remainingPath;
3061
 
  std::string nodeName;
3062
 
  bool lastNode, branchNode;
3063
 
  Node *retNode = NULL;
3064
 
 
3065
 
  ///////////// extract the next node name from the path ///////////////////
3066
 
 
3067
 
  // find the next '/' that is not preceded by the escape character '\'
3068
 
  const char *slash = strchr( path, '/' );
3069
 
  for(;;)
3070
 
    {
3071
 
      // find the next '/'
3072
 
      if( slash == NULL ) // there isn't one, so we're done
3073
 
        break;
3074
 
      // test for escape character
3075
 
      else if( slash[-1] == '\\' ) // path[0] can never be '/', so this is a safe test
3076
 
        slash = strchr( slash+1, '/' );
3077
 
      // we have it
3078
 
      else
3079
 
        break;
3080
 
    }
3081
 
 
3082
 
  // if there is no slash, then the node name is the path and it is a leaf and the last node in the path
3083
 
  if( slash == NULL )
3084
 
    {
3085
 
      branchNode = false;
3086
 
      nodeName = remove_escape_chars(path); // remove the escape characters
3087
 
      lastNode = true;
3088
 
      remainingPath = NULL;
3089
 
    }
3090
 
  // otherwise the node name is the path up to the slash, it is also a branch and may not be the last node in the path
3091
 
  else
3092
 
    {
3093
 
      branchNode = true;
3094
 
      nodeName = path;
3095
 
      nodeName.resize(slash-path);
3096
 
      nodeName = remove_escape_chars(nodeName.c_str()); // remove the escape characters
3097
 
 
3098
 
      lastNode = ( slash[1] == '\0' ); // this is the last node if there is nothing after the slash
3099
 
      if( lastNode )
3100
 
        {
3101
 
          //if( rdata.autoBranches )
3102
 
          //branchNode = false;
3103
 
          remainingPath = NULL;
3104
 
        }
3105
 
      else
3106
 
        remainingPath = slash+1;
3107
 
    }
3108
 
 
3109
 
  ///////////// process the node ///////////////////
3110
 
 
3111
 
  switch( what )
3112
 
    {
3113
 
    case ADD:
3114
 
      {
3115
 
        // if the new node is a leaf node, add the string as a leaf and return
3116
 
        if( !branchNode )
3117
 
          {
3118
 
            // is there already a node with this name?
3119
 
            /* CG REMOVED THIS
3120
 
            Node *n = _children.find( nodeName );
3121
 
            if( n )
3122
 
              {
3123
 
                // if that node is a branch node, we can't add a new one with the same name
3124
 
                if( n->is_branch() )
3125
 
                  break;
3126
 
 
3127
 
                // if we are not allowed to add multiple nodes with the same name,
3128
 
                // then just return
3129
 
                if( !rdata.allowDuplication )
3130
 
                  break;
3131
 
              }
3132
 
            */
3133
 
 
3134
 
            // add a new node
3135
 
            retNode = new Node( true, nodeName.c_str(), this, rdata, w, showLabel );
3136
 
            _children.add( retNode );
3137
 
            rdata.forceResize = true;
3138
 
            rdata.visibilityChanged = true;
3139
 
 
3140
 
            if( tree->rdata.autoBranches )
3141
 
              initType();
3142
 
          }
3143
 
        // otherwise make sure the node name exists as a branch and recurse on it
3144
 
        else
3145
 
          {
3146
 
            // if there is already a node with this name, just use it
3147
 
            Node *n = NULL;
3148
 
            /* CG REMOVED THIS
3149
 
            n = _children.find( nodeName );
3150
 
            if( n )
3151
 
              {
3152
 
                // make sure it is a branch
3153
 
                if( n->is_leaf() )
3154
 
                  break;
3155
 
              }
3156
 
            */
3157
 
 
3158
 
            // else add a new node
3159
 
            if( n == NULL )
3160
 
              {
3161
 
                // only add the widget for the last node
3162
 
                n = new Node( false, nodeName.c_str(), this, rdata, lastNode?w:NULL, lastNode?showLabel:true );
3163
 
                _children.add( n );
3164
 
                rdata.forceResize = true;
3165
 
                rdata.visibilityChanged = true;
3166
 
              }
3167
 
 
3168
 
            if( tree->rdata.autoBranches )
3169
 
              initType();
3170
 
 
3171
 
            // recurse on the remainder of the path, if not the last node
3172
 
            if( lastNode )
3173
 
              retNode = n;
3174
 
            else
3175
 
              retNode = n->modify( remainingPath, what, rdata, w, showLabel );
3176
 
          }
3177
 
      }
3178
 
      break;
3179
 
 
3180
 
    case REMOVE:
3181
 
      {
3182
 
        // try to find the indicated node. if we can't find it, just return
3183
 
        Node *n = _children.find( nodeName.c_str() );
3184
 
        if( !n )
3185
 
          break;
3186
 
 
3187
 
        // if this is the last node, remove it.
3188
 
        if( lastNode )
3189
 
          {
3190
 
            int ID = n->id();
3191
 
            _children.erase( n );
3192
 
            //if( tree->rdata.cbNode == n )
3193
 
            //tree->rdata.cbNode = NULL;
3194
 
            delete n;
3195
 
            retNode = (Node*)ID; // non-null return value means remove was successful
3196
 
            rdata.forceResize = true;
3197
 
            rdata.visibilityChanged = true;
3198
 
 
3199
 
            if( tree->rdata.autoBranches )
3200
 
              initType();
3201
 
            tree->redraw();
3202
 
          }
3203
 
        // otherwise recurse on the remainder of the path
3204
 
        else
3205
 
          retNode = n->modify( remainingPath, what, rdata, w, showLabel );
3206
 
      }
3207
 
      break;
3208
 
 
3209
 
    case FIND:
3210
 
      {
3211
 
        // if this node equals the starting node for a find_next,
3212
 
        // then by clearing rdata.previous we flag that we are allowed to return the next match
3213
 
        if( rdata.previous == this )
3214
 
          rdata.previous = NULL;
3215
 
 
3216
 
        Node *n = NULL;
3217
 
 
3218
 
        if( !lastNode )
3219
 
          {
3220
 
            // if, according to the path, this is not the last node, then just recursively
3221
 
            // search for the named node
3222
 
            n = _children.find( nodeName.c_str() );
3223
 
            if( !n )
3224
 
              break;
3225
 
            retNode = n->modify( remainingPath, what, rdata, w, showLabel );
3226
 
          }
3227
 
        else
3228
 
          {
3229
 
            // otherwise, according to the path, this is the last node (i.e. a leaf).
3230
 
            // since only leaves can have multiple identical entries,
3231
 
            // try to find the indicated node, accounting for the possibility
3232
 
            // that it may not be the one we're after
3233
 
            int next = 1;
3234
 
            for(;;)
3235
 
              {
3236
 
                // look for the named node
3237
 
                n = _children.find( nodeName.c_str(), next++ );
3238
 
 
3239
 
                // if we can't find it, just return, because it's not here
3240
 
                if( !n )
3241
 
                  break;
3242
 
 
3243
 
                // we are only allowed to return a match if the previous node is NULL,
3244
 
                // indicating we have passed the starting node for a find_next
3245
 
                if( rdata.previous == NULL )
3246
 
                  {
3247
 
                    retNode = n;
3248
 
                    break;
3249
 
                  }
3250
 
 
3251
 
                // if the found node equals the starting node for a find_next,
3252
 
                // then by clearing rdata.previous we flag that we are allowed to return the next match
3253
 
                if( rdata.previous == n )
3254
 
                  rdata.previous = NULL;
3255
 
              }
3256
 
          }
3257
 
      }
3258
 
      break;
3259
 
 
3260
 
    case FIND_NUMBER:
3261
 
      {
3262
 
        if( lastNode )  // can only match multiple leaves if the path says this is the last node
3263
 
          {
3264
 
            rdata.counter += _children.findNum( nodeName.c_str() );
3265
 
          }
3266
 
        else  // otherwise recurse down the remaining path
3267
 
          {
3268
 
            Node *n = _children.find( nodeName.c_str() );
3269
 
            n->modify( remainingPath, what, rdata, w, showLabel );
3270
 
          }
3271
 
      }
3272
 
      break;
3273
 
    }
3274
 
 
3275
 
  return retNode;
3276
 
}
3277
 
 
3278
 
void Flu_Tree_Browser :: Node :: widgetCB()
3279
 
{
3280
 
  if( _widget )
3281
 
    {
3282
 
      if( _widget->CB )
3283
 
        _widget->CB( _widget->w, _widget->CBData );
3284
 
    }
3285
 
  do_callback( FLU_WIDGET_CALLBACK );
3286
 
}
3287
 
 
3288
 
void Flu_Tree_Browser :: Node :: widget( Fl_Widget *w )
3289
 
{
3290
 
  tree->rdata.forceResize = true;
3291
 
 
3292
 
  if( _widget )
3293
 
    {
3294
 
      Fl_Group *p = _widget->w->parent();
3295
 
      if( p )
3296
 
        p->remove( *(_widget->w) );
3297
 
      delete _widget->w;
3298
 
      delete _widget;
3299
 
      _widget = NULL;
3300
 
    }
3301
 
 
3302
 
  if( !w )
3303
 
    return;
3304
 
 
3305
 
  _widget = new WidgetInfo;
3306
 
  _widget->w = w;
3307
 
  _widget->defaultW = _widget->w->w();
3308
 
  if( USE_FLU_WIDGET_CALLBACK )
3309
 
    {
3310
 
      _widget->CB = _widget->w->callback();
3311
 
      _widget->CBData = _widget->w->user_data();
3312
 
      _widget->w->callback( _widgetCB, this );
3313
 
    }
3314
 
 
3315
 
  {
3316
 
    Fl_Group *p = w->parent();
3317
 
    if( p )
3318
 
      p->remove( *w );
3319
 
  }
3320
 
 
3321
 
  if( is_root() )
3322
 
    tree->_box->add( w );
3323
 
  else
3324
 
    {
3325
 
      Node *p = parent();
3326
 
      if( !p->_group )
3327
 
        {
3328
 
          p->_group = new Fl_Group( tree->_box->x(), tree->_box->y(), tree->_box->w(), tree->_box->h() );
3329
 
          p->_group->end();
3330
 
          tree->_box->add( p->_group );
3331
 
        }
3332
 
      p->_group->add( w );
3333
 
    }
3334
 
}
3335
 
 
3336
 
void Flu_Tree_Browser :: Node :: branch_icons( Fl_Image *closed, Fl_Image *open )
3337
 
{
3338
 
  if( is_branch() )
3339
 
    {
3340
 
      bIcon[0] = closed;
3341
 
      bIcon[1] = open;
3342
 
      tree->rdata.forceResize = true;
3343
 
    }
3344
 
}
3345
 
 
3346
 
void Flu_Tree_Browser :: Node :: collapse_icons( Fl_Image *closed, Fl_Image *open )
3347
 
{
3348
 
  if( is_branch() )
3349
 
    {
3350
 
      if( !closed || !open )
3351
 
        {
3352
 
          cIcon[0] = tree->rdata.defaultCollapseIcons[0];
3353
 
          cIcon[1] = tree->rdata.defaultCollapseIcons[1];
3354
 
        }
3355
 
      else
3356
 
        {
3357
 
          cIcon[0] = closed;
3358
 
          cIcon[1] = open;
3359
 
        }
3360
 
      tree->rdata.forceResize = true;
3361
 
    }
3362
 
}
3363
 
 
3364
 
void Flu_Tree_Browser :: Node :: leaf_icon( Fl_Image *icon )
3365
 
{
3366
 
  if( is_leaf() )
3367
 
    {
3368
 
      lIcon = icon;
3369
 
      tree->rdata.forceResize = true;
3370
 
    }
3371
 
}
3372
 
 
3373
 
bool Flu_Tree_Browser :: Node :: is_branch() const
3374
 
{
3375
 
  if( tree->rdata.autoBranches )
3376
 
    return( _children.size() != 0 );
3377
 
  else
3378
 
    return !CHECK(LEAF);
3379
 
}
3380
 
 
3381
 
bool Flu_Tree_Browser :: Node :: is_leaf() const
3382
 
{
3383
 
  if( tree->rdata.autoBranches )
3384
 
    return( _children.size() == 0 && !is_root() );
3385
 
  else
3386
 
    return CHECK(LEAF);
3387
 
}
3388
 
 
3389
 
 
3390
 
#if 0 // CG test code: set to 1 and run "fltk-config --compile Flu_Tree_Browser.cpp"
3391
 
 
3392
 
#include <FL/Fl.H>
3393
 
#include <FL/Fl_Window.H>
3394
 
#include <FL/Fl_Box.H>
3395
 
#include <FL/Fl_Input.H>
3396
 
#include <FL/Fl_Choice.H>
3397
 
#include <FL/Fl_Check_Button.H>
3398
 
#include "Flu_Tree_Browser.h"
3399
 
 
3400
 
void add_points(Flu_Tree_Browser::Node *n)
3401
 
{
3402
 
  char str[128];
3403
 
  for(int i = 0; i < 2; i++){
3404
 
    sprintf(str, "Point %d", i);
3405
 
    n->add(str);
3406
 
  }
3407
 
}
3408
 
 
3409
 
void add_lines(Flu_Tree_Browser::Node *n)
3410
 
{
3411
 
  char str[128];
3412
 
  for(int i = 0; i < 10; i++){
3413
 
    sprintf(str, "Line %d/", i);
3414
 
    Flu_Tree_Browser::Node *n2 = n->add(str);
3415
 
    add_points(n2);
3416
 
  }
3417
 
}
3418
 
 
3419
 
void add_surfaces(Flu_Tree_Browser::Node *n)
3420
 
{
3421
 
  char str[128];
3422
 
  for(int i = 0; i < 100; i++){
3423
 
    sprintf(str, "Surface %d/", i);
3424
 
    Flu_Tree_Browser::Node *n2 = n->add(str);
3425
 
    //add_lines(n2);
3426
 
  }
3427
 
}
3428
 
 
3429
 
void add_volumes(Flu_Tree_Browser::Node *n)
3430
 
{
3431
 
  char str[128];
3432
 
  for(int i = 0; i < 1000; i++){
3433
 
    sprintf(str, "Volume %d/", i);
3434
 
    Flu_Tree_Browser::Node *n2 = n->add(str);
3435
 
    add_surfaces(n2);
3436
 
  }
3437
 
}
3438
 
 
3439
 
int main(int argc, char **argv)
3440
 
{
3441
 
  printf("sizeof Node = %d\n", sizeof(Flu_Tree_Browser :: Node));
3442
 
 
3443
 
  Fl_Window *window = new Fl_Window(300, 600);
3444
 
  Flu_Tree_Browser *tree = new Flu_Tree_Browser(0, 0, 300, 600);
3445
 
  tree->show_root(false);
3446
 
  tree->insertion_mode(FLU_INSERT_BACK);
3447
 
  tree->branch_icons(0, 0);
3448
 
  //tree->open(true);
3449
 
  char str[128];    
3450
 
  for(int i = 0; i < 2; i++){
3451
 
    sprintf(str, "Model %d <<DLR_F6>>/", i);
3452
 
    Fl_Check_Button *b = new Fl_Check_Button(0, 0, 20, 20);
3453
 
    b->tooltip("Set active");
3454
 
    Flu_Tree_Browser::Node *n = tree->add(str, b);
3455
 
    Flu_Tree_Browser::Node *e = n->add("Elementary entities/");
3456
 
    add_volumes(e);
3457
 
    //add_surfaces(e);
3458
 
    //add_lines(e);
3459
 
    //add_points(e);
3460
 
    Flu_Tree_Browser::Node *g = n->add("Physical groups/");
3461
 
    Flu_Tree_Browser::Node *p = n->add("Mesh partitions/");
3462
 
  }
3463
 
  Flu_Tree_Browser::Node *p = tree->add("Post-processing views/");
3464
 
  for(int i = 0; i < 7; i++){
3465
 
    sprintf(str, "View %d", i);
3466
 
    p->add(str);
3467
 
  }
3468
 
  window->end();
3469
 
  window->resizable(tree);
3470
 
  window->show(argc, argv);
3471
 
  return Fl::run();
3472
 
}
3473
 
 
3474
 
#endif