1 /********************************************************************************
2 *                                                                               *
3 *                               H e a d e r   O b j e c t                       *
4 *                                                                               *
5 *********************************************************************************
6 * Copyright (C) 1997,2020 by Jeroen van der Zijp.   All Rights Reserved.        *
7 *********************************************************************************
8 * This library is free software; you can redistribute it and/or modify          *
9 * it under the terms of the GNU Lesser General Public License as published by   *
10 * the Free Software Foundation; either version 3 of the License, or             *
11 * (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                 *
16 * GNU Lesser General Public License for more details.                           *
17 *                                                                               *
18 * You should have received a copy of the GNU Lesser General Public License      *
19 * along with this program.  If not, see <http://www.gnu.org/licenses/>          *
20 ********************************************************************************/
21 #include "xincs.h"
22 #include "fxver.h"
23 #include "fxdefs.h"
24 #include "fxmath.h"
25 #include "FXArray.h"
26 #include "FXHash.h"
27 #include "FXMutex.h"
28 #include "FXStream.h"
29 #include "FXString.h"
30 #include "FXObjectList.h"
31 #include "FXSize.h"
32 #include "FXPoint.h"
33 #include "FXRectangle.h"
34 #include "FXStringDictionary.h"
35 #include "FXSettings.h"
36 #include "FXRegistry.h"
37 #include "FXFont.h"
38 #include "FXEvent.h"
39 #include "FXWindow.h"
40 #include "FXDCWindow.h"
41 #include "FXApp.h"
42 #include "FXIcon.h"
43 #include "FXHeader.h"
44 
45 
46 
47 
48 /*
49   Notes:
50   - Perhaps, some way to drive via keyboard?
51   - Allow some header items to be stretchable.
52   - Add minimum, maximum size constraints to items.
53   - Should up/down arrows go sideways when vertically oriented?
54   - Perhaps perform drawing of border in item also.
55   - Like for FXScrollArea, pos is always <=0 when scrolled.
56   - Maybe handy feature to initialize size to default item width
57     if initial size = 0.
58   - Maybe allow attach from right instead of only from left; perhaps
59     also attach both (or none).
60 */
61 
62 
63 #define FUDGE         4
64 #define ICON_SPACING  4
65 #define HEADER_MASK   (HEADER_BUTTON|HEADER_TRACKING|HEADER_VERTICAL|HEADER_RESIZE)
66 
67 using namespace FX;
68 
69 /*******************************************************************************/
70 
71 namespace FX {
72 
73 
74 // Object implementation
75 FXIMPLEMENT(FXHeaderItem,FXObject,NULL,0)
76 
77 
78 // Construct new item with given text, icon, size, and user-data
FXHeaderItem(const FXString & text,FXIcon * ic,FXint s,void * ptr)79 FXHeaderItem::FXHeaderItem(const FXString& text,FXIcon* ic,FXint s,void* ptr):icon(ic),data(ptr),size(s),pos(0),state(LEFT|BEFORE){
80   label=text.section('\t', 0);
81   tip=text.section('\t', 1);
82   }
83 
84 
85 // Draw item
draw(const FXHeader * header,FXDC & dc,FXint x,FXint y,FXint w,FXint h) const86 void FXHeaderItem::draw(const FXHeader* header,FXDC& dc,FXint x,FXint y,FXint w,FXint h) const {
87   FXint tx,ty,tw,th,ix,iy,iw,ih,s,ml,mr,mt,mb,beg,end,t,xx,yy,bb,aa,ax,ay;
88   FXFont *font=header->getFont();
89 
90   // Get border width and padding
91   bb=header->getBorderWidth();
92   ml=header->getPadLeft()+bb;
93   mr=header->getPadRight()+bb;
94   mt=header->getPadTop()+bb;
95   mb=header->getPadBottom()+bb;
96 
97   // Shrink by margins
98   x+=ml; w-=ml+mr;
99   y+=mt; h-=mt+mb;
100 
101   // Initial clip rectangle
102   dc.setClipRectangle(x,y,w,h);
103 
104   // Text width and height
105   tw=th=iw=ih=beg=s=0;
106   do{
107     end=beg;
108     while(end<label.length() && label[end]!='\n') end++;
109     if((t=font->getTextWidth(&label[beg],end-beg))>tw) tw=t;
110     th+=font->getFontHeight();
111     beg=end+1;
112     }
113   while(end<label.length());
114 
115   // Icon size
116   if(icon){
117     iw=icon->getWidth();
118     ih=icon->getHeight();
119     }
120 
121   // Icon-text spacing
122   if(iw && tw) s=ICON_SPACING;
123 
124   // Draw arrows
125 #if 1
126   if(state&(ARROW_UP|ARROW_DOWN)){
127     aa=(font->getFontHeight()-5)|1;
128     ay=y+(h-aa)/2;
129     ax=x+w-aa-2;
130     if(state&ARROW_UP){
131       dc.setForeground(header->getHiliteColor());
132       dc.drawLine(ax+aa/2,ay,ax+aa-1,ay+aa);
133       dc.drawLine(ax,ay+aa,ax+aa,ay+aa);
134       dc.setForeground(header->getShadowColor());
135       dc.drawLine(ax+aa/2,ay,ax,ay+aa);
136       }
137     else{
138       dc.setForeground(header->getHiliteColor());
139       dc.drawLine(ax+aa/2,ay+aa,ax+aa-1,ay);
140       dc.setForeground(header->getShadowColor());
141       dc.drawLine(ax+aa/2,ay+aa,ax,ay);
142       dc.drawLine(ax,ay,ax+aa,ay);
143       }
144     w-=aa+4;
145     dc.setClipRectangle(x,y,w,h);
146     }
147 #endif
148 #if 0
149   if(state&(ARROW_UP|ARROW_DOWN)){
150     FXPoint points[3];
151     aa=(font->getFontHeight()-5)|1;
152     ay=y+(h-aa)/2;
153     ax=x+w-aa-2;
154     if(state&ARROW_UP){
155       points[0].set(ax+(aa>>1),ay-1);
156       points[1].set(ax,ay+aa);
157       points[2].set(ax+aa-1,ay+aa);
158       dc.setForeground(header->getShadowColor());
159       dc.fillPolygon(points,3);
160       }
161     else{
162       points[0].set(ax+aa,ay);
163       points[1].set(ax+(aa>>1),ay+aa);
164       points[2].set(ax+1,ay);
165       dc.setForeground(header->getShadowColor());
166       dc.fillPolygon(points,3);
167       }
168     w-=aa+4;
169     dc.setClipRectangle(x,y,w,h);
170     }
171 #endif
172 
173   // Fix x coordinate
174   if(state&LEFT){
175     if(state&BEFORE){ ix=x; tx=ix+iw+s; }
176     else if(state&AFTER){ tx=x; ix=tx+tw+s; }
177     else{ ix=x; tx=x; }
178     }
179   else if(state&RIGHT){
180     if(state&BEFORE){ tx=x+w-tw; ix=tx-iw-s; }
181     else if(state&AFTER){ ix=x+w-iw; tx=ix-tw-s; }
182     else{ ix=x+w-iw; tx=x+w-tw; }
183     }
184   else{
185     if(state&BEFORE){ ix=x+(w-tw-iw-s)/2; tx=ix+iw+s; }
186     else if(state&AFTER){ tx=x+(w-tw-iw-s)/2; ix=tx+tw+s; }
187     else{ ix=x+(w-iw)/2; tx=x+(w-tw)/2; }
188     }
189 
190   // Fix y coordinate
191   if(state&TOP){
192     if(state&ABOVE){ iy=y; ty=iy+ih; }
193     else if(state&BELOW){ ty=y; iy=ty+th; }
194     else{ iy=y; ty=y; }
195     }
196   else if(state&BOTTOM){
197     if(state&ABOVE){ ty=y+h-th; iy=ty-ih; }
198     else if(state&BELOW){ iy=y+h-ih; ty=iy-th; }
199     else{ iy=y+h-ih; ty=y+h-th; }
200     }
201   else{
202     if(state&ABOVE){ iy=y+(h-th-ih)/2; ty=iy+ih; }
203     else if(state&BELOW){ ty=y+(h-th-ih)/2; iy=ty+th; }
204     else{ iy=y+(h-ih)/2; ty=y+(h-th)/2; }
205     }
206 
207   // Offset a bit when pressed
208   if(state&PRESSED){ tx++; ty++; ix++; iy++; }
209 
210   // Paint icon
211   if(icon){
212     dc.drawIcon(icon,ix,iy);
213     }
214 
215   // Text color
216   dc.setForeground(header->getTextColor());
217 
218   // Draw text
219   yy=ty+font->getFontAscent();
220   beg=0;
221   do{
222     end=beg;
223     while(end<label.length() && label[end]!='\n') end++;
224     if(state&LEFT) xx=tx;
225     else if(state&RIGHT) xx=tx+tw-font->getTextWidth(&label[beg],end-beg);
226     else xx=tx+(tw-font->getTextWidth(&label[beg],end-beg))/2;
227     dc.drawText(xx,yy,&label[beg],end-beg);
228     yy+=font->getFontHeight();
229     beg=end+1;
230     }
231   while(end<label.length());
232 
233   // Restore original clip path
234   dc.clearClipRectangle();
235   }
236 
237 
238 // Create icon
create()239 void FXHeaderItem::create(){
240   if(icon) icon->create();
241   }
242 
243 
244 // No op, we don't own icon
destroy()245 void FXHeaderItem::destroy(){
246   if((state&ICONOWNED) && icon) icon->destroy();
247   }
248 
249 
250 // Detach from icon resource
detach()251 void FXHeaderItem::detach(){
252   if(icon) icon->detach();
253   }
254 
255 
256 // Change sort direction
setArrowDir(FXuint dir)257 void FXHeaderItem::setArrowDir(FXuint dir){
258   state^=((dir^state)&(ARROW_UP|ARROW_DOWN));
259   }
260 
261 
262 // Change sort direction
getArrowDir() const263 FXuint FXHeaderItem::getArrowDir() const {
264   return state&(ARROW_UP|ARROW_DOWN);
265   }
266 
267 
268 // Change justify mode
setJustify(FXuint justify)269 void FXHeaderItem::setJustify(FXuint justify){
270   state^=((justify^state)&(RIGHT|LEFT|TOP|BOTTOM));
271   }
272 
273 
274 // Return content justification
getJustify() const275 FXuint FXHeaderItem::getJustify() const {
276   return state&(RIGHT|LEFT|TOP|BOTTOM);
277   }
278 
279 
280 // Change icon positioning
setIconPosition(FXuint mode)281 void FXHeaderItem::setIconPosition(FXuint mode){
282   state^=((mode^state)&(BEFORE|AFTER|ABOVE|BELOW));
283   }
284 
285 
286 // Return icon position
getIconPosition() const287 FXuint FXHeaderItem::getIconPosition() const {
288   return state&(BEFORE|AFTER|ABOVE|BELOW);
289   }
290 
291 
292 // Set button state
setPressed(FXbool pressed)293 void FXHeaderItem::setPressed(FXbool pressed){
294   state^=((0-pressed)^state)&PRESSED;
295   }
296 
297 
298 // Return pressed state
isPressed() const299 FXbool FXHeaderItem::isPressed() const {
300   return (state&PRESSED)!=0;
301   }
302 
303 
304 // Get width of item
getWidth(const FXHeader * header) const305 FXint FXHeaderItem::getWidth(const FXHeader* header) const {
306   FXint ml=header->getPadLeft()+header->getBorderWidth();
307   FXint mr=header->getPadRight()+header->getBorderWidth();
308   FXFont *font=header->getFont();
309   FXint beg,end,tw,iw,s,t,w;
310   tw=iw=beg=s=0;
311   if(icon) iw=icon->getWidth();
312   do{
313     end=beg;
314     while(end<label.length() && label[end]!='\n') end++;
315     if((t=font->getTextWidth(&label[beg],end-beg))>tw) tw=t;
316     beg=end+1;
317     }
318   while(end<label.length());
319   if(iw && tw) s=4;
320   if(state&(BEFORE|AFTER))
321     w=iw+tw+s;
322   else
323     w=FXMAX(iw,tw);
324   return ml+mr+w;
325   }
326 
327 
328 // Get height of item
getHeight(const FXHeader * header) const329 FXint FXHeaderItem::getHeight(const FXHeader* header) const {
330   FXint mt=header->getPadTop()+header->getBorderWidth();
331   FXint mb=header->getPadBottom()+header->getBorderWidth();
332   FXFont *font=header->getFont();
333   FXint beg,end,th,ih,h;
334   th=ih=beg=0;
335   if(icon) ih=icon->getHeight();
336   do{
337     end=beg;
338     while(end<label.length() && label[end]!='\n') end++;
339     th+=font->getFontHeight();
340     beg=end+1;
341     }
342   while(end<label.length());
343   if(state&(ABOVE|BELOW))
344     h=ih+th;
345   else
346     h=FXMAX(ih,th);
347   return h+mt+mb;
348   }
349 
350 
351 // Change item's text label
setText(const FXString & txt)352 void FXHeaderItem::setText(const FXString& txt){
353   label=txt;
354   }
355 
356 
357 // Change item's icon
setIcon(FXIcon * icn,FXbool owned)358 void FXHeaderItem::setIcon(FXIcon* icn,FXbool owned){
359   if(icon && (state&ICONOWNED)){
360     if(icon!=icn) delete icon;
361     state&=~ICONOWNED;
362     }
363   icon=icn;
364   if(icon && owned){
365     state|=ICONOWNED;
366     }
367   icon=icn;
368   }
369 
370 
371 // Save data
save(FXStream & store) const372 void FXHeaderItem::save(FXStream& store) const {
373   FXObject::save(store);
374   store << label;
375   store << tip;
376   store << icon;
377   store << size;
378   store << pos;
379   store << state;
380   }
381 
382 
383 // Load data
load(FXStream & store)384 void FXHeaderItem::load(FXStream& store){
385   FXObject::load(store);
386   store >> label;
387   store >> tip;
388   store >> icon;
389   store >> size;
390   store >> pos;
391   store >> state;
392   }
393 
394 
395 // Delete item and free icon if owned
~FXHeaderItem()396 FXHeaderItem::~FXHeaderItem(){
397   if(state&ICONOWNED) delete icon;
398   icon=(FXIcon*)-1L;
399   }
400 
401 /*******************************************************************************/
402 
403 // Map
404 FXDEFMAP(FXHeader) FXHeaderMap[]={
405   FXMAPFUNC(SEL_PAINT,0,FXHeader::onPaint),
406   FXMAPFUNC(SEL_MOTION,0,FXHeader::onMotion),
407   FXMAPFUNC(SEL_LEFTBUTTONPRESS,0,FXHeader::onLeftBtnPress),
408   FXMAPFUNC(SEL_LEFTBUTTONRELEASE,0,FXHeader::onLeftBtnRelease),
409   FXMAPFUNC(SEL_UNGRABBED,0,FXHeader::onUngrabbed),
410   FXMAPFUNC(SEL_TIMEOUT,FXHeader::ID_TIPTIMER,FXHeader::onTipTimer),
411   FXMAPFUNC(SEL_QUERY_TIP,0,FXHeader::onQueryTip),
412   FXMAPFUNC(SEL_QUERY_HELP,0,FXHeader::onQueryHelp),
413   };
414 
415 
416 // Object implementation
FXIMPLEMENT(FXHeader,FXFrame,FXHeaderMap,ARRAYNUMBER (FXHeaderMap))417 FXIMPLEMENT(FXHeader,FXFrame,FXHeaderMap,ARRAYNUMBER(FXHeaderMap))
418 
419 
420 // Make a Header
421 FXHeader::FXHeader(){
422   flags|=FLAG_ENABLED|FLAG_SHOWN;
423   font=NULL;
424   numbering=NULL;
425   textColor=0;
426   pos=0;
427   active=-1;
428   activepos=0;
429   activesize=0;
430   offset=0;
431   }
432 
433 
434 // Make a Header
FXHeader(FXComposite * p,FXObject * tgt,FXSelector sel,FXuint opts,FXint x,FXint y,FXint w,FXint h,FXint pl,FXint pr,FXint pt,FXint pb)435 FXHeader::FXHeader(FXComposite* p,FXObject* tgt,FXSelector sel,FXuint opts,FXint x,FXint y,FXint w,FXint h,FXint pl,FXint pr,FXint pt,FXint pb):FXFrame(p,opts,x,y,w,h,pl,pr,pt,pb){
436   flags|=FLAG_ENABLED|FLAG_SHOWN;
437   target=tgt;
438   message=sel;
439   font=getApp()->getNormalFont();
440   numbering=NULL;
441   textColor=getApp()->getForeColor();
442   pos=0;
443   active=-1;
444   activepos=0;
445   activesize=0;
446   offset=0;
447   }
448 
449 
450 // Create window
create()451 void FXHeader::create(){
452   FXint i;
453   FXFrame::create();
454   for(i=0; i<items.no(); i++){items[i]->create();}
455   font->create();
456   }
457 
458 
459 // Detach window
detach()460 void FXHeader::detach(){
461   FXint i;
462   FXFrame::detach();
463   for(i=0; i<items.no(); i++){items[i]->detach();}
464   font->detach();
465   }
466 
467 
468 // Get default width
getDefaultWidth()469 FXint FXHeader::getDefaultWidth(){
470   FXint i,t,w=0;
471   if(options&HEADER_VERTICAL){
472     for(i=0; i<items.no(); i++){
473       if((t=items[i]->getWidth(this))>w) w=t;
474       }
475     }
476   else{
477     for(i=0; i<items.no(); i++){
478       w+=items[i]->getSize();
479       }
480     }
481   return w;
482   }
483 
484 
485 // Get default height
getDefaultHeight()486 FXint FXHeader::getDefaultHeight(){
487   FXint i,t,h=0;
488   if(options&HEADER_VERTICAL){
489     for(i=0; i<items.no(); i++){
490       h+=items[i]->getSize();
491       }
492     }
493   else{
494     for(i=0; i<items.no(); i++){
495       if((t=items[i]->getHeight(this))>h) h=t;
496       }
497     }
498   return h;
499   }
500 
501 
502 // Return total size
getTotalSize() const503 FXint FXHeader::getTotalSize() const {
504   return items.no() ? items[items.no()-1]->getPos()+items[items.no()-1]->getSize()-items[0]->getPos() : 0;
505   }
506 
507 
508 // Create custom item
createItem(const FXString & text,FXIcon * icon,FXint size,void * ptr)509 FXHeaderItem *FXHeader::createItem(const FXString& text,FXIcon* icon,FXint size,void* ptr){
510   return new FXHeaderItem(text,icon,size,ptr);
511   }
512 
513 
514 // Retrieve item
getItem(FXint index) const515 FXHeaderItem *FXHeader::getItem(FXint index) const {
516   if(index<0 || items.no()<=index){ fxerror("%s::getItem: index out of range.\n",getClassName()); }
517   return items[index];
518   }
519 
520 
521 // Simple decimal numbering
decimalNumbering(FXint index)522 FXString FXHeader::decimalNumbering(FXint index){
523   return FXString::value(index+1);
524   }
525 
526 
527 // Simple alpha numbering
alphaNumbering(FXint index)528 FXString FXHeader::alphaNumbering(FXint index){
529   FXchar buf[8]; FXint i=8;
530   index++;
531   while(index){
532     index-=1;
533     buf[--i]='A'+index%26;
534     index/=26;
535     }
536   return FXString(&buf[i],8-i);
537   }
538 
539 
540 // Renumber captions
renumberCaptions(FXNumberingFunc func,FXint fm,FXint to)541 void FXHeader::renumberCaptions(FXNumberingFunc func,FXint fm,FXint to){
542   if(func){
543     if(fm<=0) fm=0;
544     if(to>=items.no()) to=items.no()-1;
545     while(fm<=to){
546       setItemText(fm,func(fm));
547       ++fm;
548       }
549     }
550   }
551 
552 
553 // Replace item with another
setItem(FXint index,FXHeaderItem * item,FXbool notify)554 FXint FXHeader::setItem(FXint index,FXHeaderItem* item,FXbool notify){
555   if(index<0 || items.no()<=index){ fxerror("%s::setItem: index out of range.\n",getClassName()); }
556   if(items[index]!=item){
557 
558     // Must have item
559     if(!item){ fxerror("%s::setItem: item is NULL.\n",getClassName()); }
560 
561     // Notify old item will be deleted
562     if(notify && target){target->tryHandle(this,FXSEL(SEL_DELETED,message),(void*)(FXival)index);}
563 
564     // Copy the size over
565     item->setSize(items[index]->getSize());
566     item->setPos(items[index]->getPos());
567 
568     // Delete old
569     delete items[index];
570 
571     // Add new
572     items[index]=item;
573 
574     // Autorenumber captions
575     renumberCaptions(numbering,index,index);
576 
577     // Redo layout
578     recalc();
579 
580     // Notify new item has been inserted
581     if(notify && target){target->tryHandle(this,FXSEL(SEL_INSERTED,message),(void*)(FXival)index);}
582     }
583   return index;
584   }
585 
586 
587 // Replace item with another
setItem(FXint index,const FXString & text,FXIcon * icon,FXint size,void * ptr,FXbool notify)588 FXint FXHeader::setItem(FXint index,const FXString& text,FXIcon *icon,FXint size,void* ptr,FXbool notify){
589   return setItem(index,createItem(text,icon,FXMAX(size,0),ptr),notify);
590   }
591 
592 
593 // Insert item
insertItem(FXint index,FXHeaderItem * item,FXbool notify)594 FXint FXHeader::insertItem(FXint index,FXHeaderItem* item,FXbool notify){
595   FXint i,d;
596 
597   // Must have item
598   if(!item){ fxerror("%s::insertItem: item is NULL.\n",getClassName()); }
599 
600   // Must be in range
601   if(index<0 || items.no()<index){ fxerror("%s::insertItem: index out of range.\n",getClassName()); }
602 
603   // New item position
604   item->setPos((0<index)?items[index-1]->getPos()+items[index-1]->getSize():0);
605 
606   // Move over remaining items
607   for(i=index,d=item->getSize(); i<items.no(); ++i) items[i]->setPos(items[i]->getPos()+d);
608 
609   // Add item to list
610   items.insert(index,item);
611 
612   // Autorenumber captions
613   renumberCaptions(numbering,index,items.no()-1);
614 
615   // Redo layout
616   recalc();
617 
618   // Notify item has been inserted
619   if(notify && target){target->tryHandle(this,FXSEL(SEL_INSERTED,message),(void*)(FXival)index);}
620 
621   return index;
622   }
623 
624 
625 // Insert item
insertItem(FXint index,const FXString & text,FXIcon * icon,FXint size,void * ptr,FXbool notify)626 FXint FXHeader::insertItem(FXint index,const FXString& text,FXIcon *icon,FXint size,void* ptr,FXbool notify){
627   return insertItem(index,createItem(text,icon,FXMAX(size,0),ptr),notify);
628   }
629 
630 
631 // Append item
appendItem(FXHeaderItem * item,FXbool notify)632 FXint FXHeader::appendItem(FXHeaderItem* item,FXbool notify){
633   return insertItem(items.no(),item,notify);
634   }
635 
636 
637 // Append item
appendItem(const FXString & text,FXIcon * icon,FXint size,void * ptr,FXbool notify)638 FXint FXHeader::appendItem(const FXString& text,FXIcon *icon,FXint size,void* ptr,FXbool notify){
639   return insertItem(items.no(),createItem(text,icon,FXMAX(size,0),ptr),notify);
640   }
641 
642 
643 // Prepend item
prependItem(FXHeaderItem * item,FXbool notify)644 FXint FXHeader::prependItem(FXHeaderItem* item,FXbool notify){
645   return insertItem(0,item,notify);
646   }
647 
648 // Prepend item
prependItem(const FXString & text,FXIcon * icon,FXint size,void * ptr,FXbool notify)649 FXint FXHeader::prependItem(const FXString& text,FXIcon *icon,FXint size,void* ptr,FXbool notify){
650   return insertItem(0,createItem(text,icon,FXMAX(size,0),ptr),notify);
651   }
652 
653 
654 // Fill list by appending items from array of strings
fillItems(const FXchar * const * strings,FXIcon * icon,FXint size,void * ptr,FXbool notify)655 FXint FXHeader::fillItems(const FXchar *const *strings,FXIcon *icon,FXint size,void* ptr,FXbool notify){
656   FXint n=0;
657   if(strings){
658     while(strings[n]){
659       appendItem(strings[n++],icon,size,ptr,notify);
660       }
661     }
662   return n;
663   }
664 
665 
666 // Fill list by appending items from array of strings
fillItems(const FXString * strings,FXIcon * icon,FXint size,void * ptr,FXbool notify)667 FXint FXHeader::fillItems(const FXString* strings,FXIcon *icon,FXint size,void* ptr,FXbool notify){
668   FXint n=0;
669   if(strings){
670     while(!strings[n].empty()){
671       appendItem(strings[n++],icon,size,ptr,notify);
672       }
673     }
674   return n;
675   }
676 
677 
678 // Fill list by appending items from newline separated strings
fillItems(const FXString & strings,FXIcon * icon,FXint size,void * ptr,FXbool notify)679 FXint FXHeader::fillItems(const FXString& strings,FXIcon *icon,FXint size,void* ptr,FXbool notify){
680   FXint n=0;
681   FXString text;
682   while(!(text=strings.section('\n',n)).empty()){
683     appendItem(text,icon,size,ptr,notify);
684     n++;
685     }
686   return n;
687   }
688 
689 
690 // Extract node from list
extractItem(FXint index,FXbool notify)691 FXHeaderItem* FXHeader::extractItem(FXint index,FXbool notify){
692   FXHeaderItem *result;
693   FXint i,d;
694 
695   // Must be in range
696   if(index<0 || items.no()<=index){ fxerror("%s::extractItem: index out of range.\n",getClassName()); }
697 
698   // Notify item will be deleted
699   if(notify && target){target->tryHandle(this,FXSEL(SEL_DELETED,message),(void*)(FXival)index);}
700 
701   // Adjust remaining columns
702   for(i=index+1,d=items[index]->getSize(); i<items.no(); i++) items[i]->setPos(items[i]->getPos()-d);
703 
704   // Delete item
705   result=items[index];
706 
707   // Remove item from list
708   items.erase(index);
709 
710   // Autorenumber captions
711   renumberCaptions(numbering,index,items.no()-1);
712 
713   // Redo layout
714   recalc();
715 
716   // Return item
717   return result;
718   }
719 
720 
721 // Remove node from list
removeItem(FXint index,FXbool notify)722 void FXHeader::removeItem(FXint index,FXbool notify){
723   FXint i,d;
724 
725   // Must be in range
726   if(index<0 || items.no()<=index){ fxerror("%s::removeItem: index out of range.\n",getClassName()); }
727 
728   // Notify item will be deleted
729   if(notify && target){target->tryHandle(this,FXSEL(SEL_DELETED,message),(void*)(FXival)index);}
730 
731   // Adjust remaining columns
732   for(i=index+1,d=items[index]->getSize(); i<items.no(); i++) items[i]->setPos(items[i]->getPos()-d);
733 
734   // Delete item
735   delete items[index];
736 
737   // Remove item from list
738   items.erase(index);
739 
740   // Autorenumber captions
741   renumberCaptions(numbering,index,items.no()-1);
742 
743   // Redo layout
744   recalc();
745   }
746 
747 
748 // Remove all items
clearItems(FXbool notify)749 void FXHeader::clearItems(FXbool notify){
750 
751   // Delete items
752   for(FXint index=items.no()-1; 0<=index; index--){
753     if(notify && target){target->tryHandle(this,FXSEL(SEL_DELETED,message),(void*)(FXival)index);}
754     delete items[index];
755     }
756 
757   // Free array
758   items.clear();
759 
760   // Redo layout
761   recalc();
762   }
763 
764 
765 // Change item's text
setItemText(FXint index,const FXString & text)766 void FXHeader::setItemText(FXint index,const FXString& text){
767   if(index<0 || items.no()<=index){ fxerror("%s::setItemText: index out of range.\n",getClassName()); }
768   if(items[index]->getText()!=text){
769     items[index]->setText(text);
770     recalc();
771     }
772   }
773 
774 
775 // Get item's text
getItemText(FXint index) const776 FXString FXHeader::getItemText(FXint index) const {
777   if(index<0 || items.no()<=index){ fxerror("%s::getItemText: index out of range.\n",getClassName()); }
778   return items[index]->getText();
779   }
780 
781 
782 // Change item's tooltip text
setItemTipText(FXint index,const FXString & text)783 void FXHeader::setItemTipText(FXint index,const FXString& text){
784   if(index<0 || items.no()<=index){ fxerror("%s::setItemTipText: index out of range.\n",getClassName()); }
785   if(items[index]->getTipText()!=text){
786     items[index]->setTipText(text);
787     recalc();
788     }
789   }
790 
791 
792 // Get item's tooltip text
getItemTipText(FXint index) const793 FXString FXHeader::getItemTipText(FXint index) const {
794   if(index<0 || items.no()<=index){ fxerror("%s::getItemTipText: index out of range.\n",getClassName()); }
795   return items[index]->getTipText();
796   }
797 
798 
799 // Change item's icon
setItemIcon(FXint index,FXIcon * icon,FXbool owned)800 void FXHeader::setItemIcon(FXint index,FXIcon* icon,FXbool owned){
801   if(index<0 || items.no()<=index){ fxerror("%s::setItemIcon: index out of range.\n",getClassName()); }
802   if(items[index]->getIcon()!=icon){
803     items[index]->setIcon(icon,owned);
804     recalc();
805     }
806   }
807 
808 
809 // Get item's icon
getItemIcon(FXint index) const810 FXIcon* FXHeader::getItemIcon(FXint index) const {
811   if(index<0 || items.no()<=index){ fxerror("%s::getItemIcon: index out of range.\n",getClassName()); }
812   return items[index]->getIcon();
813   }
814 
815 
816 // Change item's size
setItemSize(FXint index,FXint size)817 void FXHeader::setItemSize(FXint index,FXint size){
818   FXint i,d;
819   if(index<0 || items.no()<=index){ fxerror("%s::setItemSize: index out of range.\n",getClassName()); }
820   if(size<0) size=0;
821   d=size-items[index]->getSize();
822   if(d!=0){
823     items[index]->setSize(size);
824     for(i=index+1; i<items.no(); i++) items[i]->setPos(items[i]->getPos()+d);
825     recalc();
826     }
827   }
828 
829 
830 // Get item's size
getItemSize(FXint index) const831 FXint FXHeader::getItemSize(FXint index) const {
832   if(index<0 || items.no()<=index){ fxerror("%s::getItemSize: index out of range.\n",getClassName()); }
833   return items[index]->getSize();
834   }
835 
836 
837 // Get item's offset
getItemOffset(FXint index) const838 FXint FXHeader::getItemOffset(FXint index) const {
839   if(index<0 || items.no()<=index){ fxerror("%s::getItemOffset: index out of range.\n",getClassName()); }
840   return pos+items[index]->getPos();
841   }
842 
843 
844 // Get index of item at offset
getItemAt(FXint coord) const845 FXint FXHeader::getItemAt(FXint coord) const {
846   FXint h=items.no()-1,l=0,p=coord-pos,m;
847   if(l<=h){
848     if(p<items[l]->getPos()) return -1;
849     if(p>=items[h]->getPos()+items[h]->getSize()) return items.no();
850     do{
851       m=(h+l)>>1;
852       if(p<items[m]->getPos()) h=m-1;
853       else if(p>=items[m]->getPos()+items[m]->getSize()) l=m+1;
854       else break;
855       }
856     while(l<=h);
857     return m;
858     }
859   return p<0 ? -1 : 0;
860   }
861 
862 
863 // Set item data
setItemData(FXint index,void * ptr)864 void FXHeader::setItemData(FXint index,void* ptr){
865   if(index<0 || items.no()<=index){ fxerror("%s::setItemData: index out of range.\n",getClassName()); }
866   items[index]->setData(ptr);
867   }
868 
869 
870 // Get item data
getItemData(FXint index) const871 void* FXHeader::getItemData(FXint index) const {
872   if(index<0 || items.no()<=index){ fxerror("%s::getItemData: index out of range.\n",getClassName()); }
873   return items[index]->getData();
874   }
875 
876 
877 // Change sort direction
setArrowDir(FXint index,FXuint dir)878 void FXHeader::setArrowDir(FXint index,FXuint dir){
879   if(index<0 || items.no()<=index){ fxerror("%s::setArrowDir: index out of range.\n",getClassName()); }
880   if(items[index]->getArrowDir()!=dir){
881     items[index]->setArrowDir(dir);
882     updateItem(index);
883     }
884   }
885 
886 
887 // Return sort direction
getArrowDir(FXint index) const888 FXuint FXHeader::getArrowDir(FXint index) const {
889   if(index<0 || items.no()<=index){ fxerror("%s::getArrowDir: index out of range.\n",getClassName()); }
890   return items[index]->getArrowDir();
891   }
892 
893 
894 // Change item justification
setItemJustify(FXint index,FXuint justify)895 void FXHeader::setItemJustify(FXint index,FXuint justify){
896   if(index<0 || items.no()<=index){ fxerror("%s::setItemJustify: index out of range.\n",getClassName()); }
897   if(items[index]->getJustify()!=justify){
898     items[index]->setJustify(justify);
899     updateItem(index);
900     }
901   }
902 
903 
904 // Return item justification
getItemJustify(FXint index) const905 FXuint FXHeader::getItemJustify(FXint index) const {
906   if(index<0 || items.no()<=index){ fxerror("%s::getItemJustify: index out of range.\n",getClassName()); }
907   return items[index]->getJustify();
908   }
909 
910 
911 // Change relative position of icon and text of item
setItemIconPosition(FXint index,FXuint mode)912 void FXHeader::setItemIconPosition(FXint index,FXuint mode){
913   if(index<0 || items.no()<=index){ fxerror("%s::setItemIconPosition: index out of range.\n",getClassName()); }
914   if(items[index]->getIconPosition()!=mode){
915     items[index]->setIconPosition(mode);
916     recalc();
917     }
918   }
919 
920 
921 // Return relative icon and text position
getItemIconPosition(FXint index) const922 FXuint FXHeader::getItemIconPosition(FXint index) const {
923   if(index<0 || items.no()<=index){ fxerror("%s::getItemIconPosition: index out of range.\n",getClassName()); }
924   return items[index]->getIconPosition();
925   }
926 
927 
928 // Changed button item's pressed state
setItemPressed(FXint index,FXbool pressed)929 void FXHeader::setItemPressed(FXint index,FXbool pressed){
930   if(index<0 || items.no()<=index){ fxerror("%s::setItemPressed: index out of range.\n",getClassName()); }
931   if(pressed!=items[index]->isPressed()){
932     items[index]->setPressed(pressed);
933     updateItem(index);
934     }
935   }
936 
937 
938 // Return true if button item is pressed in
isItemPressed(FXint index) const939 FXbool FXHeader::isItemPressed(FXint index) const {
940   if(index<0 || items.no()<=index){ fxerror("%s::isItemPressed: index out of range.\n",getClassName()); }
941   return items[index]->isPressed();
942   }
943 
944 
945 // Scroll to make given item visible
makeItemVisible(FXint index)946 void FXHeader::makeItemVisible(FXint index){
947   FXint newpos,ioffset,isize,space;
948   if(xid){
949     newpos=pos;
950     if(0<=index && index<items.no()){
951       space=(options&HEADER_VERTICAL)?height:width;
952       ioffset=items[index]->getPos();
953       isize=items[index]->getSize();
954       newpos=pos;
955       if(newpos+ioffset+isize>=space) newpos=space-ioffset-isize;
956       if(newpos+ioffset<=0) newpos=-ioffset;
957       }
958     setPosition(newpos);
959     }
960   }
961 
962 
963 // Repaint cell at index
updateItem(FXint index) const964 void FXHeader::updateItem(FXint index) const {
965   if(index<0 || items.no()<=index){ fxerror("%s::updateItem: index out of range.\n",getClassName()); }
966   if(options&HEADER_VERTICAL)
967     update(0,pos+items[index]->getPos(),width,items[index]->getSize());
968   else
969     update(pos+items[index]->getPos(),0,items[index]->getSize(),height);
970   }
971 
972 
973 // Do layout
layout()974 void FXHeader::layout(){
975 
976   // Force repaint
977   update();
978 
979   // No more dirty
980   flags&=~FLAG_DIRTY;
981   }
982 
983 
984 // Handle repaint
onPaint(FXObject *,FXSelector,void * ptr)985 long FXHeader::onPaint(FXObject*,FXSelector,void* ptr){
986   FXEvent *ev=(FXEvent*)ptr;
987   FXDCWindow dc(this,ev);
988   FXint x,y,w,h,i,ilo,ihi;
989 
990   // Set font
991   dc.setFont(font);
992 
993   // Paint background
994   dc.setForeground(backColor);
995   dc.fillRectangle(ev->rect.x,ev->rect.y,ev->rect.w,ev->rect.h);
996 
997   // Vertical
998   if(options&HEADER_VERTICAL){
999 
1000     // Determine affected items
1001     ilo=getItemAt(ev->rect.y);
1002     ihi=getItemAt(ev->rect.y+ev->rect.h);
1003 
1004     // Fragment below first item
1005     if(ilo<0){
1006       y=pos;
1007       if(0<items.no()){
1008         y=pos+items[0]->getPos();
1009         }
1010       if(0<y){
1011         if(options&FRAME_THICK)
1012           drawDoubleRaisedRectangle(dc,0,0,width,y);
1013         else if(options&FRAME_RAISED)
1014           drawRaisedRectangle(dc,0,0,width,y);
1015         }
1016       ilo=0;
1017       }
1018 
1019     // Fragment above last item
1020     if(ihi>=items.no()){
1021       y=pos;
1022       if(0<items.no()){
1023         y=pos+items[items.no()-1]->getPos()+items[items.no()-1]->getSize();
1024         }
1025       if(y<height){
1026         if(options&FRAME_THICK)
1027           drawDoubleRaisedRectangle(dc,0,y,width,height-y);
1028         else if(options&FRAME_RAISED)
1029           drawRaisedRectangle(dc,0,y,width,height-y);
1030         }
1031       ihi=items.no()-1;
1032       }
1033 
1034     // Draw only affected items
1035     for(i=ilo; i<=ihi; i++){
1036       y=pos+items[i]->getPos();
1037       h=items[i]->getSize();
1038       if(items[i]->isPressed()){
1039         if(options&FRAME_THICK)
1040           drawDoubleSunkenRectangle(dc,0,y,width,h);
1041         else if(options&FRAME_RAISED)
1042           drawSunkenRectangle(dc,0,y,width,h);
1043         }
1044       else{
1045         if(options&FRAME_THICK)
1046           drawDoubleRaisedRectangle(dc,0,y,width,h);
1047         else if(options&FRAME_RAISED)
1048           drawRaisedRectangle(dc,0,y,width,h);
1049         }
1050       items[i]->draw(this,dc,0,y,width,h);
1051       }
1052     }
1053 
1054   // Horizontal
1055   else{
1056 
1057     // Determine affected items
1058     ilo=getItemAt(ev->rect.x);
1059     ihi=getItemAt(ev->rect.x+ev->rect.w);
1060 
1061     // Fragment below first item
1062     if(ilo<0){
1063       x=pos;
1064       if(0<items.no()){
1065         x=pos+items[0]->getPos();
1066         }
1067       if(0<x){
1068         if(options&FRAME_THICK)
1069           drawDoubleRaisedRectangle(dc,0,0,x,height);
1070         else if(options&FRAME_RAISED)
1071           drawRaisedRectangle(dc,0,0,x,height);
1072         }
1073       ilo=0;
1074       }
1075 
1076     // Fragment above last item
1077     if(ihi>=items.no()){
1078       x=pos;
1079       if(0<items.no()){
1080         x=pos+items[items.no()-1]->getPos()+items[items.no()-1]->getSize();
1081         }
1082       if(x<width){
1083         if(options&FRAME_THICK)
1084           drawDoubleRaisedRectangle(dc,x,0,width-x,height);
1085         else if(options&FRAME_RAISED)
1086           drawRaisedRectangle(dc,x,0,width-x,height);
1087         }
1088       ihi=items.no()-1;
1089       }
1090 
1091     // Draw only the affected items
1092     for(i=ilo; i<=ihi; i++){
1093       x=pos+items[i]->getPos();
1094       w=items[i]->getSize();
1095       if(items[i]->isPressed()){
1096         if(options&FRAME_THICK)
1097           drawDoubleSunkenRectangle(dc,x,0,w,height);
1098         else if(options&FRAME_RAISED)
1099           drawSunkenRectangle(dc,x,0,w,height);
1100         }
1101       else{
1102         if(options&FRAME_THICK)
1103           drawDoubleRaisedRectangle(dc,x,0,w,height);
1104         else if(options&FRAME_RAISED)
1105           drawRaisedRectangle(dc,x,0,w,height);
1106         }
1107       items[i]->draw(this,dc,x,0,w,height);
1108       }
1109     }
1110   return 1;
1111   }
1112 
1113 
1114 // We were asked about tip text
onQueryTip(FXObject * sender,FXSelector sel,void * ptr)1115 long FXHeader::onQueryTip(FXObject* sender,FXSelector sel,void* ptr){
1116   if(FXFrame::onQueryTip(sender,sel,ptr)) return 1;
1117   if(flags&FLAG_TIP){
1118     FXint index,cx,cy; FXuint btns;
1119     getCursorPosition(cx,cy,btns);
1120     index=getItemAt((options&HEADER_VERTICAL)?cy:cx);
1121     if(0<=index && index<items.no()){
1122       sender->handle(this,FXSEL(SEL_COMMAND,ID_SETSTRINGVALUE),(void*)&items[index]->getTipText());
1123       return 1;
1124       }
1125     }
1126   return 0;
1127   }
1128 
1129 
1130 // We were asked about status text
onQueryHelp(FXObject * sender,FXSelector sel,void * ptr)1131 long FXHeader::onQueryHelp(FXObject* sender,FXSelector sel,void* ptr){
1132   if(FXFrame::onQueryHelp(sender,sel,ptr)) return 1;
1133   if((flags&FLAG_HELP) && !help.empty()){
1134     sender->handle(this,FXSEL(SEL_COMMAND,ID_SETSTRINGVALUE),(void*)&help);
1135     return 1;
1136     }
1137   return 0;
1138   }
1139 
1140 
1141 // We timed out, i.e. the user didn't move for a while
onTipTimer(FXObject *,FXSelector,void *)1142 long FXHeader::onTipTimer(FXObject*,FXSelector,void*){
1143   FXTRACE((250,"%s::onTipTimer %p\n",getClassName(),this));
1144   flags|=FLAG_TIP;
1145   return 1;
1146   }
1147 
1148 
1149 // Button being pressed
onLeftBtnPress(FXObject *,FXSelector,void * ptr)1150 long FXHeader::onLeftBtnPress(FXObject*,FXSelector,void* ptr){
1151   FXEvent* event=(FXEvent*)ptr;
1152   FXint coord;
1153   flags&=~FLAG_TIP;
1154   handle(this,FXSEL(SEL_FOCUS_SELF,0),ptr);
1155   if(isEnabled()){
1156     grab();
1157 
1158     // First change callback
1159     if(target && target->tryHandle(this,FXSEL(SEL_LEFTBUTTONPRESS,message),ptr)) return 1;
1160 
1161     // Where clicked
1162     coord=(options&HEADER_VERTICAL)?event->win_y:event->win_x;
1163     if((active=getItemAt(coord))>=0){
1164       if((options&HEADER_RESIZE) && (active<items.no()) && (pos+items[active]->getPos()+items[active]->getSize()-FUDGE<coord)){
1165         activepos=pos+items[active]->getPos();
1166         activesize=items[active]->getSize();
1167         offset=coord-activepos-activesize;
1168         setDragCursor((options&HEADER_VERTICAL)?getApp()->getDefaultCursor(DEF_VSPLIT_CURSOR):getApp()->getDefaultCursor(DEF_HSPLIT_CURSOR));
1169         flags|=FLAG_PRESSED|FLAG_TRYDRAG;
1170         }
1171       else if((options&HEADER_RESIZE) && (0<active) && (coord<pos+items[active-1]->getPos()+items[active-1]->getSize()+FUDGE)){
1172         active--;
1173         activepos=pos+items[active]->getPos();
1174         activesize=items[active]->getSize();
1175         offset=coord-activepos-activesize;
1176         setDragCursor((options&HEADER_VERTICAL)?getApp()->getDefaultCursor(DEF_VSPLIT_CURSOR):getApp()->getDefaultCursor(DEF_HSPLIT_CURSOR));
1177         flags|=FLAG_PRESSED|FLAG_TRYDRAG;
1178         }
1179       else if((options&HEADER_BUTTON) && (active<items.no())){
1180         activepos=pos+items[active]->getPos();
1181         activesize=items[active]->getSize();
1182         setItemPressed(active,true);
1183         flags|=FLAG_PRESSED;
1184         }
1185       }
1186     flags&=~FLAG_UPDATE;
1187     return 1;
1188     }
1189   return 0;
1190   }
1191 
1192 
1193 // Button being released
onLeftBtnRelease(FXObject *,FXSelector,void * ptr)1194 long FXHeader::onLeftBtnRelease(FXObject*,FXSelector,void* ptr){
1195   FXuint flg=flags;
1196   if(isEnabled()){
1197     ungrab();
1198     flags|=FLAG_UPDATE;
1199     flags&=~(FLAG_PRESSED|FLAG_DODRAG|FLAG_TRYDRAG);
1200 
1201     // First chance callback
1202     if(target && target->tryHandle(this,FXSEL(SEL_LEFTBUTTONRELEASE,message),ptr)) return 1;
1203 
1204     // Set cursor back
1205     setDragCursor(getApp()->getDefaultCursor(DEF_ARROW_CURSOR));
1206 
1207     // Clicked on split
1208     if(flg&FLAG_TRYDRAG){
1209       if(target) target->tryHandle(this,FXSEL(SEL_CLICKED,message),(void*)(FXival)active);
1210       return 1;
1211       }
1212 
1213     // Dragged split
1214     if(flg&FLAG_DODRAG){
1215       if(!(options&HEADER_TRACKING)){
1216         drawSplit(activepos+activesize);
1217         setItemSize(active,activesize);
1218         if(target) target->tryHandle(this,FXSEL(SEL_CHANGED,message),(void*)(FXival)active);
1219         }
1220       return 1;
1221       }
1222 
1223     // Pressed button
1224     if(flg&FLAG_PRESSED){
1225       if(items[active]->isPressed()){
1226         setItemPressed(active,false);
1227         if(target) target->tryHandle(this,FXSEL(SEL_COMMAND,message),(void*)(FXival)active);
1228         }
1229       return 1;
1230       }
1231     }
1232   return 0;
1233   }
1234 
1235 
1236 // Button being moved
onMotion(FXObject *,FXSelector,void * ptr)1237 long FXHeader::onMotion(FXObject*,FXSelector,void* ptr){
1238   FXEvent* event=(FXEvent*)ptr;
1239   FXint oldsplit,newsplit,index;
1240   FXuint flg=flags;
1241 
1242   // Kill the tip
1243   flags&=~FLAG_TIP;
1244 
1245   // Kill the tip timer
1246   getApp()->removeTimeout(this,ID_TIPTIMER);
1247 
1248   // Tentatively dragging split
1249   if(flags&FLAG_TRYDRAG){
1250     if(!(options&HEADER_TRACKING)) drawSplit(activepos+activesize);
1251     flags&=~FLAG_TRYDRAG;
1252     flags|=FLAG_DODRAG;
1253     return 1;
1254     }
1255 
1256   // Dragging split
1257   if(flags&FLAG_DODRAG){
1258     oldsplit=activepos+activesize;
1259     if(options&HEADER_VERTICAL)
1260       activesize=event->win_y-offset-activepos;
1261     else
1262       activesize=event->win_x-offset-activepos;
1263     if(activesize<0) activesize=0;
1264     newsplit=activepos+activesize;
1265     if(newsplit!=oldsplit){
1266       if(!(options&HEADER_TRACKING)){
1267         drawSplit(oldsplit);
1268         drawSplit(newsplit);
1269         }
1270       else{
1271         setItemSize(active,activesize);
1272         if(target) target->tryHandle(this,FXSEL(SEL_CHANGED,message),(void*)(FXival)active);
1273         }
1274       }
1275     return 1;
1276     }
1277 
1278   // Had the button pressed
1279   if(flags&FLAG_PRESSED){
1280     if(options&HEADER_VERTICAL){
1281       if(activepos<=event->win_y && event->win_y<activepos+activesize && 0<=event->win_x && event->win_x<width){
1282         setItemPressed(active,true);
1283         }
1284       else{
1285         setItemPressed(active,false);
1286         }
1287       }
1288     else{
1289       if(activepos<=event->win_x && event->win_x<activepos+activesize && 0<=event->win_y && event->win_y<height){
1290         setItemPressed(active,true);
1291         }
1292       else{
1293         setItemPressed(active,false);
1294         }
1295       }
1296     return 1;
1297     }
1298 
1299   // When hovering over a split, show the split cursor
1300   if(options&HEADER_RESIZE){
1301     if(options&HEADER_VERTICAL){
1302       index=getItemAt(event->win_y);
1303       if(0<=index && ((index<items.no() && pos+items[index]->getPos()+items[index]->getSize()-FUDGE<event->win_y) || (0<index && event->win_y<pos+items[index-1]->getPos()+items[index-1]->getSize()+FUDGE))){
1304         setDefaultCursor(getApp()->getDefaultCursor(DEF_VSPLIT_CURSOR));
1305         }
1306       else{
1307         setDefaultCursor(getApp()->getDefaultCursor(DEF_ARROW_CURSOR));
1308         }
1309       }
1310     else{
1311       index=getItemAt(event->win_x);
1312       if(0<=index && ((index<items.no() && pos+items[index]->getPos()+items[index]->getSize()-FUDGE<event->win_x) || (0<index && event->win_x<pos+items[index-1]->getPos()+items[index-1]->getSize()+FUDGE))){
1313         setDefaultCursor(getApp()->getDefaultCursor(DEF_HSPLIT_CURSOR));
1314         }
1315       else{
1316         setDefaultCursor(getApp()->getDefaultCursor(DEF_ARROW_CURSOR));
1317         }
1318       }
1319     }
1320 
1321   // Reset tip timer if nothing's going on
1322   getApp()->addTimeout(this,ID_TIPTIMER,getApp()->getMenuPause());
1323 
1324   // Force GUI update only when needed
1325   return (flg&FLAG_TIP);
1326   }
1327 
1328 
1329 // The widget lost the grab for some reason
onUngrabbed(FXObject * sender,FXSelector sel,void * ptr)1330 long FXHeader::onUngrabbed(FXObject* sender,FXSelector sel,void* ptr){
1331   FXFrame::onUngrabbed(sender,sel,ptr);
1332   flags&=~FLAG_PRESSED;
1333   flags&=~FLAG_CHANGED;
1334   flags|=FLAG_UPDATE;
1335   return 1;
1336   }
1337 
1338 
1339 // Draw the split
drawSplit(FXint p)1340 void FXHeader::drawSplit(FXint p){
1341   FXDCWindow dc(getParent());
1342   FXint px,py;
1343   translateCoordinatesTo(px,py,getParent(),p,p);
1344   dc.clipChildren(false);
1345   dc.setFunction(BLT_NOT_DST);
1346   if(options&HEADER_VERTICAL){
1347     dc.fillRectangle(0,py,getParent()->getWidth(),2);
1348     }
1349   else{
1350     dc.fillRectangle(px,0,2,getParent()->getHeight());
1351     }
1352   }
1353 
1354 
1355 // Set position, scrolling contents
setPosition(FXint p)1356 void FXHeader::setPosition(FXint p){
1357   if(pos!=p){
1358     if(options&HEADER_VERTICAL)
1359       scroll(0,0,width,height,0,p-pos);
1360     else
1361       scroll(0,0,width,height,p-pos,0);
1362     pos=p;
1363     }
1364   }
1365 
1366 
1367 // Change the font
setFont(FXFont * fnt)1368 void FXHeader::setFont(FXFont* fnt){
1369   if(!fnt){ fxerror("%s::setFont: NULL font specified.\n",getClassName()); }
1370   if(font!=fnt){
1371     font=fnt;
1372     recalc();
1373     update();
1374     }
1375   }
1376 
1377 
1378 // Set auto-renumbering function
setAutoNumbering(FXNumberingFunc func)1379 void FXHeader::setAutoNumbering(FXNumberingFunc func){
1380   if(numbering!=func){
1381     numbering=func;
1382     if(numbering){
1383       renumberCaptions(numbering);
1384       }
1385     }
1386   }
1387 
1388 
1389 // Set text color
setTextColor(FXColor clr)1390 void FXHeader::setTextColor(FXColor clr){
1391   if(textColor!=clr){
1392     textColor=clr;
1393     update();
1394     }
1395   }
1396 
1397 
1398 // Header style change
setHeaderStyle(FXuint style)1399 void FXHeader::setHeaderStyle(FXuint style){
1400   FXuint opts=((style^options)&HEADER_MASK)^options;
1401   if(options!=opts){
1402     options=opts;
1403     recalc();
1404     update();
1405     }
1406   }
1407 
1408 
1409 // Get header style
getHeaderStyle() const1410 FXuint FXHeader::getHeaderStyle() const {
1411   return (options&HEADER_MASK);
1412   }
1413 
1414 
1415 // Save object to stream
save(FXStream & store) const1416 void FXHeader::save(FXStream& store) const {
1417   FXFrame::save(store);
1418   items.save(store);
1419   store << textColor;
1420   store << font;
1421   store << help;
1422   store << pos;
1423   }
1424 
1425 
1426 
1427 // Load object from stream
load(FXStream & store)1428 void FXHeader::load(FXStream& store){
1429   FXFrame::load(store);
1430   items.load(store);
1431   store >> textColor;
1432   store >> font;
1433   store >> help;
1434   store >> pos;
1435   }
1436 
1437 
1438 // Clean up
~FXHeader()1439 FXHeader::~FXHeader(){
1440   getApp()->removeTimeout(this,ID_TIPTIMER);
1441   clearItems();
1442   font=(FXFont*)-1L;
1443   }
1444 }
1445