1 /*
2 FXiTe - The Free eXtensIble Text Editor
3 Copyright (c) 2009-2013 Jeffrey Pohlmeyer <yetanothergeek@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify it
6 under the terms of the GNU General Public License version 3 as
7 published by the Free Software Foundation.
8
9 This software is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19
20 #include <unistd.h>
21 #include <fx.h>
22
23 #include "compat.h"
24 #include "appwin_pub.h"
25
26 #include "intl.h"
27 #include "doctabs.h"
28
29
30 FXDEFMAP(DocTabs) DocTabsMap[]={
31 FXMAPFUNC(SEL_COMMAND,DocTabs::ID_TAB_POPUP_MENU,DocTabs::onTabPopupMenu),
32 FXMAPFUNC(SEL_COMMAND,DocTabs::ID_POPUP_CLICK,DocTabs::onPopupClick),
33 FXMAPFUNC(SEL_COMMAND,DocTabs::ID_OPEN_ITEM,DocTabs::onCmdOpenItem),
34 #ifndef WIN32
35 FXMAPFUNC(SEL_DND_ENTER, 0, DocTabs::onDnd),
36 FXMAPFUNC(SEL_DND_LEAVE, 0, DocTabs::onDnd),
37 FXMAPFUNC(SEL_DND_DROP, 0, DocTabs::onDnd),
38 FXMAPFUNC(SEL_DND_MOTION, 0, DocTabs::onDnd),
39 #endif
40 };
41
42 FXIMPLEMENT(DocTabs,ShadyTabs,DocTabsMap,ARRAYNUMBER(DocTabsMap));
43
44
45
46 #ifdef WIN32
47 # include <windows.h>
create()48 void DocTabs::create()
49 {
50 FXTabBook::create();
51 ::DragAcceptFiles((HWND)id(),true);
52 }
53 #else
onDnd(FXObject * sender,FXSelector sel,void * p)54 long DocTabs::onDnd(FXObject* sender,FXSelector sel, void*p)
55 {
56 switch (FXSELTYPE(sel)) {
57 case SEL_DND_ENTER: {
58 if (getApp()->getCursorWindow()==this) { return 0; }
59 setDragRectangle(0,0,width,height,false);
60 if (offeredDNDType(FROM_DRAGNDROP,urilistType)) {
61 acceptDrop();
62 dnd_accept=true;
63 } else {
64 dnd_accept=false;
65 }
66 break;
67 }
68 case SEL_DND_LEAVE: {
69 dnd_accept=false;
70 break;
71 }
72 case SEL_DND_DROP: {
73 dnd_accept=false;
74 FXuchar*dnd_data=NULL;
75 FXuint size=0;
76 if (getDNDData(FROM_DRAGNDROP,urilistType,dnd_data,size)) {
77 if (dnd_data) {
78 dnd_accept=false;
79 FXchar *p1, *p2;
80 for (p1=(FXchar*)dnd_data; p1&&*p1; p1=p2) {
81 p2=strchr(p1,'\r');
82 if (p2) {
83 FXString uri;
84 uri.assign(p1,p2-p1);
85 if (compare(uri, "file://",7)==0) {
86 uri.erase(0,7);
87 TopWinPub::OpenFile(uri.text(),NULL,false,true);
88 }
89 p2+=2;
90 }
91 }
92 }
93 }
94 break;
95 }
96 case SEL_DND_MOTION: {
97 if (dnd_accept) { acceptDrop(); }
98 break;
99 }
100 }
101 return 1;
102 }
103 #endif
104
105
106
onPopupClick(FXObject * sender,FXSelector sel,void * p)107 long DocTabs::onPopupClick( FXObject* sender, FXSelector sel, void* p )
108 {
109 DocTab*tab=(DocTab*)(((FXMenuCommand*)sender)->getParent()->getUserData());
110 DocTab*curr=ActiveTab();
111 if ( tab && ActivateTab(tab) ) {
112 TopWinPub::CloseFile(false,true);
113 }
114 if (curr && (tab!=curr)) { ActivateTab(curr); }
115 return 1;
116 }
117
118
119
onTabPopupMenu(FXObject * sender,FXSelector sel,void * p)120 long DocTabs::onTabPopupMenu( FXObject* sender, FXSelector sel, void* p )
121 {
122 FXEvent*ev=(FXEvent*)p;
123 if (!ev->moved) {
124 if (!tab_popup->shown()) { tab_popup->create(); }
125 tab_popup->setUserData(sender);
126 tab_popup->popup(NULL,ev->root_x-2,ev->root_y-2);
127 getApp()->runModalWhileShown(tab_popup);
128 }
129 return 1;
130 }
131
132
133
DocTabs(FXComposite * p,FXObject * trg,FXSelector sel,FXuint opts)134 DocTabs::DocTabs(FXComposite*p,FXObject*trg,FXSelector sel,FXuint opts):
135 ShadyTabs(p,trg,sel,opts,0,0,0,0,0,0,0,0)
136 {
137 tab_width_max=0;
138 tab_popup=new FXMenuPane(this);
139 new FXMenuCommand(tab_popup,_("&Close"),NULL,this,ID_POPUP_CLICK);
140 dnd_accept=false;
141 dropEnable();
142 }
143
144
145
~DocTabs()146 DocTabs::~DocTabs()
147 {
148 delete tab_popup;
149 }
150
151
152
UpdateTabWidths(FXint index,DocTab * tab,FXWindow * page,void * user_data)153 bool DocTabs::UpdateTabWidths(FXint index, DocTab*tab, FXWindow*page, void*user_data)
154 {
155 tab->setText(tab->getText());
156 return true;
157 }
158
159
160
MaxTabWidth(FXint w)161 void DocTabs::MaxTabWidth(FXint w)
162 {
163 if (w!=tab_width_max) {
164 tab_width_max=w;
165 ForEachTab(UpdateTabWidths,NULL,false);
166 }
167 }
168
169
170
171 class MySplitter: public FXSplitter {
172 FXDECLARE(MySplitter);
MySplitter()173 MySplitter(){}
174 protected:
175 FXWindow *last_focused_child;
176 virtual void changeFocus(FXWindow*child);
177 public:
178 long onFocusIn(FXObject*o,FXSelector sel,void* p);
179 long onFixFocus(FXObject*o,FXSelector sel,void* p);
MySplitter(FXComposite * p,FXuint opts)180 MySplitter(FXComposite *p, FXuint opts):FXSplitter(p,opts) { last_focused_child=NULL; }
~MySplitter()181 ~MySplitter() { getApp()->removeChore(this,ID_FIX_FOCUS); }
LastFocusedChild()182 FXWindow *LastFocusedChild() { return last_focused_child; }
183 enum {
184 ID_FIX_FOCUS=FXSplitter::ID_LAST,
185 ID_LAST
186 };
187 };
188
189
190
191 FXDEFMAP(MySplitter) MySplitterMap[] = {
192 FXMAPFUNC(SEL_FOCUSIN,0,MySplitter::onFocusIn),
193 FXMAPFUNC(SEL_CHORE,MySplitter::ID_FIX_FOCUS,MySplitter::onFixFocus)
194 };
195
FXIMPLEMENT(MySplitter,FXSplitter,MySplitterMap,ARRAYNUMBER (MySplitterMap))196 FXIMPLEMENT(MySplitter,FXSplitter,MySplitterMap,ARRAYNUMBER(MySplitterMap))
197
198
199
200 void MySplitter::changeFocus(FXWindow*child)
201 {
202 if (child) { last_focused_child=child; }
203 FXSplitter::changeFocus(child);
204 }
205
206
207
onFixFocus(FXObject * o,FXSelector sel,void * p)208 long MySplitter::onFixFocus(FXObject*o,FXSelector sel,void* p)
209 {
210 if (p) {
211 ((FXWindow*)p)->setFocus();
212 }
213 return 1;
214 }
215
216
217
onFocusIn(FXObject * o,FXSelector sel,void * p)218 long MySplitter::onFocusIn(FXObject*o,FXSelector sel,void* p)
219 {
220 long rv=FXSplitter::onFocusIn(o,sel,p);
221 if ((numChildren()>1) && last_focused_child) {
222 getApp()->addChore(this,ID_FIX_FOCUS,(void*)last_focused_child);
223 }
224 return rv;
225 }
226
ActiveView()227 FXWindow*DocTabs::ActiveView()
228 {
229 FXWindow*w=ActivePage();
230 return w?((MySplitter*)w)->LastFocusedChild():NULL;
231 return NULL;
232 }
233
NewTab(FXString text)234 DocTab*DocTabs::NewTab(FXString text)
235 {
236 DocTab*tab=new DocTab(this,text);
237 switch (getTabStyle()) {
238 case TABBOOK_TOPTABS: { tab->setTabOrientation(TAB_TOP); break; }
239 case TABBOOK_BOTTOMTABS: { tab->setTabOrientation(TAB_BOTTOM); break; }
240 case TABBOOK_LEFTTABS: { tab->setTabOrientation(TAB_LEFT); break; }
241 case TABBOOK_RIGHTTABS: { tab->setTabOrientation(TAB_RIGHT); break; }
242 }
243 MySplitter*frame=new MySplitter(this,FRAME_RAISED|LAYOUT_FILL|SPLITTER_VERTICAL);
244 if (shown()) {
245 tab->create();
246 frame->create();
247 tab->setText(text);
248 }
249 return tab;
250 }
251
252
253
MoveTab(FXint how)254 void DocTabs::MoveTab(FXint how){
255 DocTab*tab=ActiveTab();
256 if (!tab) { return; }
257 FXWindow*page=tab->getNext();
258 if (!page) { return; }
259 FXint iCurr=getCurrent();
260 switch (how) {
261 case MOVETOLAST: {
262 tab->reparent(this, NULL);
263 page->reparent(this, NULL);
264 setCurrent((numChildren()/2)-1,true);
265 break;
266 }
267 case MOVETOFIRST: {
268 page->reparent(this, getFirst());
269 tab->reparent(this, page);
270 setCurrent(0,true);
271 break;
272 }
273 case MOVEUP: {
274 FXWindow*prv=tab->getPrev();
275 if (!prv) {return;}
276 prv=prv->getPrev();
277 page->reparent(this, prv);
278 tab->reparent(this, page);
279 setCurrent(iCurr-1,true);
280 break;
281 }
282 case MOVEDOWN: {
283 FXWindow*nxt=page->getNext(); /* is tab */
284 if (!nxt) {return;}
285 nxt=nxt->getNext();/* is page */
286 nxt=nxt->getNext();/* is tab, or NULL */
287 page->reparent(this, nxt);
288 tab->reparent(this, page);
289 setCurrent(iCurr+1,true);
290 break;
291 }
292 }
293 }
294
295
296
ActivateTab(DocTab * tab)297 bool DocTabs::ActivateTab(DocTab*tab)
298 {
299
300 FXint i=indexOfChild(tab);
301 if (i>=0) {
302 setCurrent(i/2,true);
303 return true;
304 } else {
305 return false;
306 }
307
308 }
309
310
311
ActivateTab(FXint n)312 bool DocTabs::ActivateTab(FXint n)
313 {
314 FXWindow*w=childAtIndex((n*2)+1);
315 if (w) {
316 setCurrent(n,true);
317 return true;
318 } else {
319 return false;
320 }
321 }
322
323
324
ActiveTab()325 DocTab*DocTabs::ActiveTab() {
326 return (DocTab*)childAtIndex(getCurrent()*2);
327 }
328
329
330
ActivePage()331 FXWindow*DocTabs::ActivePage() {
332 FXWindow*page=childAtIndex((getCurrent()*2)+1);
333 if (page) {
334 return page;
335 } else {
336 layout();
337 return childAtIndex((getCurrent()*2)+1);
338 }
339 }
340
341
342
343 /* ForEachTab walks through the open tabs, and passes the tab index, the tab item object,
344 and the page item object to the callback, along with the user data. The callback should
345 return true to continue iterating, or false to break out of the loop. By default, the
346 "wait" cursor is displayed during execution, unless you call it with hourglass=false.
347 */
ForEachTab(TabCallback cb,void * user_data,bool hourglass)348 void DocTabs::ForEachTab(TabCallback cb, void *user_data, bool hourglass)
349 {
350 FXWindow*tab,*page;
351 FXint index=0;
352 update();
353 if ( hourglass ) {
354 getApp()->beginWaitCursor();
355 }
356 for (tab=getFirst(); tab && (page=tab->getNext()); tab=page->getNext(), index++) {
357 if (!cb(index,(DocTab*)tab,page,user_data)) { break; }
358 }
359 if ( hourglass ) { getApp()->endWaitCursor(); }
360 }
361
362
363
PageAt(FXint n)364 FXWindow*DocTabs::PageAt(FXint n)
365 {
366 return childAtIndex((n*2)+1);
367 }
368
369
OrientTabsCB(FXint index,DocTab * tab,FXWindow * page,void * user_data)370 bool OrientTabsCB(FXint index, DocTab*tab, FXWindow*page, void*user_data)
371 {
372 FXint ornt=*((FXint*)user_data);
373 tab->setTabOrientation(ornt);
374 tab->setDefaultDragCursor(
375 tab->getApp()->getDefaultCursor(((ornt==TAB_TOP)||(ornt==TAB_BOTTOM)) ? DEF_HSPLIT_CURSOR : DEF_VSPLIT_CURSOR));
376 tab->setDragCursor(tab->getApp()->getDefaultCursor(DEF_ARROW_CURSOR));
377 return true;
378 }
379
380
381
setTabStyle(FXuint style)382 void DocTabs::setTabStyle(FXuint style)
383 {
384 FXTabBook::setTabStyle(style);
385 FXint TabOrientation=TAB_TOP;
386 switch(style){
387 case TABBOOK_TOPTABS:
388 TabOrientation=TAB_TOP;
389 break;
390 case TABBOOK_BOTTOMTABS:
391 TabOrientation=TAB_BOTTOM;
392 break;
393 case TABBOOK_LEFTTABS:
394 TabOrientation=TAB_LEFT;
395 break;
396 case TABBOOK_RIGHTTABS:
397 TabOrientation=TAB_RIGHT;
398 break;
399 }
400 ForEachTab(OrientTabsCB, &TabOrientation, false);
401 if (tabs_compact=='A') setTabsCompact('A');
402 setCurrent(getCurrent(),false);
403 }
404
405
406
407 // T, B, L, R: Top, Bottom, Left, Right
setTabStyleByChar(FXuchar c)408 void DocTabs::setTabStyleByChar(FXuchar c)
409 {
410 switch (c) {
411 case 'B': { setTabStyle(TABBOOK_BOTTOMTABS); break; }
412 case 'L': { setTabStyle(TABBOOK_LEFTTABS); break; }
413 case 'R': { setTabStyle(TABBOOK_RIGHTTABS); break; }
414 default: { setTabStyle(TABBOOK_TOPTABS); break; }
415 }
416 }
417
418
419
420 // Set tab header widths:
421 // 'U' -- Uniform (All tabs the same width, based on the widest label)
422 // 'P' -- Packed (Tabs sized individually according to their label width)
423 // 'A' -- Automatic ("Packed" when orientation is top or bottom, "Uniform" when it's left or right)
setTabsCompact(FXuchar compact)424 void DocTabs::setTabsCompact(FXuchar compact)
425 {
426 FXuint packing_hints = getPackingHints();
427 FXuint ts=getTabStyle();
428 tabs_compact=compact;
429 if (compact=='A') {
430 compact=(ts==TABBOOK_TOPTABS||ts==TABBOOK_BOTTOMTABS)?'P':'U';
431 }
432 if ( compact=='P' ) {
433 packing_hints &= ~PACK_UNIFORM_WIDTH;
434 } else {
435 packing_hints |= PACK_UNIFORM_WIDTH;
436 }
437 setPackingHints(packing_hints);
438 }
439
440
441 // If forward is TRUE, activate next tab, else activate previous tab.
442 // Behavior is circular - that is, last->next==first; first->prev==last;.
FocusNextTab(bool forward)443 void DocTabs::FocusNextTab(bool forward)
444 {
445 int ntabs=numChildren()/2;
446 int itab=getCurrent();
447 if (forward) {
448 if ((itab+1)==ntabs) { itab=0; } else { itab++; }
449 } else {
450 if (itab==0) { itab=ntabs-1; } else { itab--; }
451 }
452 setCurrent(itab,true);
453 }
454
455
UpdateTabIconsCB(FXint index,DocTab * tab,FXWindow * page,void * user_data)456 static bool UpdateTabIconsCB(FXint index, DocTab*tab, FXWindow*page, void*user_data)
457 {
458 tab->SetIcon(DOCTAB_SAME);
459 return true;
460 }
461
462
setCurrent(FXint panel,FXbool notify)463 void DocTabs::setCurrent(FXint panel,FXbool notify)
464 {
465 ShadyTabs::setCurrent(panel,notify);
466 ForEachTab(UpdateTabIconsCB,NULL,false);
467 }
468
469
show()470 void DocTabs::show()
471 {
472 setCurrent(getCurrent(),false);
473 }
474
475
476 #define TAB_DND_NAME "FxteDnDTab"
477 static FXDragType FxteDnDTabType=0;
478
479
480
481 FXDEFMAP(DocTab) DocTabMap[]={
482 FXMAPFUNC(SEL_DND_ENTER, 0, DocTab::onDnd),
483 FXMAPFUNC(SEL_DND_LEAVE, 0, DocTab::onDnd),
484 FXMAPFUNC(SEL_DND_DROP, 0, DocTab::onDnd),
485 FXMAPFUNC(SEL_DND_MOTION, 0, DocTab::onDnd),
486 FXMAPFUNC(SEL_DND_REQUEST, 0, DocTab::onDnd),
487 FXMAPFUNC(SEL_BEGINDRAG, 0, DocTab::onDnd),
488 FXMAPFUNC(SEL_ENDDRAG, 0, DocTab::onDnd),
489 FXMAPFUNC(SEL_LEFTBUTTONPRESS, 0, DocTab::onDnd),
490 FXMAPFUNC(SEL_LEFTBUTTONRELEASE, 0, DocTab::onDnd),
491 FXMAPFUNC(SEL_DRAGGED, 0, DocTab::onDnd),
492 FXMAPFUNC(SEL_MOTION, 0, DocTab::onDnd),
493 FXMAPFUNC(SEL_RIGHTBUTTONRELEASE, 0, DocTab::onDnd)
494 };
495
496 FXIMPLEMENT(DocTab,FXTabItem,DocTabMap,ARRAYNUMBER(DocTabMap));
497
498
499
500
501
onDnd(FXObject * sender,FXSelector sel,void * p)502 long DocTab::onDnd(FXObject* sender,FXSelector sel, void*p)
503 {
504 FXEvent* ev=(FXEvent*)p;
505 switch(FXSELTYPE(sel)) {
506 case SEL_DND_ENTER: {
507 setDragRectangle(0,0,width,height,false);
508 if (offeredDNDType(FROM_DRAGNDROP,FxteDnDTabType)) {
509 acceptDrop();
510 dnd_accept=true;
511 } else {
512 dnd_accept=false;
513 ((DocTabs*)getParent())->handle(sender,sel,p);
514 }
515 break;
516 }
517 case SEL_DND_LEAVE: {
518 dnd_accept=false;
519 break;
520 }
521 case SEL_DND_DROP: {
522 dnd_accept=false;
523 FXuchar*dnd_data=NULL;
524 FXuint size=0;
525 if (getDNDData(FROM_DRAGNDROP,FxteDnDTabType,dnd_data,size)) {
526 if (dnd_data) {
527 dnd_accept=false;
528 DocTab*src;
529 FXint pid;
530 sscanf((const char*)dnd_data, "%p,%d", &src, &pid);
531 FXFREE(&dnd_data);
532 if ((pid==fxgetpid())&&(src!=this)) {
533 FXWindow *trg;
534 if (defaultDragCursor==getApp()->getDefaultCursor(DEF_HSPLIT_CURSOR)) {
535 trg=((src->getX()+ev->win_x)-getX())>(getWidth()/2)?this->getNext()->getNext():this;
536 } else {
537 trg=((src->getY()+ev->win_y)-getY())>(getHeight()/2)?this->getNext()->getNext():this;
538 }
539 FXWindow*doc=src->getNext();
540 doc->reparent(getParent(), trg);
541 src->reparent(getParent(), doc);
542 ((DocTabs*)getParent())->ActivateTab(src);
543 }
544 }
545 } else {
546 ((DocTabs*)getParent())->handle(sender,sel,p);
547 }
548 break;
549 }
550 case SEL_DND_MOTION: {
551 if (dnd_accept) { acceptDrop(); }
552 break;
553 }
554
555
556 case SEL_LEFTBUTTONPRESS: {
557 grab();
558 flags|=FLAG_TRYDRAG;
559 break;
560 }
561
562
563 case SEL_MOTION: {
564 if ((flags&FLAG_DODRAG)) {
565 handle(this,FXSEL(SEL_DRAGGED,0),p);
566 return 1;
567 }
568 if ((flags&FLAG_TRYDRAG) && (ev->moved) ) {
569 flags&=~FLAG_TRYDRAG;
570 if (handle(this,FXSEL(SEL_BEGINDRAG,0),p)) {
571 flags|=FLAG_DODRAG;
572 }
573 return 1;
574 }
575 return 0;
576 }
577 case SEL_LEFTBUTTONRELEASE: {
578 if (flags&FLAG_DODRAG) {
579 handle(this,FXSEL(SEL_ENDDRAG,0),p);
580 } else {
581 if (((DocTabs*)getParent())->ActiveTab()!=this) { ((DocTabs*)getParent())->ActivateTab(this); }
582 }
583 flags&=~(FLAG_DODRAG|FLAG_TRYDRAG);
584 ungrab();
585 break;
586 }
587 case SEL_BEGINDRAG:{
588 beginDrag(&FxteDnDTabType,1);
589 break;
590 }
591 case SEL_DRAGGED: {
592 handleDrag(ev->root_x,ev->root_y,DRAG_MOVE);
593 if (didAccept()!=DRAG_REJECT) {
594 setDragCursor(defaultDragCursor);
595 } else {
596 setDragCursor(getApp()->getDefaultCursor(DEF_DNDSTOP_CURSOR));
597 }
598 break;
599 }
600 case SEL_ENDDRAG:{
601 endDrag();
602 setDragCursor(getApp()->getDefaultCursor(DEF_ARROW_CURSOR));
603 break;
604 }
605 case SEL_DND_REQUEST: {
606 FXString fmt="";
607 fmt.format("%p,%d", this, fxgetpid());
608 FXint len=fmt.length()+1;
609 char*dnd_data=NULL;
610 FXMALLOC(&dnd_data,char,len);
611 strncpy(dnd_data,fmt.text(), len);
612 dnd_data[len-1]='\0';
613 setDNDData(FROM_DRAGNDROP,FxteDnDTabType,(FXuchar*)dnd_data,len);
614 }
615 case SEL_RIGHTBUTTONRELEASE: {
616 return ((DocTabs*)getParent())->onTabPopupMenu(this, sel,p);
617 }
618 default: return 0;
619 }
620 return 1;
621 }
622
623
624
DocTab(FXTabBar * bar,const FXString & text)625 DocTab::DocTab(FXTabBar*bar, const FXString&text):FXTabItem(bar,FXString::null,NULL,ICON_AFTER_TEXT|JUSTIFY_HZ_APART)
626 {
627 FXApp*a=bar->getApp();
628 if (!FxteDnDTabType) {
629 FXString DnDName;
630 DnDName.format("%s_%d", TAB_DND_NAME, fxgetpid());
631 FxteDnDTabType=a->registerDragType(DnDName);
632 }
633 setDefaultDragCursor(a->getDefaultCursor(
634 ((bar->getTabStyle()==TABBOOK_TOPTABS)||(bar->getTabStyle()==TABBOOK_BOTTOMTABS))?
635 DEF_HSPLIT_CURSOR:DEF_VSPLIT_CURSOR
636 ));
637 setDragCursor(getApp()->getDefaultCursor(DEF_ARROW_CURSOR));
638 dropEnable();
639 setText(text);
640 SetIcon(DOCTAB_CLEAN);
641 }
642
643
644 #define ICO_SIZE 8
645
646
647 static const char clean_mask[] =
648 "________"
649 "________"
650 "________"
651 "________"
652 "________"
653 "________"
654 "________"
655 "________"
656 ;
657
658
659 static const char dirty_mask[] =
660 "X__X__X_"
661 "_X___X__"
662 "__XXX___"
663 "XXXXXXX_"
664 "__XXX___"
665 "_X___X__"
666 "X__X__X_"
667 "________"
668 ;
669
670
671 static const char locked_mask[] =
672 "___##___"
673 "__#__#__"
674 "_#____#_"
675 "_#____#_"
676 "_######_"
677 "_######_"
678 "_##__##_"
679 "_######_"
680 ;
681
682
683
SetIcon(DocTabState state)684 void DocTab::SetIcon(DocTabState state)
685 {
686 const char *mask=NULL;
687 if (state==DOCTAB_SAME) { state=_state; } else { _state=state; }
688 if (!xid) { return; }
689 switch (state) {
690 case DOCTAB_CLEAN: { mask=clean_mask; break; }
691 case DOCTAB_DIRTY: { mask=dirty_mask; break; }
692 case DOCTAB_LOCKED: { mask=locked_mask; break; }
693 default: { mask=clean_mask; break; }
694 }
695 if (getIcon()) {
696 delete getIcon();
697 setIcon(NULL);
698 }
699 FXuint horiz=getTabOrientation()==TAB_TOP||getTabOrientation()==TAB_BOTTOM;
700 FXuchar packed=((DocTabs*)getParent())->getTabsCompact();
701 if (packed=='A') { packed=horiz?'P':'U'; }
702 if ((state==DOCTAB_CLEAN) && (packed=='P')) { return; }
703 FXColor ico_buf[ICO_SIZE*ICO_SIZE];
704 FXColor bg=state==DOCTAB_CLEAN?getBackColor():getApp()->getBackColor();
705 FXColor fg=getTextColor();
706 for (FXint i=0; i<ICO_SIZE*ICO_SIZE; i++) { ico_buf[i]=mask[i]=='_'?bg:fg; }
707 FXIcon *ico=new FXIcon(getApp(),ico_buf,0,IMAGE_OPAQUE,ICO_SIZE,ICO_SIZE);
708 ico->create();
709 setIcon(ico);
710 }
711
712