winuniv.cpp

来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 1,372 行 · 第 1/3 页

CPP
1,372
字号
///////////////////////////////////////////////////////////////////////////////
// Name:        univ/window.cpp
// Purpose:     implementation of extra wxWindow methods for wxUniv port
// Author:      Vadim Zeitlin
// Modified by:
// Created:     06.08.00
// RCS-ID:      $Id: winuniv.cpp,v 1.56 2005/06/16 16:07:49 JS Exp $
// Copyright:   (c) 2000 SciTech Software, Inc. (www.scitechsoft.com)
// Licence:     wxWindows licence
///////////////////////////////////////////////////////////////////////////////

// ===========================================================================
// declarations
// ===========================================================================

// ---------------------------------------------------------------------------
// headers
// ---------------------------------------------------------------------------

#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
    #pragma implementation "univwindow.h"
#endif

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

#ifdef __BORLANDC__
    #pragma hdrstop
#endif

#ifndef WX_PRECOMP
    #include "wx/app.h"
    #include "wx/window.h"
    #include "wx/dcclient.h"
    #include "wx/dcmemory.h"
    #include "wx/event.h"
    #include "wx/scrolbar.h"
    #include "wx/menu.h"
    #include "wx/frame.h"
#endif // WX_PRECOMP

#include "wx/log.h"
#include "wx/univ/colschem.h"
#include "wx/univ/renderer.h"
#include "wx/univ/theme.h"

#if wxUSE_CARET
    #include "wx/caret.h"
#endif // wxUSE_CARET

// turn Refresh() debugging on/off
#define WXDEBUG_REFRESH

#ifndef __WXDEBUG__
    #undef WXDEBUG_REFRESH
#endif

#if defined(WXDEBUG_REFRESH) && defined(__WXMSW__) && !defined(__WXMICROWIN__)
#include "wx/msw/private.h"
#endif

// ============================================================================
// implementation
// ============================================================================

// ----------------------------------------------------------------------------
// event tables
// ----------------------------------------------------------------------------

// we can't use wxWindowNative here as it won't be expanded inside the macro
#if defined(__WXMSW__)
    IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowMSW)
#elif defined(__WXGTK__)
    IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowGTK)
#elif defined(__WXMGL__)
    IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowMGL)
#elif defined(__WXX11__)
    IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowX11)
#elif defined(__WXPM__)
    IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowOS2)
#endif

BEGIN_EVENT_TABLE(wxWindow, wxWindowNative)
    EVT_SIZE(wxWindow::OnSize)

#if wxUSE_ACCEL || wxUSE_MENUS
    EVT_KEY_DOWN(wxWindow::OnKeyDown)
#endif // wxUSE_ACCEL

#if wxUSE_MENUS
    EVT_CHAR(wxWindow::OnChar)
    EVT_KEY_UP(wxWindow::OnKeyUp)
#endif // wxUSE_MENUS

    EVT_PAINT(wxWindow::OnPaint)
    EVT_NC_PAINT(wxWindow::OnNcPaint)
    EVT_ERASE_BACKGROUND(wxWindow::OnErase)
END_EVENT_TABLE()

// ----------------------------------------------------------------------------
// creation
// ----------------------------------------------------------------------------

void wxWindow::Init()
{
    m_scrollbarVert =
    m_scrollbarHorz = (wxScrollBar *)NULL;

    m_isCurrent = false;

    m_renderer = wxTheme::Get()->GetRenderer();

    m_oldSize.x = wxDefaultCoord;
    m_oldSize.y = wxDefaultCoord;
}

bool wxWindow::Create(wxWindow *parent,
                      wxWindowID id,
                      const wxPoint& pos,
                      const wxSize& size,
                      long style,
                      const wxString& name)
{
    long actualStyle = style;

    // FIXME: may need this on other platforms
#ifdef __WXMSW__
    actualStyle &= ~wxVSCROLL;
    actualStyle &= ~wxHSCROLL;
#endif

    // we add wxCLIP_CHILDREN to get the same ("natural") behaviour under MSW
    // as under the other platforms
    if ( !wxWindowNative::Create(parent, id, pos, size,
                                 actualStyle | wxCLIP_CHILDREN,
                                 name) )
    {
        return false;
    }

    // Set full style again, including those we didn't want present
    // when calling the base window Create().
    wxWindowBase::SetWindowStyleFlag(style);

    // if we allow or should always have a vertical scrollbar, make it
    if ( style & wxVSCROLL || style & wxALWAYS_SHOW_SB )
    {
#if wxUSE_TWO_WINDOWS
        SetInsertIntoMain( true );
#endif
        m_scrollbarVert = new wxScrollBar(this, wxID_ANY,
                                          wxDefaultPosition, wxDefaultSize,
                                          wxSB_VERTICAL);
#if wxUSE_TWO_WINDOWS
        SetInsertIntoMain( false );
#endif
    }

    // if we should allow a horizontal scrollbar, make it
    if ( style & wxHSCROLL )
    {
#if wxUSE_TWO_WINDOWS
        SetInsertIntoMain( true );
#endif
        m_scrollbarHorz = new wxScrollBar(this, wxID_ANY,
                                          wxDefaultPosition, wxDefaultSize,
                                          wxSB_HORIZONTAL);
#if wxUSE_TWO_WINDOWS
        SetInsertIntoMain( false );
#endif
    }

    if (m_scrollbarHorz || m_scrollbarVert)
    {
        // position it/them
        PositionScrollbars();
    }

    return true;
}

wxWindow::~wxWindow()
{
    m_isBeingDeleted = true;

    // we have to destroy our children before we're destroyed because our
    // children suppose that we're of type wxWindow, not just wxWindowNative,
    // and so bad things may happen if they're deleted from the base class dtor
    // as by then we're not a wxWindow any longer and wxUniv-specific virtual
    // functions can't be called
    DestroyChildren();
}

// ----------------------------------------------------------------------------
// background pixmap
// ----------------------------------------------------------------------------

void wxWindow::SetBackground(const wxBitmap& bitmap,
                              int alignment,
                              wxStretch stretch)
{
    m_bitmapBg = bitmap;
    m_alignBgBitmap = alignment;
    m_stretchBgBitmap = stretch;
}

const wxBitmap& wxWindow::GetBackgroundBitmap(int *alignment,
                                               wxStretch *stretch) const
{
    if ( m_bitmapBg.Ok() )
    {
        if ( alignment )
            *alignment = m_alignBgBitmap;
        if ( stretch )
            *stretch = m_stretchBgBitmap;
    }

    return m_bitmapBg;
}

// ----------------------------------------------------------------------------
// painting
// ----------------------------------------------------------------------------

// the event handlers executed when the window must be repainted
void wxWindow::OnNcPaint(wxNcPaintEvent& WXUNUSED(event))
{
    if ( m_renderer )
    {
        // get the window rect
        wxRect rect;
        wxSize size = GetSize();
        rect.x =
        rect.y = 0;
        rect.width = size.x;
        rect.height = size.y;

        // if the scrollbars are outside the border, we must adjust the rect to
        // exclude them
        if ( !m_renderer->AreScrollbarsInsideBorder() )
        {
            wxScrollBar *scrollbar = GetScrollbar(wxVERTICAL);
            if ( scrollbar )
                rect.width -= scrollbar->GetSize().x;

            scrollbar = GetScrollbar(wxHORIZONTAL);
            if ( scrollbar )
                rect.height -= scrollbar->GetSize().y;
        }

        // get the DC and draw the border on it
        wxWindowDC dc(this);
        DoDrawBorder(dc, rect);
    }
}

void wxWindow::OnPaint(wxPaintEvent& event)
{
    if ( !m_renderer )
    {
        // it is a native control which paints itself
        event.Skip();
    }
    else
    {
        // get the DC to use and create renderer on it
        wxPaintDC dc(this);
        wxControlRenderer renderer(this, dc, m_renderer);

        // draw the control
        DoDraw(&renderer);
    }
}

// the event handler executed when the window background must be painted
void wxWindow::OnErase(wxEraseEvent& event)
{
    if ( !m_renderer )
    {
        event.Skip();

        return;
    }

    DoDrawBackground(*event.GetDC());

    // if we have both scrollbars, we also have a square in the corner between
    // them which we must paint
    if ( m_scrollbarVert && m_scrollbarHorz )
    {
        wxSize size = GetSize();
        wxRect rectClient = GetClientRect(),
               rectBorder = m_renderer->GetBorderDimensions(GetBorder());

        wxRect rectCorner;
        rectCorner.x = rectClient.GetRight() + 1;
        rectCorner.y = rectClient.GetBottom() + 1;
        rectCorner.SetRight(size.x - rectBorder.width);
        rectCorner.SetBottom(size.y - rectBorder.height);

        if ( GetUpdateRegion().Contains(rectCorner) )
        {
            m_renderer->DrawScrollCorner(*event.GetDC(), rectCorner);
        }
    }
}

bool wxWindow::DoDrawBackground(wxDC& dc)
{
    wxRect rect;

    wxSize size = GetSize();  // Why not GetClientSize() ?
    rect.x = 0;
    rect.y = 0;
    rect.width = size.x;
    rect.height = size.y;

    wxWindow * const parent = GetParent();
    if ( HasTransparentBackground() && parent )
    {
        wxASSERT( !IsTopLevel() );

        wxPoint pos = GetPosition();

        AdjustForParentClientOrigin( pos.x, pos.y, 0 );

        // Adjust DC logical origin
        wxCoord org_x, org_y, x, y;
        dc.GetLogicalOrigin( &org_x, &org_y );
        x = org_x + pos.x;
        y = org_y + pos.y;
        dc.SetLogicalOrigin( x, y );

        // Adjust draw rect
        rect.x = pos.x;
        rect.y = pos.y;

        // Let parent draw the background
        parent->EraseBackground( dc, rect );

        // Restore DC logical origin
        dc.SetLogicalOrigin( org_x, org_y );
    }
    else
    {
        // Draw background ouselves
        EraseBackground( dc, rect );
    }

    return true;
}

void wxWindow::EraseBackground(wxDC& dc, const wxRect& rect)
{
    if ( GetBackgroundBitmap().Ok() )
    {
        // Get the bitmap and the flags
        int alignment;
        wxStretch stretch;
        wxBitmap bmp = GetBackgroundBitmap(&alignment, &stretch);
        wxControlRenderer::DrawBitmap(dc, bmp, rect, alignment, stretch);
    }
    else
    {
        // Just fill it with bg colour if no bitmap

        m_renderer->DrawBackground(dc, wxTHEME_BG_COLOUR(this),
                                   rect, GetStateFlags());
    }
}

void wxWindow::DoDrawBorder(wxDC& dc, const wxRect& rect)
{
    // draw outline unless the update region is enitrely inside it in which
    // case we don't need to do it
#if 0 // doesn't seem to work, why?
    if ( wxRegion(rect).Contains(GetUpdateRegion().GetBox()) != wxInRegion )
#endif
    {
        m_renderer->DrawBorder(dc, GetBorder(), rect, GetStateFlags());
    }
}

void wxWindow::DoDraw(wxControlRenderer * WXUNUSED(renderer))
{
}

void wxWindow::Refresh(bool eraseBackground, const wxRect *rectClient)
{
    wxRect rectWin;
    wxPoint pt = GetClientAreaOrigin();

    wxSize size = GetClientSize();

    if ( rectClient )
    {
        rectWin = *rectClient;

        // don't refresh anything beyond the client area (scrollbars for
        // example)
        if ( rectWin.GetRight() > size.x )
            rectWin.SetRight(size.x);
        if ( rectWin.GetBottom() > size.y )
            rectWin.SetBottom(size.y);

        rectWin.Offset(pt);
    }
    else // refresh the entire client area
    {
        rectWin.x = pt.x;
        rectWin.y = pt.y;
        rectWin.width = size.x;
        rectWin.height = size.y;
    }

    // debugging helper
#ifdef WXDEBUG_REFRESH
    static bool s_refreshDebug = false;
    if ( s_refreshDebug )
    {
        wxWindowDC dc(this);
        dc.SetBrush(*wxCYAN_BRUSH);
        dc.SetPen(*wxTRANSPARENT_PEN);
        dc.DrawRectangle(rectWin);

        // under Unix we use "--sync" X option for this
        #if defined(__WXMSW__) && !defined(__WXMICROWIN__)
            ::GdiFlush();
            ::Sleep(200);
        #endif // __WXMSW__
    }
#endif // WXDEBUG_REFRESH

    wxWindowNative::Refresh(eraseBackground, &rectWin);

    // Refresh all sub controls if any.
    wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
    while ( node )
    {
        wxWindow *win = node->GetData();
        // Only refresh sub controls when it is visible
        // and when it is in the update region.
        if(!win->IsKindOf(CLASSINFO(wxTopLevelWindow)) && win->IsShown() && wxRegion(rectWin).Contains(win->GetRect()) != wxOutRegion)
            win->Refresh(eraseBackground, &rectWin);

        node = node->GetNext();
    }
}

// ----------------------------------------------------------------------------
// state flags
// ----------------------------------------------------------------------------

bool wxWindow::Enable(bool enable)
{
    if ( !wxWindowNative::Enable(enable) )
        return false;

⌨️ 快捷键说明

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