--- /dev/null
+/////////////////////////////////////////////////////////////////////////////
+// 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;
+}
--- /dev/null
+/////////////////////////////////////////////////////////////////////////////
+// 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)
+
+/////////////////////////////////////////////////////////////////////////////