+/////////////////////////////////////////////////////////////////////////////
+// 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
+/////////////////////////////////////////////////////////////////////////////
+
+// For compilers that support precompilation, includes "wx/wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+ #pragma hdrstop
+#endif
+
+// for all others, include the necessary headers (this file is usually all you
+// need because it includes almost all "standard" wxWidgets headers)
+#ifndef WX_PRECOMP
+ #include "wx/wx.h"
+#endif
+
+#ifdef __WXMSW__
+#include "wx/mdi.h"
+#endif
+
+#include "wx/gizmos/dynamicsash.h"
+
+
+const wxChar* wxDynamicSashWindowNameStr = wxT("dynamicSashWindow");
+
+
+/*
+ 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"
+
+
+const wxEventType wxEVT_DYNAMIC_SASH_SPLIT = wxNewEventType();
+const wxEventType wxEVT_DYNAMIC_SASH_UNIFY = wxNewEventType();
+const wxEventType wxEVT_DYNAMIC_SASH_REPARENT = wxNewEventType();
+
+enum DynamicSashRegion
+{
+ DSR_NONE,
+ DSR_VERTICAL_TAB,
+ DSR_HORIZONTAL_TAB,
+ DSR_CORNER,
+ DSR_LEFT_EDGE,
+ DSR_TOP_EDGE,
+ DSR_RIGHT_EDGE,
+ DSR_BOTTOM_EDGE
+};
+
+
+/*
+ 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);
+ wxDynamicSashReparentEvent(const wxDynamicSashReparentEvent& evt);
+
+ virtual wxEvent* Clone() const { return new wxDynamicSashReparentEvent(*this); }
+
+ DECLARE_DYNAMIC_CLASS(wxDynamicSashReparentEvent)
+};
+
+
+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(const wxSize& size);
+ wxScrollBar *FindScrollBar(const wxWindow *child, int vert) const;
+
+ void OnSize(wxSizeEvent &event);
+ void OnViewSize(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(wxEVT_SIZE, wxSizeEventHandler(wxDynamicSashWindowImpl::OnSize));
+ Connect(wxEVT_PAINT, wxPaintEventHandler(wxDynamicSashWindowImpl::OnPaint));
+ Connect(wxEVT_MOTION,
+ wxMouseEventHandler(wxDynamicSashWindowImpl::OnMouseMove));
+ Connect(wxEVT_ENTER_WINDOW,
+ wxMouseEventHandler(wxDynamicSashWindowImpl::OnMouseMove));
+ Connect(wxEVT_LEAVE_WINDOW,
+ wxMouseEventHandler(wxDynamicSashWindowImpl::OnLeave));
+ Connect(wxEVT_LEFT_DOWN,
+ wxMouseEventHandler(wxDynamicSashWindowImpl::OnPress));
+ Connect(wxEVT_LEFT_UP,
+ wxMouseEventHandler(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) &&
+ (m_window->GetWindowStyle() & wxDS_DRAG_CORNER) != 0)
+ {
+ 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()
+#if defined(__WXMSW__) && wxUSE_MDI
+ && ! wxIsKindOf(win, wxMDIChildFrame) // not top-level but still a frame
+#endif
+ )
+ {
+ 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);
+ }
+
+ 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 = panel == 0 ? 1 : 0;
+
+ 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_add_child_target = NULL;
+
+ m_child[0] = new wxDynamicSashWindowImpl(m_window);
+ m_child[0]->m_container = new wxWindow(m_container, wxID_ANY);
+ 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, wxID_ANY);
+ 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();
+}
+
+
+/* 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) &&
+ (m_window->GetWindowStyle() & wxDS_DRAG_CORNER) != 0)
+ {
+ 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;
+ if (m_split == DSR_HORIZONTAL_TAB)
+ cursor = wxCursor(wxCURSOR_SIZENS);
+ else if (m_split == DSR_VERTICAL_TAB)
+ cursor = wxCursor(wxCURSOR_SIZEWE);
+ else
+ cursor = wxCursor(wxCURSOR_ARROW);
+
+ 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_hscroll->Destroy();
+ m_vscroll->Destroy();
+ m_viewport->Destroy();
+}
+
+bool wxDynamicSashWindowLeaf::Create()
+{
+ m_hscroll = new wxScrollBar();
+ m_vscroll = new wxScrollBar();
+ m_viewport = new wxWindow();
+
+ wxDynamicSashWindowImpl *add_child_target = m_impl->m_add_child_target;
+ m_impl->m_add_child_target = NULL;
+
+ bool success = m_hscroll->Create(m_impl->m_container, wxID_ANY,
+ wxDefaultPosition, wxDefaultSize,
+ wxSB_HORIZONTAL);
+ if ( success )
+ success = m_vscroll->Create(m_impl->m_container, wxID_ANY,
+ wxDefaultPosition, wxDefaultSize,
+ wxSB_VERTICAL);
+ if ( success )
+ success = m_viewport->Create(m_impl->m_container, wxID_ANY);
+ if ( !success )
+ return false;
+
+ 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);
+
+ // the viewport must resize its child when it is itself resized, but it's
+ // more convenient to do it in our own method instead of deriving a new
+ // class just for this: this is why we pass this as last Connect() argument
+ m_viewport->Connect(wxEVT_SIZE,
+ wxSizeEventHandler(wxDynamicSashWindowLeaf::OnViewSize),
+ NULL, this);
+
+ Connect(wxEVT_DYNAMIC_SASH_REPARENT,
+ wxEventHandler(wxDynamicSashWindowLeaf::OnReparent));
+
+ if (m_impl->m_window->GetWindowStyle() & wxDS_MANAGE_SCROLLBARS)
+ {
+ m_hscroll->SetEventHandler(this);
+ m_vscroll->SetEventHandler(this);
+
+ Connect(wxEVT_SET_FOCUS,
+ wxFocusEventHandler(wxDynamicSashWindowLeaf::OnFocus));
+ Connect(wxEVT_SCROLL_TOP,
+ wxScrollEventHandler(wxDynamicSashWindowLeaf::OnScroll));
+ Connect(wxEVT_SCROLL_BOTTOM,
+ wxScrollEventHandler(wxDynamicSashWindowLeaf::OnScroll));
+ Connect(wxEVT_SCROLL_LINEUP,
+ wxScrollEventHandler(wxDynamicSashWindowLeaf::OnScroll));
+ Connect(wxEVT_SCROLL_LINEDOWN,
+ wxScrollEventHandler(wxDynamicSashWindowLeaf::OnScroll));
+ Connect(wxEVT_SCROLL_PAGEUP,
+ wxScrollEventHandler(wxDynamicSashWindowLeaf::OnScroll));
+ Connect(wxEVT_SCROLL_PAGEDOWN,
+ wxScrollEventHandler(wxDynamicSashWindowLeaf::OnScroll));
+ Connect(wxEVT_SCROLL_THUMBTRACK,
+ wxScrollEventHandler(wxDynamicSashWindowLeaf::OnScroll));
+ Connect(wxEVT_SCROLL_THUMBRELEASE,
+ wxScrollEventHandler(wxDynamicSashWindowLeaf::OnScroll));
+ }
+
+ wxLayoutConstraints *layout = new wxLayoutConstraints();
+ if (!layout)
+ return false;
+
+ wxSize size = m_hscroll->GetBestSize();
+
+ 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 = m_vscroll->GetBestSize();
+
+ 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 true;
+}
+
+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(const wxSize& size)
+{
+ if (m_child)
+ {
+ if (m_impl->m_window->HasFlag(wxDS_MANAGE_SCROLLBARS))
+ {
+ 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 // !wxDS_MANAGE_SCROLLBARS
+ {
+ m_child->SetSize(size);
+ }
+ }
+}
+
+wxScrollBar *
+wxDynamicSashWindowLeaf::FindScrollBar(const wxWindow *child, int vert) const
+{
+ if (m_child == child)
+ {
+ return vert ? m_vscroll : m_hscroll;
+ }
+
+ return NULL;
+}
+
+void wxDynamicSashWindowLeaf::OnSize(wxSizeEvent &WXUNUSED(event))
+{
+ m_impl->m_container->Refresh();
+}
+
+void wxDynamicSashWindowLeaf::OnViewSize(wxSizeEvent &WXUNUSED(event))
+{
+ if ( m_viewport )
+ ResizeChild(m_viewport->GetSize());
+}
+
+void wxDynamicSashWindowLeaf::OnPaint(wxPaintEvent &WXUNUSED(event))
+{
+ wxPaintDC dc(m_impl->m_container);
+ dc.SetBackground(wxBrush(m_impl->m_container->GetBackgroundColour(), wxSOLID));
+ dc.Clear();
+
+ wxPen highlight(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNHIGHLIGHT), 1, wxSOLID);
+ wxPen shadow(wxSystemSettings::GetColour(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 &WXUNUSED(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.GetEventObject() == m_hscroll ||
+ event.GetEventObject() == 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) &&
+ (m_impl->m_window->GetWindowStyle() & wxDS_DRAG_CORNER) != 0)
+ {
+ 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 &WXUNUSED(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_CORNER) && (m_impl->m_window->GetWindowStyle() & wxDS_DRAG_CORNER) == 0)
+ return;
+
+ 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 &WXUNUSED(event))
+{
+}
+
+void wxDynamicSashWindowLeaf::OnReparent(wxEvent &WXUNUSED(event))
+{
+ if (m_child)
+ {
+ m_child->Reparent(m_viewport);
+ }
+
+ ResizeChild(m_viewport->GetSize());
+}
+
+// ============================================================================
+// events
+// ============================================================================
+
+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()
+{
+ 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)
+
+
+wxDynamicSashReparentEvent::wxDynamicSashReparentEvent()
+{
+ m_eventObject = NULL;
+ m_eventType = wxEVT_DYNAMIC_SASH_REPARENT;
+}
+
+wxDynamicSashReparentEvent::wxDynamicSashReparentEvent(wxObject *object)
+{
+ m_eventObject = object;
+ m_eventType = wxEVT_DYNAMIC_SASH_REPARENT;
+}
+
+wxDynamicSashReparentEvent::wxDynamicSashReparentEvent(const wxDynamicSashReparentEvent& evt)
+ : wxEvent(evt)
+{
+}
+
+IMPLEMENT_DYNAMIC_CLASS(wxDynamicSashReparentEvent, wxEvent)
+