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