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