⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dynamicsash.cpp

📁 Wxpython Implemented on Windows CE, Source code
💻 CPP
📖 第 1 页 / 共 3 页
字号:
/////////////////////////////////////////////////////////////////////////////
// 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: dynamicsash.cpp,v 1.20 2005/09/23 12:47:47 MR Exp $
// Copyright:   (c) 2001 Matt Kimball
// Licence:     wxWindows licence
/////////////////////////////////////////////////////////////////////////////

// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"

#ifdef __BORLANDC__
    #pragma hdrstop
#endif

// for all others, include the necessary headers (this file is usually all you
// need because it includes almost all "standard" wxWidgets headers)
#ifndef WX_PRECOMP
    #include "wx/wx.h"
#endif

#ifdef __WXMSW__
#include "wx/mdi.h"
#endif

#include "wx/gizmos/dynamicsash.h"


const wxChar* wxDynamicSashWindowNameStr = wxT("dynamicSashWindow");


/*
    wxDynamicSashWindow works by internally storing a tree of Implementation
    objects (wxDynamicSsahWindowImpl) and Leaf objects
    (wxDynamicSashWindowLeaf).  The wxDynamicSashWindow has a pointer to one
    implementation, and each implementation either has a pointer to a one
    leaf (m_leaf) or a pointer to two children implementation objects
    (m_child).  The leaves each are responsible for drawing the frame and
    decorations around one user-provided views and for responding to mouse
    and scrollbar events.

    A resulting tree might look something like this:

    wxDynamicSashWindow
     |
     +- wxDynamicSashWindowImpl
         |
         +- wxDynamicSashWindowLeaf
         |   |
         |   +- user view window
         |
         +- wxDynamicSashWindowImpl
             |
             +- wxDynamicSashWindowLeaf
             |   |
             |   +- user view window
             |
             +- wxDynamicSashWindowLeaf
                 |
                 +- user view window

    Each time a split occurs, one of the implementation objects removes its
    leaf, generates two new implementation object children, each with a new
    leaf, and reparents the user view which was connected to its old leaf
    to be one of the new leaf's user view, and sends a Split event to the
    user view in the hopes that it will generate a new user view for the
    other new leaf.

    When a unification ocurrs, an implementation object is replaced by one
    of its children, and the tree of its other child is pruned.

    One quirk is that the top-level implementation object (m_top) always
    keeps a pointer to the implementation object where a new child is needed.
    (m_add_child_target).  This is so that when a new uesr view is added
    to the hierarchy, AddChild() is able to reparent the new user view to
    the correct implementation object's leaf.

*/

#include "wx/dcmemory.h"
#include "wx/dcscreen.h"
#include "wx/layout.h"
#include "wx/scrolbar.h"
#include "wx/settings.h"


const wxEventType wxEVT_DYNAMIC_SASH_SPLIT = wxNewEventType();
const wxEventType wxEVT_DYNAMIC_SASH_UNIFY = wxNewEventType();
const wxEventType wxEVT_DYNAMIC_SASH_REPARENT = wxNewEventType();

enum DynamicSashRegion
{
    DSR_NONE,
    DSR_VERTICAL_TAB,
    DSR_HORIZONTAL_TAB,
    DSR_CORNER,
    DSR_LEFT_EDGE,
    DSR_TOP_EDGE,
    DSR_RIGHT_EDGE,
    DSR_BOTTOM_EDGE
};


/*
    wxDynamicSashReparentEvent is generated by the AddChild() method of
    wxDynamicSashWindow when it wants a Leaf to reparent a user view window
    to its viewport at some time in the future.  We can't reparent the window
    immediately, because switching parents in AddChild() confuses the wxWindow
    class.  Instead, we queue up this event, and the window is actually
    reparented the next time we process events in the idle loop.
*/
class wxDynamicSashReparentEvent : public wxEvent
{
public:
    wxDynamicSashReparentEvent();
    wxDynamicSashReparentEvent(wxObject *object);
    wxDynamicSashReparentEvent(const wxDynamicSashReparentEvent& evt);

    virtual wxEvent* Clone() const { return new wxDynamicSashReparentEvent(*this); }

    DECLARE_DYNAMIC_CLASS(wxDynamicSashReparentEvent)
};


class wxDynamicSashWindowImpl : public wxEvtHandler
{
public:
    wxDynamicSashWindowImpl(wxDynamicSashWindow *window);
    ~wxDynamicSashWindowImpl();

    bool Create();
    void AddChild(wxWindow *window);
    void DrawSash(int x, int y) const;
    void ConstrainChildren(int px, int py);
    void Split(int x, int y);
    void Unify(int panel);
    void Resize(int x, int y);
    wxDynamicSashWindowImpl *FindParent(DynamicSashRegion side) const;
    wxDynamicSashWindowImpl *FindUpperParent(wxDynamicSashWindowImpl *sash_a,
                                             wxDynamicSashWindowImpl *sash_b) const;
    wxWindow *FindFrame() const;
    wxScrollBar *FindScrollBar(const wxWindow *child, int vert) const;

    void OnSize(wxSizeEvent &event);
    void OnPaint(wxPaintEvent &event);
    void OnMouseMove(wxMouseEvent &event);
    void OnLeave(wxMouseEvent &event);
    void OnPress(wxMouseEvent &event);
    void OnRelease(wxMouseEvent &event);

    wxDynamicSashWindow *m_window;
    wxDynamicSashWindowImpl *m_add_child_target;

    /*  This is the window we are responsible for managing.  Either of
        leaf or our children are in this window.  For the top level
        implementation object, this is the same as m_window.
        Otherwise it is a window we've created an will destroy when we
        are deleted.  */
    wxWindow *m_container;

    wxDynamicSashWindowImpl *m_parent;
    wxDynamicSashWindowImpl *m_top;
    wxDynamicSashWindowImpl *m_child[2];

    class wxDynamicSashWindowLeaf *m_leaf;

    /*  If the implementation is split horizontally or vertically, m_split
        is set to DSR_HORIZONTAL_TAB or DSR_VERTICAL_TAB, respectively.
        Otherwise it is set to DSR_NONE.  */
    DynamicSashRegion m_split;

    /*  These are used to keep track of a sash as it is being dragged, for
        drawing the user interface correctly.  */
    DynamicSashRegion m_dragging;
    int m_drag_x, m_drag_y;
};

class wxDynamicSashWindowLeaf : public wxEvtHandler
{
public:
    wxDynamicSashWindowLeaf(wxDynamicSashWindowImpl *impl);
    ~wxDynamicSashWindowLeaf();

    bool Create();
    void AddChild(wxWindow *window);
    DynamicSashRegion GetRegion(int x, int y);
    void ResizeChild(const wxSize& size);
    wxScrollBar *FindScrollBar(const wxWindow *child, int vert) const;

    void OnSize(wxSizeEvent &event);
    void OnViewSize(wxSizeEvent &event);
    void OnPaint(wxPaintEvent &event);
    void OnScroll(wxScrollEvent &event);
    void OnFocus(wxFocusEvent &event);
    void OnMouseMove(wxMouseEvent &event);
    void OnLeave(wxMouseEvent &event);
    void OnPress(wxMouseEvent &event);
    void OnRelease(wxMouseEvent &event);
    void OnReparent(wxEvent &event);

    wxDynamicSashWindowImpl *m_impl;

    wxScrollBar *m_vscroll,
                *m_hscroll;

    /*  m_child is the window provided to us by the application developer.
        m_viewport is a window we've created, and it is the immediately
        parent of m_child.  We scroll m_child by moving it around within
        m_viewport.  */
    wxWindow *m_viewport,
             *m_child;
};


// ============================================================================
// wxDynamicSashWindow
// ============================================================================

wxDynamicSashWindow::wxDynamicSashWindow()
{
    m_impl = NULL;
}

wxDynamicSashWindow::wxDynamicSashWindow(wxWindow *parent,
                                         wxWindowID id,
                                         const wxPoint& pos,
                                         const wxSize& size,
                                         long style,
                                         const wxString& name)
{
    m_impl = NULL;
    Create(parent, id, pos, size, style, name);
}

wxDynamicSashWindow::~wxDynamicSashWindow()
{
    SetEventHandler(this);
    delete m_impl;
}

bool wxDynamicSashWindow::Create(wxWindow *parent,
                                 wxWindowID id,
                                 const wxPoint& pos,
                                 const wxSize& size,
                                 long style,
                                 const wxString& name)
{
    if (m_impl)
        return false;

    if (!wxWindow::Create(parent, id, pos, size, style, name))
        return false;

    m_impl = new wxDynamicSashWindowImpl(this);
    if (!m_impl)
        return false;

    if (!m_impl->Create())
    {
        delete m_impl;
        m_impl = NULL;
        return false;
    }

    return true;
}

void wxDynamicSashWindow::AddChild(wxWindowBase *child)
{
    wxWindow::AddChild(child);

    m_impl->AddChild(wxDynamicCast(child, wxWindow));
}

wxScrollBar *wxDynamicSashWindow::GetHScrollBar(const wxWindow *child) const
{
    return m_impl->FindScrollBar(child, 0);
}

wxScrollBar *wxDynamicSashWindow::GetVScrollBar(const wxWindow *child) const
{
    return m_impl->FindScrollBar(child, 1);
}

IMPLEMENT_DYNAMIC_CLASS(wxDynamicSashWindow, wxWindow)


// ============================================================================
// wxDynamicSashWindowImpl
// ============================================================================

wxDynamicSashWindowImpl::wxDynamicSashWindowImpl(wxDynamicSashWindow *window)
{
    m_window = window;
    m_add_child_target = this;

    m_container = NULL;
    m_parent = NULL;
    m_top = this;
    m_child[0] =
    m_child[1] = NULL;
    m_leaf = NULL;
    m_dragging = DSR_NONE;
    m_split = DSR_NONE;
}

wxDynamicSashWindowImpl::~wxDynamicSashWindowImpl()
{
    delete m_leaf;
    delete m_child[0];
    m_child[0] = NULL;
    delete m_child[1];
    m_child[1] = NULL;
    m_leaf = NULL;

    if (m_container != m_window && m_container)
    {
        m_container->SetEventHandler(m_container);
        m_container->Destroy();
    }
}

bool wxDynamicSashWindowImpl::Create()
{
    if (!m_container)
        m_container = m_window;

    wxCursor cursor(wxCURSOR_ARROW);
    m_container->SetCursor(cursor);

    m_leaf = new wxDynamicSashWindowLeaf(this);
    if (!m_leaf)
        return false;

    if (!m_leaf->Create())
    {
        delete m_leaf;
        m_leaf = NULL;
        return false;
    }

    m_container->SetEventHandler(this);

    Connect(wxEVT_SIZE, wxSizeEventHandler(wxDynamicSashWindowImpl::OnSize));
    Connect(wxEVT_PAINT, wxPaintEventHandler(wxDynamicSashWindowImpl::OnPaint));
    Connect(wxEVT_MOTION,
            wxMouseEventHandler(wxDynamicSashWindowImpl::OnMouseMove));
    Connect(wxEVT_ENTER_WINDOW,
            wxMouseEventHandler(wxDynamicSashWindowImpl::OnMouseMove));
    Connect(wxEVT_LEAVE_WINDOW,
            wxMouseEventHandler(wxDynamicSashWindowImpl::OnLeave));
    Connect(wxEVT_LEFT_DOWN,
            wxMouseEventHandler(wxDynamicSashWindowImpl::OnPress));
    Connect(wxEVT_LEFT_UP,
            wxMouseEventHandler(wxDynamicSashWindowImpl::OnRelease));

    return true;
}

void wxDynamicSashWindowImpl::AddChild(wxWindow *window)
{
    if (m_add_child_target && m_add_child_target->m_leaf)
        m_add_child_target->m_leaf->AddChild(window);
}

void wxDynamicSashWindowImpl::DrawSash(int x, int y) const
{
    int i, j;

    wxScreenDC dc;
    dc.StartDrawingOnTop(m_container);

    wxBitmap bmp(8, 8);
    wxMemoryDC bdc;
    bdc.SelectObject(bmp);
    bdc.DrawRectangle(-1, -1, 10, 10);
    for (i = 0; i < 8; i++)
    {
        for (j = 0; j < 8; j++)
        {
            if ((i + j) & 1)
                bdc.DrawPoint(i, j);
        }
    }

    wxBrush brush(bmp);
    dc.SetBrush(brush);
    dc.SetLogicalFunction(wxXOR);

    if ((m_dragging == DSR_CORNER) &&
        (m_window->GetWindowStyle() & wxDS_DRAG_CORNER) != 0)
    {
        int cx = 0;
        int cy = 0;

        m_container->ClientToScreen(&cx, &cy);
        m_container->ClientToScreen(&x, &y);

        if (cx < x && cy < y)
        {
            dc.DrawRectangle(cx - 2, cy - 2, x - cx + 4, 4);
            dc.DrawRectangle(x - 2, cy + 2, 4, y - cy);
            dc.DrawRectangle(cx - 2, cy + 2, 4, y - cy);
            dc.DrawRectangle(cx + 2, y - 2, x - cx - 4, 4);
        }
    }
    else
    {
        int body_w, body_h;
        m_container->GetClientSize(&body_w, &body_h);

        if (y < 0)
            y = 0;
        if (y > body_h)
            y = body_h;
        if (x < 0)
            x = 0;
        if (x > body_w)
            x = body_w;

        if (m_dragging == DSR_HORIZONTAL_TAB)
            x = 0;
        else
            y = 0;

        m_container->ClientToScreen(&x, &y);

        int w, h;
        w = body_w;  h = body_h;

        if (m_dragging == DSR_HORIZONTAL_TAB)
            dc.DrawRectangle(x, y - 2, w, 4);
        else
            dc.DrawRectangle(x - 2, y, 4, h);
    }

    dc.EndDrawingOnTop();
}

wxDynamicSashWindowImpl *
wxDynamicSashWindowImpl::FindParent(DynamicSashRegion side) const
{
    if (m_parent == NULL)
        return NULL;

    if (m_parent->m_split == DSR_HORIZONTAL_TAB)
    {
        if (side == DSR_TOP_EDGE && m_parent->m_child[1] == this)
            return m_parent;
        if (side == DSR_BOTTOM_EDGE && m_parent->m_child[0] == this)
            return m_parent;
    }
    else if (m_parent->m_split == DSR_VERTICAL_TAB)
    {
        if (side == DSR_LEFT_EDGE && m_parent->m_child[1] == this)
            return m_parent;
        if (side == DSR_RIGHT_EDGE && m_parent->m_child[0] == this)
            return m_parent;
    }

    return m_parent->FindParent(side);
}

wxDynamicSashWindowImpl *
wxDynamicSashWindowImpl::FindUpperParent(wxDynamicSashWindowImpl *sash_a,
                                         wxDynamicSashWindowImpl *sash_b) const
{
    wxWindow *win;
    win = sash_a->m_container->GetParent();
    while (win && !win->IsTopLevel())
    {
        if (win == sash_b->m_container)
            return sash_b;

        win = win->GetParent();
    }

    return sash_a;
}


wxWindow *wxDynamicSashWindowImpl::FindFrame() const
{
    wxWindow *win;

    win = m_window->GetParent();
    while (win && !win->IsTopLevel()

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -