1 /********************************************************************************
2 * *
3 * M u l t i p l e D o c u m e n t C l i e n t W i n d o w *
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 "FXObjectList.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 "FXDCWindow.h"
42 #include "FXImage.h"
43 #include "FXIcon.h"
44 #include "FXFrame.h"
45 #include "FXLabel.h"
46 #include "FXButton.h"
47 #include "FXMenuButton.h"
48 #include "FXComposite.h"
49 #include "FXShell.h"
50 #include "FXPopup.h"
51 #include "FXMenuPane.h"
52 #include "FXMDIButton.h"
53 #include "FXPacker.h"
54 #include "FXHorizontalFrame.h"
55 #include "FXToolBar.h"
56 #include "FXMenuBar.h"
57 #include "FXMDIChild.h"
58 #include "FXMDIClient.h"
59 #include "FXDialogBox.h"
60 #include "FXVerticalFrame.h"
61 #include "FXList.h"
62
63
64 /*
65 Notes:
66 - This brings up the question of the cascade design. Do you want the windows
67 to be cascaded/tiled in the order that they were created, or do you want them
68 to be cascaded in some sort of focus order, with the one that had the focus
69 to be on top, keeping its focus.
70 In the test app, if you click within any of the child windows, it pops to
71 the top with the focus, with the exception of "TEST3", which has a button.
72 If this button is clicked, that window dos not pop to the top when it
73 gets the focus. Seems like it should...
74 - Minor problems with mdi. When a window is maximized and then
75 deleted, the next window that is created is created in "normal" mode.
76 When any adjustment is made to the size of the new window, it pops to
77 "almost" maximized mode. (The child frame is visible, but as large as
78 possible). Seems like the child windows should be created maximized if
79 the mdi is in maximized mode. Also, if there are two windows and one
80 gets maximized and then deleted, the second window pops to "almost"
81 maximixed mode.
82 - We make MDIClient get a first crack at the messages, so that the MDIChild
83 can not shadow any messages really directed at the MDIClient.
84 - Need ``arrange icons'' feature.
85 - When switching active MDIChild windows, we pass the old to the new and vice
86 versa; this allows the MDIChild's target to determine if we switched windows
87 only, or if we switched between one document and another at the same time
88 */
89
90 #define HORZ_PAD 12
91 #define VERT_PAD 2
92
93 #define CASCADE_XOFF 24
94 #define CASCADE_YOFF 24
95
96 #define CLIENT_MIN_WIDTH 16
97 #define CLIENT_MIN_HEIGHT 16
98
99
100 using namespace FX;
101
102 /*******************************************************************************/
103
104 namespace FX {
105
106
107 FXDEFMAP(FXMDIClient) FXMDIClientMap[]={
108 FXMAPFUNC(SEL_PAINT,0,FXMDIClient::onPaint),
109 FXMAPFUNC(SEL_UPDATE,FXWindow::ID_MDI_NEXT,FXMDIClient::onUpdActivateNext),
110 FXMAPFUNC(SEL_UPDATE,FXWindow::ID_MDI_PREV,FXMDIClient::onUpdActivatePrev),
111 FXMAPFUNC(SEL_UPDATE,FXWindow::ID_MDI_TILEHORIZONTAL,FXMDIClient::onUpdTileHorizontal),
112 FXMAPFUNC(SEL_UPDATE,FXWindow::ID_MDI_TILEVERTICAL,FXMDIClient::onUpdTileVertical),
113 FXMAPFUNC(SEL_UPDATE,FXWindow::ID_MDI_CASCADE,FXMDIClient::onUpdCascade),
114 FXMAPFUNC(SEL_UPDATE,FXWindow::ID_MDI_CLOSE,FXMDIClient::onUpdClose),
115 FXMAPFUNC(SEL_UPDATE,FXWindow::ID_MDI_MINIMIZE,FXMDIClient::onUpdMinimize),
116 FXMAPFUNC(SEL_UPDATE,FXWindow::ID_MDI_RESTORE,FXMDIClient::onUpdRestore),
117 FXMAPFUNC(SEL_UPDATE,FXWindow::ID_MDI_MAXIMIZE,FXMDIClient::onUpdMaximize),
118 FXMAPFUNC(SEL_UPDATE,FXWindow::ID_MDI_MENURESTORE,FXMDIClient::onUpdMenuRestore),
119 FXMAPFUNC(SEL_UPDATE,FXWindow::ID_MDI_MENUCLOSE,FXMDIClient::onUpdMenuClose),
120 FXMAPFUNC(SEL_UPDATE,FXWindow::ID_MDI_MENUMINIMIZE,FXMDIClient::onUpdMenuMinimize),
121 FXMAPFUNC(SEL_UPDATE,FXWindow::ID_MDI_MENUWINDOW,FXMDIClient::onUpdMenuWindow),
122 FXMAPFUNC(SEL_UPDATE,FXMDIClient::ID_MDI_ANY,FXMDIClient::onUpdAnyWindows),
123 FXMAPFUNCS(SEL_UPDATE,FXMDIClient::ID_MDI_1,FXMDIClient::ID_MDI_10,FXMDIClient::onUpdWindowSelect),
124 FXMAPFUNCS(SEL_UPDATE,FXMDIClient::ID_MDI_OVER_1,FXMDIClient::ID_MDI_OVER_10,FXMDIClient::onUpdOthersWindows),
125 FXMAPFUNC(SEL_COMMAND,FXWindow::ID_MDI_NEXT,FXMDIClient::onCmdActivateNext),
126 FXMAPFUNC(SEL_COMMAND,FXWindow::ID_MDI_PREV,FXMDIClient::onCmdActivatePrev),
127 FXMAPFUNC(SEL_COMMAND,FXWindow::ID_MDI_TILEHORIZONTAL,FXMDIClient::onCmdTileHorizontal),
128 FXMAPFUNC(SEL_COMMAND,FXWindow::ID_MDI_TILEVERTICAL,FXMDIClient::onCmdTileVertical),
129 FXMAPFUNC(SEL_COMMAND,FXWindow::ID_MDI_CASCADE,FXMDIClient::onCmdCascade),
130 FXMAPFUNCS(SEL_COMMAND,FXMDIClient::ID_MDI_1,FXMDIClient::ID_MDI_10,FXMDIClient::onCmdWindowSelect),
131 FXMAPFUNCS(SEL_COMMAND,FXMDIClient::ID_MDI_OVER_1,FXMDIClient::ID_MDI_OVER_10,FXMDIClient::onCmdOthersWindows),
132 };
133
134
135 // Object implementation
FXIMPLEMENT(FXMDIClient,FXComposite,FXMDIClientMap,ARRAYNUMBER (FXMDIClientMap))136 FXIMPLEMENT(FXMDIClient,FXComposite,FXMDIClientMap,ARRAYNUMBER(FXMDIClientMap))
137
138
139 // Construct and init
140 FXMDIClient::FXMDIClient(){
141 flags|=FLAG_SHOWN;
142 active=NULL;
143 backImage=NULL;
144 cascadex=CASCADE_XOFF;
145 cascadey=CASCADE_YOFF;
146 }
147
148
149 // Construct and init
FXMDIClient(FXComposite * p,FXuint opts,FXint x,FXint y,FXint w,FXint h)150 FXMDIClient::FXMDIClient(FXComposite* p,FXuint opts,FXint x,FXint y,FXint w,FXint h):FXComposite(p,opts,x,y,w,h){
151 flags|=FLAG_SHOWN;
152 backColor=getApp()->getShadowColor();
153 active=NULL;
154 backImage=NULL;
155 cascadex=CASCADE_XOFF;
156 cascadey=CASCADE_YOFF;
157 }
158
159
160 // Create window
create()161 void FXMDIClient::create(){
162 FXComposite::create();
163 if(backImage) backImage->create();
164 }
165
166
167 // Get width
getDefaultWidth()168 FXint FXMDIClient::getDefaultWidth(){
169 return CLIENT_MIN_WIDTH;
170 }
171
172
173 // Get height
getDefaultHeight()174 FXint FXMDIClient::getDefaultHeight(){
175 return CLIENT_MIN_HEIGHT;
176 }
177
178
179 // Recalculate layout
layout()180 void FXMDIClient::layout(){
181 FXMDIChild* child;
182 FXint xx,yy,ww,hh;
183
184 // Place children
185 for(child=(FXMDIChild*)getFirst(); child; child=(FXMDIChild*)child->getNext()){
186 if(child->shown()){
187 if(child->isMaximized()){
188 xx=0;
189 yy=0;
190 ww=width;
191 hh=height;
192 }
193 else if(child->isMinimized()){
194 xx=child->getX();
195 yy=child->getY();
196 ww=child->getDefaultWidth();
197 hh=child->getDefaultHeight();
198 }
199 else{
200 xx=child->getX();
201 yy=child->getY();
202 ww=child->getWidth();
203 hh=child->getHeight();
204 }
205 child->position(xx,yy,ww,hh);
206 }
207 }
208
209 // Raise active child
210 if(active && active->shown()) active->raise();
211
212 // No more dirty
213 flags&=~FLAG_DIRTY;
214 }
215
216
217 // Handle repaint
onPaint(FXObject *,FXSelector,void * ptr)218 long FXMDIClient::onPaint(FXObject*,FXSelector,void* ptr){
219 FXDCWindow dc(this,(FXEvent*)ptr);
220 if(backImage){
221 dc.setFillStyle(FILL_TILED);
222 dc.setTile(backImage);
223 dc.fillRectangle(0,0,width,height);
224 }
225 else{
226 dc.setForeground(backColor);
227 dc.fillRectangle(0,0,width,height);
228 }
229 return 1;
230 }
231
232
233 // Pass message to all MDI windows; the crufty loop is because
234 // it is possible for the child receiving the message to be deleted
forallWindows(FXObject * sender,FXSelector sel,void * ptr)235 long FXMDIClient::forallWindows(FXObject* sender,FXSelector sel,void* ptr){
236 FXWindow *child,*nextchild;
237 for(child=getFirst(); child; child=nextchild){
238 nextchild=child->getNext();
239 if(!child->handle(sender,sel,ptr)) return 0;
240 }
241 return 1;
242 }
243
244
245 // Pass message to all different documents; here the complication
246 // is that the whole group of child windows sharing the same
247 // document may be deleted; also, we want to send only ONE of the
248 // document-sharing children a message.
forallDocuments(FXObject * sender,FXSelector sel,void * ptr)249 long FXMDIClient::forallDocuments(FXObject* sender,FXSelector sel,void* ptr){
250 FXWindow *child,*nextchild,*ch;
251 for(child=getFirst(); child; child=nextchild){
252 nextchild=child->getNext();
253 x: if(nextchild && nextchild->getTarget()){
254 for(ch=child; ch; ch=ch->getPrev()){
255 if(ch->getTarget()==nextchild->getTarget()){
256 nextchild=nextchild->getNext();
257 goto x;
258 }
259 }
260 }
261 if(!child->handle(sender,sel,ptr)) return 0;
262 }
263 return 1;
264 }
265
266
267 // Pass message to all MDI windows whose target is document;
268 // note that the child may be deleted as a result of the message.
forallDocWindows(FXObject * document,FXObject * sender,FXSelector sel,void * ptr)269 long FXMDIClient::forallDocWindows(FXObject* document,FXObject* sender,FXSelector sel,void* ptr){
270 FXWindow *child,*nextchild;
271 for(child=getFirst(); child; child=nextchild){
272 nextchild=child->getNext();
273 if(child->getTarget()==document){
274 if(!child->handle(sender,sel,ptr)) return 0;
275 }
276 }
277 return 1;
278 }
279
280
281 // Set the active child
setActiveChild(FXMDIChild * child,FXbool notify)282 FXbool FXMDIClient::setActiveChild(FXMDIChild* child,FXbool notify){
283 FXbool wasmax=false;
284 if(active!=child){
285
286 if(active){
287
288 // Was it maximized?
289 wasmax=active->isMaximized();
290
291 // Deactivate old MDIChild
292 active->handle(this,FXSEL(SEL_DESELECTED,0),(void*)child); // FIXME should call member function
293
294 // Restore to normal size if it was maximized
295 if(wasmax && child) active->restore(notify);
296 }
297
298 if(child){
299
300 // Activate new MDIChild
301 child->handle(this,FXSEL(SEL_SELECTED,0),(void*)active); // FIXME should call member function
302
303 // Maximize because the old MDIChild was maximized
304 if(wasmax) child->maximize(notify);
305
306 // Raise it
307 child->raise();
308 }
309
310 active=child;
311
312 // Need layout
313 recalc();
314
315 // GUI update will be needed
316 getApp()->refresh();
317
318 // Notify target
319 if(notify && target){ target->tryHandle(this,FXSEL(SEL_CHANGED,message),child); }
320
321 return true;
322 }
323 return false;
324 }
325
326
327 // Get active document; this is the target of the active MDI Child
getActiveDocument() const328 FXObject* FXMDIClient::getActiveDocument() const {
329 return getActiveChild() ? getActiveChild()->getTarget() : NULL;
330 }
331
332
333 // Change background image
setBackImage(FXImage * img)334 void FXMDIClient::setBackImage(FXImage* img){
335 if(backImage!=img){
336 backImage=img;
337 update();
338 }
339 }
340
341
342 // Cascade windows
cascade(FXbool notify)343 void FXMDIClient::cascade(FXbool notify){
344 FXMDIChild* child;
345 FXint childx,childy,childw,childh;
346 childx=5;
347 childy=5;
348 childw=(2*width)/3;
349 childh=(2*height)/3;
350 for(child=(FXMDIChild*)getFirst(); child; child=(FXMDIChild*)child->getNext()){
351 if(child==active) continue;
352 if(child->shown() && !child->isMinimized()){
353 child->restore(notify);
354 child->position(childx,childy,childw,childh);
355 child->raise();
356 childx+=cascadex;
357 childy+=cascadey;
358 if(childx+child->getWidth()>width){ childx=5; childy=5; }
359 if(childy+child->getHeight()>height){ childy=5; }
360 }
361 }
362 if(active && active->shown() && !active->isMinimized()){
363 active->restore(notify);
364 active->position(childx,childy,childw,childh);
365 active->raise();
366 }
367 }
368
369
370 // Layout horizontally
horizontal(FXbool notify)371 void FXMDIClient::horizontal(FXbool notify){
372 FXMDIChild* child;
373 FXint n,nr,nc,hroom,vroom,r,c;
374 for(n=0,child=(FXMDIChild*)getFirst(); child; child=(FXMDIChild*)child->getNext()){
375 if(child->shown() && !child->isMinimized()) n++;
376 }
377 nr=n;
378 nc=1;
379 if(n>3){
380 nc=(int)Math::sqrt((double)n);
381 nr=(n+nc-1)/nc;
382 }
383 hroom=0;
384 vroom=0;
385 if(nc>0) hroom=width/nc;
386 if(nr>0) vroom=height/nr;
387 for(child=(FXMDIChild*)getFirst(),n=0; child; child=(FXMDIChild*)child->getNext()){
388 if(child->shown() && !child->isMinimized()){
389 r=n/nc;
390 c=n%nc;
391 child->restore(notify);
392 child->position(c*hroom,r*vroom,hroom,vroom);
393 n++;
394 }
395 }
396 if(active && active->shown()) active->raise();
397 }
398
399
400 // Layout vertically
vertical(FXbool notify)401 void FXMDIClient::vertical(FXbool notify){
402 FXMDIChild* child;
403 FXint n,nr,nc,hroom,vroom,r,c;
404 for(n=0,child=(FXMDIChild*)getFirst(); child; child=(FXMDIChild*)child->getNext()){
405 if(child->shown() && !child->isMinimized()) n++;
406 }
407 nc=n;
408 nr=1;
409 if(n>3){
410 nr=(int)Math::sqrt((double)n);
411 nc=(n+nr-1)/nr;
412 }
413 hroom=0;
414 vroom=0;
415 if(nc>0) hroom=width/nc;
416 if(nr>0) vroom=height/nr;
417 for(child=(FXMDIChild*)getFirst(),n=0; child; child=(FXMDIChild*)child->getNext()){
418 if(child->shown() && !child->isMinimized()){
419 r=n/nc;
420 c=n%nc;
421 child->restore(notify);
422 child->position(c*hroom,r*vroom,hroom,vroom);
423 n++;
424 }
425 }
426 if(active && active->shown()) active->raise();
427 }
428
429
430 // User clicks on one of the window menus
onCmdWindowSelect(FXObject *,FXSelector sel,void *)431 long FXMDIClient::onCmdWindowSelect(FXObject*,FXSelector sel,void*){
432 setActiveChild((FXMDIChild*)childAtIndex(FXSELID(sel)-ID_MDI_1),true);
433 return 1;
434 }
435
436
437 // Update handler for window menus
onUpdWindowSelect(FXObject * sender,FXSelector sel,void *)438 long FXMDIClient::onUpdWindowSelect(FXObject *sender,FXSelector sel,void*){
439 FXint which=FXSELID(sel)-ID_MDI_1;
440 FXMDIChild *child=(FXMDIChild*)childAtIndex(which);
441 if(child){
442 FXString string;
443 if(which<9)
444 string.format("&%d %s",which+1,child->getTitle().text());
445 else
446 string.format("1&0 %s",child->getTitle().text());
447 sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_SETSTRINGVALUE),(void*)&string);
448 sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_SHOW),NULL);
449 if(child==active)
450 sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_CHECK),NULL);
451 else
452 sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_UNCHECK),NULL);
453 }
454 else{
455 sender->handle(this,FXSEL(SEL_COMMAND,FXWindow::ID_HIDE),NULL);
456 }
457 return 1;
458 }
459
460
461
462 // Show a menu of other MDI child windows
onCmdOthersWindows(FXObject *,FXSelector,void *)463 long FXMDIClient::onCmdOthersWindows(FXObject*,FXSelector,void*){
464 FXDialogBox choose(this,tr("Select Window"),DECOR_TITLE|DECOR_BORDER|DECOR_RESIZE,0,0,300,200,10,10,10,10, 10,10);
465 FXHorizontalFrame* buttons=new FXHorizontalFrame(&choose,LAYOUT_SIDE_BOTTOM|LAYOUT_FILL_X|PACK_UNIFORM_WIDTH|PACK_UNIFORM_HEIGHT,0,0,0,0,0,0,0,0);
466 new FXButton(buttons,tr("&OK"),NULL,&choose,FXDialogBox::ID_ACCEPT,BUTTON_INITIAL|BUTTON_DEFAULT|FRAME_RAISED|FRAME_THICK|LAYOUT_RIGHT,0,0,0,0,HORZ_PAD,HORZ_PAD,VERT_PAD,VERT_PAD);
467 new FXButton(buttons,tr("&Cancel"),NULL,&choose,FXDialogBox::ID_CANCEL,BUTTON_DEFAULT|FRAME_RAISED|FRAME_THICK|LAYOUT_RIGHT,0,0,0,0,HORZ_PAD,HORZ_PAD,VERT_PAD,VERT_PAD);
468 FXVerticalFrame* mdilistframe=new FXVerticalFrame(&choose,FRAME_SUNKEN|FRAME_THICK|LAYOUT_FILL_X|LAYOUT_FILL_Y,0,0,0,0,0,0,0,0,0,0);
469 FXList* mdilist=new FXList(mdilistframe,NULL,0,LIST_BROWSESELECT|LAYOUT_FILL_X|LAYOUT_FILL_Y);
470 mdilist->setNumVisible(10);
471 for(FXMDIChild *child=(FXMDIChild*)getFirst(); child; child=(FXMDIChild*)child->getNext()){
472 mdilist->appendItem(child->getTitle(),child->getIcon(),child);
473 if(child==active) mdilist->setCurrentItem(mdilist->getNumItems()-1);
474 }
475 if(choose.execute(PLACEMENT_OWNER)){
476 FXASSERT(mdilist->getCurrentItem()>=0);
477 setActiveChild((FXMDIChild*)mdilist->getItemData(mdilist->getCurrentItem()));
478 }
479 return 1;
480 }
481
482
483 // Update button to show menu of other MDI child windows when more than N windows
onUpdOthersWindows(FXObject * sender,FXSelector sel,void *)484 long FXMDIClient::onUpdOthersWindows(FXObject *sender,FXSelector sel,void*){
485 sender->handle(this,((FXSELID(sel)-ID_MDI_OVER_1)<numChildren())?FXSEL(SEL_COMMAND,FXWindow::ID_SHOW):FXSEL(SEL_COMMAND,FXWindow::ID_HIDE),NULL);
486 return 1;
487 }
488
489
490 // Show or hide depending on whether there are any windows
onUpdAnyWindows(FXObject * sender,FXSelector,void *)491 long FXMDIClient::onUpdAnyWindows(FXObject *sender,FXSelector,void*){
492 sender->handle(this,getFirst()?FXSEL(SEL_COMMAND,ID_SHOW):FXSEL(SEL_COMMAND,ID_HIDE),NULL);
493 return 1;
494 }
495
496
497 // Update restore; gray if no active
onUpdRestore(FXObject * sender,FXSelector sel,void * ptr)498 long FXMDIClient::onUpdRestore(FXObject* sender,FXSelector sel,void* ptr){
499 if(active) return active->handle(sender,sel,ptr);
500 sender->handle(this,FXSEL(SEL_COMMAND,ID_DISABLE),NULL);
501 return 1;
502 }
503
504
505 // Update maximized; gray if no active
onUpdMaximize(FXObject * sender,FXSelector sel,void * ptr)506 long FXMDIClient::onUpdMaximize(FXObject* sender,FXSelector sel,void* ptr){
507 if(active) return active->handle(sender,sel,ptr);
508 sender->handle(this,FXSEL(SEL_COMMAND,ID_DISABLE),NULL);
509 return 1;
510 }
511
512
513 // Update minimized
onUpdMinimize(FXObject * sender,FXSelector sel,void * ptr)514 long FXMDIClient::onUpdMinimize(FXObject* sender,FXSelector sel,void* ptr){
515 if(active) return active->handle(sender,sel,ptr);
516 sender->handle(this,FXSEL(SEL_COMMAND,ID_DISABLE),NULL);
517 return 1;
518 }
519
520
521 // Update close active child
onUpdClose(FXObject * sender,FXSelector sel,void * ptr)522 long FXMDIClient::onUpdClose(FXObject* sender,FXSelector sel,void* ptr){
523 if(active) return active->handle(sender,sel,ptr);
524 sender->handle(this,FXSEL(SEL_COMMAND,ID_DISABLE),NULL);
525 return 1;
526 }
527
528
529 // Update menu's restore button
onUpdMenuWindow(FXObject * sender,FXSelector sel,void * ptr)530 long FXMDIClient::onUpdMenuWindow(FXObject* sender,FXSelector sel,void* ptr){
531 if(active) return active->handle(sender,sel,ptr);
532 sender->handle(this,FXSEL(SEL_COMMAND,ID_HIDE),NULL);
533 return 1;
534 }
535
536
537 // Update menu's restore button
onUpdMenuRestore(FXObject * sender,FXSelector sel,void * ptr)538 long FXMDIClient::onUpdMenuRestore(FXObject* sender,FXSelector sel,void* ptr){
539 if(active) return active->handle(sender,sel,ptr);
540 sender->handle(this,FXSEL(SEL_COMMAND,ID_HIDE),NULL);
541 return 1;
542 }
543
544
545 // Update menu's minimized button
onUpdMenuMinimize(FXObject * sender,FXSelector sel,void * ptr)546 long FXMDIClient::onUpdMenuMinimize(FXObject* sender,FXSelector sel,void* ptr){
547 if(active) return active->handle(sender,sel,ptr);
548 sender->handle(this,FXSEL(SEL_COMMAND,ID_HIDE),NULL);
549 return 1;
550 }
551
552
553 // Update menu's close button
onUpdMenuClose(FXObject * sender,FXSelector sel,void * ptr)554 long FXMDIClient::onUpdMenuClose(FXObject* sender,FXSelector sel,void* ptr){
555 if(active) return active->handle(sender,sel,ptr);
556 sender->handle(this,FXSEL(SEL_COMMAND,ID_HIDE),NULL);
557 return 1;
558 }
559
560
561 // Tile horizontally (actually, prefer wider windows)
onCmdTileHorizontal(FXObject *,FXSelector,void *)562 long FXMDIClient::onCmdTileHorizontal(FXObject*,FXSelector,void*){
563 horizontal(true);
564 return 1;
565 }
566
567
568 // Update tile horizontally
onUpdTileHorizontal(FXObject * sender,FXSelector,void *)569 long FXMDIClient::onUpdTileHorizontal(FXObject* sender,FXSelector,void*){
570 sender->handle(this,getFirst()?FXSEL(SEL_COMMAND,ID_ENABLE):FXSEL(SEL_COMMAND,ID_DISABLE),NULL);
571 return 1;
572 }
573
574
575 // Tile vertically (actually, prefer taller windows)
onCmdTileVertical(FXObject *,FXSelector,void *)576 long FXMDIClient::onCmdTileVertical(FXObject*,FXSelector,void*){
577 vertical(true);
578 return 1;
579 }
580
581
582 // Update tile vertically
onUpdTileVertical(FXObject * sender,FXSelector,void *)583 long FXMDIClient::onUpdTileVertical(FXObject* sender,FXSelector,void*){
584 sender->handle(this,getFirst()?FXSEL(SEL_COMMAND,ID_ENABLE):FXSEL(SEL_COMMAND,ID_DISABLE),NULL);
585 return 1;
586 }
587
588
589 // Cascade windows
onCmdCascade(FXObject *,FXSelector,void *)590 long FXMDIClient::onCmdCascade(FXObject*,FXSelector,void*){
591 cascade(true);
592 return 1;
593 }
594
595
596 // Update cascade
onUpdCascade(FXObject * sender,FXSelector,void *)597 long FXMDIClient::onUpdCascade(FXObject* sender,FXSelector,void*){
598 sender->handle(this,getFirst()?FXSEL(SEL_COMMAND,ID_ENABLE):FXSEL(SEL_COMMAND,ID_DISABLE),NULL);
599 return 1;
600 }
601
602
603 // Activate next child
onCmdActivateNext(FXObject *,FXSelector,void *)604 long FXMDIClient::onCmdActivateNext(FXObject*,FXSelector,void*){
605 if(active && active->getNext()) setActiveChild((FXMDIChild*)active->getNext(),true);
606 return 1;
607 }
608
609
610 // Activate next child
onUpdActivateNext(FXObject * sender,FXSelector,void *)611 long FXMDIClient::onUpdActivateNext(FXObject* sender,FXSelector,void*){
612 sender->handle(this,(active && active->getNext())?FXSEL(SEL_COMMAND,ID_ENABLE):FXSEL(SEL_COMMAND,ID_DISABLE),NULL);
613 return 1;
614 }
615
616
617 // Activate previous child
onCmdActivatePrev(FXObject *,FXSelector,void *)618 long FXMDIClient::onCmdActivatePrev(FXObject*,FXSelector,void*){
619 if(active && active->getPrev()) setActiveChild((FXMDIChild*)active->getPrev(),true);
620 return 1;
621 }
622
623
624 // Activate previous child
onUpdActivatePrev(FXObject * sender,FXSelector,void *)625 long FXMDIClient::onUpdActivatePrev(FXObject* sender,FXSelector,void*){
626 sender->handle(this,(active && active->getPrev())?FXSEL(SEL_COMMAND,ID_ENABLE):FXSEL(SEL_COMMAND,ID_DISABLE),NULL);
627 return 1;
628 }
629
630
631 // Delegate all other messages to active child; we can't block any
632 // messages here as some are meant fot the FXMDIChild and some for
633 // the FXMDIChild's content or target.
onDefault(FXObject * sender,FXSelector sel,void * ptr)634 long FXMDIClient::onDefault(FXObject* sender,FXSelector sel,void* ptr){
635 return active && active->handle(sender,sel,ptr);
636 }
637
638
639 // Save object to stream
save(FXStream & store) const640 void FXMDIClient::save(FXStream& store) const {
641 FXComposite::save(store);
642 store << active;
643 store << cascadex;
644 store << cascadey;
645 }
646
647
648 // Load object from stream
load(FXStream & store)649 void FXMDIClient::load(FXStream& store){
650 FXComposite::load(store);
651 store >> active;
652 store >> cascadex;
653 store >> cascadey;
654 }
655
656
657 // Destruct thrashes object
~FXMDIClient()658 FXMDIClient::~FXMDIClient(){
659 active=(FXMDIChild*)-1L;
660 backImage=(FXImage*)-1L;
661 }
662
663 }
664