1 /********************************************************************************
2 *                                                                               *
3 *                         D o c k S i t e   W i d g e t                         *
4 *                                                                               *
5 *********************************************************************************
6 * Copyright (C) 2004,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 "FXDCWindow.h"
40 #include "FXApp.h"
41 #include "FXGIFIcon.h"
42 #include "FXFrame.h"
43 #include "FXComposite.h"
44 #include "FXPacker.h"
45 #include "FXPopup.h"
46 #include "FXMenuPane.h"
47 #include "FXMenuCaption.h"
48 #include "FXMenuCommand.h"
49 #include "FXMenuCascade.h"
50 #include "FXMenuSeparator.h"
51 #include "FXMenuRadio.h"
52 #include "FXMenuCheck.h"
53 #include "FXShell.h"
54 #include "FXSeparator.h"
55 #include "FXTopWindow.h"
56 #include "FXDockBar.h"
57 #include "FXDockSite.h"
58 #include "FXToolBarGrip.h"
59 #include "FXToolBarShell.h"
60 #include "icons.h"
61 
62 
63 /*
64   Notes:
65 
66 
67                        Jeroen's Theory of Docking
68 
69   Because if I don't write this down, no one will *ever* figure this out!
70 
71   We assume here we're docking a horizontally oriented bar inside a horizontally
72   oriented dock.  Vertical orientation works, of course, completely analoguous.
73 
74   Docking a floating bar.  When dragging a floating bar, we call findDockNear()
75   to determine which dock site this bar could dock into.  This dock site is a
76   sibling of the current widget remembered in the drydock variable.  The routine
77   findDockNear() invokes insideDock() to determine if a docking could take place
78   or not.
79 
80   Not all dock sites are available for docking.  Some dock bars have a preferred
81   orientation and can not be docked everywhere.  To this end, the dock bar
82   maintains a member variable allowed which contains the set of sides that the
83   bar is allowed to dock at.
84 
85   When findDockNear() returns a non-NULL value, a potential dock site has been
86   found; a timer is set to dock at this site if the cursor hovers near its
87   current position:- we don't dock immediately, since the user may be just moving
88   the bar across a potential dock site on his way to another place on the screen.
89 
90   When the dragging ends, or when the timer expires, the bar is docked at the
91   dock site.  Subsequent dragging will simply move the bar inside the dock site,
92   and just rearrange the dock site.
93 
94   Floating a docked bar.  When moving a docked bar, dragging it simply rearranges
95   the order of the bars inside the dock, until such time that the bar is substantially
96   moved away from the dock site, as determined by insideDock().  Then the dock bar
97   is reparented under the toolbar shell and subsequent movement will simply move
98   the floaring bar.
99 
100   The function insideDock() determines if a proposed position is to be considered
101   docked or non-docked.  This is determined differently, based on whether the bar
102   is currently docked or not:
103 
104     1 If the bar is docked, we consider the proposed bar position undocked when
105       the upper edge is FUDGE pixels above the dock site, or when the lower edge
106       is FUDGE pixels below the dock site.
107 
108     2 Alternatively, if the bar is floating, we consider the bar position docked when
109       the upper or lower edge of the bar is within PROXIMITY inside the dock site.
110 
111     3 In addition to 1 and 2, we also require that the horizontal alignment of the
112       dock bar and dock site are within a certain TOLERANCE. This is determined
113       differently depending on whether the bar is wider than the site or not:
114 
115         a If the bar is wider, we want the dock site within -TOLERANCE to
116           bar width + TOLERANCE relative to the bar.
117 
118         b If the dock site is wider, we want the bar to be within -TOLERANCE to
119           docksite width + TOLERANCE relative to the site.
120 
121         c A minor wrinkle is that if the bar is stretched (LAYOUT_FILL_X), we
122           don't use the current width of the bar in the above calculations,
123           but the default width instead; this is because a subsequent undocking,
124           which would shrink-wrap around the dock bar, leaves a smaller widget
125           and this may then immediately redock again.
126 
127     4 If the above tests indicate that the bar is docked, insideDock() returns
128       true.
129 
130    When undocking a bar, the arrangement inside the dock site needs to stay the same
131    for the remaining bars [if any].  Thus, we call undockToolBar() to inform the dock
132    site that one of its bars will be removed.  Depending on its own internal layout
133    algorithm, the dock site will then be able to adjust the options of the remaining
134    bars so that they stay in place.
135 
136    When docking a bar, we need to figure out where the new bar goes.  To that end,
137    dockToolBar() informs the dock site to determine where the new bar goes and adjust
138    the layout options of the other dock bars accordingly.
139 
140    If the dock bar is moved, the dock site is informed by moveToolBar() which lets
141    the dock site then rearrange the layouts according to the new bar position.
142 
143 */
144 
145 
146 #define HANDLESIZE       6              // Resize handle length
147 #define FUDGE            30             // Vertical distance beyond which bar pulls out
148 #define PROXIMITY        10             // Vertical proximity below which bar is sucked int dock
149 #define TOLERANCE        30             // Horizontal alignment tolerance beyond which bar pulls out
150 #define DOCKINGSNAPDELAY 300000000      // Delay before dock bar snaps to dock site
151 
152 // Docking side
153 #define LAYOUT_SIDE_MASK (LAYOUT_SIDE_LEFT|LAYOUT_SIDE_RIGHT|LAYOUT_SIDE_TOP|LAYOUT_SIDE_BOTTOM)
154 
155 using namespace FX;
156 
157 /*******************************************************************************/
158 
159 namespace FX {
160 
161 // Map
162 FXDEFMAP(FXDockBar) FXDockBarMap[]={
163 //  FXMAPFUNC(SEL_MOTION,0,FXDockBar::onMotion),
164 //  FXMAPFUNC(SEL_ENTER,0,FXDockBar::onEnter),
165 //  FXMAPFUNC(SEL_LEAVE,0,FXDockBar::onLeave),
166   FXMAPFUNC(SEL_FOCUS_PREV,0,FXDockBar::onFocusLeft),
167   FXMAPFUNC(SEL_FOCUS_NEXT,0,FXDockBar::onFocusRight),
168 //  FXMAPFUNC(SEL_LEFTBUTTONPRESS,0,FXDockBar::onLeftBtnPress),
169 //  FXMAPFUNC(SEL_LEFTBUTTONRELEASE,0,FXDockBar::onLeftBtnRelease),
170   FXMAPFUNC(SEL_UPDATE,FXDockBar::ID_DOCK_FLOAT,FXDockBar::onUpdUndock),
171   FXMAPFUNC(SEL_UPDATE,FXDockBar::ID_DOCK_TOP,FXDockBar::onUpdDockTop),
172   FXMAPFUNC(SEL_UPDATE,FXDockBar::ID_DOCK_BOTTOM,FXDockBar::onUpdDockBottom),
173   FXMAPFUNC(SEL_UPDATE,FXDockBar::ID_DOCK_LEFT,FXDockBar::onUpdDockLeft),
174   FXMAPFUNC(SEL_UPDATE,FXDockBar::ID_DOCK_RIGHT,FXDockBar::onUpdDockRight),
175   FXMAPFUNC(SEL_UPDATE,FXDockBar::ID_DOCK_FLIP,FXDockBar::onUpdDockFlip),
176   FXMAPFUNC(SEL_COMMAND,FXDockBar::ID_DOCK_FLOAT,FXDockBar::onCmdUndock),
177   FXMAPFUNC(SEL_COMMAND,FXDockBar::ID_DOCK_TOP,FXDockBar::onCmdDockTop),
178   FXMAPFUNC(SEL_COMMAND,FXDockBar::ID_DOCK_BOTTOM,FXDockBar::onCmdDockBottom),
179   FXMAPFUNC(SEL_COMMAND,FXDockBar::ID_DOCK_LEFT,FXDockBar::onCmdDockLeft),
180   FXMAPFUNC(SEL_COMMAND,FXDockBar::ID_DOCK_RIGHT,FXDockBar::onCmdDockRight),
181   FXMAPFUNC(SEL_BEGINDRAG,FXDockBar::ID_TOOLBARGRIP,FXDockBar::onBeginDragGrip),
182   FXMAPFUNC(SEL_ENDDRAG,FXDockBar::ID_TOOLBARGRIP,FXDockBar::onEndDragGrip),
183   FXMAPFUNC(SEL_DRAGGED,FXDockBar::ID_TOOLBARGRIP,FXDockBar::onDraggedGrip),
184   FXMAPFUNC(SEL_TIMEOUT,FXDockBar::ID_TIMER,FXDockBar::onDockTimer),
185   FXMAPFUNC(SEL_RIGHTBUTTONRELEASE,FXDockBar::ID_TOOLBARGRIP,FXDockBar::onPopupMenu),
186   };
187 
188 
189 // Object implementation
FXIMPLEMENT(FXDockBar,FXPacker,FXDockBarMap,ARRAYNUMBER (FXDockBarMap))190 FXIMPLEMENT(FXDockBar,FXPacker,FXDockBarMap,ARRAYNUMBER(FXDockBarMap))
191 
192 
193 /*
194 // Cursor shape based on mode
195 const FXDefaultCursor FXDockBar::cursorType[16]={
196   DEF_ARROW_CURSOR,
197   DEF_DRAGH_CURSOR,     // DRAG_TOP
198   DEF_DRAGH_CURSOR,     // DRAG_BOTTOM
199   DEF_ARROW_CURSOR,
200 
201   DEF_DRAGV_CURSOR,     // DRAG_LEFT
202   DEF_DRAGTL_CURSOR,    // DRAG_LEFT DRAG_TOP
203   DEF_DRAGTR_CURSOR,    // DRAG_LEFT DRAG_BOTTOM
204   DEF_ARROW_CURSOR,
205 
206   DEF_DRAGV_CURSOR,     // DRAG_RIGHT
207   DEF_DRAGTR_CURSOR,    // DRAG_RIGHT DRAG_TOP
208   DEF_DRAGTL_CURSOR,    // DRAG_RIGHT DRAG_BOTTOM
209   DEF_ARROW_CURSOR,
210 
211   DEF_ARROW_CURSOR,
212   DEF_ARROW_CURSOR,
213   DEF_ARROW_CURSOR,
214   DEF_ARROW_CURSOR,
215   };
216 */
217 
218 
219 // Deserialization
220 FXDockBar::FXDockBar():drydock(NULL),wetdock(NULL){
221   flags|=FLAG_ENABLED;
222   gripx=0;
223   gripy=0;
224   allowed=ALLOW_EVERYWHERE;
225 //  mode=DRAG_NONE;
226   }
227 
228 
229 // Make a dockable and, possibly, floatable toolbar
FXDockBar(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)230 FXDockBar::FXDockBar(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):FXPacker(p,opts,x,y,w,h,pl,pr,pt,pb,hs,vs),drydock(p),wetdock(q){
231   flags|=FLAG_ENABLED;
232   gripx=0;
233   gripy=0;
234   allowed=ALLOW_EVERYWHERE;
235 //  mode=DRAG_NONE;
236   }
237 
238 
239 // Make a non-floatable toolbar
FXDockBar(FXComposite * p,FXuint opts,FXint x,FXint y,FXint w,FXint h,FXint pl,FXint pr,FXint pt,FXint pb,FXint hs,FXint vs)240 FXDockBar::FXDockBar(FXComposite* p,FXuint opts,FXint x,FXint y,FXint w,FXint h,FXint pl,FXint pr,FXint pt,FXint pb,FXint hs,FXint vs):FXPacker(p,opts,x,y,w,h,pl,pr,pt,pb,hs,vs),drydock(NULL),wetdock(NULL){
241   flags|=FLAG_ENABLED;
242   gripx=0;
243   gripy=0;
244   allowed=ALLOW_EVERYWHERE;
245 //  mode=DRAG_NONE;
246   }
247 
248 
249 // Return true if toolbar is docked
isDocked() const250 FXbool FXDockBar::isDocked() const {
251   return (getParent()!=wetdock);
252   }
253 
254 
255 // Set parent when docked, if it was docked it will remain docked
setDryDock(FXComposite * dry)256 void FXDockBar::setDryDock(FXComposite* dry){
257   if(dry && dry->id() && getParent()==drydock){
258     reparent(dry,NULL);
259     }
260   drydock=dry;
261   }
262 
263 
264 // Set parent when floating
setWetDock(FXComposite * wet)265 void FXDockBar::setWetDock(FXComposite* wet){
266   if(wet && wet->id() && getParent()==wetdock){
267     reparent(wet,NULL);
268     }
269   wetdock=wet;
270   }
271 
272 
273 // Dock the bar before other window
dock(FXDockSite * docksite,FXWindow * other,FXbool notify)274 void FXDockBar::dock(FXDockSite* docksite,FXWindow* other,FXbool notify){
275   if(docksite && getParent()!=docksite){
276     setDryDock(docksite);
277     reparent(docksite,other);
278     if(wetdock) wetdock->hide();
279     docksite->dockToolBar(this,other);
280     if(notify && target){target->tryHandle(this,FXSEL(SEL_DOCKED,message),docksite);}
281     }
282   }
283 
284 
285 // Dock the bar near position in dock site
dock(FXDockSite * docksite,FXint localx,FXint localy,FXbool notify)286 void FXDockBar::dock(FXDockSite* docksite,FXint localx,FXint localy,FXbool notify){
287   if(docksite && getParent()!=docksite){
288     setDryDock(docksite);
289     reparent(docksite,NULL);
290     if(wetdock) wetdock->hide();
291     docksite->dockToolBar(this,localx,localy);
292     if(notify && target){target->tryHandle(this,FXSEL(SEL_DOCKED,message),docksite);}
293     }
294   }
295 
296 
297 // Undock the bar
undock(FXint rootx,FXint rooty,FXbool notify)298 void FXDockBar::undock(FXint rootx,FXint rooty,FXbool notify){
299   FXDockSite* docksite=dynamic_cast<FXDockSite*>(getParent());
300   if(wetdock && isDocked()){
301     if(docksite) docksite->undockToolBar(this);
302     reparent(wetdock);
303     wetdock->position(rootx,rooty,wetdock->getDefaultWidth(),wetdock->getDefaultHeight());
304     wetdock->show();
305     if(notify && target){target->tryHandle(this,FXSEL(SEL_FLOATED,message),docksite);}
306     }
307   }
308 
309 
310 // Return true if layout side is allowable
isAllowable(FXuint hints) const311 FXbool FXDockBar::isAllowable(FXuint hints) const {
312   if(hints&LAYOUT_SIDE_LEFT){
313     if(hints&LAYOUT_SIDE_BOTTOM){       // Right
314       if(allowed&ALLOW_RIGHT) return true;
315       }
316     else{                               // Left
317       if(allowed&ALLOW_LEFT) return true;
318       }
319     }
320   else{
321     if(hints&LAYOUT_SIDE_BOTTOM){       // Bottom
322       if(allowed&ALLOW_BOTTOM) return true;
323       }
324     else{                               // Top
325       if(allowed&ALLOW_TOP) return true;
326       }
327     }
328   return false;
329   }
330 
331 
332 // Search siblings of drydock for first dock opportunity
findDockAtSide(FXuint side)333 FXDockSite* FXDockBar::findDockAtSide(FXuint side){
334   FXDockSite* docksite;
335   FXWindow *child;
336   if(drydock){
337     child=drydock->getParent()->getFirst();
338     while(child){
339       docksite=dynamic_cast<FXDockSite*>(child);
340       if(docksite && docksite->shown() && side==(docksite->getLayoutHints()&LAYOUT_SIDE_MASK)){
341         if(isAllowable(docksite->getLayoutHints())) return docksite;
342         }
343       child=child->getNext();
344       }
345     }
346   return NULL;
347   }
348 
349 
350 // Test if bar is inside docksite
insideDock(FXDockSite * docksite,FXint barx,FXint bary)351 FXbool FXDockBar::insideDock(FXDockSite* docksite,FXint barx,FXint bary){
352   if(docksite){
353 
354     // Bar size
355     FXint barw=getWidth();
356     FXint barh=getHeight();
357 
358     // Vertically oriented dock
359     if(docksite->getLayoutHints()&LAYOUT_SIDE_LEFT){
360 
361       // If docked, undock when left or right edge pulls out beyond FUDGE pixels from dock; when floating, dock when left or right edge moves within PROXIMITY of dock
362       if(((getParent()==docksite) && (docksite->getX()-FUDGE<=barx && barx+barw<docksite->getX()+docksite->getWidth()+FUDGE)) || ((getParent()!=docksite) && ((docksite->getX()-PROXIMITY<=barx && barx<docksite->getX()+docksite->getWidth()+PROXIMITY) || (docksite->getX()-PROXIMITY<=barx+barw && barx+barw<=docksite->getX()+docksite->getWidth()+PROXIMITY)))){
363 
364         // If filled, fudge the height
365         if(getLayoutHints()&LAYOUT_FILL_Y) barh=getDefaultHeight();
366 
367         // Test if either bar or dock "sticks out" too much to dock
368         if(barh>docksite->getHeight()){
369           if(bary-TOLERANCE<=docksite->getY() && docksite->getY()+docksite->getHeight()<=bary+barh+TOLERANCE) return true;
370           }
371         else{
372           if(docksite->getY()-TOLERANCE<=bary && bary+barh<=docksite->getY()+docksite->getHeight()+TOLERANCE) return true;
373           }
374         }
375       }
376 
377     // Horizontally oriented dock
378     else{
379 
380       // If docked, undock when upper or lower edge pulls out beyond FUDGE pixels from dock; when floating, dock when upper or lower edge moves within PROXIMITY of dock
381       if(((getParent()==docksite) && (docksite->getY()-FUDGE<=bary && bary+barh<=docksite->getY()+docksite->getHeight()+FUDGE)) || ((getParent()!=docksite) && ((docksite->getY()-PROXIMITY<=bary && bary<=docksite->getY()+docksite->getHeight()+PROXIMITY) || (docksite->getY()-PROXIMITY<=bary+barh && bary+barh<=docksite->getY()+docksite->getHeight()+PROXIMITY)))){
382 
383         // If filled, fudge the width
384         if(getLayoutHints()&LAYOUT_FILL_X) barw=getDefaultWidth();
385 
386         // Test if either bar or dock "sticks out" too much to dock
387         if(barw>docksite->getWidth()){
388           if(barx-TOLERANCE<=docksite->getX() && docksite->getX()+docksite->getWidth()<=barx+barw+TOLERANCE) return true;
389           }
390         else{
391           if(docksite->getX()-TOLERANCE<=barx && barx+barw<=docksite->getX()+docksite->getWidth()+TOLERANCE) return true;
392           }
393         }
394       }
395     }
396   return false;
397   }
398 
399 
400 // Search siblings of drydock for dock opportunity near given coordinates
findDockNear(FXint rootx,FXint rooty)401 FXDockSite* FXDockBar::findDockNear(FXint rootx,FXint rooty){
402   FXDockSite *docksite;
403   FXWindow *child;
404   FXint barx,bary;
405   if(drydock){
406 
407     // Translate without pain; assumes position of the top window is correct
408     for(child=drydock->getParent(),barx=rootx,bary=rooty; child!=getRoot(); child=child->getParent()){
409       barx-=child->getX();
410       bary-=child->getY();
411       }
412 
413     // Localize dock site
414     child=drydock->getParent()->getFirst();
415     while(child){
416       docksite=dynamic_cast<FXDockSite*>(child);
417       if(docksite && docksite->shown() && insideDock(docksite,barx,bary)){
418         if(isAllowable(docksite->getLayoutHints())) return docksite;
419         }
420       child=child->getNext();
421       }
422     }
423   return NULL;
424   }
425 
426 
427 // Undock
onCmdUndock(FXObject *,FXSelector,void *)428 long FXDockBar::onCmdUndock(FXObject*,FXSelector,void*){
429   FXint rootx,rooty;
430   translateCoordinatesTo(rootx,rooty,getRoot(),8,8);
431   undock(rootx,rooty,true);
432   return 1;
433   }
434 
435 
436 // Check if undocked
onUpdUndock(FXObject * sender,FXSelector,void *)437 long FXDockBar::onUpdUndock(FXObject* sender,FXSelector,void*){
438   sender->handle(this,(wetdock && wetdock!=getParent())?FXSEL(SEL_COMMAND,ID_ENABLE):FXSEL(SEL_COMMAND,ID_DISABLE),NULL);
439   return 1;
440   }
441 
442 
443 // Redock on top
onCmdDockTop(FXObject *,FXSelector,void *)444 long FXDockBar::onCmdDockTop(FXObject*,FXSelector,void*){
445   dock(findDockAtSide(LAYOUT_SIDE_TOP),NULL,true);
446   return 1;
447   }
448 
449 
450 // Check if docked at top
onUpdDockTop(FXObject * sender,FXSelector,void *)451 long FXDockBar::onUpdDockTop(FXObject* sender,FXSelector,void*){
452   FXDockSite* docksite=findDockAtSide(LAYOUT_SIDE_TOP);
453   sender->handle(this,(docksite && docksite!=getParent())?FXSEL(SEL_COMMAND,ID_ENABLE):FXSEL(SEL_COMMAND,ID_DISABLE),NULL);
454   return 1;
455   }
456 
457 
458 // Redock on bottom
onCmdDockBottom(FXObject *,FXSelector,void *)459 long FXDockBar::onCmdDockBottom(FXObject*,FXSelector,void*){
460   dock(findDockAtSide(LAYOUT_SIDE_BOTTOM),NULL,true);
461   return 1;
462   }
463 
464 
465 // Check if docked at bottom
onUpdDockBottom(FXObject * sender,FXSelector,void *)466 long FXDockBar::onUpdDockBottom(FXObject* sender,FXSelector,void*){
467   FXDockSite* docksite=findDockAtSide(LAYOUT_SIDE_BOTTOM);
468   sender->handle(this,(docksite && docksite!=getParent())?FXSEL(SEL_COMMAND,ID_ENABLE):FXSEL(SEL_COMMAND,ID_DISABLE),NULL);
469   return 1;
470   }
471 
472 
473 // Redock on left
onCmdDockLeft(FXObject *,FXSelector,void *)474 long FXDockBar::onCmdDockLeft(FXObject*,FXSelector,void*){
475   dock(findDockAtSide(LAYOUT_SIDE_LEFT),NULL,true);
476   return 1;
477   }
478 
479 
480 // Check if docked at left
onUpdDockLeft(FXObject * sender,FXSelector,void *)481 long FXDockBar::onUpdDockLeft(FXObject* sender,FXSelector,void*){
482   FXDockSite* docksite=findDockAtSide(LAYOUT_SIDE_LEFT);
483   sender->handle(this,(docksite && docksite!=getParent())?FXSEL(SEL_COMMAND,ID_ENABLE):FXSEL(SEL_COMMAND,ID_DISABLE),NULL);
484   return 1;
485   }
486 
487 
488 // Redock on right
onCmdDockRight(FXObject *,FXSelector,void *)489 long FXDockBar::onCmdDockRight(FXObject*,FXSelector,void*){
490   dock(findDockAtSide(LAYOUT_SIDE_RIGHT),NULL,true);
491   return 1;
492   }
493 
494 
495 // Check if docked at right
onUpdDockRight(FXObject * sender,FXSelector,void *)496 long FXDockBar::onUpdDockRight(FXObject* sender,FXSelector,void*){
497   FXDockSite* docksite=findDockAtSide(LAYOUT_SIDE_RIGHT);
498   sender->handle(this,(docksite && docksite!=getParent())?FXSEL(SEL_COMMAND,ID_ENABLE):FXSEL(SEL_COMMAND,ID_DISABLE),NULL);
499   return 1;
500   }
501 
502 
503 // Check for flip
onUpdDockFlip(FXObject * sender,FXSelector,void *)504 long FXDockBar::onUpdDockFlip(FXObject* sender,FXSelector,void*){
505   sender->handle(this,FXSEL(SEL_COMMAND,ID_DISABLE),NULL);
506   return 1;
507   }
508 
509 
510 // Right clicked on bar
onPopupMenu(FXObject *,FXSelector,void * ptr)511 long FXDockBar::onPopupMenu(FXObject*,FXSelector,void* ptr){
512   FXEvent* event=static_cast<FXEvent*>(ptr);
513   if(event->moved) return 1;
514   FXMenuPane dockmenu(this);
515   FXGIFIcon dockflipicon(getApp(),dockflip);
516   FXGIFIcon docktopicon(getApp(),docktop,FXRGB(255,255,255),IMAGE_ALPHACOLOR);
517   FXGIFIcon dockbottomicon(getApp(),dockbottom,FXRGB(255,255,255),IMAGE_ALPHACOLOR);
518   FXGIFIcon docklefticon(getApp(),dockleft,FXRGB(255,255,255),IMAGE_ALPHACOLOR);
519   FXGIFIcon dockrighticon(getApp(),dockright,FXRGB(255,255,255),IMAGE_ALPHACOLOR);
520   FXGIFIcon dockfreeicon(getApp(),dockfree,FXRGB(255,255,255),IMAGE_ALPHACOLOR);
521   new FXMenuCaption(&dockmenu,tr("Docking"));
522   new FXMenuSeparator(&dockmenu);
523   new FXMenuCommand(&dockmenu,tr("Top"),&docktopicon,this,ID_DOCK_TOP);
524   new FXMenuCommand(&dockmenu,tr("Bottom"),&dockbottomicon,this,ID_DOCK_BOTTOM);
525   new FXMenuCommand(&dockmenu,tr("Left"),&docklefticon,this,ID_DOCK_LEFT);
526   new FXMenuCommand(&dockmenu,tr("Right"),&dockrighticon,this,ID_DOCK_RIGHT);
527   new FXMenuCommand(&dockmenu,tr("Float"),&dockfreeicon,this,ID_DOCK_FLOAT);
528   new FXMenuCommand(&dockmenu,tr("Flip"),&dockflipicon,this,ID_DOCK_FLIP);
529   dockmenu.create();
530   dockmenu.popup(NULL,event->root_x,event->root_y);
531   getApp()->runModalWhileShown(&dockmenu);
532   return 1;
533   }
534 
535 
536 // Tool bar grip drag started; the grip widget can be at any level under this dock bar
onBeginDragGrip(FXObject * sender,FXSelector,void * ptr)537 long FXDockBar::onBeginDragGrip(FXObject* sender,FXSelector,void* ptr){
538   FXWindow *grip=static_cast<FXWindow*>(sender);
539   FXEvent* event=static_cast<FXEvent*>(ptr);
540   if(dynamic_cast<FXDockSite*>(drydock)){
541     for(gripx=event->click_x,gripy=event->click_y; grip && grip!=this; grip=grip->getParent()){
542       gripx+=grip->getX();
543       gripy+=grip->getY();
544       }
545     raise();
546     return 1;
547     }
548   return 0;
549   }
550 
551 
552 // Tool bar grip drag ended
onEndDragGrip(FXObject *,FXSelector,void * ptr)553 long FXDockBar::onEndDragGrip(FXObject*,FXSelector,void* ptr){
554   FXToolBarShell *toolbarshell=dynamic_cast<FXToolBarShell*>(getParent());
555   FXEvent* event=static_cast<FXEvent*>(ptr);
556   FXDockSite *toolbardock;
557   FXint rootx,rooty,localx,localy;
558   getApp()->removeTimeout(this,ID_TIMER);
559   if(toolbarshell){
560     if(!(event->state&CONTROLMASK)){
561       rootx=event->root_x-gripx;
562       rooty=event->root_y-gripy;
563       toolbardock=findDockNear(rootx,rooty);
564       if(toolbardock){
565         translateCoordinatesTo(localx,localy,toolbardock,0,0);
566         dock(toolbardock,localx,localy,true);
567         }
568       }
569     }
570   return 1;
571   }
572 
573 
574 // Hovered near dock site:- dock it!
onDockTimer(FXObject *,FXSelector,void * ptr)575 long FXDockBar::onDockTimer(FXObject*,FXSelector,void* ptr){
576   FXDockSite *toolbardock=static_cast<FXDockSite*>(ptr);
577   FXint localx,localy;
578   translateCoordinatesTo(localx,localy,toolbardock,0,0);
579   dock(toolbardock,localx,localy,true);
580   return 1;
581   }
582 
583 
584 // Tool bar grip dragged
onDraggedGrip(FXObject *,FXSelector,void * ptr)585 long FXDockBar::onDraggedGrip(FXObject*,FXSelector,void* ptr){
586   FXToolBarShell *toolbarshell=dynamic_cast<FXToolBarShell*>(getParent());
587   FXDockSite *toolbardock=dynamic_cast<FXDockSite*>(getParent());
588   FXEvent* event=static_cast<FXEvent*>(ptr);
589   FXint rootx,rooty,dockx,docky;
590 
591   // Root position
592   rootx=event->root_x-gripx;
593   rooty=event->root_y-gripy;
594 
595   // Stop dock timer
596   getApp()->removeTimeout(this,ID_TIMER);
597 
598   // We are docked
599   if(toolbardock){
600 
601     // Get mouse position relative to dock site
602     toolbardock->translateCoordinatesFrom(dockx,docky,getRoot(),rootx,rooty);
603 
604     // Move the bar around in dock site
605     toolbardock->moveToolBar(this,dockx,docky);
606 
607     // Test if we pulled too far to stay inside
608     if(!insideDock(toolbardock,dockx+toolbardock->getX(),docky+toolbardock->getY())){
609       undock(rootx,rooty,true);
610       }
611     }
612 
613   // We are floating
614   else if(toolbarshell){
615 
616     // We're near a dock, if we hover around we'll dock there
617     if(!(event->state&CONTROLMASK)){
618       toolbardock=findDockNear(rootx,rooty);
619       if(toolbardock) getApp()->addTimeout(this,ID_TIMER,DOCKINGSNAPDELAY,toolbardock);
620       }
621 
622     // Move around freely
623     wetdock->move(rootx,rooty);
624     }
625 
626   return 1;
627   }
628 
629 
630 /*
631 // Find out where window was grabbed
632 FXuchar FXDockBar::where(FXint x,FXint y) const {
633   FXuchar code=DRAG_NONE;
634   if((0<=x && x<border+padleft) || (0<=y && y<border+padtop) || (width-padright-border<=x && x<width) || (height-padbottom-border<=y && y<height)){
635     if(x<HANDLESIZE) code|=DRAG_LEFT;
636     if(width-HANDLESIZE<=x) code|=DRAG_RIGHT;
637     if(y<HANDLESIZE) code|=DRAG_TOP;
638     if(height-HANDLESIZE<=y) code|=DRAG_BOTTOM;
639     }
640   return code;
641   }
642 
643 
644 // Change cursor if we entered the window normally
645 long FXDockBar::onEnter(FXObject* sender,FXSelector sel,void* ptr){
646   FXPacker::onEnter(sender,sel,ptr);
647   if(((FXEvent*)ptr)->code!=CROSSINGGRAB){
648     setDefaultCursor(getApp()->getDefaultCursor(cursorType[where(((FXEvent*)ptr)->win_x,((FXEvent*)ptr)->win_y)]));
649     }
650   return 1;
651   }
652 
653 
654 // Restore cursor if we left the window normally
655 long FXDockBar::onLeave(FXObject* sender,FXSelector sel,void* ptr){
656   FXPacker::onLeave(sender,sel,ptr);
657   if(((FXEvent*)ptr)->code!=CROSSINGUNGRAB){
658     setDefaultCursor(getApp()->getDefaultCursor(DEF_ARROW_CURSOR));
659     }
660   return 1;
661   }
662 
663 
664 // Pressed LEFT button
665 long FXDockBar::onLeftBtnPress(FXObject*,FXSelector,void* ptr){
666   FXEvent *event=(FXEvent*)ptr;
667   flags&=~FLAG_TIP;
668   handle(this,FXSEL(SEL_FOCUS_SELF,0),ptr);
669   if(isEnabled()){
670     grab();
671     if(target && target->tryHandle(this,FXSEL(SEL_LEFTBUTTONPRESS,message),ptr)) return 1;
672     mode=where(event->win_x,event->win_y);
673     if(mode!=DRAG_NONE){
674       if(mode&DRAG_TOP) gripy=event->win_y;
675       else if(mode&DRAG_BOTTOM) gripy=event->win_y-height;
676       if(mode&DRAG_LEFT) gripx=event->win_x;
677       else if(mode&DRAG_RIGHT) gripx=event->win_x-width;
678       setDragCursor(getApp()->getDefaultCursor(cursorType[mode]));
679       }
680     return 1;
681     }
682   return 0;
683   }
684 
685 
686 // Released LEFT button
687 long FXDockBar::onLeftBtnRelease(FXObject*,FXSelector,void* ptr){
688   if(isEnabled()){
689     ungrab();
690     setDragCursor(getApp()->getDefaultCursor(DEF_ARROW_CURSOR));
691     if(target && target->tryHandle(this,FXSEL(SEL_LEFTBUTTONRELEASE,message),ptr)) return 1;
692     if(mode!=DRAG_NONE){
693       mode=DRAG_NONE;
694       recalc();
695       }
696     return 1;
697     }
698   return 0;
699   }
700 
701 
702 // Moved the mouse
703 long FXDockBar::onMotion(FXObject*,FXSelector,void* ptr){
704   FXEvent *event=(FXEvent*)ptr;
705   if(mode!=DRAG_NONE){
706     FXDockSite *toolbardock=dynamic_cast<FXDockSite*>(getParent());
707     FXint mousex,mousey;
708     FXint x,y,w,h;
709 
710     // Translate to dock site's frame
711     toolbardock->translateCoordinatesFrom(mousex,mousey,getRoot(),event->root_x-gripx,event->root_y-gripy);
712 
713     x=xpos;
714     y=ypos;
715     w=width;
716     h=height;
717 
718     // Vertical
719     if(mode&DRAG_TOP){
720       y=mousey;
721       h=ypos+height-mousey;
722       }
723     else if(mode&DRAG_BOTTOM){
724       h=mousey-ypos;
725       }
726 
727     // Horizontal
728     if(mode&DRAG_LEFT){
729       x=mousex;
730       w=xpos+width-mousex;
731       }
732     else if(mode&DRAG_RIGHT){
733       w=mousex-xpos;
734       }
735 
736     // Resize and move
737     toolbardock->resizeToolBar(this,x,y,w,h);
738     recalc();
739     return 1;
740     }
741 
742   // Change cursor based on location
743   setDefaultCursor(getApp()->getDefaultCursor(cursorType[where(event->win_x,event->win_y)]));
744   return 0;
745   }
746 */
747 
748 
749 // Save data
save(FXStream & store) const750 void FXDockBar::save(FXStream& store) const {
751   FXPacker::save(store);
752   store << drydock;
753   store << wetdock;
754   store << allowed;
755   }
756 
757 
758 // Load data
load(FXStream & store)759 void FXDockBar::load(FXStream& store){
760   FXPacker::load(store);
761   store >> drydock;
762   store >> wetdock;
763   store >> allowed;
764   }
765 
766 
767 // Destroy
~FXDockBar()768 FXDockBar::~FXDockBar(){
769   getApp()->removeTimeout(this,ID_TIMER);
770   drydock=(FXComposite*)-1L;
771   wetdock=(FXComposite*)-1L;
772   }
773 
774 }
775