should use the MDI Child, not it's parent. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@29674 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
1315 lines
43 KiB
C++
1315 lines
43 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
// 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
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#ifdef __GNUG__
|
|
#pragma implementation "splittree.h"
|
|
#endif
|
|
|
|
// For compilers that support precompilation, includes "wx/wx.h".
|
|
#include "wx/wxprec.h"
|
|
|
|
#ifdef __BORLANDC__
|
|
#pragma hdrstop
|
|
#endif
|
|
|
|
// for all others, include the necessary headers (this file is usually all you
|
|
// need because it includes almost all "standard" wxWidgets headers)
|
|
#ifndef WX_PRECOMP
|
|
#include "wx/wx.h"
|
|
#endif
|
|
|
|
#ifdef __WXMSW__
|
|
#include "wx/mdi.h"
|
|
#endif
|
|
|
|
#include "wx/gizmos/dynamicsash.h"
|
|
|
|
|
|
const wxChar* wxDynamicSashWindowNameStr = wxT("dynamicSashWindow");
|
|
|
|
|
|
/*
|
|
wxDynamicSashWindow works by internally storing a tree of Implementation
|
|
objects (wxDynamicSsahWindowImpl) and Leaf objects
|
|
(wxDynamicSashWindowLeaf). The wxDynamicSashWindow has a pointer to one
|
|
implementation, and each implementation either has a pointer to a one
|
|
leaf (m_leaf) or a pointer to two children implementation objects
|
|
(m_child). The leaves each are responsible for drawing the frame and
|
|
decorations around one user-provided views and for responding to mouse
|
|
and scrollbar events.
|
|
|
|
A resulting tree might look something like this:
|
|
|
|
wxDynamicSashWindow
|
|
|
|
|
+- wxDynamicSashWindowImpl
|
|
|
|
|
+- wxDynamicSashWindowLeaf
|
|
| |
|
|
| +- user view window
|
|
|
|
|
+- wxDynamicSashWindowImpl
|
|
|
|
|
+- wxDynamicSashWindowLeaf
|
|
| |
|
|
| +- user view window
|
|
|
|
|
+- wxDynamicSashWindowLeaf
|
|
|
|
|
+- user view window
|
|
|
|
Each time a split occurs, one of the implementation objects removes its
|
|
leaf, generates two new implementation object children, each with a new
|
|
leaf, and reparents the user view which was connected to its old leaf
|
|
to be one of the new leaf's user view, and sends a Split event to the
|
|
user view in the hopes that it will generate a new user view for the
|
|
other new leaf.
|
|
|
|
When a unification ocurrs, an implementation object is replaced by one
|
|
of its children, and the tree of its other child is pruned.
|
|
|
|
One quirk is that the top-level implementation object (m_top) always
|
|
keeps a pointer to the implementation object where a new child is needed.
|
|
(m_add_child_target). This is so that when a new uesr view is added
|
|
to the hierarchy, AddChild() is able to reparent the new user view to
|
|
the correct implementation object's leaf.
|
|
|
|
*/
|
|
|
|
#include <wx/dcmemory.h>
|
|
#include <wx/dcscreen.h>
|
|
#include <wx/layout.h>
|
|
#include <wx/scrolbar.h>
|
|
#include <wx/settings.h>
|
|
|
|
|
|
#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);
|
|
wxDynamicSashReparentEvent(const wxDynamicSashReparentEvent& evt);
|
|
|
|
virtual wxEvent* Clone() const { return new wxDynamicSashReparentEvent(*this); }
|
|
|
|
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(wxID_ANY, wxEVT_SIZE, (wxObjectEventFunction)
|
|
(wxEventFunction)
|
|
(wxSizeEventFunction)&wxDynamicSashWindowImpl::OnSize);
|
|
Connect(wxID_ANY, wxEVT_PAINT, (wxObjectEventFunction)
|
|
(wxEventFunction)
|
|
(wxPaintEventFunction)&wxDynamicSashWindowImpl::OnPaint);
|
|
Connect(wxID_ANY, wxEVT_MOTION, (wxObjectEventFunction)
|
|
(wxEventFunction)
|
|
(wxMouseEventFunction)&wxDynamicSashWindowImpl::OnMouseMove);
|
|
Connect(wxID_ANY, wxEVT_ENTER_WINDOW, (wxObjectEventFunction)
|
|
(wxEventFunction)
|
|
(wxMouseEventFunction)&wxDynamicSashWindowImpl::OnMouseMove);
|
|
Connect(wxID_ANY, wxEVT_LEAVE_WINDOW, (wxObjectEventFunction)
|
|
(wxEventFunction)
|
|
(wxMouseEventFunction)&wxDynamicSashWindowImpl::OnLeave);
|
|
Connect(wxID_ANY, wxEVT_LEFT_DOWN, (wxObjectEventFunction)
|
|
(wxEventFunction)
|
|
(wxMouseEventFunction)&wxDynamicSashWindowImpl::OnPress);
|
|
Connect(wxID_ANY, wxEVT_LEFT_UP, (wxObjectEventFunction)
|
|
(wxEventFunction)
|
|
(wxMouseEventFunction)&wxDynamicSashWindowImpl::OnRelease);
|
|
|
|
return true;
|
|
}
|
|
|
|
void wxDynamicSashWindowImpl::AddChild(wxWindow *window) {
|
|
if (m_add_child_target && m_add_child_target->m_leaf) {
|
|
m_add_child_target->m_leaf->AddChild(window);
|
|
}
|
|
}
|
|
|
|
void wxDynamicSashWindowImpl::DrawSash(int x, int y) const {
|
|
int i, j;
|
|
|
|
wxScreenDC dc;
|
|
dc.StartDrawingOnTop(m_container);
|
|
|
|
wxBitmap bmp(8, 8);
|
|
wxMemoryDC bdc;
|
|
bdc.SelectObject(bmp);
|
|
bdc.DrawRectangle(-1, -1, 10, 10);
|
|
for (i = 0; i < 8; i++) {
|
|
for (j = 0; j < 8; j++) {
|
|
if ((i + j) & 1) {
|
|
bdc.DrawPoint(i, j);
|
|
}
|
|
}
|
|
}
|
|
|
|
wxBrush brush(bmp);
|
|
dc.SetBrush(brush);
|
|
dc.SetLogicalFunction(wxXOR);
|
|
|
|
if ((m_dragging == DSR_CORNER) &&
|
|
(m_window->GetWindowStyle() & wxDS_DRAG_CORNER) != 0) {
|
|
int cx = 0;
|
|
int cy = 0;
|
|
|
|
m_container->ClientToScreen(&cx, &cy);
|
|
m_container->ClientToScreen(&x, &y);
|
|
|
|
if (cx < x && cy < y) {
|
|
dc.DrawRectangle(cx - 2, cy - 2, x - cx + 4, 4);
|
|
dc.DrawRectangle(x - 2, cy + 2, 4, y - cy);
|
|
dc.DrawRectangle(cx - 2, cy + 2, 4, y - cy);
|
|
dc.DrawRectangle(cx + 2, y - 2, x - cx - 4, 4);
|
|
}
|
|
} else {
|
|
int body_w, body_h;
|
|
m_container->GetClientSize(&body_w, &body_h);
|
|
|
|
if (y < 0)
|
|
y = 0;
|
|
if (y > body_h)
|
|
y = body_h;
|
|
if (x < 0)
|
|
x = 0;
|
|
if (x > body_w)
|
|
x = body_w;
|
|
|
|
if (m_dragging == DSR_HORIZONTAL_TAB)
|
|
x = 0;
|
|
else
|
|
y = 0;
|
|
|
|
m_container->ClientToScreen(&x, &y);
|
|
|
|
int w, h;
|
|
w = body_w; h = body_h;
|
|
|
|
if (m_dragging == DSR_HORIZONTAL_TAB)
|
|
dc.DrawRectangle(x, y - 2, w, 4);
|
|
else
|
|
dc.DrawRectangle(x - 2, y, 4, h);
|
|
}
|
|
|
|
dc.EndDrawingOnTop();
|
|
}
|
|
|
|
wxDynamicSashWindowImpl *wxDynamicSashWindowImpl::FindParent(DynamicSashRegion side) const {
|
|
if (m_parent == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
if (m_parent->m_split == DSR_HORIZONTAL_TAB) {
|
|
if (side == DSR_TOP_EDGE && m_parent->m_child[1] == this)
|
|
return m_parent;
|
|
if (side == DSR_BOTTOM_EDGE && m_parent->m_child[0] == this)
|
|
return m_parent;
|
|
} else if (m_parent->m_split == DSR_VERTICAL_TAB) {
|
|
if (side == DSR_LEFT_EDGE && m_parent->m_child[1] == this)
|
|
return m_parent;
|
|
if (side == DSR_RIGHT_EDGE && m_parent->m_child[0] == this)
|
|
return m_parent;
|
|
}
|
|
|
|
return m_parent->FindParent(side);
|
|
}
|
|
|
|
wxDynamicSashWindowImpl *wxDynamicSashWindowImpl::FindUpperParent(wxDynamicSashWindowImpl *sash_a,
|
|
wxDynamicSashWindowImpl *sash_b) const {
|
|
wxWindow *win;
|
|
win = sash_a->m_container->GetParent();
|
|
while (win && !win->IsTopLevel()) {
|
|
if (win == sash_b->m_container) {
|
|
return sash_b;
|
|
}
|
|
|
|
win = win->GetParent();
|
|
}
|
|
|
|
return sash_a;
|
|
}
|
|
|
|
|
|
wxWindow *wxDynamicSashWindowImpl::FindFrame() const {
|
|
wxWindow *win;
|
|
|
|
win = m_window->GetParent();
|
|
while (win && !win->IsTopLevel()
|
|
#ifdef __WXMSW__
|
|
&& ! wxIsKindOf(win, wxMDIChildFrame) // not top-level but still a frame
|
|
#endif
|
|
) {
|
|
win = win->GetParent();
|
|
}
|
|
|
|
return win;
|
|
}
|
|
|
|
wxScrollBar *wxDynamicSashWindowImpl::FindScrollBar(const wxWindow *child, int vert) const {
|
|
if (m_child[0] == NULL && m_leaf == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
if (!m_child[0]) {
|
|
return m_leaf->FindScrollBar(child, vert);
|
|
} 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_add_child_target = NULL;
|
|
|
|
m_child[0] = new wxDynamicSashWindowImpl(m_window);
|
|
m_child[0]->m_container = new wxWindow(m_container, wxID_ANY);
|
|
m_child[0]->m_parent = this;
|
|
m_child[0]->m_top = m_top;
|
|
m_child[0]->Create();
|
|
if (m_leaf->m_child) {
|
|
m_leaf->m_child->Reparent(m_container);
|
|
m_child[0]->AddChild(m_leaf->m_child);
|
|
}
|
|
|
|
m_child[1] = new wxDynamicSashWindowImpl(m_window);
|
|
m_child[1]->m_container = new wxWindow(m_container, wxID_ANY);
|
|
m_child[1]->m_parent = this;
|
|
m_child[1]->m_top = m_top;
|
|
m_child[1]->Create();
|
|
|
|
m_split = m_dragging;
|
|
ConstrainChildren(px, py);
|
|
|
|
m_top->m_add_child_target = m_child[1];
|
|
wxDynamicSashSplitEvent split(m_child[0]->m_leaf->m_child);
|
|
m_child[0]->m_leaf->m_child->ProcessEvent(split);
|
|
|
|
m_child[0]->m_leaf->m_vscroll->SetScrollbar(m_leaf->m_vscroll->GetThumbPosition(),
|
|
m_leaf->m_vscroll->GetThumbSize(),
|
|
m_leaf->m_vscroll->GetRange(),
|
|
m_leaf->m_vscroll->GetPageSize());
|
|
m_child[0]->m_leaf->m_hscroll->SetScrollbar(m_leaf->m_hscroll->GetThumbPosition(),
|
|
m_leaf->m_hscroll->GetThumbSize(),
|
|
m_leaf->m_hscroll->GetRange(),
|
|
m_leaf->m_hscroll->GetPageSize());
|
|
m_child[1]->m_leaf->m_vscroll->SetScrollbar(m_leaf->m_vscroll->GetThumbPosition(),
|
|
m_leaf->m_vscroll->GetThumbSize(),
|
|
m_leaf->m_vscroll->GetRange(),
|
|
m_leaf->m_vscroll->GetPageSize());
|
|
m_child[1]->m_leaf->m_hscroll->SetScrollbar(m_leaf->m_hscroll->GetThumbPosition(),
|
|
m_leaf->m_hscroll->GetThumbSize(),
|
|
m_leaf->m_hscroll->GetRange(),
|
|
m_leaf->m_hscroll->GetPageSize());
|
|
delete m_leaf;
|
|
m_leaf = NULL;
|
|
|
|
m_container->Layout();
|
|
}
|
|
|
|
|
|
/* This code is called when you finish resizing a view by dragging the
|
|
corner tab, but I think this implementation is lousy and will surprise
|
|
the user more often than it will do what they are trying to do. What
|
|
I really need to be doing here is do a rewrite such that *no* sashes
|
|
move except the ones immediately to the bottom and right of this window,
|
|
and handle the case where you resize a window larger than it's neighbors
|
|
by destroying the neighbors.
|
|
|
|
But this will do for now. */
|
|
void wxDynamicSashWindowImpl::Resize(int x, int y) {
|
|
wxDynamicSashWindowImpl *h_parent = FindParent(DSR_BOTTOM_EDGE);
|
|
wxDynamicSashWindowImpl *v_parent = FindParent(DSR_RIGHT_EDGE);
|
|
int h_unify = -1;
|
|
int v_unify = -1;
|
|
wxWindow *frame = FindFrame();
|
|
|
|
if (x < 0) {
|
|
x = 0;
|
|
}
|
|
if (y < 0) {
|
|
y = 0;
|
|
}
|
|
|
|
if (h_parent) {
|
|
m_container->ClientToScreen(NULL, &y);
|
|
h_parent->m_container->ScreenToClient(NULL, &y);
|
|
|
|
int py = (int)((y * 100) / h_parent->m_container->GetSize().GetHeight() + 0.5);
|
|
|
|
if (py < 10) {
|
|
wxDynamicSashWindowImpl *ho_parent = FindParent(DSR_TOP_EDGE);
|
|
|
|
if (ho_parent) {
|
|
if (FindUpperParent(h_parent, ho_parent) == ho_parent) {
|
|
h_unify = 1;
|
|
} else {
|
|
py = (int)((ho_parent->m_child[0]->m_container->GetSize().GetHeight() * 100)
|
|
/ h_parent->m_container->GetSize().GetHeight() + 0.5);
|
|
h_parent->m_child[0]->m_container->GetConstraints()->height.PercentOf(
|
|
h_parent->m_container, wxHeight, py);
|
|
|
|
h_parent = ho_parent;
|
|
h_unify = 0;
|
|
}
|
|
} else {
|
|
h_unify = 1;
|
|
}
|
|
} else if (py > 90) {
|
|
h_unify = 0;
|
|
} else {
|
|
h_parent->m_child[0]->m_container->GetConstraints()->height.PercentOf(
|
|
h_parent->m_container, wxHeight, py);
|
|
h_parent->m_container->Layout();
|
|
}
|
|
} else {
|
|
int do_resize = 1;
|
|
h_parent = FindParent(DSR_TOP_EDGE);
|
|
|
|
if (h_parent) {
|
|
int py = (int)((y * 100) /
|
|
(h_parent->m_container->GetSize().GetHeight() +
|
|
y - m_container->GetSize().GetHeight()) + 0.5);
|
|
|
|
if (py < 10) {
|
|
h_unify = 0;
|
|
}
|
|
} else if (y < 64) {
|
|
do_resize = 0;
|
|
}
|
|
|
|
if (do_resize) {
|
|
wxSize size = frame->GetSize();
|
|
frame->SetSize(size.GetWidth(), size.GetHeight() + y - m_container->GetSize().GetHeight());
|
|
}
|
|
}
|
|
|
|
if (v_parent) {
|
|
m_container->ClientToScreen(&x, NULL);
|
|
v_parent->m_container->ScreenToClient(&x, NULL);
|
|
|
|
int px = (int)((x * 100) / v_parent->m_container->GetSize().GetWidth() + 0.5);
|
|
|
|
if (px < 10) {
|
|
wxDynamicSashWindowImpl *vo_parent = FindParent(DSR_LEFT_EDGE);
|
|
|
|
if (vo_parent) {
|
|
if (FindUpperParent(v_parent, vo_parent) == vo_parent) {
|
|
v_unify = 1;
|
|
} else {
|
|
px = (int)((vo_parent->m_child[0]->m_container->GetSize().GetWidth() * 100)
|
|
/ v_parent->m_container->GetSize().GetWidth() + 0.5);
|
|
v_parent->m_child[0]->m_container->GetConstraints()->width.PercentOf(
|
|
v_parent->m_container, wxWidth, px);
|
|
|
|
v_parent = vo_parent;
|
|
v_unify = 0;
|
|
}
|
|
} else {
|
|
v_unify = 1;
|
|
}
|
|
} else if (px > 90) {
|
|
v_unify = 0;
|
|
} else {
|
|
v_parent->m_child[0]->m_container->GetConstraints()->width.PercentOf(
|
|
v_parent->m_container, wxWidth, px);
|
|
v_parent->m_container->Layout();
|
|
}
|
|
} else {
|
|
int do_resize = 1;
|
|
v_parent = FindParent(DSR_LEFT_EDGE);
|
|
|
|
if (v_parent) {
|
|
int px = (int)((x * 100) /
|
|
(v_parent->m_container->GetSize().GetWidth() +
|
|
x - m_container->GetSize().GetWidth()) + 0.5);
|
|
|
|
if (px < 10) {
|
|
v_unify = 0;
|
|
}
|
|
} else if (x < 64) {
|
|
do_resize = 0;
|
|
}
|
|
|
|
if (do_resize) {
|
|
wxSize size = frame->GetSize();
|
|
frame->SetSize(size.GetWidth() + x - m_container->GetSize().GetWidth(), size.GetHeight());
|
|
}
|
|
}
|
|
|
|
if (h_unify != -1 && v_unify != -1) {
|
|
wxDynamicSashWindowImpl *parent = FindUpperParent(h_parent, v_parent);
|
|
|
|
if (parent == h_parent) {
|
|
h_parent->Unify(h_unify);
|
|
} else {
|
|
v_parent->Unify(v_unify);
|
|
}
|
|
} else if (h_unify != -1) {
|
|
h_parent->Unify(h_unify);
|
|
} else if (v_unify != -1) {
|
|
v_parent->Unify(v_unify);
|
|
}
|
|
}
|
|
|
|
|
|
void wxDynamicSashWindowImpl::OnSize(wxSizeEvent &event) {
|
|
m_container->Layout();
|
|
|
|
if (m_leaf)
|
|
m_leaf->OnSize(event);
|
|
}
|
|
|
|
void wxDynamicSashWindowImpl::OnPaint(wxPaintEvent &event) {
|
|
if (m_leaf)
|
|
m_leaf->OnPaint(event);
|
|
else {
|
|
wxPaintDC dc(m_container);
|
|
dc.SetBackground(wxBrush(m_container->GetBackgroundColour(), wxSOLID));
|
|
dc.Clear();
|
|
}
|
|
}
|
|
|
|
void wxDynamicSashWindowImpl::OnMouseMove(wxMouseEvent &event) {
|
|
if (m_dragging) {
|
|
DrawSash(m_drag_x, m_drag_y);
|
|
m_drag_x = event.m_x; m_drag_y = event.m_y;
|
|
DrawSash(m_drag_x, m_drag_y);
|
|
} else if (m_leaf) {
|
|
m_leaf->OnMouseMove(event);
|
|
}
|
|
}
|
|
|
|
void wxDynamicSashWindowImpl::OnLeave(wxMouseEvent &event) {
|
|
if (m_leaf) {
|
|
m_leaf->OnLeave(event);
|
|
}
|
|
}
|
|
|
|
void wxDynamicSashWindowImpl::OnPress(wxMouseEvent &event) {
|
|
if (m_leaf) {
|
|
m_leaf->OnPress(event);
|
|
} else {
|
|
m_dragging = m_split;
|
|
m_drag_x = event.m_x;
|
|
m_drag_y = event.m_y;
|
|
DrawSash(m_drag_x, m_drag_y);
|
|
m_container->CaptureMouse();
|
|
}
|
|
}
|
|
|
|
void wxDynamicSashWindowImpl::OnRelease(wxMouseEvent &event) {
|
|
if ((m_dragging == DSR_CORNER) &&
|
|
(m_window->GetWindowStyle() & wxDS_DRAG_CORNER) != 0) {
|
|
DrawSash(m_drag_x, m_drag_y);
|
|
m_container->ReleaseMouse();
|
|
|
|
Resize(event.m_x, event.m_y);
|
|
|
|
m_dragging = DSR_NONE;
|
|
} else if (m_dragging) {
|
|
DrawSash(m_drag_x, m_drag_y);
|
|
m_container->ReleaseMouse();
|
|
|
|
wxSize size = m_container->GetSize();
|
|
int px = (int)((event.m_x * 100) / size.GetWidth() + 0.5);
|
|
int py = (int)((event.m_y * 100) / size.GetHeight() + 0.5);
|
|
|
|
if ((m_dragging == DSR_HORIZONTAL_TAB && py >= 10 && py <= 90)
|
|
|| (m_dragging == DSR_VERTICAL_TAB && px >= 10 && px <= 90)) {
|
|
if (m_child[0] == NULL) {
|
|
Split(px, py);
|
|
} else {
|
|
/* It would be nice if moving *this* sash didn't implicitly move
|
|
the sashes of our children (if any). But this will do. */
|
|
wxLayoutConstraints *layout = m_child[0]->m_container->GetConstraints();
|
|
if (m_split == DSR_HORIZONTAL_TAB) {
|
|
layout->height.PercentOf(m_container, wxHeight, py);
|
|
} else {
|
|
layout->width.PercentOf(m_container, wxWidth, px);
|
|
}
|
|
m_container->Layout();
|
|
}
|
|
} else {
|
|
if (m_child[0] != NULL) {
|
|
if ((m_dragging == DSR_HORIZONTAL_TAB && py <= 10)
|
|
|| (m_dragging == DSR_VERTICAL_TAB && px <= 10)) {
|
|
Unify(1);
|
|
} else {
|
|
Unify(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
wxCursor cursor(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, wxID_ANY, wxDefaultPosition, wxDefaultSize,
|
|
wxSB_HORIZONTAL);
|
|
success = success && m_vscroll->Create(m_impl->m_container, wxID_ANY, wxDefaultPosition, wxDefaultSize,
|
|
wxSB_VERTICAL);
|
|
success = success && m_viewport->Create(m_impl->m_container, wxID_ANY);
|
|
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(wxID_ANY, wxEVT_DYNAMIC_SASH_REPARENT, (wxObjectEventFunction)&wxDynamicSashWindowLeaf::OnReparent);
|
|
|
|
if (m_impl->m_window->GetWindowStyle() & wxDS_MANAGE_SCROLLBARS) {
|
|
m_hscroll->SetEventHandler(this);
|
|
m_vscroll->SetEventHandler(this);
|
|
|
|
Connect(wxID_ANY, wxEVT_SET_FOCUS, (wxObjectEventFunction)
|
|
(wxEventFunction)
|
|
(wxFocusEventFunction)&wxDynamicSashWindowLeaf::OnFocus);
|
|
Connect(wxID_ANY, wxEVT_SCROLL_TOP, (wxObjectEventFunction)
|
|
(wxEventFunction)
|
|
(wxScrollEventFunction)&wxDynamicSashWindowLeaf::OnScroll);
|
|
Connect(wxID_ANY, wxEVT_SCROLL_BOTTOM, (wxObjectEventFunction)
|
|
(wxEventFunction)
|
|
(wxScrollEventFunction)&wxDynamicSashWindowLeaf::OnScroll);
|
|
Connect(wxID_ANY, wxEVT_SCROLL_LINEUP, (wxObjectEventFunction)
|
|
(wxEventFunction)
|
|
(wxScrollEventFunction)&wxDynamicSashWindowLeaf::OnScroll);
|
|
Connect(wxID_ANY, wxEVT_SCROLL_LINEDOWN, (wxObjectEventFunction)
|
|
(wxEventFunction)
|
|
(wxScrollEventFunction)&wxDynamicSashWindowLeaf::OnScroll);
|
|
Connect(wxID_ANY, wxEVT_SCROLL_PAGEUP, (wxObjectEventFunction)
|
|
(wxEventFunction)
|
|
(wxScrollEventFunction)&wxDynamicSashWindowLeaf::OnScroll);
|
|
Connect(wxID_ANY, wxEVT_SCROLL_PAGEDOWN, (wxObjectEventFunction)
|
|
(wxEventFunction)
|
|
(wxScrollEventFunction)&wxDynamicSashWindowLeaf::OnScroll);
|
|
Connect(wxID_ANY, wxEVT_SCROLL_THUMBTRACK, (wxObjectEventFunction)
|
|
(wxEventFunction)
|
|
(wxScrollEventFunction)&wxDynamicSashWindowLeaf::OnScroll);
|
|
Connect(wxID_ANY, wxEVT_SCROLL_THUMBRELEASE, (wxObjectEventFunction)
|
|
(wxEventFunction)
|
|
(wxScrollEventFunction)&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() & wxDS_MANAGE_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 &WXUNUSED(event)) {
|
|
m_impl->m_container->Refresh();
|
|
ResizeChild(m_viewport->GetSize());
|
|
}
|
|
|
|
void wxDynamicSashWindowLeaf::OnPaint(wxPaintEvent &WXUNUSED(event)) {
|
|
wxPaintDC dc(m_impl->m_container);
|
|
dc.SetBackground(wxBrush(m_impl->m_container->GetBackgroundColour(), wxSOLID));
|
|
dc.Clear();
|
|
|
|
wxPen highlight(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNHIGHLIGHT), 1, wxSOLID);
|
|
wxPen shadow(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW), 1, wxSOLID);
|
|
wxPen black(*wxBLACK, 1, wxSOLID);
|
|
|
|
wxSize size = m_impl->m_container->GetSize();
|
|
int w = size.GetWidth();
|
|
int h = size.GetHeight();
|
|
size = m_hscroll->GetSize();
|
|
int sh = size.GetHeight();
|
|
size = m_vscroll->GetSize();
|
|
int sw = size.GetWidth();
|
|
|
|
dc.SetPen(shadow);
|
|
dc.DrawLine(1, 1, 1, h - 2);
|
|
dc.DrawLine(1, 1, w - 2, 1);
|
|
dc.SetPen(black);
|
|
dc.DrawLine(2, 2, 2, h - 3);
|
|
dc.DrawLine(2, 2, w - 3, 2);
|
|
dc.SetPen(highlight);
|
|
dc.DrawLine(w - 2, 2, w - 2, h - sh - 2);
|
|
dc.DrawLine(w - 2, h - sh - 2, w - sw - 2, h - sh - 2);
|
|
dc.DrawLine(w - sw - 2, h - sh - 2, w - sw - 2, h - 2);
|
|
dc.DrawLine(w - sw - 2, h - 2, 2, h - 2);
|
|
|
|
dc.SetPen(highlight);
|
|
dc.DrawLine(w - sw - 2, 8, w - sw - 2, 4);
|
|
dc.DrawLine(w - sw - 2, 4, w - 5, 4);
|
|
dc.SetPen(shadow);
|
|
dc.DrawLine(w - 5, 4, w - 5, 8);
|
|
dc.DrawLine(w - 5, 8, w - sw - 2, 8);
|
|
dc.SetPen(black);
|
|
dc.DrawLine(w - 4, 3, w - 4, 9);
|
|
dc.DrawLine(w - 4, 9, w - sw - 3, 9);
|
|
|
|
dc.SetPen(highlight);
|
|
dc.DrawLine(4, h - 5, 4, h - sh - 2);
|
|
dc.DrawLine(4, h - sh - 2, 8, h - sh - 2);
|
|
dc.SetPen(shadow);
|
|
dc.DrawLine(8, h - sh - 2, 8, h - 5);
|
|
dc.DrawLine(8, h - 5, 4, h - 5);
|
|
dc.SetPen(black);
|
|
dc.DrawLine(9, h - sh - 3, 9, h - 4);
|
|
dc.DrawLine(9, h - 4, 3, h - 4);
|
|
|
|
int cy = (h - sh + h - 6) / 2 + 1;
|
|
int cx = (w - sw + w - 6) / 2 + 1;
|
|
int sy = cy;
|
|
while (sy > h - sh)
|
|
sy -= 4;
|
|
int sx = cx;
|
|
while (sx > w - sw)
|
|
sx -= 4;
|
|
|
|
int x, y;
|
|
for (y = sy; y < h - 2; y += 4) {
|
|
for (x = sx; x < w - 2; x += 4) {
|
|
if (x - cx >= -(y - cy)) {
|
|
dc.SetPen(highlight);
|
|
dc.DrawPoint(x, y);
|
|
dc.SetPen(shadow);
|
|
dc.DrawPoint(x + 1, y + 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void wxDynamicSashWindowLeaf::OnScroll(wxScrollEvent &WXUNUSED(event)) {
|
|
int nx = -m_hscroll->GetThumbPosition();
|
|
int ny = -m_vscroll->GetThumbPosition();
|
|
|
|
if (m_child) {
|
|
wxPoint pos = m_child->GetPosition();
|
|
|
|
m_viewport->ScrollWindow(nx - pos.x, ny - pos.y);
|
|
}
|
|
}
|
|
|
|
void wxDynamicSashWindowLeaf::OnFocus(wxFocusEvent &event) {
|
|
if (event.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) &&
|
|
(m_impl->m_window->GetWindowStyle() & wxDS_DRAG_CORNER) != 0) {
|
|
cursor = wxCursor(wxCURSOR_SIZENWSE);
|
|
} else if (region == DSR_LEFT_EDGE || region == DSR_TOP_EDGE
|
|
|| region == DSR_RIGHT_EDGE || region == DSR_BOTTOM_EDGE) {
|
|
if (m_impl->FindParent(region)) {
|
|
if (region == DSR_LEFT_EDGE || region == DSR_RIGHT_EDGE) {
|
|
cursor = wxCursor(wxCURSOR_SIZEWE);
|
|
} else {
|
|
cursor = wxCursor(wxCURSOR_SIZENS);
|
|
}
|
|
}
|
|
}
|
|
|
|
m_impl->m_container->SetCursor(cursor);
|
|
}
|
|
|
|
void wxDynamicSashWindowLeaf::OnLeave(wxMouseEvent &WXUNUSED(event)) {
|
|
wxCursor cursor(wxCURSOR_ARROW);
|
|
m_impl->m_container->SetCursor(cursor);
|
|
}
|
|
|
|
|
|
void wxDynamicSashWindowLeaf::OnPress(wxMouseEvent &event) {
|
|
DynamicSashRegion region = GetRegion(event.m_x, event.m_y);
|
|
|
|
if ((region == DSR_CORNER) && (m_impl->m_window->GetWindowStyle() & wxDS_DRAG_CORNER) == 0)
|
|
return;
|
|
|
|
if (region == DSR_HORIZONTAL_TAB || region == DSR_VERTICAL_TAB || region == DSR_CORNER) {
|
|
m_impl->m_dragging = region;
|
|
m_impl->m_drag_x = event.m_x;
|
|
m_impl->m_drag_y = event.m_y;
|
|
m_impl->DrawSash(event.m_x, event.m_y);
|
|
m_impl->m_container->CaptureMouse();
|
|
} else if (region == DSR_LEFT_EDGE || region == DSR_TOP_EDGE
|
|
|| region == DSR_RIGHT_EDGE || region == DSR_BOTTOM_EDGE) {
|
|
wxDynamicSashWindowImpl *parent = m_impl->FindParent(region);
|
|
|
|
if (parent) {
|
|
int x = event.m_x;
|
|
int y = event.m_y;
|
|
|
|
m_impl->m_container->ClientToScreen(&x, &y);
|
|
parent->m_container->ScreenToClient(&x, &y);
|
|
|
|
parent->m_dragging = parent->m_split;
|
|
parent->m_drag_x = x;
|
|
parent->m_drag_y = y;
|
|
parent->DrawSash(x, y);
|
|
parent->m_container->CaptureMouse();
|
|
}
|
|
}
|
|
}
|
|
|
|
void wxDynamicSashWindowLeaf::OnRelease(wxMouseEvent &WXUNUSED(event)) {
|
|
}
|
|
|
|
void wxDynamicSashWindowLeaf::OnReparent(wxEvent &WXUNUSED(event)) {
|
|
if (m_child) {
|
|
m_child->Reparent(m_viewport);
|
|
}
|
|
|
|
ResizeChild(m_viewport->GetSize());
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
|
|
wxDynamicSashReparentEvent::wxDynamicSashReparentEvent(const wxDynamicSashReparentEvent& evt)
|
|
: wxEvent(evt)
|
|
{
|
|
}
|
|
|
|
IMPLEMENT_DYNAMIC_CLASS(wxDynamicSashReparentEvent, wxEvent)
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|