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_
 |