Merge branch 'grid-uitests-gtk'

Fixes to wxUIActionSimulator allowing the tests using it to work for
wxGrid in wxGTK.

And some improvements and bug fixes to wxGrid itself.

Closes https://github.com/wxWidgets/wxWidgets/pull/1609
This commit is contained in:
Vadim Zeitlin
2019-10-21 21:12:01 +02:00
10 changed files with 389 additions and 127 deletions

View File

@@ -936,7 +936,7 @@ struct WXDLLIMPEXP_CORE wxGridSizesInfo
// wxGrid
// ----------------------------------------------------------------------------
class WXDLLIMPEXP_CORE wxGrid : public wxScrolledWindow
class WXDLLIMPEXP_CORE wxGrid : public wxScrolledCanvas
{
public:
// possible selection modes
@@ -1937,9 +1937,8 @@ public:
// override some base class functions
virtual wxWindow *GetMainWindowOfCompositeControl() wxOVERRIDE
{ return (wxWindow*)m_gridWin; }
virtual void Fit() wxOVERRIDE;
virtual void SetFocus() wxOVERRIDE;
// implementation only
void CancelMouseCapture();
@@ -2277,7 +2276,7 @@ protected:
private:
// implement wxScrolledWindow method to return m_gridWin size
// implement wxScrolledCanvas method to return m_gridWin size
virtual wxSize GetSizeAvailableForScrollTarget(const wxSize& size) wxOVERRIDE;
// depending on the values of m_numFrozenRows and m_numFrozenCols, it will

View File

@@ -2866,8 +2866,14 @@ public:
/**
Enables or disables in-place editing of grid cell data.
The grid will issue either a @c wxEVT_GRID_EDITOR_SHOWN or
@c wxEVT_GRID_EDITOR_HIDDEN event.
Enabling in-place editing generates @c wxEVT_GRID_EDITOR_SHOWN and, if
it isn't vetoed by the application, shows the in-place editor which
allows the user to change the cell value.
Disabling in-place editing does nothing if the in-place editor isn't
currently show, otherwise the @c wxEVT_GRID_EDITOR_HIDDEN event is
generated but, unlike the "shown" event, it can't be vetoed and the
in-place editor is dismissed unconditionally.
*/
void EnableCellEditControl(bool enable = true);
@@ -3249,7 +3255,11 @@ public:
void SetReadOnly(int row, int col, bool isReadOnly = true);
/**
Displays the in-place cell edit control for the current cell.
Displays the active in-place cell edit control for the current cell
after it was hidden.
Note that this method does @em not start editing the cell, this is only
done by EnableCellEditControl().
*/
void ShowCellEditControl();

View File

@@ -183,6 +183,7 @@ wxBEGIN_EVENT_TABLE( GridFrame, wxFrame )
EVT_MENU( ID_DELETEROW, GridFrame::DeleteSelectedRows )
EVT_MENU( ID_DELETECOL, GridFrame::DeleteSelectedCols )
EVT_MENU( ID_CLEARGRID, GridFrame::ClearGrid )
EVT_MENU( ID_EDITCELL, GridFrame::EditCell )
EVT_MENU( ID_SETCORNERLABEL, GridFrame::SetCornerLabelValue )
EVT_MENU( ID_SHOWSEL, GridFrame::ShowSelection )
EVT_MENU( ID_SELCELLS, GridFrame::SelectCells )
@@ -372,6 +373,7 @@ GridFrame::GridFrame()
editMenu->Append( ID_DELETEROW, "Delete selected ro&ws" );
editMenu->Append( ID_DELETECOL, "Delete selected co&ls" );
editMenu->Append( ID_CLEARGRID, "Cl&ear grid cell contents" );
editMenu->Append( ID_EDITCELL, "&Edit current cell" );
editMenu->Append( ID_SETCORNERLABEL, "&Set corner label..." );
editMenu->AppendCheckItem( ID_FREEZE_OR_THAW, "Freeze up to cursor\tCtrl-F" );
@@ -1161,6 +1163,11 @@ void GridFrame::ClearGrid( wxCommandEvent& WXUNUSED(ev) )
grid->ClearGrid();
}
void GridFrame::EditCell( wxCommandEvent& WXUNUSED(ev) )
{
grid->EnableCellEditControl();
}
void GridFrame::SetCornerLabelValue( wxCommandEvent& WXUNUSED(ev) )
{
wxTextEntryDialog dialog(this,

View File

@@ -69,6 +69,7 @@ class GridFrame : public wxFrame
void DeleteSelectedRows( wxCommandEvent& );
void DeleteSelectedCols( wxCommandEvent& );
void ClearGrid( wxCommandEvent& );
void EditCell( wxCommandEvent& );
void SetCornerLabelValue( wxCommandEvent& );
void ShowSelection( wxCommandEvent& );
void SelectCells( wxCommandEvent& );
@@ -179,6 +180,7 @@ public:
ID_DELETEROW,
ID_DELETECOL,
ID_CLEARGRID,
ID_EDITCELL,
ID_SETCORNERLABEL,
ID_SHOWSEL,
ID_CHANGESEL,

View File

@@ -2257,7 +2257,7 @@ void wxGridWindow::OnFocus(wxFocusEvent& event)
/////////////////////////////////////////////////////////////////////
wxBEGIN_EVENT_TABLE( wxGrid, wxScrolledWindow )
wxBEGIN_EVENT_TABLE( wxGrid, wxScrolledCanvas )
EVT_PAINT( wxGrid::OnPaint )
EVT_SIZE( wxGrid::OnSize )
EVT_KEY_DOWN( wxGrid::OnKeyDown )
@@ -2271,7 +2271,7 @@ bool wxGrid::Create(wxWindow *parent, wxWindowID id,
const wxPoint& pos, const wxSize& size,
long style, const wxString& name)
{
if (!wxScrolledWindow::Create(parent, id, pos, size,
if (!wxScrolledCanvas::Create(parent, id, pos, size,
style | wxWANTS_CHARS, name))
return false;
@@ -3390,7 +3390,7 @@ wxGridCellCoordsArray wxGrid::CalcCellsExposed( const wxRegion& reg,
void wxGrid::PrepareDCFor(wxDC &dc, wxGridWindow *gridWindow)
{
wxScrolledWindow::PrepareDC( dc );
wxScrolledCanvas::PrepareDC( dc );
wxPoint dcOrigin = dc.GetDeviceOrigin() - GetGridWindowOffset(gridWindow);
@@ -5186,7 +5186,7 @@ void wxGrid::Refresh(bool eraseb, const wxRect* rect)
if ( m_created && !GetBatchCount() )
{
// Refresh to get correct scrolled position:
wxScrolledWindow::Refresh(eraseb, rect);
wxScrolledCanvas::Refresh(eraseb, rect);
if (rect)
{
@@ -6824,7 +6824,7 @@ void wxGrid::ForceRefresh()
void wxGrid::DoEnable(bool enable)
{
wxScrolledWindow::DoEnable(enable);
wxScrolledCanvas::DoEnable(enable);
Refresh(false /* don't erase background */);
}
@@ -7908,7 +7908,7 @@ void wxGrid::SetRowLabelSize( int width )
m_rowLabelWidth = width;
InvalidateBestSize();
CalcWindowSizes();
wxScrolledWindow::Refresh( true );
wxScrolledCanvas::Refresh( true );
}
}
@@ -7938,7 +7938,7 @@ void wxGrid::SetColLabelSize( int height )
m_colLabelHeight = height;
InvalidateBestSize();
CalcWindowSizes();
wxScrolledWindow::Refresh( true );
wxScrolledCanvas::Refresh( true );
}
}
@@ -9397,52 +9397,67 @@ wxGrid::AutoSizeColOrRow(int colOrRow, bool setAsMin, wxGridDirection direction)
}
// now also compare with the column label extent
wxCoord w, h;
wxCoord extentLabel;
dc.SetFont( GetLabelFont() );
bool addMargin = true;
// We add some margin around text for better readability.
const int margin = FromDIP(column ? 10 : 6);
if ( column )
{
if ( m_useNativeHeader )
{
w = GetGridColHeader()->GetColumnTitleWidth(colOrRow);
extentLabel = GetGridColHeader()->GetColumnTitleWidth(colOrRow);
// GetColumnTitleWidth already adds margins internally.
addMargin = false;
h = 0;
// Note that GetColumnTitleWidth already adds margins internally,
// so we don't need to add them here.
}
else
{
dc.GetMultiLineTextExtent( GetColLabelValue(colOrRow), &w, &h );
if ( GetColLabelTextOrientation() == wxVERTICAL )
w = h;
const wxSize
size = dc.GetMultiLineTextExtent(GetColLabelValue(colOrRow));
extentLabel = GetColLabelTextOrientation() == wxVERTICAL
? size.y
: size.x;
// Add some margins around text for better readability.
extentLabel += margin;
}
}
else
{
dc.GetMultiLineTextExtent( GetRowLabelValue(colOrRow), &w, &h );
extentLabel = dc.GetMultiLineTextExtent(GetRowLabelValue(colOrRow)).y;
// As above, add some margins for readability, although a smaller one
// in vertical direction.
extentLabel += margin;
}
extent = column ? w : h;
if ( extent > extentMax )
extentMax = extent;
// Finally determine the suitable extent fitting both the cells contents
// and the label.
if ( !extentMax )
{
// empty column - give default extent (notice that if extentMax is less
// than default extent but != 0, it's OK)
extentMax = column ? m_defaultColWidth : m_defaultRowHeight;
// Special case: all the cells are empty, use the label extent.
extentMax = extentLabel;
if ( !extentMax )
{
// But if the label is empty too, use the default width/height.
extentMax = column ? m_defaultColWidth : m_defaultRowHeight;
}
}
else if ( addMargin )
else // We have some data in the column cells.
{
// leave some space around text
if ( column )
extentMax += 10;
else
extentMax += 6;
// Ensure we have the same margin around the cells text as we use
// around the label.
extentMax += margin;
// And increase it to fit the label if necessary.
if ( extentLabel > extentMax )
extentMax = extentLabel;
}
if ( column )
{
// Ensure automatic width is not less than minimal width. See the
@@ -9659,6 +9674,11 @@ void wxGrid::Fit()
AutoSize();
}
void wxGrid::SetFocus()
{
m_gridWin->SetFocus();
}
#if WXWIN_COMPATIBILITY_2_8
wxPen& wxGrid::GetDividerPen() const
{

View File

@@ -28,6 +28,8 @@
#include "wx/unix/utilsx11.h"
#ifdef __WXGTK3__
#include "wx/utils.h"
#include "wx/gtk/private/wrapgtk.h"
GtkWidget* wxGetTopLevelGTK();
#endif
@@ -108,7 +110,12 @@ bool wxUIActionSimulatorX11Impl::SendButtonEvent(int button, bool isDown)
// all pending events, notably mouse moves.
XSync(m_display, False /* don't discard */);
return DoX11Button(xbutton, isDown);
if ( !DoX11Button(xbutton, isDown) )
return false;
XFlush(m_display);
return true;
}
#if wxUSE_PLAINX_IMPL
@@ -243,7 +250,7 @@ private:
bool wxUIActionSimulatorXTestImpl::DoX11Button(int xbutton, bool isDown)
{
return XTestFakeButtonEvent(m_display, xbutton, isDown, 0) != 0;
return XTestFakeButtonEvent(m_display, xbutton, isDown, CurrentTime) != 0;
}
bool wxUIActionSimulatorXTestImpl::DoX11MouseMove(long x, long y)
@@ -266,7 +273,7 @@ bool wxUIActionSimulatorXTestImpl::DoX11MouseMove(long x, long y)
#endif // GTK+ 3.10+
#endif // __WXGTK3__
return XTestFakeMotionEvent(m_display, -1, x, y, 0) != 0;
return XTestFakeMotionEvent(m_display, -1, x, y, CurrentTime) != 0;
}
bool
@@ -274,7 +281,7 @@ wxUIActionSimulatorXTestImpl::DoX11Key(KeyCode xkeycode,
int WXUNUSED(modifiers),
bool isDown)
{
return XTestFakeKeyEvent(m_display, xkeycode, isDown, 0) != 0;
return XTestFakeKeyEvent(m_display, xkeycode, isDown, CurrentTime) != 0;
}
#endif // wxUSE_XTEST
@@ -328,6 +335,13 @@ bool wxUIActionSimulatorX11Impl::MouseMove(long x, long y)
bool wxUIActionSimulatorX11Impl::MouseUp(int button)
{
#ifdef __WXGTK3__
// This is a horrible hack, but some mouse click events are just lost
// without any apparent reason when using GTK 3 without this, i.e. they
// simply never reach GTK in some runs of the tests.
wxMilliSleep(10);
#endif
return SendButtonEvent(button, false);
}
@@ -341,7 +355,12 @@ bool wxUIActionSimulatorX11Impl::DoKey(int keycode, int modifiers, bool isDown)
if ( xkeycode == NoSymbol )
return false;
return DoX11Key(xkeycode, modifiers, isDown);
if ( !DoX11Key(xkeycode, modifiers, isDown) )
return false;
XFlush(m_display);
return true;
}
wxUIActionSimulator::wxUIActionSimulator()

View File

@@ -16,26 +16,20 @@
#ifndef WX_PRECOMP
#include "wx/app.h"
#include "wx/dcclient.h"
#endif // WX_PRECOMP
#include "wx/grid.h"
#include "wx/headerctrl.h"
#include "testableframe.h"
#include "asserthelper.h"
#include "wx/uiaction.h"
// FIXME: A lot of mouse-related tests sporadically fail in wxGTK. This happens
// almost all the time but sometimes the tests do pass and the failure
// doesn't happen when debugging so this looks like some kind of event
// dispatching/simulating problem rather than a real problem in wxGrid.
//
// Just disable these tests for now but it would be really great to
// really fix the problem.
#ifdef __WXGTK__
#define NONGTK_TEST(test)
#else
#define NONGTK_TEST(test) WXUISIM_TEST(test)
#endif
#include "wx/stopwatch.h"
#endif // __WXGTK__
#include "waitforpaint.h"
class GridTestCase : public CppUnit::TestCase
{
@@ -48,13 +42,13 @@ public:
private:
CPPUNIT_TEST_SUITE( GridTestCase );
WXUISIM_TEST( CellEdit );
NONGTK_TEST( CellClick );
NONGTK_TEST( ReorderedColumnsCellClick );
NONGTK_TEST( CellSelect );
NONGTK_TEST( LabelClick );
NONGTK_TEST( SortClick );
WXUISIM_TEST( CellClick );
WXUISIM_TEST( ReorderedColumnsCellClick );
WXUISIM_TEST( CellSelect );
WXUISIM_TEST( LabelClick );
WXUISIM_TEST( SortClick );
WXUISIM_TEST( Size );
NONGTK_TEST( RangeSelect );
WXUISIM_TEST( RangeSelect );
CPPUNIT_TEST( Cursor );
CPPUNIT_TEST( Selection );
CPPUNIT_TEST( AddRowCol );
@@ -70,18 +64,21 @@ private:
WXUISIM_TEST( ReadOnly );
WXUISIM_TEST( ResizeScrolledHeader );
WXUISIM_TEST( ColumnMinWidth );
WXUISIM_TEST( AutoSizeColumn );
CPPUNIT_TEST( PseudoTest_NativeHeader );
NONGTK_TEST( LabelClick );
NONGTK_TEST( SortClick );
WXUISIM_TEST( LabelClick );
WXUISIM_TEST( SortClick );
CPPUNIT_TEST( ColumnOrder );
WXUISIM_TEST( ResizeScrolledHeader );
WXUISIM_TEST( ColumnMinWidth );
WXUISIM_TEST( AutoSizeColumn );
CPPUNIT_TEST( DeleteAndAddRowCol );
CPPUNIT_TEST( PseudoTest_NativeLabels );
NONGTK_TEST( LabelClick );
NONGTK_TEST( SortClick );
WXUISIM_TEST( LabelClick );
WXUISIM_TEST( SortClick );
CPPUNIT_TEST( ColumnOrder );
WXUISIM_TEST( WindowAsEditorControl );
WXUISIM_TEST( AutoSizeColumn );
CPPUNIT_TEST_SUITE_END();
void CellEdit();
@@ -108,10 +105,25 @@ private:
void WindowAsEditorControl();
void ResizeScrolledHeader();
void ColumnMinWidth();
void AutoSizeColumn();
void PseudoTest_NativeHeader() { ms_nativeheader = true; }
void PseudoTest_NativeLabels() { ms_nativeheader = false;
ms_nativelabels = true; }
// The helper function to determine the width of the column label depending
// on whether the native column is used.
int GetColumnLabelWidth(wxClientDC& dc, int col, int margin) const
{
if (ms_nativeheader)
return m_grid->GetGridColHeader()->GetColumnTitleWidth(col);
int w, h;
dc.GetMultiLineTextExtent(m_grid->GetColLabelValue(col), &w, &h);
return w + margin;
}
void CheckFirstColAutoSize(int expected);
static bool ms_nativeheader;
static bool ms_nativelabels;
@@ -142,8 +154,15 @@ void GridTestCase::setUp()
if( ms_nativelabels )
m_grid->SetUseNativeColLabels();
WaitForPaint waitForPaint(m_grid->GetGridWindow());
m_grid->Refresh();
m_grid->Update();
if ( !waitForPaint.YieldUntilPainted() )
{
WARN("Grid not repainted until timeout expiration");
}
}
void GridTestCase::tearDown()
@@ -176,16 +195,48 @@ void GridTestCase::CellEdit()
m_grid->SetFocus();
m_grid->SetGridCursor(1, 1);
m_grid->ShowCellEditControl();
wxYield();
sim.Text("abab");
// We need to wait until the editor is really shown under GTK, consider
// that it happens once it gets focus.
#ifdef __WXGTK__
for ( wxStopWatch sw; wxWindow::FindFocus() == m_grid; )
{
if ( sw.Time() > 250 )
{
WARN("Editor control not shown until timeout expiration");
break;
}
wxYield();
}
#endif // __WXGTK__
sim.Char(WXK_RETURN);
wxYield();
CPPUNIT_ASSERT_EQUAL(1, created.GetCount());
CPPUNIT_ASSERT_EQUAL(1, changing.GetCount());
CPPUNIT_ASSERT_EQUAL(1, changed.GetCount());
#ifdef __WXGTK__
for ( wxStopWatch sw; wxWindow::FindFocus() != m_grid; )
{
if ( sw.Time() > 250 )
{
WARN("Editor control not hidden until timeout expiration");
break;
}
wxYield();
}
#endif // __WXGTK__
CHECK(m_grid->GetCellValue(1, 1) == "abab");
CHECK(created.GetCount() == 1);
CHECK(changing.GetCount() == 1);
CHECK(changed.GetCount() == 1);
#endif
}
@@ -770,7 +821,6 @@ void GridTestCase::Editable()
m_grid->SetFocus();
m_grid->SetGridCursor(1, 1);
m_grid->ShowCellEditControl();
sim.Text("abab");
wxYield();
@@ -797,12 +847,20 @@ void GridTestCase::ReadOnly()
CPPUNIT_ASSERT(m_grid->IsReadOnly(1, 1));
m_grid->SetFocus();
#ifdef __WXGTK__
// This is a mystery, but we somehow get WXK_RETURN generated by the
// previous test (Editable) in this one. In spite of wxYield() in that
// test, the key doesn't get dispatched there and we have to consume it
// here before setting the current grid cell, as getting WXK_RETURN later
// would move the selection down, to a non read-only cell.
wxYield();
#endif // __WXGTK__
m_grid->SetGridCursor(1, 1);
CPPUNIT_ASSERT(m_grid->IsCurrentCellReadOnly());
m_grid->ShowCellEditControl();
sim.Text("abab");
wxYield();
@@ -950,4 +1008,94 @@ void GridTestCase::ColumnMinWidth()
#endif
}
void GridTestCase::CheckFirstColAutoSize(int expected)
{
m_grid->AutoSizeColumn(0);
wxYield();
CHECK(m_grid->GetColSize(0) == expected);
}
void GridTestCase::AutoSizeColumn()
{
// Hardcoded extra margin for the columns used in grid.cpp.
const int margin = m_grid->FromDIP(10);
wxGridCellAttr *attr = m_grid->GetOrCreateCellAttr(0, 0);
wxGridCellRenderer *renderer = attr->GetRenderer(m_grid, 0, 0);
REQUIRE(renderer != NULL);
wxClientDC dcCell(m_grid->GetGridWindow());
wxClientDC dcLabel(m_grid->GetGridWindow());
dcLabel.SetFont(m_grid->GetLabelFont());
const wxString shortStr = "W";
const wxString mediumStr = "WWWW";
const wxString longStr = "WWWWWWWW";
const wxString multilineStr = mediumStr + "\n" + longStr;
SECTION("Empty column and label")
{
m_grid->SetColLabelValue(0, wxString());
CheckFirstColAutoSize( m_grid->GetDefaultColSize() );
}
SECTION("Empty column with label")
{
m_grid->SetColLabelValue(0, mediumStr);
CheckFirstColAutoSize( GetColumnLabelWidth(dcLabel, 0, margin) );
}
SECTION("Column with empty label")
{
m_grid->SetColLabelValue(0, wxString());
m_grid->SetCellValue(0, 0, mediumStr);
m_grid->SetCellValue(1, 0, shortStr);
m_grid->SetCellValue(3, 0, longStr);
CheckFirstColAutoSize(
renderer->GetBestWidth(*m_grid, *attr, dcCell, 3, 0,
m_grid->GetRowHeight(3)) + margin );
}
SECTION("Column with label longer than contents")
{
m_grid->SetColLabelValue(0, multilineStr);
m_grid->SetCellValue(0, 0, mediumStr);
m_grid->SetCellValue(1, 0, shortStr);
CheckFirstColAutoSize( GetColumnLabelWidth(dcLabel, 0, margin) );
}
SECTION("Column with contents longer than label")
{
m_grid->SetColLabelValue(0, mediumStr);
m_grid->SetCellValue(0, 0, mediumStr);
m_grid->SetCellValue(1, 0, shortStr);
m_grid->SetCellValue(3, 0, multilineStr);
CheckFirstColAutoSize(
renderer->GetBestWidth(*m_grid, *attr, dcCell, 3, 0,
m_grid->GetRowHeight(3)) + margin );
}
SECTION("Column with equally sized contents and label")
{
m_grid->SetColLabelValue(0, mediumStr);
m_grid->SetCellValue(0, 0, mediumStr);
m_grid->SetCellValue(1, 0, mediumStr);
m_grid->SetCellValue(3, 0, mediumStr);
const int labelWidth = GetColumnLabelWidth(dcLabel, 0, margin);
const int cellWidth =
renderer->GetBestWidth(*m_grid, *attr, dcCell, 3, 0,
m_grid->GetRowHeight(3))
+ margin;
// We can't be sure which size will be greater because of different fonts
// so just calculate the maximum width.
CheckFirstColAutoSize( wxMax(labelWidth, cellWidth) );
}
}
#endif //wxUSE_GRID

View File

@@ -577,11 +577,11 @@ bool TestApp::ProcessEvent(wxEvent& event)
int TestApp::RunTests()
{
#if wxUSE_LOG
// Switch off logging unless --verbose
bool verbose = wxLog::GetVerbose();
wxLog::EnableLogging(verbose);
#else
bool verbose = false;
// Switch off logging to avoid interfering with the tests output unless
// WXTRACE is set, as otherwise setting it would have no effect while
// running the tests.
if ( !wxGetEnv("WXTRACE", NULL) )
wxLog::EnableLogging(false);
#endif
// Cast is needed under MSW where Catch also provides an overload taking

96
tests/waitforpaint.h Normal file
View File

@@ -0,0 +1,96 @@
///////////////////////////////////////////////////////////////////////////////
// Name: tests/waitforpaint.h
// Purpose: Helper WaitForPaint class
// Author: Vadim Zeitlin
// Created: 2019-10-17 (extracted from tests/window/setsize.cpp)
// Copyright: (c) 2019 Vadim Zeitlin <vadim@wxwidgets.org>
///////////////////////////////////////////////////////////////////////////////
#ifndef _WX_TESTS_WAITFORPAINT_H_
#define _WX_TESTS_WAITFORPAINT_H_
#include "wx/stopwatch.h"
#include "wx/window.h"
// Class used to check if we received the (first) paint event: this is
// currently used under GTK only, as MSW doesn't seem to need to wait for the
// things to work, while under Mac nothing works anyhow.
#ifdef __WXGTK__
class WaitForPaint
{
public:
explicit WaitForPaint(wxWindow* win)
: m_win(*win),
m_painted(false),
m_handler(&m_painted)
{
m_win.Bind(wxEVT_PAINT, m_handler);
}
// This function waits up to the given number of milliseconds for the paint
// event to come and returns true if we did get it or false otherwise.
bool YieldUntilPainted(int timeoutInMS = 250) const
{
wxStopWatch sw;
for ( ;; )
{
wxYield();
if ( m_painted )
return true;
if ( sw.Time() > timeoutInMS )
return false;
}
}
~WaitForPaint()
{
m_win.Unbind(wxEVT_PAINT, m_handler);
}
private:
wxWindow& m_win;
bool m_painted;
class PaintHandler
{
public:
// Note that we have to use a pointer here, i.e. we can't just store
// the flag inside the class itself because it's going to be cloned
// inside wx and querying the flag of the original copy wouldtn' work.
explicit PaintHandler(bool* painted)
: m_painted(*painted)
{
}
void operator()(wxPaintEvent& event)
{
event.Skip();
m_painted = true;
}
private:
bool& m_painted;
} m_handler;
};
#else // !__WXGTK__
class WaitForPaint
{
public:
explicit WaitForPaint(wxWindow* WXUNUSED(win))
{
}
bool YieldUntilPainted(int WXUNUSED(timeoutInMS) = 250) const
{
return true;
}
};
#endif // __WXGTK__/!__WXGTK__
#endif // _WX_TESTS_WAITFORPAINT_H_

View File

@@ -23,9 +23,9 @@
#endif // WX_PRECOMP
#include "wx/scopedptr.h"
#include "wx/stopwatch.h"
#include "asserthelper.h"
#include "waitforpaint.h"
// ----------------------------------------------------------------------------
// tests helpers
@@ -47,57 +47,6 @@ protected:
virtual wxSize DoGetBestSize() const wxOVERRIDE { return wxSize(50, 250); }
};
// Class used to check if we received the (first) paint event.
class WaitForPaint
{
public:
// Note that we have to use a pointer here, i.e. we can't just store the
// flag inside the class itself because it's going to be cloned inside wx
// and querying the flag of the original copy is not going to work.
explicit WaitForPaint(bool* painted)
: m_painted(*painted)
{
m_painted = false;
}
void operator()(wxPaintEvent& event)
{
event.Skip();
m_painted = true;
}
private:
bool& m_painted;
};
// This function should be used to show the window and wait until we can get
// its real geometry.
void ShowAndWaitForPaint(wxWindow* w)
{
// Unfortunately showing the window is asynchronous, at least when using
// X11, so we have to wait for some time before retrieving its true
// geometry. And it's not clear how long should we wait, so we do it until
// we get the first paint event -- by then the window really should have
// its final size.
bool painted;
WaitForPaint waitForPaint(&painted);
w->Bind(wxEVT_PAINT, waitForPaint);
w->Show();
wxStopWatch sw;
while ( !painted )
{
wxYield();
if ( sw.Time() > 250 )
{
WARN("Didn't get a paint event until timeout expiration");
break;
}
}
}
} // anonymous namespace
// ----------------------------------------------------------------------------
@@ -143,7 +92,19 @@ TEST_CASE("wxWindow::MovePreservesSize", "[window][size][move]")
wxScopedPtr<wxWindow>
w(new wxFrame(wxTheApp->GetTopWindow(), wxID_ANY, "Test child frame"));
ShowAndWaitForPaint(w.get());
// Unfortunately showing the window is asynchronous, at least when using
// X11, so we have to wait for some time before retrieving its true
// geometry. And it's not clear how long should we wait, so we do it until
// we get the first paint event -- by then the window really should have
// its final size.
WaitForPaint waitForPaint(w.get());
w->Show();
if ( !waitForPaint.YieldUntilPainted() )
{
WARN("Didn't get a paint event until timeout expiration");
}
const wxRect rectOrig = w->GetRect();