Flu_Tree_Browser.cpp 91 KB

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