1 /********************************************************************************
2 * *
3 * T o o l B a r T a b O b j e c t *
4 * *
5 *********************************************************************************
6 * Copyright (C) 1999,2006 by Jeroen van der Zijp. All Rights Reserved. *
7 *********************************************************************************
8 * This library is free software; you can redistribute it and/or *
9 * modify it under the terms of the GNU Lesser General Public *
10 * License as published by the Free Software Foundation; either *
11 * version 2.1 of the License, or (at your option) any later version. *
12 * *
13 * This library is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
16 * Lesser General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU Lesser General Public *
19 * License along with this library; if not, write to the Free Software *
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *
21 *********************************************************************************
22 * $Id: FXToolBarTab.cpp 4937 2019-03-10 19:59:30Z arthurcnorman $ *
23 ********************************************************************************/
24 #include "xincs.h"
25 #include "fxver.h"
26 #include "fxdefs.h"
27 #include "fxkeys.h"
28 #include "FXHash.h"
29 #include "FXThread.h"
30 #include "FXStream.h"
31 #include "FXString.h"
32 #include "FXSize.h"
33 #include "FXPoint.h"
34 #include "FXRectangle.h"
35 #include "FXRegistry.h"
36 #include "FXApp.h"
37 #include "FXDCWindow.h"
38 #include "FXFont.h"
39 #include "FXToolBarTab.h"
40
41
42 /*
43 To do:
44 */
45
46
47 // Size
48 #define TOOLBARTAB_WIDTH 9 // Width for horizontal toolbar tab
49 #define TOOLBARTAB_HEIGHT 24 // Height for horizontal toolbar tab
50
51 // Tool Bar Tab styles
52 #define TOOLBARTAB_MASK TOOLBARTAB_VERTICAL
53
54 using namespace FX;
55
56 /*******************************************************************************/
57
58 namespace FX {
59
60 // Map
61 FXDEFMAP(FXToolBarTab) FXToolBarTabMap[]={
62 FXMAPFUNC(SEL_PAINT,0,FXToolBarTab::onPaint),
63 FXMAPFUNC(SEL_UPDATE,0,FXToolBarTab::onUpdate),
64 FXMAPFUNC(SEL_ENTER,0,FXToolBarTab::onEnter),
65 FXMAPFUNC(SEL_LEAVE,0,FXToolBarTab::onLeave),
66 FXMAPFUNC(SEL_UNGRABBED,0,FXToolBarTab::onUngrabbed),
67 FXMAPFUNC(SEL_LEFTBUTTONPRESS,0,FXToolBarTab::onLeftBtnPress),
68 FXMAPFUNC(SEL_LEFTBUTTONRELEASE,0,FXToolBarTab::onLeftBtnRelease),
69 FXMAPFUNC(SEL_KEYPRESS,0,FXToolBarTab::onKeyPress),
70 FXMAPFUNC(SEL_KEYRELEASE,0,FXToolBarTab::onKeyRelease),
71 FXMAPFUNC(SEL_QUERY_TIP,0,FXToolBarTab::onQueryTip),
72 FXMAPFUNC(SEL_UPDATE,FXToolBarTab::ID_COLLAPSE,FXToolBarTab::onUpdCollapse),
73 FXMAPFUNC(SEL_UPDATE,FXToolBarTab::ID_UNCOLLAPSE,FXToolBarTab::onUpdUncollapse),
74 FXMAPFUNC(SEL_COMMAND,FXToolBarTab::ID_COLLAPSE,FXToolBarTab::onCmdCollapse),
75 FXMAPFUNC(SEL_COMMAND,FXToolBarTab::ID_UNCOLLAPSE,FXToolBarTab::onCmdUncollapse),
76 FXMAPFUNC(SEL_COMMAND,FXToolBarTab::ID_SETTIPSTRING,FXToolBarTab::onCmdSetTip),
77 FXMAPFUNC(SEL_COMMAND,FXToolBarTab::ID_GETTIPSTRING,FXToolBarTab::onCmdGetTip),
78 };
79
80
81 // Object implementation
FXIMPLEMENT(FXToolBarTab,FXFrame,FXToolBarTabMap,ARRAYNUMBER (FXToolBarTabMap))82 FXIMPLEMENT(FXToolBarTab,FXFrame,FXToolBarTabMap,ARRAYNUMBER(FXToolBarTabMap))
83
84
85 // Deserialization
86 FXToolBarTab::FXToolBarTab(){
87 flags|=FLAG_ENABLED;
88 activeColor=FXRGB(150,156,224);
89 collapsed=FALSE;
90 down=FALSE;
91 }
92
93
94 // Construct and init
FXToolBarTab(FXComposite * p,FXObject * tgt,FXSelector sel,FXuint opts,FXint x,FXint y,FXint w,FXint h)95 FXToolBarTab::FXToolBarTab(FXComposite* p,FXObject* tgt,FXSelector sel,FXuint opts,FXint x,FXint y,FXint w,FXint h):
96 FXFrame(p,opts,x,y,w,h){
97 flags|=FLAG_ENABLED;
98 activeColor=FXRGB(150,156,224);
99 target=tgt;
100 message=sel;
101 collapsed=FALSE;
102 down=FALSE;
103 }
104
105
106 // If window can have focus
canFocus() const107 bool FXToolBarTab::canFocus() const { return true; }
108
109
110 // Enable the window
enable()111 void FXToolBarTab::enable(){
112 if(!(flags&FLAG_ENABLED)){
113 FXFrame::enable();
114 update();
115 }
116 }
117
118
119 // Disable the window
disable()120 void FXToolBarTab::disable(){
121 if(flags&FLAG_ENABLED){
122 FXFrame::disable();
123 update();
124 }
125 }
126
127
128 // Get default width
getDefaultWidth()129 FXint FXToolBarTab::getDefaultWidth(){
130 FXWindow *sibling=getNext() ? getNext() : getPrev();
131 FXint w;
132 if(options&TOOLBARTAB_VERTICAL){ // Vertical
133 if(collapsed){
134 w=TOOLBARTAB_WIDTH;
135 }
136 else{
137 w=TOOLBARTAB_HEIGHT;
138 if(sibling) w=sibling->getDefaultWidth();
139 }
140 }
141 else{ // Horizontal
142 if(collapsed){
143 w=TOOLBARTAB_HEIGHT;
144 if(sibling) w=sibling->getDefaultHeight();
145 }
146 else{
147 w=TOOLBARTAB_WIDTH;
148 }
149 }
150 return w;
151 }
152
153
154 // Get default height
getDefaultHeight()155 FXint FXToolBarTab::getDefaultHeight(){
156 FXWindow *sibling=getNext() ? getNext() : getPrev();
157 FXint h;
158 if(options&TOOLBARTAB_VERTICAL){ // Vertical
159 if(collapsed){
160 h=TOOLBARTAB_HEIGHT;
161 if(sibling) h=sibling->getDefaultWidth();
162 }
163 else{
164 h=TOOLBARTAB_WIDTH;
165 }
166 }
167 else{ // Horizontal
168 if(collapsed){
169 h=TOOLBARTAB_WIDTH;
170 }
171 else{
172 h=TOOLBARTAB_HEIGHT;
173 if(sibling) h=sibling->getDefaultHeight();
174 }
175 }
176 return h;
177 }
178
179
180 // Collapse or uncollapse
collapse(FXbool fold,FXbool notify)181 void FXToolBarTab::collapse(FXbool fold,FXbool notify){
182 FXWindow *sibling;
183 if(fold!=collapsed){
184 sibling=getNext() ? getNext() : getPrev();
185 if(sibling){
186 if(fold){
187 sibling->hide();
188 }
189 else{
190 sibling->show();
191 }
192 }
193 collapsed=fold;
194 recalc();
195 update();
196 if(notify && target) target->tryHandle(this,FXSEL(SEL_COMMAND,message),(void*)(FXuval)fold);
197 }
198 }
199
200
201 // Update
onUpdate(FXObject * sender,FXSelector sel,void * ptr)202 long FXToolBarTab::onUpdate(FXObject* sender,FXSelector sel,void* ptr){
203 FXWindow *sibling=getNext() ? getNext() : getPrev();
204 FXFrame::onUpdate(sender,sel,ptr);
205 if(sibling){
206 if(sibling->shown() && collapsed){
207 collapsed=FALSE;
208 update();
209 recalc();
210 }
211 else if(!sibling->shown() && !collapsed){
212 collapsed=TRUE;
213 update();
214 recalc();
215 }
216 }
217 return 1;
218 }
219
220
221 // Entered button
onEnter(FXObject * sender,FXSelector sel,void * ptr)222 long FXToolBarTab::onEnter(FXObject* sender,FXSelector sel,void* ptr){
223 FXFrame::onEnter(sender,sel,ptr);
224 if(isEnabled()){
225 if(flags&FLAG_PRESSED) down=TRUE;
226 update();
227 }
228 return 1;
229 }
230
231
232 // Leave button
onLeave(FXObject * sender,FXSelector sel,void * ptr)233 long FXToolBarTab::onLeave(FXObject* sender,FXSelector sel,void* ptr){
234 FXFrame::onLeave(sender,sel,ptr);
235 if(isEnabled()){
236 if(flags&FLAG_PRESSED) down=FALSE;
237 update();
238 }
239 return 1;
240 }
241
242
243 // Pressed mouse button
onLeftBtnPress(FXObject * sender,FXSelector sel,void * ptr)244 long FXToolBarTab::onLeftBtnPress(FXObject* sender,FXSelector sel,void* ptr){
245 if(!FXFrame::onLeftBtnPress(sender,sel,ptr)){
246 if(isEnabled() && !(flags&FLAG_PRESSED)){
247 flags|=FLAG_PRESSED;
248 flags&=~FLAG_UPDATE;
249 down=TRUE;
250 update();
251 return 1;
252 }
253 }
254 return 0;
255 }
256
257
258 // Released mouse button
onLeftBtnRelease(FXObject * sender,FXSelector sel,void * ptr)259 long FXToolBarTab::onLeftBtnRelease(FXObject* sender,FXSelector sel,void* ptr){
260 FXbool click=down;
261 if(!FXFrame::onLeftBtnRelease(sender,sel,ptr)){
262 if(isEnabled() && (flags&FLAG_PRESSED)){
263 flags|=FLAG_UPDATE;
264 flags&=~FLAG_PRESSED;
265 down=FALSE;
266 update();
267 if(click) collapse(!collapsed,TRUE);
268 return 1;
269 }
270 }
271 return 0;
272 }
273
274
275 // The widget lost the grab for some reason
onUngrabbed(FXObject * sender,FXSelector sel,void * ptr)276 long FXToolBarTab::onUngrabbed(FXObject* sender,FXSelector sel,void* ptr){
277 FXFrame::onUngrabbed(sender,sel,ptr);
278 flags&=~FLAG_PRESSED;
279 flags|=FLAG_UPDATE;
280 down=FALSE;
281 update();
282 return 1;
283 }
284
285
286 // Key Press
onKeyPress(FXObject *,FXSelector,void * ptr)287 long FXToolBarTab::onKeyPress(FXObject*,FXSelector,void* ptr){
288 FXEvent* event=(FXEvent*)ptr;
289 flags&=~FLAG_TIP;
290 if(isEnabled() && !(flags&FLAG_PRESSED)){
291 if(target && target->tryHandle(this,FXSEL(SEL_KEYPRESS,message),ptr)) return 1;
292 if(event->code==KEY_space || event->code==KEY_KP_Space){
293 down=TRUE;
294 update();
295 flags|=FLAG_PRESSED;
296 flags&=~FLAG_UPDATE;
297 return 1;
298 }
299 }
300 return 0;
301 }
302
303
304 // Key Release
onKeyRelease(FXObject *,FXSelector,void * ptr)305 long FXToolBarTab::onKeyRelease(FXObject*,FXSelector,void* ptr){
306 FXEvent* event=(FXEvent*)ptr;
307 if(isEnabled() && (flags&FLAG_PRESSED)){
308 if(target && target->tryHandle(this,FXSEL(SEL_KEYRELEASE,message),ptr)) return 1;
309 if(event->code==KEY_space || event->code==KEY_KP_Space){
310 down=FALSE;
311 update();
312 flags|=FLAG_UPDATE;
313 flags&=~FLAG_PRESSED;
314 collapse(!collapsed,TRUE);
315 return 1;
316 }
317 }
318 return 0;
319 }
320
321
322 // Collapse
onCmdCollapse(FXObject *,FXSelector,void *)323 long FXToolBarTab::onCmdCollapse(FXObject*,FXSelector,void*){
324 collapse(TRUE,TRUE);
325 return 1;
326 }
327
328
329 // Update collapse
onUpdCollapse(FXObject * sender,FXSelector,void *)330 long FXToolBarTab::onUpdCollapse(FXObject* sender,FXSelector,void*){
331 if(collapsed)
332 sender->handle(this,FXSEL(SEL_COMMAND,ID_CHECK),NULL);
333 else
334 sender->handle(this,FXSEL(SEL_COMMAND,ID_UNCHECK),NULL);
335 return 1;
336 }
337
338
339 // Uncollapse
onCmdUncollapse(FXObject *,FXSelector,void *)340 long FXToolBarTab::onCmdUncollapse(FXObject*,FXSelector,void*){
341 collapse(FALSE,TRUE);
342 return 1;
343 }
344
345
346 // Update uncollapse
onUpdUncollapse(FXObject * sender,FXSelector,void *)347 long FXToolBarTab::onUpdUncollapse(FXObject* sender,FXSelector,void*){
348 if(!collapsed)
349 sender->handle(this,FXSEL(SEL_COMMAND,ID_CHECK),NULL);
350 else
351 sender->handle(this,FXSEL(SEL_COMMAND,ID_UNCHECK),NULL);
352 return 1;
353 }
354
355
356 // We were asked about tip text
onQueryTip(FXObject * sender,FXSelector sel,void * ptr)357 long FXToolBarTab::onQueryTip(FXObject* sender,FXSelector sel,void* ptr){
358 if(FXWindow::onQueryTip(sender,sel,ptr)) return 1;
359 if((flags&FLAG_TIP) && !tip.empty()){
360 sender->handle(this,FXSEL(SEL_COMMAND,ID_SETSTRINGVALUE),(void*)&tip);
361 return 1;
362 }
363 return 0;
364 }
365
366
367 // Set tip using a message
onCmdSetTip(FXObject *,FXSelector,void * ptr)368 long FXToolBarTab::onCmdSetTip(FXObject*,FXSelector,void* ptr){
369 setTipText(*((FXString*)ptr));
370 return 1;
371 }
372
373
374 // Get tip using a message
onCmdGetTip(FXObject *,FXSelector,void * ptr)375 long FXToolBarTab::onCmdGetTip(FXObject*,FXSelector,void* ptr){
376 *((FXString*)ptr)=getTipText();
377 return 1;
378 }
379
380
381 // Draw horizontal speckles
drawHSpeckles(FXDCWindow & dc,FXint x,FXint w)382 void FXToolBarTab::drawHSpeckles(FXDCWindow& dc,FXint x,FXint w){
383 FXint i;
384 dc.setForeground(hiliteColor);
385 for(i=0; i<w-5; i+=4){dc.drawPoint(x+i,2);dc.drawPoint(x+i+1,5);}
386 dc.setForeground(shadowColor);
387 for(i=0; i<w-5; i+=4){dc.drawPoint(x+i+1,3);dc.drawPoint(x+i+2,6);}
388 }
389
390
391 // Draw vertical speckles
drawVSpeckles(FXDCWindow & dc,FXint y,FXint h)392 void FXToolBarTab::drawVSpeckles(FXDCWindow& dc,FXint y,FXint h){
393 FXint i;
394 dc.setForeground(hiliteColor);
395 for(i=0; i<h-5; i+=3){dc.drawPoint(2,y+i+1);dc.drawPoint(5,y+i);}
396 dc.setForeground(shadowColor);
397 for(i=0; i<h-5; i+=3){dc.drawPoint(6,y+i+1);dc.drawPoint(3,y+i+2);}
398 }
399
400
401 // Draw up arrow
drawUpArrow(FXDCWindow & dc)402 void FXToolBarTab::drawUpArrow(FXDCWindow& dc){
403 dc.setForeground(borderColor);
404 dc.drawLine(2,height-5,6,height-5);
405 dc.drawPoint(3,height-6);
406 dc.drawPoint(4,height-7);
407 dc.drawPoint(5,height-6);
408 dc.drawPoint(4,height-6);
409 }
410
411
412 // Draw down arrow
drawDownArrow(FXDCWindow & dc)413 void FXToolBarTab::drawDownArrow(FXDCWindow& dc){
414 dc.setForeground(borderColor);
415 dc.drawLine(2,4,6,4);
416 dc.drawPoint(3,5);
417 dc.drawPoint(4,6);
418 dc.drawPoint(5,5);
419 dc.drawPoint(4,5);
420 }
421
422
423 // Draw left arrow
drawLeftArrow(FXDCWindow & dc)424 void FXToolBarTab::drawLeftArrow(FXDCWindow& dc){
425 dc.setForeground(borderColor);
426 dc.drawLine(width-5,2,width-5,6);
427 dc.drawPoint(width-6,3);
428 dc.drawPoint(width-7,4);
429 dc.drawPoint(width-6,5);
430 dc.drawPoint(width-6,4);
431 }
432
433
434 // Draw right arrow
drawRightArrow(FXDCWindow & dc)435 void FXToolBarTab::drawRightArrow(FXDCWindow& dc){
436 dc.setForeground(borderColor);
437 dc.drawLine(4,2,4,6);
438 dc.drawPoint(5,3);
439 dc.drawPoint(6,4);
440 dc.drawPoint(5,5);
441 dc.drawPoint(5,4);
442 }
443
444
445 // Handle repaint
onPaint(FXObject *,FXSelector,void * ptr)446 long FXToolBarTab::onPaint(FXObject*,FXSelector,void* ptr){
447 FXEvent *ev=(FXEvent*)ptr;
448 FXDCWindow dc(this,ev);
449
450 // Got a border at all?
451 if(options&(FRAME_RAISED|FRAME_SUNKEN)){
452
453 // Draw sunken if enabled and either checked or pressed
454 if(isEnabled() && down){
455 if(down) dc.setForeground(hiliteColor); else dc.setForeground(backColor);
456 dc.fillRectangle(border,border,width-border*2,height-border*2);
457 if(options&FRAME_THICK) drawDoubleSunkenRectangle(dc,0,0,width,height);
458 else drawSunkenRectangle(dc,0,0,width,height);
459 }
460
461 // Draw in up state if disabled or up
462 else{
463 if(underCursor())
464 dc.setForeground(activeColor);
465 else
466 dc.setForeground(backColor);
467 dc.fillRectangle(border,border,width-border*2,height-border*2);
468 if(options&FRAME_THICK) drawDoubleRaisedRectangle(dc,0,0,width,height);
469 else drawRaisedRectangle(dc,0,0,width,height);
470 }
471 }
472
473 // No borders
474 else{
475 if(isEnabled() && down){
476 dc.setForeground(hiliteColor);
477 dc.fillRectangle(0,0,width,height);
478 }
479 else{
480 if(underCursor())
481 dc.setForeground(activeColor);
482 else
483 dc.setForeground(backColor);
484 dc.fillRectangle(0,0,width,height);
485 }
486 }
487
488 // Draw spickles
489 if(options&TOOLBARTAB_VERTICAL){ // Vertical
490 if(collapsed){
491 if(options&LAYOUT_BOTTOM){
492 drawVSpeckles(dc,3,height-10);
493 drawUpArrow(dc);
494 }
495 else{
496 drawVSpeckles(dc,10,height-10);
497 drawDownArrow(dc);
498 }
499 }
500 else{
501 if(options&LAYOUT_RIGHT){
502 drawHSpeckles(dc,3,width-10);
503 drawLeftArrow(dc);
504 }
505 else{
506 drawHSpeckles(dc,10,width-10);
507 drawRightArrow(dc);
508 }
509 }
510 }
511 else{ // Horizontal
512 if(collapsed){
513 if(options&LAYOUT_RIGHT){
514 drawHSpeckles(dc,3,width-10);
515 drawLeftArrow(dc);
516 }
517 else{
518 drawHSpeckles(dc,10,width-10);
519 drawRightArrow(dc);
520 }
521 }
522 else{
523 if(options&LAYOUT_BOTTOM){
524 drawVSpeckles(dc,3,height-10);
525 drawUpArrow(dc);
526 }
527 else{
528 drawVSpeckles(dc,10,height-10);
529 drawDownArrow(dc);
530 }
531 }
532 }
533 return 1;
534 }
535
536
537 // Change tab style
setTabStyle(FXuint style)538 void FXToolBarTab::setTabStyle(FXuint style){
539 FXuint opts=(options&~TOOLBARTAB_MASK) | (style&TOOLBARTAB_MASK);
540 if(options!=opts){
541 options=opts;
542 update();
543 }
544 }
545
546
547 // Get tab style
getTabStyle() const548 FXuint FXToolBarTab::getTabStyle() const {
549 return (options&TOOLBARTAB_MASK);
550 }
551
552
553 // Set text color
setActiveColor(FXColor clr)554 void FXToolBarTab::setActiveColor(FXColor clr){
555 if(clr!=activeColor){
556 activeColor=clr;
557 update();
558 }
559 }
560
561
562 // Save object to stream
save(FXStream & store) const563 void FXToolBarTab::save(FXStream& store) const {
564 FXFrame::save(store);
565 store << activeColor;
566 store << tip;
567 store << collapsed;
568 }
569
570
571
572 // Load object from stream
load(FXStream & store)573 void FXToolBarTab::load(FXStream& store){
574 FXFrame::load(store);
575 store >> activeColor;
576 store >> tip;
577 store >> collapsed;
578 }
579
580 }
581