Files
wxWidgets/src/univ/ctrlrend.cpp
Vadim Zeitlin 01c1dde264 Avoid deprecated wxPen/wxBrush/wxFont API in wxX11 code.
Also simplify the code by relying on implicit constructors of wxPen and
wxBrush from wxColour.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@77873 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
2014-09-23 17:45:10 +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(m_window->GetBackgroundColour());
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(col);
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