scrolbar.cpp
来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 959 行 · 第 1/2 页
CPP
959 行
/////////////////////////////////////////////////////////////////////////////
// Name: univ/scrolbar.cpp
// Purpose: wxScrollBar implementation
// Author: Vadim Zeitlin
// Modified by:
// Created: 20.08.00
// RCS-ID: $Id: scrolbar.cpp,v 1.25 2005/07/28 21:38:43 VZ Exp $
// Copyright: (c) 2000 SciTech Software, Inc. (www.scitechsoft.com)
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
#pragma implementation "univscrolbar.h"
#endif
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_SCROLLBAR
#ifndef WX_PRECOMP
#include "wx/timer.h"
#include "wx/dcclient.h"
#include "wx/scrolbar.h"
#include "wx/validate.h"
#endif
#include "wx/univ/scrtimer.h"
#include "wx/univ/renderer.h"
#include "wx/univ/inphand.h"
#include "wx/univ/theme.h"
#include "wx/log.h"
#define WXDEBUG_SCROLLBAR
#ifndef __WXDEBUG__
#undef WXDEBUG_SCROLLBAR
#endif // !__WXDEBUG__
#if defined(WXDEBUG_SCROLLBAR) && defined(__WXMSW__) && !defined(__WXMICROWIN__)
#include "wx/msw/private.h"
#endif
// ----------------------------------------------------------------------------
// wxScrollBarTimer: this class is used to repeatedly scroll the scrollbar
// when the mouse is help pressed on the arrow or on the bar. It generates the
// given scroll action command periodically.
// ----------------------------------------------------------------------------
class wxScrollBarTimer : public wxScrollTimer
{
public:
wxScrollBarTimer(wxStdScrollBarInputHandler *handler,
const wxControlAction& action,
wxScrollBar *control);
protected:
virtual bool DoNotify();
private:
wxStdScrollBarInputHandler *m_handler;
wxControlAction m_action;
wxScrollBar *m_control;
};
// ============================================================================
// implementation
// ============================================================================
IMPLEMENT_DYNAMIC_CLASS(wxScrollBar, wxControl)
BEGIN_EVENT_TABLE(wxScrollBar, wxScrollBarBase)
END_EVENT_TABLE()
// ----------------------------------------------------------------------------
// creation
// ----------------------------------------------------------------------------
#ifdef __VISUALC__
// warning C4355: 'this' : used in base member initializer list
#pragma warning(disable:4355) // so what? disable it...
#endif
wxScrollBar::wxScrollBar()
: m_arrows(this)
{
Init();
}
wxScrollBar::wxScrollBar(wxWindow *parent,
wxWindowID id,
const wxPoint& pos,
const wxSize& size,
long style,
const wxValidator& validator,
const wxString& name)
: m_arrows(this)
{
Init();
(void)Create(parent, id, pos, size, style, validator, name);
}
#ifdef __VISUALC__
// warning C4355: 'this' : used in base member initializer list
#pragma warning(default:4355)
#endif
void wxScrollBar::Init()
{
m_range =
m_thumbSize =
m_thumbPos =
m_pageSize = 0;
m_thumbPosOld = -1;
for ( size_t n = 0; n < WXSIZEOF(m_elementsState); n++ )
{
m_elementsState[n] = 0;
}
m_dirty = false;
}
bool wxScrollBar::Create(wxWindow *parent,
wxWindowID id,
const wxPoint &pos,
const wxSize &size,
long style,
const wxValidator& validator,
const wxString &name)
{
// the scrollbars never have the border
style &= ~wxBORDER_MASK;
if ( !wxControl::Create(parent, id, pos, size, style, validator, name) )
return false;
SetBestSize(size);
// override the cursor of the target window (if any)
SetCursor(wxCURSOR_ARROW);
CreateInputHandler(wxINP_HANDLER_SCROLLBAR);
return true;
}
wxScrollBar::~wxScrollBar()
{
}
// ----------------------------------------------------------------------------
// misc accessors
// ----------------------------------------------------------------------------
bool wxScrollBar::IsStandalone() const
{
wxWindow *parent = GetParent();
if ( !parent )
{
return true;
}
return (parent->GetScrollbar(wxHORIZONTAL) != this) &&
(parent->GetScrollbar(wxVERTICAL) != this);
}
bool wxScrollBar::AcceptsFocus() const
{
// the window scrollbars never accept focus
return wxScrollBarBase::AcceptsFocus() && IsStandalone();
}
// ----------------------------------------------------------------------------
// scrollbar API
// ----------------------------------------------------------------------------
void wxScrollBar::DoSetThumb(int pos)
{
// don't assert hecks here, we're a private function which is meant to be
// called with any args at all
if ( pos < 0 )
{
pos = 0;
}
else if ( pos > m_range - m_thumbSize )
{
pos = m_range - m_thumbSize;
}
if ( m_thumbPos == pos )
{
// nothing changed, avoid refreshes which would provoke flicker
return;
}
if ( m_thumbPosOld == -1 )
{
// remember the old thumb position
m_thumbPosOld = m_thumbPos;
}
m_thumbPos = pos;
// we have to refresh the part of the bar which was under the thumb and the
// thumb itself
m_elementsState[Element_Thumb] |= wxCONTROL_DIRTY;
m_elementsState[m_thumbPos > m_thumbPosOld
? Element_Bar_1 : Element_Bar_2] |= wxCONTROL_DIRTY;
m_dirty = true;
}
int wxScrollBar::GetThumbPosition() const
{
return m_thumbPos;
}
int wxScrollBar::GetThumbSize() const
{
return m_thumbSize;
}
int wxScrollBar::GetPageSize() const
{
return m_pageSize;
}
int wxScrollBar::GetRange() const
{
return m_range;
}
void wxScrollBar::SetThumbPosition(int pos)
{
wxCHECK_RET( pos >= 0 && pos <= m_range, _T("thumb position out of range") );
DoSetThumb(pos);
}
void wxScrollBar::SetScrollbar(int position, int thumbSize,
int range, int pageSize,
bool refresh)
{
// we only refresh everything when the range changes, thumb position
// changes are handled in OnIdle
bool needsRefresh = (range != m_range) ||
(thumbSize != m_thumbSize) ||
(pageSize != m_pageSize);
// set all parameters
m_range = range;
m_thumbSize = thumbSize;
SetThumbPosition(position);
m_pageSize = pageSize;
// ignore refresh parameter unless we really need to refresh everything -
// there ir a lot of existing code which just calls SetScrollbar() without
// specifying the last parameter even though it doesn't need at all to
// refresh the window immediately
if ( refresh && needsRefresh )
{
// and update the window
Refresh();
Update();
}
}
// ----------------------------------------------------------------------------
// geometry
// ----------------------------------------------------------------------------
wxSize wxScrollBar::DoGetBestClientSize() const
{
// this dimension is completely arbitrary
static const wxCoord SIZE = 140;
wxSize size = m_renderer->GetScrollbarArrowSize();
if ( IsVertical() )
{
size.y = SIZE;
}
else // horizontal
{
size.x = SIZE;
}
return size;
}
wxScrollArrows::Arrow wxScrollBar::HitTest(const wxPoint& pt) const
{
switch ( m_renderer->HitTestScrollbar(this, pt) )
{
case wxHT_SCROLLBAR_ARROW_LINE_1:
return wxScrollArrows::Arrow_First;
case wxHT_SCROLLBAR_ARROW_LINE_2:
return wxScrollArrows::Arrow_Second;
default:
return wxScrollArrows::Arrow_None;
}
}
// ----------------------------------------------------------------------------
// drawing
// ----------------------------------------------------------------------------
void wxScrollBar::OnInternalIdle()
{
UpdateThumb();
wxControl::OnInternalIdle();
}
void wxScrollBar::UpdateThumb()
{
if ( m_dirty )
{
for ( size_t n = 0; n < WXSIZEOF(m_elementsState); n++ )
{
if ( m_elementsState[n] & wxCONTROL_DIRTY )
{
wxRect rect = GetRenderer()->GetScrollbarRect(this, (Element)n);
if ( rect.width && rect.height )
{
// we try to avoid redrawing the entire shaft (which might
// be quite long) if possible by only redrawing the area
// wich really changed
if ( (n == Element_Bar_1 || n == Element_Bar_2) &&
(m_thumbPosOld != -1) )
{
// the less efficient but more reliable (i.e. this will
// probably work everywhere) version: refresh the
// distance covered by thumb since the last update
#if 0
wxRect rectOld =
GetRenderer()->GetScrollbarRect(this,
(Element)n,
m_thumbPosOld);
if ( IsVertical() )
{
if ( n == Element_Bar_1 )
rect.SetTop(rectOld.GetBottom());
else
rect.SetBottom(rectOld.GetBottom());
}
else // horizontal
{
if ( n == Element_Bar_1 )
rect.SetLeft(rectOld.GetRight());
else
rect.SetRight(rectOld.GetRight());
}
#else // efficient version: only repaint the area occupied by
// the thumb previously - we can't do better than this
rect = GetRenderer()->GetScrollbarRect(this,
Element_Thumb,
m_thumbPosOld);
#endif // 0/1
}
#ifdef WXDEBUG_SCROLLBAR
static bool s_refreshDebug = false;
if ( s_refreshDebug )
{
wxClientDC dc(this);
dc.SetBrush(*wxCYAN_BRUSH);
dc.SetPen(*wxTRANSPARENT_PEN);
dc.DrawRectangle(rect);
// under Unix we use "--sync" X option for this
#if defined(__WXMSW__) && !defined(__WXMICROWIN__)
::GdiFlush();
::Sleep(200);
#endif // __WXMSW__
}
#endif // WXDEBUG_SCROLLBAR
Refresh(false, &rect);
}
m_elementsState[n] &= ~wxCONTROL_DIRTY;
}
}
m_dirty = false;
}
}
void wxScrollBar::DoDraw(wxControlRenderer *renderer)
{
renderer->DrawScrollbar(this, m_thumbPosOld);
// clear all dirty flags
m_dirty = false;
m_thumbPosOld = -1;
}
// ----------------------------------------------------------------------------
// state flags
// ----------------------------------------------------------------------------
static inline wxScrollBar::Element ElementForArrow(wxScrollArrows::Arrow arrow)
{
return arrow == wxScrollArrows::Arrow_First
? wxScrollBar::Element_Arrow_Line_1
: wxScrollBar::Element_Arrow_Line_2;
}
int wxScrollBar::GetArrowState(wxScrollArrows::Arrow arrow) const
{
return GetState(ElementForArrow(arrow));
}
void wxScrollBar::SetArrowFlag(wxScrollArrows::Arrow arrow, int flag, bool set)
{
Element which = ElementForArrow(arrow);
int state = GetState(which);
if ( set )
state |= flag;
else
state &= ~flag;
SetState(which, state);
}
int wxScrollBar::GetState(Element which) const
{
// if the entire scrollbar is disabled, all of its elements are too
int flags = m_elementsState[which];
if ( !IsEnabled() )
flags |= wxCONTROL_DISABLED;
return flags;
}
void wxScrollBar::SetState(Element which, int flags)
{
if ( (int)(m_elementsState[which] & ~wxCONTROL_DIRTY) != flags )
{
m_elementsState[which] = flags | wxCONTROL_DIRTY;
m_dirty = true;
}
}
// ----------------------------------------------------------------------------
// input processing
// ----------------------------------------------------------------------------
bool wxScrollBar::OnArrow(wxScrollArrows::Arrow arrow)
{
int oldThumbPos = GetThumbPosition();
PerformAction(arrow == wxScrollArrows::Arrow_First
? wxACTION_SCROLL_LINE_UP
: wxACTION_SCROLL_LINE_DOWN);
// did we scroll till the end?
return GetThumbPosition() != oldThumbPos;
}
bool wxScrollBar::PerformAction(const wxControlAction& action,
long numArg,
const wxString& strArg)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?