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