Factor out wxMaxWidthCalculatorBase from wxDataViewCtrl code.
This will allow reusing it elsewhere, notably in the generic wxListCtrl.
See #10326.
(this is a backport of fa1c3ecfa6
from master)
This commit is contained in:
122
include/wx/generic/private/widthcalc.h
Normal file
122
include/wx/generic/private/widthcalc.h
Normal file
@@ -0,0 +1,122 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Name: wx/generic/private/widthcalc.h
|
||||
// Purpose: wxMaxWidthCalculatorBase helper class.
|
||||
// Author: Václav Slavík, Kinaou Hervé
|
||||
// Copyright: (c) 2015 wxWidgets team
|
||||
// Licence: wxWindows licence
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _WX_GENERIC_PRIVATE_WIDTHCALC_H_
|
||||
#define _WX_GENERIC_PRIVATE_WIDTHCALC_H_
|
||||
|
||||
#include "wx/defs.h"
|
||||
|
||||
#if wxUSE_DATAVIEWCTRL
|
||||
|
||||
#include "wx/timer.h"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxMaxWidthCalculatorBase: base class for calculating max column width
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class wxMaxWidthCalculatorBase
|
||||
{
|
||||
public:
|
||||
// column of which calculate the width
|
||||
explicit wxMaxWidthCalculatorBase(size_t column)
|
||||
: m_column(column),
|
||||
m_width(0)
|
||||
{
|
||||
}
|
||||
|
||||
void UpdateWithWidth(int width)
|
||||
{
|
||||
m_width = wxMax(m_width, width);
|
||||
}
|
||||
|
||||
// Update the max with for the expected row
|
||||
virtual void UpdateWithRow(int row) = 0;
|
||||
|
||||
int GetMaxWidth() const { return m_width; }
|
||||
size_t GetColumn() const { return m_column; }
|
||||
|
||||
void
|
||||
ComputeBestColumnWidth(size_t count,
|
||||
size_t first_visible,
|
||||
size_t last_visible)
|
||||
{
|
||||
// The code below deserves some explanation. For very large controls, we
|
||||
// simply can't afford to calculate sizes for all items, it takes too
|
||||
// long. So the best we can do is to check the first and the last N/2
|
||||
// items in the control for some sufficiently large N and calculate best
|
||||
// sizes from that. That can result in the calculated best width being too
|
||||
// small for some outliers, but it's better to get slightly imperfect
|
||||
// result than to wait several seconds after every update. To avoid highly
|
||||
// visible miscalculations, we also include all currently visible items
|
||||
// no matter what. Finally, the value of N is determined dynamically by
|
||||
// measuring how much time we spent on the determining item widths so far.
|
||||
|
||||
#if wxUSE_STOPWATCH
|
||||
size_t top_part_end = count;
|
||||
static const long CALC_TIMEOUT = 20/*ms*/;
|
||||
// don't call wxStopWatch::Time() too often
|
||||
static const unsigned CALC_CHECK_FREQ = 100;
|
||||
wxStopWatch timer;
|
||||
#else
|
||||
// use some hard-coded limit, that's the best we can do without timer
|
||||
size_t top_part_end = wxMin(500, count);
|
||||
#endif // wxUSE_STOPWATCH/!wxUSE_STOPWATCH
|
||||
|
||||
size_t row = 0;
|
||||
|
||||
for ( row = 0; row < top_part_end; row++ )
|
||||
{
|
||||
#if wxUSE_STOPWATCH
|
||||
if ( row % CALC_CHECK_FREQ == CALC_CHECK_FREQ-1 &&
|
||||
timer.Time() > CALC_TIMEOUT )
|
||||
break;
|
||||
#endif // wxUSE_STOPWATCH
|
||||
UpdateWithRow(row);
|
||||
}
|
||||
|
||||
// row is the first unmeasured item now; that's our value of N/2
|
||||
if ( row < count )
|
||||
{
|
||||
top_part_end = row;
|
||||
|
||||
// add bottom N/2 items now:
|
||||
const size_t bottom_part_start = wxMax(row, count - row);
|
||||
for ( row = bottom_part_start; row < count; row++ )
|
||||
{
|
||||
UpdateWithRow(row);
|
||||
}
|
||||
|
||||
// finally, include currently visible items in the calculation:
|
||||
first_visible = wxMax(first_visible, top_part_end);
|
||||
last_visible = wxMin(bottom_part_start, last_visible);
|
||||
|
||||
for ( row = first_visible; row < last_visible; row++ )
|
||||
{
|
||||
UpdateWithRow(row);
|
||||
}
|
||||
|
||||
wxLogTrace("items container",
|
||||
"determined best size from %d top, %d bottom "
|
||||
"plus %d more visible items out of %d total",
|
||||
top_part_end,
|
||||
count - bottom_part_start,
|
||||
wxMax(0, last_visible - first_visible),
|
||||
count);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const size_t m_column;
|
||||
int m_width;
|
||||
|
||||
wxDECLARE_NO_COPY_CLASS(wxMaxWidthCalculatorBase);
|
||||
};
|
||||
|
||||
#endif // wxUSE_DATAVIEWCTRL
|
||||
|
||||
#endif // _WX_GENERIC_PRIVATE_WIDTHCALC_H_
|
Reference in New Issue
Block a user