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