1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/generic/laywin.cpp
3 // Purpose: Implements a simple layout algorithm, plus
4 // wxSashLayoutWindow which is an example of a window with
5 // layout-awareness (via event handlers). This is suited to
6 // IDE-style window layout.
7 // Author: Julian Smart
10 // Copyright: (c) Julian Smart
11 // Licence: wxWindows licence
12 /////////////////////////////////////////////////////////////////////////////
14 // For compilers that support precompilation, includes "wx/wx.h".
15 #include "wx/wxprec.h"
25 #include "wx/laywin.h"
29 IMPLEMENT_DYNAMIC_CLASS(wxQueryLayoutInfoEvent
, wxEvent
)
30 IMPLEMENT_DYNAMIC_CLASS(wxCalculateLayoutEvent
, wxEvent
)
32 wxDEFINE_EVENT( wxEVT_QUERY_LAYOUT_INFO
, wxQueryLayoutInfoEvent
);
33 wxDEFINE_EVENT( wxEVT_CALCULATE_LAYOUT
, wxCalculateLayoutEvent
);
36 // ----------------------------------------------------------------------------
38 // ----------------------------------------------------------------------------
41 IMPLEMENT_CLASS(wxSashLayoutWindow
, wxSashWindow
)
42 BEGIN_EVENT_TABLE(wxSashLayoutWindow
, wxSashWindow
)
43 EVT_CALCULATE_LAYOUT(wxSashLayoutWindow::OnCalculateLayout
)
44 EVT_QUERY_LAYOUT_INFO(wxSashLayoutWindow::OnQueryLayoutInfo
)
47 bool wxSashLayoutWindow::Create(wxWindow
*parent
, wxWindowID id
, const wxPoint
& pos
,
48 const wxSize
& size
, long style
, const wxString
& name
)
50 return wxSashWindow::Create(parent
, id
, pos
, size
, style
, name
);
53 void wxSashLayoutWindow::Init()
55 m_orientation
= wxLAYOUT_HORIZONTAL
;
56 m_alignment
= wxLAYOUT_TOP
;
58 MacSetClipChildren( true ) ;
62 // This is the function that wxLayoutAlgorithm calls to ascertain the window
64 void wxSashLayoutWindow::OnQueryLayoutInfo(wxQueryLayoutInfoEvent
& event
)
66 // int flags = event.GetFlags();
67 int requestedLength
= event
.GetRequestedLength();
69 event
.SetOrientation(m_orientation
);
70 event
.SetAlignment(m_alignment
);
72 if (m_orientation
== wxLAYOUT_HORIZONTAL
)
73 event
.SetSize(wxSize(requestedLength
, m_defaultSize
.y
));
75 event
.SetSize(wxSize(m_defaultSize
.x
, requestedLength
));
78 // Called by parent to allow window to take a bit out of the
79 // client rectangle, and size itself if not in wxLAYOUT_QUERY mode.
81 void wxSashLayoutWindow::OnCalculateLayout(wxCalculateLayoutEvent
& event
)
83 wxRect
clientSize(event
.GetRect());
85 int flags
= event
.GetFlags();
90 // Let's assume that all windows stretch the full extent of the window in
91 // the direction of that window orientation. This will work for non-docking toolbars,
92 // and the status bar. Note that the windows have to have been created in a certain
93 // order to work, else you might get a left-aligned window going to the bottom
94 // of the window, and the status bar appearing to the right of it. The
95 // status bar would have to be created after or before the toolbar(s).
100 int length
= (GetOrientation() == wxLAYOUT_HORIZONTAL
) ? clientSize
.width
: clientSize
.height
;
101 wxLayoutOrientation orient
= GetOrientation();
103 // We assume that a window that says it's horizontal, wants to be stretched in that
104 // direction. Is this distinction too fine? Do we assume that any horizontal
105 // window needs to be stretched in that direction? Possibly.
106 int whichDimension
= (GetOrientation() == wxLAYOUT_HORIZONTAL
) ? wxLAYOUT_LENGTH_X
: wxLAYOUT_LENGTH_Y
;
108 wxQueryLayoutInfoEvent
infoEvent(GetId());
109 infoEvent
.SetEventObject(this);
110 infoEvent
.SetRequestedLength(length
);
111 infoEvent
.SetFlags(orient
| whichDimension
);
113 if (!GetEventHandler()->ProcessEvent(infoEvent
))
116 wxSize sz
= infoEvent
.GetSize();
118 if (sz
.x
== 0 && sz
.y
== 0) // Assume it's invisible
121 // Now we know the size it wants to be. We wish to decide where to place it, i.e.
123 switch (GetAlignment())
127 thisRect
.x
= clientSize
.x
; thisRect
.y
= clientSize
.y
;
128 thisRect
.width
= sz
.x
; thisRect
.height
= sz
.y
;
129 clientSize
.y
+= thisRect
.height
;
130 clientSize
.height
-= thisRect
.height
;
135 thisRect
.x
= clientSize
.x
; thisRect
.y
= clientSize
.y
;
136 thisRect
.width
= sz
.x
; thisRect
.height
= sz
.y
;
137 clientSize
.x
+= thisRect
.width
;
138 clientSize
.width
-= thisRect
.width
;
143 thisRect
.x
= clientSize
.x
+ (clientSize
.width
- sz
.x
); thisRect
.y
= clientSize
.y
;
144 thisRect
.width
= sz
.x
; thisRect
.height
= sz
.y
;
145 clientSize
.width
-= thisRect
.width
;
148 case wxLAYOUT_BOTTOM
:
150 thisRect
.x
= clientSize
.x
; thisRect
.y
= clientSize
.y
+ (clientSize
.height
- sz
.y
);
151 thisRect
.width
= sz
.x
; thisRect
.height
= sz
.y
;
152 clientSize
.height
-= thisRect
.height
;
162 if ((flags
& wxLAYOUT_QUERY
) == 0)
164 // If not in query mode, resize the window.
165 // TODO: add wxRect& form to wxWindow::SetSize
166 wxSize sz2
= GetSize();
167 wxPoint pos
= GetPosition();
168 SetSize(thisRect
.x
, thisRect
.y
, thisRect
.width
, thisRect
.height
);
170 // Make sure the sash is erased when the window is resized
171 if ((pos
.x
!= thisRect
.x
|| pos
.y
!= thisRect
.y
|| sz2
.x
!= thisRect
.width
|| sz2
.y
!= thisRect
.height
) &&
172 (GetSashVisible(wxSASH_TOP
) || GetSashVisible(wxSASH_RIGHT
) || GetSashVisible(wxSASH_BOTTOM
) || GetSashVisible(wxSASH_LEFT
)))
177 event
.SetRect(clientSize
);
182 // ----------------------------------------------------------------------------
184 // ----------------------------------------------------------------------------
186 #if wxUSE_MDI_ARCHITECTURE
188 // Lays out windows for an MDI frame. The MDI client area gets what's left
190 bool wxLayoutAlgorithm::LayoutMDIFrame(wxMDIParentFrame
* frame
, wxRect
* r
)
193 frame
->GetClientSize(& cw
, & ch
);
195 wxRect
rect(0, 0, cw
, ch
);
199 wxCalculateLayoutEvent event
;
202 wxWindowList::compatibility_iterator node
= frame
->GetChildren().GetFirst();
205 wxWindow
* win
= node
->GetData();
207 event
.SetId(win
->GetId());
208 event
.SetEventObject(win
);
209 event
.SetFlags(0); // ??
211 win
->GetEventHandler()->ProcessEvent(event
);
213 node
= node
->GetNext();
216 wxWindow
* clientWindow
= frame
->GetClientWindow();
218 rect
= event
.GetRect();
220 clientWindow
->SetSize(rect
.x
, rect
.y
, rect
.width
, rect
.height
);
225 #endif // wxUSE_MDI_ARCHITECTURE
227 bool wxLayoutAlgorithm::LayoutFrame(wxFrame
* frame
, wxWindow
* mainWindow
)
229 return LayoutWindow(frame
, mainWindow
);
232 // Layout algorithm for any window. mainWindow gets what's left over.
233 bool wxLayoutAlgorithm::LayoutWindow(wxWindow
* parent
, wxWindow
* mainWindow
)
235 // Test if the parent is a sash window, and if so,
236 // reduce the available space to allow space for any active edges.
238 int leftMargin
= 0, rightMargin
= 0, topMargin
= 0, bottomMargin
= 0;
240 if (wxDynamicCast(parent
, wxSashWindow
))
242 wxSashWindow
* sashWindow
= (wxSashWindow
*) parent
;
244 leftMargin
= sashWindow
->GetExtraBorderSize();
245 rightMargin
= sashWindow
->GetExtraBorderSize();
246 topMargin
= sashWindow
->GetExtraBorderSize();
247 bottomMargin
= sashWindow
->GetExtraBorderSize();
249 if (sashWindow
->GetSashVisible(wxSASH_LEFT
))
250 leftMargin
+= sashWindow
->GetDefaultBorderSize();
251 if (sashWindow
->GetSashVisible(wxSASH_RIGHT
))
252 rightMargin
+= sashWindow
->GetDefaultBorderSize();
253 if (sashWindow
->GetSashVisible(wxSASH_TOP
))
254 topMargin
+= sashWindow
->GetDefaultBorderSize();
255 if (sashWindow
->GetSashVisible(wxSASH_BOTTOM
))
256 bottomMargin
+= sashWindow
->GetDefaultBorderSize();
261 parent
->GetClientSize(& cw
, & ch
);
263 wxRect
rect(leftMargin
, topMargin
, cw
- leftMargin
- rightMargin
, ch
- topMargin
- bottomMargin
);
265 wxCalculateLayoutEvent event
;
268 // Find the last layout-aware window, so we can make it fill all remaining
270 wxWindow
*lastAwareWindow
= NULL
;
271 wxWindowList::compatibility_iterator node
= parent
->GetChildren().GetFirst();
275 wxWindow
* win
= node
->GetData();
279 wxCalculateLayoutEvent
tempEvent(win
->GetId());
280 tempEvent
.SetEventObject(win
);
281 tempEvent
.SetFlags(wxLAYOUT_QUERY
);
282 tempEvent
.SetRect(event
.GetRect());
283 if (win
->GetEventHandler()->ProcessEvent(tempEvent
))
284 lastAwareWindow
= win
;
287 node
= node
->GetNext();
290 // Now do a dummy run to see if we have any space left for the final window (fail if not)
291 node
= parent
->GetChildren().GetFirst();
294 wxWindow
* win
= node
->GetData();
296 // If mainWindow is NULL and we're at the last window,
297 // skip this, because we'll simply make it fit the remaining space.
298 if (win
->IsShown() && (win
!= mainWindow
) && (mainWindow
!= NULL
|| win
!= lastAwareWindow
))
300 event
.SetId(win
->GetId());
301 event
.SetEventObject(win
);
302 event
.SetFlags(wxLAYOUT_QUERY
);
304 win
->GetEventHandler()->ProcessEvent(event
);
307 node
= node
->GetNext();
310 if (event
.GetRect().GetWidth() < 0 || event
.GetRect().GetHeight() < 0)
315 node
= parent
->GetChildren().GetFirst();
318 wxWindow
* win
= node
->GetData();
320 // If mainWindow is NULL and we're at the last window,
321 // skip this, because we'll simply make it fit the remaining space.
322 if (win
->IsShown() && (win
!= mainWindow
) && (mainWindow
!= NULL
|| win
!= lastAwareWindow
))
324 event
.SetId(win
->GetId());
325 event
.SetEventObject(win
);
326 event
.SetFlags(0); // ??
328 win
->GetEventHandler()->ProcessEvent(event
);
331 node
= node
->GetNext();
334 rect
= event
.GetRect();
337 mainWindow
->SetSize(rect
.x
, rect
.y
, wxMax(0, rect
.width
), wxMax(0, rect
.height
));
338 else if (lastAwareWindow
)
340 // Fit the remaining space
341 lastAwareWindow
->SetSize(rect
.x
, rect
.y
, wxMax(0, rect
.width
), wxMax(0, rect
.height
));