1 ///////////////////////////////////////////////////////////////////////////// 
   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 
  11 // Copyright:   (c) Julian Smart 
  12 // Licence:     wxWindows licence 
  13 ///////////////////////////////////////////////////////////////////////////// 
  15 // For compilers that support precompilation, includes "wx/wx.h". 
  16 #include "wx/wxprec.h" 
  27 #include "wx/laywin.h" 
  29 IMPLEMENT_DYNAMIC_CLASS(wxQueryLayoutInfoEvent
, wxEvent
) 
  30 IMPLEMENT_DYNAMIC_CLASS(wxCalculateLayoutEvent
, wxEvent
) 
  32 DEFINE_EVENT_TYPE(wxEVT_QUERY_LAYOUT_INFO
) 
  33 DEFINE_EVENT_TYPE(wxEVT_CALCULATE_LAYOUT
) 
  36 IMPLEMENT_CLASS(wxSashLayoutWindow
, wxSashWindow
) 
  38 BEGIN_EVENT_TABLE(wxSashLayoutWindow
, wxSashWindow
) 
  39     EVT_CALCULATE_LAYOUT(wxSashLayoutWindow::OnCalculateLayout
) 
  40     EVT_QUERY_LAYOUT_INFO(wxSashLayoutWindow::OnQueryLayoutInfo
) 
  43 bool wxSashLayoutWindow::Create(wxWindow 
*parent
, wxWindowID id
, const wxPoint
& pos
, 
  44         const wxSize
& size
, long style
, const wxString
& name
) 
  46     return wxSashWindow::Create(parent
, id
, pos
, size
, style
, name
); 
  49 void wxSashLayoutWindow::Init() 
  51     m_orientation 
= wxLAYOUT_HORIZONTAL
; 
  52     m_alignment 
= wxLAYOUT_TOP
; 
  54     MacSetClipChildren( true ) ; 
  58 // This is the function that wxLayoutAlgorithm calls to ascertain the window 
  60 void wxSashLayoutWindow::OnQueryLayoutInfo(wxQueryLayoutInfoEvent
& event
) 
  62   //    int flags = event.GetFlags(); 
  63     int requestedLength 
= event
.GetRequestedLength(); 
  65     event
.SetOrientation(m_orientation
); 
  66     event
.SetAlignment(m_alignment
); 
  68     if (m_orientation 
== wxLAYOUT_HORIZONTAL
) 
  69         event
.SetSize(wxSize(requestedLength
, m_defaultSize
.y
)); 
  71         event
.SetSize(wxSize(m_defaultSize
.x
, requestedLength
)); 
  74 // Called by parent to allow window to take a bit out of the 
  75 // client rectangle, and size itself if not in wxLAYOUT_QUERY mode. 
  77 void wxSashLayoutWindow::OnCalculateLayout(wxCalculateLayoutEvent
& event
) 
  79     wxRect 
clientSize(event
.GetRect()); 
  81     int flags 
= event
.GetFlags(); 
  86     // Let's assume that all windows stretch the full extent of the window in 
  87     // the direction of that window orientation. This will work for non-docking toolbars, 
  88     // and the status bar. Note that the windows have to have been created in a certain 
  89     // order to work, else you might get a left-aligned window going to the bottom 
  90     // of the window, and the status bar appearing to the right of it. The 
  91     // status bar would have to be created after or before the toolbar(s). 
  96     int length 
= (GetOrientation() == wxLAYOUT_HORIZONTAL
) ? clientSize
.width 
: clientSize
.height
; 
  97     wxLayoutOrientation orient 
= GetOrientation(); 
  99     // We assume that a window that says it's horizontal, wants to be stretched in that 
 100     // direction. Is this distinction too fine? Do we assume that any horizontal 
 101     // window needs to be stretched in that direction? Possibly. 
 102     int whichDimension 
= (GetOrientation() == wxLAYOUT_HORIZONTAL
) ? wxLAYOUT_LENGTH_X 
: wxLAYOUT_LENGTH_Y
; 
 104     wxQueryLayoutInfoEvent 
infoEvent(GetId()); 
 105     infoEvent
.SetEventObject(this); 
 106     infoEvent
.SetRequestedLength(length
); 
 107     infoEvent
.SetFlags(orient 
| whichDimension
); 
 109     if (!GetEventHandler()->ProcessEvent(infoEvent
)) 
 112     wxSize sz 
= infoEvent
.GetSize(); 
 114     if (sz
.x 
== 0 && sz
.y 
== 0) // Assume it's invisible 
 117     // Now we know the size it wants to be. We wish to decide where to place it, i.e. 
 119     switch (GetAlignment()) 
 123             thisRect
.x 
= clientSize
.x
; thisRect
.y 
= clientSize
.y
; 
 124             thisRect
.width 
= sz
.x
; thisRect
.height 
= sz
.y
; 
 125             clientSize
.y 
+= thisRect
.height
; 
 126             clientSize
.height 
-= thisRect
.height
; 
 131             thisRect
.x 
= clientSize
.x
; thisRect
.y 
= clientSize
.y
; 
 132             thisRect
.width 
= sz
.x
; thisRect
.height 
= sz
.y
; 
 133             clientSize
.x 
+= thisRect
.width
; 
 134             clientSize
.width 
-= thisRect
.width
; 
 139             thisRect
.x 
= clientSize
.x 
+ (clientSize
.width 
- sz
.x
); thisRect
.y 
= clientSize
.y
; 
 140             thisRect
.width 
= sz
.x
; thisRect
.height 
= sz
.y
; 
 141             clientSize
.width 
-= thisRect
.width
; 
 144         case wxLAYOUT_BOTTOM
: 
 146             thisRect
.x 
= clientSize
.x
; thisRect
.y 
= clientSize
.y 
+ (clientSize
.height 
- sz
.y
); 
 147             thisRect
.width 
= sz
.x
; thisRect
.height 
= sz
.y
; 
 148             clientSize
.height 
-= thisRect
.height
; 
 158     if ((flags 
& wxLAYOUT_QUERY
) == 0) 
 160         // If not in query mode, resize the window. 
 161         // TODO: add wxRect& form to wxWindow::SetSize 
 162         wxSize sz2 
= GetSize(); 
 163         wxPoint pos 
= GetPosition(); 
 164         SetSize(thisRect
.x
, thisRect
.y
, thisRect
.width
, thisRect
.height
); 
 166         // Make sure the sash is erased when the window is resized 
 167         if ((pos
.x 
!= thisRect
.x 
|| pos
.y 
!= thisRect
.y 
|| sz2
.x 
!= thisRect
.width 
|| sz2
.y 
!= thisRect
.height
) && 
 168             (GetSashVisible(wxSASH_TOP
) || GetSashVisible(wxSASH_RIGHT
) || GetSashVisible(wxSASH_BOTTOM
) || GetSashVisible(wxSASH_LEFT
))) 
 173     event
.SetRect(clientSize
); 
 181 #if wxUSE_MDI_ARCHITECTURE 
 183 // Lays out windows for an MDI frame. The MDI client area gets what's left 
 185 bool wxLayoutAlgorithm::LayoutMDIFrame(wxMDIParentFrame
* frame
, wxRect
* r
) 
 188     frame
->GetClientSize(& cw
, & ch
); 
 190     wxRect 
rect(0, 0, cw
, ch
); 
 194     wxCalculateLayoutEvent event
; 
 197     wxWindowList::compatibility_iterator node 
= frame
->GetChildren().GetFirst(); 
 200         wxWindow
* win 
= node
->GetData(); 
 202         event
.SetId(win
->GetId()); 
 203         event
.SetEventObject(win
); 
 204         event
.SetFlags(0); // ?? 
 206         win
->GetEventHandler()->ProcessEvent(event
); 
 208         node 
= node
->GetNext(); 
 211     wxWindow
* clientWindow 
= frame
->GetClientWindow(); 
 213     rect 
= event
.GetRect(); 
 215     clientWindow
->SetSize(rect
.x
, rect
.y
, rect
.width
, rect
.height
); 
 220 #endif // wxUSE_MDI_ARCHITECTURE 
 222 bool wxLayoutAlgorithm::LayoutFrame(wxFrame
* frame
, wxWindow
* mainWindow
) 
 224     return LayoutWindow(frame
, mainWindow
); 
 227 // Layout algorithm for any window. mainWindow gets what's left over. 
 228 bool wxLayoutAlgorithm::LayoutWindow(wxWindow
* parent
, wxWindow
* mainWindow
) 
 230     // Test if the parent is a sash window, and if so, 
 231     // reduce the available space to allow space for any active edges. 
 233     int leftMargin 
= 0, rightMargin 
= 0, topMargin 
= 0, bottomMargin 
= 0; 
 235     if (parent
->IsKindOf(CLASSINFO(wxSashWindow
))) 
 237         wxSashWindow
* sashWindow 
= (wxSashWindow
*) parent
; 
 239         leftMargin 
= sashWindow
->GetExtraBorderSize(); 
 240         rightMargin 
= sashWindow
->GetExtraBorderSize(); 
 241         topMargin 
= sashWindow
->GetExtraBorderSize(); 
 242         bottomMargin 
= sashWindow
->GetExtraBorderSize(); 
 244         if (sashWindow
->GetSashVisible(wxSASH_LEFT
)) 
 245             leftMargin 
+= sashWindow
->GetDefaultBorderSize(); 
 246         if (sashWindow
->GetSashVisible(wxSASH_RIGHT
)) 
 247             rightMargin 
+= sashWindow
->GetDefaultBorderSize(); 
 248         if (sashWindow
->GetSashVisible(wxSASH_TOP
)) 
 249             topMargin 
+= sashWindow
->GetDefaultBorderSize(); 
 250         if (sashWindow
->GetSashVisible(wxSASH_BOTTOM
)) 
 251             bottomMargin 
+= sashWindow
->GetDefaultBorderSize(); 
 256     parent
->GetClientSize(& cw
, & ch
); 
 258     wxRect 
rect(leftMargin
, topMargin
, cw 
- leftMargin 
- rightMargin
, ch 
- topMargin 
- bottomMargin
); 
 260     wxCalculateLayoutEvent event
; 
 263     // Find the last layout-aware window, so we can make it fill all remaining 
 265     wxWindow 
*lastAwareWindow 
= NULL
; 
 266     wxWindowList::compatibility_iterator node 
= parent
->GetChildren().GetFirst(); 
 270         wxWindow
* win 
= node
->GetData(); 
 274             wxCalculateLayoutEvent 
tempEvent(win
->GetId()); 
 275             tempEvent
.SetEventObject(win
); 
 276             tempEvent
.SetFlags(wxLAYOUT_QUERY
); 
 277             tempEvent
.SetRect(event
.GetRect()); 
 278             if (win
->GetEventHandler()->ProcessEvent(tempEvent
)) 
 279                 lastAwareWindow 
= win
; 
 282         node 
= node
->GetNext(); 
 285     // Now do a dummy run to see if we have any space left for the final window (fail if not) 
 286     node 
= parent
->GetChildren().GetFirst(); 
 289         wxWindow
* win 
= node
->GetData(); 
 291         // If mainWindow is NULL and we're at the last window, 
 292         // skip this, because we'll simply make it fit the remaining space. 
 293         if (win
->IsShown() && (win 
!= mainWindow
) && (mainWindow 
!= NULL 
|| win 
!= lastAwareWindow
)) 
 295             event
.SetId(win
->GetId()); 
 296             event
.SetEventObject(win
); 
 297             event
.SetFlags(wxLAYOUT_QUERY
); 
 299             win
->GetEventHandler()->ProcessEvent(event
); 
 302         node 
= node
->GetNext(); 
 305     if (event
.GetRect().GetWidth() < 0 || event
.GetRect().GetHeight() < 0) 
 310     node 
= parent
->GetChildren().GetFirst(); 
 313         wxWindow
* win 
= node
->GetData(); 
 315         // If mainWindow is NULL and we're at the last window, 
 316         // skip this, because we'll simply make it fit the remaining space. 
 317         if (win
->IsShown() && (win 
!= mainWindow
) && (mainWindow 
!= NULL 
|| win 
!= lastAwareWindow
)) 
 319             event
.SetId(win
->GetId()); 
 320             event
.SetEventObject(win
); 
 321             event
.SetFlags(0); // ?? 
 323             win
->GetEventHandler()->ProcessEvent(event
); 
 326         node 
= node
->GetNext(); 
 329     rect 
= event
.GetRect(); 
 332         mainWindow
->SetSize(rect
.x
, rect
.y
, wxMax(0, rect
.width
), wxMax(0, rect
.height
)); 
 333     else if (lastAwareWindow
) 
 335         // Fit the remaining space 
 336         lastAwareWindow
->SetSize(rect
.x
, rect
.y
, wxMax(0, rect
.width
), wxMax(0, rect
.height
));