1 /********************************************************************************
2 * *
3 * M e n u B a r W i d g e t *
4 * *
5 *********************************************************************************
6 * Copyright (C) 1998,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 "FXArray.h"
26 #include "FXHash.h"
27 #include "FXMutex.h"
28 #include "FXStream.h"
29 #include "FXString.h"
30 #include "FXSize.h"
31 #include "FXPoint.h"
32 #include "FXRectangle.h"
33 #include "FXStringDictionary.h"
34 #include "FXSettings.h"
35 #include "FXRegistry.h"
36 #include "FXAccelTable.h"
37 #include "FXEvent.h"
38 #include "FXWindow.h"
39 #include "FXApp.h"
40 #include "FXButton.h"
41 #include "FXMenuBar.h"
42
43
44 /*
45 Notes:
46 - Hittin Alt- key only should attract focus to the first item in the menubar.
47 - If width of menu gets too small, expand the height to make it multiple rows.
48 - FIXME popping a menu and leaving the cursor inside the menu title
49 somehow does not allow keyboard navigation.
50 */
51
52 using namespace FX;
53
54 /*******************************************************************************/
55
56 namespace FX {
57
58 // Map
59 FXDEFMAP(FXMenuBar) FXMenuBarMap[]={
60 FXMAPFUNC(SEL_ENTER,0,FXMenuBar::onEnter),
61 FXMAPFUNC(SEL_LEAVE,0,FXMenuBar::onLeave),
62 FXMAPFUNC(SEL_MOTION,0,FXMenuBar::onMotion),
63 FXMAPFUNC(SEL_LEFTBUTTONPRESS,0,FXMenuBar::onButtonPress),
64 FXMAPFUNC(SEL_LEFTBUTTONRELEASE,0,FXMenuBar::onButtonRelease),
65 FXMAPFUNC(SEL_MIDDLEBUTTONPRESS,0,FXMenuBar::onButtonPress),
66 FXMAPFUNC(SEL_MIDDLEBUTTONRELEASE,0,FXMenuBar::onButtonRelease),
67 FXMAPFUNC(SEL_RIGHTBUTTONPRESS,0,FXMenuBar::onButtonPress),
68 FXMAPFUNC(SEL_RIGHTBUTTONRELEASE,0,FXMenuBar::onButtonRelease),
69 FXMAPFUNC(SEL_FOCUS_RIGHT,0,FXMenuBar::onFocusRight),
70 FXMAPFUNC(SEL_FOCUS_LEFT,0,FXMenuBar::onFocusLeft),
71 FXMAPFUNC(SEL_FOCUS_NEXT,0,FXMenuBar::onDefault),
72 FXMAPFUNC(SEL_FOCUS_PREV,0,FXMenuBar::onDefault),
73 FXMAPFUNC(SEL_FOCUS_UP,0,FXMenuBar::onDefault),
74 FXMAPFUNC(SEL_FOCUS_DOWN,0,FXMenuBar::onDefault),
75 FXMAPFUNC(SEL_COMMAND,FXWindow::ID_UNPOST,FXMenuBar::onCmdUnpost),
76 };
77
78
79 // Object implementation
FXIMPLEMENT(FXMenuBar,FXToolBar,FXMenuBarMap,ARRAYNUMBER (FXMenuBarMap))80 FXIMPLEMENT(FXMenuBar,FXToolBar,FXMenuBarMap,ARRAYNUMBER(FXMenuBarMap))
81
82
83 // Make a floatable menubar
84 FXMenuBar::FXMenuBar(FXComposite* p,FXComposite* q,FXuint opts,FXint x,FXint y,FXint w,FXint h,FXint pl,FXint pr,FXint pt,FXint pb,FXint hs,FXint vs):FXToolBar(p,q,opts,x,y,w,h,pl,pr,pt,pb,hs,vs){
85 flags|=FLAG_ENABLED;
86 dragCursor=getApp()->getDefaultCursor(DEF_RARROW_CURSOR);
87 }
88
89
90 // Make a non-floatable menubar
FXMenuBar(FXComposite * p,FXuint opts,FXint x,FXint y,FXint w,FXint h,FXint pl,FXint pr,FXint pt,FXint pb,FXint hs,FXint vs)91 FXMenuBar::FXMenuBar(FXComposite* p,FXuint opts,FXint x,FXint y,FXint w,FXint h,FXint pl,FXint pr,FXint pt,FXint pb,FXint hs,FXint vs):FXToolBar(p,opts,x,y,w,h,pl,pr,pt,pb,hs,vs){
92 flags|=FLAG_ENABLED;
93 dragCursor=getApp()->getDefaultCursor(DEF_RARROW_CURSOR);
94 }
95
96
97 // Focus moved to right
onFocusRight(FXObject *,FXSelector,void * ptr)98 long FXMenuBar::onFocusRight(FXObject*,FXSelector,void* ptr){
99 FXWindow *child;
100 if(getFocus()){
101 child=getFocus()->getNext();
102 while(child){
103 if(child->handle(this,FXSEL(SEL_FOCUS_SELF,0),ptr)) return 1;
104 child=child->getNext();
105 }
106 child=getFirst();
107 while(child){
108 if(child->handle(this,FXSEL(SEL_FOCUS_SELF,0),ptr)) return 1;
109 child=child->getNext();
110 }
111 }
112 return 0;
113 }
114
115
116 // Focus moved to left
onFocusLeft(FXObject *,FXSelector,void * ptr)117 long FXMenuBar::onFocusLeft(FXObject*,FXSelector,void* ptr){
118 FXWindow *child;
119 if(getFocus()){
120 child=getFocus()->getPrev();
121 while(child){
122 if(child->handle(this,FXSEL(SEL_FOCUS_SELF,0),ptr)) return 1;
123 child=child->getPrev();
124 }
125 child=getLast();
126 while(child){
127 if(child->handle(this,FXSEL(SEL_FOCUS_SELF,0),ptr)) return 1;
128 child=child->getPrev();
129 }
130 }
131 return 0;
132 }
133
134
135 // Enter:- when inside the popup, all is normal!
onEnter(FXObject * sender,FXSelector sel,void * ptr)136 long FXMenuBar::onEnter(FXObject* sender,FXSelector sel,void* ptr){
137 FXint px,py;
138 FXToolBar::onEnter(sender,sel,ptr);
139 if(!getFocus() || !getFocus()->isActive()) return 1;
140 if(((FXEvent*)ptr)->code==CROSSINGNORMAL){
141 translateCoordinatesTo(px,py,getParent(),((FXEvent*)ptr)->win_x,((FXEvent*)ptr)->win_y);
142 if(contains(px,py) && grabbed()) ungrab();
143 }
144 return 1;
145 }
146
147
148 // Leave:- when outside the popup, a click will hide the popup!
onLeave(FXObject * sender,FXSelector sel,void * ptr)149 long FXMenuBar::onLeave(FXObject* sender,FXSelector sel,void* ptr){
150 FXint px,py;
151 FXToolBar::onLeave(sender,sel,ptr);
152 if(!getFocus() || !getFocus()->isActive()) return 1;
153 if(((FXEvent*)ptr)->code==CROSSINGNORMAL){
154 translateCoordinatesTo(px,py,getParent(),((FXEvent*)ptr)->win_x,((FXEvent*)ptr)->win_y);
155 if(!contains(px,py) && !grabbed()) grab();
156 }
157 return 1;
158 }
159
160
161 // We're considered inside the menu bar when either
162 // in the bar or in any active menus
contains(FXint parentx,FXint parenty) const163 FXbool FXMenuBar::contains(FXint parentx,FXint parenty) const {
164 FXint x,y;
165 if(FXComposite::contains(parentx,parenty)) return true;
166 if(getFocus()){
167 getParent()->translateCoordinatesTo(x,y,this,parentx,parenty);
168 if(getFocus()->contains(x,y)) return true;
169 }
170 return false;
171 }
172
173
174 // Moved while outside
175 // We need to do this because the definition of ``inside'' means
176 // that we're inside even though possibly we're not in THIS window!!!
onMotion(FXObject *,FXSelector,void * ptr)177 long FXMenuBar::onMotion(FXObject*,FXSelector,void* ptr){
178 FXEvent* ev=(FXEvent*)ptr;
179 FXint px,py;
180 if(!getFocus() || !getFocus()->isActive()) return 0;
181 translateCoordinatesTo(px,py,getParent(),ev->win_x,ev->win_y);
182 if(contains(px,py)){
183 if(grabbed()) ungrab();
184 }
185 else{
186 if(!grabbed()) grab();
187 }
188 return 0;
189 }
190
191
192 // Button pressed
onButtonPress(FXObject *,FXSelector,void *)193 long FXMenuBar::onButtonPress(FXObject*,FXSelector,void*){
194 FXTRACE((200,"%s::onButtonPress %p\n",getClassName(),this));
195 handle(this,FXSEL(SEL_COMMAND,ID_UNPOST),NULL);
196 return 1;
197 }
198
199
200 // Button released
onButtonRelease(FXObject *,FXSelector,void * ptr)201 long FXMenuBar::onButtonRelease(FXObject*,FXSelector,void* ptr){
202 FXEvent* ev=(FXEvent*)ptr;
203 FXTRACE((200,"%s::onButtonRelease %p\n",getClassName(),this));
204 if(ev->moved){ handle(this,FXSEL(SEL_COMMAND,ID_UNPOST),NULL); }
205 return 1;
206 }
207
208
209 // Unpost the menu
onCmdUnpost(FXObject *,FXSelector,void *)210 long FXMenuBar::onCmdUnpost(FXObject*,FXSelector,void*){
211 FXTRACE((200,"%s::onCmdUnpost %p\n",getClassName(),this));
212 if(getFocus()) getFocus()->killFocus();
213 //killFocus();
214 return 1;
215 }
216
217 }
218