]> git.saurik.com Git - wxWidgets.git/commitdiff
Added wxSashWindow, wxSashLayoutWindow, wxLayoutAlgorithm classes and sample
authorJulian Smart <julian@anthemion.co.uk>
Mon, 7 Sep 1998 09:27:34 +0000 (09:27 +0000)
committerJulian Smart <julian@anthemion.co.uk>
Mon, 7 Sep 1998 09:27:34 +0000 (09:27 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@702 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

12 files changed:
include/wx/generic/laywin.h [new file with mode: 0644]
include/wx/generic/sashwin.h [new file with mode: 0644]
include/wx/laywin.h [new file with mode: 0644]
include/wx/sashwin.h [new file with mode: 0644]
samples/sashtest/makefile.nt [new file with mode: 0644]
samples/sashtest/sashtest.cpp [new file with mode: 0644]
samples/sashtest/sashtest.h [new file with mode: 0644]
samples/sashtest/sashtest.ico [new file with mode: 0644]
samples/sashtest/sashtest.rc [new file with mode: 0644]
src/generic/laywin.cpp [new file with mode: 0644]
src/generic/sashwin.cpp [new file with mode: 0644]
src/msw/makefile.nt

diff --git a/include/wx/generic/laywin.h b/include/wx/generic/laywin.h
new file mode 100644 (file)
index 0000000..fcfc87a
--- /dev/null
@@ -0,0 +1,179 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        laywin.h
+// Purpose:     Implements a simple layout algorithm, plus
+//              wxSashLayoutWindow which is an example of a window with
+//              layout-awareness (via event handlers). This is suited to
+//              IDE-style window layout.
+// Author:      Julian Smart
+// Modified by:
+// Created:     04/01/98
+// RCS-ID:      $Id$
+// Copyright:   (c) Julian Smart
+// Licence:    wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+#ifndef _WX_LAYWIN_H_G_
+#define _WX_LAYWIN_H_G_
+
+#ifdef __GNUG__
+#pragma interface "laywin.h"
+#endif
+
+#include "wx/sashwin.h"
+
+const wxEventType wxEVT_QUERY_LAYOUT_INFO =     wxEVT_FIRST + 1500;
+const wxEventType wxEVT_CALCULATE_LAYOUT =      wxEVT_FIRST + 1501;
+
+enum wxLayoutOrientation {
+    wxLAYOUT_HORIZONTAL,
+    wxLAYOUT_VERTICAL
+};
+
+enum wxLayoutAlignment {
+    wxLAYOUT_NONE,
+    wxLAYOUT_TOP,
+    wxLAYOUT_LEFT,
+    wxLAYOUT_RIGHT,
+    wxLAYOUT_BOTTOM,
+};
+
+// Not sure this is necessary
+// Tell window which dimension we're sizing on
+#define wxLAYOUT_LENGTH_Y       0x0008
+#define wxLAYOUT_LENGTH_X       0x0000
+
+// Use most recently used length
+#define wxLAYOUT_MRU_LENGTH     0x0010
+
+// Only a query, so don't actually move it.
+#define wxLAYOUT_QUERY          0x0100
+
+/*
+ * This event is used to get information about window alignment,
+ * orientation and size.
+ */
+
+class wxQueryLayoutInfoEvent: public wxEvent
+{
+DECLARE_DYNAMIC_CLASS(wxQueryLayoutInfoEvent)
+public:
+
+    wxQueryLayoutInfoEvent(wxWindowID id = 0)
+    {
+        SetEventType(wxEVT_QUERY_LAYOUT_INFO);
+        m_requestedLength = 0;
+        m_flags = 0;
+        m_alignment = wxLAYOUT_TOP;
+        m_orientation = wxLAYOUT_HORIZONTAL;
+    }
+// Read by the app
+    inline void SetRequestedLength(int length) { m_requestedLength = length; }
+    inline int GetRequestedLength() const { return m_requestedLength; }
+
+    inline void SetFlags(int flags) { m_flags = flags; }
+    inline int GetFlags() const { return m_flags; }
+
+// Set by the app
+    inline void SetSize(const wxSize& size) { m_size = size; }
+    inline wxSize GetSize() const { return m_size; }
+
+    inline void SetOrientation(wxLayoutOrientation orient) { m_orientation = orient; }
+    inline wxLayoutOrientation GetOrientation() const { return m_orientation; }
+
+    inline void SetAlignment(wxLayoutAlignment align) { m_alignment = align; }
+    inline wxLayoutAlignment GetAlignment() const { return m_alignment; }
+protected:
+    int                     m_flags;
+    int                     m_requestedLength;
+    wxSize                  m_size;
+    wxLayoutOrientation     m_orientation;
+    wxLayoutAlignment       m_alignment;
+
+};
+
+typedef void (wxEvtHandler::*wxQueryLayoutInfoEventFunction)(wxQueryLayoutInfoEvent&);
+
+#define EVT_QUERY_LAYOUT_INFO(func)  { wxEVT_QUERY_LAYOUT_INFO, -1, -1, (wxObjectEventFunction) (wxEventFunction) (wxQueryLayoutInfoEventFunction) & func, NULL },
+
+/*
+ * This event is used to take a bite out of the available client area.
+ */
+
+class wxCalculateLayoutEvent: public wxEvent
+{
+DECLARE_DYNAMIC_CLASS(wxCalculateLayoutEvent)
+public:
+    wxCalculateLayoutEvent(wxWindowID id = 0)
+    {
+        SetEventType(wxEVT_CALCULATE_LAYOUT);
+        m_flags = 0;
+    }
+// Read by the app
+    inline void SetFlags(int flags) { m_flags = flags; }
+    inline int GetFlags() const { return m_flags; }
+
+// Set by the app
+    inline void SetRect(const wxRect& rect) { m_rect = rect; }
+    inline wxRect GetRect() const { return m_rect; }
+protected:
+    int                     m_flags;
+    wxRect                  m_rect;
+};
+
+typedef void (wxEvtHandler::*wxCalculateLayoutEventFunction)(wxCalculateLayoutEvent&);
+
+#define EVT_CALCULATE_LAYOUT(func)  { wxEVT_CALCULATE_LAYOUT, -1, -1, (wxObjectEventFunction) (wxEventFunction) (wxCalculateLayoutEventFunction) & func, NULL },
+
+// This is window that can remember alignment/orientation, does its own layout,
+// and can provide sashes too. Useful for implementing docked windows with sashes in
+// an IDE-style interface.
+class wxSashLayoutWindow: public wxSashWindow
+{
+    DECLARE_CLASS(wxSashLayoutWindow)
+public:
+    wxSashLayoutWindow(wxWindow *parent, wxWindowID id = -1, const wxPoint& pos = wxDefaultPosition,
+        const wxSize& size = wxDefaultSize, long style = wxSW_3D|wxCLIP_CHILDREN, const wxString& name = "layoutWindow");
+
+// Accessors
+    inline wxLayoutAlignment GetAlignment() const { return m_alignment; };
+    inline wxLayoutOrientation GetOrientation() const { return m_orientation; };
+
+    inline void SetAlignment(wxLayoutAlignment align) { m_alignment = align; };
+    inline void SetOrientation(wxLayoutOrientation orient) { m_orientation = orient; };
+
+    // Give the window default dimensions
+    inline void SetDefaultSize(const wxSize& size) { m_defaultSize = size; }
+
+// Event handlers
+    // Called by layout algorithm to allow window to take a bit out of the
+    // client rectangle, and size itself if not in wxLAYOUT_QUERY mode.
+    void OnCalculateLayout(wxCalculateLayoutEvent& event);
+
+    // Called by layout algorithm to retrieve information about the window.
+    void OnQueryLayoutInfo(wxQueryLayoutInfoEvent& event);
+protected:
+    wxLayoutAlignment           m_alignment;
+    wxLayoutOrientation         m_orientation;
+    wxSize                      m_defaultSize;
+
+DECLARE_EVENT_TABLE()
+};
+
+class WXDLLEXPORT wxMDIParentFrame;
+class WXDLLEXPORT wxFrame;
+
+// This class implements the layout algorithm
+class wxLayoutAlgorithm: public wxObject
+{
+public:
+    wxLayoutAlgorithm() {}
+
+    // The MDI client window is sized to whatever's left over.
+    bool LayoutMDIFrame(wxMDIParentFrame* frame);
+
+    // mainWindow is sized to whatever's left over.
+    bool LayoutFrame(wxFrame* frame, wxWindow* mainWindow);
+};
+
+#endif
+    // _WX_LAYWIN_H_G_
diff --git a/include/wx/generic/sashwin.h b/include/wx/generic/sashwin.h
new file mode 100644 (file)
index 0000000..c102392
--- /dev/null
@@ -0,0 +1,214 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        sashwin.h
+// Purpose:     wxSashWindow implementation. A sash window has an optional
+//              sash on each edge, allowing it to be dragged. An event
+//              is generated when the sash is released.
+// Author:      Julian Smart
+// Modified by:
+// Created:     01/02/97
+// RCS-ID:      $Id$
+// Copyright:   (c) Julian Smart
+// Licence:    wxWindows license
+/////////////////////////////////////////////////////////////////////////////
+
+#ifndef _WX_SASHWIN_H_G_
+#define _WX_SASHWIN_H_G_
+
+#ifdef __GNUG__
+#pragma interface "sashwin.h"
+#endif
+
+#include "wx/defs.h"
+#include "wx/window.h"
+#include "wx/string.h"
+
+#define wxSASH_DRAG_NONE       0
+#define wxSASH_DRAG_DRAGGING   1
+#define wxSASH_DRAG_LEFT_DOWN  2
+
+enum wxSashEdgePosition {
+    wxSASH_TOP = 0,
+    wxSASH_RIGHT,
+    wxSASH_BOTTOM,
+    wxSASH_LEFT,
+    wxSASH_NONE = 100
+};
+
+/*
+ * wxSashEdge represents one of the four edges of a window.
+ */
+
+class WXDLLEXPORT wxSashEdge
+{
+public:
+    wxSashEdge() { m_show = FALSE; m_border = FALSE; m_margin = 0; }
+
+    bool    m_show;     // Is the sash showing?
+    bool    m_border;   // Do we draw a border?
+    int     m_margin;   // The margin size
+};
+
+/*
+ * wxSashWindow flags
+ */
+
+#define wxSW_3D             0x0004
+
+/*
+ * wxSashWindow allows any of its edges to have a sash which can be dragged
+ * to resize the window. The actual content window will be created as a child
+ * of wxSashWindow.
+ */
+
+class WXDLLEXPORT wxSashWindow: public wxWindow
+{
+  DECLARE_DYNAMIC_CLASS(wxSashWindow)
+
+public:
+
+////////////////////////////////////////////////////////////////////////////
+// Public API
+
+    // Default constructor
+    wxSashWindow();
+
+    // Normal constructor
+    wxSashWindow(wxWindow *parent, wxWindowID id = -1, const wxPoint& pos = wxDefaultPosition,
+        const wxSize& size = wxDefaultSize, long style = wxSW_3D|wxCLIP_CHILDREN, const wxString& name = "splitter");
+    ~wxSashWindow();
+
+    // Set whether there's a sash in this position
+    void SetSashVisible(wxSashEdgePosition edge, bool sash);
+
+    // Get whether there's a sash in this position
+    inline bool GetSashVisible(wxSashEdgePosition edge) { return m_sashes[edge].m_show; }
+
+    // Set whether there's a border in this position
+    inline void SetSashBorder(wxSashEdgePosition edge, bool border) { m_sashes[edge].m_border = border; }
+
+    // Get whether there's a border in this position
+    inline bool HasBorder(wxSashEdgePosition edge) { return m_sashes[edge].m_border; }
+
+    // Get border size
+    inline int GetEdgeMargin(wxSashEdgePosition edge) { return m_sashes[edge].m_margin; }
+
+    // Sets the default sash border size
+    inline void SetDefaultBorderSize(int width) { m_borderSize = width; }
+
+    // Gets the default sash border size
+    inline int GetDefaultBorderSize() const { return m_borderSize; }
+
+    // Sets the addition border size between child and sash window
+    inline void SetExtraBorderSize(int width) { m_extraBorderSize = width; }
+
+    // Gets the addition border size between child and sash window
+    inline int GetExtraBorderSize() const { return m_extraBorderSize; }
+
+    virtual void SetMinimumSizeX(int min) { m_minimumPaneSizeX = min; }
+    virtual void SetMinimumSizeY(int min) { m_minimumPaneSizeY = min; }
+    virtual int GetMinimumSizeX() const { return m_minimumPaneSizeX; }
+    virtual int GetMinimumSizeY() const { return m_minimumPaneSizeY; }
+
+    virtual void SetMaximumSizeX(int max) { m_maximumPaneSizeX = max; }
+    virtual void SetMaximumSizeY(int max) { m_maximumPaneSizeY = max; }
+    virtual int GetMaximumSizeX() const { return m_maximumPaneSizeX; }
+    virtual int GetMaximumSizeY() const { return m_maximumPaneSizeY; }
+
+////////////////////////////////////////////////////////////////////////////
+// Implementation
+
+    // Paints the border and sash
+    void OnPaint(wxPaintEvent& event);
+
+    // Handles mouse events
+    void OnMouseEvent(wxMouseEvent& ev);
+
+    // Adjusts the panes
+    void OnSize(wxSizeEvent& event);
+
+    // Draws borders
+    void DrawBorders(wxDC& dc);
+
+    // Draws the sashes
+    void DrawSash(wxSashEdgePosition edge, wxDC& dc);
+
+    // Draws the sashes
+    void DrawSashes(wxDC& dc);
+
+    // Draws the sash tracker (for whilst moving the sash)
+    void DrawSashTracker(wxSashEdgePosition edge, int x, int y);
+
+    // Tests for x, y over sash
+    wxSashEdgePosition SashHitTest(int x, int y, int tolerance = 2);
+
+    // Resizes subwindows
+    void SizeWindows();
+
+    // Initialize colours
+    void InitColours();
+
+protected:
+    wxSashEdge  m_sashes[4];
+    int         m_dragMode;
+    wxSashEdgePosition m_draggingEdge;
+    int         m_oldX;
+    int         m_oldY;
+    int         m_borderSize;
+    int         m_extraBorderSize;
+    int         m_firstX;
+    int         m_firstY;
+    int         m_minimumPaneSizeX;
+    int         m_minimumPaneSizeY;
+    int         m_maximumPaneSizeX;
+    int         m_maximumPaneSizeY;
+    wxCursor*   m_sashCursorWE;
+    wxCursor*   m_sashCursorNS;
+    wxColour    m_lightShadowColour;
+    wxColour    m_mediumShadowColour;
+    wxColour    m_darkShadowColour;
+    wxColour    m_hilightColour;
+    wxColour    m_faceColour;
+
+DECLARE_EVENT_TABLE()
+};
+
+#define wxEVT_SASH_DRAGGED (wxEVT_FIRST + 1200)
+
+enum wxSashDragStatus
+{
+    wxSASH_STATUS_OK,
+    wxSASH_STATUS_OUT_OF_RANGE
+};
+
+class WXDLLEXPORT wxSashEvent: public wxCommandEvent
+{
+  DECLARE_DYNAMIC_CLASS(wxSashEvent)
+
+ public:
+    inline wxSashEvent(int id = 0, wxSashEdgePosition edge = wxSASH_NONE) {
+     m_eventType = (wxEventType) wxEVT_SASH_DRAGGED; m_id = id; m_edge = edge; }
+
+    inline void SetEdge(wxSashEdgePosition edge) { m_edge = edge; }
+    inline wxSashEdgePosition GetEdge() const { return m_edge; }
+
+    //// The rectangle formed by the drag operation
+    inline void SetDragRect(const wxRect& rect) { m_dragRect = rect; }
+    inline wxRect GetDragRect() const { return m_dragRect; }
+
+    //// Whether the drag caused the rectangle to be reversed (e.g.
+    //// dragging the top below the bottom)
+    inline void SetDragStatus(wxSashDragStatus status) { m_dragStatus = status; }
+    inline wxSashDragStatus GetDragStatus() const { return m_dragStatus; }
+ private:
+    wxSashEdgePosition  m_edge;
+    wxRect              m_dragRect;
+    wxSashDragStatus    m_dragStatus;
+};
+
+typedef void (wxEvtHandler::*wxSashEventFunction)(wxSashEvent&);
+
+#define EVT_SASH_DRAGGED(id, fn) { wxEVT_SASH_DRAGGED, id, -1, (wxObjectEventFunction) (wxEventFunction) (wxSashEventFunction) & fn, NULL },
+#define EVT_SASH_DRAGGED_RANGE(id1, id2, fn) { wxEVT_SASH_DRAGGED, id1, id2, (wxObjectEventFunction) (wxEventFunction) (wxSashEventFunction) & fn, NULL },
+
+#endif
+  // _WX_SASHWIN_H_G_
diff --git a/include/wx/laywin.h b/include/wx/laywin.h
new file mode 100644 (file)
index 0000000..f3ad272
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef _WX_LAYWIN_H_BASE_
+#define _WX_LAYWIN_H_BASE_
+
+#include "wx/generic/laywin.h"
+
+#endif
+    // _WX_LAYWIN_H_BASE_
diff --git a/include/wx/sashwin.h b/include/wx/sashwin.h
new file mode 100644 (file)
index 0000000..6b46b63
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef _WX_SASHWIN_H_BASE_
+#define _WX_SASHWIN_H_BASE_
+
+#include "wx/generic/sashwin.h"
+
+#endif
+    // _WX_SASHWIN_H_BASE_
diff --git a/samples/sashtest/makefile.nt b/samples/sashtest/makefile.nt
new file mode 100644 (file)
index 0000000..99fa33d
--- /dev/null
@@ -0,0 +1,51 @@
+#
+# File:                makefile.nt
+# Author:      Julian Smart
+# Created:     1993
+# Updated:     
+# Copyright:   (c) 1993, AIAI, University of Edinburgh
+#
+# "%W% %G%"
+#
+# Makefile : Builds sashtest example (MS VC++).
+# Use FINAL=1 argument to nmake to build final version with no debugging
+# info
+
+# Set WXDIR for your system
+WXDIR = $(WXWIN)
+WXUSINGDLL=0
+
+!include $(WXDIR)\src\ntwxwin.mak
+
+PROGRAM=sashtest
+PROGOBJECTS = $(PROGRAM).obj
+
+all:    $(PROGRAM)
+
+$(PROGRAM):    $(PROGRAM).exe
+
+$(PROGRAM).exe:      $(DUMMYOBJ) $(WXLIB) $(PROGOBJECTS) $(PROGRAM).res
+       $(link) @<<
+-out:$(PROGRAM).exe
+$(LINKFLAGS)
+$(DUMMYOBJ) $(PROGOBJECTS) $(PROGRAM).res
+$(LIBS)
+<<
+
+$(PROGRAM).obj:      $(PROGRAM).$(SRCSUFF) $(DUMMYOBJ)
+        $(cc) @<<
+$(CPPFLAGS) /c /Tp $*.$(SRCSUFF)
+<<
+
+$(PROGRAM).res :      $(PROGRAM).rc $(WXDIR)\include\wx\msw\wx.rc
+    $(rc) -r /i$(WXDIR)\include -fo$@ $(PROGRAM).rc
+
+
+clean:
+        -erase *.obj
+        -erase *.exe
+        -erase *.res
+        -erase *.map
+        -erase *.sbr
+        -erase *.pdb
+
diff --git a/samples/sashtest/sashtest.cpp b/samples/sashtest/sashtest.cpp
new file mode 100644 (file)
index 0000000..1542d08
--- /dev/null
@@ -0,0 +1,375 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        sashtest.cpp
+// Purpose:     Layout/sash sample
+// Author:      Julian Smart
+// Modified by:
+// Created:     04/01/98
+// RCS-ID:      $Id$
+// Copyright:   (c) Julian Smart and Markus Holzem
+// Licence:    wxWindows license
+/////////////////////////////////////////////////////////////////////////////
+
+// For compilers that support precompilation, includes "wx/wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+#ifndef WX_PRECOMP
+#include "wx/wx.h"
+#include "wx/mdi.h"
+#endif
+
+#include <wx/toolbar.h>
+#include <wx/laywin.h>
+
+#include "sashtest.h"
+
+MyFrame *frame = NULL;
+wxList my_children;
+
+IMPLEMENT_APP(MyApp)
+
+// For drawing lines in a canvas
+long xpos = -1;
+long ypos = -1;
+
+int winNumber = 1;
+
+// Initialise this in OnInit, not statically
+bool MyApp::OnInit(void)
+{
+  // Create the main frame window
+
+  frame = new MyFrame(NULL, -1, "Sash Demo", wxPoint(0, 0), wxSize(500, 400),
+   wxDEFAULT_FRAME | wxHSCROLL | wxVSCROLL);
+
+  // Give it an icon (this is ignored in MDI mode: uses resources)
+#ifdef __WXMSW__
+  frame->SetIcon(wxIcon("sashtest_icn"));
+#endif
+#ifdef __X__
+  frame->SetIcon(wxIcon("sashtest.xbm"));
+#endif
+
+  // Make a menubar
+  wxMenu *file_menu = new wxMenu;
+
+  file_menu->Append(SASHTEST_NEW_WINDOW, "&New window");
+  file_menu->Append(SASHTEST_TOGGLE_WINDOW, "&Toggle window");
+  file_menu->Append(SASHTEST_QUIT, "&Exit");
+
+  wxMenu *help_menu = new wxMenu;
+  help_menu->Append(SASHTEST_ABOUT, "&About");
+
+  wxMenuBar *menu_bar = new wxMenuBar;
+
+  menu_bar->Append(file_menu, "&File");
+  menu_bar->Append(help_menu, "&Help");
+
+  // Associate the menu bar with the frame
+  frame->SetMenuBar(menu_bar);
+
+  frame->CreateStatusBar();
+
+  frame->Show(TRUE);
+
+  SetTopWindow(frame);
+
+  return TRUE;
+}
+
+BEGIN_EVENT_TABLE(MyFrame, wxMDIParentFrame)
+    EVT_MENU(SASHTEST_ABOUT, MyFrame::OnAbout)
+    EVT_MENU(SASHTEST_NEW_WINDOW, MyFrame::OnNewWindow)
+    EVT_SIZE(MyFrame::OnSize)
+    EVT_MENU(SASHTEST_QUIT, MyFrame::OnQuit)
+    EVT_MENU(SASHTEST_TOGGLE_WINDOW, MyFrame::OnToggleWindow)
+    EVT_SASH_DRAGGED_RANGE(ID_WINDOW_TOP, ID_WINDOW_BOTTOM, MyFrame::OnSashDrag)
+END_EVENT_TABLE()
+
+
+// Define my frame constructor
+MyFrame::MyFrame(wxWindow *parent, const wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size,
+       const long style):
+  wxMDIParentFrame(parent, id, title, pos, size, style)
+{
+  // Create some dummy layout windows
+
+  // A window like a toolbar
+  wxSashLayoutWindow* win = new wxSashLayoutWindow(this, ID_WINDOW_TOP, wxDefaultPosition, wxSize(200, 30), wxNO_BORDER|wxSW_3D);
+  win->SetDefaultSize(wxSize(1000, 30));
+  win->SetOrientation(wxLAYOUT_HORIZONTAL);
+  win->SetAlignment(wxLAYOUT_TOP);
+  win->SetBackgroundColour(wxColour(255, 0, 0));
+  win->SetSashVisible(wxSASH_BOTTOM, TRUE);
+
+  m_topWindow = win;
+
+  // A window like a statusbar
+  win = new wxSashLayoutWindow(this, ID_WINDOW_BOTTOM, wxDefaultPosition, wxSize(200, 30), wxNO_BORDER|wxSW_3D);
+  win->SetDefaultSize(wxSize(1000, 30));
+  win->SetOrientation(wxLAYOUT_HORIZONTAL);
+  win->SetAlignment(wxLAYOUT_BOTTOM);
+  win->SetBackgroundColour(wxColour(0, 0, 255));
+  win->SetSashVisible(wxSASH_TOP, TRUE);
+
+  m_bottomWindow = win;
+
+  // A window to the left of the client window
+  win = new wxSashLayoutWindow(this, ID_WINDOW_LEFT1, wxDefaultPosition, wxSize(200, 30), wxNO_BORDER|wxSW_3D);
+  win->SetDefaultSize(wxSize(120, 1000));
+  win->SetOrientation(wxLAYOUT_VERTICAL);
+  win->SetAlignment(wxLAYOUT_LEFT);
+  win->SetBackgroundColour(wxColour(0, 255, 0));
+  win->SetSashVisible(wxSASH_RIGHT, TRUE);
+  win->SetExtraBorderSize(10);
+
+  wxTextCtrl* textWindow = new wxTextCtrl(win, -1, "", wxDefaultPosition, wxDefaultSize,
+        wxTE_MULTILINE|wxSUNKEN_BORDER);
+//        wxTE_MULTILINE|wxNO_BORDER);
+  textWindow->SetValue("A help window");
+
+  m_leftWindow1 = win;
+
+  // Another window to the left of the client window
+  win = new wxSashLayoutWindow(this, ID_WINDOW_LEFT2, wxDefaultPosition, wxSize(200, 30), wxNO_BORDER|wxSW_3D);
+  win->SetDefaultSize(wxSize(120, 1000));
+  win->SetOrientation(wxLAYOUT_VERTICAL);
+  win->SetAlignment(wxLAYOUT_LEFT);
+  win->SetBackgroundColour(wxColour(0, 255, 255));
+  win->SetSashVisible(wxSASH_RIGHT, TRUE);
+
+  m_leftWindow2 = win;
+}
+
+void MyFrame::OnQuit(wxCommandEvent& event)
+{
+      Close(TRUE);
+}
+
+void MyFrame::OnAbout(wxCommandEvent& event)
+{
+      (void)wxMessageBox("wxWindows 2.0 Sash Demo\nAuthor: Julian Smart (c) 1998", "About Sash Demo");
+}
+
+void MyFrame::OnToggleWindow(wxCommandEvent& event)
+{
+    if (m_leftWindow1->IsShown())
+    {
+        m_leftWindow1->Show(FALSE);
+    }
+    else
+    {
+        m_leftWindow1->Show(TRUE);
+    }
+    wxLayoutAlgorithm layout;
+    layout.LayoutMDIFrame(this);
+}
+
+void MyFrame::OnSashDrag(wxSashEvent& event)
+{
+    if (event.GetDragStatus() == wxSASH_STATUS_OUT_OF_RANGE)
+        return;
+
+    switch (event.GetId())
+    {
+        case ID_WINDOW_TOP:
+        {
+            m_topWindow->SetDefaultSize(wxSize(1000, event.GetDragRect().height));
+            break;
+        }
+        case ID_WINDOW_LEFT1:
+        {
+            m_leftWindow1->SetDefaultSize(wxSize(event.GetDragRect().width, 1000));
+            break;
+        }
+        case ID_WINDOW_LEFT2:
+        {
+            m_leftWindow2->SetDefaultSize(wxSize(event.GetDragRect().width, 1000));
+            break;
+        }
+        case ID_WINDOW_BOTTOM:
+        {
+            m_bottomWindow->SetDefaultSize(wxSize(1000, event.GetDragRect().height));
+            break;
+        }
+    }
+    wxLayoutAlgorithm layout;
+    layout.LayoutMDIFrame(this);
+
+    // Leaves bits of itself behind sometimes
+    GetClientWindow()->Refresh();
+}
+
+void MyFrame::OnNewWindow(wxCommandEvent& event)
+{
+      // Make another frame, containing a canvas
+      MyChild *subframe = new MyChild(frame, "Canvas Frame", wxPoint(10, 10), wxSize(300, 300),
+                             wxDEFAULT_FRAME);
+
+      char titleBuf[100];
+      sprintf(titleBuf, "Canvas Frame %d", winNumber);
+      subframe->SetTitle(titleBuf);
+      winNumber ++;
+
+      // Give it an icon (this is ignored in MDI mode: uses resources)
+#ifdef __WXMSW__
+      subframe->SetIcon(wxIcon("sashtest_icn"));
+#endif
+
+      // Give it a status line
+      subframe->CreateStatusBar();
+
+      // Make a menubar
+      wxMenu *file_menu = new wxMenu;
+
+      file_menu->Append(SASHTEST_NEW_WINDOW, "&New window");
+      file_menu->Append(SASHTEST_CHILD_QUIT, "&Close child");
+      file_menu->Append(SASHTEST_QUIT, "&Exit");
+
+      wxMenu *option_menu = new wxMenu;
+
+      // Dummy option
+      option_menu->Append(SASHTEST_REFRESH, "&Refresh picture");
+
+      wxMenu *help_menu = new wxMenu;
+      help_menu->Append(SASHTEST_ABOUT, "&About");
+
+      wxMenuBar *menu_bar = new wxMenuBar;
+
+      menu_bar->Append(file_menu, "&File");
+      menu_bar->Append(option_menu, "&Options");
+      menu_bar->Append(help_menu, "&Help");
+
+      // Associate the menu bar with the frame
+      subframe->SetMenuBar(menu_bar);
+
+      int width, height;
+      subframe->GetClientSize(&width, &height);
+      MyCanvas *canvas = new MyCanvas(subframe, wxPoint(0, 0), wxSize(width, height));
+      canvas->SetCursor(wxCursor(wxCURSOR_PENCIL));
+      subframe->canvas = canvas;
+
+      // Give it scrollbars
+      canvas->SetScrollbars(20, 20, 50, 50);
+
+      subframe->Show(TRUE);
+}
+
+BEGIN_EVENT_TABLE(MyCanvas, wxScrolledWindow)
+       EVT_MOUSE_EVENTS(MyCanvas::OnEvent)
+END_EVENT_TABLE()
+
+// Define a constructor for my canvas
+MyCanvas::MyCanvas(wxWindow *parent, const wxPoint& pos, const wxSize& size):
+ wxScrolledWindow(parent, -1, pos, size, wxSUNKEN_BORDER)
+{
+}
+
+// Define the repainting behaviour
+void MyCanvas::OnDraw(wxDC& dc)
+{
+  dc.SetFont(*wxSWISS_FONT);
+  dc.SetPen(*wxGREEN_PEN);
+  dc.DrawLine(0, 0, 200, 200);
+  dc.DrawLine(200, 0, 0, 200);
+
+  dc.SetBrush(*wxCYAN_BRUSH);
+  dc.SetPen(*wxRED_PEN);
+  dc.DrawRectangle(100, 100, 100, 50);
+  dc.DrawRoundedRectangle(150, 150, 100, 50, 20);
+
+  dc.DrawEllipse(250, 250, 100, 50);
+  dc.DrawSpline(50, 200, 50, 100, 200, 10);
+  dc.DrawLine(50, 230, 200, 230);
+  dc.DrawText("This is a test string", 50, 230);
+
+  wxPoint points[3];
+  points[0].x = 200; points[0].y = 300;
+  points[1].x = 100; points[1].y = 400;
+  points[2].x = 300; points[2].y = 400;
+  
+  dc.DrawPolygon(3, points);
+}
+
+// This implements a tiny doodling program! Drag the mouse using
+// the left button.
+void MyCanvas::OnEvent(wxMouseEvent& event)
+{
+  wxClientDC dc(this);
+  PrepareDC(dc);
+
+  wxPoint pt(event.GetLogicalPosition(dc));
+
+  if (xpos > -1 && ypos > -1 && event.Dragging())
+  {
+    dc.SetPen(*wxBLACK_PEN);
+    dc.DrawLine(xpos, ypos, pt.x, pt.y);
+  }
+  xpos = pt.x;
+  ypos = pt.y;
+}
+
+// Define the behaviour for the frame closing
+// - must delete all frames except for the main one.
+bool MyFrame::OnClose(void)
+{
+  // Must delete children
+  wxNode *node = my_children.First();
+  while (node)
+  {
+    MyChild *child = (MyChild *)node->Data();
+    wxNode *next = node->Next();
+    child->OnClose();
+    delete child;
+    node = next;
+  }
+  return TRUE;
+}
+
+void MyFrame::OnSize(wxSizeEvent& event)
+{
+    wxLayoutAlgorithm layout;
+    layout.LayoutMDIFrame(this);
+}
+
+// Note that SASHTEST_NEW_WINDOW and SASHTEST_ABOUT commands get passed
+// to the parent window for processing, so no need to
+// duplicate event handlers here.
+
+BEGIN_EVENT_TABLE(MyChild, wxMDIChildFrame)
+  EVT_MENU(SASHTEST_CHILD_QUIT, MyChild::OnQuit)
+END_EVENT_TABLE()
+
+MyChild::MyChild(wxMDIParentFrame *parent, const wxString& title, const wxPoint& pos, const wxSize& size,
+const long style):
+  wxMDIChildFrame(parent, -1, title, pos, size, style)
+{
+  canvas = NULL;
+  my_children.Append(this);
+}
+
+MyChild::~MyChild(void)
+{
+  my_children.DeleteObject(this);
+}
+
+void MyChild::OnQuit(wxCommandEvent& WXUNUSED(event))
+{
+      Close(TRUE);
+}
+
+void MyChild::OnActivate(wxActivateEvent& event)
+{
+  if (event.GetActive() && canvas)
+    canvas->SetFocus();
+}
+
+bool MyChild::OnClose(void)
+{
+  return TRUE;
+}
+
+
diff --git a/samples/sashtest/sashtest.h b/samples/sashtest/sashtest.h
new file mode 100644 (file)
index 0000000..ed5fa54
--- /dev/null
@@ -0,0 +1,79 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        sashtest.h
+// Purpose:     Layout window/sash sample
+// Author:      Julian Smart
+// Modified by:
+// Created:     04/01/98
+// RCS-ID:      $Id$
+// Copyright:   (c) Julian Smart
+// Licence:    wxWindows license
+/////////////////////////////////////////////////////////////////////////////
+
+#include <wx/toolbar.h>
+
+// Define a new application
+class MyApp: public wxApp
+{
+  public:
+    bool OnInit(void);
+};
+
+class MyCanvas: public wxScrolledWindow
+{
+  public:
+    MyCanvas(wxWindow *parent, const wxPoint& pos, const wxSize& size);
+    virtual void OnDraw(wxDC& dc);
+    void OnEvent(wxMouseEvent& event);
+
+    DECLARE_EVENT_TABLE()
+};
+
+// Define a new frame
+class MyFrame: public wxMDIParentFrame
+{
+  public:
+
+    MyFrame(wxWindow *parent, const wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, const long style);
+
+    bool OnClose(void);
+    void OnSize(wxSizeEvent& event);
+    void OnAbout(wxCommandEvent& event);
+    void OnNewWindow(wxCommandEvent& event);
+    void OnQuit(wxCommandEvent& event);
+    void OnToggleWindow(wxCommandEvent& event);
+    void OnSashDrag(wxSashEvent& event);
+
+protected:
+    wxSashLayoutWindow* m_topWindow;
+    wxSashLayoutWindow* m_leftWindow1;
+    wxSashLayoutWindow* m_leftWindow2;
+    wxSashLayoutWindow* m_bottomWindow;
+
+DECLARE_EVENT_TABLE()
+};
+
+class MyChild: public wxMDIChildFrame
+{
+  public:
+    MyCanvas *canvas;
+    MyChild(wxMDIParentFrame *parent, const wxString& title, const wxPoint& pos, const wxSize& size, const long style);
+    ~MyChild(void);
+    bool OnClose(void);
+    void OnActivate(wxActivateEvent& event);
+    void OnQuit(wxCommandEvent& event);
+
+DECLARE_EVENT_TABLE()
+};
+
+#define SASHTEST_QUIT        1
+#define SASHTEST_NEW_WINDOW  2
+#define SASHTEST_REFRESH     3
+#define SASHTEST_CHILD_QUIT  4
+#define SASHTEST_ABOUT       5
+#define SASHTEST_TOGGLE_WINDOW 6
+
+#define ID_WINDOW_TOP       100
+#define ID_WINDOW_LEFT1     101
+#define ID_WINDOW_LEFT2     102
+#define ID_WINDOW_BOTTOM    103
+
diff --git a/samples/sashtest/sashtest.ico b/samples/sashtest/sashtest.ico
new file mode 100644 (file)
index 0000000..2dc1bde
Binary files /dev/null and b/samples/sashtest/sashtest.ico differ
diff --git a/samples/sashtest/sashtest.rc b/samples/sashtest/sashtest.rc
new file mode 100644 (file)
index 0000000..3719f5a
--- /dev/null
@@ -0,0 +1,9 @@
+aaaa                    ICON        "sashtest.ico"
+
+wxSTD_MDIPARENTFRAME    ICON        "sashtest.ico"
+wxSTD_MDICHILDFRAME     ICON        "sashtest.ico"
+
+sashtest_icn            ICON        "sashtest.ico"
+
+#include "wx/msw/wx.rc"
+
diff --git a/src/generic/laywin.cpp b/src/generic/laywin.cpp
new file mode 100644 (file)
index 0000000..1f2094e
--- /dev/null
@@ -0,0 +1,226 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        laywin.cpp
+// Purpose:     Implements a simple layout algorithm, plus
+//              wxSashLayoutWindow which is an example of a window with
+//              layout-awareness (via event handlers). This is suited to
+//              IDE-style window layout.
+// Author:      Julian Smart
+// Modified by:
+// Created:     04/01/98
+// RCS-ID:      $Id$
+// Copyright:   (c) Julian Smart
+// Licence:    wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+// For compilers that support precompilation, includes "wx/wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+#ifndef WX_PRECOMP
+#include "wx/wx.h"
+#include "wx/mdi.h"
+#endif
+
+#include "wx/laywin.h"
+
+IMPLEMENT_DYNAMIC_CLASS(wxQueryLayoutInfoEvent, wxEvent)
+IMPLEMENT_DYNAMIC_CLASS(wxCalculateLayoutEvent, wxEvent)
+
+IMPLEMENT_CLASS(wxSashLayoutWindow, wxSashWindow)
+
+BEGIN_EVENT_TABLE(wxSashLayoutWindow, wxSashWindow)
+    EVT_CALCULATE_LAYOUT(wxSashLayoutWindow::OnCalculateLayout)
+    EVT_QUERY_LAYOUT_INFO(wxSashLayoutWindow::OnQueryLayoutInfo)
+END_EVENT_TABLE()
+
+wxSashLayoutWindow::wxSashLayoutWindow(wxWindow *parent, wxWindowID id, const wxPoint& pos,
+        const wxSize& size, long style, const wxString& name):
+    wxSashWindow(parent, id, pos, size, style, name)
+{
+    m_orientation = wxLAYOUT_HORIZONTAL;
+    m_alignment = wxLAYOUT_TOP;
+}
+
+// These are the functions that wxWin will call to ascertain the window
+// dimensions.
+void wxSashLayoutWindow::OnQueryLayoutInfo(wxQueryLayoutInfoEvent& event)
+{
+    int flags = event.GetFlags();
+    int requestedLength = event.GetRequestedLength();
+
+    // This code won't be in the final thing, it's just so we don't have to give it
+    // real windows: mock up some dimensions.
+
+    event.SetOrientation(m_orientation);
+    event.SetAlignment(m_alignment);
+
+    if (m_orientation == wxLAYOUT_HORIZONTAL)
+        event.SetSize(wxSize(requestedLength, m_defaultSize.y));
+    else
+        event.SetSize(wxSize(m_defaultSize.x, requestedLength));
+}
+
+// Called by parent to allow window to take a bit out of the
+// client rectangle, and size itself if not in wxLAYOUT_QUERY mode.
+// Will eventually be an event.
+
+void wxSashLayoutWindow::OnCalculateLayout(wxCalculateLayoutEvent& event)
+{
+    wxRect clientSize(event.GetRect());
+
+    int flags = event.GetFlags();
+
+    if (!IsShown())
+        return;
+
+    // Let's assume that all windows stretch the full extent of the window in
+    // the direction of that window orientation. This will work for non-docking toolbars,
+    // and the status bar. Note that the windows have to have been created in a certain
+    // order to work, else you might get a left-aligned window going to the bottom
+    // of the window, and the status bar appearing to the right of it. The
+    // status bar would have to be created after or before the toolbar(s).
+
+    wxRect thisRect;
+
+    // Try to stretch
+    int length = (GetOrientation() == wxLAYOUT_HORIZONTAL) ? clientSize.width : clientSize.height;
+    wxLayoutOrientation orient = GetOrientation();
+
+    // We assume that a window that says it's horizontal, wants to be stretched in that
+    // direction. Is this distinction too fine? Do we assume that any horizontal
+    // window needs to be stretched in that direction? Possibly.
+    int whichDimension = (GetOrientation() == wxLAYOUT_HORIZONTAL) ? wxLAYOUT_LENGTH_X : wxLAYOUT_LENGTH_Y;
+
+    wxQueryLayoutInfoEvent infoEvent(GetId());
+    infoEvent.SetEventObject(this);
+    infoEvent.SetRequestedLength(length);
+    infoEvent.SetFlags(orient | whichDimension);
+
+    if (!GetEventHandler()->ProcessEvent(infoEvent))
+        return;
+
+    wxSize sz = infoEvent.GetSize();
+
+    if (sz.x == 0 && sz.y == 0) // Assume it's invisible
+        return;
+
+    // Now we know the size it wants to be. We wish to decide where to place it, i.e.
+    // how it's aligned.
+    switch (GetAlignment())
+    {
+        case wxLAYOUT_TOP:
+        {
+            thisRect.x = clientSize.x; thisRect.y = clientSize.y;
+            thisRect.width = sz.x; thisRect.height = sz.y;
+            clientSize.y += thisRect.height;
+            clientSize.height -= thisRect.height;
+            break;
+        }
+        case wxLAYOUT_LEFT:
+        {
+            thisRect.x = clientSize.x; thisRect.y = clientSize.y;
+            thisRect.width = sz.x; thisRect.height = sz.y;
+            clientSize.x += thisRect.width;
+            clientSize.width -= thisRect.width;
+            break;
+        }
+        case wxLAYOUT_RIGHT:
+        {
+            thisRect.x = clientSize.x + (clientSize.width - sz.x); thisRect.y = clientSize.y;
+            thisRect.width = sz.x; thisRect.height = sz.y;
+            clientSize.width -= thisRect.width;
+            break;
+        }
+        case wxLAYOUT_BOTTOM:
+        {
+            thisRect.x = clientSize.x; thisRect.y = clientSize.y + (clientSize.height - sz.y);
+            thisRect.width = sz.x; thisRect.height = sz.y;
+            clientSize.height -= thisRect.height;
+            break;
+        }
+    }
+
+    if ((flags & wxLAYOUT_QUERY) == 0)
+    {
+        // If not in query mode, resize the window.
+        // TODO: add wxRect& form to wxWindow::SetSize
+        SetSize(thisRect.x, thisRect.y, thisRect.width, thisRect.height);
+    }
+
+    event.SetRect(clientSize);
+}
+
+/*
+ * wxLayoutAlgorithm
+ */
+
+// Lays out windows for an MDI frame. The MDI client area gets what's left
+// over.
+bool wxLayoutAlgorithm::LayoutMDIFrame(wxMDIParentFrame* frame)
+{
+    int cw, ch;
+    frame->GetClientSize(& cw, & ch);
+
+    wxRect rect(0, 0, cw, ch);
+
+    wxCalculateLayoutEvent event;
+    event.SetRect(rect);
+
+    wxNode* node = frame->GetChildren()->First();
+    while (node)
+    {
+        wxWindow* win = (wxWindow*) node->Data();
+
+        event.SetId(win->GetId());
+        event.SetEventObject(win);
+        event.SetFlags(0); // ??
+
+        win->GetEventHandler()->ProcessEvent(event);
+
+        node = node->Next();
+    }
+
+    wxWindow* clientWindow = frame->GetClientWindow();
+
+    rect = event.GetRect();
+
+    clientWindow->SetSize(rect.x, rect.y, rect.width, rect.height);
+
+    return TRUE;
+}
+
+// Layout algorithm for normal frame. mainWindow gets what's left over.
+bool wxLayoutAlgorithm::LayoutFrame(wxFrame* frame, wxWindow* mainWindow)
+{
+    int cw, ch;
+    frame->GetClientSize(& cw, & ch);
+
+    wxRect rect(0, 0, cw, ch);
+
+    wxCalculateLayoutEvent event;
+    event.SetRect(rect);
+
+    wxNode* node = frame->GetChildren()->First();
+    while (node)
+    {
+        wxWindow* win = (wxWindow*) node->Data();
+
+        event.SetId(win->GetId());
+        event.SetEventObject(win);
+        event.SetFlags(0); // ??
+
+        win->GetEventHandler()->ProcessEvent(event);
+
+        node = node->Next();
+    }
+
+    rect = event.GetRect();
+
+    mainWindow->SetSize(rect.x, rect.y, rect.width, rect.height);
+
+    return TRUE;
+}
+
diff --git a/src/generic/sashwin.cpp b/src/generic/sashwin.cpp
new file mode 100644 (file)
index 0000000..2f53738
--- /dev/null
@@ -0,0 +1,588 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        sashwin.cpp
+// Purpose:     wxSashWindow implementation. A sash window has an optional
+//              sash on each edge, allowing it to be dragged. An event
+//              is generated when the sash is released.
+// Author:      Julian Smart
+// Modified by:
+// Created:     01/02/97
+// RCS-ID:      $Id$
+// Copyright:   (c) Julian Smart
+// Licence:    wxWindows license
+/////////////////////////////////////////////////////////////////////////////
+
+#ifdef __GNUG__
+#pragma implementation "sashwin.h"
+#endif
+
+// For compilers that support precompilation, includes "wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+#ifndef WX_PRECOMP
+#include "wx/wx.h"
+#endif
+
+#include <math.h>
+#include <stdlib.h>
+
+#include "wx/string.h"
+#include "wx/dcscreen.h"
+#include "wx/sashwin.h"
+
+#if !USE_SHARED_LIBRARY
+IMPLEMENT_DYNAMIC_CLASS(wxSashWindow, wxWindow)
+IMPLEMENT_DYNAMIC_CLASS(wxSashEvent, wxCommandEvent)
+
+BEGIN_EVENT_TABLE(wxSashWindow, wxWindow)
+    EVT_PAINT(wxSashWindow::OnPaint)
+    EVT_SIZE(wxSashWindow::OnSize)
+    EVT_MOUSE_EVENTS(wxSashWindow::OnMouseEvent)
+END_EVENT_TABLE()
+#endif
+
+wxSashWindow::wxSashWindow()
+{
+    m_draggingEdge = wxSASH_NONE;
+    m_dragMode = wxSASH_DRAG_NONE;
+    m_oldX = 0;
+    m_oldY = 0;
+    m_firstX = 0;
+    m_firstY = 0;
+    m_borderSize = 3 ;
+    m_extraBorderSize = 0;
+    m_sashCursorWE = NULL;
+    m_sashCursorNS = NULL;
+
+    m_minimumPaneSizeX = 0;
+    m_minimumPaneSizeY = 0;
+    m_maximumPaneSizeX = 0;
+    m_maximumPaneSizeY = 0;
+}
+
+wxSashWindow::wxSashWindow(wxWindow *parent, wxWindowID id, const wxPoint& pos,
+    const wxSize& size, long style, const wxString& name)
+  :wxWindow(parent, id, pos, size, style, name)
+{
+    m_draggingEdge = wxSASH_NONE;
+    m_dragMode = wxSASH_DRAG_NONE;
+    m_oldX = 0;
+    m_oldY = 0;
+    m_firstX = 0;
+    m_firstY = 0;
+    m_borderSize = 3;
+    m_extraBorderSize = 0;
+    m_minimumPaneSizeX = 0;
+    m_minimumPaneSizeY = 0;
+    m_maximumPaneSizeX = 0;
+    m_maximumPaneSizeY = 0;
+    m_sashCursorWE = new wxCursor(wxCURSOR_SIZEWE);
+    m_sashCursorNS = new wxCursor(wxCURSOR_SIZENS);
+
+    // Eventually, we'll respond to colour change messages
+    InitColours();
+}
+
+wxSashWindow::~wxSashWindow()
+{
+    delete m_sashCursorWE;
+    delete m_sashCursorNS;
+}
+
+void wxSashWindow::OnPaint(wxPaintEvent& WXUNUSED(event))
+{
+    wxPaintDC dc(this);
+
+#if 0
+    if ( m_borderSize > 0 )
+        DrawBorders(dc);
+#endif
+
+    DrawSashes(dc);
+}
+
+void wxSashWindow::OnMouseEvent(wxMouseEvent& event)
+{
+    long x, y;
+    event.Position(&x, &y);
+
+    wxSashEdgePosition sashHit = SashHitTest(x, y);
+
+       if (event.LeftDown())
+       {
+        if ( sashHit != wxSASH_NONE )
+        {
+               CaptureMouse();
+
+           // Required for X to specify that
+               // that we wish to draw on top of all windows
+               // - and we optimise by specifying the area
+               // for creating the overlap window.
+               wxScreenDC::StartDrawingOnTop(this);
+
+            // We don't say we're dragging yet; we leave that
+            // decision for the Dragging() branch, to ensure
+            // the user has dragged a little bit.
+            m_dragMode = wxSASH_DRAG_LEFT_DOWN;
+            m_draggingEdge = sashHit;
+            m_firstX = x;
+            m_firstY = y;
+        }
+       }
+    else if ( event.LeftUp() && m_dragMode == wxSASH_DRAG_LEFT_DOWN )
+    {
+        // Wasn't a proper drag
+        ReleaseMouse();
+        wxScreenDC::EndDrawingOnTop();
+        m_dragMode = wxSASH_DRAG_NONE;
+        m_draggingEdge = wxSASH_NONE;
+
+        SetCursor(*wxSTANDARD_CURSOR);
+    }
+       else if (event.LeftUp() && m_dragMode == wxSASH_DRAG_DRAGGING)
+       {
+        // We can stop dragging now and see what we've got.
+        m_dragMode = wxSASH_DRAG_NONE;
+               ReleaseMouse();
+        // Erase old tracker
+        DrawSashTracker(m_draggingEdge, m_oldX, m_oldY);
+
+        // End drawing on top (frees the window used for drawing
+        // over the screen)
+        wxScreenDC::EndDrawingOnTop();
+
+        int w, h;
+               GetSize(&w, &h);
+        int xp, yp;
+               GetPosition(&xp, &yp);
+
+        wxSashEdgePosition edge = m_draggingEdge;
+        m_draggingEdge = wxSASH_NONE;
+
+        wxRect dragRect;
+        wxSashDragStatus status = wxSASH_STATUS_OK;
+        switch (edge)
+        {
+            case wxSASH_TOP:
+            {
+                if (y > (yp + h))
+                    status = wxSASH_STATUS_OUT_OF_RANGE;
+                int newHeight = (h - y);
+                dragRect = wxRect(xp, (yp + h) - newHeight, w, newHeight);
+                break;
+            }
+            case wxSASH_BOTTOM:
+            {
+                if (y < 0)
+                    status = wxSASH_STATUS_OUT_OF_RANGE;
+                int newHeight = y;
+                dragRect = wxRect(xp, yp, w, newHeight);
+                break;
+            }
+            case wxSASH_LEFT:
+            {
+                if (x > (xp + w))
+                    status = wxSASH_STATUS_OUT_OF_RANGE;
+                int newWidth = (w - x);
+                dragRect = wxRect((xp + w) - newWidth, yp, newWidth, h);
+                break;
+            }
+            case wxSASH_RIGHT:
+            {
+                if (x < 0)
+                    status = wxSASH_STATUS_OUT_OF_RANGE;
+                int newWidth = x;
+                dragRect = wxRect(xp, yp, newWidth, h);
+                break;
+            }
+        }
+
+        wxSashEvent event(GetId(), edge);
+        event.SetEventObject(this);
+        event.SetDragStatus(status);
+        event.SetDragRect(dragRect);
+        GetEventHandler()->ProcessEvent(event);
+       }
+       else if (event.Moving() && !event.Dragging())
+       {
+        // Just change the cursor if required
+        if ( sashHit != wxSASH_NONE )
+        {
+               if ( (sashHit == wxSASH_LEFT) || (sashHit == wxSASH_RIGHT) )
+                {
+                       SetCursor(*m_sashCursorWE);
+                }
+                else
+                {
+                       SetCursor(*m_sashCursorNS);
+                }
+        }
+        else
+        {
+           SetCursor(*wxSTANDARD_CURSOR);
+        }
+       }
+       else if ( event.Dragging() &&
+              ((m_dragMode == wxSASH_DRAG_DRAGGING) || (m_dragMode == wxSASH_DRAG_LEFT_DOWN))
+            )
+       {
+                if ( (m_draggingEdge == wxSASH_LEFT) || (m_draggingEdge == wxSASH_RIGHT) )
+         {
+               SetCursor(*m_sashCursorWE);
+         }
+         else
+         {
+               SetCursor(*m_sashCursorNS);
+         }
+
+        if (m_dragMode == wxSASH_DRAG_LEFT_DOWN)
+        {
+            m_dragMode = wxSASH_DRAG_DRAGGING;
+            DrawSashTracker(m_draggingEdge, x, y);
+        }
+        else
+        {
+          if ( m_dragMode == wxSASH_DRAG_DRAGGING )
+          {
+            // Erase old tracker
+            DrawSashTracker(m_draggingEdge, m_oldX, m_oldY);
+
+            // Draw new one
+            DrawSashTracker(m_draggingEdge, x, y);
+          }
+        }
+        m_oldX = x;
+        m_oldY = y;
+       }
+    else if ( event.LeftDClick() )
+    {
+        // Nothing
+    }
+    else
+    {
+    }
+}
+
+void wxSashWindow::OnSize(wxSizeEvent& WXUNUSED(event))
+{
+    SizeWindows();
+}
+
+wxSashEdgePosition wxSashWindow::SashHitTest(int x, int y, int tolerance)
+{
+    int cx, cy;
+    GetClientSize(& cx, & cy);
+
+    int i;
+    for (i = 0; i < 4; i++)
+    {
+        wxSashEdge& edge = m_sashes[i];
+        wxSashEdgePosition position = (wxSashEdgePosition) i ;
+
+        if (edge.m_show)
+        {
+            switch (position)
+            {
+                case wxSASH_TOP:
+                {
+                    if (y >= 0 && y <= GetEdgeMargin(position))
+                        return wxSASH_TOP;
+                    break;
+                }
+                case wxSASH_RIGHT:
+                {
+                    if ((x >= cx - GetEdgeMargin(position)) && (x <= cx))
+                        return wxSASH_RIGHT;
+                    break;
+                }
+                case wxSASH_BOTTOM:
+                {
+                    if ((y >= cy - GetEdgeMargin(position)) && (y <= cy))
+                        return wxSASH_BOTTOM;
+                    break;
+                }
+                case wxSASH_LEFT:
+                {
+                    if ((x >= GetEdgeMargin(position)) && (x >= 0))
+                        return wxSASH_LEFT;
+                    break;
+                }
+            }
+        }
+    }
+    return wxSASH_NONE;
+}
+
+// Draw 3D effect borders
+void wxSashWindow::DrawBorders(wxDC& dc)
+{
+    int w, h;
+    GetClientSize(&w, &h);
+
+    wxPen mediumShadowPen(m_mediumShadowColour, 1, wxSOLID);
+    wxPen darkShadowPen(m_darkShadowColour, 1, wxSOLID);
+    wxPen lightShadowPen(m_lightShadowColour, 1, wxSOLID);
+    wxPen hilightPen(m_hilightColour, 1, wxSOLID);
+
+    if ( GetWindowStyleFlag() & wxSP_3D )
+    {
+        dc.SetPen(mediumShadowPen);
+        dc.DrawLine(0, 0, w-1, 0);
+        dc.DrawLine(0, 0, 0, h - 1);
+
+        dc.SetPen(darkShadowPen);
+        dc.DrawLine(1, 1, w-2, 1);
+        dc.DrawLine(1, 1, 1, h-2);
+
+        dc.SetPen(hilightPen);
+        dc.DrawLine(0, h-1, w-1, h-1);
+        dc.DrawLine(w-1, 0, w-1, h); // Surely the maximum y pos. should be h - 1.
+                                     /// Anyway, h is required for MSW.
+
+        dc.SetPen(lightShadowPen);
+        dc.DrawLine(w-2, 1, w-2, h-2); // Right hand side
+        dc.DrawLine(1, h-2, w-1, h-2);     // Bottom
+    }
+    else if ( GetWindowStyleFlag() & wxSP_BORDER )
+    {
+        dc.SetBrush(*wxTRANSPARENT_BRUSH);
+        dc.SetPen(*wxBLACK_PEN);
+        dc.DrawRectangle(0, 0, w-1, h-1);
+    }
+
+    dc.SetPen(wxNullPen);
+    dc.SetBrush(wxNullBrush);
+}
+
+void wxSashWindow::DrawSashes(wxDC& dc)
+{
+    int i;
+    for (i = 0; i < 4; i++)
+        if (m_sashes[i].m_show)
+            DrawSash((wxSashEdgePosition) i, dc);
+}
+
+// Draw the sash
+void wxSashWindow::DrawSash(wxSashEdgePosition edge, wxDC& dc)
+{
+    int w, h;
+    GetClientSize(&w, &h);
+
+    wxPen facePen(m_faceColour, 1, wxSOLID);
+    wxBrush faceBrush(m_faceColour, wxSOLID);
+    wxPen mediumShadowPen(m_mediumShadowColour, 1, wxSOLID);
+    wxPen darkShadowPen(m_darkShadowColour, 1, wxSOLID);
+    wxPen lightShadowPen(m_lightShadowColour, 1, wxSOLID);
+    wxPen hilightPen(m_hilightColour, 1, wxSOLID);
+    wxPen blackPen(wxColour(0, 0, 0), 1, wxSOLID);
+    wxPen whitePen(wxColour(255, 255, 255), 1, wxSOLID);
+
+    if ( edge == wxSASH_LEFT || edge == wxSASH_RIGHT )
+    {
+        int sashPosition = 0;
+        if (edge == wxSASH_LEFT)
+            sashPosition = 0;
+        else
+            sashPosition = w - GetEdgeMargin(edge);
+
+        dc.SetPen(facePen);
+        dc.SetBrush(faceBrush);
+        dc.DrawRectangle(sashPosition, 0, GetEdgeMargin(edge), h);
+
+        if (GetWindowStyleFlag() & wxSW_3D)
+        {
+            if (edge == wxSASH_LEFT)
+            {
+                // Draw a black line on the left to indicate that the
+                // sash is raised
+                dc.SetPen(blackPen);
+                dc.DrawLine(GetEdgeMargin(edge), 0, GetEdgeMargin(edge), h);
+            }
+            else
+            {
+                // Draw a white line on the right to indicate that the
+                // sash is raised
+                dc.SetPen(whitePen);
+                dc.DrawLine(w - GetEdgeMargin(edge), 0, w - GetEdgeMargin(edge), h);
+            }
+        }
+    }
+    else // top or bottom
+    {
+        int sashPosition = 0;
+        if (edge == wxSASH_TOP)
+            sashPosition = 0;
+        else
+            sashPosition = h - GetEdgeMargin(edge);
+
+        dc.SetPen(facePen);
+        dc.SetBrush(faceBrush);
+        dc.DrawRectangle(0, sashPosition, w, GetEdgeMargin(edge));
+
+        if (GetWindowStyleFlag() & wxSW_3D)
+        {
+            if (edge == wxSASH_BOTTOM)
+            {
+                // Draw a black line on the bottom to indicate that the
+                // sash is raised
+                dc.SetPen(blackPen);
+                dc.DrawLine(0, h - GetEdgeMargin(edge), w, h - GetEdgeMargin(edge));
+            }
+            else
+            {
+                // Draw a white line on the top to indicate that the
+                // sash is raised
+                dc.SetPen(whitePen);
+                dc.DrawLine(0, GetEdgeMargin(edge), w, GetEdgeMargin(edge));
+            }
+        }
+    }
+
+    dc.SetPen(wxNullPen);
+    dc.SetBrush(wxNullBrush);
+}
+
+// Draw the sash tracker (for whilst moving the sash)
+void wxSashWindow::DrawSashTracker(wxSashEdgePosition edge, int x, int y)
+{
+    int w, h;
+    GetClientSize(&w, &h);
+
+    wxScreenDC screenDC;
+    int x1, y1;
+    int x2, y2;
+
+    if ( edge == wxSASH_LEFT || edge == wxSASH_RIGHT )
+    {
+        x1 = x; y1 = 2;
+        x2 = x; y2 = h-2;
+
+        if ( (edge == wxSASH_LEFT) && (x1 > w) )
+        {
+            x1 = w; x2 = w;
+        }
+        else if ( (edge == wxSASH_RIGHT) && (x1 < 0) )
+        {
+            x1 = 0; x2 = 0;
+        }
+    }
+    else
+    {
+        x1 = 2; y1 = y;
+        x2 = w-2; y2 = y;
+
+        if ( (edge == wxSASH_TOP) && (y1 > h) )
+        {
+            y1 = h;
+            y2 = h;
+        }
+        else if ( (edge == wxSASH_BOTTOM) && (y1 < 0) )
+        {
+            y1 = 0;
+            y2 = 0;
+        }
+    }
+
+    ClientToScreen(&x1, &y1);
+    ClientToScreen(&x2, &y2);
+
+    wxPen sashTrackerPen(*wxBLACK, 2, wxSOLID);
+
+    screenDC.SetLogicalFunction(wxXOR);
+    screenDC.SetPen(sashTrackerPen);
+    screenDC.SetBrush(*wxTRANSPARENT_BRUSH);
+
+    screenDC.DrawLine(x1, y1, x2, y2);
+
+    screenDC.SetLogicalFunction(wxCOPY);
+
+    screenDC.SetPen(wxNullPen);
+    screenDC.SetBrush(wxNullBrush);
+}
+
+// Position and size subwindows.
+// Note that the border size applies to each subwindow, not
+// including the edges next to the sash.
+void wxSashWindow::SizeWindows()
+{
+    int cw, ch;
+    GetClientSize(&cw, &ch);
+
+    if (GetChildren()->Number() > 0)
+    {
+        wxWindow* child = (wxWindow*) (GetChildren()->First()->Data());
+
+        int x = 0;
+        int y = 0;
+        int width = cw;
+        int height = ch;
+
+        // Top
+        if (m_sashes[0].m_show)
+        {
+            y = m_borderSize;
+            height -= m_borderSize;
+        }
+        y += m_extraBorderSize;
+
+        // Left
+        if (m_sashes[3].m_show)
+        {
+            x = m_borderSize;
+            width -= m_borderSize;
+        }
+        x += m_extraBorderSize;
+
+        // Right
+        if (m_sashes[1].m_show)
+        {
+            width -= m_borderSize;
+        }
+        width -= 2*m_extraBorderSize;
+
+        // Bottom
+        if (m_sashes[2].m_show)
+        {
+            height -= m_borderSize;
+        }
+        height -= 2*m_extraBorderSize;
+
+        child->SetSize(x, y, width, height);
+    }
+
+    wxClientDC dc(this);
+    DrawBorders(dc);
+    DrawSashes(dc);
+}
+
+// Initialize colours
+void wxSashWindow::InitColours()
+{
+    // Shadow colours
+#if defined(__WIN95__)
+    m_faceColour = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE);
+    m_mediumShadowColour = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DSHADOW);
+    m_darkShadowColour = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DDKSHADOW);
+    m_lightShadowColour = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DLIGHT);
+    m_hilightColour = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DHILIGHT);
+#else
+    m_faceColour = *(wxTheColourDatabase->FindColour("LIGHT GREY"));
+    m_mediumShadowColour = *(wxTheColourDatabase->FindColour("GREY", 1, wxSOLID));
+    m_darkShadowColour = *(wxTheColourDatabase->FindColour("BLACK"));
+    m_lightShadowColour = *(wxTheColourDatabase->FindColour("LIGHT GREY"));
+    m_hilightColour = *(wxTheColourDatabase->FindColour("WHITE"));
+#endif
+}
+
+void wxSashWindow::SetSashVisible(wxSashEdgePosition edge, bool sash)
+{
+     m_sashes[edge].m_show = sash;
+     if (sash)
+        m_sashes[edge].m_margin = m_borderSize;
+     else
+        m_sashes[edge].m_margin = 0;
+}
+
index cb546731b93a90b610352ca84bef3ecb7364a8c3..a84f84dfdcaba69ad5ea22ca714236a6aeae5813 100644 (file)
@@ -61,10 +61,12 @@ GENERICOBJS= \
   $(GENDIR)\fontdlgg.obj \
   $(GENDIR)\gridg.obj \
   $(GENDIR)\helpxlp.obj \
+  $(GENDIR)\laywin.obj \
   $(GENDIR)\msgdlgg.obj \
   $(GENDIR)\panelg.obj \
   $(GENDIR)\printps.obj \
   $(GENDIR)\prntdlgg.obj \
+  $(GENDIR)\sashwin.obj \
   $(GENDIR)\scrolwin.obj \
   $(GENDIR)\splitter.obj \
   $(GENDIR)\statusbr.obj \
@@ -1074,6 +1076,11 @@ $(GENDIR)/helpxlp.obj:     $*.$(SRCSUFF)
 $(CPPFLAGS) /c /Tp $*.$(SRCSUFF) /Fo$@
 <<
 
+$(GENDIR)/laywin.obj:     $*.$(SRCSUFF)
+        cl @<<
+$(CPPFLAGS) /c /Tp $*.$(SRCSUFF) /Fo$@
+<<
+
 $(GENDIR)/msgdlgg.obj:     $*.$(SRCSUFF)
         cl @<<
 $(CPPFLAGS) /c /Tp $*.$(SRCSUFF) /Fo$@
@@ -1094,6 +1101,11 @@ $(GENDIR)/prntdlgg.obj:     $*.$(SRCSUFF)
 $(CPPFLAGS) /c /Tp $*.$(SRCSUFF) /Fo$@
 <<
 
+$(GENDIR)/sashwin.obj:     $*.$(SRCSUFF)
+        cl @<<
+$(CPPFLAGS) /c /Tp $*.$(SRCSUFF) /Fo$@
+<<
+
 $(GENDIR)/scrolwin.obj:     $*.$(SRCSUFF)
         cl @<<
 $(CPPFLAGS) /c /Tp $*.$(SRCSUFF) /Fo$@