1 /********************************************************************************
2 *                                                                               *
3 *                    F o l d i n g   L i s t   W i d g e t                      *
4 *                                                                               *
5 *********************************************************************************
6 * Copyright (C) 1997,2005 by Jeroen van der Zijp.   All Rights Reserved.        *
7 *********************************************************************************
8 * This library is free software; you can redistribute it and/or                 *
9 * modify it under the terms of the GNU Lesser General Public                    *
10 * License as published by the Free Software Foundation; either                  *
11 * version 2.1 of the License, or (at your option) any later version.            *
12 *                                                                               *
13 * This library is distributed in the hope that it will be useful,               *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of                *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU             *
16 * Lesser General Public License for more details.                               *
17 *                                                                               *
18 * You should have received a copy of the GNU Lesser General Public              *
19 * License along with this library; if not, write to the Free Software           *
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.    *
21 *********************************************************************************
22 * $Id: FXFoldingList.cpp,v 1.55.2.1 2005/12/15 22:52:37 fox Exp $                   *
23 ********************************************************************************/
24 #include "xincs.h"
25 #include "fxver.h"
26 #include "fxdefs.h"
27 #include "fxkeys.h"
28 #include "FXHash.h"
29 #include "FXThread.h"
30 #include "FXStream.h"
31 #include "FXString.h"
32 #include "FXSize.h"
33 #include "FXPoint.h"
34 #include "FXObjectList.h"
35 #include "FXRectangle.h"
36 #include "FXRegistry.h"
37 #include "FXApp.h"
38 #include "FXDCWindow.h"
39 #include "FXFont.h"
40 #include "FXIcon.h"
41 #include "FXButton.h"
42 #include "FXScrollBar.h"
43 #include "FXScrollArea.h"
44 #include "FXHeader.h"
45 #include "FXFoldingList.h"
46 
47 
48 /*
49   Notes:
50   - Tooltip should pop up exactly on top of current item.
51   - Clicking on + does not make it current.
52   - Need translate right-clicks into message with item figured out...
53   - In autoselect mode, all items are expanded.
54   - Sortfunc's will be hard to serialize.
55   - As with FXIconList, it probably shouldn't autoscroll when draggin icons.
56   - Maybe moving (dragging) items around in the treelist is something that should
57     be supported?
58   - Click outside of list perhaps should also change current item?
59 */
60 
61 
62 #define ICON_SPACING        4   // Spacing between parent and child in x direction
63 #define TEXT_SPACING        4   // Spacing between icon and text
64 #define SIDE_SPACING        4   // Spacing between side and item
65 #define DEFAULT_INDENT      8   // Indent between parent and child
66 #define HALFBOX_SIZE        4   // Half box size
67 #define BOX_FUDGE           3   // Fudge border around box
68 
69 
70 #define SELECT_MASK         (FOLDINGLIST_SINGLESELECT|FOLDINGLIST_BROWSESELECT)
71 #define FOLDINGLIST_MASK    (SELECT_MASK|FOLDINGLIST_AUTOSELECT|FOLDINGLIST_SHOWS_LINES|FOLDINGLIST_SHOWS_BOXES|FOLDINGLIST_ROOT_BOXES)
72 
73 
74 using namespace FX;
75 
76 /*******************************************************************************/
77 
78 namespace FX {
79 
80 
81 // Object implementation
82 FXIMPLEMENT(FXFoldingItem,FXObject,NULL,0)
83 
84 
85 // Draw item
draw(const FXFoldingList * list,FXDC & dc,FXint x,FXint y,FXint,FXint h) const86 void FXFoldingItem::draw(const FXFoldingList* list,FXDC& dc,FXint x,FXint y,FXint,FXint h) const {
87   register FXHeader *header=list->getHeader();
88   register FXIcon *icon=(state&OPENED)?openIcon:closedIcon;
89   register FXFont *font=list->getFont();
90   register FXint th=0,tw=0,ih=0,iw=0,yt,xb,beg,end,hi,drw,space,used,dw,xx;
91   if(header->getNumItems()==0) return;
92   xx=x+SIDE_SPACING/2;
93   if(icon){
94     iw=icon->getWidth();
95     ih=icon->getHeight();
96     dc.setClipRectangle(header->getItemOffset(0),y,header->getItemSize(0),h);
97     dc.drawIcon(icon,xx,y+(h-ih)/2);
98     dc.clearClipRectangle();
99     xx+=ICON_SPACING+iw;
100     }
101   if(!label.empty()){
102     th=font->getFontHeight();
103     dw=font->getTextWidth("...",3);
104     xb=header->getItemOffset(0)+header->getItemSize(0);
105     if(xb>xx) xb=xx;
106     yt=y+(h-th-4)/2;
107     if(isSelected()){
108       dc.setForeground(list->getSelBackColor());
109       dc.fillRectangle(xb,y,header->getTotalSize()-xb,h);
110       }
111     if(hasFocus()){
112       dc.drawFocusRectangle(xb+1,y+1,header->getTotalSize()-xb-2,h-2);
113       }
114     if(!isEnabled())
115       dc.setForeground(makeShadowColor(list->getBackColor()));
116     else if(isSelected())
117       dc.setForeground(list->getSelTextColor());
118     else
119       dc.setForeground(list->getTextColor());
120     used=xx-header->getItemOffset(0);
121     for(hi=beg=0; beg<label.length() && hi<header->getNumItems(); hi++,beg=end+1){
122       space=header->getItemSize(hi)-used;
123       for(end=beg; end<label.length() && label[end]!='\t'; end++);
124       if(end>beg){
125         drw=end-beg;
126         tw=font->getTextWidth(&label[beg],drw);
127         if(tw>space-4){
128           while((tw=font->getTextWidth(&label[beg],drw))+dw>space-4 && drw>1) drw--;
129           dc.setClipRectangle(xx,y,space,h);
130           dc.drawText(xx+2,yt+font->getFontAscent()+2,&label[beg],drw);
131           dc.drawText(xx+tw+2,yt+font->getFontAscent()+2,"...",3);
132           dc.clearClipRectangle();
133           }
134         else{
135           dc.drawText(xx+2,yt+font->getFontAscent()+2,&label[beg],drw);
136           }
137         }
138       xx+=space;
139       used=0;
140       }
141     }
142   }
143 
144 
145 // See if item got hit, and where:- 1 is icon, 2 is text
hitItem(const FXFoldingList * list,FXint x,FXint y) const146 FXint FXFoldingItem::hitItem(const FXFoldingList* list,FXint x,FXint y) const {
147   register FXint oiw=0,ciw=0,oih=0,cih=0,tw=0,th=0,iw,ih,ix,iy,tx,ty,h;
148   register FXFont *font=list->getFont();
149   if(openIcon){
150     oiw=openIcon->getWidth();
151     oih=openIcon->getHeight();
152     }
153   if(closedIcon){
154     ciw=closedIcon->getWidth();
155     cih=closedIcon->getHeight();
156     }
157   if(!label.empty()){
158     if(!list->getHeader()->getNumItems())
159       tw=4+font->getTextWidth(label.text(),label.length());
160     else
161       tw=4+list->getHeader()->getDefaultWidth();
162     th=4+font->getFontHeight();
163     }
164   iw=FXMAX(oiw,ciw);
165   ih=FXMAX(oih,cih);
166   h=FXMAX(th,ih);
167   ix=SIDE_SPACING/2;
168   tx=SIDE_SPACING/2;
169   if(iw) tx+=iw+ICON_SPACING;
170   iy=(h-ih)/2;
171   ty=(h-th)/2;
172 
173   // In icon?
174   if(ix<=x && iy<=y && x<ix+iw && y<iy+ih) return 1;
175 
176   // In text?
177   if(tx<=x && ty<=y && x<tx+tw && y<ty+th) return 2;
178 
179   // Outside
180   return 0;
181   }
182 
183 
184 // Set or kill focus
setFocus(FXbool focus)185 void FXFoldingItem::setFocus(FXbool focus){
186   if(focus) state|=FOCUS; else state&=~FOCUS;
187   }
188 
189 // Select or deselect item
setSelected(FXbool selected)190 void FXFoldingItem::setSelected(FXbool selected){
191   if(selected) state|=SELECTED; else state&=~SELECTED;
192   }
193 
194 // Set item opened
setOpened(FXbool opened)195 void FXFoldingItem::setOpened(FXbool opened){
196   if(opened) state|=OPENED; else state&=~OPENED;
197   }
198 
199 // Set item expanded
setExpanded(FXbool expanded)200 void FXFoldingItem::setExpanded(FXbool expanded){
201   if(expanded) state|=EXPANDED; else state&=~EXPANDED;
202   }
203 
204 // Enable or disable the item
setEnabled(FXbool enabled)205 void FXFoldingItem::setEnabled(FXbool enabled){
206   if(enabled) state&=~DISABLED; else state|=DISABLED;
207   }
208 
209 // Icon is draggable
setDraggable(FXbool draggable)210 void FXFoldingItem::setDraggable(FXbool draggable){
211   if(draggable) state|=DRAGGABLE; else state&=~DRAGGABLE;
212   }
213 
214 
215 // Change item label
setText(const FXString & txt)216 void FXFoldingItem::setText(const FXString& txt){
217   label=txt;
218   }
219 
220 
221 // Change item's open icon
setOpenIcon(FXIcon * icn,FXbool owned)222 void FXFoldingItem::setOpenIcon(FXIcon* icn,FXbool owned){
223   if(openIcon && (state&OPENICONOWNED)){
224     if(openIcon!=icn) delete openIcon;
225     state&=~OPENICONOWNED;
226     }
227   openIcon=icn;
228   if(openIcon && owned){
229     state|=OPENICONOWNED;
230     }
231   }
232 
233 
234 // Change item's mini icon
setClosedIcon(FXIcon * icn,FXbool owned)235 void FXFoldingItem::setClosedIcon(FXIcon* icn,FXbool owned){
236   if(closedIcon && (state&CLOSEDICONOWNED)){
237     if(closedIcon!=icn) delete closedIcon;
238     state&=~CLOSEDICONOWNED;
239     }
240   closedIcon=icn;
241   if(closedIcon && owned){
242     state|=CLOSEDICONOWNED;
243     }
244   }
245 
246 
247 // Change has items flag
setHasItems(FXbool flag)248 void FXFoldingItem::setHasItems(FXbool flag){
249   if(flag) state|=HASITEMS; else state&=~HASITEMS;
250   }
251 
252 
253 // Create icon
create()254 void FXFoldingItem::create(){
255   if(openIcon) openIcon->create();
256   if(closedIcon) closedIcon->create();
257   }
258 
259 
260 // Destroy icon
destroy()261 void FXFoldingItem::destroy(){
262   if((state&OPENICONOWNED) && openIcon) openIcon->destroy();
263   if((state&CLOSEDICONOWNED) && closedIcon) closedIcon->destroy();
264   }
265 
266 
267 // Detach from icon resource
detach()268 void FXFoldingItem::detach(){
269   if(openIcon) openIcon->detach();
270   if(closedIcon) closedIcon->detach();
271   }
272 
273 
274 // Get number of child items
getNumChildren() const275 FXint FXFoldingItem::getNumChildren() const {
276   register FXFoldingItem *item=first;
277   register FXint n=0;
278   while(item){item=item->next;n++;}
279   return n;
280   }
281 
282 
283 
284 // Get item (logically) below this one
getBelow() const285 FXFoldingItem* FXFoldingItem::getBelow() const {
286   register FXFoldingItem* item=(FXFoldingItem*)this;
287   if(first) return first;
288   while(!item->next && item->parent) item=item->parent;
289   return item->next;
290   }
291 
292 
293 // Get item (logically) above this one
getAbove() const294 FXFoldingItem* FXFoldingItem::getAbove() const {
295   register FXFoldingItem* item=prev;
296   if(!item) return parent;
297   while(item->last) item=item->last;
298   return item;
299   }
300 
301 
302 // Return true if child of parent item
isChildOf(const FXFoldingItem * item) const303 FXbool FXFoldingItem::isChildOf(const FXFoldingItem* item) const {
304   register const FXFoldingItem* child=this;
305   while(child){ child=child->parent; if(child==item) return TRUE; }
306   return FALSE;
307   }
308 
309 
310 // Return true if parent of child item
isParentOf(const FXFoldingItem * item) const311 FXbool FXFoldingItem::isParentOf(const FXFoldingItem* item) const {
312   register const FXFoldingItem* child=item;
313   while(child){ child=child->parent; if(child==this) return TRUE; }
314   return FALSE;
315   }
316 
317 
318 // Get item width
getWidth(const FXFoldingList *) const319 FXint FXFoldingItem::getWidth(const FXFoldingList*) const {
320   return SIDE_SPACING;
321   }
322 
323 
324 // Get item height
getHeight(const FXFoldingList * list) const325 FXint FXFoldingItem::getHeight(const FXFoldingList* list) const {
326   register FXint th=0,oih=0,cih=0;
327   if(openIcon) oih=openIcon->getHeight();
328   if(closedIcon) cih=closedIcon->getHeight();
329   if(!label.empty()) th=4+list->getFont()->getFontHeight();
330   return FXMAX3(th,oih,cih);
331   }
332 
333 
334 // Save data
save(FXStream & store) const335 void FXFoldingItem::save(FXStream& store) const {
336   FXObject::save(store);
337   store << prev;
338   store << next;
339   store << parent;
340   store << first;
341   store << last;
342   store << label;
343   store << openIcon;
344   store << closedIcon;
345   store << state;
346   }
347 
348 
349 // Load data
load(FXStream & store)350 void FXFoldingItem::load(FXStream& store){
351   FXObject::load(store);
352   store >> prev;
353   store >> next;
354   store >> parent;
355   store >> first;
356   store >> last;
357   store >> label;
358   store >> openIcon;
359   store >> closedIcon;
360   store >> state;
361   }
362 
363 
364 // Delete icons if owned
~FXFoldingItem()365 FXFoldingItem::~FXFoldingItem(){
366   if(state&OPENICONOWNED) delete openIcon;
367   if(state&CLOSEDICONOWNED) delete closedIcon;
368   parent=(FXFoldingItem*)-1L;
369   prev=(FXFoldingItem*)-1L;
370   next=(FXFoldingItem*)-1L;
371   first=(FXFoldingItem*)-1L;
372   last=(FXFoldingItem*)-1L;
373   openIcon=(FXIcon*)-1L;
374   closedIcon=(FXIcon*)-1L;
375   }
376 
377 
378 /*******************************************************************************/
379 
380 // Map
381 FXDEFMAP(FXFoldingList) FXFoldingListMap[]={
382   FXMAPFUNC(SEL_PAINT,0,FXFoldingList::onPaint),
383   FXMAPFUNC(SEL_MOTION,0,FXFoldingList::onMotion),
384   FXMAPFUNC(SEL_TIMEOUT,FXWindow::ID_AUTOSCROLL,FXFoldingList::onAutoScroll),
385   FXMAPFUNC(SEL_TIMEOUT,FXFoldingList::ID_TIPTIMER,FXFoldingList::onTipTimer),
386   FXMAPFUNC(SEL_TIMEOUT,FXFoldingList::ID_LOOKUPTIMER,FXFoldingList::onLookupTimer),
387   FXMAPFUNC(SEL_LEFTBUTTONPRESS,0,FXFoldingList::onLeftBtnPress),
388   FXMAPFUNC(SEL_LEFTBUTTONRELEASE,0,FXFoldingList::onLeftBtnRelease),
389   FXMAPFUNC(SEL_RIGHTBUTTONPRESS,0,FXFoldingList::onRightBtnPress),
390   FXMAPFUNC(SEL_RIGHTBUTTONRELEASE,0,FXFoldingList::onRightBtnRelease),
391   FXMAPFUNC(SEL_UNGRABBED,0,FXFoldingList::onUngrabbed),
392   FXMAPFUNC(SEL_KEYPRESS,0,FXFoldingList::onKeyPress),
393   FXMAPFUNC(SEL_KEYRELEASE,0,FXFoldingList::onKeyRelease),
394   FXMAPFUNC(SEL_ENTER,0,FXFoldingList::onEnter),
395   FXMAPFUNC(SEL_LEAVE,0,FXFoldingList::onLeave),
396   FXMAPFUNC(SEL_FOCUSIN,0,FXFoldingList::onFocusIn),
397   FXMAPFUNC(SEL_FOCUSOUT,0,FXFoldingList::onFocusOut),
398   FXMAPFUNC(SEL_QUERY_TIP,0,FXFoldingList::onQueryTip),
399   FXMAPFUNC(SEL_QUERY_HELP,0,FXFoldingList::onQueryHelp),
400   FXMAPFUNC(SEL_CLICKED,0,FXFoldingList::onClicked),
401   FXMAPFUNC(SEL_DOUBLECLICKED,0,FXFoldingList::onDoubleClicked),
402   FXMAPFUNC(SEL_TRIPLECLICKED,0,FXFoldingList::onTripleClicked),
403   FXMAPFUNC(SEL_COMMAND,0,FXFoldingList::onCommand),
404   FXMAPFUNC(SEL_CHANGED,FXFoldingList::ID_HEADER_CHANGE,FXFoldingList::onHeaderChanged),
405   };
406 
407 
408 // Object implementation
FXIMPLEMENT(FXFoldingList,FXScrollArea,FXFoldingListMap,ARRAYNUMBER (FXFoldingListMap))409 FXIMPLEMENT(FXFoldingList,FXScrollArea,FXFoldingListMap,ARRAYNUMBER(FXFoldingListMap))
410 
411 
412 /*******************************************************************************/
413 
414 
415 // Tree List
416 FXFoldingList::FXFoldingList(){
417   flags|=FLAG_ENABLED;
418   header=(FXHeader*)-1L;
419   firstitem=NULL;
420   lastitem=NULL;
421   anchoritem=NULL;
422   currentitem=NULL;
423   extentitem=NULL;
424   cursoritem=NULL;
425   font=(FXFont*)-1L;
426   sortfunc=NULL;
427   textColor=0;
428   selbackColor=0;
429   seltextColor=0;
430   lineColor=0;
431   treeWidth=0;
432   treeHeight=0;
433   visible=0;
434   indent=DEFAULT_INDENT;
435   grabx=0;
436   graby=0;
437   state=FALSE;
438   }
439 
440 
441 // Tree List
FXFoldingList(FXComposite * p,FXObject * tgt,FXSelector sel,FXuint opts,FXint x,FXint y,FXint w,FXint h)442 FXFoldingList::FXFoldingList(FXComposite *p,FXObject* tgt,FXSelector sel,FXuint opts,FXint x,FXint y,FXint w,FXint h):
443   FXScrollArea(p,opts,x,y,w,h){
444   flags|=FLAG_ENABLED;
445   header=new FXHeader(this,this,FXFoldingList::ID_HEADER_CHANGE,HEADER_TRACKING|HEADER_BUTTON|HEADER_RESIZE|FRAME_RAISED|FRAME_THICK);
446   target=tgt;
447   message=sel;
448   firstitem=NULL;
449   lastitem=NULL;
450   anchoritem=NULL;
451   currentitem=NULL;
452   extentitem=NULL;
453   cursoritem=NULL;
454   font=getApp()->getNormalFont();
455   sortfunc=NULL;
456   textColor=getApp()->getForeColor();
457   selbackColor=getApp()->getSelbackColor();
458   seltextColor=getApp()->getSelforeColor();
459   lineColor=getApp()->getShadowColor();
460   treeWidth=0;
461   treeHeight=0;
462   visible=0;
463   indent=DEFAULT_INDENT;
464   grabx=0;
465   graby=0;
466   state=FALSE;
467   }
468 
469 
470 // Create window
create()471 void FXFoldingList::create(){
472   register FXFoldingItem *item=firstitem;
473   FXScrollArea::create();
474   while(item){
475     item->create();
476     if(item->first){item=item->first;continue;}
477     while(!item->next && item->parent){item=item->parent;}
478     item=item->next;
479     }
480   font->create();
481   }
482 
483 
484 // Detach window
detach()485 void FXFoldingList::detach(){
486   register FXFoldingItem *item=firstitem;
487   FXScrollArea::detach();
488   while(item){
489     item->detach();
490     if(item->first){item=item->first;continue;}
491     while(!item->next && item->parent){item=item->parent;}
492     item=item->next;
493     }
494   font->detach();
495   }
496 
497 
498 // Can have focus
canFocus() const499 FXbool FXFoldingList::canFocus() const { return TRUE; }
500 
501 
502 // Into focus chain
setFocus()503 void FXFoldingList::setFocus(){
504   FXScrollArea::setFocus();
505   setDefault(TRUE);
506   }
507 
508 
509 // Out of focus chain
killFocus()510 void FXFoldingList::killFocus(){
511   FXScrollArea::killFocus();
512   setDefault(MAYBE);
513   }
514 
515 
516 // Get default width
getDefaultWidth()517 FXint FXFoldingList::getDefaultWidth(){
518   return FXScrollArea::getDefaultWidth();
519   }
520 
521 
522 // Get default height
getDefaultHeight()523 FXint FXFoldingList::getDefaultHeight(){
524   if(visible) return visible*(4+font->getFontHeight())+header->getDefaultHeight();
525   return FXScrollArea::getDefaultHeight();
526   }
527 
528 
529 // Propagate size change
recalc()530 void FXFoldingList::recalc(){
531   FXScrollArea::recalc();
532   flags|=FLAG_RECALC;
533   cursoritem=NULL;
534   }
535 
536 // Move content
moveContents(FXint x,FXint y)537 void FXFoldingList::moveContents(FXint x,FXint y){
538   FXint dx=x-pos_x;
539   FXint dy=y-pos_y;
540   pos_x=x;
541   pos_y=y;
542   header->setPosition(x);
543   scroll(0,header->getHeight(),viewport_w,viewport_h,dx,dy);
544   }
545 
546 
547 // List is multiple of nitems
setNumVisible(FXint nvis)548 void FXFoldingList::setNumVisible(FXint nvis){
549   if(nvis<0) nvis=0;
550   if(visible!=nvis){
551     visible=nvis;
552     recalc();
553     }
554   }
555 
556 
557 // Get number of toplevel items
getNumItems() const558 FXint FXFoldingList::getNumItems() const {
559   register FXFoldingItem *item=firstitem;
560   register FXint n=0;
561   while(item){
562     item=item->next;
563     n++;
564     }
565   return n;
566   }
567 
568 
569 // Recompute interior
recompute()570 void FXFoldingList::recompute(){
571   register FXFoldingItem* item;
572   register FXint x,y,h;
573   x=y=0;
574   treeWidth=0;
575   treeHeight=0;
576   item=firstitem;
577   if(options&FOLDINGLIST_ROOT_BOXES) x+=(4+indent);
578   while(item){
579     item->x=x;
580     item->y=y;
581     h=item->getHeight(this);
582     y+=h;
583     if(item->first && ((options&FOLDINGLIST_AUTOSELECT) || item->isExpanded())){
584       x+=(indent+h/2);
585       item=item->first;
586       continue;
587       }
588     while(!item->next && item->parent){
589       item=item->parent;
590       x-=(indent+item->getHeight(this)/2);
591       }
592     item=item->next;
593     }
594   treeWidth=header->getDefaultWidth();
595   treeHeight=header->getDefaultHeight()+y;
596   flags&=~FLAG_RECALC;
597   }
598 
599 
600 // Determine content width of tree list
getContentWidth()601 FXint FXFoldingList::getContentWidth(){
602   if(flags&FLAG_RECALC) recompute();
603   return treeWidth;
604   }
605 
606 
607 // Determine content height of tree list
getContentHeight()608 FXint FXFoldingList::getContentHeight(){
609   if(flags&FLAG_RECALC) recompute();
610   return treeHeight;
611   }
612 
613 
614 // Recalculate layout
layout()615 void FXFoldingList::layout(){
616 
617   // Calculate contents
618   FXScrollArea::layout();
619 
620   // Place header control
621   header->position(0,0,viewport_w,header->getDefaultHeight());
622 
623   // Set line size based on item size
624   if(firstitem){
625     vertical->setLine(firstitem->getHeight(this));
626     horizontal->setLine(firstitem->getWidth(this)/10);
627     }
628 
629   // Force repaint
630   update();
631 
632   // No more dirty
633   flags&=~FLAG_DIRTY;
634   }
635 
636 
637 // Header changed but content size didn't
onHeaderChanged(FXObject *,FXSelector,void *)638 long FXFoldingList::onHeaderChanged(FXObject*,FXSelector,void*){
639 //  flags&=~FLAG_RECALC;
640   return 1;
641   }
642 
643 
644 // Set headers from array of strings
setHeaders(const FXchar ** strings,FXint size)645 void FXFoldingList::setHeaders(const FXchar** strings,FXint size){
646   header->clearItems();
647   header->fillItems(strings,NULL,size);
648   }
649 
650 
651 // Set headers from newline separated strings
setHeaders(const FXString & strings,FXint size)652 void FXFoldingList::setHeaders(const FXString& strings,FXint size){
653   header->clearItems();
654   header->fillItems(strings,NULL,size);
655   }
656 
657 // Append header caption
appendHeader(const FXString & text,FXIcon * icon,FXint size)658 void FXFoldingList::appendHeader(const FXString& text,FXIcon *icon,FXint size){
659   header->appendItem(text,icon,size);
660   }
661 
662 
663 // Remove header caption
removeHeader(FXint index)664 void FXFoldingList::removeHeader(FXint index){
665   if(index<0 || header->getNumItems()<=index){ fxerror("%s::removeHeader: index out of range.\n",getClassName()); }
666   header->removeItem(index);
667   }
668 
669 
670 // Change header caption
setHeaderText(FXint index,const FXString & text)671 void FXFoldingList::setHeaderText(FXint index,const FXString& text){
672   if(index<0 || header->getNumItems()<=index){ fxerror("%s::setHeaderText: index out of range.\n",getClassName()); }
673   header->setItemText(index,text);
674   }
675 
676 
677 // Get header caption
getHeaderText(FXint index) const678 FXString FXFoldingList::getHeaderText(FXint index) const {
679   if(index<0 || header->getNumItems()<=index){ fxerror("%s::getHeaderText: index out of range.\n",getClassName()); }
680   return header->getItemText(index);
681   }
682 
683 
684 // Change header icon
setHeaderIcon(FXint index,FXIcon * icon)685 void FXFoldingList::setHeaderIcon(FXint index,FXIcon *icon){
686   if(index<0 || header->getNumItems()<=index){ fxerror("%s::setHeaderIcon: index out of range.\n",getClassName()); }
687   header->setItemIcon(index,icon);
688   }
689 
690 
691 // Get header icon
getHeaderIcon(FXint index) const692 FXIcon* FXFoldingList::getHeaderIcon(FXint index) const {
693   if(index<0 || header->getNumItems()<=index){ fxerror("%s::getHeaderIcon: index out of range.\n",getClassName()); }
694   return header->getItemIcon(index);
695   }
696 
697 
698 // Change header size
setHeaderSize(FXint index,FXint size)699 void FXFoldingList::setHeaderSize(FXint index,FXint size){
700   if(index<0 || header->getNumItems()<=index){ fxerror("%s::setHeaderSize: index out of range.\n",getClassName()); }
701   header->setItemSize(index,size);
702   }
703 
704 
705 // Get header size
getHeaderSize(FXint index) const706 FXint FXFoldingList::getHeaderSize(FXint index) const {
707   if(index<0 || header->getNumItems()<=index){ fxerror("%s::getHeaderSize: index out of range.\n",getClassName()); }
708   return header->getItemSize(index);
709   }
710 
711 
712 // Return number of headers
getNumHeaders() const713 FXint FXFoldingList::getNumHeaders() const {
714   return header->getNumItems();
715   }
716 
717 
718 // Set item text
setItemText(FXFoldingItem * item,const FXString & text)719 void FXFoldingList::setItemText(FXFoldingItem* item,const FXString& text){
720   if(item==NULL){ fxerror("%s::setItemText: item is NULL.\n",getClassName()); }
721   if(item->getText()!=text){
722     item->setText(text);
723     recalc();
724     }
725   }
726 
727 
728 // Get item text
getItemText(const FXFoldingItem * item) const729 FXString FXFoldingList::getItemText(const FXFoldingItem* item) const {
730   if(item==NULL){ fxerror("%s::getItemText: item is NULL.\n",getClassName()); }
731   return item->getText();
732   }
733 
734 
735 // Set item open icon
setItemOpenIcon(FXFoldingItem * item,FXIcon * icon,FXbool owned)736 void FXFoldingList::setItemOpenIcon(FXFoldingItem* item,FXIcon* icon,FXbool owned){
737   if(item==NULL){ fxerror("%s::setItemOpenIcon: item is NULL.\n",getClassName()); }
738   if(item->getOpenIcon()!=icon) recalc();
739   item->setOpenIcon(icon,owned);
740   }
741 
742 
743 // Get item open icon
getItemOpenIcon(const FXFoldingItem * item) const744 FXIcon* FXFoldingList::getItemOpenIcon(const FXFoldingItem* item) const {
745   if(item==NULL){ fxerror("%s::getItemOpenIcon: item is NULL.\n",getClassName()); }
746   return item->getOpenIcon();
747   }
748 
749 
750 // Set item closed icon
setItemClosedIcon(FXFoldingItem * item,FXIcon * icon,FXbool owned)751 void FXFoldingList::setItemClosedIcon(FXFoldingItem* item,FXIcon* icon,FXbool owned){
752   if(item==NULL){ fxerror("%s::setItemClosedIcon: item is NULL.\n",getClassName()); }
753   if(item->getClosedIcon()!=icon) recalc();
754   item->setClosedIcon(icon,owned);
755   }
756 
757 
758 // Get item closed icon
getItemClosedIcon(const FXFoldingItem * item) const759 FXIcon* FXFoldingList::getItemClosedIcon(const FXFoldingItem* item) const {
760   if(item==NULL){ fxerror("%s::getItemClosedIcon: item is NULL.\n",getClassName()); }
761   return item->getClosedIcon();
762   }
763 
764 
765 // Set item data
setItemData(FXFoldingItem * item,void * ptr) const766 void FXFoldingList::setItemData(FXFoldingItem* item,void* ptr) const {
767   if(item==NULL){ fxerror("%s::setItemData: item is NULL.\n",getClassName()); }
768   item->setData(ptr);
769   }
770 
771 
772 // Get item data
getItemData(const FXFoldingItem * item) const773 void* FXFoldingList::getItemData(const FXFoldingItem* item) const {
774   if(item==NULL){ fxerror("%s::getItemData: item is NULL.\n",getClassName()); }
775   return item->getData();
776   }
777 
778 
779 // True if item is selected
isItemSelected(const FXFoldingItem * item) const780 FXbool FXFoldingList::isItemSelected(const FXFoldingItem* item) const {
781   if(!item){ fxerror("%s::isItemSelected: item is NULL.\n",getClassName()); }
782   return item->isSelected();
783   }
784 
785 
786 // True if item is current
isItemCurrent(const FXFoldingItem * item) const787 FXbool FXFoldingList::isItemCurrent(const FXFoldingItem* item) const {
788   if(!item){ fxerror("%s::isItemCurrent: item is NULL.\n",getClassName()); }
789   return currentitem==item;
790   }
791 
792 
793 // Check if item is expanded
isItemExpanded(const FXFoldingItem * item) const794 FXbool FXFoldingList::isItemExpanded(const FXFoldingItem* item) const {
795   if(!item){ fxerror("%s::isItemExpanded: item is NULL.\n",getClassName()); }
796   return (options&FOLDINGLIST_AUTOSELECT) || item->isExpanded();
797   }
798 
799 
800 // Is item a leaf item
isItemLeaf(const FXFoldingItem * item) const801 FXbool FXFoldingList::isItemLeaf(const FXFoldingItem* item) const {
802   if(!item){ fxerror("%s::isItemLeaf: item is NULL.\n",getClassName()); }
803   return item->first==NULL;
804   }
805 
806 
807 // Check if item is enabled
isItemEnabled(const FXFoldingItem * item) const808 FXbool FXFoldingList::isItemEnabled(const FXFoldingItem* item) const {
809   if(!item){ fxerror("%s::isItemEnabled: item is NULL.\n",getClassName()); }
810   return item->isEnabled();
811   }
812 
813 
814 // Check item is open
isItemOpened(const FXFoldingItem * item) const815 FXbool FXFoldingList::isItemOpened(const FXFoldingItem* item) const {
816   if(!item){ fxerror("%s::isItemOpen: item is NULL.\n",getClassName()); }
817   return item->isOpened();
818   }
819 
820 
821 // True if item (partially) visible
isItemVisible(const FXFoldingItem * item) const822 FXbool FXFoldingList::isItemVisible(const FXFoldingItem* item) const {
823   if(!item){ fxerror("%s::isItemVisible: item is NULL.\n",getClassName()); }
824   return 0<pos_y+header->getHeight()+item->y+item->getHeight(this) && pos_y+header->getHeight()+item->y<viewport_h;
825   }
826 
827 
828 // Make item fully visible
makeItemVisible(FXFoldingItem * item)829 void FXFoldingList::makeItemVisible(FXFoldingItem* item){
830   register FXint hh=header->getHeight();
831   register FXFoldingItem *par;
832   register FXint y,h;
833   if(item){
834 
835     // Expand parents of this node
836     if(!(options&FOLDINGLIST_AUTOSELECT)){
837       for(par=item->parent; par; par=par->parent){
838         expandTree(par);
839         }
840       }
841 
842     // Now we adjust the scrolled position to fit everything
843     if(xid){
844 
845       // Force layout if dirty
846       if(flags&FLAG_RECALC) layout();
847 
848       y=pos_y;
849       h=item->getHeight(this);
850 
851       if(viewport_h<=y+item->y+h+hh) y=viewport_h-item->y-h-hh;
852       if(y+item->y<=0) y=-item->y;
853 
854       setPosition(pos_x,y);
855       }
856     }
857   }
858 
859 
860 // Get item at position x,y
getItemAt(FXint,FXint y) const861 FXFoldingItem* FXFoldingList::getItemAt(FXint,FXint y) const {
862   register FXint hh=header->getHeight();
863   register FXFoldingItem* item=firstitem;
864   register FXint ix,iy,ih;
865   ix=pos_x;
866   iy=pos_y+hh;
867   if(options&FOLDINGLIST_ROOT_BOXES) ix+=(4+indent);
868   while(item && iy<=y){
869     ih=item->getHeight(this);
870     if(y<iy+ih) return item;
871     iy+=ih;
872     if(item->first && ((options&FOLDINGLIST_AUTOSELECT) || item->isExpanded())){
873       ix+=(indent+ih/2);
874       item=item->first;
875       continue;
876       }
877     while(!item->next && item->parent){
878       item=item->parent;
879       ix-=(indent+item->getHeight(this)/2);
880       }
881     item=item->next;
882     }
883   return NULL;
884   }
885 
886 
887 // Did we hit the item, and which part of it did we hit (0=outside, 1=icon, 2=text, 3=box)
hitItem(const FXFoldingItem * item,FXint x,FXint y) const888 FXint FXFoldingList::hitItem(const FXFoldingItem* item,FXint x,FXint y) const {
889   register FXint hh=header->getHeight();
890   register FXint ix,iy,ih,xh,yh,hit=0;
891   if(item){
892     x-=pos_x;
893     y-=pos_y;
894     ix=item->x;
895     iy=item->y+hh;
896     ih=item->getHeight(this);
897     if(iy<=y && y<iy+ih){
898       if((options&FOLDINGLIST_SHOWS_BOXES) && (item->hasItems() || item->getFirst())){
899         xh=ix-indent+(SIDE_SPACING/2);
900         yh=iy+ih/2;
901         if(xh-HALFBOX_SIZE-BOX_FUDGE<=x && x<=xh+HALFBOX_SIZE+BOX_FUDGE && yh-HALFBOX_SIZE-BOX_FUDGE<=y && y<=yh+HALFBOX_SIZE+BOX_FUDGE) return 3;
902         }
903       hit=item->hitItem(this,x-ix,y-iy);
904       }
905     }
906   return hit;
907   }
908 
909 
910 // Repaint
updateItem(FXFoldingItem * item)911 void FXFoldingList::updateItem(FXFoldingItem* item){
912   if(item) update(0,pos_y+item->y+header->getHeight(),width,item->getHeight(this));
913   }
914 
915 
916 // Enable one item
enableItem(FXFoldingItem * item)917 FXbool FXFoldingList::enableItem(FXFoldingItem* item){
918   if(!item){ fxerror("%s::enableItem: item is NULL.\n",getClassName()); }
919   if(!item->isEnabled()){
920     item->setEnabled(TRUE);
921     updateItem(item);
922     return TRUE;
923     }
924   return FALSE;
925   }
926 
927 
928 // Disable one item
disableItem(FXFoldingItem * item)929 FXbool FXFoldingList::disableItem(FXFoldingItem* item){
930   if(!item){ fxerror("%s::disableItem: item is NULL.\n",getClassName()); }
931   if(item->isEnabled()){
932     item->setEnabled(FALSE);
933     updateItem(item);
934     return TRUE;
935     }
936   return FALSE;
937   }
938 
939 
940 // Select one item
selectItem(FXFoldingItem * item,FXbool notify)941 FXbool FXFoldingList::selectItem(FXFoldingItem* item,FXbool notify){
942   if(!item){ fxerror("%s::selectItem: NULL argument.\n",getClassName()); }
943   if(!item->isSelected()){
944     switch(options&SELECT_MASK){
945       case FOLDINGLIST_SINGLESELECT:
946       case FOLDINGLIST_BROWSESELECT:
947         killSelection(notify);
948       case FOLDINGLIST_EXTENDEDSELECT:
949       case FOLDINGLIST_MULTIPLESELECT:
950         item->setSelected(TRUE);
951         updateItem(item);
952         if(notify && target){target->tryHandle(this,FXSEL(SEL_SELECTED,message),(void*)item);}
953         break;
954       }
955     return TRUE;
956     }
957   return FALSE;
958   }
959 
960 
961 // Deselect one item
deselectItem(FXFoldingItem * item,FXbool notify)962 FXbool FXFoldingList::deselectItem(FXFoldingItem* item,FXbool notify){
963   if(!item){ fxerror("%s::deselectItem: item is NULL.\n",getClassName()); }
964   if(item->isSelected()){
965     switch(options&SELECT_MASK){
966       case FOLDINGLIST_EXTENDEDSELECT:
967       case FOLDINGLIST_MULTIPLESELECT:
968       case FOLDINGLIST_SINGLESELECT:
969         item->setSelected(FALSE);
970         updateItem(item);
971         if(notify && target){target->tryHandle(this,FXSEL(SEL_DESELECTED,message),(void*)item);}
972         break;
973       }
974     return TRUE;
975     }
976   return FALSE;
977   }
978 
979 
980 // toggle one item
toggleItem(FXFoldingItem * item,FXbool notify)981 FXbool FXFoldingList::toggleItem(FXFoldingItem* item,FXbool notify){
982   if(!item){ fxerror("%s::toggleItem: item is NULL.\n",getClassName()); }
983   switch(options&SELECT_MASK){
984     case FOLDINGLIST_BROWSESELECT:
985       if(!item->isSelected()){
986         killSelection(notify);
987         item->setSelected(TRUE);
988         updateItem(item);
989         if(notify && target){target->tryHandle(this,FXSEL(SEL_SELECTED,message),(void*)item);}
990         }
991       break;
992     case FOLDINGLIST_SINGLESELECT:
993       if(!item->isSelected()){
994         killSelection(notify);
995         item->setSelected(TRUE);
996         updateItem(item);
997         if(notify && target){target->tryHandle(this,FXSEL(SEL_SELECTED,message),(void*)item);}
998         }
999       else{
1000         item->setSelected(FALSE);
1001         updateItem(item);
1002         if(notify && target){target->tryHandle(this,FXSEL(SEL_DESELECTED,message),(void*)item);}
1003         }
1004       break;
1005     case FOLDINGLIST_EXTENDEDSELECT:
1006     case FOLDINGLIST_MULTIPLESELECT:
1007       if(!item->isSelected()){
1008         item->setSelected(TRUE);
1009         updateItem(item);
1010         if(notify && target){target->tryHandle(this,FXSEL(SEL_SELECTED,message),(void*)item);}
1011         }
1012       else{
1013         item->setSelected(FALSE);
1014         updateItem(item);
1015         if(notify && target){target->tryHandle(this,FXSEL(SEL_DESELECTED,message),(void*)item);}
1016         }
1017       break;
1018     }
1019   return TRUE;
1020   }
1021 
1022 
1023 
1024 // Extend selection
extendSelection(FXFoldingItem * item,FXbool notify)1025 FXbool FXFoldingList::extendSelection(FXFoldingItem* item,FXbool notify){
1026   register FXFoldingItem *it,*i1,*i2,*i3;
1027   register FXbool changes=FALSE;
1028   if(item && anchoritem && extentitem){
1029     it=firstitem;
1030     i1=i2=i3=NULL;
1031 
1032     // Find segments
1033     while(it){
1034       if(it==item){i1=i2;i2=i3;i3=it;}
1035       if(it==anchoritem){i1=i2;i2=i3;i3=it;}
1036       if(it==extentitem){i1=i2;i2=i3;i3=it;}
1037       it=it->getBelow();
1038       }
1039 
1040     FXASSERT(i1 && i2 && i3);
1041 
1042     // First segment
1043     it=i1;
1044     while(it!=i2){
1045 
1046       // item = extent - anchor
1047       // item = anchor - extent
1048       if(i1==item){
1049         if(!it->isSelected()){
1050           it->setSelected(TRUE);
1051           updateItem(it);
1052           changes=TRUE;
1053           if(notify && target){target->tryHandle(this,FXSEL(SEL_SELECTED,message),(void*)it);}
1054           }
1055         }
1056 
1057       // extent = anchor - item
1058       // extent = item   - anchor
1059       else if(i1==extentitem){
1060         if(it->isSelected()){
1061           it->setSelected(FALSE);
1062           updateItem(it);
1063           changes=TRUE;
1064           if(notify && target){target->tryHandle(this,FXSEL(SEL_DESELECTED,message),(void*)it);}
1065           }
1066         }
1067       it=it->getBelow();
1068       }
1069 
1070     // Second segment
1071     it=i2;
1072     while(it!=i3){
1073       it=it->getBelow();
1074 
1075       // extent - anchor = item
1076       // anchor - extent = item
1077       if(i3==item){
1078         if(!it->isSelected()){
1079           it->setSelected(TRUE);
1080           updateItem(it);
1081           changes=TRUE;
1082           if(notify && target){target->tryHandle(this,FXSEL(SEL_SELECTED,message),(void*)it);}
1083           }
1084         }
1085 
1086       // item   - anchor = extent
1087       // anchor - item   = extent
1088       else if(i3==extentitem){
1089         if(it->isSelected()){
1090           it->setSelected(FALSE);
1091           updateItem(it);
1092           changes=TRUE;
1093           if(notify && target){target->tryHandle(this,FXSEL(SEL_DESELECTED,message),(void*)it);}
1094           }
1095         }
1096       }
1097     extentitem=item;
1098     }
1099   return changes;
1100   }
1101 
1102 
1103 // Kill selection
killSelection(FXbool notify)1104 FXbool FXFoldingList::killSelection(FXbool notify){
1105   register FXFoldingItem *item=firstitem;
1106   register FXbool changes=FALSE;
1107   while(item){
1108     if(item->isSelected()){
1109       item->setSelected(FALSE);
1110       updateItem(item);
1111       changes=TRUE;
1112       if(notify && target){target->tryHandle(this,FXSEL(SEL_DESELECTED,message),(void*)item);}
1113       }
1114     item=item->getBelow();
1115     }
1116   return changes;
1117   }
1118 
1119 
1120 // Open item
openItem(FXFoldingItem * item,FXbool notify)1121 FXbool FXFoldingList::openItem(FXFoldingItem* item,FXbool notify){
1122   if(item==NULL){ fxerror("%s::openItem: item is NULL.\n",getClassName()); }
1123   if(!item->isOpened()){
1124     item->setOpened(TRUE);
1125     updateItem(item);
1126     if(notify && target){target->tryHandle(this,FXSEL(SEL_OPENED,message),(void*)item);}
1127     return TRUE;
1128     }
1129   return FALSE;
1130   }
1131 
1132 
1133 // Close item
closeItem(FXFoldingItem * item,FXbool notify)1134 FXbool FXFoldingList::closeItem(FXFoldingItem* item,FXbool notify){
1135   if(item==NULL){ fxerror("%s::closeItem: item is NULL.\n",getClassName()); }
1136   if(item->isOpened()){
1137     item->setOpened(FALSE);
1138     updateItem(item);
1139     if(notify && target){target->tryHandle(this,FXSEL(SEL_CLOSED,message),(void*)item);}
1140     return TRUE;
1141     }
1142   return FALSE;
1143   }
1144 
1145 
1146 // Collapse all subtrees under item
collapseTree(FXFoldingItem * tree,FXbool notify)1147 FXbool FXFoldingList::collapseTree(FXFoldingItem* tree,FXbool notify){
1148   if(tree==NULL){ fxerror("%s::collapseTree: tree is NULL.\n",getClassName()); }
1149   if(tree->isExpanded()){
1150     tree->setExpanded(FALSE);
1151     if(!(options&FOLDINGLIST_AUTOSELECT)){     // In autoselect, already shown as expanded!
1152       if(tree->first){
1153         recalc();
1154         }
1155       else{
1156         updateItem(tree);
1157         }
1158       }
1159     if(notify && target){target->tryHandle(this,FXSEL(SEL_COLLAPSED,message),(void*)tree);}
1160     return TRUE;
1161     }
1162   return FALSE;
1163   }
1164 
1165 
1166 // Expand subtree under item
expandTree(FXFoldingItem * tree,FXbool notify)1167 FXbool FXFoldingList::expandTree(FXFoldingItem* tree,FXbool notify){
1168   if(tree==NULL){ fxerror("%s::expandTree: tree is NULL.\n",getClassName()); }
1169   if(!tree->isExpanded()){
1170     tree->setExpanded(TRUE);
1171     if(!(options&FOLDINGLIST_AUTOSELECT)){     // In autoselect, already shown as expanded!
1172       if(tree->first){
1173         recalc();
1174         }
1175       else{
1176         updateItem(tree);
1177         }
1178       }
1179     if(notify && target){target->tryHandle(this,FXSEL(SEL_EXPANDED,message),(void*)tree);}
1180     return TRUE;
1181     }
1182   return FALSE;
1183   }
1184 
1185 
1186 // Start motion timer while in this window
onEnter(FXObject * sender,FXSelector sel,void * ptr)1187 long FXFoldingList::onEnter(FXObject* sender,FXSelector sel,void* ptr){
1188   FXScrollArea::onEnter(sender,sel,ptr);
1189   getApp()->addTimeout(this,ID_TIPTIMER,getApp()->getMenuPause());
1190   cursoritem=NULL;
1191   return 1;
1192   }
1193 
1194 
1195 // Stop motion timer when leaving window
onLeave(FXObject * sender,FXSelector sel,void * ptr)1196 long FXFoldingList::onLeave(FXObject* sender,FXSelector sel,void* ptr){
1197   FXScrollArea::onLeave(sender,sel,ptr);
1198   getApp()->removeTimeout(this,ID_TIPTIMER);
1199   cursoritem=NULL;
1200   return 1;
1201   }
1202 
1203 
1204 // We timed out, i.e. the user didn't move for a while
onTipTimer(FXObject *,FXSelector,void *)1205 long FXFoldingList::onTipTimer(FXObject*,FXSelector,void*){
1206   FXTRACE((200,"%s::onTipTimer %p\n",getClassName(),this));
1207   flags|=FLAG_TIP;
1208   return 1;
1209   }
1210 
1211 
1212 // We were asked about tip text
onQueryTip(FXObject * sender,FXSelector sel,void * ptr)1213 long FXFoldingList::onQueryTip(FXObject* sender,FXSelector sel,void* ptr){
1214   if(FXWindow::onQueryTip(sender,sel,ptr)) return 1;
1215   if((flags&FLAG_TIP) && !(options&FOLDINGLIST_AUTOSELECT)){   // No tip when autoselect!
1216     FXint x,y; FXuint buttons;
1217     getCursorPosition(x,y,buttons);
1218     FXFoldingItem *item=getItemAt(x,y);
1219     if(item){
1220       FXString string=item->getText().section('\t',0);
1221       sender->handle(this,FXSEL(SEL_COMMAND,ID_SETSTRINGVALUE),(void*)&string);
1222       return 1;
1223       }
1224     }
1225   return 0;
1226   }
1227 
1228 
1229 // We were asked about status text
onQueryHelp(FXObject * sender,FXSelector sel,void * ptr)1230 long FXFoldingList::onQueryHelp(FXObject* sender,FXSelector sel,void* ptr){
1231   if(FXWindow::onQueryHelp(sender,sel,ptr)) return 1;
1232   if((flags&FLAG_HELP) && !help.empty()){
1233     sender->handle(this,FXSEL(SEL_COMMAND,ID_SETSTRINGVALUE),(void*)&help);
1234     return 1;
1235     }
1236   return 0;
1237   }
1238 
1239 
1240 // Gained focus
onFocusIn(FXObject * sender,FXSelector sel,void * ptr)1241 long FXFoldingList::onFocusIn(FXObject* sender,FXSelector sel,void* ptr){
1242   FXScrollArea::onFocusIn(sender,sel,ptr);
1243   if(currentitem){
1244     currentitem->setFocus(TRUE);
1245     updateItem(currentitem);
1246     }
1247   return 1;
1248   }
1249 
1250 
1251 // Lost focus
onFocusOut(FXObject * sender,FXSelector sel,void * ptr)1252 long FXFoldingList::onFocusOut(FXObject* sender,FXSelector sel,void* ptr){
1253   FXScrollArea::onFocusOut(sender,sel,ptr);
1254   if(currentitem){
1255     currentitem->setFocus(FALSE);
1256     updateItem(currentitem);
1257     }
1258   return 1;
1259   }
1260 
1261 
1262 // Draw item list
onPaint(FXObject *,FXSelector,void * ptr)1263 long FXFoldingList::onPaint(FXObject*,FXSelector,void* ptr){
1264   FXEvent* event=(FXEvent*)ptr;
1265   FXFoldingItem* item=firstitem;
1266   FXFoldingItem* p;
1267   FXint yh,xh,x,y,w,h,xp,hh;
1268   FXDCWindow dc(this,event);
1269   dc.setFont(font);
1270   if(header->getNumItems()==0){
1271     dc.setForeground(backColor);
1272     dc.fillRectangle(0,0,width,height);
1273     return 1;
1274     }
1275   x=pos_x;
1276   y=pos_y+header->getHeight();
1277   if(options&FOLDINGLIST_ROOT_BOXES) x+=(4+indent);
1278   while(item && y<event->rect.y+event->rect.h){
1279     w=item->getWidth(this);
1280     h=item->getHeight(this);
1281     if(event->rect.y<=y+h){
1282 
1283       // Draw item
1284       dc.setForeground(backColor);
1285       dc.fillRectangle(0,y,width,h);
1286       item->draw(this,dc,x,y,w,h);
1287 
1288       // Show other paraphernalia such as dotted lines and expand-boxes
1289       if((options&(FOLDINGLIST_SHOWS_LINES|FOLDINGLIST_SHOWS_BOXES)) && (item->parent || (options&FOLDINGLIST_ROOT_BOXES))){
1290         dc.setClipRectangle(header->getX(),y,header->getItemSize(0),h);
1291         hh=h/2;
1292         yh=y+hh;
1293         xh=x-indent+(SIDE_SPACING/2);
1294         dc.setForeground(lineColor);
1295         dc.setStipple(STIPPLE_GRAY,pos_x&1,pos_y&1);
1296         if(options&FOLDINGLIST_SHOWS_LINES){                   // Connect items with lines
1297           p=item->parent;
1298           xp=xh;
1299           dc.setFillStyle(FILL_STIPPLED);
1300           while(p){
1301             xp-=(indent+p->getHeight(this)/2);
1302             if(p->next) dc.fillRectangle(xp,y,1,h);
1303             p=p->parent;
1304             }
1305           if((options&FOLDINGLIST_SHOWS_BOXES) && (item->hasItems() || item->getFirst())){
1306             if(item->prev || item->parent) dc.fillRectangle(xh,y,1,yh-y-HALFBOX_SIZE);
1307             if(item->next) dc.fillRectangle(xh,yh+HALFBOX_SIZE,1,y+h-yh-HALFBOX_SIZE);
1308             }
1309           else{
1310             if(item->prev || item->parent) dc.fillRectangle(xh,y,1,hh);
1311             if( item->next) dc.fillRectangle(xh,yh,1,h);
1312             dc.fillRectangle(xh,yh,x+(SIDE_SPACING/2)-2-xh,1);
1313             }
1314           dc.setFillStyle(FILL_SOLID);
1315           }
1316 
1317         // Boxes before items for expand/collapse of item
1318         if((options&FOLDINGLIST_SHOWS_BOXES) && (item->hasItems() || item->getFirst())){
1319           dc.setFillStyle(FILL_STIPPLED);
1320           dc.fillRectangle(xh+4,yh,(SIDE_SPACING/2)-2,1);
1321           dc.setFillStyle(FILL_SOLID);
1322           dc.drawRectangle(xh-HALFBOX_SIZE,yh-HALFBOX_SIZE,HALFBOX_SIZE+HALFBOX_SIZE,HALFBOX_SIZE+HALFBOX_SIZE);
1323           dc.setForeground(textColor);
1324           dc.fillRectangle(xh-HALFBOX_SIZE+2,yh,HALFBOX_SIZE+HALFBOX_SIZE-3,1);
1325           if(!(options&FOLDINGLIST_AUTOSELECT) && !item->isExpanded()){
1326             dc.fillRectangle(xh,yh-HALFBOX_SIZE+2,1,HALFBOX_SIZE+HALFBOX_SIZE-3);
1327             }
1328           }
1329         dc.clearClipRectangle();
1330         }
1331       }
1332 
1333     y+=h;
1334 
1335     // Move on to the next item
1336     if(item->first && ((options&FOLDINGLIST_AUTOSELECT) || item->isExpanded())){
1337       x+=(indent+h/2);
1338       item=item->first;
1339       continue;
1340       }
1341     while(!item->next && item->parent){
1342       item=item->parent;
1343       x-=(indent+item->getHeight(this)/2);
1344       }
1345     item=item->next;
1346     }
1347   if(y<event->rect.y+event->rect.h){
1348     dc.setForeground(backColor);
1349     dc.fillRectangle(event->rect.x,y,event->rect.w,event->rect.y+event->rect.h-y);
1350     }
1351   return 1;
1352   }
1353 
1354 
1355 // Zero out lookup string
onLookupTimer(FXObject *,FXSelector,void *)1356 long FXFoldingList::onLookupTimer(FXObject*,FXSelector,void*){
1357   lookup=FXString::null;
1358   return 1;
1359   }
1360 
1361 
1362 // Key Press
onKeyPress(FXObject *,FXSelector,void * ptr)1363 long FXFoldingList::onKeyPress(FXObject*,FXSelector,void* ptr){
1364   FXEvent* event=(FXEvent*)ptr;
1365   FXFoldingItem *item=currentitem;
1366   flags&=~FLAG_TIP;
1367   if(!isEnabled()) return 0;
1368   if(target && target->tryHandle(this,FXSEL(SEL_KEYPRESS,message),ptr)) return 1;
1369   if(item==NULL) item=firstitem;
1370   switch(event->code){
1371     case KEY_Control_L:
1372     case KEY_Control_R:
1373     case KEY_Shift_L:
1374     case KEY_Shift_R:
1375     case KEY_Alt_L:
1376     case KEY_Alt_R:
1377       if(flags&FLAG_DODRAG){handle(this,FXSEL(SEL_DRAGGED,0),ptr);}
1378       return 1;
1379     case KEY_Page_Up:
1380     case KEY_KP_Page_Up:
1381       lookup=FXString::null;
1382       setPosition(pos_x,pos_y+verticalScrollBar()->getPage());
1383       return 1;
1384     case KEY_Page_Down:
1385     case KEY_KP_Page_Down:
1386       lookup=FXString::null;
1387       setPosition(pos_x,pos_y-verticalScrollBar()->getPage());
1388       return 1;
1389     case KEY_Up:                          // Move up
1390     case KEY_KP_Up:
1391       if(item){
1392         if(item->prev){
1393           item=item->prev;
1394           while(item->first && ((options&FOLDINGLIST_AUTOSELECT) || item->isExpanded())) item=item->last;
1395           }
1396         else if(item->parent){
1397           item=item->parent;
1398           }
1399         }
1400       goto hop;
1401     case KEY_Down:                        // Move down
1402     case KEY_KP_Down:
1403       if(item){
1404         if(item->first && ((options&FOLDINGLIST_AUTOSELECT) || item->isExpanded())){
1405           item=item->first;
1406           }
1407         else{
1408           while(!item->next && item->parent) item=item->parent;
1409           item=item->next;
1410           }
1411         }
1412       goto hop;
1413     case KEY_Right:                       // Move right/down and open subtree
1414     case KEY_KP_Right:
1415       if(item){
1416         if(!(options&FOLDINGLIST_AUTOSELECT) && !item->isExpanded() && (item->hasItems() || item->getFirst())){
1417           expandTree(item,TRUE);
1418           }
1419         else if(item->first){
1420           item=item->first;
1421           }
1422         else{
1423           while(!item->next && item->parent) item=item->parent;
1424           item=item->next;
1425           }
1426         }
1427       goto hop;
1428     case KEY_Left:                        // Move left/up and close subtree
1429     case KEY_KP_Left:
1430       if(item){
1431         if(!(options&FOLDINGLIST_AUTOSELECT) && item->isExpanded() && (item->hasItems() || item->getFirst())){
1432           collapseTree(item,TRUE);
1433           }
1434         else if(item->parent){
1435           item=item->parent;
1436           }
1437         else if(item->prev){
1438           item=item->prev;
1439           }
1440         }
1441       goto hop;
1442     case KEY_Home:                        // Move to first
1443     case KEY_KP_Home:
1444       item=firstitem;
1445       goto hop;
1446     case KEY_End:                         // Move to last
1447     case KEY_KP_End:
1448       item=lastitem;
1449       while(item){
1450         if(item->last && ((options&FOLDINGLIST_AUTOSELECT) || item->isExpanded())){
1451           item=item->last;
1452           }
1453         else if(item->next){
1454           item=item->next;
1455           }
1456         else{
1457           break;
1458           }
1459         }
1460 hop:  lookup=FXString::null;
1461       if(item){
1462         setCurrentItem(item,TRUE);
1463         makeItemVisible(item);
1464         if((options&SELECT_MASK)==FOLDINGLIST_EXTENDEDSELECT){
1465           if(item->isEnabled()){
1466             if(event->state&SHIFTMASK){
1467               if(anchoritem){
1468                 selectItem(anchoritem,TRUE);
1469                 extendSelection(item,TRUE);
1470                 }
1471               else{
1472                 selectItem(item,TRUE);
1473                 setAnchorItem(item);
1474                 }
1475               }
1476             else if(!(event->state&CONTROLMASK)){
1477               killSelection(TRUE);
1478               selectItem(item,TRUE);
1479               setAnchorItem(item);
1480               }
1481             }
1482           }
1483         }
1484       handle(this,FXSEL(SEL_CLICKED,0),(void*)currentitem);
1485       if(currentitem && currentitem->isEnabled()){
1486         handle(this,FXSEL(SEL_COMMAND,0),(void*)currentitem);
1487         }
1488       return 1;
1489     case KEY_space:
1490     case KEY_KP_Space:
1491       lookup=FXString::null;
1492       if(item && item->isEnabled()){
1493         switch(options&SELECT_MASK){
1494           case FOLDINGLIST_EXTENDEDSELECT:
1495             if(event->state&SHIFTMASK){
1496               if(anchoritem){
1497                 selectItem(anchoritem,TRUE);
1498                 extendSelection(item,TRUE);
1499                 }
1500               else{
1501                 selectItem(item,TRUE);
1502                 }
1503               }
1504             else if(event->state&CONTROLMASK){
1505               toggleItem(item,TRUE);
1506               }
1507             else{
1508               killSelection(TRUE);
1509               selectItem(item,TRUE);
1510               }
1511             break;
1512           case FOLDINGLIST_MULTIPLESELECT:
1513           case FOLDINGLIST_SINGLESELECT:
1514             toggleItem(item,TRUE);
1515             break;
1516           }
1517         setAnchorItem(item);
1518         }
1519       handle(this,FXSEL(SEL_CLICKED,0),(void*)currentitem);
1520       if(currentitem && currentitem->isEnabled()){
1521         handle(this,FXSEL(SEL_COMMAND,0),(void*)currentitem);
1522         }
1523       return 1;
1524     case KEY_Return:
1525     case KEY_KP_Enter:
1526       lookup=FXString::null;
1527       handle(this,FXSEL(SEL_DOUBLECLICKED,0),(void*)currentitem);
1528       if(currentitem && currentitem->isEnabled()){
1529         handle(this,FXSEL(SEL_COMMAND,0),(void*)currentitem);
1530         }
1531       return 1;
1532     default:
1533       if((FXuchar)event->text[0]<' ') return 0;
1534       if(event->state&(CONTROLMASK|ALTMASK)) return 0;
1535       if(!isprint((FXuchar)event->text[0])) return 0;
1536       lookup.append(event->text);
1537       getApp()->addTimeout(this,ID_LOOKUPTIMER,getApp()->getTypingSpeed());
1538       item=findItem(lookup,currentitem,SEARCH_FORWARD|SEARCH_WRAP|SEARCH_PREFIX);
1539       if(item){
1540 	setCurrentItem(item,TRUE);
1541 	makeItemVisible(item);
1542 	if((options&SELECT_MASK)==FOLDINGLIST_EXTENDEDSELECT){
1543 	  if(item->isEnabled()){
1544 	    killSelection(TRUE);
1545 	    selectItem(item,TRUE);
1546 	    }
1547 	  }
1548 	setAnchorItem(item);
1549         }
1550       handle(this,FXSEL(SEL_CLICKED,0),(void*)currentitem);
1551       if(currentitem && currentitem->isEnabled()){
1552 	handle(this,FXSEL(SEL_COMMAND,0),(void*)currentitem);
1553 	}
1554       return 1;
1555     }
1556   return 0;
1557   }
1558 
1559 
1560 // Key Release
onKeyRelease(FXObject *,FXSelector,void * ptr)1561 long FXFoldingList::onKeyRelease(FXObject*,FXSelector,void* ptr){
1562   FXEvent* event=(FXEvent*)ptr;
1563   if(!isEnabled()) return 0;
1564   if(target && target->tryHandle(this,FXSEL(SEL_KEYRELEASE,message),ptr)) return 1;
1565   switch(event->code){
1566     case KEY_Shift_L:
1567     case KEY_Shift_R:
1568     case KEY_Control_L:
1569     case KEY_Control_R:
1570     case KEY_Alt_L:
1571     case KEY_Alt_R:
1572       if(flags&FLAG_DODRAG){handle(this,FXSEL(SEL_DRAGGED,0),ptr);}
1573       return 1;
1574     }
1575   return 0;
1576   }
1577 
1578 
1579 // Scroll timer
onAutoScroll(FXObject * sender,FXSelector sel,void * ptr)1580 long FXFoldingList::onAutoScroll(FXObject* sender,FXSelector sel,void* ptr){
1581   FXEvent* event=(FXEvent*)ptr;
1582   FXFoldingItem *item;
1583   FXint xx,yy;
1584 
1585   // Scroll the content
1586   FXScrollArea::onAutoScroll(sender,sel,ptr);
1587 
1588   // Drag and drop mode
1589   if(flags&FLAG_DODRAG){
1590     handle(this,FXSEL(SEL_DRAGGED,0),ptr);
1591     return 1;
1592     }
1593 
1594   // In autoselect mode, stop scrolling when mouse outside window
1595   if((flags&FLAG_PRESSED) || (options&FOLDINGLIST_AUTOSELECT)){
1596 
1597     // Validated position
1598     xx=event->win_x; if(xx<0) xx=0; else if(xx>=viewport_w) xx=viewport_w-1;
1599     yy=event->win_y; if(yy<0) yy=0; else if(yy>=viewport_h) yy=viewport_h-1;
1600 
1601     // Find item
1602     item=getItemAt(xx,yy);
1603 
1604     // Got item and different from last time
1605     if(item && item!=currentitem){
1606 
1607       // Make it the current item
1608       setCurrentItem(item,TRUE);
1609 
1610       // Extend the selection
1611       if((options&SELECT_MASK)==FOLDINGLIST_EXTENDEDSELECT){
1612         state=FALSE;
1613         extendSelection(item,TRUE);
1614         }
1615       }
1616     return 1;
1617     }
1618   return 0;
1619   }
1620 
1621 
1622 // Mouse motion
onMotion(FXObject *,FXSelector,void * ptr)1623 long FXFoldingList::onMotion(FXObject*,FXSelector,void* ptr){
1624   FXEvent* event=(FXEvent*)ptr;
1625   FXFoldingItem *oldcursoritem=cursoritem;
1626   FXuint flg=flags;
1627   FXFoldingItem *item;
1628 
1629   // Kill the tip
1630   flags&=~FLAG_TIP;
1631 
1632   // Kill the tip timer
1633   getApp()->removeTimeout(this,ID_TIPTIMER);
1634 
1635   // Right mouse scrolling
1636   if(flags&FLAG_SCROLLING){
1637     setPosition(event->win_x-grabx,event->win_y-graby);
1638     return 1;
1639     }
1640 
1641   // Drag and drop mode
1642   if(flags&FLAG_DODRAG){
1643     if(startAutoScroll(event,TRUE)) return 1;
1644     handle(this,FXSEL(SEL_DRAGGED,0),ptr);
1645     return 1;
1646     }
1647 
1648   // Tentative drag and drop
1649   if((flags&FLAG_TRYDRAG) && event->moved){
1650     flags&=~FLAG_TRYDRAG;
1651     if(handle(this,FXSEL(SEL_BEGINDRAG,0),ptr)){
1652       flags|=FLAG_DODRAG;
1653       }
1654     return 1;
1655     }
1656 
1657   // Normal operation
1658   if((flags&FLAG_PRESSED) || (options&FOLDINGLIST_AUTOSELECT)){
1659 
1660     // Start auto scrolling?
1661     if(startAutoScroll(event,FALSE)) return 1;
1662 
1663     // Find item
1664     item=getItemAt(event->win_x,event->win_y);
1665 
1666     // Got an item different from before
1667     if(item && item!=currentitem){
1668 
1669       // Make it the current item
1670       setCurrentItem(item,TRUE);
1671 
1672       // Extend the selection
1673       if((options&SELECT_MASK)==FOLDINGLIST_EXTENDEDSELECT){
1674         state=FALSE;
1675         extendSelection(item,TRUE);
1676         }
1677       }
1678     return 1;
1679     }
1680 
1681   // Reset tip timer if nothing's going on
1682   getApp()->addTimeout(this,ID_TIPTIMER,getApp()->getMenuPause());
1683 
1684   // Get item we're over
1685   cursoritem=getItemAt(event->win_x,event->win_y);
1686 
1687   // Force GUI update only when needed
1688   return (cursoritem!=oldcursoritem)||(flg&FLAG_TIP);
1689   }
1690 
1691 
1692 // Pressed a button
onLeftBtnPress(FXObject *,FXSelector,void * ptr)1693 long FXFoldingList::onLeftBtnPress(FXObject*,FXSelector,void* ptr){
1694   FXEvent* event=(FXEvent*)ptr;
1695   FXFoldingItem *item;
1696   FXint code;
1697   flags&=~FLAG_TIP;
1698   handle(this,FXSEL(SEL_FOCUS_SELF,0),ptr);
1699   if(isEnabled()){
1700     grab();
1701     flags&=~FLAG_UPDATE;
1702 
1703     // First chance callback
1704     if(target && target->tryHandle(this,FXSEL(SEL_LEFTBUTTONPRESS,message),ptr)) return 1;
1705 
1706     // Not autoselect mode
1707     if(options&FOLDINGLIST_AUTOSELECT) return 1;
1708 
1709     // Locate item
1710     item=getItemAt(event->win_x,event->win_y);
1711 
1712     // No item
1713     if(item==NULL){
1714       if((options&SELECT_MASK)==FOLDINGLIST_EXTENDEDSELECT){
1715         if(!(event->state&(SHIFTMASK|CONTROLMASK))){
1716           killSelection(TRUE);
1717           }
1718         }
1719       return 1;
1720       }
1721 
1722     // Find out where hit
1723     code=hitItem(item,event->win_x,event->win_y);
1724 
1725     // Maybe clicked on box
1726     if(code==3){
1727       if(isItemExpanded(item))
1728         collapseTree(item,TRUE);
1729       else
1730         expandTree(item,TRUE);
1731       return 1;
1732       }
1733 
1734     // Change current item
1735     setCurrentItem(item,TRUE);
1736 
1737     // Change item selection
1738     state=item->isSelected();
1739     switch(options&SELECT_MASK){
1740       case FOLDINGLIST_EXTENDEDSELECT:
1741         if(event->state&SHIFTMASK){
1742           if(anchoritem){
1743             if(anchoritem->isEnabled()) selectItem(anchoritem,TRUE);
1744             extendSelection(item,TRUE);
1745             }
1746           else{
1747             if(item->isEnabled()) selectItem(item,TRUE);
1748             setAnchorItem(item);
1749             }
1750           }
1751         else if(event->state&CONTROLMASK){
1752           if(item->isEnabled() && !state) selectItem(item,TRUE);
1753           setAnchorItem(item);
1754           }
1755         else{
1756           if(item->isEnabled() && !state){ killSelection(TRUE); selectItem(item,TRUE); }
1757           setAnchorItem(item);
1758           }
1759         break;
1760       case FOLDINGLIST_MULTIPLESELECT:
1761       case FOLDINGLIST_SINGLESELECT:
1762         if(item->isEnabled() && !state) selectItem(item,TRUE);
1763         break;
1764       }
1765 
1766     // Start drag if actually pressed text or icon only
1767     if(code && item->isSelected() && item->isDraggable()){
1768       flags|=FLAG_TRYDRAG;
1769       }
1770 
1771     flags|=FLAG_PRESSED;
1772     return 1;
1773     }
1774   return 0;
1775   }
1776 
1777 
1778 // Released button
onLeftBtnRelease(FXObject *,FXSelector,void * ptr)1779 long FXFoldingList::onLeftBtnRelease(FXObject*,FXSelector,void* ptr){
1780   FXEvent* event=(FXEvent*)ptr;
1781   FXuint flg=flags;
1782   if(isEnabled()){
1783     ungrab();
1784     stopAutoScroll();
1785     flags|=FLAG_UPDATE;
1786     flags&=~(FLAG_PRESSED|FLAG_TRYDRAG|FLAG_DODRAG);
1787 
1788     // First chance callback
1789     if(target && target->tryHandle(this,FXSEL(SEL_LEFTBUTTONRELEASE,message),ptr)) return 1;
1790 
1791     // No activity
1792     if(!(flg&FLAG_PRESSED) && !(options&FOLDINGLIST_AUTOSELECT)) return 1;
1793 
1794     // Was dragging
1795     if(flg&FLAG_DODRAG){
1796       handle(this,FXSEL(SEL_ENDDRAG,0),ptr);
1797       return 1;
1798       }
1799 
1800     // Select only enabled item
1801     switch(options&SELECT_MASK){
1802       case FOLDINGLIST_EXTENDEDSELECT:
1803         if(currentitem && currentitem->isEnabled()){
1804           if(event->state&CONTROLMASK){
1805             if(state) deselectItem(currentitem,TRUE);
1806             }
1807           else if(!(event->state&SHIFTMASK)){
1808             if(state){ killSelection(TRUE); selectItem(currentitem,TRUE); }
1809             }
1810           }
1811         break;
1812       case FOLDINGLIST_MULTIPLESELECT:
1813       case FOLDINGLIST_SINGLESELECT:
1814         if(currentitem && currentitem->isEnabled()){
1815           if(state) deselectItem(currentitem,TRUE);
1816           }
1817         break;
1818       }
1819 
1820     // Scroll to make item visibke
1821     makeItemVisible(currentitem);
1822 
1823     // Update anchor
1824     setAnchorItem(currentitem);
1825 
1826     // Generate clicked callbacks
1827     if(event->click_count==1){
1828       handle(this,FXSEL(SEL_CLICKED,0),(void*)currentitem);
1829       }
1830     else if(event->click_count==2){
1831       handle(this,FXSEL(SEL_DOUBLECLICKED,0),(void*)currentitem);
1832       }
1833     else if(event->click_count==3){
1834       handle(this,FXSEL(SEL_TRIPLECLICKED,0),(void*)currentitem);
1835       }
1836 
1837     // Command callback only when clicked on item
1838     if(currentitem && currentitem->isEnabled()){
1839       handle(this,FXSEL(SEL_COMMAND,0),(void*)currentitem);
1840       }
1841     return 1;
1842     }
1843   return 0;
1844   }
1845 
1846 
1847 // Pressed right button
onRightBtnPress(FXObject *,FXSelector,void * ptr)1848 long FXFoldingList::onRightBtnPress(FXObject*,FXSelector,void* ptr){
1849   FXEvent* event=(FXEvent*)ptr;
1850   flags&=~FLAG_TIP;
1851   handle(this,FXSEL(SEL_FOCUS_SELF,0),ptr);
1852   if(isEnabled()){
1853     grab();
1854     flags&=~FLAG_UPDATE;
1855     if(target && target->tryHandle(this,FXSEL(SEL_RIGHTBUTTONPRESS,message),ptr)) return 1;
1856     flags|=FLAG_SCROLLING;
1857     grabx=event->win_x-pos_x;
1858     graby=event->win_y-pos_y;
1859     return 1;
1860     }
1861   return 0;
1862   }
1863 
1864 
1865 // Released right button
onRightBtnRelease(FXObject *,FXSelector,void * ptr)1866 long FXFoldingList::onRightBtnRelease(FXObject*,FXSelector,void* ptr){
1867   if(isEnabled()){
1868     ungrab();
1869     flags&=~FLAG_SCROLLING;
1870     flags|=FLAG_UPDATE;
1871     if(target && target->tryHandle(this,FXSEL(SEL_RIGHTBUTTONRELEASE,message),ptr)) return 1;
1872     return 1;
1873     }
1874   return 0;
1875   }
1876 
1877 
1878 
1879 // The widget lost the grab for some reason
onUngrabbed(FXObject * sender,FXSelector sel,void * ptr)1880 long FXFoldingList::onUngrabbed(FXObject* sender,FXSelector sel,void* ptr){
1881   FXScrollArea::onUngrabbed(sender,sel,ptr);
1882   flags&=~(FLAG_DODRAG|FLAG_TRYDRAG|FLAG_PRESSED|FLAG_CHANGED|FLAG_SCROLLING);
1883   flags|=FLAG_UPDATE;
1884   stopAutoScroll();
1885   return 1;
1886   }
1887 
1888 
1889 // Command message
onCommand(FXObject *,FXSelector,void * ptr)1890 long FXFoldingList::onCommand(FXObject*,FXSelector,void* ptr){
1891   return target && target->tryHandle(this,FXSEL(SEL_COMMAND,message),ptr);
1892   }
1893 
1894 
1895 // Clicked in list
onClicked(FXObject *,FXSelector,void * ptr)1896 long FXFoldingList::onClicked(FXObject*,FXSelector,void* ptr){
1897   return target && target->tryHandle(this,FXSEL(SEL_CLICKED,message),ptr);
1898   }
1899 
1900 
1901 // Double clicked in list; ptr may or may not point to an item
onDoubleClicked(FXObject *,FXSelector,void * ptr)1902 long FXFoldingList::onDoubleClicked(FXObject*,FXSelector,void* ptr){
1903 
1904   // Double click anywhere in the widget
1905   if(target && target->tryHandle(this,FXSEL(SEL_DOUBLECLICKED,message),ptr)) return 1;
1906 
1907   // Double click on an item
1908   if(ptr){
1909     if(isItemExpanded((FXFoldingItem*)ptr))
1910       collapseTree((FXFoldingItem*)ptr,TRUE);
1911     else
1912       expandTree((FXFoldingItem*)ptr,TRUE);
1913     }
1914   return 0;
1915   }
1916 
1917 
1918 // Triple clicked in list; ptr may or may not point to an item
onTripleClicked(FXObject *,FXSelector,void * ptr)1919 long FXFoldingList::onTripleClicked(FXObject*,FXSelector,void* ptr){
1920   return target && target->tryHandle(this,FXSEL(SEL_TRIPLECLICKED,message),ptr);
1921   }
1922 
1923 
1924 // Sort items in ascending order
ascending(const FXFoldingItem * a,const FXFoldingItem * b)1925 FXint FXFoldingList::ascending(const FXFoldingItem* a,const FXFoldingItem* b){
1926   register const FXuchar *p=(const FXuchar*)a->getText().text();
1927   register const FXuchar *q=(const FXuchar*)b->getText().text();
1928   while(1){
1929     if(*p > *q) return 1;
1930     if(*p < *q) return -1;
1931     if(*p <= '\t') return 0;
1932     p++;
1933     q++;
1934     }
1935   return 0;
1936   }
1937 
1938 
1939 // Sort items in descending order
descending(const FXFoldingItem * a,const FXFoldingItem * b)1940 FXint FXFoldingList::descending(const FXFoldingItem* a,const FXFoldingItem* b){
1941   return FXFoldingList::ascending(b,a);
1942   }
1943 
1944 
1945 // Sort ascending order, case insensitive
ascendingCase(const FXFoldingItem * a,const FXFoldingItem * b)1946 FXint FXFoldingList::ascendingCase(const FXFoldingItem* a,const FXFoldingItem* b){
1947   register const FXuchar *p=(const FXuchar*)a->getText().text();
1948   register const FXuchar *q=(const FXuchar*)b->getText().text();
1949   while(1){
1950     if(tolower((FXuchar)*p) > tolower((FXuchar)*q)) return 1;
1951     if(tolower((FXuchar)*p) < tolower((FXuchar)*q)) return -1;
1952     if(*p <= '\t') return 0;
1953     p++;
1954     q++;
1955     }
1956   return 0;
1957   }
1958 
1959 
1960 // Sort descending order, case insensitive
descendingCase(const FXFoldingItem * a,const FXFoldingItem * b)1961 FXint FXFoldingList::descendingCase(const FXFoldingItem* a,const FXFoldingItem* b){
1962   return FXFoldingList::ascendingCase(b,a);
1963   }
1964 
1965 
1966 // Sort items
sort(FXFoldingItem * & f1,FXFoldingItem * & t1,FXFoldingItem * & f2,FXFoldingItem * & t2,int n)1967 void FXFoldingList::sort(FXFoldingItem*& f1,FXFoldingItem*& t1,FXFoldingItem*& f2,FXFoldingItem*& t2,int n){
1968   FXFoldingItem *ff1,*tt1,*ff2,*tt2,*q;
1969   FXint m;
1970   if(f2==NULL){
1971     f1=NULL;
1972     t1=NULL;
1973     return;
1974     }
1975   if(n>1){
1976     m=n/2;
1977     n=n-m;
1978     sort(ff1,tt1,f2,t2,n);  // 1 or more
1979     sort(ff2,tt2,f2,t2,m);  // 0 or more
1980     FXASSERT(ff1);
1981     if(ff2 && sortfunc(ff1,ff2)>0){
1982       f1=ff2;
1983       ff2->prev=NULL;
1984       ff2=ff2->next;
1985       }
1986     else{
1987       f1=ff1;
1988       ff1->prev=NULL;
1989       ff1=ff1->next;
1990       }
1991     t1=f1;
1992     t1->next=NULL;
1993     while(ff1 || ff2){
1994       if(ff1==NULL){ t1->next=ff2; ff2->prev=t1; t1=tt2; break; }
1995       if(ff2==NULL){ t1->next=ff1; ff1->prev=t1; t1=tt1; break; }
1996       if(sortfunc(ff1,ff2)>0){
1997         t1->next=ff2;
1998         ff2->prev=t1;
1999         t1=ff2;
2000         ff2=ff2->next;
2001         }
2002       else{
2003         t1->next=ff1;
2004         ff1->prev=t1;
2005         t1=ff1;
2006         ff1=ff1->next;
2007         }
2008       t1->next=NULL;
2009       }
2010     return;
2011     }
2012   FXASSERT(f2);
2013   f1=f2;
2014   t1=f2;
2015   f2=f2->next;
2016   while(f2){
2017     f2->prev=NULL;
2018     if(sortfunc(f2,t1)>0){
2019       t1->next=f2;
2020       f2->prev=t1;
2021       t1=f2;
2022       f2=f2->next;
2023       continue;
2024       }
2025     if(sortfunc(f1,f2)>0){
2026       q=f2;
2027       f2=f2->next;
2028       q->next=f1;
2029       f1->prev=q;
2030       f1=q;
2031       continue;
2032       }
2033     break;
2034     }
2035   FXASSERT(f1);
2036   FXASSERT(t1);
2037   f1->prev=NULL;
2038   t1->next=NULL;
2039   }
2040 
2041 
2042 // Sort the items based on the sort function
sortRootItems()2043 void FXFoldingList::sortRootItems(){
2044   if(sortfunc){
2045     FXFoldingItem* f=firstitem;
2046     FXFoldingItem* l=lastitem;
2047     sort(firstitem,lastitem,f,l,getNumItems());
2048     recalc();
2049     }
2050   }
2051 
2052 
2053 // Sort child items
sortChildItems(FXFoldingItem * item)2054 void FXFoldingList::sortChildItems(FXFoldingItem* item){
2055   if(sortfunc){
2056     FXFoldingItem* f=item->first;
2057     FXFoldingItem* l=item->last;
2058     sort(item->first,item->last,f,l,item->getNumChildren());
2059     if(item->isExpanded()) recalc();     // No need to recalc if it ain't visible!
2060     }
2061   }
2062 
2063 
2064 // Sort all items recursively
sortItems()2065 void FXFoldingList::sortItems(){
2066   register FXFoldingItem *item;
2067   if(sortfunc){
2068     sortRootItems();
2069     item=firstitem;
2070     while(item){
2071       sortChildItems(item);
2072       if(item->first){item=item->first;continue;}
2073       while(!item->next && item->parent){item=item->parent;}
2074       item=item->next;
2075       }
2076     }
2077   }
2078 
2079 
2080 // Set current item
setCurrentItem(FXFoldingItem * item,FXbool notify)2081 void FXFoldingList::setCurrentItem(FXFoldingItem* item,FXbool notify){
2082   if(item!=currentitem){
2083 
2084     // Deactivate old item
2085     if(currentitem){
2086 
2087       // No visible change if it doen't have the focus
2088       if(hasFocus()){
2089         currentitem->setFocus(FALSE);
2090         updateItem(currentitem);
2091         }
2092 
2093       // Close old item
2094       closeItem(currentitem,notify);
2095       }
2096 
2097     currentitem=item;
2098 
2099     // Activate new item
2100     if(currentitem){
2101 
2102       // No visible change if it doen't have the focus
2103       if(hasFocus()){
2104         currentitem->setFocus(TRUE);
2105         updateItem(currentitem);
2106         }
2107 
2108       // Open new item
2109       openItem(currentitem,notify);
2110       }
2111 
2112     // Notify item change
2113     if(notify && target){target->tryHandle(this,FXSEL(SEL_CHANGED,message),(void*)currentitem);}
2114     }
2115 
2116   // Select if browse mode
2117   if((options&SELECT_MASK)==FOLDINGLIST_BROWSESELECT && currentitem && currentitem->isEnabled()){
2118     selectItem(currentitem,notify);
2119     }
2120   }
2121 
2122 
2123 // Set anchor item
setAnchorItem(FXFoldingItem * item)2124 void FXFoldingList::setAnchorItem(FXFoldingItem* item){
2125   anchoritem=item;
2126   extentitem=item;
2127   }
2128 
2129 
2130 
2131 // Create item
createItem(const FXString & text,FXIcon * oi,FXIcon * ci,void * ptr)2132 FXFoldingItem* FXFoldingList::createItem(const FXString& text,FXIcon* oi,FXIcon* ci,void* ptr){
2133   return new FXFoldingItem(text,oi,ci,ptr);
2134   }
2135 
2136 
2137 // Insert item under father before other item
insertItem(FXFoldingItem * other,FXFoldingItem * father,FXFoldingItem * item,FXbool notify)2138 FXFoldingItem* FXFoldingList::insertItem(FXFoldingItem* other,FXFoldingItem* father,FXFoldingItem* item,FXbool notify){
2139   register FXFoldingItem* olditem=currentitem;
2140 
2141   // Verify correctness of arguments
2142   if(!item){ fxerror("%s::insertItem: NULL item argument.\n",getClassName()); }
2143   if(other && other->parent!=father){ fxerror("%s::insertItem: bad argument.\n",getClassName()); }
2144 
2145   // Hang item into the list
2146   if(father){
2147     if(other){
2148       item->next=other;
2149       item->prev=other->prev;
2150       other->prev=item;
2151       }
2152     else{
2153       item->next=NULL;
2154       item->prev=father->last;
2155       father->last=item;
2156       }
2157     if(item->prev) item->prev->next=item; else father->first=item;
2158     }
2159   else{
2160     if(other){
2161       item->next=other;
2162       item->prev=other->prev;
2163       other->prev=item;
2164       }
2165     else{
2166       item->next=NULL;
2167       item->prev=lastitem;
2168       lastitem=item;
2169       }
2170     if(item->prev) item->prev->next=item; else firstitem=item;
2171     }
2172 
2173   // Fill in the rest
2174   item->parent=father;
2175   item->first=NULL;
2176   item->last=NULL;
2177   item->x=0;
2178   item->y=0;
2179 
2180   // Make current if just added
2181   if(!currentitem && item==lastitem) currentitem=item;
2182 
2183   // Notify item has been inserted
2184   if(notify && target){target->tryHandle(this,FXSEL(SEL_INSERTED,message),(void*)item);}
2185 
2186   // Current item may have changed
2187   if(olditem!=currentitem){
2188     if(notify && target){target->tryHandle(this,FXSEL(SEL_CHANGED,message),(void*)currentitem);}
2189     }
2190 
2191   // Was new item
2192   if(currentitem==item){
2193     if(hasFocus()){
2194       currentitem->setFocus(TRUE);
2195       }
2196     if((options&SELECT_MASK)==FOLDINGLIST_BROWSESELECT && currentitem->isEnabled()){
2197       selectItem(currentitem,notify);
2198       }
2199     }
2200 
2201   // Redo layout
2202   recalc();
2203   return item;
2204   }
2205 
2206 
2207 // Insert item under father before other item
insertItem(FXFoldingItem * other,FXFoldingItem * father,const FXString & text,FXIcon * oi,FXIcon * ci,void * ptr,FXbool notify)2208 FXFoldingItem* FXFoldingList::insertItem(FXFoldingItem* other,FXFoldingItem* father,const FXString& text,FXIcon* oi,FXIcon* ci,void* ptr,FXbool notify){
2209   return insertItem(other,father,createItem(text,oi,ci,ptr),notify);
2210   }
2211 
2212 
2213 // Append item under father
appendItem(FXFoldingItem * father,FXFoldingItem * item,FXbool notify)2214 FXFoldingItem* FXFoldingList::appendItem(FXFoldingItem* father,FXFoldingItem* item,FXbool notify){
2215   return insertItem(NULL,father,item,notify);
2216   }
2217 
2218 
2219 // Append item under father
appendItem(FXFoldingItem * father,const FXString & text,FXIcon * oi,FXIcon * ci,void * ptr,FXbool notify)2220 FXFoldingItem* FXFoldingList::appendItem(FXFoldingItem* father,const FXString& text,FXIcon* oi,FXIcon* ci,void* ptr,FXbool notify){
2221   return insertItem(NULL,father,createItem(text,oi,ci,ptr),notify);
2222   }
2223 
2224 
2225 // Prepend item under father
prependItem(FXFoldingItem * father,FXFoldingItem * item,FXbool notify)2226 FXFoldingItem* FXFoldingList::prependItem(FXFoldingItem* father,FXFoldingItem* item,FXbool notify){
2227   return insertItem(father?father->first:firstitem,father,item,notify);
2228   }
2229 
2230 // Prepend item under father
prependItem(FXFoldingItem * father,const FXString & text,FXIcon * oi,FXIcon * ci,void * ptr,FXbool notify)2231 FXFoldingItem* FXFoldingList::prependItem(FXFoldingItem* father,const FXString& text,FXIcon* oi,FXIcon* ci,void* ptr,FXbool notify){
2232   return insertItem(father?father->first:firstitem,father,createItem(text,oi,ci,ptr),notify);
2233   }
2234 
2235 
2236 // Fill list by appending items from array of strings
fillItems(FXFoldingItem * father,const FXchar ** strings,FXIcon * oi,FXIcon * ci,void * ptr,FXbool notify)2237 FXint FXFoldingList::fillItems(FXFoldingItem* father,const FXchar** strings,FXIcon* oi,FXIcon* ci,void* ptr,FXbool notify){
2238   register FXint n=0;
2239   if(strings){
2240     while(strings[n]){
2241       appendItem(father,strings[n++],oi,ci,ptr,notify);
2242       }
2243     }
2244   return n;
2245   }
2246 
2247 
2248 // Fill list by appending items from newline separated strings
fillItems(FXFoldingItem * father,const FXString & strings,FXIcon * oi,FXIcon * ci,void * ptr,FXbool notify)2249 FXint FXFoldingList::fillItems(FXFoldingItem* father,const FXString& strings,FXIcon* oi,FXIcon* ci,void* ptr,FXbool notify){
2250   register FXint n=0;
2251   FXString text;
2252   while(!(text=strings.section('\n',n)).empty()){
2253     appendItem(father,text,oi,ci,ptr,notify);
2254     n++;
2255     }
2256   return n;
2257   }
2258 
2259 
2260 // Move item under father before other item
moveItem(FXFoldingItem * other,FXFoldingItem * father,FXFoldingItem * item)2261 FXFoldingItem *FXFoldingList::moveItem(FXFoldingItem* other,FXFoldingItem* father,FXFoldingItem* item){
2262 
2263   // Verify arguments
2264   if(!item){ fxerror("%s::moveItem: NULL item argument.\n",getClassName()); }
2265   if(other && other->parent!=father){ fxerror("%s::moveItem: bad argument.\n",getClassName()); }
2266 
2267   // Can't move in front of itself
2268   if(item!=other){
2269 
2270     // Unlink from current spot
2271     if(item->prev) item->prev->next=item->next; else if(item->parent) item->parent->first=item->next; else firstitem=item->next;
2272     if(item->next) item->next->prev=item->prev; else if(item->parent) item->parent->last=item->prev; else lastitem=item->prev;
2273 
2274     // Hang item into the list
2275     if(father){
2276       if(other){
2277         item->next=other;
2278         item->prev=other->prev;
2279         other->prev=item;
2280         }
2281       else{
2282         item->next=NULL;
2283         item->prev=father->last;
2284         father->last=item;
2285         }
2286       if(item->prev) item->prev->next=item; else father->first=item;
2287       }
2288     else{
2289       if(other){
2290         item->next=other;
2291         item->prev=other->prev;
2292         other->prev=item;
2293         }
2294       else{
2295         item->next=NULL;
2296         item->prev=lastitem;
2297         lastitem=item;
2298         }
2299       if(item->prev) item->prev->next=item; else firstitem=item;
2300       }
2301 
2302     // Fill in the rest
2303     item->parent=father;
2304 
2305     // Redo layout
2306     recalc();
2307     }
2308   return item;
2309   }
2310 
2311 
2312 // Remove all siblings from [fm,to]
removeItems(FXFoldingItem * fm,FXFoldingItem * to,FXbool notify)2313 void FXFoldingList::removeItems(FXFoldingItem* fm,FXFoldingItem* to,FXbool notify){
2314   register FXFoldingItem *olditem=currentitem;
2315   register FXFoldingItem *prv,*nxt,*par;
2316   if(fm && to){
2317     if(fm->parent!=to->parent){ fxerror("%s::removeItems: arguments have different parent.\n",getClassName()); }
2318 
2319     // Delete items
2320     while(1){
2321 
2322       // Scan till end
2323       while(to->last) to=to->last;
2324 
2325       do{
2326 
2327         // Notify item will be deleted
2328         if(notify && target){target->tryHandle(this,FXSEL(SEL_DELETED,message),(void*)to);}
2329 
2330         // Remember hookups
2331         nxt=to->next;
2332         prv=to->prev;
2333         par=to->parent;
2334 
2335          // Adjust pointers; suggested by Alan Ott <ott@acusoft.com>
2336         if(anchoritem==to){ anchoritem=par; if(prv) anchoritem=prv; if(nxt) anchoritem=nxt; }
2337         if(extentitem==to){ extentitem=par; if(prv) extentitem=prv; if(nxt) extentitem=nxt; }
2338         if(currentitem==to){ currentitem=par; if(prv) currentitem=prv; if(nxt) currentitem=nxt; }
2339 
2340         // Remove item from list
2341         if(prv) prv->next=nxt; else if(par) par->first=nxt; else firstitem=nxt;
2342         if(nxt) nxt->prev=prv; else if(par) par->last=prv; else lastitem=prv;
2343 
2344         // Delete it
2345         delete to;
2346 
2347         // Was last one?
2348         if(to==fm) goto x;
2349         to=par;
2350         }
2351       while(!prv);
2352       to=prv;
2353       }
2354 
2355     // Current item has changed
2356 x:  if(olditem!=currentitem){
2357       if(notify && target){target->tryHandle(this,FXSEL(SEL_CHANGED,message),(void*)currentitem);}
2358       }
2359 
2360     // Deleted current item
2361     if(currentitem && currentitem!=olditem){
2362       if(hasFocus()){
2363         currentitem->setFocus(TRUE);
2364         }
2365       if((options&SELECT_MASK)==FOLDINGLIST_BROWSESELECT && currentitem->isEnabled()){
2366         selectItem(currentitem,notify);
2367         }
2368       }
2369 
2370     // Redo layout
2371     recalc();
2372     }
2373   }
2374 
2375 
2376 // Remove node from list
removeItem(FXFoldingItem * item,FXbool notify)2377 void FXFoldingList::removeItem(FXFoldingItem* item,FXbool notify){
2378   removeItems(item,item,notify);
2379   }
2380 
2381 
2382 // Remove all items
clearItems(FXbool notify)2383 void FXFoldingList::clearItems(FXbool notify){
2384   removeItems(firstitem,lastitem,notify);
2385   }
2386 
2387 
2388 typedef FXint (*FXCompareFunc)(const FXString&,const FXString &,FXint);
2389 
2390 
2391 // Get item by name
findItem(const FXString & text,FXFoldingItem * start,FXuint flgs) const2392 FXFoldingItem* FXFoldingList::findItem(const FXString& text,FXFoldingItem* start,FXuint flgs) const {
2393   register FXCompareFunc comparefunc;
2394   register FXFoldingItem *item;
2395   register FXint len;
2396   if(firstitem){
2397     comparefunc=(flgs&SEARCH_IGNORECASE) ? (FXCompareFunc)comparecase : (FXCompareFunc)compare;
2398     len=(flgs&SEARCH_PREFIX)?text.length():2147483647;
2399     if(flgs&SEARCH_BACKWARD){
2400       item=start;
2401       while(item!=NULL){
2402         if((*comparefunc)(item->getText(),text,len)==0) return item;
2403         item=item->getAbove();
2404         }
2405       if(start && !(flgs&SEARCH_WRAP)) return NULL;
2406       for(item=lastitem; item->getLast(); item=item->getLast());
2407       while(item!=start){
2408         if((*comparefunc)(item->getText(),text,len)==0) return item;
2409         item=item->getAbove();
2410         }
2411       }
2412     else{
2413       item=start;
2414       while(item!=NULL){
2415         if((*comparefunc)(item->getText(),text,len)==0) return item;
2416         item=item->getBelow();
2417         }
2418       if(start && !(flgs&SEARCH_WRAP)) return NULL;
2419       item=firstitem;
2420       while(item!=start){
2421         if((*comparefunc)(item->getText(),text,len)==0) return item;
2422         item=item->getBelow();
2423         }
2424       }
2425     }
2426   return NULL;
2427   }
2428 
2429 
2430 // Get item by data
findItemByData(const void * ptr,FXFoldingItem * start,FXuint flgs) const2431 FXFoldingItem* FXFoldingList::findItemByData(const void *ptr,FXFoldingItem* start,FXuint flgs) const {
2432   register FXFoldingItem *item;
2433   if(firstitem){
2434     if(flgs&SEARCH_BACKWARD){
2435       item=start;
2436       while(item!=NULL){
2437         if(item->getData()==ptr) return item;
2438         item=item->getAbove();
2439         }
2440       if(start && !(flgs&SEARCH_WRAP)) return NULL;
2441       for(item=lastitem; item->getLast(); item=item->getLast());
2442       while(item!=start){
2443         if(item->getData()==ptr) return item;
2444         item=item->getAbove();
2445         }
2446       }
2447     else{
2448       item=start;
2449       while(item!=NULL){
2450         if(item->getData()==ptr) return item;
2451         item=item->getBelow();
2452         }
2453       if(start && !(flgs&SEARCH_WRAP)) return NULL;
2454       item=firstitem;
2455       while(item!=start){
2456         if(item->getData()==ptr) return item;
2457         item=item->getBelow();
2458         }
2459       }
2460     }
2461   return NULL;
2462   }
2463 
2464 
2465 // Change the font
setFont(FXFont * fnt)2466 void FXFoldingList::setFont(FXFont* fnt){
2467   if(!fnt){ fxerror("%s::setFont: NULL font specified.\n",getClassName()); }
2468   if(font!=fnt){
2469     font=fnt;
2470     recalc();
2471     update();
2472     }
2473   }
2474 
2475 
2476 // Change help text
setHelpText(const FXString & text)2477 void FXFoldingList::setHelpText(const FXString& text){
2478   help=text;
2479   }
2480 
2481 
2482 // Set text color
setTextColor(FXColor clr)2483 void FXFoldingList::setTextColor(FXColor clr){
2484   if(clr!=textColor){
2485     textColor=clr;
2486     update();
2487     }
2488   }
2489 
2490 
2491 // Set select background color
setSelBackColor(FXColor clr)2492 void FXFoldingList::setSelBackColor(FXColor clr){
2493   if(clr!=selbackColor){
2494     selbackColor=clr;
2495     update();
2496     }
2497   }
2498 
2499 
2500 // Set selected text color
setSelTextColor(FXColor clr)2501 void FXFoldingList::setSelTextColor(FXColor clr){
2502   if(clr!=seltextColor){
2503     seltextColor=clr;
2504     update();
2505     }
2506   }
2507 
2508 
2509 // Set line color
setLineColor(FXColor clr)2510 void FXFoldingList::setLineColor(FXColor clr){
2511   if(clr!=lineColor){
2512     lineColor=clr;
2513     update();
2514     }
2515   }
2516 
2517 
2518 // Set parent to child indent amount
setIndent(FXint in)2519 void FXFoldingList::setIndent(FXint in){
2520   if(indent!=in){
2521     indent=in;
2522     recalc();
2523     }
2524   }
2525 
2526 
2527 // Change list style
setListStyle(FXuint style)2528 void FXFoldingList::setListStyle(FXuint style){
2529   FXuint opts=(options&~FOLDINGLIST_MASK) | (style&FOLDINGLIST_MASK);
2530   if(options!=opts){
2531     options=opts;
2532     recalc();
2533     }
2534   }
2535 
2536 
2537 // Get list style
getListStyle() const2538 FXuint FXFoldingList::getListStyle() const {
2539   return (options&FOLDINGLIST_MASK);
2540   }
2541 
2542 
2543 // Save data
save(FXStream & store) const2544 void FXFoldingList::save(FXStream& store) const {
2545   FXScrollArea::save(store);
2546   store << header;
2547   store << firstitem;
2548   store << lastitem;
2549   store << anchoritem;
2550   store << currentitem;
2551   store << extentitem;
2552   store << font;
2553   store << textColor;
2554   store << selbackColor;
2555   store << seltextColor;
2556   store << lineColor;
2557   store << treeWidth;
2558   store << treeHeight;
2559   store << visible;
2560   store << indent;
2561   store << help;
2562   }
2563 
2564 
2565 // Load data
load(FXStream & store)2566 void FXFoldingList::load(FXStream& store){
2567   FXScrollArea::load(store);
2568   store >> header;
2569   store >> firstitem;
2570   store >> lastitem;
2571   store >> anchoritem;
2572   store >> currentitem;
2573   store >> extentitem;
2574   store >> font;
2575   store >> textColor;
2576   store >> selbackColor;
2577   store >> seltextColor;
2578   store >> lineColor;
2579   store >> treeWidth;
2580   store >> treeHeight;
2581   store >> visible;
2582   store >> indent;
2583   store >> help;
2584   }
2585 
2586 
2587 // Cleanup
~FXFoldingList()2588 FXFoldingList::~FXFoldingList(){
2589   getApp()->removeTimeout(this,ID_TIPTIMER);
2590   getApp()->removeTimeout(this,ID_LOOKUPTIMER);
2591   clearItems(FALSE);
2592   header=(FXHeader*)-1L;
2593   firstitem=(FXFoldingItem*)-1L;
2594   lastitem=(FXFoldingItem*)-1L;
2595   anchoritem=(FXFoldingItem*)-1L;
2596   currentitem=(FXFoldingItem*)-1L;
2597   extentitem=(FXFoldingItem*)-1L;
2598   font=(FXFont*)-1L;
2599   }
2600 
2601 }
2602 
2603