1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxSashWindow implementation. A sash window has an optional
4 // sash on each edge, allowing it to be dragged. An event
5 // is generated when the sash is released.
6 // Author: Julian Smart
10 // Copyright: (c) Julian Smart
11 // Licence: wxWindows license
12 /////////////////////////////////////////////////////////////////////////////
15 #pragma implementation "sashwin.h"
18 // For compilers that support precompilation, includes "wx.h".
19 #include "wx/wxprec.h"
32 #include "wx/string.h"
33 #include "wx/dcscreen.h"
34 #include "wx/sashwin.h"
36 #if !USE_SHARED_LIBRARY
37 IMPLEMENT_DYNAMIC_CLASS(wxSashWindow
, wxWindow
)
38 IMPLEMENT_DYNAMIC_CLASS(wxSashEvent
, wxCommandEvent
)
40 BEGIN_EVENT_TABLE(wxSashWindow
, wxWindow
)
41 EVT_PAINT(wxSashWindow::OnPaint
)
42 EVT_SIZE(wxSashWindow::OnSize
)
43 EVT_MOUSE_EVENTS(wxSashWindow::OnMouseEvent
)
47 wxSashWindow::wxSashWindow()
49 m_draggingEdge
= wxSASH_NONE
;
50 m_dragMode
= wxSASH_DRAG_NONE
;
56 m_extraBorderSize
= 0;
57 m_sashCursorWE
= NULL
;
58 m_sashCursorNS
= NULL
;
60 m_minimumPaneSizeX
= 0;
61 m_minimumPaneSizeY
= 0;
62 m_maximumPaneSizeX
= 0;
63 m_maximumPaneSizeY
= 0;
66 wxSashWindow::wxSashWindow(wxWindow
*parent
, wxWindowID id
, const wxPoint
& pos
,
67 const wxSize
& size
, long style
, const wxString
& name
)
68 :wxWindow(parent
, id
, pos
, size
, style
, name
)
70 m_draggingEdge
= wxSASH_NONE
;
71 m_dragMode
= wxSASH_DRAG_NONE
;
77 m_extraBorderSize
= 0;
78 m_minimumPaneSizeX
= 0;
79 m_minimumPaneSizeY
= 0;
80 m_maximumPaneSizeX
= 0;
81 m_maximumPaneSizeY
= 0;
82 m_sashCursorWE
= new wxCursor(wxCURSOR_SIZEWE
);
83 m_sashCursorNS
= new wxCursor(wxCURSOR_SIZENS
);
85 // Eventually, we'll respond to colour change messages
89 wxSashWindow::~wxSashWindow()
91 delete m_sashCursorWE
;
92 delete m_sashCursorNS
;
95 void wxSashWindow::OnPaint(wxPaintEvent
& WXUNUSED(event
))
100 if ( m_borderSize
> 0 )
107 void wxSashWindow::OnMouseEvent(wxMouseEvent
& event
)
110 event
.Position(&x
, &y
);
112 wxSashEdgePosition sashHit
= SashHitTest(x
, y
);
114 if (event
.LeftDown())
116 if ( sashHit
!= wxSASH_NONE
)
120 // Required for X to specify that
121 // that we wish to draw on top of all windows
122 // - and we optimise by specifying the area
123 // for creating the overlap window.
124 wxScreenDC::StartDrawingOnTop(this);
126 // We don't say we're dragging yet; we leave that
127 // decision for the Dragging() branch, to ensure
128 // the user has dragged a little bit.
129 m_dragMode
= wxSASH_DRAG_LEFT_DOWN
;
130 m_draggingEdge
= sashHit
;
135 else if ( event
.LeftUp() && m_dragMode
== wxSASH_DRAG_LEFT_DOWN
)
137 // Wasn't a proper drag
139 wxScreenDC::EndDrawingOnTop();
140 m_dragMode
= wxSASH_DRAG_NONE
;
141 m_draggingEdge
= wxSASH_NONE
;
143 SetCursor(*wxSTANDARD_CURSOR
);
145 else if (event
.LeftUp() && m_dragMode
== wxSASH_DRAG_DRAGGING
)
147 // We can stop dragging now and see what we've got.
148 m_dragMode
= wxSASH_DRAG_NONE
;
151 DrawSashTracker(m_draggingEdge
, m_oldX
, m_oldY
);
153 // End drawing on top (frees the window used for drawing
155 wxScreenDC::EndDrawingOnTop();
160 GetPosition(&xp
, &yp
);
162 wxSashEdgePosition edge
= m_draggingEdge
;
163 m_draggingEdge
= wxSASH_NONE
;
166 wxSashDragStatus status
= wxSASH_STATUS_OK
;
172 status
= wxSASH_STATUS_OUT_OF_RANGE
;
173 int newHeight
= (h
- y
);
174 dragRect
= wxRect(xp
, (yp
+ h
) - newHeight
, w
, newHeight
);
180 status
= wxSASH_STATUS_OUT_OF_RANGE
;
182 dragRect
= wxRect(xp
, yp
, w
, newHeight
);
188 status
= wxSASH_STATUS_OUT_OF_RANGE
;
189 int newWidth
= (w
- x
);
190 dragRect
= wxRect((xp
+ w
) - newWidth
, yp
, newWidth
, h
);
196 status
= wxSASH_STATUS_OUT_OF_RANGE
;
198 dragRect
= wxRect(xp
, yp
, newWidth
, h
);
203 wxSashEvent
event(GetId(), edge
);
204 event
.SetEventObject(this);
205 event
.SetDragStatus(status
);
206 event
.SetDragRect(dragRect
);
207 GetEventHandler()->ProcessEvent(event
);
209 else if (event
.Moving() && !event
.Dragging())
211 // Just change the cursor if required
212 if ( sashHit
!= wxSASH_NONE
)
214 if ( (sashHit
== wxSASH_LEFT
) || (sashHit
== wxSASH_RIGHT
) )
216 SetCursor(*m_sashCursorWE
);
220 SetCursor(*m_sashCursorNS
);
225 SetCursor(*wxSTANDARD_CURSOR
);
228 else if ( event
.Dragging() &&
229 ((m_dragMode
== wxSASH_DRAG_DRAGGING
) || (m_dragMode
== wxSASH_DRAG_LEFT_DOWN
))
232 if ( (m_draggingEdge
== wxSASH_LEFT
) || (m_draggingEdge
== wxSASH_RIGHT
) )
234 SetCursor(*m_sashCursorWE
);
238 SetCursor(*m_sashCursorNS
);
241 if (m_dragMode
== wxSASH_DRAG_LEFT_DOWN
)
243 m_dragMode
= wxSASH_DRAG_DRAGGING
;
244 DrawSashTracker(m_draggingEdge
, x
, y
);
248 if ( m_dragMode
== wxSASH_DRAG_DRAGGING
)
251 DrawSashTracker(m_draggingEdge
, m_oldX
, m_oldY
);
254 DrawSashTracker(m_draggingEdge
, x
, y
);
260 else if ( event
.LeftDClick() )
269 void wxSashWindow::OnSize(wxSizeEvent
& WXUNUSED(event
))
274 wxSashEdgePosition
wxSashWindow::SashHitTest(int x
, int y
, int tolerance
)
277 GetClientSize(& cx
, & cy
);
280 for (i
= 0; i
< 4; i
++)
282 wxSashEdge
& edge
= m_sashes
[i
];
283 wxSashEdgePosition position
= (wxSashEdgePosition
) i
;
291 if (y
>= 0 && y
<= GetEdgeMargin(position
))
297 if ((x
>= cx
- GetEdgeMargin(position
)) && (x
<= cx
))
303 if ((y
>= cy
- GetEdgeMargin(position
)) && (y
<= cy
))
304 return wxSASH_BOTTOM
;
309 if ((x
>= GetEdgeMargin(position
)) && (x
>= 0))
319 // Draw 3D effect borders
320 void wxSashWindow::DrawBorders(wxDC
& dc
)
323 GetClientSize(&w
, &h
);
325 wxPen
mediumShadowPen(m_mediumShadowColour
, 1, wxSOLID
);
326 wxPen
darkShadowPen(m_darkShadowColour
, 1, wxSOLID
);
327 wxPen
lightShadowPen(m_lightShadowColour
, 1, wxSOLID
);
328 wxPen
hilightPen(m_hilightColour
, 1, wxSOLID
);
330 if ( GetWindowStyleFlag() & wxSP_3D
)
332 dc
.SetPen(mediumShadowPen
);
333 dc
.DrawLine(0, 0, w
-1, 0);
334 dc
.DrawLine(0, 0, 0, h
- 1);
336 dc
.SetPen(darkShadowPen
);
337 dc
.DrawLine(1, 1, w
-2, 1);
338 dc
.DrawLine(1, 1, 1, h
-2);
340 dc
.SetPen(hilightPen
);
341 dc
.DrawLine(0, h
-1, w
-1, h
-1);
342 dc
.DrawLine(w
-1, 0, w
-1, h
); // Surely the maximum y pos. should be h - 1.
343 /// Anyway, h is required for MSW.
345 dc
.SetPen(lightShadowPen
);
346 dc
.DrawLine(w
-2, 1, w
-2, h
-2); // Right hand side
347 dc
.DrawLine(1, h
-2, w
-1, h
-2); // Bottom
349 else if ( GetWindowStyleFlag() & wxSP_BORDER
)
351 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
352 dc
.SetPen(*wxBLACK_PEN
);
353 dc
.DrawRectangle(0, 0, w
-1, h
-1);
356 dc
.SetPen(wxNullPen
);
357 dc
.SetBrush(wxNullBrush
);
360 void wxSashWindow::DrawSashes(wxDC
& dc
)
363 for (i
= 0; i
< 4; i
++)
364 if (m_sashes
[i
].m_show
)
365 DrawSash((wxSashEdgePosition
) i
, dc
);
369 void wxSashWindow::DrawSash(wxSashEdgePosition edge
, wxDC
& dc
)
372 GetClientSize(&w
, &h
);
374 wxPen
facePen(m_faceColour
, 1, wxSOLID
);
375 wxBrush
faceBrush(m_faceColour
, wxSOLID
);
376 wxPen
mediumShadowPen(m_mediumShadowColour
, 1, wxSOLID
);
377 wxPen
darkShadowPen(m_darkShadowColour
, 1, wxSOLID
);
378 wxPen
lightShadowPen(m_lightShadowColour
, 1, wxSOLID
);
379 wxPen
hilightPen(m_hilightColour
, 1, wxSOLID
);
380 wxPen
blackPen(wxColour(0, 0, 0), 1, wxSOLID
);
381 wxPen
whitePen(wxColour(255, 255, 255), 1, wxSOLID
);
383 if ( edge
== wxSASH_LEFT
|| edge
== wxSASH_RIGHT
)
385 int sashPosition
= 0;
386 if (edge
== wxSASH_LEFT
)
389 sashPosition
= w
- GetEdgeMargin(edge
);
392 dc
.SetBrush(faceBrush
);
393 dc
.DrawRectangle(sashPosition
, 0, GetEdgeMargin(edge
), h
);
395 if (GetWindowStyleFlag() & wxSW_3D
)
397 if (edge
== wxSASH_LEFT
)
399 // Draw a black line on the left to indicate that the
402 dc
.DrawLine(GetEdgeMargin(edge
), 0, GetEdgeMargin(edge
), h
);
406 // Draw a white line on the right to indicate that the
409 dc
.DrawLine(w
- GetEdgeMargin(edge
), 0, w
- GetEdgeMargin(edge
), h
);
413 else // top or bottom
415 int sashPosition
= 0;
416 if (edge
== wxSASH_TOP
)
419 sashPosition
= h
- GetEdgeMargin(edge
);
422 dc
.SetBrush(faceBrush
);
423 dc
.DrawRectangle(0, sashPosition
, w
, GetEdgeMargin(edge
));
425 if (GetWindowStyleFlag() & wxSW_3D
)
427 if (edge
== wxSASH_BOTTOM
)
429 // Draw a black line on the bottom to indicate that the
432 dc
.DrawLine(0, h
- GetEdgeMargin(edge
), w
, h
- GetEdgeMargin(edge
));
436 // Draw a white line on the top to indicate that the
439 dc
.DrawLine(0, GetEdgeMargin(edge
), w
, GetEdgeMargin(edge
));
444 dc
.SetPen(wxNullPen
);
445 dc
.SetBrush(wxNullBrush
);
448 // Draw the sash tracker (for whilst moving the sash)
449 void wxSashWindow::DrawSashTracker(wxSashEdgePosition edge
, int x
, int y
)
452 GetClientSize(&w
, &h
);
458 if ( edge
== wxSASH_LEFT
|| edge
== wxSASH_RIGHT
)
463 if ( (edge
== wxSASH_LEFT
) && (x1
> w
) )
467 else if ( (edge
== wxSASH_RIGHT
) && (x1
< 0) )
477 if ( (edge
== wxSASH_TOP
) && (y1
> h
) )
482 else if ( (edge
== wxSASH_BOTTOM
) && (y1
< 0) )
489 ClientToScreen(&x1
, &y1
);
490 ClientToScreen(&x2
, &y2
);
492 wxPen
sashTrackerPen(*wxBLACK
, 2, wxSOLID
);
494 screenDC
.SetLogicalFunction(wxXOR
);
495 screenDC
.SetPen(sashTrackerPen
);
496 screenDC
.SetBrush(*wxTRANSPARENT_BRUSH
);
498 screenDC
.DrawLine(x1
, y1
, x2
, y2
);
500 screenDC
.SetLogicalFunction(wxCOPY
);
502 screenDC
.SetPen(wxNullPen
);
503 screenDC
.SetBrush(wxNullBrush
);
506 // Position and size subwindows.
507 // Note that the border size applies to each subwindow, not
508 // including the edges next to the sash.
509 void wxSashWindow::SizeWindows()
512 GetClientSize(&cw
, &ch
);
514 if (GetChildren()->Number() > 0)
516 wxWindow
* child
= (wxWindow
*) (GetChildren()->First()->Data());
524 if (m_sashes
[0].m_show
)
527 height
-= m_borderSize
;
529 y
+= m_extraBorderSize
;
532 if (m_sashes
[3].m_show
)
535 width
-= m_borderSize
;
537 x
+= m_extraBorderSize
;
540 if (m_sashes
[1].m_show
)
542 width
-= m_borderSize
;
544 width
-= 2*m_extraBorderSize
;
547 if (m_sashes
[2].m_show
)
549 height
-= m_borderSize
;
551 height
-= 2*m_extraBorderSize
;
553 child
->SetSize(x
, y
, width
, height
);
561 // Initialize colours
562 void wxSashWindow::InitColours()
565 #if defined(__WIN95__)
566 m_faceColour
= wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE
);
567 m_mediumShadowColour
= wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DSHADOW
);
568 m_darkShadowColour
= wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DDKSHADOW
);
569 m_lightShadowColour
= wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DLIGHT
);
570 m_hilightColour
= wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DHILIGHT
);
572 m_faceColour
= *(wxTheColourDatabase
->FindColour("LIGHT GREY"));
573 m_mediumShadowColour
= *(wxTheColourDatabase
->FindColour("GREY", 1, wxSOLID
));
574 m_darkShadowColour
= *(wxTheColourDatabase
->FindColour("BLACK"));
575 m_lightShadowColour
= *(wxTheColourDatabase
->FindColour("LIGHT GREY"));
576 m_hilightColour
= *(wxTheColourDatabase
->FindColour("WHITE"));
580 void wxSashWindow::SetSashVisible(wxSashEdgePosition edge
, bool sash
)
582 m_sashes
[edge
].m_show
= sash
;
584 m_sashes
[edge
].m_margin
= m_borderSize
;
586 m_sashes
[edge
].m_margin
= 0;