124 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			124 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/////////////////////////////////////////////////////////////////////////////
 | 
						|
// 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 || wxUSE_LISTCTRL
 | 
						|
 | 
						|
#include "wx/log.h"
 | 
						|
#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 %zu top, %zu bottom "
 | 
						|
                       "plus %zu more visible items out of %zu total",
 | 
						|
                       top_part_end,
 | 
						|
                       count - bottom_part_start,
 | 
						|
                       last_visible - first_visible,
 | 
						|
                       count);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
private:
 | 
						|
    const size_t m_column;
 | 
						|
    int m_width;
 | 
						|
 | 
						|
    wxDECLARE_NO_COPY_CLASS(wxMaxWidthCalculatorBase);
 | 
						|
};
 | 
						|
 | 
						|
#endif // wxUSE_DATAVIEWCTRL || wxUSE_LISTCTRL
 | 
						|
 | 
						|
#endif // _WX_GENERIC_PRIVATE_WIDTHCALC_H_
 |