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 ///////////////////////////////////////////////////////////////////////////// 
  16 #pragma implementation "laywin.h" 
  19 // For compilers that support precompilation, includes "wx/wx.h". 
  20 #include "wx/wxprec.h" 
  31 #include "wx/laywin.h" 
  33 IMPLEMENT_DYNAMIC_CLASS(wxQueryLayoutInfoEvent
, wxEvent
) 
  34 IMPLEMENT_DYNAMIC_CLASS(wxCalculateLayoutEvent
, wxEvent
) 
  36 DEFINE_EVENT_TYPE(wxEVT_QUERY_LAYOUT_INFO
) 
  37 DEFINE_EVENT_TYPE(wxEVT_CALCULATE_LAYOUT
) 
  40 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
; 
  59 // This is the function that wxLayoutAlgorithm calls to ascertain the window 
  61 void wxSashLayoutWindow::OnQueryLayoutInfo(wxQueryLayoutInfoEvent
& event
) 
  63   //    int flags = event.GetFlags(); 
  64     int requestedLength 
= event
.GetRequestedLength(); 
  66     event
.SetOrientation(m_orientation
); 
  67     event
.SetAlignment(m_alignment
); 
  69     if (m_orientation 
== wxLAYOUT_HORIZONTAL
) 
  70         event
.SetSize(wxSize(requestedLength
, m_defaultSize
.y
)); 
  72         event
.SetSize(wxSize(m_defaultSize
.x
, requestedLength
)); 
  75 // Called by parent to allow window to take a bit out of the 
  76 // client rectangle, and size itself if not in wxLAYOUT_QUERY mode. 
  78 void wxSashLayoutWindow::OnCalculateLayout(wxCalculateLayoutEvent
& event
) 
  80     wxRect 
clientSize(event
.GetRect()); 
  82     int flags 
= event
.GetFlags(); 
  87     // Let's assume that all windows stretch the full extent of the window in 
  88     // the direction of that window orientation. This will work for non-docking toolbars, 
  89     // and the status bar. Note that the windows have to have been created in a certain 
  90     // order to work, else you might get a left-aligned window going to the bottom 
  91     // of the window, and the status bar appearing to the right of it. The 
  92     // status bar would have to be created after or before the toolbar(s). 
  97     int length 
= (GetOrientation() == wxLAYOUT_HORIZONTAL
) ? clientSize
.width 
: clientSize
.height
; 
  98     wxLayoutOrientation orient 
= GetOrientation(); 
 100     // We assume that a window that says it's horizontal, wants to be stretched in that 
 101     // direction. Is this distinction too fine? Do we assume that any horizontal 
 102     // window needs to be stretched in that direction? Possibly. 
 103     int whichDimension 
= (GetOrientation() == wxLAYOUT_HORIZONTAL
) ? wxLAYOUT_LENGTH_X 
: wxLAYOUT_LENGTH_Y
; 
 105     wxQueryLayoutInfoEvent 
infoEvent(GetId()); 
 106     infoEvent
.SetEventObject(this); 
 107     infoEvent
.SetRequestedLength(length
); 
 108     infoEvent
.SetFlags(orient 
| whichDimension
); 
 110     if (!GetEventHandler()->ProcessEvent(infoEvent
)) 
 113     wxSize sz 
= infoEvent
.GetSize(); 
 115     if (sz
.x 
== 0 && sz
.y 
== 0) // Assume it's invisible 
 118     // Now we know the size it wants to be. We wish to decide where to place it, i.e. 
 120     switch (GetAlignment()) 
 124             thisRect
.x 
= clientSize
.x
; thisRect
.y 
= clientSize
.y
; 
 125             thisRect
.width 
= sz
.x
; thisRect
.height 
= sz
.y
; 
 126             clientSize
.y 
+= thisRect
.height
; 
 127             clientSize
.height 
-= thisRect
.height
; 
 132             thisRect
.x 
= clientSize
.x
; thisRect
.y 
= clientSize
.y
; 
 133             thisRect
.width 
= sz
.x
; thisRect
.height 
= sz
.y
; 
 134             clientSize
.x 
+= thisRect
.width
; 
 135             clientSize
.width 
-= thisRect
.width
; 
 140             thisRect
.x 
= clientSize
.x 
+ (clientSize
.width 
- sz
.x
); thisRect
.y 
= clientSize
.y
; 
 141             thisRect
.width 
= sz
.x
; thisRect
.height 
= sz
.y
; 
 142             clientSize
.width 
-= thisRect
.width
; 
 145         case wxLAYOUT_BOTTOM
: 
 147             thisRect
.x 
= clientSize
.x
; thisRect
.y 
= clientSize
.y 
+ (clientSize
.height 
- sz
.y
); 
 148             thisRect
.width 
= sz
.x
; thisRect
.height 
= sz
.y
; 
 149             clientSize
.height 
-= thisRect
.height
; 
 159     if ((flags 
& wxLAYOUT_QUERY
) == 0) 
 161         // If not in query mode, resize the window. 
 162         // TODO: add wxRect& form to wxWindow::SetSize 
 163         wxSize sz 
= GetSize(); 
 164         wxPoint pos 
= GetPosition(); 
 165         SetSize(thisRect
.x
, thisRect
.y
, thisRect
.width
, thisRect
.height
); 
 167         // Make sure the sash is erased when the window is resized 
 168         if ((pos
.x 
!= thisRect
.x 
|| pos
.y 
!= thisRect
.y 
|| sz
.x 
!= thisRect
.width 
|| sz
.y 
!= thisRect
.height
) && 
 169             (GetSashVisible(wxSASH_TOP
) || GetSashVisible(wxSASH_RIGHT
) || GetSashVisible(wxSASH_BOTTOM
) || GetSashVisible(wxSASH_LEFT
))) 
 174     event
.SetRect(clientSize
); 
 182 #if wxUSE_MDI_ARCHITECTURE 
 184 // Lays out windows for an MDI frame. The MDI client area gets what's left 
 186 bool wxLayoutAlgorithm::LayoutMDIFrame(wxMDIParentFrame
* frame
, wxRect
* r
) 
 189     frame
->GetClientSize(& cw
, & ch
); 
 191     wxRect 
rect(0, 0, cw
, ch
); 
 195     wxCalculateLayoutEvent event
; 
 198     wxWindowList::Node  
*node 
= frame
->GetChildren().GetFirst(); 
 201         wxWindow
* win 
= node
->GetData(); 
 203         event
.SetId(win
->GetId()); 
 204         event
.SetEventObject(win
); 
 205         event
.SetFlags(0); // ?? 
 207         win
->GetEventHandler()->ProcessEvent(event
); 
 209         node 
= node
->GetNext(); 
 212     wxWindow
* clientWindow 
= frame
->GetClientWindow(); 
 214     rect 
= event
.GetRect(); 
 216     clientWindow
->SetSize(rect
.x
, rect
.y
, rect
.width
, rect
.height
); 
 221 #endif // wxUSE_MDI_ARCHITECTURE 
 223 bool wxLayoutAlgorithm::LayoutFrame(wxFrame
* frame
, wxWindow
* mainWindow
) 
 225     return LayoutWindow(frame
, mainWindow
); 
 228 // Layout algorithm for any window. mainWindow gets what's left over. 
 229 bool wxLayoutAlgorithm::LayoutWindow(wxWindow
* parent
, wxWindow
* mainWindow
) 
 231     // Test if the parent is a sash window, and if so, 
 232     // reduce the available space to allow space for any active edges. 
 234     int leftMargin 
= 0, rightMargin 
= 0, topMargin 
= 0, bottomMargin 
= 0; 
 236     if (parent
->IsKindOf(CLASSINFO(wxSashWindow
))) 
 238         wxSashWindow
* sashWindow 
= (wxSashWindow
*) parent
; 
 240         leftMargin 
= sashWindow
->GetExtraBorderSize(); 
 241         rightMargin 
= sashWindow
->GetExtraBorderSize(); 
 242         topMargin 
= sashWindow
->GetExtraBorderSize(); 
 243         bottomMargin 
= sashWindow
->GetExtraBorderSize(); 
 245         if (sashWindow
->GetSashVisible(wxSASH_LEFT
)) 
 246             leftMargin 
+= sashWindow
->GetDefaultBorderSize(); 
 247         if (sashWindow
->GetSashVisible(wxSASH_RIGHT
)) 
 248             rightMargin 
+= sashWindow
->GetDefaultBorderSize(); 
 249         if (sashWindow
->GetSashVisible(wxSASH_TOP
)) 
 250             topMargin 
+= sashWindow
->GetDefaultBorderSize(); 
 251         if (sashWindow
->GetSashVisible(wxSASH_BOTTOM
)) 
 252             bottomMargin 
+= sashWindow
->GetDefaultBorderSize(); 
 257     parent
->GetClientSize(& cw
, & ch
); 
 259     wxRect 
rect(leftMargin
, topMargin
, cw 
- leftMargin 
- rightMargin
, ch 
- topMargin 
- bottomMargin
); 
 261     wxCalculateLayoutEvent event
; 
 264     // Find the last layout-aware window, so we can make it fill all remaining 
 266     wxWindow            
*lastAwareWindow 
= NULL
; 
 267     wxWindowList::Node  
*node 
= parent
->GetChildren().GetFirst(); 
 271         wxWindow
* win 
= node
->GetData(); 
 275             wxCalculateLayoutEvent 
tempEvent(win
->GetId()); 
 276             tempEvent
.SetEventObject(win
); 
 277             tempEvent
.SetFlags(wxLAYOUT_QUERY
); 
 278             tempEvent
.SetRect(event
.GetRect()); 
 279             if (win
->GetEventHandler()->ProcessEvent(tempEvent
)) 
 280                 lastAwareWindow 
= win
; 
 283         node 
= node
->GetNext(); 
 286     // Now do a dummy run to see if we have any space left for the final window (fail if not) 
 287     node 
= parent
->GetChildren().GetFirst(); 
 290         wxWindow
* win 
= node
->GetData(); 
 292         // If mainWindow is NULL and we're at the last window, 
 293         // skip this, because we'll simply make it fit the remaining space. 
 294         if (win
->IsShown() && (win 
!= mainWindow
) && (mainWindow 
!= NULL 
|| win 
!= lastAwareWindow
)) 
 296             event
.SetId(win
->GetId()); 
 297             event
.SetEventObject(win
); 
 298             event
.SetFlags(wxLAYOUT_QUERY
); 
 300             win
->GetEventHandler()->ProcessEvent(event
); 
 303         node 
= node
->GetNext(); 
 306     if (event
.GetRect().GetWidth() < 0 || event
.GetRect().GetHeight() < 0) 
 311     node 
= parent
->GetChildren().GetFirst(); 
 314         wxWindow
* win 
= node
->GetData(); 
 316         // If mainWindow is NULL and we're at the last window, 
 317         // skip this, because we'll simply make it fit the remaining space. 
 318         if (win
->IsShown() && (win 
!= mainWindow
) && (mainWindow 
!= NULL 
|| win 
!= lastAwareWindow
)) 
 320             event
.SetId(win
->GetId()); 
 321             event
.SetEventObject(win
); 
 322             event
.SetFlags(0); // ?? 
 324             win
->GetEventHandler()->ProcessEvent(event
); 
 327         node 
= node
->GetNext(); 
 330     rect 
= event
.GetRect(); 
 333         mainWindow
->SetSize(rect
.x
, rect
.y
, wxMax(0, rect
.width
), wxMax(0, rect
.height
)); 
 334     else if (lastAwareWindow
) 
 336         // Fit the remaining space 
 337         lastAwareWindow
->SetSize(rect
.x
, rect
.y
, wxMax(0, rect
.width
), wxMax(0, rect
.height
));