1 /********************************************************************************
2 * *
3 * C o m p o s i t e W i n d o w O b j e c t *
4 * *
5 *********************************************************************************
6 * Copyright (C) 1997,2020 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 "FXAccelTable.h"
38 #include "FXEvent.h"
39 #include "FXWindow.h"
40 #include "FXApp.h"
41 #include "FXComposite.h"
42
43
44 /*
45 Notes:
46 - Rather a slim class.
47 - Focus should be assigned to a window via SEL_FOCUSELF message.
48 Composite widgets won't have focus so SEL_FOCUSELF should return 0
49 and do nothing.
50 - Maybe add flag to exempt a widget from maxChildWidth() and/or maxChildHeight()
51 so that things like separators can stay small when everything else gets
52 as big as the biggest child.
53 */
54
55 using namespace FX;
56
57 /*******************************************************************************/
58
59 namespace FX {
60
61 // Map
62 FXDEFMAP(FXComposite) FXCompositeMap[]={
63 FXMAPFUNC(SEL_KEYPRESS,0,FXComposite::onKeyPress),
64 FXMAPFUNC(SEL_KEYRELEASE,0,FXComposite::onKeyRelease),
65 FXMAPFUNC(SEL_FOCUS_NEXT,0,FXComposite::onFocusNext),
66 FXMAPFUNC(SEL_FOCUS_PREV,0,FXComposite::onFocusPrev),
67 FXMAPFUNC(SEL_FOCUS_UP,0,FXComposite::onFocusPrev),
68 FXMAPFUNC(SEL_FOCUS_DOWN,0,FXComposite::onFocusNext),
69 FXMAPFUNC(SEL_FOCUS_LEFT,0,FXComposite::onFocusPrev),
70 FXMAPFUNC(SEL_FOCUS_RIGHT,0,FXComposite::onFocusNext),
71 FXMAPFUNC(SEL_COMMAND,FXComposite::ID_UPDATE,FXComposite::onCmdUpdate),
72 };
73
74
75 // Object implementation
FXIMPLEMENT(FXComposite,FXWindow,FXCompositeMap,ARRAYNUMBER (FXCompositeMap))76 FXIMPLEMENT(FXComposite,FXWindow,FXCompositeMap,ARRAYNUMBER(FXCompositeMap))
77
78
79 // Only used for Root Window
80 FXComposite::FXComposite(FXApp* a,FXVisual *vis):FXWindow(a,vis){
81 }
82
83
84 // Only used for Shell Window
FXComposite(FXApp * a,FXWindow * own,FXuint opts,FXint x,FXint y,FXint w,FXint h)85 FXComposite::FXComposite(FXApp* a,FXWindow* own,FXuint opts,FXint x,FXint y,FXint w,FXint h):FXWindow(a,own,opts,x,y,w,h){
86 }
87
88
89 // Create empty composite window
FXComposite(FXComposite * p,FXuint opts,FXint x,FXint y,FXint w,FXint h)90 FXComposite::FXComposite(FXComposite* p,FXuint opts,FXint x,FXint y,FXint w,FXint h):FXWindow(p,opts,x,y,w,h){
91 }
92
93
94 // Is widget a composite
isComposite() const95 FXbool FXComposite::isComposite() const {
96 return true;
97 }
98
99
100 // Create window
create()101 void FXComposite::create(){
102 FXWindow::create();
103 for(FXWindow *c=getFirst(); c; c=c->getNext()) c->create();
104 }
105
106
107 // Detach window
detach()108 void FXComposite::detach(){
109 for(FXWindow *c=getFirst(); c; c=c->getNext()) c->detach();
110 FXWindow::detach();
111 }
112
113
114 // Destroy window
destroy()115 void FXComposite::destroy(){
116 for(FXWindow *c=getFirst(); c; c=c->getNext()) c->destroy();
117 FXWindow::destroy();
118 }
119
120
121 // Get width
getDefaultWidth()122 FXint FXComposite::getDefaultWidth(){
123 FXint w=0,t;
124 for(FXWindow *child=getFirst(); child; child=child->getNext()){
125 if(child->shown()){
126 t=child->getX()+child->getWidth();
127 if(w<t) w=t;
128 }
129 }
130 return w;
131 }
132
133
134 // Get height
getDefaultHeight()135 FXint FXComposite::getDefaultHeight(){
136 FXint h=0,t;
137 for(FXWindow *child=getFirst(); child; child=child->getNext()){
138 if(child->shown()){
139 t=child->getY()+child->getHeight();
140 if(h<t) h=t;
141 }
142 }
143 return h;
144 }
145
146
147 // Get maximum child width
maxChildWidth() const148 FXint FXComposite::maxChildWidth() const {
149 FXuint hints;
150 FXint m=0,t;
151 for(FXWindow *child=getFirst(); child; child=child->getNext()){
152 if(child->shown()){
153 hints=child->getLayoutHints();
154 if(hints&LAYOUT_FIX_WIDTH) t=child->getWidth();
155 else t=child->getDefaultWidth();
156 if(m<t) m=t;
157 }
158 }
159 return m;
160 }
161
162
163 // Get maximum child height
maxChildHeight() const164 FXint FXComposite::maxChildHeight() const {
165 FXuint hints;
166 FXint m=0,t;
167 for(FXWindow *child=getFirst(); child; child=child->getNext()){
168 if(child->shown()){
169 hints=child->getLayoutHints();
170 if(hints&LAYOUT_FIX_HEIGHT) t=child->getHeight();
171 else t=child->getDefaultHeight();
172 if(m<t) m=t;
173 }
174 }
175 return m;
176 }
177
178
179 // Just tell server where the windows are!
layout()180 void FXComposite::layout(){
181 for(FXWindow *child=getFirst(); child; child=child->getNext()){
182 if(child->shown()){
183 child->position(child->getX(),child->getY(),child->getWidth(),child->getHeight());
184 }
185 }
186 flags&=~FLAG_DIRTY;
187 }
188
189
190 // Update all subwindows
onCmdUpdate(FXObject * sender,FXSelector,void * ptr)191 long FXComposite::onCmdUpdate(FXObject* sender,FXSelector,void* ptr){
192 update();
193 for(FXWindow *child=getFirst(); child; child=child->getNext()){
194 if(child->shown()) child->handle(sender,FXSEL(SEL_COMMAND,ID_UPDATE),ptr);
195 }
196 return 1;
197 }
198
199
200 // Focus moved to next
onFocusNext(FXObject *,FXSelector sel,void * ptr)201 long FXComposite::onFocusNext(FXObject*,FXSelector sel,void* ptr){
202 FXWindow *child;
203 if(getFocus())
204 child=getFocus()->getNext();
205 else
206 child=getFirst();
207 while(child){
208 if(child->shown()){
209 if(child->handle(this,FXSEL(SEL_FOCUS_SELF,0),ptr)) return 1;
210 if(child->handle(this,sel,ptr)) return 1;
211 }
212 child=child->getNext();
213 }
214 return 0;
215 }
216
217
218 // Focus moved to previous
onFocusPrev(FXObject *,FXSelector sel,void * ptr)219 long FXComposite::onFocusPrev(FXObject*,FXSelector sel,void* ptr){
220 FXWindow *child;
221 if(getFocus())
222 child=getFocus()->getPrev();
223 else
224 child=getLast();
225 while(child){
226 if(child->shown()){
227 if(child->handle(this,FXSEL(SEL_FOCUS_SELF,0),ptr)) return 1;
228 if(child->handle(this,sel,ptr)) return 1;
229 }
230 child=child->getPrev();
231 }
232 return 0;
233 }
234
235
236 // Keyboard press
onKeyPress(FXObject * sender,FXSelector sel,void * ptr)237 long FXComposite::onKeyPress(FXObject* sender,FXSelector sel,void* ptr){
238 FXEvent* event=(FXEvent*)ptr;
239
240 FXTRACE((200,"%p->%s::onKeyPress keysym=0x%04x state=%04x\n",this,getClassName(),((FXEvent*)ptr)->code,((FXEvent*)ptr)->state));
241
242 // Bounce to focus widget
243 if(getFocus() && getFocus()->handle(sender,sel,ptr)) return 1;
244
245 // Try target first
246 if(isEnabled() && target && target->tryHandle(this,FXSEL(SEL_KEYPRESS,message),ptr)) return 1;
247
248 // Check the accelerators
249 if(getAccelTable() && getAccelTable()->handle(this,sel,ptr)) return 1;
250
251 // Otherwise, perform the default keyboard processing
252 switch(MKUINT(event->code,event->state&(SHIFTMASK|CONTROLMASK|ALTMASK|METAMASK))){
253 case KEY_Tab:
254 case KEY_Next:
255 return handle(this,FXSEL(SEL_FOCUS_NEXT,0),ptr);
256 case KEY_Prior:
257 case KEY_ISO_Left_Tab:
258 case MKUINT(KEY_ISO_Left_Tab,SHIFTMASK):
259 case MKUINT(KEY_Tab,SHIFTMASK):
260 return handle(this,FXSEL(SEL_FOCUS_PREV,0),ptr);
261 case KEY_Up:
262 case KEY_KP_Up:
263 return handle(this,FXSEL(SEL_FOCUS_UP,0),ptr);
264 case KEY_Down:
265 case KEY_KP_Down:
266 return handle(this,FXSEL(SEL_FOCUS_DOWN,0),ptr);
267 case KEY_Left:
268 case KEY_KP_Left:
269 return handle(this,FXSEL(SEL_FOCUS_LEFT,0),ptr);
270 case KEY_Right:
271 case KEY_KP_Right:
272 return handle(this,FXSEL(SEL_FOCUS_RIGHT,0),ptr);
273 }
274 return 0;
275 }
276
277
278 // Keyboard release
onKeyRelease(FXObject * sender,FXSelector sel,void * ptr)279 long FXComposite::onKeyRelease(FXObject* sender,FXSelector sel,void* ptr){
280
281 FXTRACE((200,"%p->%s::onKeyRelease keysym=0x%04x state=%04x\n",this,getClassName(),((FXEvent*)ptr)->code,((FXEvent*)ptr)->state));
282
283 // Bounce to focus widget
284 if(getFocus() && getFocus()->handle(sender,sel,ptr)) return 1;
285
286 // Try target first
287 if(isEnabled() && target && target->tryHandle(this,FXSEL(SEL_KEYRELEASE,message),ptr)) return 1;
288
289 // Check the accelerators
290 if(getAccelTable() && getAccelTable()->handle(this,sel,ptr)) return 1;
291
292 return 0;
293 }
294
295
296 // Dispose of all the children
~FXComposite()297 FXComposite::~FXComposite(){
298 while(getFirst()){ delete getFirst(); }
299 }
300
301 }
302