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