1 /********************************************************************************
2 * *
3 * M e n u B u t t o n O b j e c t *
4 * *
5 *********************************************************************************
6 * Copyright (C) 1998,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: FXMenuButton.cpp,v 1.50 2006/01/22 17:58:35 fox Exp $ *
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 "FXAccelTable.h"
37 #include "FXApp.h"
38 #include "FXDCWindow.h"
39 #include "FXFont.h"
40 #include "FXIcon.h"
41 #include "FXMenuButton.h"
42 #include "FXMenuPane.h"
43
44 #include "FXMenuBar.h"
45
46 /*
47 Notes:
48 - You can turn off arrows.
49 - You can pop the pane right,left,up,or down.
50 - For each of the above, you can align the pane four ways; for
51 the case of popping it down:
52
53 MENUBUTTON_ATTACH_LEFT: MENUBUTTON_ATTACH_RIGHT:
54
55 +------+ +------+
56 |Button| |Button|
57 +------+---+ +---+------+
58 | Pane | | Pane |
59 +----------+ +----------+
60
61
62 MENUBUTTON_ATTACH_CENTER: MENUBUTTON_ATTACH_BOTH:
63
64 +------+ +----------+
65 |Button| | Button |
66 +-+------+-+ +----------+
67 | Pane | | Pane |
68 +----------+ +----------+
69
70 - The width (height) of the pane is taken into account by getDefaultWidth()
71 (getDefaultHeight()), so that the button will stretch to fit the pane.
72 - You can specify horizontal or vertical offset to position the pane away
73 from the button a bit.
74 - Should it grab first before doing the POST?
75 - GUI update disabled while menu is popped up.
76 */
77
78 #define MENUBUTTONARROW_WIDTH 11
79 #define MENUBUTTONARROW_HEIGHT 5
80
81 #define MENUBUTTON_MASK (MENUBUTTON_AUTOGRAY|MENUBUTTON_AUTOHIDE|MENUBUTTON_TOOLBAR|MENUBUTTON_NOARROWS)
82 #define POPUP_MASK (MENUBUTTON_UP|MENUBUTTON_LEFT)
83 #define ATTACH_MASK (MENUBUTTON_ATTACH_RIGHT|MENUBUTTON_ATTACH_CENTER)
84
85 using namespace FX;
86
87 /*******************************************************************************/
88
89 namespace FX {
90
91 // Map
92 FXDEFMAP(FXMenuButton) FXMenuButtonMap[]={
93 FXMAPFUNC(SEL_PAINT,0,FXMenuButton::onPaint),
94 FXMAPFUNC(SEL_UPDATE,0,FXMenuButton::onUpdate),
95 FXMAPFUNC(SEL_ENTER,0,FXMenuButton::onEnter),
96 FXMAPFUNC(SEL_LEAVE,0,FXMenuButton::onLeave),
97 FXMAPFUNC(SEL_MOTION,0,FXMenuButton::onMotion),
98 FXMAPFUNC(SEL_FOCUSIN,0,FXMenuButton::onFocusIn),
99 FXMAPFUNC(SEL_FOCUSOUT,0,FXMenuButton::onFocusOut),
100 FXMAPFUNC(SEL_UNGRABBED,0,FXMenuButton::onUngrabbed),
101 FXMAPFUNC(SEL_LEFTBUTTONPRESS,0,FXMenuButton::onLeftBtnPress),
102 FXMAPFUNC(SEL_LEFTBUTTONRELEASE,0,FXMenuButton::onLeftBtnRelease),
103 FXMAPFUNC(SEL_KEYPRESS,0,FXMenuButton::onKeyPress),
104 FXMAPFUNC(SEL_KEYRELEASE,0,FXMenuButton::onKeyRelease),
105 FXMAPFUNC(SEL_KEYPRESS,FXWindow::ID_HOTKEY,FXMenuButton::onHotKeyPress),
106 FXMAPFUNC(SEL_KEYRELEASE,FXWindow::ID_HOTKEY,FXMenuButton::onHotKeyRelease),
107 FXMAPFUNC(SEL_COMMAND,FXWindow::ID_POST,FXMenuButton::onCmdPost),
108 FXMAPFUNC(SEL_COMMAND,FXWindow::ID_UNPOST,FXMenuButton::onCmdUnpost),
109 };
110
111
112 // Object implementation
FXIMPLEMENT(FXMenuButton,FXLabel,FXMenuButtonMap,ARRAYNUMBER (FXMenuButtonMap))113 FXIMPLEMENT(FXMenuButton,FXLabel,FXMenuButtonMap,ARRAYNUMBER(FXMenuButtonMap))
114
115
116 // Deserialization
117 FXMenuButton::FXMenuButton(){
118 pane=(FXPopup*)-1L;
119 offsetx=0;
120 offsety=0;
121 state=FALSE;
122 }
123
124
125 // Make a check button
FXMenuButton(FXComposite * p,const FXString & text,FXIcon * ic,FXPopup * pup,FXuint opts,FXint x,FXint y,FXint w,FXint h,FXint pl,FXint pr,FXint pt,FXint pb)126 FXMenuButton::FXMenuButton(FXComposite* p,const FXString& text,FXIcon* ic,FXPopup* pup,FXuint opts,FXint x,FXint y,FXint w,FXint h,FXint pl,FXint pr,FXint pt,FXint pb):
127 FXLabel(p,text,ic,opts,x,y,w,h,pl,pr,pt,pb){
128 pane=pup;
129 offsetx=0;
130 offsety=0;
131 state=FALSE;
132 }
133
134
135 // Create window
create()136 void FXMenuButton::create(){
137 FXLabel::create();
138 if(pane) pane->create();
139 }
140
141
142 // Detach window
detach()143 void FXMenuButton::detach(){
144 FXLabel::detach();
145 if(pane) pane->detach();
146 }
147
148
149 // If window can have focus
canFocus() const150 bool FXMenuButton::canFocus() const { return true; }
151
152
153 // Get default width
getDefaultWidth()154 FXint FXMenuButton::getDefaultWidth(){
155 FXint tw=0,iw=0,s=0,w,pw;
156 if(!label.empty()){ tw=labelWidth(label); s=4; }
157 if(!(options&MENUBUTTON_NOARROWS)){
158 if(options&MENUBUTTON_LEFT) iw=MENUBUTTONARROW_HEIGHT; else iw=MENUBUTTONARROW_WIDTH;
159 }
160 if(icon) iw=icon->getWidth();
161 if(!(options&(ICON_AFTER_TEXT|ICON_BEFORE_TEXT))) w=FXMAX(tw,iw); else w=tw+iw+s;
162 w=padleft+padright+(border<<1)+w;
163 if(!(options&MENUBUTTON_LEFT) && (options&MENUBUTTON_ATTACH_RIGHT) && (options&MENUBUTTON_ATTACH_CENTER)){
164 if(pane){ pw=pane->getDefaultWidth(); if(pw>w) w=pw; }
165 }
166 return w;
167 }
168
169
170 // Get default height
getDefaultHeight()171 FXint FXMenuButton::getDefaultHeight(){
172 FXint th=0,ih=0,h,ph;
173 if(!label.empty()){ th=labelHeight(label); }
174 if(!(options&MENUBUTTON_NOARROWS)){
175 if(options&MENUBUTTON_LEFT) ih=MENUBUTTONARROW_WIDTH; else ih=MENUBUTTONARROW_HEIGHT;
176 }
177 if(icon) ih=icon->getHeight();
178 if(!(options&(ICON_ABOVE_TEXT|ICON_BELOW_TEXT))) h=FXMAX(th,ih); else h=th+ih;
179 h=padtop+padbottom+(border<<1)+h;
180 if((options&MENUBUTTON_LEFT) && (options&MENUBUTTON_ATTACH_BOTTOM)&&(options&MENUBUTTON_ATTACH_CENTER)){
181 if(pane){ ph=pane->getDefaultHeight(); if(ph>h) h=ph; }
182 }
183 return h;
184 }
185
186
187 // Implement auto-hide or auto-gray modes
onUpdate(FXObject * sender,FXSelector sel,void * ptr)188 long FXMenuButton::onUpdate(FXObject* sender,FXSelector sel,void* ptr){
189 if(!FXLabel::onUpdate(sender,sel,ptr)){
190 if(options&MENUBUTTON_AUTOHIDE){if(shown()){hide();recalc();}}
191 if(options&MENUBUTTON_AUTOGRAY){disable();}
192 }
193 return 1;
194 }
195
196
197 // Gained focus
onFocusIn(FXObject * sender,FXSelector sel,void * ptr)198 long FXMenuButton::onFocusIn(FXObject* sender,FXSelector sel,void* ptr){
199 FXLabel::onFocusIn(sender,sel,ptr);
200 update(border,border,width-(border<<1),height-(border<<1));
201 return 1;
202 }
203
204
205 // Lost focus
onFocusOut(FXObject * sender,FXSelector sel,void * ptr)206 long FXMenuButton::onFocusOut(FXObject* sender,FXSelector sel,void* ptr){
207 FXLabel::onFocusOut(sender,sel,ptr);
208 update(border,border,width-(border<<1),height-(border<<1));
209 return 1;
210 }
211
212
213 // Inside the button
onEnter(FXObject * sender,FXSelector sel,void * ptr)214 long FXMenuButton::onEnter(FXObject* sender,FXSelector sel,void* ptr){
215 FXLabel::onEnter(sender,sel,ptr);
216 if(isEnabled()){
217 if(options&MENUBUTTON_TOOLBAR) update();
218 }
219 return 1;
220 }
221
222
223 // Outside the button
onLeave(FXObject * sender,FXSelector sel,void * ptr)224 long FXMenuButton::onLeave(FXObject* sender,FXSelector sel,void* ptr){
225 FXLabel::onLeave(sender,sel,ptr);
226 if(isEnabled()){
227 if(options&MENUBUTTON_TOOLBAR) update();
228 }
229 return 1;
230 }
231
232
233 // Pressed left button
onLeftBtnPress(FXObject *,FXSelector,void * ptr)234 long FXMenuButton::onLeftBtnPress(FXObject*,FXSelector,void* ptr){
235 flags&=~FLAG_TIP;
236 handle(this,FXSEL(SEL_FOCUS_SELF,0),ptr);
237 if(isEnabled()){
238 if(target && target->tryHandle(this,FXSEL(SEL_LEFTBUTTONPRESS,message),ptr)) return 1;
239 if(state)
240 handle(this,FXSEL(SEL_COMMAND,ID_UNPOST),NULL);
241 else
242 handle(this,FXSEL(SEL_COMMAND,ID_POST),NULL);
243 return 1;
244 }
245 return 0;
246 }
247
248
249 // Released left button
onLeftBtnRelease(FXObject *,FXSelector,void * ptr)250 long FXMenuButton::onLeftBtnRelease(FXObject*,FXSelector,void* ptr){
251 FXEvent* ev=(FXEvent*)ptr;
252 if(isEnabled()){
253 if(target && target->tryHandle(this,FXSEL(SEL_LEFTBUTTONRELEASE,message),ptr)) return 1;
254 if(ev->moved){ handle(this,FXSEL(SEL_COMMAND,ID_UNPOST),NULL); }
255 return 1;
256 }
257 return 0;
258 }
259
260
261 // If we moved over the pane, we'll ungrab again, or re-grab
262 // when outside of the plane
onMotion(FXObject *,FXSelector,void * ptr)263 long FXMenuButton::onMotion(FXObject*,FXSelector,void* ptr){
264 FXEvent* ev=(FXEvent*)ptr;
265 if(state){
266 if(pane){
267 if(pane->contains(ev->root_x,ev->root_y)){
268 if(grabbed()) ungrab();
269 }
270 else{
271 if(!grabbed()) grab();
272 }
273 return 1;
274 }
275 }
276 return 0;
277 }
278
279
280 // The widget lost the grab for some reason
onUngrabbed(FXObject * sender,FXSelector sel,void * ptr)281 long FXMenuButton::onUngrabbed(FXObject* sender,FXSelector sel,void* ptr){
282 FXLabel::onUngrabbed(sender,sel,ptr);
283 handle(this,FXSEL(SEL_COMMAND,ID_UNPOST),NULL);
284 return 1;
285 }
286
287
288 // Keyboard press; forward to menu pane, or handle it here
onKeyPress(FXObject *,FXSelector sel,void * ptr)289 long FXMenuButton::onKeyPress(FXObject*,FXSelector sel,void* ptr){
290 FXEvent* event=(FXEvent*)ptr;
291 flags&=~FLAG_TIP;
292 if(pane && pane->shown() && pane->handle(pane,sel,ptr)) return 1;
293 if(isEnabled()){
294 if(target && target->tryHandle(this,FXSEL(SEL_KEYPRESS,message),ptr)) return 1;
295 if(event->code==KEY_space || event->code==KEY_KP_Space){
296 if(state)
297 handle(this,FXSEL(SEL_COMMAND,ID_UNPOST),NULL);
298 else
299 handle(this,FXSEL(SEL_COMMAND,ID_POST),NULL);
300 return 1;
301 }
302 }
303 return 0;
304 }
305
306
307 // Keyboard release; forward to menu pane, or handle here
onKeyRelease(FXObject *,FXSelector sel,void * ptr)308 long FXMenuButton::onKeyRelease(FXObject*,FXSelector sel,void* ptr){
309 FXEvent* event=(FXEvent*)ptr;
310 if(pane && pane->shown() && pane->handle(pane,sel,ptr)) return 1;
311 if(isEnabled()){
312 if(target && target->tryHandle(this,FXSEL(SEL_KEYRELEASE,message),ptr)) return 1;
313 if(event->code==KEY_space || event->code==KEY_KP_Space){
314 return 1;
315 }
316 }
317 return 0;
318 }
319
320
321 // Hot key combination pressed
onHotKeyPress(FXObject *,FXSelector,void * ptr)322 long FXMenuButton::onHotKeyPress(FXObject*,FXSelector,void* ptr){
323 FXTRACE((200,"%s::onHotKeyPress %p\n",getClassName(),this));
324 flags&=~FLAG_TIP;
325 handle(this,FXSEL(SEL_FOCUS_SELF,0),ptr);
326 if(isEnabled()){
327 if(state)
328 handle(this,FXSEL(SEL_COMMAND,ID_UNPOST),NULL);
329 else
330 handle(this,FXSEL(SEL_COMMAND,ID_POST),NULL);
331 }
332 return 1;
333 }
334
335
336 // Hot key combination released
onHotKeyRelease(FXObject *,FXSelector,void *)337 long FXMenuButton::onHotKeyRelease(FXObject*,FXSelector,void*){
338 FXTRACE((200,"%s::onHotKeyRelease %p\n",getClassName(),this));
339 return 1;
340 }
341
342
343 // Post the menu
onCmdPost(FXObject *,FXSelector,void *)344 long FXMenuButton::onCmdPost(FXObject*,FXSelector,void*){
345 if(!state){
346 if(pane){
347 FXint x,y,w,h;
348 translateCoordinatesTo(x,y,getRoot(),0,0);
349 w=pane->getShrinkWrap() ? pane->getDefaultWidth() : pane->getWidth();
350 h=pane->getShrinkWrap() ? pane->getDefaultHeight() : pane->getHeight();
351 if((options&MENUBUTTON_LEFT)&&(options&MENUBUTTON_UP)){ // Right
352 if((options&MENUBUTTON_ATTACH_BOTTOM)&&(options&MENUBUTTON_ATTACH_CENTER)){
353 h=height;
354 }
355 else if(options&MENUBUTTON_ATTACH_CENTER){
356 y=y+(height-h)/2;
357 }
358 else if(options&MENUBUTTON_ATTACH_BOTTOM){
359 y=y+height-h;
360 }
361 x=x+offsetx+width;
362 y=y+offsety;
363 }
364 else if(options&MENUBUTTON_LEFT){ // Left
365 if((options&MENUBUTTON_ATTACH_BOTTOM)&&(options&MENUBUTTON_ATTACH_CENTER)){
366 h=height;
367 }
368 else if(options&MENUBUTTON_ATTACH_CENTER){
369 y=y+(height-h)/2;
370 }
371 else if(options&MENUBUTTON_ATTACH_BOTTOM){
372 y=y+height-h;
373 }
374 x=x-offsetx-w;
375 y=y+offsety;
376 }
377 else if(options&MENUBUTTON_UP){ // Up
378 if((options&MENUBUTTON_ATTACH_RIGHT)&&(options&MENUBUTTON_ATTACH_CENTER)){
379 w=width;
380 }
381 else if(options&MENUBUTTON_ATTACH_CENTER){
382 x=x+(width-w)/2;
383 }
384 else if(options&MENUBUTTON_ATTACH_RIGHT){
385 x=x+width-w;
386 }
387 x=x+offsetx;
388 y=y-offsety-h;
389 }
390 else{ // Down
391 if((options&MENUBUTTON_ATTACH_RIGHT)&&(options&MENUBUTTON_ATTACH_CENTER)){
392 w=width;
393 }
394 else if(options&MENUBUTTON_ATTACH_CENTER){
395 x=x+(width-w)/2;
396 }
397 else if(options&MENUBUTTON_ATTACH_RIGHT){
398 x=x+width-w;
399 }
400 x=x+offsetx;
401 y=y+offsety+height;
402 }
403 pane->popup(this,x,y,w,h);
404 if(!grabbed()) grab();
405 }
406 flags&=~FLAG_UPDATE;
407 state=TRUE;
408 update();
409 }
410 return 1;
411 }
412
413
414 // Unpost the menu
onCmdUnpost(FXObject *,FXSelector,void *)415 long FXMenuButton::onCmdUnpost(FXObject*,FXSelector,void*){
416 if(state){
417 if(pane){
418 pane->popdown();
419 if(grabbed()) ungrab();
420 }
421 flags|=FLAG_UPDATE;
422 state=FALSE;
423 update();
424 }
425 return 1;
426 }
427
428
429 // Handle repaint
onPaint(FXObject *,FXSelector,void * ptr)430 long FXMenuButton::onPaint(FXObject*,FXSelector,void* ptr){
431 FXint tw=0,th=0,iw=0,ih=0,tx,ty,ix,iy;
432 FXEvent *ev=(FXEvent*)ptr;
433 FXPoint points[3];
434 FXDCWindow dc(this,ev);
435
436 // Got a border at all?
437 if(options&(FRAME_RAISED|FRAME_SUNKEN)){
438
439 // Toolbar style
440 if(options&MENUBUTTON_TOOLBAR){
441
442 // Enabled and cursor inside, and not popped up
443 if(isEnabled() && underCursor() && !state){
444 dc.setForeground(backColor);
445 dc.fillRectangle(border,border,width-border*2,height-border*2);
446 if(options&FRAME_THICK) drawDoubleRaisedRectangle(dc,0,0,width,height);
447 else drawRaisedRectangle(dc,0,0,width,height);
448 }
449
450 // Enabled and popped up
451 else if(isEnabled() && state){
452 dc.setForeground(hiliteColor);
453 dc.fillRectangle(border,border,width-border*2,height-border*2);
454 if(options&FRAME_THICK) drawDoubleSunkenRectangle(dc,0,0,width,height);
455 else drawSunkenRectangle(dc,0,0,width,height);
456 }
457
458 // Disabled or unchecked or not under cursor
459 else{
460 dc.setForeground(backColor);
461 dc.fillRectangle(0,0,width,height);
462 }
463 }
464
465 // Normal style
466 else{
467
468 // Draw in up state if disabled or up
469 if(!isEnabled() || !state){
470 dc.setForeground(backColor);
471 dc.fillRectangle(border,border,width-border*2,height-border*2);
472 if(options&FRAME_THICK) drawDoubleRaisedRectangle(dc,0,0,width,height);
473 else drawRaisedRectangle(dc,0,0,width,height);
474 }
475
476 // Draw sunken if enabled and either checked or pressed
477 else{
478 dc.setForeground(hiliteColor);
479 dc.fillRectangle(border,border,width-border*2,height-border*2);
480 if(options&FRAME_THICK) drawDoubleSunkenRectangle(dc,0,0,width,height);
481 else drawSunkenRectangle(dc,0,0,width,height);
482 }
483 }
484 }
485
486 // No borders
487 else{
488 if(isEnabled() && state){
489 dc.setForeground(hiliteColor);
490 dc.fillRectangle(0,0,width,height);
491 }
492 else{
493 dc.setForeground(backColor);
494 dc.fillRectangle(0,0,width,height);
495 }
496 }
497
498 // Position text & icon
499 if(!label.empty()){
500 tw=labelWidth(label);
501 th=labelHeight(label);
502 }
503
504 // Icon?
505 if(icon){
506 iw=icon->getWidth();
507 ih=icon->getHeight();
508 }
509
510 // Arrows?
511 else if(!(options&MENUBUTTON_NOARROWS)){
512 if(options&MENUBUTTON_LEFT){
513 ih=MENUBUTTONARROW_WIDTH;
514 iw=MENUBUTTONARROW_HEIGHT;
515 }
516 else{
517 iw=MENUBUTTONARROW_WIDTH;
518 ih=MENUBUTTONARROW_HEIGHT;
519 }
520 }
521
522 // Keep some room for the arrow!
523 just_x(tx,ix,tw,iw);
524 just_y(ty,iy,th,ih);
525
526 // Move a bit when pressed
527 if(state){ ++tx; ++ty; ++ix; ++iy; }
528
529 // Draw icon
530 if(icon){
531 if(isEnabled())
532 dc.drawIcon(icon,ix,iy);
533 else
534 dc.drawIconSunken(icon,ix,iy);
535 }
536
537 // Draw arrows
538 else if(!(options&MENUBUTTON_NOARROWS)){
539
540 // Right arrow
541 if((options&MENUBUTTON_RIGHT)==MENUBUTTON_RIGHT){
542 if(isEnabled())
543 dc.setForeground(textColor);
544 else
545 dc.setForeground(shadowColor);
546 points[0].x=ix;
547 points[0].y=iy;
548 points[1].x=ix;
549 points[1].y=iy+MENUBUTTONARROW_WIDTH-1;
550 points[2].x=ix+MENUBUTTONARROW_HEIGHT;
551 points[2].y=(FXshort)(iy+(MENUBUTTONARROW_WIDTH>>1));
552 dc.fillPolygon(points,3);
553 }
554
555 // Left arrow
556 else if(options&MENUBUTTON_LEFT){
557 if(isEnabled())
558 dc.setForeground(textColor);
559 else
560 dc.setForeground(shadowColor);
561 points[0].x=ix+MENUBUTTONARROW_HEIGHT;
562 points[0].y=iy;
563 points[1].x=ix+MENUBUTTONARROW_HEIGHT;
564 points[1].y=iy+MENUBUTTONARROW_WIDTH-1;
565 points[2].x=ix;
566 points[2].y=(FXshort)(iy+(MENUBUTTONARROW_WIDTH>>1));
567 dc.fillPolygon(points,3);
568 }
569
570 // Up arrow
571 else if(options&MENUBUTTON_UP){
572 if(isEnabled())
573 dc.setForeground(textColor);
574 else
575 dc.setForeground(shadowColor);
576 points[0].x=(FXshort)(ix+(MENUBUTTONARROW_WIDTH>>1));
577 points[0].y=iy-1;
578 points[1].x=ix;
579 points[1].y=iy+MENUBUTTONARROW_HEIGHT;
580 points[2].x=ix+MENUBUTTONARROW_WIDTH;
581 points[2].y=iy+MENUBUTTONARROW_HEIGHT;
582 dc.fillPolygon(points,3);
583 }
584
585 // Down arrow
586 else{
587 if(isEnabled())
588 dc.setForeground(textColor);
589 else
590 dc.setForeground(shadowColor);
591 points[0].x=ix+1;
592 points[0].y=iy;
593 points[2].x=ix+MENUBUTTONARROW_WIDTH-1;
594 points[2].y=iy;
595 points[1].x=(FXshort)(ix+(MENUBUTTONARROW_WIDTH>>1));
596 points[1].y=iy+MENUBUTTONARROW_HEIGHT;
597 dc.fillPolygon(points,3);
598 }
599 }
600
601 // Draw text
602 if(!label.empty()){
603 dc.setFont(font);
604 if(isEnabled()){
605 dc.setForeground(textColor);
606 drawLabel(dc,label,hotoff,tx,ty,tw,th);
607 }
608 else{
609 dc.setForeground(hiliteColor);
610 drawLabel(dc,label,hotoff,tx+1,ty+1,tw,th);
611 dc.setForeground(shadowColor);
612 drawLabel(dc,label,hotoff,tx,ty,tw,th);
613 }
614 }
615
616 // Draw focus
617 if(hasFocus()){
618 if(isEnabled()){
619 dc.drawFocusRectangle(border+1,border+1,width-2*border-2,height-2*border-2);
620 }
621 }
622 return 1;
623 }
624
625
626 // Out of focus chain
killFocus()627 void FXMenuButton::killFocus(){
628 FXLabel::killFocus();
629 handle(this,FXSEL(SEL_COMMAND,ID_UNPOST),NULL);
630 }
631
632
633 // Logically inside pane
contains(FXint parentx,FXint parenty) const634 bool FXMenuButton::contains(FXint parentx,FXint parenty) const {
635 if(pane && pane->shown() && pane->contains(parentx,parenty)) return true;
636 return false;
637 }
638
639
640
641 // Change the popup menu
setMenu(FXPopup * pup)642 void FXMenuButton::setMenu(FXPopup *pup){
643 if(pup!=pane){
644 pane=pup;
645 recalc();
646 }
647 }
648
649
650 // Set icon positioning
setButtonStyle(FXuint style)651 void FXMenuButton::setButtonStyle(FXuint style){
652 FXuint opts=(options&~MENUBUTTON_MASK) | (style&MENUBUTTON_MASK);
653 if(options!=opts){
654 options=opts;
655 update();
656 }
657 }
658
659
660 // Get icon positioning
getButtonStyle() const661 FXuint FXMenuButton::getButtonStyle() const {
662 return (options&MENUBUTTON_MASK);
663 }
664
665
666 // Set menu button popup style
setPopupStyle(FXuint style)667 void FXMenuButton::setPopupStyle(FXuint style){
668 FXuint opts=(options&~POPUP_MASK) | (style&POPUP_MASK);
669 if(options!=opts){
670 options=opts;
671 update();
672 }
673 }
674
675
676 // Get menu button popup style
getPopupStyle() const677 FXuint FXMenuButton::getPopupStyle() const {
678 return (options&POPUP_MASK);
679 }
680
681
682 // Change pane attachment
setAttachment(FXuint att)683 void FXMenuButton::setAttachment(FXuint att){
684 FXuint opts=(options&~ATTACH_MASK) | (att&ATTACH_MASK);
685 if(options!=opts){
686 options=opts;
687 update();
688 }
689 }
690
691
692 // Get pane attachment
getAttachment() const693 FXuint FXMenuButton::getAttachment() const {
694 return (options&ATTACH_MASK);
695 }
696
697
698 // Save object to stream
save(FXStream & store) const699 void FXMenuButton::save(FXStream& store) const {
700 FXLabel::save(store);
701 store << pane;
702 store << offsetx;
703 store << offsety;
704 }
705
706
707 // Load object from stream
load(FXStream & store)708 void FXMenuButton::load(FXStream& store){
709 FXLabel::load(store);
710 store >> pane;
711 store >> offsetx;
712 store >> offsety;
713 }
714
715
716 // Delete it
~FXMenuButton()717 FXMenuButton::~FXMenuButton(){
718 pane=(FXPopup*)-1L;
719 }
720
721 }
722