home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2240.zip / wxWindows-2.4.0 / src / generic / laywin.cpp < prev    next >
C/C++ Source or Header  |  2001-07-05  |  11KB  |  342 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name:        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
  8. // Modified by:
  9. // Created:     04/01/98
  10. // RCS-ID:      $Id: laywin.cpp,v 1.16 2001/07/05 18:48:48 VZ Exp $
  11. // Copyright:   (c) Julian Smart
  12. // Licence:     wxWindows licence
  13. /////////////////////////////////////////////////////////////////////////////
  14.  
  15. #ifdef __GNUG__
  16. #pragma implementation "laywin.h"
  17. #endif
  18.  
  19. // For compilers that support precompilation, includes "wx/wx.h".
  20. #include "wx/wxprec.h"
  21.  
  22. #ifdef __BORLANDC__
  23. #pragma hdrstop
  24. #endif
  25.  
  26. #ifndef WX_PRECOMP
  27.     #include "wx/frame.h"
  28.     #include "wx/mdi.h"
  29. #endif
  30.  
  31. #include "wx/laywin.h"
  32.  
  33. IMPLEMENT_DYNAMIC_CLASS(wxQueryLayoutInfoEvent, wxEvent)
  34. IMPLEMENT_DYNAMIC_CLASS(wxCalculateLayoutEvent, wxEvent)
  35.  
  36. DEFINE_EVENT_TYPE(wxEVT_QUERY_LAYOUT_INFO)
  37. DEFINE_EVENT_TYPE(wxEVT_CALCULATE_LAYOUT)
  38.  
  39. #if wxUSE_SASH
  40. IMPLEMENT_CLASS(wxSashLayoutWindow, wxSashWindow)
  41.  
  42. BEGIN_EVENT_TABLE(wxSashLayoutWindow, wxSashWindow)
  43.     EVT_CALCULATE_LAYOUT(wxSashLayoutWindow::OnCalculateLayout)
  44.     EVT_QUERY_LAYOUT_INFO(wxSashLayoutWindow::OnQueryLayoutInfo)
  45. END_EVENT_TABLE()
  46.  
  47. bool wxSashLayoutWindow::Create(wxWindow *parent, wxWindowID id, const wxPoint& pos,
  48.         const wxSize& size, long style, const wxString& name)
  49. {
  50.     return wxSashWindow::Create(parent, id, pos, size, style, name);
  51. }
  52.  
  53. void wxSashLayoutWindow::Init()
  54. {
  55.     m_orientation = wxLAYOUT_HORIZONTAL;
  56.     m_alignment = wxLAYOUT_TOP;
  57. }
  58.  
  59. // This is the function that wxLayoutAlgorithm calls to ascertain the window
  60. // dimensions.
  61. void wxSashLayoutWindow::OnQueryLayoutInfo(wxQueryLayoutInfoEvent& event)
  62. {
  63.   //    int flags = event.GetFlags();
  64.     int requestedLength = event.GetRequestedLength();
  65.  
  66.     event.SetOrientation(m_orientation);
  67.     event.SetAlignment(m_alignment);
  68.  
  69.     if (m_orientation == wxLAYOUT_HORIZONTAL)
  70.         event.SetSize(wxSize(requestedLength, m_defaultSize.y));
  71.     else
  72.         event.SetSize(wxSize(m_defaultSize.x, requestedLength));
  73. }
  74.  
  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.
  77.  
  78. void wxSashLayoutWindow::OnCalculateLayout(wxCalculateLayoutEvent& event)
  79. {
  80.     wxRect clientSize(event.GetRect());
  81.  
  82.     int flags = event.GetFlags();
  83.  
  84.     if (!IsShown())
  85.         return;
  86.  
  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).
  93.  
  94.     wxRect thisRect;
  95.  
  96.     // Try to stretch
  97.     int length = (GetOrientation() == wxLAYOUT_HORIZONTAL) ? clientSize.width : clientSize.height;
  98.     wxLayoutOrientation orient = GetOrientation();
  99.  
  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;
  104.  
  105.     wxQueryLayoutInfoEvent infoEvent(GetId());
  106.     infoEvent.SetEventObject(this);
  107.     infoEvent.SetRequestedLength(length);
  108.     infoEvent.SetFlags(orient | whichDimension);
  109.  
  110.     if (!GetEventHandler()->ProcessEvent(infoEvent))
  111.         return;
  112.  
  113.     wxSize sz = infoEvent.GetSize();
  114.  
  115.     if (sz.x == 0 && sz.y == 0) // Assume it's invisible
  116.         return;
  117.  
  118.     // Now we know the size it wants to be. We wish to decide where to place it, i.e.
  119.     // how it's aligned.
  120.     switch (GetAlignment())
  121.     {
  122.         case wxLAYOUT_TOP:
  123.         {
  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;
  128.             break;
  129.         }
  130.         case wxLAYOUT_LEFT:
  131.         {
  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;
  136.             break;
  137.         }
  138.         case wxLAYOUT_RIGHT:
  139.         {
  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;
  143.             break;
  144.         }
  145.         case wxLAYOUT_BOTTOM:
  146.         {
  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;
  150.             break;
  151.         }
  152.         case wxLAYOUT_NONE:
  153.         {
  154.             break;
  155.         }
  156.  
  157.     }
  158.  
  159.     if ((flags & wxLAYOUT_QUERY) == 0)
  160.     {
  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);
  166.  
  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)))
  170.             Refresh(TRUE);
  171.  
  172.     }
  173.  
  174.     event.SetRect(clientSize);
  175. }
  176. #endif // wxUSE_SASH
  177.  
  178. /*
  179.  * wxLayoutAlgorithm
  180.  */
  181.  
  182. #if wxUSE_MDI_ARCHITECTURE
  183.  
  184. // Lays out windows for an MDI frame. The MDI client area gets what's left
  185. // over.
  186. bool wxLayoutAlgorithm::LayoutMDIFrame(wxMDIParentFrame* frame, wxRect* r)
  187. {
  188.     int cw, ch;
  189.     frame->GetClientSize(& cw, & ch);
  190.  
  191.     wxRect rect(0, 0, cw, ch);
  192.     if (r)
  193.         rect = * r;
  194.  
  195.     wxCalculateLayoutEvent event;
  196.     event.SetRect(rect);
  197.  
  198.     wxNode* node = frame->GetChildren().First();
  199.     while (node)
  200.     {
  201.         wxWindow* win = (wxWindow*) node->Data();
  202.  
  203.         event.SetId(win->GetId());
  204.         event.SetEventObject(win);
  205.         event.SetFlags(0); // ??
  206.  
  207.         win->GetEventHandler()->ProcessEvent(event);
  208.  
  209.         node = node->Next();
  210.     }
  211.  
  212.     wxWindow* clientWindow = frame->GetClientWindow();
  213.  
  214.     rect = event.GetRect();
  215.  
  216.     clientWindow->SetSize(rect.x, rect.y, rect.width, rect.height);
  217.  
  218.     return TRUE;
  219. }
  220.  
  221. #endif // wxUSE_MDI_ARCHITECTURE
  222.  
  223. bool wxLayoutAlgorithm::LayoutFrame(wxFrame* frame, wxWindow* mainWindow)
  224. {
  225.     return LayoutWindow(frame, mainWindow);
  226. }
  227.  
  228. // Layout algorithm for any window. mainWindow gets what's left over.
  229. bool wxLayoutAlgorithm::LayoutWindow(wxWindow* parent, wxWindow* mainWindow)
  230. {
  231.     // Test if the parent is a sash window, and if so,
  232.     // reduce the available space to allow space for any active edges.
  233.  
  234.     int leftMargin = 0, rightMargin = 0, topMargin = 0, bottomMargin = 0;
  235. #if wxUSE_SASH
  236.     if (parent->IsKindOf(CLASSINFO(wxSashWindow)))
  237.     {
  238.         wxSashWindow* sashWindow = (wxSashWindow*) parent;
  239.  
  240.         leftMargin = sashWindow->GetExtraBorderSize();
  241.         rightMargin = sashWindow->GetExtraBorderSize();
  242.         topMargin = sashWindow->GetExtraBorderSize();
  243.         bottomMargin = sashWindow->GetExtraBorderSize();
  244.  
  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();
  253.     }
  254. #endif // wxUSE_SASH
  255.  
  256.     int cw, ch;
  257.     parent->GetClientSize(& cw, & ch);
  258.  
  259.     wxRect rect(leftMargin, topMargin, cw - leftMargin - rightMargin, ch - topMargin - bottomMargin);
  260.  
  261.     wxCalculateLayoutEvent event;
  262.     event.SetRect(rect);
  263.  
  264.     // Find the last layout-aware window, so we can make it fill all remaining
  265.     // space.
  266.     wxWindow* lastAwareWindow = NULL;
  267.     wxNode* node = parent->GetChildren().First();
  268.     while (node)
  269.     {
  270.         wxWindow* win = (wxWindow*) node->Data();
  271.  
  272.         if (win->IsShown())
  273.         {
  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;
  280.         }
  281.  
  282.         node = node->Next();
  283.     }
  284.  
  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().First();
  287.     while (node)
  288.     {
  289.         wxWindow* win = (wxWindow*) node->Data();
  290.  
  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))
  294.         {
  295.             event.SetId(win->GetId());
  296.             event.SetEventObject(win);
  297.             event.SetFlags(wxLAYOUT_QUERY);
  298.  
  299.             win->GetEventHandler()->ProcessEvent(event);
  300.         }
  301.  
  302.         node = node->Next();
  303.     }
  304.  
  305.     if (event.GetRect().GetWidth() < 0 || event.GetRect().GetHeight() < 0)
  306.         return FALSE;
  307.  
  308.     event.SetRect(rect);
  309.  
  310.     node = parent->GetChildren().First();
  311.     while (node)
  312.     {
  313.         wxWindow* win = (wxWindow*) node->Data();
  314.  
  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))
  318.         {
  319.             event.SetId(win->GetId());
  320.             event.SetEventObject(win);
  321.             event.SetFlags(0); // ??
  322.  
  323.             win->GetEventHandler()->ProcessEvent(event);
  324.         }
  325.  
  326.         node = node->Next();
  327.     }
  328.  
  329.     rect = event.GetRect();
  330.  
  331.     if (mainWindow)
  332.         mainWindow->SetSize(rect.x, rect.y, wxMax(0, rect.width), wxMax(0, rect.height));
  333.     else if (lastAwareWindow)
  334.     {
  335.         // Fit the remaining space
  336.         lastAwareWindow->SetSize(rect.x, rect.y, wxMax(0, rect.width), wxMax(0, rect.height));
  337.     }
  338.  
  339.     return TRUE;
  340. }
  341.  
  342.