git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@10795 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
865 lines
26 KiB
C++
865 lines
26 KiB
C++
///////////////////////////////////////////////////////////////////////////////
|
|
// Name: univ/renderer.cpp
|
|
// Purpose: wxControlRenderer implementation
|
|
// Author: Vadim Zeitlin
|
|
// Modified by:
|
|
// Created: 15.08.00
|
|
// RCS-ID: $Id$
|
|
// Copyright: (c) 2000 SciTech Software, Inc. (www.scitechsoft.com)
|
|
// Licence: wxWindows license
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// ===========================================================================
|
|
// declarations
|
|
// ===========================================================================
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// headers
|
|
// ---------------------------------------------------------------------------
|
|
|
|
#ifdef __GNUG__
|
|
#pragma implementation "renderer.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/control.h"
|
|
#include "wx/checklst.h"
|
|
#include "wx/listbox.h"
|
|
#include "wx/scrolbar.h"
|
|
#include "wx/dc.h"
|
|
#endif // WX_PRECOMP
|
|
|
|
#include "wx/image.h"
|
|
|
|
#include "wx/univ/theme.h"
|
|
#include "wx/univ/renderer.h"
|
|
#include "wx/univ/colschem.h"
|
|
|
|
#if wxUSE_GAUGE
|
|
#include "wx/gauge.h"
|
|
#endif
|
|
|
|
// ============================================================================
|
|
// implementation
|
|
// ============================================================================
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// wxRenderer: drawing helpers
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void wxRenderer::StandardDrawFrame(wxDC& dc,
|
|
const wxRect& rectFrame,
|
|
const wxRect& rectLabel)
|
|
{
|
|
// draw left, bottom and right lines entirely
|
|
DrawVerticalLine(dc, rectFrame.GetLeft(),
|
|
rectFrame.GetTop(), rectFrame.GetBottom() - 2);
|
|
DrawHorizontalLine(dc, rectFrame.GetBottom() - 1,
|
|
rectFrame.GetLeft(), rectFrame.GetRight());
|
|
DrawVerticalLine(dc, rectFrame.GetRight() - 1,
|
|
rectFrame.GetTop(), rectFrame.GetBottom() - 1);
|
|
|
|
// and 2 parts of the top line
|
|
DrawHorizontalLine(dc, rectFrame.GetTop(),
|
|
rectFrame.GetLeft() + 1, rectLabel.GetLeft());
|
|
DrawHorizontalLine(dc, rectFrame.GetTop(),
|
|
rectLabel.GetRight(), rectFrame.GetRight() - 2);
|
|
}
|
|
|
|
/* static */
|
|
void wxRenderer::StandardDrawTextLine(wxDC& dc,
|
|
const wxString& text,
|
|
const wxRect& rect,
|
|
int selStart, int selEnd,
|
|
int flags)
|
|
{
|
|
if ( (selStart == -1) || !(flags & wxCONTROL_FOCUSED) )
|
|
{
|
|
// just draw it as is
|
|
dc.DrawText(text, rect.x, rect.y);
|
|
}
|
|
else // we have selection
|
|
{
|
|
wxCoord width,
|
|
x = rect.x;
|
|
|
|
// draw the part before selection
|
|
wxString s(text, (size_t)selStart);
|
|
if ( !s.empty() )
|
|
{
|
|
dc.DrawText(s, x, rect.y);
|
|
|
|
dc.GetTextExtent(s, &width, NULL);
|
|
x += width;
|
|
}
|
|
|
|
// draw the selection itself
|
|
s = wxString(text.c_str() + selStart, text.c_str() + selEnd);
|
|
if ( !s.empty() )
|
|
{
|
|
wxColour colFg = dc.GetTextForeground(),
|
|
colBg = dc.GetTextBackground();
|
|
dc.SetTextForeground(wxTHEME_COLOUR(HIGHLIGHT_TEXT));
|
|
dc.SetTextBackground(wxTHEME_COLOUR(HIGHLIGHT));
|
|
dc.SetBackgroundMode(wxSOLID);
|
|
|
|
dc.DrawText(s, x, rect.y);
|
|
dc.GetTextExtent(s, &width, NULL);
|
|
x += width;
|
|
|
|
dc.SetBackgroundMode(wxTRANSPARENT);
|
|
dc.SetTextBackground(colBg);
|
|
dc.SetTextForeground(colFg);
|
|
}
|
|
|
|
// draw the final part
|
|
s = text.c_str() + selEnd;
|
|
if ( !s.empty() )
|
|
{
|
|
dc.DrawText(s, x, rect.y);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// wxRenderer: scrollbar geometry
|
|
// ----------------------------------------------------------------------------
|
|
|
|
/* static */
|
|
void wxRenderer::StandardScrollBarThumbSize(wxCoord length,
|
|
int thumbPos,
|
|
int thumbSize,
|
|
int range,
|
|
wxCoord *thumbStart,
|
|
wxCoord *thumbEnd)
|
|
{
|
|
// the thumb can't be made less than this number of pixels
|
|
static const wxCoord thumbMinWidth = 8; // FIXME: should be configurable
|
|
|
|
*thumbStart = (length*thumbPos) / range;
|
|
*thumbEnd = (length*(thumbPos + thumbSize)) / range;
|
|
|
|
if ( *thumbEnd - *thumbStart < thumbMinWidth )
|
|
{
|
|
// adjust the end if possible
|
|
if ( *thumbStart <= length - thumbMinWidth )
|
|
{
|
|
// yes, just make it wider
|
|
*thumbEnd = *thumbStart + thumbMinWidth;
|
|
}
|
|
else // it is at the bottom of the scrollbar
|
|
{
|
|
// so move it a bit up
|
|
*thumbStart = length - thumbMinWidth;
|
|
*thumbEnd = length;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* static */
|
|
wxRect wxRenderer::StandardGetScrollbarRect(const wxScrollBar *scrollbar,
|
|
wxScrollBar::Element elem,
|
|
int thumbPos,
|
|
const wxSize& sizeArrow)
|
|
{
|
|
if ( thumbPos == -1 )
|
|
{
|
|
thumbPos = scrollbar->GetThumbPosition();
|
|
}
|
|
|
|
wxSize sizeTotal = scrollbar->GetClientSize();
|
|
wxCoord *start, *width, length, arrow;
|
|
wxRect rect;
|
|
if ( scrollbar->IsVertical() )
|
|
{
|
|
rect.x = 0;
|
|
rect.width = sizeTotal.x;
|
|
length = sizeTotal.y;
|
|
start = &rect.y;
|
|
width = &rect.height;
|
|
arrow = sizeArrow.y;
|
|
}
|
|
else // horizontal
|
|
{
|
|
rect.y = 0;
|
|
rect.height = sizeTotal.y;
|
|
length = sizeTotal.x;
|
|
start = &rect.x;
|
|
width = &rect.width;
|
|
arrow = sizeArrow.x;
|
|
}
|
|
|
|
switch ( elem )
|
|
{
|
|
case wxScrollBar::Element_Arrow_Line_1:
|
|
*start = 0;
|
|
*width = arrow;
|
|
break;
|
|
|
|
case wxScrollBar::Element_Arrow_Line_2:
|
|
*start = length - arrow;
|
|
*width = arrow;
|
|
break;
|
|
|
|
case wxScrollBar::Element_Arrow_Page_1:
|
|
case wxScrollBar::Element_Arrow_Page_2:
|
|
// we don't have them at all
|
|
break;
|
|
|
|
case wxScrollBar::Element_Thumb:
|
|
case wxScrollBar::Element_Bar_1:
|
|
case wxScrollBar::Element_Bar_2:
|
|
// we need to calculate the thumb position - do it
|
|
{
|
|
length -= 2*arrow;
|
|
wxCoord thumbStart, thumbEnd;
|
|
int range = scrollbar->GetRange();
|
|
if ( !range )
|
|
{
|
|
thumbStart =
|
|
thumbEnd = 0;
|
|
}
|
|
else
|
|
{
|
|
StandardScrollBarThumbSize(length,
|
|
thumbPos,
|
|
scrollbar->GetThumbSize(),
|
|
range,
|
|
&thumbStart,
|
|
&thumbEnd);
|
|
}
|
|
|
|
if ( elem == wxScrollBar::Element_Thumb )
|
|
{
|
|
*start = thumbStart;
|
|
*width = thumbEnd - thumbStart;
|
|
}
|
|
else if ( elem == wxScrollBar::Element_Bar_1 )
|
|
{
|
|
*start = 0;
|
|
*width = thumbStart;
|
|
}
|
|
else // elem == wxScrollBar::Element_Bar_2
|
|
{
|
|
*start = thumbEnd;
|
|
*width = length - thumbEnd;
|
|
}
|
|
|
|
// everything is relative to the start of the shaft so far
|
|
*start += arrow;
|
|
}
|
|
break;
|
|
|
|
case wxScrollBar::Element_Max:
|
|
default:
|
|
wxFAIL_MSG( _T("unknown scrollbar element") );
|
|
}
|
|
|
|
return rect;
|
|
}
|
|
|
|
/* static */
|
|
wxCoord wxRenderer::StandardScrollBarSize(const wxScrollBar *scrollbar,
|
|
const wxSize& sizeArrowSB)
|
|
{
|
|
wxCoord sizeArrow, sizeTotal;
|
|
if ( scrollbar->GetWindowStyle() & wxVERTICAL )
|
|
{
|
|
sizeArrow = sizeArrowSB.y;
|
|
sizeTotal = scrollbar->GetSize().y;
|
|
}
|
|
else // horizontal
|
|
{
|
|
sizeArrow = sizeArrowSB.x;
|
|
sizeTotal = scrollbar->GetSize().x;
|
|
}
|
|
|
|
return sizeTotal - 2*sizeArrow;
|
|
}
|
|
|
|
/* static */
|
|
wxCoord wxRenderer::StandardScrollbarToPixel(const wxScrollBar *scrollbar,
|
|
int thumbPos,
|
|
const wxSize& sizeArrow)
|
|
{
|
|
int range = scrollbar->GetRange();
|
|
if ( !range )
|
|
{
|
|
// the only valid position anyhow
|
|
return 0;
|
|
}
|
|
|
|
if ( thumbPos == -1 )
|
|
{
|
|
// by default use the current thumb position
|
|
thumbPos = scrollbar->GetThumbPosition();
|
|
}
|
|
|
|
return ( thumbPos*StandardScrollBarSize(scrollbar, sizeArrow) ) / range
|
|
+ (scrollbar->IsVertical() ? sizeArrow.y : sizeArrow.x);
|
|
}
|
|
|
|
/* static */
|
|
int wxRenderer::StandardPixelToScrollbar(const wxScrollBar *scrollbar,
|
|
wxCoord coord,
|
|
const wxSize& sizeArrow)
|
|
{
|
|
return ( (coord - (scrollbar->IsVertical() ? sizeArrow.y : sizeArrow.x)) *
|
|
scrollbar->GetRange() ) /
|
|
StandardScrollBarSize(scrollbar, sizeArrow);
|
|
}
|
|
|
|
/* static */
|
|
wxHitTest wxRenderer::StandardHitTestScrollbar(const wxScrollBar *scrollbar,
|
|
const wxPoint& pt,
|
|
const wxSize& sizeArrowSB)
|
|
{
|
|
// we only need to work with either x or y coord depending on the
|
|
// orientation, choose one (but still check the other one to verify if the
|
|
// mouse is in the window at all)
|
|
wxCoord coord, sizeArrow, sizeTotal;
|
|
wxSize size = scrollbar->GetSize();
|
|
if ( scrollbar->GetWindowStyle() & wxVERTICAL )
|
|
{
|
|
if ( pt.x < 0 || pt.x > size.x )
|
|
return wxHT_NOWHERE;
|
|
|
|
coord = pt.y;
|
|
sizeArrow = sizeArrowSB.y;
|
|
sizeTotal = size.y;
|
|
}
|
|
else // horizontal
|
|
{
|
|
if ( pt.y < 0 || pt.y > size.y )
|
|
return wxHT_NOWHERE;
|
|
|
|
coord = pt.x;
|
|
sizeArrow = sizeArrowSB.x;
|
|
sizeTotal = size.x;
|
|
}
|
|
|
|
// test for the arrows first as it's faster
|
|
if ( coord < 0 || coord > sizeTotal )
|
|
{
|
|
return wxHT_NOWHERE;
|
|
}
|
|
else if ( coord < sizeArrow )
|
|
{
|
|
return wxHT_SCROLLBAR_ARROW_LINE_1;
|
|
}
|
|
else if ( coord > sizeTotal - sizeArrow )
|
|
{
|
|
return wxHT_SCROLLBAR_ARROW_LINE_2;
|
|
}
|
|
else
|
|
{
|
|
// calculate the thumb position in pixels
|
|
sizeTotal -= 2*sizeArrow;
|
|
wxCoord thumbStart, thumbEnd;
|
|
int range = scrollbar->GetRange();
|
|
if ( !range )
|
|
{
|
|
// clicking the scrollbar without range has no effect
|
|
return wxHT_NOWHERE;
|
|
}
|
|
else
|
|
{
|
|
StandardScrollBarThumbSize(sizeTotal,
|
|
scrollbar->GetThumbPosition(),
|
|
scrollbar->GetThumbSize(),
|
|
range,
|
|
&thumbStart,
|
|
&thumbEnd);
|
|
}
|
|
|
|
// now compare with the thumb position
|
|
coord -= sizeArrow;
|
|
if ( coord < thumbStart )
|
|
return wxHT_SCROLLBAR_BAR_1;
|
|
else if ( coord > thumbEnd )
|
|
return wxHT_SCROLLBAR_BAR_2;
|
|
else
|
|
return wxHT_SCROLLBAR_THUMB;
|
|
}
|
|
}
|
|
|
|
wxRenderer::~wxRenderer()
|
|
{
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// wxControlRenderer
|
|
// ----------------------------------------------------------------------------
|
|
|
|
wxControlRenderer::wxControlRenderer(wxWindow *window,
|
|
wxDC& dc,
|
|
wxRenderer *renderer)
|
|
: m_dc(dc)
|
|
{
|
|
m_window = window;
|
|
m_renderer = renderer;
|
|
|
|
wxSize size = m_window->GetClientSize();
|
|
m_rect.x =
|
|
m_rect.y = 0;
|
|
m_rect.width = size.x;
|
|
m_rect.height = size.y;
|
|
}
|
|
|
|
void wxControlRenderer::DrawLabel(const wxBitmap& bitmap,
|
|
wxCoord marginX, wxCoord marginY)
|
|
{
|
|
m_dc.SetFont(m_window->GetFont());
|
|
m_dc.SetTextForeground(m_window->GetForegroundColour());
|
|
|
|
wxString label = m_window->GetLabel();
|
|
if ( !label.empty() || bitmap.Ok() )
|
|
{
|
|
wxRect rectLabel = m_rect;
|
|
if ( bitmap.Ok() )
|
|
{
|
|
rectLabel.Inflate(-marginX, -marginY);
|
|
}
|
|
|
|
wxControl *ctrl = wxStaticCast(m_window, wxControl);
|
|
|
|
m_renderer->DrawButtonLabel(m_dc,
|
|
label,
|
|
bitmap,
|
|
rectLabel,
|
|
m_window->GetStateFlags(),
|
|
ctrl->GetAlignment(),
|
|
ctrl->GetAccelIndex());
|
|
}
|
|
}
|
|
|
|
void wxControlRenderer::DrawFrame()
|
|
{
|
|
m_dc.SetFont(m_window->GetFont());
|
|
m_dc.SetTextForeground(m_window->GetForegroundColour());
|
|
m_dc.SetTextBackground(m_window->GetBackgroundColour());
|
|
|
|
wxControl *ctrl = wxStaticCast(m_window, wxControl);
|
|
|
|
m_renderer->DrawFrame(m_dc,
|
|
m_window->GetLabel(),
|
|
m_rect,
|
|
m_window->GetStateFlags(),
|
|
ctrl->GetAlignment(),
|
|
ctrl->GetAccelIndex());
|
|
}
|
|
|
|
void wxControlRenderer::DrawButtonBorder()
|
|
{
|
|
int flags = m_window->GetStateFlags();
|
|
|
|
m_renderer->DrawButtonBorder(m_dc, m_rect, flags, &m_rect);
|
|
|
|
m_renderer->DrawBackground(m_dc, wxTHEME_BG_COLOUR(m_window), m_rect, flags);
|
|
}
|
|
|
|
void wxControlRenderer::DrawBitmap(const wxBitmap& bitmap)
|
|
{
|
|
int style = m_window->GetWindowStyle();
|
|
DrawBitmap(m_dc, bitmap, m_rect,
|
|
style & wxALIGN_MASK,
|
|
style & wxBI_EXPAND ? wxEXPAND : wxSTRETCH_NOT);
|
|
}
|
|
|
|
/* static */
|
|
void wxControlRenderer::DrawBitmap(wxDC &dc,
|
|
const wxBitmap& bitmap,
|
|
const wxRect& rect,
|
|
int alignment,
|
|
wxStretch stretch)
|
|
{
|
|
// we may change the bitmap if we stretch it
|
|
wxBitmap bmp = bitmap;
|
|
if ( !bmp.Ok() )
|
|
return;
|
|
|
|
int width = bmp.GetWidth(),
|
|
height = bmp.GetHeight();
|
|
|
|
wxCoord x = 0,
|
|
y = 0;
|
|
if ( stretch & wxTILE )
|
|
{
|
|
// tile the bitmap
|
|
for ( ; x < rect.width; x += width )
|
|
{
|
|
for ( y = 0; y < rect.height; y += height )
|
|
{
|
|
// no need to use mask here as we cover the entire window area
|
|
dc.DrawBitmap(bmp, x, y);
|
|
}
|
|
}
|
|
}
|
|
else if ( stretch & wxEXPAND )
|
|
{
|
|
// stretch bitmap to fill the entire control
|
|
bmp = wxImage(bmp).Scale(rect.width, rect.height).ConvertToBitmap();
|
|
}
|
|
else // not stretched, not tiled
|
|
{
|
|
if ( alignment & wxALIGN_RIGHT )
|
|
{
|
|
x = rect.GetRight() - width;
|
|
}
|
|
else if ( alignment & wxALIGN_CENTRE )
|
|
{
|
|
x = (rect.GetLeft() + rect.GetRight() - width + 1) / 2;
|
|
}
|
|
else // alignment & wxALIGN_LEFT
|
|
{
|
|
x = rect.GetLeft();
|
|
}
|
|
|
|
if ( alignment & wxALIGN_BOTTOM )
|
|
{
|
|
y = rect.GetBottom() - height;
|
|
}
|
|
else if ( alignment & wxALIGN_CENTRE_VERTICAL )
|
|
{
|
|
y = (rect.GetTop() + rect.GetBottom() - height + 1) / 2;
|
|
}
|
|
else // alignment & wxALIGN_TOP
|
|
{
|
|
y = rect.GetTop();
|
|
}
|
|
}
|
|
|
|
// do draw it
|
|
dc.DrawBitmap(bmp, x, y, TRUE /* use mask */);
|
|
}
|
|
|
|
void wxControlRenderer::DrawScrollbar(const wxScrollBar *scrollbar,
|
|
int thumbPosOld)
|
|
{
|
|
// we will only redraw the parts which must be redrawn and not everything
|
|
wxRegion rgnUpdate = scrollbar->GetUpdateRegion();
|
|
|
|
{
|
|
wxRect rectUpdate = rgnUpdate.GetBox();
|
|
wxLogTrace(_T("scrollbar"),
|
|
_T("%s redraw: update box is (%d, %d)-(%d, %d)"),
|
|
scrollbar->IsVertical() ? _T("vert") : _T("horz"),
|
|
rectUpdate.GetLeft(),
|
|
rectUpdate.GetTop(),
|
|
rectUpdate.GetRight(),
|
|
rectUpdate.GetBottom());
|
|
|
|
#if 0 //def WXDEBUG_SCROLLBAR
|
|
static bool s_refreshDebug = FALSE;
|
|
if ( s_refreshDebug )
|
|
{
|
|
wxClientDC dc(wxConstCast(scrollbar, wxScrollBar));
|
|
dc.SetBrush(*wxRED_BRUSH);
|
|
dc.SetPen(*wxTRANSPARENT_PEN);
|
|
dc.DrawRectangle(rectUpdate);
|
|
|
|
// under Unix we use "--sync" X option for this
|
|
#ifdef __WXMSW__
|
|
::GdiFlush();
|
|
::Sleep(200);
|
|
#endif // __WXMSW__
|
|
}
|
|
#endif // WXDEBUG_SCROLLBAR
|
|
}
|
|
|
|
wxOrientation orient = scrollbar->IsVertical() ? wxVERTICAL
|
|
: wxHORIZONTAL;
|
|
|
|
// the shaft
|
|
for ( int nBar = 0; nBar < 2; nBar++ )
|
|
{
|
|
wxScrollBar::Element elem =
|
|
(wxScrollBar::Element)(wxScrollBar::Element_Bar_1 + nBar);
|
|
|
|
wxRect rectBar = m_renderer->GetScrollbarRect(scrollbar, elem);
|
|
|
|
if ( rgnUpdate.Contains(rectBar) )
|
|
{
|
|
wxLogTrace(_T("scrollbar"),
|
|
_T("drawing bar part %d at (%d, %d)-(%d, %d)"),
|
|
nBar + 1,
|
|
rectBar.GetLeft(),
|
|
rectBar.GetTop(),
|
|
rectBar.GetRight(),
|
|
rectBar.GetBottom());
|
|
|
|
m_renderer->DrawScrollbarShaft(m_dc,
|
|
orient,
|
|
rectBar,
|
|
scrollbar->GetState(elem));
|
|
}
|
|
}
|
|
|
|
// arrows
|
|
for ( int nArrow = 0; nArrow < 2; nArrow++ )
|
|
{
|
|
wxScrollBar::Element elem =
|
|
(wxScrollBar::Element)(wxScrollBar::Element_Arrow_Line_1 + nArrow);
|
|
|
|
wxRect rectArrow = m_renderer->GetScrollbarRect(scrollbar, elem);
|
|
if ( rgnUpdate.Contains(rectArrow) )
|
|
{
|
|
wxLogTrace(_T("scrollbar"),
|
|
_T("drawing arrow %d at (%d, %d)-(%d, %d)"),
|
|
nArrow + 1,
|
|
rectArrow.GetLeft(),
|
|
rectArrow.GetTop(),
|
|
rectArrow.GetRight(),
|
|
rectArrow.GetBottom());
|
|
|
|
scrollbar->GetArrows().DrawArrow
|
|
(
|
|
(wxScrollArrows::Arrow)nArrow,
|
|
m_dc,
|
|
rectArrow,
|
|
TRUE // draw a scrollbar arrow, not just an arrow
|
|
);
|
|
}
|
|
}
|
|
|
|
// TODO: support for page arrows
|
|
|
|
// and the thumb
|
|
wxScrollBar::Element elem = wxScrollBar::Element_Thumb;
|
|
wxRect rectThumb = m_renderer->GetScrollbarRect(scrollbar, elem);
|
|
if ( rectThumb.width && rectThumb.height && rgnUpdate.Contains(rectThumb) )
|
|
{
|
|
wxLogTrace(_T("scrollbar"),
|
|
_T("drawing thumb at (%d, %d)-(%d, %d)"),
|
|
rectThumb.GetLeft(),
|
|
rectThumb.GetTop(),
|
|
rectThumb.GetRight(),
|
|
rectThumb.GetBottom());
|
|
|
|
m_renderer->DrawScrollbarThumb(m_dc,
|
|
orient,
|
|
rectThumb,
|
|
scrollbar->GetState(elem));
|
|
}
|
|
}
|
|
|
|
void wxControlRenderer::DrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
|
|
{
|
|
wxASSERT_MSG( x1 == x2 || y1 == y2,
|
|
_T("line must be either horizontal or vertical") );
|
|
|
|
if ( x1 == x2 )
|
|
m_renderer->DrawVerticalLine(m_dc, x1, y1, y2);
|
|
else // horizontal
|
|
m_renderer->DrawHorizontalLine(m_dc, y1, x1, x2);
|
|
}
|
|
|
|
#if wxUSE_LISTBOX
|
|
|
|
void wxControlRenderer::DrawItems(const wxListBox *lbox,
|
|
size_t itemFirst, size_t itemLast)
|
|
{
|
|
DoDrawItems(lbox, itemFirst, itemLast);
|
|
}
|
|
|
|
void wxControlRenderer::DoDrawItems(const wxListBox *lbox,
|
|
size_t itemFirst, size_t itemLast,
|
|
bool isCheckLbox)
|
|
{
|
|
// prepare for the drawing: calc the initial position
|
|
wxCoord lineHeight = lbox->GetLineHeight();
|
|
|
|
// note that SetClippingRegion() needs the physical (unscrolled)
|
|
// coordinates while we use the logical (scrolled) ones for the drawing
|
|
// itself
|
|
wxRect rect;
|
|
wxSize size = lbox->GetClientSize();
|
|
rect.width = size.x;
|
|
rect.height = size.y;
|
|
|
|
// keep the text inside the client rect or we will overwrite the vertical
|
|
// scrollbar for the long strings
|
|
m_dc.SetClippingRegion(rect.x, rect.y, rect.width + 1, rect.height + 1);
|
|
|
|
// adjust the rect position now
|
|
lbox->CalcScrolledPosition(rect.x, rect.y, &rect.x, &rect.y);
|
|
rect.y += itemFirst*lineHeight;
|
|
rect.height = lineHeight;
|
|
|
|
// the rect should go to the right visible border so adjust the width if x
|
|
// is shifted (rightmost point should stay the same)
|
|
rect.width -= rect.x;
|
|
|
|
// we'll keep the text colour unchanged
|
|
m_dc.SetTextForeground(lbox->GetForegroundColour());
|
|
|
|
// an item should have the focused rect only when the lbox has focus, so
|
|
// make sure that we never set wxCONTROL_FOCUSED flag if it doesn't
|
|
int itemCurrent = wxWindow::FindFocus() == (wxWindow *)lbox // cast needed
|
|
? lbox->GetCurrentItem()
|
|
: -1;
|
|
for ( size_t n = itemFirst; n < itemLast; n++ )
|
|
{
|
|
int flags = 0;
|
|
if ( (int)n == itemCurrent )
|
|
flags |= wxCONTROL_FOCUSED;
|
|
if ( lbox->IsSelected(n) )
|
|
flags |= wxCONTROL_SELECTED;
|
|
|
|
#if wxUSE_CHECKLISTBOX
|
|
if ( isCheckLbox )
|
|
{
|
|
wxCheckListBox *checklstbox = wxStaticCast(lbox, wxCheckListBox);
|
|
if ( checklstbox->IsChecked(n) )
|
|
flags |= wxCONTROL_CHECKED;
|
|
|
|
m_renderer->DrawCheckItem(m_dc, lbox->GetString(n),
|
|
wxNullBitmap,
|
|
rect,
|
|
flags);
|
|
}
|
|
else
|
|
#endif // wxUSE_CHECKLISTBOX
|
|
{
|
|
m_renderer->DrawItem(m_dc, lbox->GetString(n), rect, flags);
|
|
}
|
|
|
|
rect.y += lineHeight;
|
|
}
|
|
}
|
|
|
|
#endif // wxUSE_LISTBOX
|
|
|
|
#if wxUSE_CHECKLISTBOX
|
|
|
|
void wxControlRenderer::DrawCheckItems(const wxCheckListBox *lbox,
|
|
size_t itemFirst, size_t itemLast)
|
|
{
|
|
DoDrawItems(lbox, itemFirst, itemLast, TRUE);
|
|
}
|
|
|
|
#endif // wxUSE_CHECKLISTBOX
|
|
|
|
#if wxUSE_GAUGE
|
|
|
|
void wxControlRenderer::DrawProgressBar(const wxGauge *gauge)
|
|
{
|
|
// draw background
|
|
m_dc.SetBrush(wxBrush(m_window->GetBackgroundColour(), wxSOLID));
|
|
m_dc.SetPen(*wxTRANSPARENT_PEN);
|
|
m_dc.DrawRectangle(m_rect);
|
|
|
|
int max = gauge->GetRange();
|
|
if ( !max )
|
|
{
|
|
// nothing to draw
|
|
return;
|
|
}
|
|
|
|
// calc the filled rect
|
|
int pos = gauge->GetValue();
|
|
int left = max - pos;
|
|
|
|
wxRect rect = m_rect;
|
|
rect.Deflate(1); // FIXME this depends on the border width
|
|
|
|
m_dc.SetBrush(wxBrush(m_window->GetForegroundColour(), wxSOLID));
|
|
|
|
if ( gauge->IsSmooth() )
|
|
{
|
|
// just draw the rectangle in one go
|
|
if ( gauge->IsVertical() )
|
|
{
|
|
// vert bars grow from bottom to top
|
|
wxCoord dy = ((rect.height - 1) * left) / max;
|
|
rect.y += dy;
|
|
rect.height -= dy;
|
|
}
|
|
else // horizontal
|
|
{
|
|
// grow from left to right
|
|
rect.width -= ((rect.width - 1) * left) / max;
|
|
}
|
|
|
|
m_dc.DrawRectangle(rect);
|
|
}
|
|
else // discrete
|
|
{
|
|
wxSize sizeStep = m_renderer->GetProgressBarStep();
|
|
int step = gauge->IsVertical() ? sizeStep.y : sizeStep.x;
|
|
|
|
// we divide by it below!
|
|
wxCHECK_RET( step, _T("invalid wxGauge step") );
|
|
|
|
// round up to make the progress appear to start faster
|
|
int lenTotal = gauge->IsVertical() ? rect.height : rect.width;
|
|
int steps = ((lenTotal + step - 1) * pos) / (max * step);
|
|
|
|
// calc the coords of one small rect
|
|
wxCoord *px, dx, dy;
|
|
if ( gauge->IsVertical() )
|
|
{
|
|
// draw from bottom to top: so first set y to the bottom
|
|
rect.y += rect.height - 1;
|
|
|
|
// then adjust the height
|
|
rect.height = step;
|
|
|
|
// and then adjust y again to be what it should for the first rect
|
|
rect.y -= rect.height;
|
|
|
|
// we are going up
|
|
step = -step;
|
|
|
|
// remember that this will be the coord which will change
|
|
px = &rect.y;
|
|
|
|
dy = 1;
|
|
dx = 0;
|
|
}
|
|
else // horizontal
|
|
{
|
|
// don't leave 2 empty pixels in the beginning
|
|
rect.x--;
|
|
|
|
px = &rect.x;
|
|
rect.width = step;
|
|
|
|
dy = 0;
|
|
dx = 1;
|
|
}
|
|
|
|
for ( int n = 0; n < steps; n++ )
|
|
{
|
|
wxRect rectSegment = rect;
|
|
rectSegment.Deflate(dx, dy);
|
|
|
|
m_dc.DrawRectangle(rectSegment);
|
|
|
|
*px += step;
|
|
if ( *px < 1 )
|
|
{
|
|
// this can only happen for the last step of vertical gauge
|
|
rect.height = *px - step - 1;
|
|
*px = 1;
|
|
}
|
|
else if ( *px > lenTotal - step )
|
|
{
|
|
// this can only happen for the last step of horizontal gauge
|
|
rect.width = lenTotal - *px - 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif // wxUSE_GAUGE
|
|
|