Files
wxWidgets/src/univ/ctrlrend.cpp
Vadim Zeitlin 3f66f6a5b3 Remove all lines containing cvs/svn "$Id$" keyword.
This keyword is not expanded by Git which means it's not replaced with the
correct revision value in the releases made using git-based scripts and it's
confusing to have lines with unexpanded "$Id$" in the released files. As
expanding them with Git is not that simple (it could be done with git archive
and export-subst attribute) and there are not many benefits in having them in
the first place, just remove all these lines.

If nothing else, this will make an eventual transition to Git simpler.

Closes #14487.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@74602 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
2013-07-26 16:02:46 +00:00

552 lines
16 KiB
C++

///////////////////////////////////////////////////////////////////////////////
// Name: src/univ/ctrlrend.cpp
// Purpose: wxControlRenderer implementation
// Author: Vadim Zeitlin
// Modified by:
// Created: 15.08.00
// Copyright: (c) 2000 SciTech Software, Inc. (www.scitechsoft.com)
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
// ===========================================================================
// declarations
// ===========================================================================
// ---------------------------------------------------------------------------
// headers
// ---------------------------------------------------------------------------
// 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"
#include "wx/log.h"
#include "wx/gauge.h"
#include "wx/image.h"
#endif // WX_PRECOMP
#include "wx/univ/theme.h"
#include "wx/univ/renderer.h"
#include "wx/univ/colschem.h"
// ============================================================================
// implementation
// ============================================================================
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()
{
m_dc.SetBackgroundMode(wxTRANSPARENT);
m_dc.SetFont(m_window->GetFont());
m_dc.SetTextForeground(m_window->GetForegroundColour());
wxString label = m_window->GetLabel();
if ( !label.empty() )
{
wxControl *ctrl = wxStaticCast(m_window, wxControl);
m_renderer->DrawLabel(m_dc,
label,
m_rect,
m_window->GetStateFlags(),
ctrl->GetAlignment(),
ctrl->GetAccelIndex());
}
}
void wxControlRenderer::DrawButtonLabel(const wxBitmap& bitmap,
wxCoord marginX, wxCoord marginY)
{
m_dc.SetBackgroundMode(wxTRANSPARENT);
m_dc.SetFont(m_window->GetFont());
m_dc.SetTextForeground(m_window->GetForegroundColour());
wxString label = m_window->GetLabel();
if ( !label.empty() || bitmap.IsOk() )
{
wxRect rectLabel = m_rect;
if ( bitmap.IsOk() )
{
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);
// Why do this here?
// m_renderer->DrawButtonSurface(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.IsOk() )
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);
}
}
}
#if wxUSE_IMAGE
else if ( stretch & wxEXPAND )
{
// stretch bitmap to fill the entire control
bmp = wxBitmap(wxImage(bmp.ConvertToImage()).Scale(rect.width, rect.height));
}
#endif // wxUSE_IMAGE
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 */);
}
#if wxUSE_SCROLLBAR
void wxControlRenderer::DrawScrollbar(const wxScrollBar *scrollbar,
int WXUNUSED(thumbPosOld))
{
// we will only redraw the parts which must be redrawn and not everything
wxRegion rgnUpdate = scrollbar->GetUpdateRegion();
{
wxRect rectUpdate = rgnUpdate.GetBox();
wxLogTrace(wxT("scrollbar"),
wxT("%s redraw: update box is (%d, %d)-(%d, %d)"),
scrollbar->IsVertical() ? wxT("vert") : wxT("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 = scrollbar->GetScrollbarRect(elem);
if ( rgnUpdate.Contains(rectBar) )
{
wxLogTrace(wxT("scrollbar"),
wxT("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 = scrollbar->GetScrollbarRect(elem);
if ( rgnUpdate.Contains(rectArrow) )
{
wxLogTrace(wxT("scrollbar"),
wxT("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 = scrollbar->GetScrollbarRect(elem);
if ( rectThumb.width && rectThumb.height && rgnUpdate.Contains(rectThumb) )
{
wxLogTrace(wxT("scrollbar"),
wxT("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));
}
}
#endif // wxUSE_SCROLLBAR
void wxControlRenderer::DrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
{
wxASSERT_MSG( x1 == x2 || y1 == y2,
wxT("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,
#if wxUSE_CHECKLISTBOX
bool isCheckLbox
#else
bool WXUNUSED(isCheckLbox)
#endif
)
{
// 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
wxColour col = m_window->UseFgCol() ? m_window->GetForegroundColour()
: wxTHEME_COLOUR(GAUGE);
m_dc.SetBrush(wxBrush(col, 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, wxT("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;
wxCoord 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