home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2240.zip / wxWindows-2.4.0 / contrib / src / gizmos / dynamicsash.cpp next >
C/C++ Source or Header  |  2002-12-18  |  43KB  |  1,275 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name:        dynamicsash.cpp
  3. // Purpose:     A window which can be dynamically split to an arbitrary depth
  4. //              and later reunified through the user interface
  5. // Author:      Matt Kimball
  6. // Modified by:
  7. // Created:     7/15/2001
  8. // RCS-ID:      $Id: dynamicsash.cpp,v 1.6.2.1 2002/12/18 06:10:24 RD Exp $
  9. // Copyright:   (c) 2001 Matt Kimball
  10. // Licence:     wxWindows licence
  11. /////////////////////////////////////////////////////////////////////////////
  12.  
  13. #ifdef __GNUG__
  14.     #pragma implementation "splittree.h"
  15. #endif
  16.  
  17. // For compilers that support precompilation, includes "wx/wx.h".
  18. #include "wx/wxprec.h"
  19.  
  20. #ifdef __BORLANDC__
  21.     #pragma hdrstop
  22. #endif
  23.  
  24. // for all others, include the necessary headers (this file is usually all you
  25. // need because it includes almost all "standard" wxWindows headers)
  26. #ifndef WX_PRECOMP
  27.     #include "wx/wx.h"
  28. #endif
  29.  
  30. #include "wx/gizmos/dynamicsash.h"
  31.  
  32.  
  33. const wxChar* wxDynamicSashWindowNameStr = wxT("dynamicSashWindow");
  34.  
  35.  
  36. /*
  37.     wxDynamicSashWindow works by internally storing a tree of Implementation
  38.     objects (wxDynamicSsahWindowImpl) and Leaf objects
  39.     (wxDynamicSashWindowLeaf).  The wxDynamicSashWindow has a pointer to one
  40.     implementation, and each implementation either has a pointer to a one
  41.     leaf (m_leaf) or a pointer to two children implementation objects
  42.     (m_child).  The leaves each are responsible for drawing the frame and
  43.     decorations around one user-provided views and for responding to mouse
  44.     and scrollbar events.
  45.  
  46.     A resulting tree might look something like this:
  47.  
  48.     wxDynamicSashWindow
  49.      |
  50.      +- wxDynamicSashWindowImpl
  51.          |
  52.          +- wxDynamicSashWindowLeaf
  53.          |   |
  54.          |   +- user view window
  55.          |
  56.          +- wxDynamicSashWindowImpl
  57.              |
  58.              +- wxDynamicSashWindowLeaf
  59.              |   |
  60.              |   +- user view window
  61.              |
  62.              +- wxDynamicSashWindowLeaf
  63.                  |
  64.                  +- user view window
  65.  
  66.     Each time a split occurs, one of the implementation objects removes its
  67.     leaf, generates two new implementation object children, each with a new
  68.     leaf, and reparents the user view which was connected to its old leaf
  69.     to be one of the new leaf's user view, and sends a Split event to the
  70.     user view in the hopes that it will generate a new user view for the
  71.     other new leaf.
  72.  
  73.     When a unification ocurrs, an implementation object is replaced by one
  74.     of its children, and the tree of its other child is pruned.
  75.  
  76.     One quirk is that the top-level implementation object (m_top) always
  77.     keeps a pointer to the implementation object where a new child is needed.
  78.     (m_add_child_target).  This is so that when a new uesr view is added
  79.     to the hierarchy, AddChild() is able to reparent the new user view to
  80.     the correct implementation object's leaf.
  81.  
  82. */
  83.  
  84. #include <wx/dcmemory.h>
  85. #include <wx/dcscreen.h>
  86. #include <wx/layout.h>
  87. #include <wx/scrolbar.h>
  88. #include <wx/settings.h>
  89.  
  90.  
  91. #define wxEVT_DYNAMIC_SASH_PRIVATE          (wxEVT_DYNAMIC_SASH_BASE + 8)
  92. #define wxEVT_DYNAMIC_SASH_REPARENT         (wxEVT_DYNAMIC_SASH_PRIVATE + 1)
  93.  
  94.  
  95. /*
  96.     wxDynamicSashReparentEvent is generated by the AddChild() method of
  97.     wxDynamicSashWindow when it wants a Leaf to reparent a user view window
  98.     to its viewport at some time in the future.  We can't reparent the window
  99.     immediately, because switching parents in AddChild() confuses the wxWindow
  100.     class.  Instead, we queue up this event, and the window is actually
  101.     reparented the next time we process events in the idle loop.
  102. */
  103. class wxDynamicSashReparentEvent : public wxEvent {
  104. public:
  105.     wxDynamicSashReparentEvent();
  106.     wxDynamicSashReparentEvent(wxObject *object);
  107.     wxDynamicSashReparentEvent(const wxDynamicSashReparentEvent& evt);
  108.  
  109.     virtual wxEvent* Clone() const { return new wxDynamicSashReparentEvent(*this); }
  110.  
  111.     DECLARE_DYNAMIC_CLASS(wxDynamicSashReparentEvent);
  112. };
  113.  
  114.  
  115. enum DynamicSashRegion {
  116.     DSR_NONE,
  117.     DSR_VERTICAL_TAB,
  118.     DSR_HORIZONTAL_TAB,
  119.     DSR_CORNER,
  120.     DSR_LEFT_EDGE,
  121.     DSR_TOP_EDGE,
  122.     DSR_RIGHT_EDGE,
  123.     DSR_BOTTOM_EDGE
  124. };
  125.  
  126.  
  127. class wxDynamicSashWindowImpl : public wxEvtHandler {
  128. public:
  129.     wxDynamicSashWindowImpl(wxDynamicSashWindow *window);
  130.     ~wxDynamicSashWindowImpl();
  131.  
  132.     bool Create();
  133.     void AddChild(wxWindow *window);
  134.     void DrawSash(int x, int y) const;
  135.     void ConstrainChildren(int px, int py);
  136.     void Split(int x, int y);
  137.     void Unify(int panel);
  138.     void Resize(int x, int y);
  139.     wxDynamicSashWindowImpl *FindParent(DynamicSashRegion side) const;
  140.     wxDynamicSashWindowImpl *FindUpperParent(wxDynamicSashWindowImpl *sash_a,
  141.                                              wxDynamicSashWindowImpl *sash_b) const;
  142.     wxWindow *FindFrame() const;
  143.     wxScrollBar *FindScrollBar(const wxWindow *child, int vert) const;
  144.  
  145.     void OnSize(wxSizeEvent &event);
  146.     void OnPaint(wxPaintEvent &event);
  147.     void OnMouseMove(wxMouseEvent &event);
  148.     void OnLeave(wxMouseEvent &event);
  149.     void OnPress(wxMouseEvent &event);
  150.     void OnRelease(wxMouseEvent &event);
  151.  
  152.     wxDynamicSashWindow *m_window;
  153.     wxDynamicSashWindowImpl *m_add_child_target;
  154.  
  155.     /*  This is the window we are responsible for managing.  Either of
  156.         leaf or our children are in this window.  For the top level
  157.         implementation object, this is the same as m_window.
  158.         Otherwise it is a window we've created an will destroy when we
  159.         are deleted.  */
  160.     wxWindow *m_container;
  161.  
  162.     wxDynamicSashWindowImpl *m_parent;
  163.     wxDynamicSashWindowImpl *m_top;
  164.     wxDynamicSashWindowImpl *m_child[2];
  165.  
  166.     class wxDynamicSashWindowLeaf *m_leaf;
  167.  
  168.     /*  If the implementation is split horizontally or vertically, m_split
  169.         is set to DSR_HORIZONTAL_TAB or DSR_VERTICAL_TAB, respectively.
  170.         Otherwise it is set to DSR_NONE.  */
  171.     DynamicSashRegion m_split;
  172.  
  173.     /*  These are used to keep track of a sash as it is being dragged, for
  174.         drawing the user interface correctly.  */
  175.     DynamicSashRegion m_dragging;
  176.     int m_drag_x, m_drag_y;
  177. };
  178.  
  179. class wxDynamicSashWindowLeaf : public wxEvtHandler {
  180. public:
  181.     wxDynamicSashWindowLeaf(wxDynamicSashWindowImpl *impl);
  182.     ~wxDynamicSashWindowLeaf();
  183.  
  184.     bool Create();
  185.     void AddChild(wxWindow *window);
  186.     DynamicSashRegion GetRegion(int x, int y);
  187.     void ResizeChild(wxSize size);
  188.     wxScrollBar *FindScrollBar(const wxWindow *child, int vert) const;
  189.  
  190.     void OnSize(wxSizeEvent &event);
  191.     void OnPaint(wxPaintEvent &event);
  192.     void OnScroll(wxScrollEvent &event);
  193.     void OnFocus(wxFocusEvent &event);
  194.     void OnMouseMove(wxMouseEvent &event);
  195.     void OnLeave(wxMouseEvent &event);
  196.     void OnPress(wxMouseEvent &event);
  197.     void OnRelease(wxMouseEvent &event);
  198.     void OnReparent(wxEvent &event);
  199.  
  200.     wxDynamicSashWindowImpl *m_impl;
  201.  
  202.     wxScrollBar *m_vscroll, *m_hscroll;
  203.  
  204.     /*  m_child is the window provided to us by the application developer.
  205.         m_viewport is a window we've created, and it is the immediately
  206.         parent of m_child.  We scroll m_child by moving it around within
  207.         m_viewport.  */
  208.     wxWindow *m_viewport, *m_child;
  209. };
  210.  
  211. // wxDynamicSashWindow //////////////////////////////////////////////////////
  212.  
  213. wxDynamicSashWindow::wxDynamicSashWindow() {
  214.     m_impl = NULL;
  215. }
  216.  
  217. wxDynamicSashWindow::wxDynamicSashWindow(wxWindow *parent, wxWindowID id,
  218.                                          const wxPoint& pos, const wxSize& size,
  219.                                          long style, const wxString& name) {
  220.     m_impl = NULL;
  221.     Create(parent, id, pos, size, style, name);
  222. }
  223.  
  224. wxDynamicSashWindow::~wxDynamicSashWindow() {
  225.     SetEventHandler(this);
  226.     delete m_impl;
  227. }
  228.  
  229. bool wxDynamicSashWindow::Create(wxWindow *parent, wxWindowID id,
  230.                                  const wxPoint& pos, const wxSize& size,
  231.                                  long style, const wxString& name) {
  232.     if (m_impl)
  233.         return FALSE;
  234.  
  235.     if (!wxWindow::Create(parent, id, pos, size, style, name))
  236.         return FALSE;
  237.  
  238.     m_impl = new wxDynamicSashWindowImpl(this);
  239.     if (!m_impl)
  240.         return FALSE;
  241.  
  242.     if (!m_impl->Create()) {
  243.         delete m_impl;
  244.         m_impl = NULL;
  245.         return FALSE;
  246.     }
  247.  
  248.     return TRUE;
  249. }
  250.  
  251. void wxDynamicSashWindow::AddChild(wxWindowBase *child) {
  252.     wxWindow::AddChild(child);
  253.  
  254.     m_impl->AddChild(wxDynamicCast(child, wxWindow));
  255. }
  256.  
  257. wxScrollBar *wxDynamicSashWindow::GetHScrollBar(const wxWindow *child) const {
  258.     return m_impl->FindScrollBar(child, 0);
  259. }
  260.  
  261. wxScrollBar *wxDynamicSashWindow::GetVScrollBar(const wxWindow *child) const {
  262.     return m_impl->FindScrollBar(child, 1);
  263. }
  264.  
  265. IMPLEMENT_DYNAMIC_CLASS(wxDynamicSashWindow, wxWindow)
  266.  
  267. // wxDynamicSashWindowImpl //////////////////////////////////////////////////
  268.  
  269. wxDynamicSashWindowImpl::wxDynamicSashWindowImpl(wxDynamicSashWindow *window) {
  270.     m_window = window;
  271.     m_add_child_target = this;
  272.  
  273.     m_container = NULL;
  274.     m_parent = NULL;
  275.     m_top = this;
  276.     m_child[0] = m_child[1] = NULL;
  277.     m_leaf = NULL;
  278.     m_dragging = DSR_NONE;
  279.     m_split = DSR_NONE;
  280. }
  281.  
  282. wxDynamicSashWindowImpl::~wxDynamicSashWindowImpl() {
  283.     delete m_leaf;
  284.     delete m_child[0];
  285.     m_child[0] = NULL;
  286.     delete m_child[1];
  287.     m_child[1] = NULL;
  288.     m_leaf = NULL;
  289.  
  290.     if (m_container != m_window && m_container) {
  291.         m_container->SetEventHandler(m_container);
  292.         m_container->Destroy();
  293.     }
  294. }
  295.  
  296. bool wxDynamicSashWindowImpl::Create() {
  297.     if (!m_container) {
  298.         m_container = m_window;
  299.     }
  300.  
  301.     wxCursor cursor(wxCURSOR_ARROW);
  302.     m_container->SetCursor(cursor);
  303.  
  304.     m_leaf = new wxDynamicSashWindowLeaf(this);
  305.     if (!m_leaf)
  306.         return FALSE;
  307.  
  308.     if (!m_leaf->Create()) {
  309.         delete m_leaf;
  310.         m_leaf = NULL;
  311.         return FALSE;
  312.     }
  313.  
  314.     m_container->SetEventHandler(this);
  315.  
  316.     Connect(-1, wxEVT_SIZE, (wxObjectEventFunction)&wxDynamicSashWindowImpl::OnSize);
  317.     Connect(-1, wxEVT_PAINT, (wxObjectEventFunction)&wxDynamicSashWindowImpl::OnPaint);
  318.     Connect(-1, wxEVT_MOTION, (wxObjectEventFunction)&wxDynamicSashWindowImpl::OnMouseMove);
  319.     Connect(-1, wxEVT_ENTER_WINDOW, (wxObjectEventFunction)&wxDynamicSashWindowImpl::OnMouseMove);
  320.     Connect(-1, wxEVT_LEAVE_WINDOW, (wxObjectEventFunction)&wxDynamicSashWindowImpl::OnLeave);
  321.     Connect(-1, wxEVT_LEFT_DOWN, (wxObjectEventFunction)&wxDynamicSashWindowImpl::OnPress);
  322.     Connect(-1, wxEVT_LEFT_UP, (wxObjectEventFunction)&wxDynamicSashWindowImpl::OnRelease);
  323.  
  324.     return TRUE;
  325. }
  326.  
  327. void wxDynamicSashWindowImpl::AddChild(wxWindow *window) {
  328.     if (m_add_child_target && m_add_child_target->m_leaf) {
  329.         m_add_child_target->m_leaf->AddChild(window);
  330.     }
  331. }
  332.  
  333. void wxDynamicSashWindowImpl::DrawSash(int x, int y) const {
  334.     int i, j;
  335.  
  336.     wxScreenDC dc;
  337.     dc.StartDrawingOnTop(m_container);
  338.  
  339.     wxBitmap bmp(8, 8);
  340.     wxMemoryDC bdc;
  341.     bdc.SelectObject(bmp);
  342.     bdc.DrawRectangle(-1, -1, 10, 10);
  343.     for (i = 0; i < 8; i++) {
  344.         for (j = 0; j < 8; j++) {
  345.             if ((i + j) & 1) {
  346.                 bdc.DrawPoint(i, j);
  347.             }
  348.         }
  349.     }
  350.  
  351.     wxBrush brush(bmp);
  352.     dc.SetBrush(brush);
  353.     dc.SetLogicalFunction(wxXOR);
  354.  
  355.     if ((m_dragging == DSR_CORNER) &&
  356.         (m_window->GetWindowStyle() & wxDS_DRAG_CORNER) != 0) {
  357.         int cx = 0;
  358.         int cy = 0;
  359.  
  360.         m_container->ClientToScreen(&cx, &cy);
  361.         m_container->ClientToScreen(&x, &y);
  362.  
  363.         if (cx < x && cy < y) {
  364.             dc.DrawRectangle(cx - 2, cy - 2, x - cx + 4, 4);
  365.             dc.DrawRectangle(x - 2, cy + 2, 4, y - cy);
  366.             dc.DrawRectangle(cx - 2, cy + 2, 4, y - cy);
  367.             dc.DrawRectangle(cx + 2, y - 2, x - cx - 4, 4);
  368.         }
  369.     } else {
  370.         int body_w, body_h;
  371.         m_container->GetClientSize(&body_w, &body_h);
  372.  
  373.         if (y < 0)
  374.             y = 0;
  375.         if (y > body_h)
  376.             y = body_h;
  377.         if (x < 0)
  378.             x = 0;
  379.         if (x > body_w)
  380.             x = body_w;
  381.  
  382.         if (m_dragging == DSR_HORIZONTAL_TAB)
  383.             x = 0;
  384.         else
  385.             y = 0;
  386.  
  387.         m_container->ClientToScreen(&x, &y);
  388.  
  389.         int w, h;
  390.         w = body_w;  h = body_h;
  391.  
  392.         if (m_dragging == DSR_HORIZONTAL_TAB)
  393.             dc.DrawRectangle(x, y - 2, w, 4);
  394.         else
  395.             dc.DrawRectangle(x - 2, y, 4, h);
  396.     }
  397.  
  398.     dc.EndDrawingOnTop();
  399. }
  400.  
  401. wxDynamicSashWindowImpl *wxDynamicSashWindowImpl::FindParent(DynamicSashRegion side) const {
  402.     if (m_parent == NULL) {
  403.         return NULL;
  404.     }
  405.  
  406.     if (m_parent->m_split == DSR_HORIZONTAL_TAB) {
  407.         if (side == DSR_TOP_EDGE && m_parent->m_child[1] == this)
  408.             return m_parent;
  409.         if (side == DSR_BOTTOM_EDGE && m_parent->m_child[0] == this)
  410.             return m_parent;
  411.     } else if (m_parent->m_split == DSR_VERTICAL_TAB) {
  412.         if (side == DSR_LEFT_EDGE && m_parent->m_child[1] == this)
  413.             return m_parent;
  414.         if (side == DSR_RIGHT_EDGE && m_parent->m_child[0] == this)
  415.             return m_parent;
  416.     }
  417.  
  418.     return m_parent->FindParent(side);
  419. }
  420.  
  421. wxDynamicSashWindowImpl *wxDynamicSashWindowImpl::FindUpperParent(wxDynamicSashWindowImpl *sash_a,
  422.                                                                   wxDynamicSashWindowImpl *sash_b) const {
  423.     wxWindow *win;
  424.     win = sash_a->m_container->GetParent();
  425.     while (win && !win->IsTopLevel()) {
  426.         if (win == sash_b->m_container) {
  427.             return sash_b;
  428.         }
  429.  
  430.         win = win->GetParent();
  431.     }
  432.  
  433.     return sash_a;
  434. }
  435.  
  436.  
  437. wxWindow *wxDynamicSashWindowImpl::FindFrame() const {
  438.     wxWindow *win;
  439.  
  440.     win = m_window->GetParent();
  441.     while (win && !win->IsTopLevel()) {
  442.         win = win->GetParent();
  443.     }
  444.  
  445.     return win;
  446. }
  447.  
  448. wxScrollBar *wxDynamicSashWindowImpl::FindScrollBar(const wxWindow *child, int vert) const {
  449.     if (m_child[0] == NULL && m_leaf == NULL) {
  450.         return NULL;
  451.     }
  452.  
  453.     if (!m_child[0]) {
  454.         return m_leaf->FindScrollBar(child, vert);
  455.     } else {
  456.         wxScrollBar *ret = m_child[0]->FindScrollBar(child, vert);
  457.         if (!ret) {
  458.             ret = m_child[1]->FindScrollBar(child, vert);
  459.         }
  460.  
  461.         return ret;
  462.     }
  463. }
  464.  
  465. void wxDynamicSashWindowImpl::ConstrainChildren(int px, int py) {
  466.     wxLayoutConstraints *layout = new wxLayoutConstraints();
  467.     layout->left.SameAs(m_container, wxLeft);
  468.     layout->top.SameAs(m_container, wxTop);
  469.     if (m_split == DSR_HORIZONTAL_TAB) {
  470.         layout->right.SameAs(m_container, wxRight);
  471.         layout->height.PercentOf(m_container, wxHeight, py);
  472.     } else {
  473.         layout->bottom.SameAs(m_container, wxBottom);
  474.         layout->width.PercentOf(m_container, wxWidth, px);
  475.     }
  476.     m_child[0]->m_container->SetConstraints(layout);
  477.  
  478.     layout = new wxLayoutConstraints();
  479.     layout->right.SameAs(m_container, wxRight);
  480.     layout->bottom.SameAs(m_container, wxBottom);
  481.     if (m_split == DSR_HORIZONTAL_TAB) {
  482.         layout->top.Below(m_child[0]->m_container, 1);
  483.         layout->left.SameAs(m_container, wxLeft);
  484.     } else {
  485.         layout->left.RightOf(m_child[0]->m_container, 1);
  486.         layout->top.SameAs(m_container, wxTop);
  487.     }
  488.     m_child[1]->m_container->SetConstraints(layout);
  489. }
  490.  
  491. void wxDynamicSashWindowImpl::Unify(int panel) {
  492.     int other = 0;
  493.     if (panel == 0) {
  494.         other = 1;
  495.     }
  496.  
  497.     if (m_child[panel]->m_leaf) {
  498.         wxDynamicSashWindowImpl *child[2];
  499.  
  500.         child[0] = m_child[0];
  501.         child[1] = m_child[1];
  502.  
  503.         m_child[0] = m_child[1] = NULL;
  504.  
  505.         m_leaf = new wxDynamicSashWindowLeaf(this);
  506.         m_leaf->Create();
  507.         m_leaf->m_child = child[panel]->m_leaf->m_child;
  508.  
  509.         m_leaf->m_vscroll->SetScrollbar(child[panel]->m_leaf->m_vscroll->GetThumbPosition(),
  510.                                         child[panel]->m_leaf->m_vscroll->GetThumbSize(),
  511.                                         child[panel]->m_leaf->m_vscroll->GetRange(),
  512.                                         child[panel]->m_leaf->m_vscroll->GetPageSize());
  513.         m_leaf->m_hscroll->SetScrollbar(child[panel]->m_leaf->m_hscroll->GetThumbPosition(),
  514.                                         child[panel]->m_leaf->m_hscroll->GetThumbSize(),
  515.                                         child[panel]->m_leaf->m_hscroll->GetRange(),
  516.                                         child[panel]->m_leaf->m_hscroll->GetPageSize());
  517.         m_add_child_target = NULL;
  518.         wxDynamicSashReparentEvent event(m_leaf);
  519.         m_leaf->ProcessEvent(event);
  520.  
  521.         delete child[0];
  522.         delete child[1];
  523.  
  524.         m_split = DSR_NONE;
  525.  
  526.         wxDynamicSashUnifyEvent unify(m_leaf->m_child);
  527.         m_leaf->m_child->ProcessEvent(unify);
  528.     } else {
  529.         m_split = m_child[panel]->m_split;
  530.  
  531.         delete m_child[other];
  532.  
  533.         wxDynamicSashWindowImpl *child_panel = m_child[panel];
  534.         m_child[0] = child_panel->m_child[0];
  535.         m_child[1] = child_panel->m_child[1];
  536.  
  537.         m_child[0]->m_parent = this;
  538.         m_child[1]->m_parent = this;
  539.  
  540.         m_add_child_target = NULL;
  541.         m_child[0]->m_container->Reparent(m_container);
  542.         m_child[1]->m_container->Reparent(m_container);
  543.  
  544.         child_panel->m_child[0] = child_panel->m_child[1] = NULL;
  545.         delete child_panel;
  546.  
  547.         wxSize size = m_container->GetSize();
  548.         wxSize child_size = m_child[0]->m_container->GetSize();
  549.  
  550.         ConstrainChildren(child_size.GetWidth() * 100 / size.GetWidth(),
  551.                             child_size.GetHeight() * 100 / size.GetHeight());
  552.  
  553.         m_container->Layout();
  554.     }
  555. }
  556.  
  557. void wxDynamicSashWindowImpl::Split(int px, int py) {
  558.  
  559.     m_add_child_target = NULL;
  560.  
  561.     m_child[0] = new wxDynamicSashWindowImpl(m_window);
  562.     m_child[0]->m_container = new wxWindow(m_container, -1);
  563.     m_child[0]->m_parent = this;
  564.     m_child[0]->m_top = m_top;
  565.     m_child[0]->Create();
  566.     if (m_leaf->m_child) {
  567.         m_leaf->m_child->Reparent(m_container);
  568.         m_child[0]->AddChild(m_leaf->m_child);
  569.     }
  570.  
  571.     m_child[1] = new wxDynamicSashWindowImpl(m_window);
  572.     m_child[1]->m_container = new wxWindow(m_container, -1);
  573.     m_child[1]->m_parent = this;
  574.     m_child[1]->m_top = m_top;
  575.     m_child[1]->Create();
  576.  
  577.     m_split = m_dragging;
  578.     ConstrainChildren(px, py);
  579.  
  580.     m_top->m_add_child_target = m_child[1];
  581.     wxDynamicSashSplitEvent split(m_child[0]->m_leaf->m_child);
  582.     m_child[0]->m_leaf->m_child->ProcessEvent(split);
  583.  
  584.     m_child[0]->m_leaf->m_vscroll->SetScrollbar(m_leaf->m_vscroll->GetThumbPosition(),
  585.                                                 m_leaf->m_vscroll->GetThumbSize(),
  586.                                                 m_leaf->m_vscroll->GetRange(),
  587.                                                 m_leaf->m_vscroll->GetPageSize());
  588.     m_child[0]->m_leaf->m_hscroll->SetScrollbar(m_leaf->m_hscroll->GetThumbPosition(),
  589.                                                 m_leaf->m_hscroll->GetThumbSize(),
  590.                                                 m_leaf->m_hscroll->GetRange(),
  591.                                                 m_leaf->m_hscroll->GetPageSize());
  592.     m_child[1]->m_leaf->m_vscroll->SetScrollbar(m_leaf->m_vscroll->GetThumbPosition(),
  593.                                                 m_leaf->m_vscroll->GetThumbSize(),
  594.                                                 m_leaf->m_vscroll->GetRange(),
  595.                                                 m_leaf->m_vscroll->GetPageSize());
  596.     m_child[1]->m_leaf->m_hscroll->SetScrollbar(m_leaf->m_hscroll->GetThumbPosition(),
  597.                                                 m_leaf->m_hscroll->GetThumbSize(),
  598.                                                 m_leaf->m_hscroll->GetRange(),
  599.                                                 m_leaf->m_hscroll->GetPageSize());
  600.     delete m_leaf;
  601.     m_leaf = NULL;
  602.  
  603.     m_container->Layout();
  604. }
  605.  
  606.  
  607. /*  This code is called when you finish resizing a view by dragging the
  608.     corner tab, but I think this implementation is lousy and will surprise
  609.     the user more often than it will do what they are trying to do.  What
  610.     I really need to be doing here is do a rewrite such that *no* sashes
  611.     move except the ones immediately to the bottom and right of this window,
  612.     and handle the case where you resize a window larger than it's neighbors
  613.     by destroying the neighbors.
  614.  
  615.     But this will do for now.  */
  616. void wxDynamicSashWindowImpl::Resize(int x, int y) {
  617.     wxDynamicSashWindowImpl *h_parent = FindParent(DSR_BOTTOM_EDGE);
  618.     wxDynamicSashWindowImpl *v_parent = FindParent(DSR_RIGHT_EDGE);
  619.     int h_unify = -1;
  620.     int v_unify = -1;
  621.     wxWindow *frame = FindFrame();
  622.  
  623.     if (x < 0) {
  624.         x = 0;
  625.     }
  626.     if (y < 0) {
  627.         y = 0;
  628.     }
  629.  
  630.     if (h_parent) {
  631.         m_container->ClientToScreen(NULL, &y);
  632.         h_parent->m_container->ScreenToClient(NULL, &y);
  633.  
  634.         int py = (int)((y * 100) / h_parent->m_container->GetSize().GetHeight() + 0.5);
  635.  
  636.         if (py < 10) {
  637.             wxDynamicSashWindowImpl *ho_parent = FindParent(DSR_TOP_EDGE);
  638.  
  639.             if (ho_parent) {
  640.                 if (FindUpperParent(h_parent, ho_parent) == ho_parent) {
  641.                     h_unify = 1;
  642.                 } else {
  643.                     py = (int)((ho_parent->m_child[0]->m_container->GetSize().GetHeight() * 100)
  644.                                 / h_parent->m_container->GetSize().GetHeight() + 0.5);
  645.                     h_parent->m_child[0]->m_container->GetConstraints()->height.PercentOf(
  646.                             h_parent->m_container, wxHeight, py);
  647.  
  648.                     h_parent = ho_parent;
  649.                     h_unify = 0;
  650.                 }
  651.             } else {
  652.                 h_unify = 1;
  653.             }
  654.         } else if (py > 90) {
  655.             h_unify = 0;
  656.         } else {
  657.             h_parent->m_child[0]->m_container->GetConstraints()->height.PercentOf(
  658.                     h_parent->m_container, wxHeight, py);
  659.             h_parent->m_container->Layout();
  660.         }
  661.     } else {
  662.         int do_resize = 1;
  663.         h_parent = FindParent(DSR_TOP_EDGE);
  664.  
  665.         if (h_parent) {
  666.             int py = (int)((y * 100) /
  667.                         (h_parent->m_container->GetSize().GetHeight() +
  668.                                 y - m_container->GetSize().GetHeight()) + 0.5);
  669.  
  670.             if (py < 10) {
  671.                 h_unify = 0;
  672.             }
  673.         } else if (y < 64) {
  674.             do_resize = 0;
  675.         }
  676.  
  677.         if (do_resize) {
  678.             wxSize size = frame->GetSize();
  679.             frame->SetSize(size.GetWidth(), size.GetHeight() + y - m_container->GetSize().GetHeight());
  680.         }
  681.     }
  682.  
  683.     if (v_parent) {
  684.         m_container->ClientToScreen(&x, NULL);
  685.         v_parent->m_container->ScreenToClient(&x, NULL);
  686.  
  687.         int px = (int)((x * 100) / v_parent->m_container->GetSize().GetWidth() + 0.5);
  688.  
  689.         if (px < 10) {
  690.             wxDynamicSashWindowImpl *vo_parent = FindParent(DSR_LEFT_EDGE);
  691.  
  692.             if (vo_parent) {
  693.                 if (FindUpperParent(v_parent, vo_parent) == vo_parent) {
  694.                     v_unify = 1;
  695.                 } else {
  696.                     px = (int)((vo_parent->m_child[0]->m_container->GetSize().GetWidth() * 100)
  697.                                 / v_parent->m_container->GetSize().GetWidth() + 0.5);
  698.                     v_parent->m_child[0]->m_container->GetConstraints()->width.PercentOf(
  699.                             v_parent->m_container, wxWidth, px);
  700.  
  701.                     v_parent = vo_parent;
  702.                     v_unify = 0;
  703.                 }
  704.             } else {
  705.                 v_unify = 1;
  706.             }
  707.         } else if (px > 90) {
  708.             v_unify = 0;
  709.         } else {
  710.             v_parent->m_child[0]->m_container->GetConstraints()->width.PercentOf(
  711.                     v_parent->m_container, wxWidth, px);
  712.             v_parent->m_container->Layout();
  713.         }
  714.     } else {
  715.         int do_resize = 1;
  716.         v_parent = FindParent(DSR_LEFT_EDGE);
  717.  
  718.         if (v_parent) {
  719.             int px = (int)((x * 100) /
  720.                         (v_parent->m_container->GetSize().GetWidth() +
  721.                                 x - m_container->GetSize().GetWidth()) + 0.5);
  722.  
  723.             if (px < 10) {
  724.                 v_unify = 0;
  725.             }
  726.         } else if (x < 64) {
  727.             do_resize = 0;
  728.         }
  729.  
  730.         if (do_resize) {
  731.             wxSize size = frame->GetSize();
  732.             frame->SetSize(size.GetWidth() + x - m_container->GetSize().GetWidth(), size.GetHeight());
  733.         }
  734.     }
  735.  
  736.     if (h_unify != -1 && v_unify != -1) {
  737.         wxDynamicSashWindowImpl *parent = FindUpperParent(h_parent, v_parent);
  738.  
  739.         if (parent == h_parent) {
  740.             h_parent->Unify(h_unify);
  741.         } else {
  742.             v_parent->Unify(v_unify);
  743.         }
  744.     } else if (h_unify != -1) {
  745.         h_parent->Unify(h_unify);
  746.     } else if (v_unify != -1) {
  747.         v_parent->Unify(v_unify);
  748.     }
  749. }
  750.  
  751.  
  752. void wxDynamicSashWindowImpl::OnSize(wxSizeEvent &event) {
  753.     m_container->Layout();
  754.  
  755.     if (m_leaf)
  756.         m_leaf->OnSize(event);
  757. }
  758.  
  759. void wxDynamicSashWindowImpl::OnPaint(wxPaintEvent &event) {
  760.     if (m_leaf)
  761.         m_leaf->OnPaint(event);
  762.     else {
  763.         wxPaintDC dc(m_container);
  764.         dc.SetBackground(wxBrush(m_container->GetBackgroundColour(), wxSOLID));
  765.         dc.Clear();
  766.     }
  767. }
  768.  
  769. void wxDynamicSashWindowImpl::OnMouseMove(wxMouseEvent &event) {
  770.     if (m_dragging) {
  771.         DrawSash(m_drag_x, m_drag_y);
  772.         m_drag_x = event.m_x;  m_drag_y = event.m_y;
  773.         DrawSash(m_drag_x, m_drag_y);
  774.     } else if (m_leaf) {
  775.         m_leaf->OnMouseMove(event);
  776.     }
  777. }
  778.  
  779. void wxDynamicSashWindowImpl::OnLeave(wxMouseEvent &event) {
  780.     if (m_leaf) {
  781.         m_leaf->OnLeave(event);
  782.     }
  783. }
  784.  
  785. void wxDynamicSashWindowImpl::OnPress(wxMouseEvent &event) {
  786.     if (m_leaf) {
  787.         m_leaf->OnPress(event);
  788.     } else {
  789.         m_dragging = m_split;
  790.         m_drag_x = event.m_x;
  791.         m_drag_y = event.m_y;
  792.         DrawSash(m_drag_x, m_drag_y);
  793.         m_container->CaptureMouse();
  794.     }
  795. }
  796.  
  797. void wxDynamicSashWindowImpl::OnRelease(wxMouseEvent &event) {
  798.     if ((m_dragging == DSR_CORNER) &&
  799.         (m_window->GetWindowStyle() & wxDS_DRAG_CORNER) != 0) {
  800.         DrawSash(m_drag_x, m_drag_y);
  801.         m_container->ReleaseMouse();
  802.  
  803.         Resize(event.m_x, event.m_y);
  804.  
  805.         m_dragging = DSR_NONE;
  806.     } else if (m_dragging) {
  807.         DrawSash(m_drag_x, m_drag_y);
  808.         m_container->ReleaseMouse();
  809.  
  810.         wxSize size = m_container->GetSize();
  811.         int px = (int)((event.m_x * 100) / size.GetWidth() + 0.5);
  812.         int py = (int)((event.m_y * 100) / size.GetHeight() + 0.5);
  813.  
  814.         if ((m_dragging == DSR_HORIZONTAL_TAB && py >= 10 && py <= 90)
  815.                     || (m_dragging == DSR_VERTICAL_TAB && px >= 10 && px <= 90)) {
  816.             if (m_child[0] == NULL) {
  817.                 Split(px, py);
  818.             } else {
  819.                 /*  It would be nice if moving *this* sash didn't implicitly move
  820.                     the sashes of our children (if any).  But this will do.  */
  821.                 wxLayoutConstraints *layout = m_child[0]->m_container->GetConstraints();
  822.                 if (m_split == DSR_HORIZONTAL_TAB) {
  823.                     layout->height.PercentOf(m_container, wxHeight, py);
  824.                 } else {
  825.                     layout->width.PercentOf(m_container, wxWidth, px);
  826.                 }
  827.                 m_container->Layout();
  828.             }
  829.         } else {
  830.             if (m_child[0] != NULL) {
  831.                 if ((m_dragging == DSR_HORIZONTAL_TAB && py <= 10)
  832.                         || (m_dragging == DSR_VERTICAL_TAB && px <= 10)) {
  833.                     Unify(1);
  834.                 } else {
  835.                     Unify(0);
  836.                 }
  837.             }
  838.         }
  839.  
  840.         wxCursor cursor(wxCURSOR_ARROW);
  841.         if (m_split == DSR_HORIZONTAL_TAB) {
  842.             cursor = wxCursor(wxCURSOR_SIZENS);
  843.         } else if (m_split == DSR_VERTICAL_TAB) {
  844.             cursor = wxCursor(wxCURSOR_SIZEWE);
  845.         }
  846.         m_container->SetCursor(cursor);
  847.  
  848.         m_dragging = DSR_NONE;
  849.     } else if (m_leaf) {
  850.         m_leaf->OnRelease(event);
  851.     }
  852. }
  853.  
  854. // wxDynamicSashWindowLeaf //////////////////////////////////////////////////
  855.  
  856. wxDynamicSashWindowLeaf::wxDynamicSashWindowLeaf(wxDynamicSashWindowImpl *impl) {
  857.     m_impl = impl;
  858.  
  859.     m_hscroll = m_vscroll = NULL;
  860.     m_child = NULL;
  861. }
  862.  
  863. wxDynamicSashWindowLeaf::~wxDynamicSashWindowLeaf() {
  864.     m_hscroll->SetEventHandler(m_hscroll);
  865.     m_vscroll->SetEventHandler(m_vscroll);
  866.     m_viewport->SetEventHandler(m_viewport);
  867.  
  868.     m_hscroll->Destroy();
  869.     m_vscroll->Destroy();
  870.     m_viewport->Destroy();
  871. }
  872.  
  873. bool wxDynamicSashWindowLeaf::Create() {
  874.     bool success;
  875.  
  876.     m_hscroll = new wxScrollBar();
  877.     m_vscroll = new wxScrollBar();
  878.     m_viewport = new wxWindow();
  879.  
  880.     if (!m_hscroll || !m_vscroll || !m_viewport) {
  881.         return FALSE;
  882.     }
  883.  
  884.     wxDynamicSashWindowImpl *add_child_target = m_impl->m_add_child_target;
  885.     m_impl->m_add_child_target = NULL;
  886.     success = m_hscroll->Create(m_impl->m_container, -1, wxDefaultPosition, wxDefaultSize,
  887.                                 wxSB_HORIZONTAL);
  888.     success = success && m_vscroll->Create(m_impl->m_container, -1, wxDefaultPosition, wxDefaultSize,
  889.                                             wxSB_VERTICAL);
  890.     success = success && m_viewport->Create(m_impl->m_container, -1);
  891.     m_impl->m_add_child_target = add_child_target;
  892.  
  893.     wxCursor cursor(wxCURSOR_ARROW);
  894.     m_hscroll->SetCursor(cursor);
  895.     m_vscroll->SetCursor(cursor);
  896.     m_viewport->SetCursor(cursor);
  897.  
  898.     m_viewport->SetEventHandler(this);
  899.     Connect(-1, wxEVT_DYNAMIC_SASH_REPARENT, (wxObjectEventFunction)&wxDynamicSashWindowLeaf::OnReparent);
  900.  
  901.     if (m_impl->m_window->GetWindowStyle() & wxDS_MANAGE_SCROLLBARS) {
  902.         m_hscroll->SetEventHandler(this);
  903.         m_vscroll->SetEventHandler(this);
  904.  
  905.         Connect(-1, wxEVT_SET_FOCUS, (wxObjectEventFunction)&wxDynamicSashWindowLeaf::OnFocus);
  906.         Connect(-1, wxEVT_SCROLL_TOP, (wxObjectEventFunction)&wxDynamicSashWindowLeaf::OnScroll);
  907.         Connect(-1, wxEVT_SCROLL_BOTTOM, (wxObjectEventFunction)&wxDynamicSashWindowLeaf::OnScroll);
  908.         Connect(-1, wxEVT_SCROLL_LINEUP, (wxObjectEventFunction)&wxDynamicSashWindowLeaf::OnScroll);
  909.         Connect(-1, wxEVT_SCROLL_LINEDOWN, (wxObjectEventFunction)&wxDynamicSashWindowLeaf::OnScroll);
  910.         Connect(-1, wxEVT_SCROLL_PAGEUP, (wxObjectEventFunction)&wxDynamicSashWindowLeaf::OnScroll);
  911.         Connect(-1, wxEVT_SCROLL_PAGEDOWN, (wxObjectEventFunction)&wxDynamicSashWindowLeaf::OnScroll);
  912.         Connect(-1, wxEVT_SCROLL_THUMBTRACK, (wxObjectEventFunction)&wxDynamicSashWindowLeaf::OnScroll);
  913.         Connect(-1, wxEVT_SCROLL_THUMBRELEASE, (wxObjectEventFunction)&wxDynamicSashWindowLeaf::OnScroll);
  914.     }
  915.  
  916.     wxLayoutConstraints *layout = new wxLayoutConstraints();
  917.     if (!layout)
  918.         return FALSE;
  919.     wxSize size = m_hscroll->GetBestSize();
  920. #ifdef __WXMSW__
  921.     size = m_hscroll->GetSize();
  922. #endif
  923.  
  924.     layout->left.SameAs(m_impl->m_container, wxLeft, 10);
  925.     layout->right.LeftOf(m_vscroll);
  926.     layout->bottom.SameAs(m_impl->m_container, wxBottom, 3);
  927.     layout->height.Absolute(size.GetHeight());
  928.     m_hscroll->SetConstraints(layout);
  929.  
  930.     layout = new wxLayoutConstraints();
  931.     if (!layout)
  932.         return FALSE;
  933.     size = size = m_vscroll->GetBestSize();
  934. #ifdef __WXMSW__
  935.     size = m_vscroll->GetSize();
  936. #endif
  937.  
  938.     layout->top.SameAs(m_impl->m_container, wxTop, 10);
  939.     layout->bottom.Above(m_hscroll);
  940.     layout->right.SameAs(m_impl->m_container, wxRight, 3);
  941.     layout->width.Absolute(size.GetWidth());
  942.     m_vscroll->SetConstraints(layout);
  943.  
  944.     layout = new wxLayoutConstraints();
  945.     if (!layout)
  946.         return FALSE;
  947.     layout->left.SameAs(m_impl->m_container, wxLeft, 3);
  948.     layout->right.LeftOf(m_vscroll);
  949.     layout->top.SameAs(m_impl->m_container, wxTop, 3);
  950.     layout->bottom.Above(m_hscroll);
  951.     m_viewport->SetConstraints(layout);
  952.  
  953.     m_impl->m_container->Layout();
  954.  
  955.     return success;
  956. }
  957.  
  958. void wxDynamicSashWindowLeaf::AddChild(wxWindow *window) {
  959.     if (m_child) {
  960.         m_child->Destroy();
  961.     }
  962.  
  963.     m_child = window;
  964.  
  965.     wxDynamicSashReparentEvent event(this);
  966.     AddPendingEvent(event);
  967. }
  968.  
  969. DynamicSashRegion wxDynamicSashWindowLeaf::GetRegion(int x, int y) {
  970.     wxSize size = m_impl->m_container->GetSize();
  971.     int w = size.GetWidth();
  972.     int h = size.GetHeight();
  973.     size = m_hscroll->GetSize();
  974.     int sh = size.GetHeight();
  975.     size = m_vscroll->GetSize();
  976.     int sw = size.GetWidth();
  977.  
  978.     if (x >= w - sw - 3 && x < w && y >= h - sh - 3 && y < h)
  979.         return DSR_CORNER;
  980.     if (x >= 3 && x < 10 && y >= h - sh - 3 && y < h - 2)
  981.         return DSR_VERTICAL_TAB;
  982.     if (x >= w - sw - 3 && x < w - 2 && y >= 3 && y < 10)
  983.         return DSR_HORIZONTAL_TAB;
  984.     if (x < 3)
  985.         return DSR_LEFT_EDGE;
  986.     if (y < 3)
  987.         return DSR_TOP_EDGE;
  988.     if (x >= w - 2)
  989.         return DSR_RIGHT_EDGE;
  990.     if (y >= h - 2)
  991.         return DSR_BOTTOM_EDGE;
  992.  
  993.     return DSR_NONE;
  994. }
  995.  
  996. void wxDynamicSashWindowLeaf::ResizeChild(wxSize size) {
  997.     if (m_child) {
  998.         if (m_impl->m_window->GetWindowStyle() & wxDS_MANAGE_SCROLLBARS) {
  999.             m_child->SetSize(size);
  1000.             wxSize best_size = m_child->GetBestSize();
  1001.             if (best_size.GetWidth() < size.GetWidth()) {
  1002.                 best_size.SetWidth(size.GetWidth());
  1003.             }
  1004.             if (best_size.GetHeight() < size.GetHeight()) {
  1005.                 best_size.SetHeight(size.GetHeight());
  1006.             }
  1007.             m_child->SetSize(best_size);
  1008.  
  1009.             int hpos = m_hscroll->GetThumbPosition();
  1010.             int vpos = m_vscroll->GetThumbPosition();
  1011.  
  1012.             if (hpos < 0) {
  1013.                 hpos = 0;
  1014.             }
  1015.             if (vpos < 0) {
  1016.                 vpos = 0;
  1017.             }
  1018.             if (hpos > best_size.GetWidth() - size.GetWidth()) {
  1019.                 hpos = best_size.GetWidth() - size.GetWidth();
  1020.             }
  1021.             if (vpos > best_size.GetHeight() - size.GetHeight()) {
  1022.                 vpos = best_size.GetHeight() - size.GetHeight();
  1023.             }
  1024.  
  1025.             m_hscroll->SetScrollbar(hpos, size.GetWidth(),
  1026.                                     best_size.GetWidth(), size.GetWidth());
  1027.             m_vscroll->SetScrollbar(vpos, size.GetHeight(),
  1028.                                     best_size.GetHeight(), size.GetHeight());
  1029.  
  1030.             //  Umm, the scrollbars are doing something insane under GTK+ and subtracting
  1031.             //  one from the position I pass in.  This works around that.
  1032.             m_hscroll->SetThumbPosition(hpos + hpos - m_hscroll->GetThumbPosition());
  1033.             m_vscroll->SetThumbPosition(vpos + vpos - m_vscroll->GetThumbPosition());
  1034.  
  1035.             wxPoint pos = m_child->GetPosition();
  1036.             m_viewport->ScrollWindow(-hpos - pos.x, -vpos - pos.y);
  1037.         } else {
  1038.             m_child->SetSize(size);
  1039.         }
  1040.     }
  1041. }
  1042.  
  1043. wxScrollBar *wxDynamicSashWindowLeaf::FindScrollBar(const wxWindow *child, int vert) const {
  1044.     if (m_child == child) {
  1045.         if (vert) {
  1046.             return m_vscroll;
  1047.         } else {
  1048.             return m_hscroll;
  1049.         }
  1050.     }
  1051.  
  1052.     return NULL;
  1053. }
  1054.  
  1055. void wxDynamicSashWindowLeaf::OnSize(wxSizeEvent &event) {
  1056.     m_impl->m_container->Refresh();
  1057.     ResizeChild(m_viewport->GetSize());
  1058. }
  1059.  
  1060. void wxDynamicSashWindowLeaf::OnPaint(wxPaintEvent &event) {
  1061.     wxPaintDC dc(m_impl->m_container);
  1062.     dc.SetBackground(wxBrush(m_impl->m_container->GetBackgroundColour(), wxSOLID));
  1063.     dc.Clear();
  1064.  
  1065.     wxPen highlight(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNHIGHLIGHT), 1, wxSOLID);
  1066.     wxPen shadow(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW), 1, wxSOLID);
  1067.     wxPen black(*wxBLACK, 1, wxSOLID);
  1068.  
  1069.     wxSize size = m_impl->m_container->GetSize();
  1070.     int w = size.GetWidth();
  1071.     int h = size.GetHeight();
  1072.     size = m_hscroll->GetSize();
  1073.     int sh = size.GetHeight();
  1074.     size = m_vscroll->GetSize();
  1075.     int sw = size.GetWidth();
  1076.  
  1077.     dc.SetPen(shadow);
  1078.     dc.DrawLine(1, 1, 1, h - 2);
  1079.     dc.DrawLine(1, 1, w - 2, 1);
  1080.     dc.SetPen(black);
  1081.     dc.DrawLine(2, 2, 2, h - 3);
  1082.     dc.DrawLine(2, 2, w - 3, 2);
  1083.     dc.SetPen(highlight);
  1084.     dc.DrawLine(w - 2, 2, w - 2, h - sh - 2);
  1085.     dc.DrawLine(w - 2, h - sh - 2, w - sw - 2, h - sh - 2);
  1086.     dc.DrawLine(w - sw - 2, h - sh - 2, w - sw - 2, h - 2);
  1087.     dc.DrawLine(w - sw - 2, h - 2, 2, h - 2);
  1088.  
  1089.     dc.SetPen(highlight);
  1090.     dc.DrawLine(w - sw - 2, 8, w - sw - 2, 4);
  1091.     dc.DrawLine(w - sw - 2, 4, w - 5, 4);
  1092.     dc.SetPen(shadow);
  1093.     dc.DrawLine(w - 5, 4, w - 5, 8);
  1094.     dc.DrawLine(w - 5, 8, w - sw - 2, 8);
  1095.     dc.SetPen(black);
  1096.     dc.DrawLine(w - 4, 3, w - 4, 9);
  1097.     dc.DrawLine(w - 4, 9, w - sw - 3, 9);
  1098.  
  1099.     dc.SetPen(highlight);
  1100.     dc.DrawLine(4, h - 5, 4, h - sh - 2);
  1101.     dc.DrawLine(4, h - sh - 2, 8, h - sh - 2);
  1102.     dc.SetPen(shadow);
  1103.     dc.DrawLine(8, h - sh - 2, 8, h - 5);
  1104.     dc.DrawLine(8, h - 5, 4, h - 5);
  1105.     dc.SetPen(black);
  1106.     dc.DrawLine(9, h - sh - 3, 9, h - 4);
  1107.     dc.DrawLine(9, h - 4, 3, h - 4);
  1108.  
  1109.     int cy = (h - sh + h - 6) / 2 + 1;
  1110.     int cx = (w - sw + w - 6) / 2 + 1;
  1111.     int sy = cy;
  1112.     while (sy > h - sh)
  1113.         sy -= 4;
  1114.     int sx = cx;
  1115.     while (sx > w - sw)
  1116.         sx -= 4;
  1117.  
  1118.     int x, y;
  1119.     for (y = sy; y < h - 2; y += 4) {
  1120.         for (x = sx; x < w - 2; x += 4) {
  1121.             if (x - cx >= -(y - cy)) {
  1122.                 dc.SetPen(highlight);
  1123.                 dc.DrawPoint(x, y);
  1124.                 dc.SetPen(shadow);
  1125.                 dc.DrawPoint(x + 1, y + 1);
  1126.             }
  1127.         }
  1128.     }
  1129. }
  1130.  
  1131. void wxDynamicSashWindowLeaf::OnScroll(wxScrollEvent &event) {
  1132.     int nx = -m_hscroll->GetThumbPosition();
  1133.     int ny = -m_vscroll->GetThumbPosition();
  1134.  
  1135.     if (m_child) {
  1136.         wxPoint pos = m_child->GetPosition();
  1137.  
  1138.         m_viewport->ScrollWindow(nx - pos.x, ny - pos.y);
  1139.     }
  1140. }
  1141.  
  1142. void wxDynamicSashWindowLeaf::OnFocus(wxFocusEvent &event) {
  1143.     if (event.m_eventObject == m_hscroll || event.m_eventObject == m_vscroll) {
  1144.         m_child->SetFocus();
  1145.     }
  1146. }
  1147.  
  1148.  
  1149. void wxDynamicSashWindowLeaf::OnMouseMove(wxMouseEvent &event) {
  1150.     if (m_impl->m_dragging) {
  1151.         return;
  1152.     }
  1153.  
  1154.     DynamicSashRegion region = GetRegion(event.m_x, event.m_y);
  1155.  
  1156.     wxCursor cursor(wxCURSOR_ARROW);
  1157.     if (region == DSR_HORIZONTAL_TAB) {
  1158.         cursor = wxCursor(wxCURSOR_SIZENS);
  1159.     } else if (region == DSR_VERTICAL_TAB) {
  1160.         cursor = wxCursor(wxCURSOR_SIZEWE);
  1161.     } else if ((region == DSR_CORNER) &&
  1162.                (m_impl->m_window->GetWindowStyle() & wxDS_DRAG_CORNER) != 0) {
  1163.         cursor = wxCursor(wxCURSOR_SIZENWSE);
  1164.     } else if (region == DSR_LEFT_EDGE || region == DSR_TOP_EDGE
  1165.                 || region == DSR_RIGHT_EDGE || region == DSR_BOTTOM_EDGE) {
  1166.         if (m_impl->FindParent(region)) {
  1167.             if (region == DSR_LEFT_EDGE || region == DSR_RIGHT_EDGE) {
  1168.                 cursor = wxCursor(wxCURSOR_SIZEWE);
  1169.             } else {
  1170.                 cursor = wxCursor(wxCURSOR_SIZENS);
  1171.             }
  1172.         }
  1173.     }
  1174.  
  1175.     m_impl->m_container->SetCursor(cursor);
  1176. }
  1177.  
  1178. void wxDynamicSashWindowLeaf::OnLeave(wxMouseEvent &event) {
  1179.     wxCursor cursor(wxCURSOR_ARROW);
  1180.     m_impl->m_container->SetCursor(cursor);
  1181. }
  1182.  
  1183.  
  1184. void wxDynamicSashWindowLeaf::OnPress(wxMouseEvent &event) {
  1185.     DynamicSashRegion region = GetRegion(event.m_x, event.m_y);
  1186.  
  1187.     if ((region == DSR_CORNER) && (m_impl->m_window->GetWindowStyle() & wxDS_DRAG_CORNER) == 0)
  1188.         return;
  1189.  
  1190.     if (region == DSR_HORIZONTAL_TAB || region == DSR_VERTICAL_TAB || region == DSR_CORNER) {
  1191.         m_impl->m_dragging = region;
  1192.         m_impl->m_drag_x = event.m_x;
  1193.         m_impl->m_drag_y = event.m_y;
  1194.         m_impl->DrawSash(event.m_x, event.m_y);
  1195.         m_impl->m_container->CaptureMouse();
  1196.     } else if (region == DSR_LEFT_EDGE || region == DSR_TOP_EDGE
  1197.                 || region == DSR_RIGHT_EDGE || region == DSR_BOTTOM_EDGE) {
  1198.         wxDynamicSashWindowImpl *parent = m_impl->FindParent(region);
  1199.  
  1200.         if (parent) {
  1201.             int x = event.m_x;
  1202.             int y = event.m_y;
  1203.  
  1204.             m_impl->m_container->ClientToScreen(&x, &y);
  1205.             parent->m_container->ScreenToClient(&x, &y);
  1206.  
  1207.             parent->m_dragging = parent->m_split;
  1208.             parent->m_drag_x = x;
  1209.             parent->m_drag_y = y;
  1210.             parent->DrawSash(x, y);
  1211.             parent->m_container->CaptureMouse();
  1212.         }
  1213.     }
  1214. }
  1215.  
  1216. void wxDynamicSashWindowLeaf::OnRelease(wxMouseEvent &event) {
  1217. }
  1218.  
  1219. void wxDynamicSashWindowLeaf::OnReparent(wxEvent &event) {
  1220.     if (m_child) {
  1221.         m_child->Reparent(m_viewport);
  1222.     }
  1223.  
  1224.     ResizeChild(m_viewport->GetSize());
  1225. }
  1226.  
  1227. // wxDynamicSashSplitEvent //////////////////////////////////////////////////
  1228.  
  1229. wxDynamicSashSplitEvent::wxDynamicSashSplitEvent() {
  1230.     m_eventObject = NULL;
  1231.     m_eventType = wxEVT_DYNAMIC_SASH_SPLIT;
  1232. }
  1233.  
  1234. wxDynamicSashSplitEvent::wxDynamicSashSplitEvent(wxObject *object) {
  1235.     m_eventObject = object;
  1236.     m_eventType = wxEVT_DYNAMIC_SASH_SPLIT;
  1237. }
  1238.  
  1239. IMPLEMENT_DYNAMIC_CLASS(wxDynamicSashSplitEvent, wxCommandEvent)
  1240.  
  1241. // wxDynamicSashUnifyEvent //////////////////////////////////////////////////
  1242.  
  1243. wxDynamicSashUnifyEvent::wxDynamicSashUnifyEvent() {
  1244.     m_eventObject = NULL;
  1245.     m_eventType = wxEVT_DYNAMIC_SASH_UNIFY;
  1246. }
  1247.  
  1248. wxDynamicSashUnifyEvent::wxDynamicSashUnifyEvent(wxObject *object) {
  1249.     m_eventObject = object;
  1250.     m_eventType = wxEVT_DYNAMIC_SASH_UNIFY;
  1251. }
  1252.  
  1253. IMPLEMENT_DYNAMIC_CLASS(wxDynamicSashUnifyEvent, wxCommandEvent)
  1254.  
  1255. // wxDynamicSsahReparentEvent ///////////////////////////////////////////////
  1256.  
  1257. wxDynamicSashReparentEvent::wxDynamicSashReparentEvent() {
  1258.     m_eventObject = NULL;
  1259.     m_eventType = wxEVT_DYNAMIC_SASH_REPARENT;
  1260. }
  1261.  
  1262. wxDynamicSashReparentEvent::wxDynamicSashReparentEvent(wxObject *object) {
  1263.     m_eventObject = object;
  1264.     m_eventType = wxEVT_DYNAMIC_SASH_REPARENT;
  1265. }
  1266.  
  1267. wxDynamicSashReparentEvent::wxDynamicSashReparentEvent(const wxDynamicSashReparentEvent& evt)
  1268.     : wxEvent(evt)
  1269. {
  1270. }
  1271.  
  1272. IMPLEMENT_DYNAMIC_CLASS(wxDynamicSashReparentEvent, wxEvent)
  1273.  
  1274. /////////////////////////////////////////////////////////////////////////////
  1275.