introduce wxBG_STYLE_{ERASE,PAINT} and implement their documented semantics in wxGTK

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@61084 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin 2009-06-16 23:04:42 +00:00
parent b85b06e13d
commit 9c61c5b04b
9 changed files with 250 additions and 184 deletions

View File

@ -124,6 +124,10 @@ Changes in behaviour not resulting in compilation errors, please read this!
- wxLoadFileSelector() now allows the user to select existing files only.
- Erase background events are now not generated at all when background style is
changed. See the updated wxWindow::SetBackgroundStyle() description in the
manual for more details.
Changes in behaviour which may result in compilation errors
-----------------------------------------------------------

View File

@ -219,8 +219,8 @@ public:
wxAutoBufferedPaintDC(wxWindow* win)
: wxAutoBufferedPaintDCBase(win)
{
wxASSERT_MSG( win->GetBackgroundStyle() == wxBG_STYLE_CUSTOM,
"You need to call SetBackgroundStyle(wxBG_STYLE_CUSTOM) in ctor, "
wxASSERT_MSG( win->GetBackgroundStyle() == wxBG_STYLE_PAINT,
"You need to call SetBackgroundStyle(wxBG_STYLE_PAINT) in ctor, "
"and also, if needed, paint the background in wxEVT_PAINT handler."
);
}

View File

@ -1836,13 +1836,32 @@ enum wxBorder
/*
* Background styles. See wxWindow::SetBackgroundStyle
*/
enum wxBackgroundStyle
{
// background is erased in the EVT_ERASE_BACKGROUND handler or using the
// system default background if no such handler is defined (this is the
// default style)
wxBG_STYLE_ERASE,
// background is erased by the system, no EVT_ERASE_BACKGROUND event is
// generated at all
wxBG_STYLE_SYSTEM,
// background is erased in EVT_PAINT handler and not erased at all before
// it, this should be used if the paint handler paints over the entire
// window to avoid flicker
wxBG_STYLE_PAINT,
// this is a Mac-only style, don't use in portable code
wxBG_STYLE_TRANSPARENT,
// this style is deprecated and doesn't do anything, don't use
wxBG_STYLE_COLOUR,
wxBG_STYLE_CUSTOM,
wxBG_STYLE_TRANSPARENT
// this style is deprecated and is synonymous with wxBG_STYLE_PAINT, use
// the new name
wxBG_STYLE_CUSTOM = wxBG_STYLE_PAINT
};
/*

View File

@ -1032,9 +1032,10 @@ public:
wxColour GetForegroundColour() const;
// Set/get the background style.
// Pass one of wxBG_STYLE_SYSTEM, wxBG_STYLE_COLOUR, wxBG_STYLE_CUSTOM
virtual bool SetBackgroundStyle(wxBackgroundStyle style) { m_backgroundStyle = style; return true; }
virtual wxBackgroundStyle GetBackgroundStyle() const { return m_backgroundStyle; }
virtual bool SetBackgroundStyle(wxBackgroundStyle style)
{ m_backgroundStyle = style; return true; }
wxBackgroundStyle GetBackgroundStyle() const
{ return m_backgroundStyle; }
// returns true if the control has "transparent" areas such as a
// wxStaticText and wxCheckBox and the background should be adapted

View File

@ -136,28 +136,54 @@ enum wxBorder
/**
Background styles. See wxWindow::SetBackgroundStyle().
Background styles.
@see wxWindow::SetBackgroundStyle()
*/
enum wxBackgroundStyle
{
/// Use the default background, as determined by
/// the system or the current theme.
/**
Default background style value indicating that the background may be
erased in the user-defined EVT_ERASE_BACKGROUND handler.
If no such handler is defined (or if it skips the event), the effect of
this style is the same as wxBG_STYLE_SYSTEM. If an empty handler (@em
not skipping the event) is defined, the effect is the same as
wxBG_STYLE_PAINT, i.e. the background is not erased at all until
EVT_PAINT handler is executed.
This is the only background style value for which erase background
events are generated at all.
*/
wxBG_STYLE_ERASE,
/**
Use the default background, as determined by the system or the current
theme.
If the window has been assigned a non-default background colour, it
will be used for erasing its background. Otherwise the default
background (which might be a gradient or a pattern) will be used.
EVT_ERASE_BACKGROUND event will not be generated at all for windows
with this style.
*/
wxBG_STYLE_SYSTEM,
/// Use a solid colour for the background, this style is set automatically if you call
/// SetBackgroundColour() so you only need to set it explicitly if you had
/// changed the background style to something else before.
wxBG_STYLE_COLOUR,
/**
Indicates that the background is only erased in the user-defined
EVT_PAINT handler.
/// Don't draw the background at all, it's supposed that it is drawn by
/// the user-defined erase background event handler.
/// This style should be used to avoid flicker when the background is entirely
/// custom-drawn.
wxBG_STYLE_CUSTOM,
Using this style avoids flicker which would result from redrawing the
background twice if the EVT_PAINT handler entirely overwrites it. It
must not be used however if the paint handler leaves any parts of the
window unpainted as their contents is then undetermined. Only use it if
you repaint the whole window in your handler.
/// The background is (partially) transparent,this style is automatically set if you call
/// SetTransparent() which is used to set the transparency level.
wxBG_STYLE_TRANSPARENT
EVT_ERASE_BACKGROUND event will not be generated at all for windows
with this style.
*/
wxBG_STYLE_PAINT
};

View File

@ -1418,12 +1418,12 @@ public:
/**
Returns the background style of the window.
The background style can be one of the wxBackgroundStyle.
@see SetBackgroundColour(), GetForegroundColour(),
SetBackgroundStyle(), SetTransparent()
*/
virtual wxBackgroundStyle GetBackgroundStyle() const;
/**
Returns the character height for this window.
*/
@ -1583,8 +1583,28 @@ public:
virtual bool SetBackgroundColour(const wxColour& colour);
/**
Sets the background style of the window. see GetBackgroundStyle() for
the description of the possible style values.
Sets the background style of the window.
The default background style is wxBG_STYLE_ERASE which indicates that
the window background may be erased in EVT_ERASE_BACKGROUND handler.
This is a safe compatibility default however you may want to change it
to wxBG_STYLE_SYSTEM if you don't define any erase background event
handlers at all to avoid unnecessary generation of erase background
events and always let system erase the background. And you should
change the background style to wxBG_STYLE_PAINT if you define an
EVT_PAINT handler which completely overwrites the window background as
in this case erasing it previously, either in EVT_ERASE_BACKGROUND
handler or in the system default handler, would result in flicker as
the background pixels will be repainted twice every time the window is
redrawn. Do ensure that the background is entirely erased by your
EVT_PAINT handler in this case however as otherwise garbage may be left
on screen.
Notice that in previous versions of wxWidgets a common way to work
around the above mentioned flickering problem was to define an empty
EVT_ERASE_BACKGROUND handler. Setting background style to
wxBG_STYLE_PAINT is a simpler and more efficient solution to the same
problem.
@see SetBackgroundColour(), GetForegroundColour(),
SetTransparent()

View File

@ -1,11 +1,11 @@
/////////////////////////////////////////////////////////////////////////////
// Name: erase.cpp
// Name: samples/erase/erase.cpp
// Purpose: Erase wxWidgets sample
// Author: Robert Roebling
// Modified by:
// Author: Robert Roebling, Vadim Zeitlin
// Created: 04/01/98
// RCS-ID: $Id$
// Copyright: (c) Robert Roebling
// Copyright: (c) 1998 Robert Roebling
// (c) 2009 Vadim Zeitlin
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
@ -30,6 +30,8 @@
#include "wx/wx.h"
#endif
#include "wx/dcbuffer.h"
// ----------------------------------------------------------------------------
// resources
// ----------------------------------------------------------------------------
@ -52,10 +54,10 @@ public:
class MyCanvas : public wxScrolledWindow
{
public:
MyCanvas( wxFrame *parent );
MyCanvas(wxFrame *parent);
void UseBuffer(bool useBuffer) { m_useBuffer = useBuffer; Refresh(); }
void EraseBg(bool eraseBg) { m_eraseBg = eraseBg; Refresh(); }
bool UsesBuffer() const { return m_useBuffer; }
private:
void OnPaint( wxPaintEvent &event );
@ -71,9 +73,6 @@ private:
// use wxMemoryDC in OnPaint()?
bool m_useBuffer;
// paint custom background in OnEraseBackground()?
bool m_eraseBg;
DECLARE_EVENT_TABLE()
};
@ -83,12 +82,23 @@ class MyFrame : public wxFrame
public:
MyFrame();
private:
void OnUseBuffer(wxCommandEvent& event);
void OnEraseBg(wxCommandEvent& event);
void OnChangeBgStyle(wxCommandEvent& event);
void OnQuit(wxCommandEvent& event);
void OnAbout(wxCommandEvent& event);
private:
// we can only use double-buffering with wxBG_STYLE_PAINT
void OnUpdateUIUseBuffer(wxUpdateUIEvent& event)
{
event.Enable( m_canvas->GetBackgroundStyle() == wxBG_STYLE_PAINT );
}
void OnUpdateUIChangeBgStyle(wxUpdateUIEvent& event)
{
event.Enable( !m_canvas->UsesBuffer() );
}
MyCanvas *m_canvas;
DECLARE_EVENT_TABLE()
@ -103,7 +113,9 @@ enum
{
// menu items
Erase_Menu_UseBuffer = 100,
Erase_Menu_EraseBg,
Erase_Menu_BgStyleErase,
Erase_Menu_BgStyleSystem,
Erase_Menu_BgStylePaint,
Erase_Menu_Exit = wxID_EXIT,
Erase_Menu_About = wxID_ABOUT
};
@ -133,40 +145,46 @@ bool MyApp::OnInit()
BEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_MENU(Erase_Menu_UseBuffer, MyFrame::OnUseBuffer)
EVT_MENU(Erase_Menu_EraseBg, MyFrame::OnEraseBg)
EVT_MENU_RANGE(Erase_Menu_BgStyleErase, Erase_Menu_BgStylePaint,
MyFrame::OnChangeBgStyle)
EVT_MENU(Erase_Menu_Exit, MyFrame::OnQuit)
EVT_MENU(Erase_Menu_About, MyFrame::OnAbout)
EVT_UPDATE_UI(Erase_Menu_UseBuffer, MyFrame::OnUpdateUIUseBuffer)
EVT_UPDATE_UI_RANGE(Erase_Menu_BgStyleErase, Erase_Menu_BgStylePaint,
MyFrame::OnUpdateUIChangeBgStyle)
END_EVENT_TABLE()
// frame constructor
MyFrame::MyFrame()
: wxFrame(NULL, wxID_ANY, _T("Erase sample"),
: wxFrame(NULL, wxID_ANY, "Erase sample",
wxPoint(50, 50), wxSize(450, 340))
{
SetIcon(wxICON(mondrian));
wxMenu *menuFile = new wxMenu(_T(""), wxMENU_TEAROFF);
menuFile->AppendCheckItem(Erase_Menu_UseBuffer, _T("&Use memory DC\tCtrl-M"));
menuFile->AppendCheckItem(Erase_Menu_EraseBg, _T("Custom &background\tCtrl-B"));
wxMenu *menuFile = new wxMenu("", wxMENU_TEAROFF);
menuFile->AppendCheckItem(Erase_Menu_UseBuffer, "&Use memory DC\tCtrl-M");
menuFile->AppendSeparator();
menuFile->Append(Erase_Menu_Exit, _T("E&xit\tAlt-X"), _T("Quit this program"));
menuFile->AppendRadioItem(Erase_Menu_BgStyleErase,
"Use wxBG_STYLE_&ERASE\tCtrl-E");
menuFile->AppendRadioItem(Erase_Menu_BgStyleSystem,
"Use wxBG_STYLE_&SYSTEM\tCtrl-S");
menuFile->AppendRadioItem(Erase_Menu_BgStylePaint,
"Use wxBG_STYLE_&PAINT\tCtrl-P");
menuFile->AppendSeparator();
menuFile->Append(Erase_Menu_Exit, "E&xit\tAlt-X", "Quit this program");
wxMenu *helpMenu = new wxMenu;
helpMenu->Append(Erase_Menu_About, _T("&About...\tCtrl-A"), _T("Show about dialog"));
helpMenu->Append(Erase_Menu_About, "&About...\tCtrl-A", "Show about dialog");
wxMenuBar *menuBar = new wxMenuBar();
menuBar->Append(menuFile, _T("&File"));
menuBar->Append(helpMenu, _T("&Help"));
menuBar->Append(menuFile, "&File");
menuBar->Append(helpMenu, "&Help");
SetMenuBar(menuBar);
#if wxUSE_STATUSBAR
// create a status bar just for fun (by default with 1 pane only)
CreateStatusBar(2);
SetStatusText(_T("Welcome to wxWidgets erase sample!"));
#endif // wxUSE_STATUSBAR
m_canvas = new MyCanvas( this );
}
@ -176,9 +194,12 @@ void MyFrame::OnUseBuffer(wxCommandEvent& event)
m_canvas->UseBuffer(event.IsChecked());
}
void MyFrame::OnEraseBg(wxCommandEvent& event)
void MyFrame::OnChangeBgStyle(wxCommandEvent& event)
{
m_canvas->EraseBg(event.IsChecked());
int style = wxBG_STYLE_ERASE + event.GetId() - Erase_Menu_BgStyleErase;
m_canvas->SetBackgroundStyle(static_cast<wxBackgroundStyle>(style));
m_canvas->Refresh();
}
void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
@ -188,22 +209,29 @@ void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
{
wxMessageBox(_T("This sample shows how you can draw custom background."),
_T("About Erase Sample"), wxOK | wxICON_INFORMATION, this);
wxMessageBox
(
"This sample shows differences between different background styles "
"and how you may draw custom background.\n"
"\n"
"(c) 1998 Robert Roebling\n"
"(c) 2009 Vadim Zeitlin\n",
"About Erase Sample",
wxOK | wxICON_INFORMATION,
this
);
}
BEGIN_EVENT_TABLE(MyCanvas, wxScrolledWindow)
EVT_PAINT( MyCanvas::OnPaint)
EVT_CHAR( MyCanvas::OnChar)
EVT_ERASE_BACKGROUND( MyCanvas::OnEraseBackground)
EVT_PAINT(MyCanvas::OnPaint)
EVT_CHAR(MyCanvas::OnChar)
EVT_ERASE_BACKGROUND(MyCanvas::OnEraseBackground)
END_EVENT_TABLE()
MyCanvas::MyCanvas( wxFrame *parent )
: wxScrolledWindow( parent, wxID_ANY, wxDefaultPosition, wxDefaultSize,
wxScrolledWindowStyle | wxSUNKEN_BORDER )
MyCanvas::MyCanvas(wxFrame *parent)
: wxScrolledWindow(parent, wxID_ANY)
{
m_eraseBg =
m_useBuffer = false;
SetScrollbars( 10, 10, 40, 100, 0, 0 );
@ -213,6 +241,7 @@ MyCanvas::MyCanvas( wxFrame *parent )
new wxStaticBitmap( this, wxID_ANY, m_bitmap, wxPoint(80,20) );
SetFocusIgnoringChildren();
SetBackgroundColour(*wxBLUE);
}
void MyCanvas::OnChar( wxKeyEvent &event )
@ -241,99 +270,47 @@ void MyCanvas::OnChar( wxKeyEvent &event )
void MyCanvas::DoPaint(wxDC& dc)
{
dc.SetBrush( *wxBLACK_BRUSH );
dc.DrawRectangle( 10,10,200,50 );
dc.DrawRectangle( 10,10,60,50 );
dc.DrawBitmap( m_bitmap, 10, 20, true );
dc.DrawBitmap( m_bitmap, 20, 20, true );
dc.SetTextForeground(*wxBLUE);
dc.DrawText(_T("This text is drawn from OnPaint"), 65, 65);
dc.SetTextForeground(*wxWHITE);
dc.DrawText("This text is drawn from OnPaint", 65, 65);
wxString tmp;
tmp.Printf( _T("Hit any key to display more text: %s"), m_text.c_str() );
tmp.Printf("Hit any key to display more text: %s", m_text);
int w,h;
dc.GetTextExtent( tmp, &w, &h );
dc.SetBrush( *wxWHITE_BRUSH );
dc.DrawRectangle( 65, 85, w, h );
dc.DrawText( tmp, 65, 85 );
#if 0
wxRegionIterator upd( GetUpdateRegion() );
while (upd)
{
wxLogDebug( _T("Paint: %d %d %d %d"), upd.GetX(), upd.GetY(), upd.GetWidth(), upd.GetHeight() );
upd ++;
}
#endif
#if 0
wxSize size = GetSize();
wxSize client_size = GetClientSize();
wxLogDebug( _T("size %d %d client_size %d %d"), size.x, size.y, client_size.x, client_size.y );
#endif
#if 0
int i;
dc.SetPen( *wxWHITE_PEN );
for (i = 0; i < 20; i += 2)
dc.DrawLine( i,i, i+100,i );
dc.SetPen( *wxWHITE_PEN );
for (i = 200; i < 220; i += 2)
dc.DrawLine( i-200,i, i-100,i );
wxRegion region( 110, 110, 80, 80 );
wxRegion hole( 130, 130, 40, 1 );
region.Intersect( hole );
dc.SetClippingRegion( region );
dc.SetBrush( *wxRED_BRUSH );
dc.DrawRectangle( 100, 100, 200, 200 );
dc.DestroyClippingRegion();
dc.SetPen( *wxTRANSPARENT_PEN );
wxRegion strip( 110, 200, 30, 1 );
wxRegionIterator it( strip );
while (it)
{
dc.DrawRectangle( it.GetX(), it.GetY(), it.GetWidth(), it.GetHeight() );
it ++;
}
#endif // 0
}
void MyCanvas::OnPaint( wxPaintEvent &WXUNUSED(event) )
{
wxPaintDC dcWin(this);
PrepareDC( dcWin );
if ( m_useBuffer )
{
const wxSize size = GetClientSize();
wxMemoryDC dc;
wxBitmap bmp(size.x, size.y);
dc.SelectObject(bmp);
dc.Blit(0, 0, size.x, size.y, &dcWin, 0, 0);
dc.DrawText(_T("(copy of background)"), 5, 120 );
wxAutoBufferedPaintDC dc(this);
PrepareDC(dc);
DoPaint(dc);
dcWin.Blit(0, 0, size.x, size.y, &dc, 0, 0);
}
else
{
DoPaint(dcWin);
wxPaintDC dc(this);
PrepareDC(dc);
DoPaint(dc);
}
}
void MyCanvas::OnEraseBackground( wxEraseEvent& event )
{
if ( !m_eraseBg )
{
event.Skip();
return;
}
wxASSERT_MSG
(
GetBackgroundStyle() == wxBG_STYLE_ERASE,
"shouldn't be called unless background style is \"erase\""
);
wxDC& dc = *event.GetDC();
dc.SetPen(*wxGREEN_PEN);
@ -355,6 +332,7 @@ void MyCanvas::OnEraseBackground( wxEraseEvent& event )
}
dc.SetTextForeground(*wxRED);
dc.DrawText(_T("This text is drawn from OnEraseBackground"), 60, 160);
dc.SetBackgroundMode(wxSOLID);
dc.DrawText("This text is drawn from OnEraseBackground", 60, 160);
}

View File

@ -154,7 +154,7 @@ wxWindowBase::wxWindowBase()
m_exStyle =
m_windowStyle = 0;
m_backgroundStyle = wxBG_STYLE_SYSTEM;
m_backgroundStyle = wxBG_STYLE_ERASE;
#if wxUSE_CONSTRAINTS
// no constraints whatsoever
@ -1333,8 +1333,6 @@ bool wxWindowBase::SetBackgroundColour( const wxColour &colour )
return false;
m_hasBgCol = colour.IsOk();
if ( m_backgroundStyle != wxBG_STYLE_CUSTOM )
m_backgroundStyle = m_hasBgCol ? wxBG_STYLE_COLOUR : wxBG_STYLE_SYSTEM;
m_inheritBgCol = m_hasBgCol;
m_backgroundColour = colour;

View File

@ -2586,8 +2586,8 @@ void wxWindowGTK::OnInternalIdle()
RealizeTabOrder();
}
// Update style if the window was not yet realized
// and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
// Update style if the window was not yet realized when
// SetBackgroundStyle() was called
if (m_needsStyleChange)
{
SetBackgroundStyle(GetBackgroundStyle());
@ -3655,7 +3655,36 @@ void wxWindowGTK::GtkSendPaintEvents()
}
}
if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM))
switch ( GetBackgroundStyle() )
{
case wxBG_STYLE_ERASE:
{
wxWindowDC dc( (wxWindow*)this );
dc.SetDeviceClippingRegion( m_updateRegion );
// Work around gtk-qt <= 0.60 bug whereby the window colour
// remains grey
if ( UseBgCol() &&
wxSystemOptions::
GetOptionInt("gtk.window.force-background-colour") )
{
dc.SetBackground(GetBackgroundColour());
dc.Clear();
}
wxEraseEvent erase_event( GetId(), &dc );
erase_event.SetEventObject( this );
if ( HandleWindowEvent(erase_event) )
{
// background erased, don't do it again
break;
}
}
// fall through
case wxBG_STYLE_SYSTEM:
if ( GetThemeEnabled() )
{
// find ancestor from which to steal background
wxWindow *parent = wxGetTopLevelParent((wxWindow *)this);
@ -3686,23 +3715,14 @@ void wxWindowGTK::GtkSendPaintEvents()
}
}
}
else
{
wxWindowDC dc( (wxWindow*)this );
dc.SetDeviceClippingRegion( m_updateRegion );
break;
// Work around gtk-qt <= 0.60 bug whereby the window colour
// remains grey
if (GetBackgroundStyle() == wxBG_STYLE_COLOUR && GetBackgroundColour().Ok() && wxSystemOptions::GetOptionInt(wxT("gtk.window.force-background-colour")) == 1)
{
dc.SetBackground(wxBrush(GetBackgroundColour()));
dc.Clear();
}
case wxBG_STYLE_PAINT:
// nothing to do: window will be painted over in EVT_PAINT
break;
wxEraseEvent erase_event( GetId(), &dc );
erase_event.SetEventObject( this );
HandleWindowEvent(erase_event);
default:
wxFAIL_MSG( "unsupported background style" );
}
wxNcPaintEvent nc_paint_event( GetId() );
@ -3767,7 +3787,6 @@ bool wxWindowGTK::SetBackgroundColour( const wxColour &colour )
// apply style change (forceStyle=true so that new style is applied
// even if the bg colour changed from valid to wxNullColour)
if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM)
GTKApplyWidgetStyle(true);
return true;
@ -3896,7 +3915,7 @@ bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style)
{
wxWindowBase::SetBackgroundStyle(style);
if (style == wxBG_STYLE_CUSTOM)
if ( style == wxBG_STYLE_PAINT )
{
GdkWindow *window;
if ( m_wxwindow )
@ -3934,6 +3953,7 @@ bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style)
// even if the bg colour changed from valid to wxNullColour):
GTKApplyWidgetStyle(true);
}
return true;
}