]> git.saurik.com Git - wxWidgets.git/commitdiff
added wxDynamicSashWindow (patch 441518)
authorVadim Zeitlin <vadim@wxwidgets.org>
Wed, 22 Aug 2001 15:02:40 +0000 (15:02 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Wed, 22 Aug 2001 15:02:40 +0000 (15:02 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@11437 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

17 files changed:
contrib/configure
contrib/configure.in
contrib/include/wx/gizmos/dynamicsash.h [new file with mode: 0644]
contrib/samples/gizmos/Makefile.in
contrib/samples/gizmos/dynsash/Makefile.in [new file with mode: 0644]
contrib/samples/gizmos/dynsash/dynsash.cpp [new file with mode: 0644]
contrib/samples/gizmos/dynsash_switch/Makefile.in [new file with mode: 0644]
contrib/samples/gizmos/dynsash_switch/dynsash_switch.cpp [new file with mode: 0644]
contrib/src/gizmos/GizmosVC.dsp
contrib/src/gizmos/Makefile.in
contrib/src/gizmos/dynamicsash.cpp [new file with mode: 0644]
contrib/src/gizmos/makefile.b32
contrib/src/gizmos/makefile.bcc
contrib/src/gizmos/makefile.g95
contrib/src/gizmos/makefile.unx
contrib/src/gizmos/makefile.vc
contrib/src/gizmos/makefile.wat

index 27de39350808131fbd4ea515ebdf9f4fc1ac1bf1..054e0c7389aa552d4aeb85aff0a10fe8890653da 100755 (executable)
@@ -822,6 +822,7 @@ trap 'rm -fr `echo "
             src/plot/Makefile
             src/applet/Makefile
             src/fl/Makefile
+            src/net/Makefile
             samples/Makefile
             samples/mmedia/Makefile
             samples/ogl/Makefile
@@ -835,6 +836,8 @@ trap 'rm -fr `echo "
             samples/gizmos/multicell/Makefile
             samples/gizmos/splittree/Makefile
             samples/gizmos/editlbox/Makefile
+            samples/gizmos/dynsash/Makefile
+            samples/gizmos/dynsash_switch/Makefile
             samples/xrc/Makefile
             samples/plot/Makefile
             samples/applet/Makefile
@@ -936,6 +939,7 @@ CONFIG_FILES=\${CONFIG_FILES-"src/Makefile
             src/plot/Makefile
             src/applet/Makefile
             src/fl/Makefile
+            src/net/Makefile
             samples/Makefile
             samples/mmedia/Makefile
             samples/ogl/Makefile
@@ -949,6 +953,8 @@ CONFIG_FILES=\${CONFIG_FILES-"src/Makefile
             samples/gizmos/multicell/Makefile
             samples/gizmos/splittree/Makefile
             samples/gizmos/editlbox/Makefile
+            samples/gizmos/dynsash/Makefile
+            samples/gizmos/dynsash_switch/Makefile
             samples/xrc/Makefile
             samples/plot/Makefile
             samples/applet/Makefile
index 8a245132fb67e04927b18a89d2ec22e1824469c5..c35f135d478b61f7d75f8461d100cef91d35897d 100644 (file)
@@ -61,6 +61,8 @@ AC_OUTPUT([
             samples/gizmos/multicell/Makefile
             samples/gizmos/splittree/Makefile
             samples/gizmos/editlbox/Makefile
+            samples/gizmos/dynsash/Makefile
+            samples/gizmos/dynsash_switch/Makefile
             samples/xrc/Makefile
             samples/plot/Makefile
             samples/applet/Makefile
diff --git a/contrib/include/wx/gizmos/dynamicsash.h b/contrib/include/wx/gizmos/dynamicsash.h
new file mode 100644 (file)
index 0000000..10b6b94
--- /dev/null
@@ -0,0 +1,148 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        dynamicsash.h
+// Purpose:     A window which can be dynamically split to an arbitrary depth
+//              and later reunified through the user interface
+// Author:      Matt Kimball
+// Modified by:
+// Created:     7/15/2001
+// RCS-ID:      $Id$
+// Copyright:   (c) 2001 Matt Kimball
+// Licence:     wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+#ifndef _WX_DYNAMICSASH_H_
+#define _WX_DYNAMICSASH_H_
+
+/*
+
+    wxDynamicSashWindow
+
+    wxDynamicSashWindow widgets manages the way other widgets are viewed.
+    When a wxDynamicSashWindow is first shown, it will contain one child
+    view, a viewport for that child, and a pair of scrollbars to allow the
+    user to navigate the child view area.  Next to each scrollbar is a small
+    tab.  By clicking on either tab and dragging to the appropriate spot, a
+    user can split the view area into two smaller views separated by a
+    draggable sash.  Later, when the user wishes to reunify the two subviews,
+    the user simply drags the sash to the side of the window.
+    wxDynamicSashWindow will automatically reparent the appropriate child
+    view back up the window hierarchy, and the wxDynamicSashWindow will have
+    only one child view once again.
+
+    As an application developer, you will simply create a wxDynamicSashWindow
+    using either the Create() function or the more complex constructor
+    provided below, and then create a view window whose parent is the
+    wxDynamicSashWindow.  The child should respond to
+    wxDynamicSashSplitEvents -- perhaps with an OnSplit() event handler -- by
+    constructing a new view window whose parent is also the
+    wxDynamicSashWindow.  That's it!  Now your users can dynamically split
+    and reunify the view you provided.
+
+    If you wish to handle the scrollbar events for your view, rather than
+    allowing wxDynamicSashWindow to do it for you, things are a bit more
+    complex.  (You might want to handle scrollbar events yourself, if,
+    for instance, you wish to scroll a subwindow of the view you add to
+    your wxDynamicSashWindow object, rather than scrolling the whole view.)
+    In this case, you will need to construct your wxDynamicSashWindow without
+    the wxMANAGE_SCROLLBARS style and  you will need to use the
+    GetHScrollBar() and GetVScrollBar() methods to retrieve the scrollbar
+    controls and call SetEventHanler() on them to redirect the scrolling
+    events whenever your window is reparented by wxDyanmicSashWindow.
+    You will need to set the scrollbars' event handler at three times:
+
+        *  When your view is created
+        *  When your view receives a wxDynamicSashSplitEvent
+        *  When your view receives a wxDynamicSashUnifyEvent
+
+    See the dynsash_switch sample application for an example which does this.
+
+*/
+
+
+#include <wx/event.h>
+#include <wx/window.h>
+class wxScrollBar;
+
+
+#define wxEVT_DYNAMIC_SASH_BASE             (((int)('d' - 'a') << 11) | ((int)('s' - 'a') << 6) | ((int)('h' - 'a') << 1))
+#define wxEVT_DYNAMIC_SASH_SPLIT            (wxEVT_DYNAMIC_SASH_BASE + 1)
+#define wxEVT_DYNAMIC_SASH_UNIFY            (wxEVT_DYNAMIC_SASH_BASE + 2)
+
+#define EVT_DYNAMIC_SASH_SPLIT(id, func)    EVT_CUSTOM(wxEVT_DYNAMIC_SASH_SPLIT, (id), (func))
+#define EVT_DYNAMIC_SASH_UNIFY(id, func)    EVT_CUSTOM(wxEVT_DYNAMIC_SASH_UNIFY, (id), (func))
+
+
+/*
+    wxMANAGE_SCROLLBARS is a default style of wxDynamicSashWindow which
+    will cause it to respond to scrollbar events for your application by
+    automatically scrolling the child view.
+*/
+#define wxMANAGE_SCROLLBARS     0x00800000
+
+
+/*
+    wxDynamicSashSplitEvents are sent to your view by wxDynamicSashWindow
+    whenever your view is being split by the user.  It is your
+    responsibility to handle this event by creating a new view window as
+    a child of the wxDynamicSashWindow.  wxDynamicSashWindow will
+    automatically reparent it to the proper place in its window hierarchy.
+*/
+class wxDynamicSashSplitEvent : public wxCommandEvent {
+public:
+    wxDynamicSashSplitEvent();
+    wxDynamicSashSplitEvent(wxObject *target);
+
+private:
+    DECLARE_DYNAMIC_CLASS(wxDynamicSashSplitEvent)
+};
+
+/*
+    wxDynamicSashUnifyEvents are sent to your view by wxDynamicSashWindow
+    whenever the sash which splits your view and its sibling is being
+    reunified such that your view is expanding to replace its sibling.
+    You needn't do anything with this event if you are allowing
+    wxDynamicSashWindow to manage your view's scrollbars, but it is useful
+    if you are managing the scrollbars yourself so that you can keep
+    the scrollbars' event handlers connected to your view's event handler
+    class.
+*/
+class wxDynamicSashUnifyEvent : public wxCommandEvent {
+public:
+    wxDynamicSashUnifyEvent();
+    wxDynamicSashUnifyEvent(wxObject *target);
+
+private:
+    DECLARE_DYNAMIC_CLASS(wxDynamicSashUnifyEvent);
+};
+
+/*
+    wxDynamicSashWindow.  See above.
+*/
+class wxDynamicSashWindow : public wxWindow {
+public:
+    wxDynamicSashWindow();
+    wxDynamicSashWindow(wxWindow *parent, wxWindowID id,
+                        const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
+                        long style = wxCLIP_CHILDREN | wxMANAGE_SCROLLBARS,
+                        const wxString& name = "dynamicSashWindow");
+    virtual ~wxDynamicSashWindow();
+
+    virtual bool Create(wxWindow *parent, wxWindowID id,
+                        const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
+                        long style = wxCLIP_CHILDREN | wxMANAGE_SCROLLBARS,
+                        const wxString& name = "dynamicSashWindow");
+    virtual wxScrollBar *GetHScrollBar(const wxWindow *child) const;
+    virtual wxScrollBar *GetVScrollBar(const wxWindow *child) const;
+
+    /*  This is overloaded from wxWindowBase.  It's not here for you to
+        call directly.  */
+    virtual void AddChild(wxWindowBase *child);
+
+private:
+    class wxDynamicSashWindowImpl *m_impl;
+
+    DECLARE_DYNAMIC_CLASS(wxDynamicSashWindow)
+};
+
+
+#endif
index b8ea713e3b05d977ceb7e62adfa6a4ac2b884837..223d5330fe779bb11655c08b1005b722797b0fe8 100644 (file)
@@ -1,6 +1,6 @@
 # $Id$
 
-CONTRIB_SAMPLES=multicell splittree editlbox
+CONTRIB_SAMPLES=multicell splittree editlbox dynsash dynsash_switch
 
 all:
        @for d in $(CONTRIB_SAMPLES); do (cd $$d && $(MAKE)); done
diff --git a/contrib/samples/gizmos/dynsash/Makefile.in b/contrib/samples/gizmos/dynsash/Makefile.in
new file mode 100644 (file)
index 0000000..5e5fd58
--- /dev/null
@@ -0,0 +1,23 @@
+#
+# File:                Makefile.in
+# Author:      Matt Kimball
+# Created:     2001
+# Updated:
+# Copyright:   (c) 2001 Matt Kimball
+#
+# "%W% %G%"
+#
+# Makefile for the dynsash example (UNIX).
+
+top_srcdir = @top_srcdir@/..
+top_builddir = ../../../..
+program_dir = contrib/samples/gizmos/dynsash
+
+PROGRAM=dynsash
+OBJECTS=dynsash.o
+
+APPEXTRALIBS=$(top_builddir)/lib/libgizmos.@WX_TARGET_LIBRARY_TYPE@
+APPEXTRADEFS=-I$(top_srcdir)/contrib/include
+
+include $(top_builddir)/src/makeprog.env
+
diff --git a/contrib/samples/gizmos/dynsash/dynsash.cpp b/contrib/samples/gizmos/dynsash/dynsash.cpp
new file mode 100644 (file)
index 0000000..8e7bbb4
--- /dev/null
@@ -0,0 +1,86 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        dynsash.cpp
+// Purpose:     Test the wxDynamicSash class by creating a dynamic sash which
+//              contains an HTML view
+// Author:      Matt Kimball
+// Modified by:
+// Created:     7/15/2001
+// RCS-ID:      $Id$
+// Copyright:   (c) 2001 Matt Kimball
+// Licence:     wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+#include <wx/app.h>
+#include <wx/gizmos/dynamicsash.h>
+#include <wx/html/htmlwin.h>
+#include <wx/image.h>
+
+class Demo : public wxApp {
+public:
+    bool OnInit();
+};
+
+class SashHtmlWindow : public wxHtmlWindow {
+public:
+    SashHtmlWindow(wxWindow *parent, wxWindowID id = -1,
+                   const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
+                   long style = wxHW_SCROLLBAR_NEVER, const wxString& name = "sashHtmlWindow");
+
+    wxSize DoGetBestSize() const;
+
+private:
+    void OnSplit(wxDynamicSashSplitEvent& event);
+
+    wxWindow *m_dyn_sash;
+};
+
+IMPLEMENT_APP(Demo)
+
+char *HTML_content =
+"<P><H1>wxDynamicSashWindow demo</H1>"
+"<P>Here is an example of how you can use <TT>wxDynamicSashWindow</TT> to allow your users to "
+"dynamically split and unify the views of your windows.  Try dragging out a few splits "
+"and then reunifying the window."
+"<P>Also, see the <TT>dynsash_switch</TT> sample for an example of an application which "
+"manages the scrollbars provided by <TT>wxDynamicSashWindow</TT> itself."
+;
+
+bool Demo::OnInit() {
+    wxInitAllImageHandlers();
+
+    wxFrame *frame = new wxFrame(NULL, -1, "Dynamic Sash Demo");
+    frame->SetSize(480, 480);
+
+    wxDynamicSashWindow *sash = new wxDynamicSashWindow(frame, -1);
+    wxHtmlWindow *html = new SashHtmlWindow(sash, -1);
+    html->SetPage(HTML_content);
+
+    frame->Show();
+
+    return TRUE;
+}
+
+
+SashHtmlWindow::SashHtmlWindow(wxWindow *parent, wxWindowID id,
+                               const wxPoint& pos, const wxSize& size, long style, const wxString& name) :
+                                    wxHtmlWindow(parent, id, pos, size, style, name) {
+    Connect(-1, wxEVT_DYNAMIC_SASH_SPLIT, (wxObjectEventFunction)&SashHtmlWindow::OnSplit);
+
+    m_dyn_sash = parent;
+}
+
+wxSize SashHtmlWindow::DoGetBestSize() const {
+    wxHtmlContainerCell *cell = GetInternalRepresentation();
+    wxSize size = GetSize();
+
+    if (cell) {
+        cell->Layout(size.GetWidth());
+        return wxSize(cell->GetWidth(), cell->GetHeight());
+    } else
+        return wxHtmlWindow::GetBestSize();
+}
+
+void SashHtmlWindow::OnSplit(wxDynamicSashSplitEvent& event) {
+    wxHtmlWindow *html = new SashHtmlWindow(m_dyn_sash, -1);
+    html->SetPage(HTML_content);
+}
diff --git a/contrib/samples/gizmos/dynsash_switch/Makefile.in b/contrib/samples/gizmos/dynsash_switch/Makefile.in
new file mode 100644 (file)
index 0000000..b9796bb
--- /dev/null
@@ -0,0 +1,23 @@
+#
+# File:                Makefile.in
+# Author:      Matt Kimball
+# Created:     2001
+# Updated:
+# Copyright:   (c) 2001 Matt Kimball
+#
+# "%W% %G%"
+#
+# Makefile for the dynsash_switch example (UNIX).
+
+top_srcdir = @top_srcdir@/..
+top_builddir = ../../../..
+program_dir = contrib/samples/gizmos/dynsash_switch
+
+PROGRAM=dynsash_switch
+OBJECTS=dynsash_switch.o
+
+APPEXTRALIBS=$(top_builddir)/lib/libgizmos.@WX_TARGET_LIBRARY_TYPE@
+APPEXTRADEFS=-I$(top_srcdir)/contrib/include
+
+include $(top_builddir)/src/makeprog.env
+
diff --git a/contrib/samples/gizmos/dynsash_switch/dynsash_switch.cpp b/contrib/samples/gizmos/dynsash_switch/dynsash_switch.cpp
new file mode 100644 (file)
index 0000000..208745d
--- /dev/null
@@ -0,0 +1,219 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        dynsash_switch.cpp
+// Purpose:     Test custom scrollbar handling of wxDynamicSashWindow by
+//              creating a dynamic sash window where the client scrolls a
+//              a subwindow of the client window by responding to scroll
+//              events itself
+// Author:      Matt Kimball
+// Modified by:
+// Created:     7/15/2001
+// RCS-ID:      $Id$
+// Copyright:   (c) 2001 Matt Kimball
+// Licence:     wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+#include <wx/app.h>
+#include <wx/choice.h>
+#include <wx/dcclient.h>
+#include <wx/gizmos/dynamicsash.h>
+#include <wx/layout.h>
+#include <wx/scrolbar.h>
+
+class SwitchDemo : public wxApp {
+public:
+    bool OnInit();
+};
+
+
+class SwitchView : public wxWindow {
+public:
+    SwitchView(wxDynamicSashWindow *parent);
+
+    wxSize DoGetBestSize() const;
+
+private:
+    void OnSize(wxSizeEvent& event);
+    void OnPaint(wxPaintEvent& event);
+    void OnChoice(wxCommandEvent& event);
+    void OnScroll(wxScrollEvent& event);
+    void OnFocus(wxFocusEvent& event);
+    void OnErase(wxEraseEvent& event);
+    void OnSplit(wxDynamicSashSplitEvent& event);
+    void OnUnify(wxDynamicSashUnifyEvent& event);
+
+    wxDynamicSashWindow *m_dyn_sash;
+    wxWindow *m_bar;
+    wxChoice *m_choice;
+    wxWindow *m_view;
+};
+
+IMPLEMENT_APP(SwitchDemo)
+
+
+SwitchView::SwitchView(wxDynamicSashWindow *win) {
+    Create(win, -1);
+
+    m_dyn_sash = win;
+
+    m_bar = new wxWindow(this, -1, wxDefaultPosition, wxDefaultSize, wxRAISED_BORDER, "bar");
+    m_choice = new wxChoice(m_bar, -1);
+    m_choice->SetEventHandler(this);
+    m_view = new wxWindow(this, -1, wxDefaultPosition, wxDefaultSize, 0, "view");
+    m_view->SetBackgroundColour(*wxWHITE);
+    m_view->SetEventHandler(this);
+
+    m_choice->Append("Triangle");
+    m_choice->Append("Square");
+    m_choice->SetSelection(0);
+
+    wxLayoutConstraints *layout;
+
+    layout = new wxLayoutConstraints();
+    layout->left.Absolute(0);
+    layout->top.Absolute(0);
+    layout->height.Absolute(36);
+    layout->width.SameAs(this, wxWidth);
+    m_bar->SetConstraints(layout);
+
+    layout = new wxLayoutConstraints();
+    layout->left.Absolute(3);
+    layout->width.AsIs();
+    layout->height.AsIs();
+    layout->top.Absolute(3);
+    m_choice->SetConstraints(layout);
+
+    layout = new wxLayoutConstraints();
+    layout->left.Absolute(0);
+    layout->width.SameAs(this, wxWidth);
+    layout->top.Below(m_bar);
+    layout->bottom.SameAs(this, wxBottom);
+    m_view->SetConstraints(layout);
+
+    wxScrollBar *hscroll = m_dyn_sash->GetHScrollBar(this);
+    wxScrollBar *vscroll = m_dyn_sash->GetVScrollBar(this);
+
+    hscroll->SetEventHandler(this);
+    vscroll->SetEventHandler(this);
+
+    Connect(GetId(), wxEVT_SIZE, (wxObjectEventFunction)&SwitchView::OnSize);
+    Connect(m_choice->GetId(), wxEVT_COMMAND_CHOICE_SELECTED, (wxObjectEventFunction)&SwitchView::OnChoice);
+    Connect(m_view->GetId(), wxEVT_PAINT, (wxObjectEventFunction)&SwitchView::OnPaint);
+
+    Connect(-1, wxEVT_SET_FOCUS, (wxObjectEventFunction)&SwitchView::OnFocus);
+    Connect(-1, wxEVT_SCROLL_TOP, (wxObjectEventFunction)&SwitchView::OnScroll);
+    Connect(-1, wxEVT_SCROLL_BOTTOM, (wxObjectEventFunction)&SwitchView::OnScroll);
+    Connect(-1, wxEVT_SCROLL_LINEUP, (wxObjectEventFunction)&SwitchView::OnScroll);
+    Connect(-1, wxEVT_SCROLL_LINEDOWN, (wxObjectEventFunction)&SwitchView::OnScroll);
+    Connect(-1, wxEVT_SCROLL_PAGEUP, (wxObjectEventFunction)&SwitchView::OnScroll);
+    Connect(-1, wxEVT_SCROLL_PAGEDOWN, (wxObjectEventFunction)&SwitchView::OnScroll);
+    Connect(-1, wxEVT_SCROLL_THUMBTRACK, (wxObjectEventFunction)&SwitchView::OnScroll);
+    Connect(-1, wxEVT_SCROLL_THUMBRELEASE, (wxObjectEventFunction)&SwitchView::OnScroll);
+    Connect(-1, wxEVT_ERASE_BACKGROUND, (wxObjectEventFunction)&SwitchView::OnErase);
+
+    Connect(-1, wxEVT_DYNAMIC_SASH_SPLIT, (wxObjectEventFunction)&SwitchView::OnSplit);
+    Connect(-1, wxEVT_DYNAMIC_SASH_UNIFY, (wxObjectEventFunction)&SwitchView::OnUnify);
+}
+
+wxSize SwitchView::DoGetBestSize() const {
+    return wxSize(64, 64);
+}
+
+void SwitchView::OnSize(wxSizeEvent& event) {
+    Layout();
+
+    wxScrollBar *hscroll = m_dyn_sash->GetHScrollBar(this);
+    wxScrollBar *vscroll = m_dyn_sash->GetVScrollBar(this);
+
+    if (hscroll && vscroll) {
+        int hpos = hscroll->GetThumbPosition();
+        int vpos = vscroll->GetThumbPosition();
+
+        wxSize size = m_view->GetSize();
+        if (hpos + size.GetWidth() > 300)
+            hpos = 300 - size.GetWidth();
+        if (vpos + size.GetHeight() > 300)
+            vpos = 300 - size.GetHeight();
+
+        hscroll->SetScrollbar(hpos, size.GetWidth(), 300, size.GetWidth());
+        vscroll->SetScrollbar(vpos, size.GetHeight(), 300, size.GetHeight());
+    }
+}
+
+void SwitchView::OnPaint(wxPaintEvent& event) {
+    wxPaintDC dc(m_view);
+
+    wxScrollBar *hscroll = m_dyn_sash->GetHScrollBar(this);
+    wxScrollBar *vscroll = m_dyn_sash->GetVScrollBar(this);
+
+    dc.Clear();
+    dc.SetDeviceOrigin(-hscroll->GetThumbPosition(), -vscroll->GetThumbPosition());
+
+    if (m_choice->GetSelection()) {
+        dc.DrawLine(20, 20, 280, 20);
+        dc.DrawLine(280, 20, 280, 280);
+        dc.DrawLine(280, 280, 20, 280);
+        dc.DrawLine(20, 280, 20, 20);
+    } else {
+        dc.DrawLine(150, 20, 280, 280);
+        dc.DrawLine(280, 280, 20, 280);
+        dc.DrawLine(20, 280, 150, 20);
+    }
+}
+
+void SwitchView::OnErase(wxEraseEvent& event) {
+    // Do nothing
+}
+
+void SwitchView::OnSplit(wxDynamicSashSplitEvent& event) {
+    SwitchView *view = new SwitchView(m_dyn_sash);
+    view->m_choice->SetSelection(m_choice->GetSelection());
+
+    wxScrollBar *hscroll = m_dyn_sash->GetHScrollBar(this);
+    wxScrollBar *vscroll = m_dyn_sash->GetVScrollBar(this);
+
+    hscroll->SetEventHandler(this);
+    vscroll->SetEventHandler(this);
+}
+
+void SwitchView::OnUnify(wxDynamicSashUnifyEvent& event) {
+    wxScrollBar *hscroll = m_dyn_sash->GetHScrollBar(this);
+    wxScrollBar *vscroll = m_dyn_sash->GetVScrollBar(this);
+
+    hscroll->SetEventHandler(this);
+    vscroll->SetEventHandler(this);
+}
+
+void SwitchView::OnChoice(wxCommandEvent& event) {
+    m_view->Refresh();
+}
+
+void SwitchView::OnScroll(wxScrollEvent& event) {
+    m_view->Refresh();
+}
+
+void SwitchView::OnFocus(wxFocusEvent& event) {
+    wxScrollBar *hscroll = m_dyn_sash->GetHScrollBar(this);
+    wxScrollBar *vscroll = m_dyn_sash->GetVScrollBar(this);
+
+    if (event.m_eventObject == hscroll || event.m_eventObject == vscroll) {
+        m_view->SetFocus();
+    } else {
+        event.Skip();
+    }
+}
+
+
+
+bool SwitchDemo::OnInit() {
+    wxFrame *frame;
+    wxDynamicSashWindow *dyn;
+
+    frame = new wxFrame(NULL, -1, "Dynamic Sash Window Switch Demo");
+    dyn = new wxDynamicSashWindow(frame, -1, wxDefaultPosition, wxDefaultSize, wxCLIP_CHILDREN);
+    new SwitchView(dyn);
+
+    frame->SetSize(480, 480);
+    frame->Show();
+
+    return TRUE;
+}
index cacdb63d7ba7d2adb2a8354c5b45c2a66b3044d4..2b60bbe078aec748954732bd1bd287335012814d 100644 (file)
@@ -97,6 +97,10 @@ SOURCE=..\..\include\wx\gizmos\editlbox.h
 
 SOURCE=..\..\include\wx\gizmos\splittree.h
 # End Source File
+# Begin Source File
+
+SOURCE=..\..\include\wx\gizmos\dynamicsash.h
+# End Source File
 # End Group
 # Begin Source File
 
@@ -110,5 +114,9 @@ SOURCE=.\editlbox.cpp
 
 SOURCE=.\splittree.cpp
 # End Source File
+# Begin Source File
+
+SOURCE=.\dynamicsash.cpp
+# End Source File
 # End Target
 # End Project
index b015c7d15f578b070ca6a7157b90e33a410781b7..a307c535761ddee6df473a49db2e5191768e63f0 100644 (file)
@@ -13,9 +13,9 @@ LIBVERSION_AGE=0
 HEADER_PATH=$(top_srcdir)/contrib/include/wx
 HEADER_SUBDIR=gizmos
 
-HEADERS=multicell.h splittree.h editlbox.h
+HEADERS=multicell.h splittree.h editlbox.h dynamicsash.h
 
-OBJECTS=multicell.o splittree.o editlbox.o
+OBJECTS=multicell.o splittree.o editlbox.o dynamicsash.o
 
 APPEXTRADEFS=-I$(top_srcdir)/contrib/include
 
diff --git a/contrib/src/gizmos/dynamicsash.cpp b/contrib/src/gizmos/dynamicsash.cpp
new file mode 100644 (file)
index 0000000..3787b4d
--- /dev/null
@@ -0,0 +1,1242 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        dynamicsash.cpp
+// Purpose:     A window which can be dynamically split to an arbitrary depth
+//              and later reunified through the user interface
+// Author:      Matt Kimball
+// Modified by:
+// Created:     7/15/2001
+// RCS-ID:      $Id$
+// Copyright:   (c) 2001 Matt Kimball
+// Licence:     wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+#include "wx/gizmos/dynamicsash.h"
+
+/*
+    wxDynamicSashWindow works by internally storing a tree of Implementation
+    objects (wxDynamicSsahWindowImpl) and Leaf objects
+    (wxDynamicSashWindowLeaf).  The wxDynamicSashWindow has a pointer to one
+    implementation, and each implementation either has a pointer to a one
+    leaf (m_leaf) or a pointer to two children implementation objects
+    (m_child).  The leaves each are responsible for drawing the frame and
+    decorations around one user-provided views and for responding to mouse
+    and scrollbar events.
+
+    A resulting tree might look something like this:
+
+    wxDynamicSashWindow
+     |
+     +- wxDynamicSashWindowImpl
+         |
+         +- wxDynamicSashWindowLeaf
+         |   |
+         |   +- user view window
+         |
+         +- wxDynamicSashWindowImpl
+             |
+             +- wxDynamicSashWindowLeaf
+             |   |
+             |   +- user view window
+             |
+             +- wxDynamicSashWindowLeaf
+                 |
+                 +- user view window
+
+    Each time a split occurs, one of the implementation objects removes its
+    leaf, generates two new implementation object children, each with a new
+    leaf, and reparents the user view which was connected to its old leaf
+    to be one of the new leaf's user view, and sends a Split event to the
+    user view in the hopes that it will generate a new user view for the
+    other new leaf.
+
+    When a unification ocurrs, an implementation object is replaced by one
+    of its children, and the tree of its other child is pruned.
+
+    One quirk is that the top-level implementation object (m_top) always
+    keeps a pointer to the implementation object where a new child is needed.
+    (m_add_child_target).  This is so that when a new uesr view is added
+    to the hierarchy, AddChild() is able to reparent the new user view to
+    the correct implementation object's leaf.
+
+*/
+
+#include <wx/dcmemory.h>
+#include <wx/dcscreen.h>
+#include <wx/layout.h>
+#include <wx/scrolbar.h>
+#include <wx/settings.h>
+
+
+#define wxEVT_DYNAMIC_SASH_PRIVATE          (wxEVT_DYNAMIC_SASH_BASE + 8)
+#define wxEVT_DYNAMIC_SASH_REPARENT         (wxEVT_DYNAMIC_SASH_PRIVATE + 1)
+
+
+/*
+    wxDynamicSashReparentEvent is generated by the AddChild() method of
+    wxDynamicSashWindow when it wants a Leaf to reparent a user view window
+    to its viewport at some time in the future.  We can't reparent the window
+    immediately, because switching parents in AddChild() confuses the wxWindow
+    class.  Instead, we queue up this event, and the window is actually
+    reparented the next time we process events in the idle loop.
+*/
+class wxDynamicSashReparentEvent : public wxEvent {
+public:
+    wxDynamicSashReparentEvent();
+    wxDynamicSashReparentEvent(wxObject *object);
+
+    DECLARE_DYNAMIC_CLASS(wxDynamicSashReparentEvent);
+};
+
+
+enum DynamicSashRegion {
+    DSR_NONE,
+    DSR_VERTICAL_TAB,
+    DSR_HORIZONTAL_TAB,
+    DSR_CORNER,
+    DSR_LEFT_EDGE,
+    DSR_TOP_EDGE,
+    DSR_RIGHT_EDGE,
+    DSR_BOTTOM_EDGE
+};
+
+
+class wxDynamicSashWindowImpl : public wxEvtHandler {
+public:
+    wxDynamicSashWindowImpl(wxDynamicSashWindow *window);
+    ~wxDynamicSashWindowImpl();
+
+    bool Create();
+    void AddChild(wxWindow *window);
+    void DrawSash(int x, int y) const;
+    void ConstrainChildren(int px, int py);
+    void Split(int x, int y);
+    void Unify(int panel);
+    void Resize(int x, int y);
+    wxDynamicSashWindowImpl *FindParent(DynamicSashRegion side) const;
+    wxDynamicSashWindowImpl *FindUpperParent(wxDynamicSashWindowImpl *sash_a,
+                                             wxDynamicSashWindowImpl *sash_b) const;
+    wxWindow *FindFrame() const;
+    wxScrollBar *FindScrollBar(const wxWindow *child, int vert) const;
+
+    void OnSize(wxSizeEvent &event);
+    void OnPaint(wxPaintEvent &event);
+    void OnMouseMove(wxMouseEvent &event);
+    void OnLeave(wxMouseEvent &event);
+    void OnPress(wxMouseEvent &event);
+    void OnRelease(wxMouseEvent &event);
+
+    wxDynamicSashWindow *m_window;
+    wxDynamicSashWindowImpl *m_add_child_target;
+
+    /*  This is the window we are responsible for managing.  Either of
+        leaf or our children are in this window.  For the top level
+        implementation object, this is the same as m_window.
+        Otherwise it is a window we've created an will destroy when we
+        are deleted.  */
+    wxWindow *m_container;
+
+    wxDynamicSashWindowImpl *m_parent;
+    wxDynamicSashWindowImpl *m_top;
+    wxDynamicSashWindowImpl *m_child[2];
+
+    class wxDynamicSashWindowLeaf *m_leaf;
+
+    /*  If the implementation is split horizontally or vertically, m_split
+        is set to DSR_HORIZONTAL_TAB or DSR_VERTICAL_TAB, respectively.
+        Otherwise it is set to DSR_NONE.  */
+    DynamicSashRegion m_split;
+
+    /*  These are used to keep track of a sash as it is being dragged, for
+        drawing the user interface correctly.  */
+    DynamicSashRegion m_dragging;
+    int m_drag_x, m_drag_y;
+};
+
+class wxDynamicSashWindowLeaf : public wxEvtHandler {
+public:
+    wxDynamicSashWindowLeaf(wxDynamicSashWindowImpl *impl);
+    ~wxDynamicSashWindowLeaf();
+
+    bool Create();
+    void AddChild(wxWindow *window);
+    DynamicSashRegion GetRegion(int x, int y);
+    void ResizeChild(wxSize size);
+    wxScrollBar *FindScrollBar(const wxWindow *child, int vert) const;
+
+    void OnSize(wxSizeEvent &event);
+    void OnPaint(wxPaintEvent &event);
+    void OnScroll(wxScrollEvent &event);
+    void OnFocus(wxFocusEvent &event);
+    void OnMouseMove(wxMouseEvent &event);
+    void OnLeave(wxMouseEvent &event);
+    void OnPress(wxMouseEvent &event);
+    void OnRelease(wxMouseEvent &event);
+    void OnReparent(wxEvent &event);
+
+    wxDynamicSashWindowImpl *m_impl;
+
+    wxScrollBar *m_vscroll, *m_hscroll;
+
+    /*  m_child is the window provided to us by the application developer.
+        m_viewport is a window we've created, and it is the immediately
+        parent of m_child.  We scroll m_child by moving it around within
+        m_viewport.  */
+    wxWindow *m_viewport, *m_child;
+};
+
+// wxDynamicSashWindow //////////////////////////////////////////////////////
+
+wxDynamicSashWindow::wxDynamicSashWindow() {
+    m_impl = NULL;
+}
+
+wxDynamicSashWindow::wxDynamicSashWindow(wxWindow *parent, wxWindowID id,
+                                         const wxPoint& pos, const wxSize& size,
+                                         long style, const wxString& name) {
+    m_impl = NULL;
+    Create(parent, id, pos, size, style, name);
+}
+
+wxDynamicSashWindow::~wxDynamicSashWindow() {
+    SetEventHandler(this);
+    delete m_impl;
+}
+
+bool wxDynamicSashWindow::Create(wxWindow *parent, wxWindowID id,
+                                 const wxPoint& pos, const wxSize& size,
+                                 long style, const wxString& name) {
+    if (m_impl)
+        return FALSE;
+
+    if (!wxWindow::Create(parent, id, pos, size, style, name))
+        return FALSE;
+
+    m_impl = new wxDynamicSashWindowImpl(this);
+    if (!m_impl)
+        return FALSE;
+
+    if (!m_impl->Create()) {
+        delete m_impl;
+        m_impl = NULL;
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+void wxDynamicSashWindow::AddChild(wxWindowBase *child) {
+    wxWindow::AddChild(child);
+
+    m_impl->AddChild(wxDynamicCast(child, wxWindow));
+}
+
+wxScrollBar *wxDynamicSashWindow::GetHScrollBar(const wxWindow *child) const {
+    return m_impl->FindScrollBar(child, 0);
+}
+
+wxScrollBar *wxDynamicSashWindow::GetVScrollBar(const wxWindow *child) const {
+    return m_impl->FindScrollBar(child, 1);
+}
+
+IMPLEMENT_DYNAMIC_CLASS(wxDynamicSashWindow, wxWindow)
+
+// wxDynamicSashWindowImpl //////////////////////////////////////////////////
+
+wxDynamicSashWindowImpl::wxDynamicSashWindowImpl(wxDynamicSashWindow *window) {
+    m_window = window;
+    m_add_child_target = this;
+
+    m_container = NULL;
+    m_parent = NULL;
+    m_top = this;
+    m_child[0] = m_child[1] = NULL;
+    m_leaf = NULL;
+    m_dragging = DSR_NONE;
+    m_split = DSR_NONE;
+}
+
+wxDynamicSashWindowImpl::~wxDynamicSashWindowImpl() {
+    delete m_leaf;
+    delete m_child[0];
+    m_child[0] = NULL;
+    delete m_child[1];
+    m_child[1] = NULL;
+    m_leaf = NULL;
+
+    if (m_container != m_window && m_container) {
+        m_container->SetEventHandler(m_container);
+        m_container->Destroy();
+    }
+}
+
+bool wxDynamicSashWindowImpl::Create() {
+    if (!m_container) {
+        m_container = m_window;
+    }
+
+    wxCursor cursor(wxCURSOR_ARROW);
+    m_container->SetCursor(cursor);
+
+    m_leaf = new wxDynamicSashWindowLeaf(this);
+    if (!m_leaf)
+        return FALSE;
+
+    if (!m_leaf->Create()) {
+        delete m_leaf;
+        m_leaf = NULL;
+        return FALSE;
+    }
+
+    m_container->SetEventHandler(this);
+
+    Connect(-1, wxEVT_SIZE, (wxObjectEventFunction)&wxDynamicSashWindowImpl::OnSize);
+    Connect(-1, wxEVT_PAINT, (wxObjectEventFunction)&wxDynamicSashWindowImpl::OnPaint);
+    Connect(-1, wxEVT_MOTION, (wxObjectEventFunction)&wxDynamicSashWindowImpl::OnMouseMove);
+    Connect(-1, wxEVT_ENTER_WINDOW, (wxObjectEventFunction)&wxDynamicSashWindowImpl::OnMouseMove);
+    Connect(-1, wxEVT_LEAVE_WINDOW, (wxObjectEventFunction)&wxDynamicSashWindowImpl::OnLeave);
+    Connect(-1, wxEVT_LEFT_DOWN, (wxObjectEventFunction)&wxDynamicSashWindowImpl::OnPress);
+    Connect(-1, wxEVT_LEFT_UP, (wxObjectEventFunction)&wxDynamicSashWindowImpl::OnRelease);
+
+    return TRUE;
+}
+
+void wxDynamicSashWindowImpl::AddChild(wxWindow *window) {
+    if (m_add_child_target && m_add_child_target->m_leaf) {
+        m_add_child_target->m_leaf->AddChild(window);
+    }
+}
+
+void wxDynamicSashWindowImpl::DrawSash(int x, int y) const {
+    int i, j;
+
+    wxScreenDC dc;
+    dc.StartDrawingOnTop(m_container);
+
+    wxBitmap bmp(8, 8);
+    wxMemoryDC bdc;
+    bdc.SelectObject(bmp);
+    bdc.DrawRectangle(-1, -1, 10, 10);
+    for (i = 0; i < 8; i++) {
+        for (j = 0; j < 8; j++) {
+            if ((i + j) & 1) {
+                bdc.DrawPoint(i, j);
+            }
+        }
+    }
+
+    wxBrush brush(bmp);
+    dc.SetBrush(brush);
+    dc.SetLogicalFunction(wxXOR);
+
+    if (m_dragging == DSR_CORNER) {
+        int cx = 0;
+        int cy = 0;
+
+        m_container->ClientToScreen(&cx, &cy);
+        m_container->ClientToScreen(&x, &y);
+
+        if (cx < x && cy < y) {
+            dc.DrawRectangle(cx - 2, cy - 2, x - cx + 4, 4);
+            dc.DrawRectangle(x - 2, cy + 2, 4, y - cy);
+            dc.DrawRectangle(cx - 2, cy + 2, 4, y - cy);
+            dc.DrawRectangle(cx + 2, y - 2, x - cx - 4, 4);
+        }
+    } else {
+        int body_w, body_h;
+        m_container->GetClientSize(&body_w, &body_h);
+
+        if (y < 0)
+            y = 0;
+        if (y > body_h)
+            y = body_h;
+        if (x < 0)
+            x = 0;
+        if (x > body_w)
+            x = body_w;
+
+        if (m_dragging == DSR_HORIZONTAL_TAB)
+            x = 0;
+        else
+            y = 0;
+
+        m_container->ClientToScreen(&x, &y);
+
+        int w, h;
+        w = body_w;  h = body_h;
+
+        if (m_dragging == DSR_HORIZONTAL_TAB)
+            dc.DrawRectangle(x, y - 2, w, 4);
+        else
+            dc.DrawRectangle(x - 2, y, 4, h);
+    }
+
+    dc.EndDrawingOnTop();
+}
+
+wxDynamicSashWindowImpl *wxDynamicSashWindowImpl::FindParent(DynamicSashRegion side) const {
+    if (m_parent == NULL) {
+        return NULL;
+    }
+
+    if (m_parent->m_split == DSR_HORIZONTAL_TAB) {
+        if (side == DSR_TOP_EDGE && m_parent->m_child[1] == this)
+            return m_parent;
+        if (side == DSR_BOTTOM_EDGE && m_parent->m_child[0] == this)
+            return m_parent;
+    } else if (m_parent->m_split == DSR_VERTICAL_TAB) {
+        if (side == DSR_LEFT_EDGE && m_parent->m_child[1] == this)
+            return m_parent;
+        if (side == DSR_RIGHT_EDGE && m_parent->m_child[0] == this)
+            return m_parent;
+    }
+
+    return m_parent->FindParent(side);
+}
+
+wxDynamicSashWindowImpl *wxDynamicSashWindowImpl::FindUpperParent(wxDynamicSashWindowImpl *sash_a,
+                                                                  wxDynamicSashWindowImpl *sash_b) const {
+    wxWindow *win;
+    win = sash_a->m_container->GetParent();
+    while (win && !win->IsTopLevel()) {
+        if (win == sash_b->m_container) {
+            return sash_b;
+        }
+
+        win = win->GetParent();
+    }
+
+    return sash_a;
+}
+
+
+wxWindow *wxDynamicSashWindowImpl::FindFrame() const {
+    wxWindow *win;
+
+    win = m_window->GetParent();
+    while (win && !win->IsTopLevel()) {
+        win = win->GetParent();
+    }
+
+    return win;
+}
+
+wxScrollBar *wxDynamicSashWindowImpl::FindScrollBar(const wxWindow *child, int vert) const {
+    if (m_child[0] == NULL && m_leaf == NULL) {
+        return NULL;
+    }
+
+    if (!m_child[0]) {
+        return m_leaf->FindScrollBar(child, vert);
+    } else {
+        wxScrollBar *ret = m_child[0]->FindScrollBar(child, vert);
+        if (!ret) {
+            ret = m_child[1]->FindScrollBar(child, vert);
+        }
+
+        return ret;
+    }
+}
+
+void wxDynamicSashWindowImpl::ConstrainChildren(int px, int py) {
+    wxLayoutConstraints *layout = new wxLayoutConstraints();
+    layout->left.SameAs(m_container, wxLeft);
+    layout->top.SameAs(m_container, wxTop);
+    if (m_split == DSR_HORIZONTAL_TAB) {
+        layout->right.SameAs(m_container, wxRight);
+        layout->height.PercentOf(m_container, wxHeight, py);
+    } else {
+        layout->bottom.SameAs(m_container, wxBottom);
+        layout->width.PercentOf(m_container, wxWidth, px);
+    }
+    m_child[0]->m_container->SetConstraints(layout);
+
+    layout = new wxLayoutConstraints();
+    layout->right.SameAs(m_container, wxRight);
+    layout->bottom.SameAs(m_container, wxBottom);
+    if (m_split == DSR_HORIZONTAL_TAB) {
+        layout->top.Below(m_child[0]->m_container, 1);
+        layout->left.SameAs(m_container, wxLeft);
+    } else {
+        layout->left.RightOf(m_child[0]->m_container, 1);
+        layout->top.SameAs(m_container, wxTop);
+    }
+    m_child[1]->m_container->SetConstraints(layout);
+}
+
+void wxDynamicSashWindowImpl::Unify(int panel) {
+    int other = 0;
+    if (panel == 0) {
+        other = 1;
+    }
+
+    if (m_child[panel]->m_leaf) {
+        wxDynamicSashWindowImpl *child[2];
+
+        child[0] = m_child[0];
+        child[1] = m_child[1];
+
+        m_child[0] = m_child[1] = NULL;
+
+        m_leaf = new wxDynamicSashWindowLeaf(this);
+        m_leaf->Create();
+        m_leaf->m_child = child[panel]->m_leaf->m_child;
+
+        m_leaf->m_vscroll->SetScrollbar(child[panel]->m_leaf->m_vscroll->GetThumbPosition(),
+                                        child[panel]->m_leaf->m_vscroll->GetThumbSize(),
+                                        child[panel]->m_leaf->m_vscroll->GetRange(),
+                                        child[panel]->m_leaf->m_vscroll->GetPageSize());
+        m_leaf->m_hscroll->SetScrollbar(child[panel]->m_leaf->m_hscroll->GetThumbPosition(),
+                                        child[panel]->m_leaf->m_hscroll->GetThumbSize(),
+                                        child[panel]->m_leaf->m_hscroll->GetRange(),
+                                        child[panel]->m_leaf->m_hscroll->GetPageSize());
+        m_add_child_target = NULL;
+        wxDynamicSashReparentEvent event(m_leaf);
+        m_leaf->ProcessEvent(event);
+
+        delete child[0];
+        delete child[1];
+
+        m_split = DSR_NONE;
+
+        wxDynamicSashUnifyEvent unify(m_leaf->m_child);
+        m_leaf->m_child->ProcessEvent(unify);
+    } else {
+        m_split = m_child[panel]->m_split;
+
+        delete m_child[other];
+
+        wxDynamicSashWindowImpl *child_panel = m_child[panel];
+        m_child[0] = child_panel->m_child[0];
+        m_child[1] = child_panel->m_child[1];
+
+        m_child[0]->m_parent = this;
+        m_child[1]->m_parent = this;
+
+        m_add_child_target = NULL;
+        m_child[0]->m_container->Reparent(m_container);
+        m_child[1]->m_container->Reparent(m_container);
+
+        child_panel->m_child[0] = child_panel->m_child[1] = NULL;
+        delete child_panel;
+
+        wxSize size = m_container->GetSize();
+        wxSize child_size = m_child[0]->m_container->GetSize();
+
+        ConstrainChildren(child_size.GetWidth() * 100 / size.GetWidth(),
+                            child_size.GetHeight() * 100 / size.GetHeight());
+
+        m_container->Layout();
+    }
+}
+
+void wxDynamicSashWindowImpl::Split(int px, int py) {
+    m_window->Hide();
+
+    m_add_child_target = NULL;
+
+    m_child[0] = new wxDynamicSashWindowImpl(m_window);
+    m_child[0]->m_container = new wxWindow(m_container, -1);
+    m_child[0]->m_parent = this;
+    m_child[0]->m_top = m_top;
+    m_child[0]->Create();
+    if (m_leaf->m_child) {
+        m_leaf->m_child->Reparent(m_container);
+        m_child[0]->AddChild(m_leaf->m_child);
+    }
+
+    m_child[1] = new wxDynamicSashWindowImpl(m_window);
+    m_child[1]->m_container = new wxWindow(m_container, -1);
+    m_child[1]->m_parent = this;
+    m_child[1]->m_top = m_top;
+    m_child[1]->Create();
+
+    m_split = m_dragging;
+    ConstrainChildren(px, py);
+
+    m_top->m_add_child_target = m_child[1];
+    wxDynamicSashSplitEvent split(m_child[0]->m_leaf->m_child);
+    m_child[0]->m_leaf->m_child->ProcessEvent(split);
+
+    m_child[0]->m_leaf->m_vscroll->SetScrollbar(m_leaf->m_vscroll->GetThumbPosition(),
+                                                m_leaf->m_vscroll->GetThumbSize(),
+                                                m_leaf->m_vscroll->GetRange(),
+                                                m_leaf->m_vscroll->GetPageSize());
+    m_child[0]->m_leaf->m_hscroll->SetScrollbar(m_leaf->m_hscroll->GetThumbPosition(),
+                                                m_leaf->m_hscroll->GetThumbSize(),
+                                                m_leaf->m_hscroll->GetRange(),
+                                                m_leaf->m_hscroll->GetPageSize());
+    m_child[1]->m_leaf->m_vscroll->SetScrollbar(m_leaf->m_vscroll->GetThumbPosition(),
+                                                m_leaf->m_vscroll->GetThumbSize(),
+                                                m_leaf->m_vscroll->GetRange(),
+                                                m_leaf->m_vscroll->GetPageSize());
+    m_child[1]->m_leaf->m_hscroll->SetScrollbar(m_leaf->m_hscroll->GetThumbPosition(),
+                                                m_leaf->m_hscroll->GetThumbSize(),
+                                                m_leaf->m_hscroll->GetRange(),
+                                                m_leaf->m_hscroll->GetPageSize());
+    delete m_leaf;
+    m_leaf = NULL;
+
+    m_container->Layout();
+
+    m_window->Show();
+}
+
+/*  This code is called when you finish resizing a view by dragging the
+    corner tab, but I think this implementation is lousy and will surprise
+    the user more often than it will do what they are trying to do.  What
+    I really need to be doing here is do a rewrite such that *no* sashes
+    move except the ones immediately to the bottom and right of this window,
+    and handle the case where you resize a window larger than it's neighbors
+    by destroying the neighbors.
+
+    But this will do for now.  */
+void wxDynamicSashWindowImpl::Resize(int x, int y) {
+    wxDynamicSashWindowImpl *h_parent = FindParent(DSR_BOTTOM_EDGE);
+    wxDynamicSashWindowImpl *v_parent = FindParent(DSR_RIGHT_EDGE);
+    int h_unify = -1;
+    int v_unify = -1;
+    wxWindow *frame = FindFrame();
+
+    if (x < 0) {
+        x = 0;
+    }
+    if (y < 0) {
+        y = 0;
+    }
+
+    if (h_parent) {
+        m_container->ClientToScreen(NULL, &y);
+        h_parent->m_container->ScreenToClient(NULL, &y);
+
+        int py = (int)((y * 100) / h_parent->m_container->GetSize().GetHeight() + 0.5);
+
+        if (py < 10) {
+            wxDynamicSashWindowImpl *ho_parent = FindParent(DSR_TOP_EDGE);
+
+            if (ho_parent) {
+                if (FindUpperParent(h_parent, ho_parent) == ho_parent) {
+                    h_unify = 1;
+                } else {
+                    py = (int)((ho_parent->m_child[0]->m_container->GetSize().GetHeight() * 100)
+                                / h_parent->m_container->GetSize().GetHeight() + 0.5);
+                    h_parent->m_child[0]->m_container->GetConstraints()->height.PercentOf(
+                            h_parent->m_container, wxHeight, py);
+
+                    h_parent = ho_parent;
+                    h_unify = 0;
+                }
+            } else {
+                h_unify = 1;
+            }
+        } else if (py > 90) {
+            h_unify = 0;
+        } else {
+            h_parent->m_child[0]->m_container->GetConstraints()->height.PercentOf(
+                    h_parent->m_container, wxHeight, py);
+            h_parent->m_container->Layout();
+        }
+    } else {
+        int do_resize = 1;
+        h_parent = FindParent(DSR_TOP_EDGE);
+
+        if (h_parent) {
+            int py = (int)((y * 100) /
+                        (h_parent->m_container->GetSize().GetHeight() +
+                                y - m_container->GetSize().GetHeight()) + 0.5);
+
+            if (py < 10) {
+                h_unify = 0;
+            }
+        } else if (y < 64) {
+            do_resize = 0;
+        }
+
+        if (do_resize) {
+            wxSize size = frame->GetSize();
+            frame->SetSize(size.GetWidth(), size.GetHeight() + y - m_container->GetSize().GetHeight());
+        }
+    }
+
+    if (v_parent) {
+        m_container->ClientToScreen(&x, NULL);
+        v_parent->m_container->ScreenToClient(&x, NULL);
+
+        int px = (int)((x * 100) / v_parent->m_container->GetSize().GetWidth() + 0.5);
+
+        if (px < 10) {
+            wxDynamicSashWindowImpl *vo_parent = FindParent(DSR_LEFT_EDGE);
+
+            if (vo_parent) {
+                if (FindUpperParent(v_parent, vo_parent) == vo_parent) {
+                    v_unify = 1;
+                } else {
+                    px = (int)((vo_parent->m_child[0]->m_container->GetSize().GetWidth() * 100)
+                                / v_parent->m_container->GetSize().GetWidth() + 0.5);
+                    v_parent->m_child[0]->m_container->GetConstraints()->width.PercentOf(
+                            v_parent->m_container, wxWidth, px);
+
+                    v_parent = vo_parent;
+                    v_unify = 0;
+                }
+            } else {
+                v_unify = 1;
+            }
+        } else if (px > 90) {
+            v_unify = 0;
+        } else {
+            v_parent->m_child[0]->m_container->GetConstraints()->width.PercentOf(
+                    v_parent->m_container, wxWidth, px);
+            v_parent->m_container->Layout();
+        }
+    } else {
+        int do_resize = 1;
+        v_parent = FindParent(DSR_LEFT_EDGE);
+
+        if (v_parent) {
+            int px = (int)((x * 100) /
+                        (v_parent->m_container->GetSize().GetWidth() +
+                                x - m_container->GetSize().GetWidth()) + 0.5);
+
+            if (px < 10) {
+                v_unify = 0;
+            }
+        } else if (x < 64) {
+            do_resize = 0;
+        }
+
+        if (do_resize) {
+            wxSize size = frame->GetSize();
+            frame->SetSize(size.GetWidth() + x - m_container->GetSize().GetWidth(), size.GetHeight());
+        }
+    }
+
+    if (h_unify != -1 && v_unify != -1) {
+        wxDynamicSashWindowImpl *parent = FindUpperParent(h_parent, v_parent);
+
+        if (parent == h_parent) {
+            h_parent->Unify(h_unify);
+        } else {
+            v_parent->Unify(v_unify);
+        }
+    } else if (h_unify != -1) {
+        h_parent->Unify(h_unify);
+    } else if (v_unify != -1) {
+        v_parent->Unify(v_unify);
+    }
+}
+
+
+void wxDynamicSashWindowImpl::OnSize(wxSizeEvent &event) {
+    m_container->Layout();
+
+    if (m_leaf)
+        m_leaf->OnSize(event);
+}
+
+void wxDynamicSashWindowImpl::OnPaint(wxPaintEvent &event) {
+    if (m_leaf)
+        m_leaf->OnPaint(event);
+    else {
+        wxPaintDC dc(m_container);
+        dc.SetBackground(wxBrush(m_container->GetBackgroundColour(), wxSOLID));
+        dc.Clear();
+    }
+}
+
+void wxDynamicSashWindowImpl::OnMouseMove(wxMouseEvent &event) {
+    if (m_dragging) {
+        DrawSash(m_drag_x, m_drag_y);
+        m_drag_x = event.m_x;  m_drag_y = event.m_y;
+        DrawSash(m_drag_x, m_drag_y);
+    } else if (m_leaf) {
+        m_leaf->OnMouseMove(event);
+    }
+}
+
+void wxDynamicSashWindowImpl::OnLeave(wxMouseEvent &event) {
+    if (m_leaf) {
+        m_leaf->OnLeave(event);
+    }
+}
+
+void wxDynamicSashWindowImpl::OnPress(wxMouseEvent &event) {
+    if (m_leaf) {
+        m_leaf->OnPress(event);
+    } else {
+        m_dragging = m_split;
+        m_drag_x = event.m_x;
+        m_drag_y = event.m_y;
+        DrawSash(m_drag_x, m_drag_y);
+        m_container->CaptureMouse();
+    }
+}
+
+void wxDynamicSashWindowImpl::OnRelease(wxMouseEvent &event) {
+    if (m_dragging == DSR_CORNER) {
+        DrawSash(m_drag_x, m_drag_y);
+        m_container->ReleaseMouse();
+
+        Resize(event.m_x, event.m_y);
+
+        m_dragging = DSR_NONE;
+    } else if (m_dragging) {
+        DrawSash(m_drag_x, m_drag_y);
+        m_container->ReleaseMouse();
+
+        wxSize size = m_container->GetSize();
+        int px = (int)((event.m_x * 100) / size.GetWidth() + 0.5);
+        int py = (int)((event.m_y * 100) / size.GetHeight() + 0.5);
+
+        if ((m_dragging == DSR_HORIZONTAL_TAB && py >= 10 && py <= 90)
+                    || (m_dragging == DSR_VERTICAL_TAB && px >= 10 && px <= 90)) {
+            if (m_child[0] == NULL) {
+                Split(px, py);
+            } else {
+                /*  It would be nice if moving *this* sash didn't implicitly move
+                    the sashes of our children (if any).  But this will do.  */
+                wxLayoutConstraints *layout = m_child[0]->m_container->GetConstraints();
+                if (m_split == DSR_HORIZONTAL_TAB) {
+                    layout->height.PercentOf(m_container, wxHeight, py);
+                } else {
+                    layout->width.PercentOf(m_container, wxWidth, px);
+                }
+                m_container->Layout();
+            }
+        } else {
+            if (m_child[0] != NULL) {
+                if ((m_dragging == DSR_HORIZONTAL_TAB && py <= 10)
+                        || (m_dragging == DSR_VERTICAL_TAB && px <= 10)) {
+                    Unify(1);
+                } else {
+                    Unify(0);
+                }
+            }
+        }
+
+        wxCursor cursor(wxCURSOR_ARROW);
+        if (m_split == DSR_HORIZONTAL_TAB) {
+            cursor = wxCursor(wxCURSOR_SIZENS);
+        } else if (m_split == DSR_VERTICAL_TAB) {
+            cursor = wxCursor(wxCURSOR_SIZEWE);
+        }
+        m_container->SetCursor(cursor);
+
+        m_dragging = DSR_NONE;
+    } else if (m_leaf) {
+        m_leaf->OnRelease(event);
+    }
+}
+
+// wxDynamicSashWindowLeaf //////////////////////////////////////////////////
+
+wxDynamicSashWindowLeaf::wxDynamicSashWindowLeaf(wxDynamicSashWindowImpl *impl) {
+    m_impl = impl;
+
+    m_hscroll = m_vscroll = NULL;
+    m_child = NULL;
+}
+
+wxDynamicSashWindowLeaf::~wxDynamicSashWindowLeaf() {
+    m_hscroll->SetEventHandler(m_hscroll);
+    m_vscroll->SetEventHandler(m_vscroll);
+    m_viewport->SetEventHandler(m_viewport);
+
+    m_hscroll->Destroy();
+    m_vscroll->Destroy();
+    m_viewport->Destroy();
+}
+
+bool wxDynamicSashWindowLeaf::Create() {
+    bool success;
+
+    m_hscroll = new wxScrollBar();
+    m_vscroll = new wxScrollBar();
+    m_viewport = new wxWindow();
+
+    if (!m_hscroll || !m_vscroll || !m_viewport) {
+        return FALSE;
+    }
+
+    wxDynamicSashWindowImpl *add_child_target = m_impl->m_add_child_target;
+    m_impl->m_add_child_target = NULL;
+    success = m_hscroll->Create(m_impl->m_container, -1, wxDefaultPosition, wxDefaultSize,
+                                wxSB_HORIZONTAL);
+    success = success && m_vscroll->Create(m_impl->m_container, -1, wxDefaultPosition, wxDefaultSize,
+                                            wxSB_VERTICAL);
+    success = success && m_viewport->Create(m_impl->m_container, -1);
+    m_impl->m_add_child_target = add_child_target;
+
+    wxCursor cursor(wxCURSOR_ARROW);
+    m_hscroll->SetCursor(cursor);
+    m_vscroll->SetCursor(cursor);
+    m_viewport->SetCursor(cursor);
+
+    m_viewport->SetEventHandler(this);
+    Connect(-1, wxEVT_DYNAMIC_SASH_REPARENT, (wxObjectEventFunction)&wxDynamicSashWindowLeaf::OnReparent);
+
+    if (m_impl->m_window->GetWindowStyle() & wxMANAGE_SCROLLBARS) {
+        m_hscroll->SetEventHandler(this);
+        m_vscroll->SetEventHandler(this);
+
+        Connect(-1, wxEVT_SET_FOCUS, (wxObjectEventFunction)&wxDynamicSashWindowLeaf::OnFocus);
+        Connect(-1, wxEVT_SCROLL_TOP, (wxObjectEventFunction)&wxDynamicSashWindowLeaf::OnScroll);
+        Connect(-1, wxEVT_SCROLL_BOTTOM, (wxObjectEventFunction)&wxDynamicSashWindowLeaf::OnScroll);
+        Connect(-1, wxEVT_SCROLL_LINEUP, (wxObjectEventFunction)&wxDynamicSashWindowLeaf::OnScroll);
+        Connect(-1, wxEVT_SCROLL_LINEDOWN, (wxObjectEventFunction)&wxDynamicSashWindowLeaf::OnScroll);
+        Connect(-1, wxEVT_SCROLL_PAGEUP, (wxObjectEventFunction)&wxDynamicSashWindowLeaf::OnScroll);
+        Connect(-1, wxEVT_SCROLL_PAGEDOWN, (wxObjectEventFunction)&wxDynamicSashWindowLeaf::OnScroll);
+        Connect(-1, wxEVT_SCROLL_THUMBTRACK, (wxObjectEventFunction)&wxDynamicSashWindowLeaf::OnScroll);
+        Connect(-1, wxEVT_SCROLL_THUMBRELEASE, (wxObjectEventFunction)&wxDynamicSashWindowLeaf::OnScroll);
+    }
+
+    wxLayoutConstraints *layout = new wxLayoutConstraints();
+    if (!layout)
+        return FALSE;
+    wxSize size = m_hscroll->GetBestSize();
+#ifdef __WXMSW__
+    size = m_hscroll->GetSize();
+#endif
+
+    layout->left.SameAs(m_impl->m_container, wxLeft, 10);
+    layout->right.LeftOf(m_vscroll);
+    layout->bottom.SameAs(m_impl->m_container, wxBottom, 3);
+    layout->height.Absolute(size.GetHeight());
+    m_hscroll->SetConstraints(layout);
+
+    layout = new wxLayoutConstraints();
+    if (!layout)
+        return FALSE;
+    size = size = m_vscroll->GetBestSize();
+#ifdef __WXMSW__
+    size = m_vscroll->GetSize();
+#endif
+
+    layout->top.SameAs(m_impl->m_container, wxTop, 10);
+    layout->bottom.Above(m_hscroll);
+    layout->right.SameAs(m_impl->m_container, wxRight, 3);
+    layout->width.Absolute(size.GetWidth());
+    m_vscroll->SetConstraints(layout);
+
+    layout = new wxLayoutConstraints();
+    if (!layout)
+        return FALSE;
+    layout->left.SameAs(m_impl->m_container, wxLeft, 3);
+    layout->right.LeftOf(m_vscroll);
+    layout->top.SameAs(m_impl->m_container, wxTop, 3);
+    layout->bottom.Above(m_hscroll);
+    m_viewport->SetConstraints(layout);
+
+    m_impl->m_container->Layout();
+
+    return success;
+}
+
+void wxDynamicSashWindowLeaf::AddChild(wxWindow *window) {
+    if (m_child) {
+        m_child->Destroy();
+    }
+
+    m_child = window;
+
+    wxDynamicSashReparentEvent event(this);
+    AddPendingEvent(event);
+}
+
+DynamicSashRegion wxDynamicSashWindowLeaf::GetRegion(int x, int y) {
+    wxSize size = m_impl->m_container->GetSize();
+    int w = size.GetWidth();
+    int h = size.GetHeight();
+    size = m_hscroll->GetSize();
+    int sh = size.GetHeight();
+    size = m_vscroll->GetSize();
+    int sw = size.GetWidth();
+
+    if (x >= w - sw - 3 && x < w && y >= h - sh - 3 && y < h)
+        return DSR_CORNER;
+    if (x >= 3 && x < 10 && y >= h - sh - 3 && y < h - 2)
+        return DSR_VERTICAL_TAB;
+    if (x >= w - sw - 3 && x < w - 2 && y >= 3 && y < 10)
+        return DSR_HORIZONTAL_TAB;
+    if (x < 3)
+        return DSR_LEFT_EDGE;
+    if (y < 3)
+        return DSR_TOP_EDGE;
+    if (x >= w - 2)
+        return DSR_RIGHT_EDGE;
+    if (y >= h - 2)
+        return DSR_BOTTOM_EDGE;
+
+    return DSR_NONE;
+}
+
+void wxDynamicSashWindowLeaf::ResizeChild(wxSize size) {
+    if (m_child) {
+        if (m_impl->m_window->GetWindowStyle() & wxMANAGE_SCROLLBARS) {
+            m_child->SetSize(size);
+            wxSize best_size = m_child->GetBestSize();
+            if (best_size.GetWidth() < size.GetWidth()) {
+                best_size.SetWidth(size.GetWidth());
+            }
+            if (best_size.GetHeight() < size.GetHeight()) {
+                best_size.SetHeight(size.GetHeight());
+            }
+            m_child->SetSize(best_size);
+
+            int hpos = m_hscroll->GetThumbPosition();
+            int vpos = m_vscroll->GetThumbPosition();
+
+            if (hpos < 0) {
+                hpos = 0;
+            }
+            if (vpos < 0) {
+                vpos = 0;
+            }
+            if (hpos > best_size.GetWidth() - size.GetWidth()) {
+                hpos = best_size.GetWidth() - size.GetWidth();
+            }
+            if (vpos > best_size.GetHeight() - size.GetHeight()) {
+                vpos = best_size.GetHeight() - size.GetHeight();
+            }
+
+            m_hscroll->SetScrollbar(hpos, size.GetWidth(),
+                                    best_size.GetWidth(), size.GetWidth());
+            m_vscroll->SetScrollbar(vpos, size.GetHeight(),
+                                    best_size.GetHeight(), size.GetHeight());
+
+            //  Umm, the scrollbars are doing something insane under GTK+ and subtracting
+            //  one from the position I pass in.  This works around that.
+            m_hscroll->SetThumbPosition(hpos + hpos - m_hscroll->GetThumbPosition());
+            m_vscroll->SetThumbPosition(vpos + vpos - m_vscroll->GetThumbPosition());
+
+            wxPoint pos = m_child->GetPosition();
+            m_viewport->ScrollWindow(-hpos - pos.x, -vpos - pos.y);
+        } else {
+            m_child->SetSize(size);
+        }
+    }
+}
+
+wxScrollBar *wxDynamicSashWindowLeaf::FindScrollBar(const wxWindow *child, int vert) const {
+    if (m_child == child) {
+        if (vert) {
+            return m_vscroll;
+        } else {
+            return m_hscroll;
+        }
+    }
+
+    return NULL;
+}
+
+void wxDynamicSashWindowLeaf::OnSize(wxSizeEvent &event) {
+    m_impl->m_container->Refresh();
+    ResizeChild(m_viewport->GetSize());
+}
+
+void wxDynamicSashWindowLeaf::OnPaint(wxPaintEvent &event) {
+    wxPaintDC dc(m_impl->m_container);
+    dc.SetBackground(wxBrush(m_impl->m_container->GetBackgroundColour(), wxSOLID));
+    dc.Clear();
+
+    wxPen highlight(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNHIGHLIGHT), 1, wxSOLID);
+    wxPen shadow(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNSHADOW), 1, wxSOLID);
+    wxPen black(*wxBLACK, 1, wxSOLID);
+
+    wxSize size = m_impl->m_container->GetSize();
+    int w = size.GetWidth();
+    int h = size.GetHeight();
+    size = m_hscroll->GetSize();
+    int sh = size.GetHeight();
+    size = m_vscroll->GetSize();
+    int sw = size.GetWidth();
+
+    dc.SetPen(shadow);
+    dc.DrawLine(1, 1, 1, h - 2);
+    dc.DrawLine(1, 1, w - 2, 1);
+    dc.SetPen(black);
+    dc.DrawLine(2, 2, 2, h - 3);
+    dc.DrawLine(2, 2, w - 3, 2);
+    dc.SetPen(highlight);
+    dc.DrawLine(w - 2, 2, w - 2, h - sh - 2);
+    dc.DrawLine(w - 2, h - sh - 2, w - sw - 2, h - sh - 2);
+    dc.DrawLine(w - sw - 2, h - sh - 2, w - sw - 2, h - 2);
+    dc.DrawLine(w - sw - 2, h - 2, 2, h - 2);
+
+    dc.SetPen(highlight);
+    dc.DrawLine(w - sw - 2, 8, w - sw - 2, 4);
+    dc.DrawLine(w - sw - 2, 4, w - 5, 4);
+    dc.SetPen(shadow);
+    dc.DrawLine(w - 5, 4, w - 5, 8);
+    dc.DrawLine(w - 5, 8, w - sw - 2, 8);
+    dc.SetPen(black);
+    dc.DrawLine(w - 4, 3, w - 4, 9);
+    dc.DrawLine(w - 4, 9, w - sw - 3, 9);
+
+    dc.SetPen(highlight);
+    dc.DrawLine(4, h - 5, 4, h - sh - 2);
+    dc.DrawLine(4, h - sh - 2, 8, h - sh - 2);
+    dc.SetPen(shadow);
+    dc.DrawLine(8, h - sh - 2, 8, h - 5);
+    dc.DrawLine(8, h - 5, 4, h - 5);
+    dc.SetPen(black);
+    dc.DrawLine(9, h - sh - 3, 9, h - 4);
+    dc.DrawLine(9, h - 4, 3, h - 4);
+
+
+    int cy = (h - sh + h - 6) / 2 + 1;
+    int cx = (w - sw + w - 6) / 2 + 1;
+    int sy = cy;
+    while (sy > h - sh)
+        sy -= 4;
+    int sx = cx;
+    while (sx > w - sw)
+        sx -= 4;
+
+    int x, y;
+    for (y = sy; y < h - 2; y += 4) {
+        for (x = sx; x < w - 2; x += 4) {
+            if (x - cx >= -(y - cy)) {
+                dc.SetPen(highlight);
+                dc.DrawPoint(x, y);
+                dc.SetPen(shadow);
+                dc.DrawPoint(x + 1, y + 1);
+            }
+        }
+    }
+}
+
+void wxDynamicSashWindowLeaf::OnScroll(wxScrollEvent &event) {
+    int nx = -m_hscroll->GetThumbPosition();
+    int ny = -m_vscroll->GetThumbPosition();
+
+    if (m_child) {
+        wxPoint pos = m_child->GetPosition();
+
+        m_viewport->ScrollWindow(nx - pos.x, ny - pos.y);
+    }
+}
+
+void wxDynamicSashWindowLeaf::OnFocus(wxFocusEvent &event) {
+    if (event.m_eventObject == m_hscroll || event.m_eventObject == m_vscroll) {
+        m_child->SetFocus();
+    }
+}
+
+
+void wxDynamicSashWindowLeaf::OnMouseMove(wxMouseEvent &event) {
+    if (m_impl->m_dragging) {
+        return;
+    }
+
+    DynamicSashRegion region = GetRegion(event.m_x, event.m_y);
+
+    wxCursor cursor(wxCURSOR_ARROW);
+    if (region == DSR_HORIZONTAL_TAB) {
+        cursor = wxCursor(wxCURSOR_SIZENS);
+    } else if (region == DSR_VERTICAL_TAB) {
+        cursor = wxCursor(wxCURSOR_SIZEWE);
+    } else if (region == DSR_CORNER) {
+        cursor = wxCursor(wxCURSOR_SIZENWSE);
+    } else if (region == DSR_LEFT_EDGE || region == DSR_TOP_EDGE
+                || region == DSR_RIGHT_EDGE || region == DSR_BOTTOM_EDGE) {
+        if (m_impl->FindParent(region)) {
+            if (region == DSR_LEFT_EDGE || region == DSR_RIGHT_EDGE) {
+                cursor = wxCursor(wxCURSOR_SIZEWE);
+            } else {
+                cursor = wxCursor(wxCURSOR_SIZENS);
+            }
+        }
+    }
+
+    m_impl->m_container->SetCursor(cursor);
+}
+
+void wxDynamicSashWindowLeaf::OnLeave(wxMouseEvent &event) {
+    wxCursor cursor(wxCURSOR_ARROW);
+    m_impl->m_container->SetCursor(cursor);
+}
+
+
+void wxDynamicSashWindowLeaf::OnPress(wxMouseEvent &event) {
+    DynamicSashRegion region = GetRegion(event.m_x, event.m_y);
+
+    if (region == DSR_HORIZONTAL_TAB || region == DSR_VERTICAL_TAB || region == DSR_CORNER) {
+        m_impl->m_dragging = region;
+        m_impl->m_drag_x = event.m_x;
+        m_impl->m_drag_y = event.m_y;
+        m_impl->DrawSash(event.m_x, event.m_y);
+        m_impl->m_container->CaptureMouse();
+    } else if (region == DSR_LEFT_EDGE || region == DSR_TOP_EDGE
+                || region == DSR_RIGHT_EDGE || region == DSR_BOTTOM_EDGE) {
+        wxDynamicSashWindowImpl *parent = m_impl->FindParent(region);
+
+        if (parent) {
+            int x = event.m_x;
+            int y = event.m_y;
+
+            m_impl->m_container->ClientToScreen(&x, &y);
+            parent->m_container->ScreenToClient(&x, &y);
+
+            parent->m_dragging = parent->m_split;
+            parent->m_drag_x = x;
+            parent->m_drag_y = y;
+            parent->DrawSash(x, y);
+            parent->m_container->CaptureMouse();
+        }
+    }
+}
+
+void wxDynamicSashWindowLeaf::OnRelease(wxMouseEvent &event) {
+}
+
+void wxDynamicSashWindowLeaf::OnReparent(wxEvent &event) {
+    if (m_child) {
+        m_child->Reparent(m_viewport);
+    }
+
+    ResizeChild(m_viewport->GetSize());
+}
+
+// wxDynamicSashSplitEvent //////////////////////////////////////////////////
+
+wxDynamicSashSplitEvent::wxDynamicSashSplitEvent() {
+    m_eventObject = NULL;
+    m_eventType = wxEVT_DYNAMIC_SASH_SPLIT;
+}
+
+wxDynamicSashSplitEvent::wxDynamicSashSplitEvent(wxObject *object) {
+    m_eventObject = object;
+    m_eventType = wxEVT_DYNAMIC_SASH_SPLIT;
+}
+
+IMPLEMENT_DYNAMIC_CLASS(wxDynamicSashSplitEvent, wxCommandEvent)
+
+// wxDynamicSashUnifyEvent //////////////////////////////////////////////////
+
+wxDynamicSashUnifyEvent::wxDynamicSashUnifyEvent() {
+    m_eventObject = NULL;
+    m_eventType = wxEVT_DYNAMIC_SASH_UNIFY;
+}
+
+wxDynamicSashUnifyEvent::wxDynamicSashUnifyEvent(wxObject *object) {
+    m_eventObject = object;
+    m_eventType = wxEVT_DYNAMIC_SASH_UNIFY;
+}
+
+IMPLEMENT_DYNAMIC_CLASS(wxDynamicSashUnifyEvent, wxCommandEvent)
+
+// wxDynamicSsahReparentEvent ///////////////////////////////////////////////
+
+wxDynamicSashReparentEvent::wxDynamicSashReparentEvent() {
+    m_eventObject = NULL;
+    m_eventType = wxEVT_DYNAMIC_SASH_REPARENT;
+}
+
+wxDynamicSashReparentEvent::wxDynamicSashReparentEvent(wxObject *object) {
+    m_eventObject = object;
+    m_eventType = wxEVT_DYNAMIC_SASH_REPARENT;
+}
+
+IMPLEMENT_DYNAMIC_CLASS(wxDynamicSashReparentEvent, wxEvent)
+
+/////////////////////////////////////////////////////////////////////////////
index b50cd162dabee2a428dc0d4570b55f31992270ba..75f719eb1ee5216389d232edf7cedb98a1ef84c3 100644 (file)
@@ -11,7 +11,7 @@ WXDIR = $(WXWIN)
 
 LIBTARGET=$(WXDIR)\lib\gizmos.lib
 
-OBJECTS = multicell.obj splittree.obj editlbox.obj
+OBJECTS = multicell.obj splittree.obj editlbox.obj dynamicsash.obj
 
 !include $(WXDIR)\src\makelib.b32
 
index 052c8b09c0a67e23e13223abe79eb03a6cd9d3b4..a9cbb5a799dc1382bca88678b3e3fee3f1642c02 100644 (file)
@@ -14,7 +14,7 @@ WXDIR = $(WXWIN)
 
 LIBTARGET=$(WXDIR)\lib\gizmos.lib
 
-OBJECTS = multicell.obj splittree.obj editlbox.obj
+OBJECTS = multicell.obj splittree.obj editlbox.obj dynamicsash.obj
 
 !include $(WXDIR)\src\makelib.bcc
 
index e28945428840c7731ba4338a345efd24f65a8073..5b5237e9fc336e3adedf8207d6dfabb4f471ed6f 100644 (file)
@@ -10,7 +10,7 @@
 WXDIR = ../../..
 
 LIBTARGET=$(WXDIR)/lib/libgizmos.a
-OBJECTS = multicell.o splittree.o editlbox.o
+OBJECTS = multicell.o splittree.o editlbox.o dynamicsash.o
 
 include $(WXDIR)/src/makelib.g95
 
index c1fae75d2ab62de6d0f57413ee741de436b39d4d..b070bc96afd382998bd7a10af7add2549f5b6b76 100644 (file)
@@ -16,7 +16,8 @@ LIB_CPP_SRC=\
 \
   multicell.o\
   editlbox.o\
-  splittree.o
+  splittree.o\
+  dynamicsash.o
 
 all:    $(GIZMOSLIB)
 
index 7aef83ead29800c723e6b0c3a4555e22e6a1f155..a7d0f925f4152da513768e67ea9d9b557b6705e6 100644 (file)
@@ -23,7 +23,7 @@ LOCALDOCDIR=$(WXDIR)\contrib\docs\latex\gizmos
 
 !include $(WXDIR)\src\makevc.env
 
-OBJECTS = $(D)\multicell.obj $(D)\splittree.obj $(D)\editlbox.obj
+OBJECTS = $(D)\multicell.obj $(D)\splittree.obj $(D)\editlbox.obj $(D)\dynamicsash.obj
 
 LIBTARGET=$(WXDIR)\lib\gizmos$(LIBEXT).lib
 
@@ -65,6 +65,11 @@ $(D)\editlbox.obj:      editlbox.$(SRCSUFF)
 $(CPPFLAGS) /c /Fo$@ /Tp $(*B).$(SRCSUFF)
 <<
 
+$(D)\dynamicsash.obj:      dynamicsash.$(SRCSUFF)
+        cl @<<
+$(CPPFLAGS) /c /Fo$@ /Tp $(*B).$(SRCSUFF)
+<<
+
 clean:
         -erase $(D)\*.obj
         -erase *.sbr
index 0d01935c1faf2d35f8ff1ba97de1dfada35891ac..3d3a85f6a468e40ed0f9bea0ba9b2892be16128c 100644 (file)
@@ -10,7 +10,7 @@ THISDIR = $(WXDIR)\contrib\src\gizmos
 NAME = gizmos
 LNK = $(name).lnk
 
-OBJECTS =  multicell.obj splittree.obj editlbox.obj
+OBJECTS =  multicell.obj splittree.obj editlbox.obj dynamicsash.obj
 
 all: $(GIZMOSLIB)