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