2016-07-10 01:29:09 +03:00
/************************************************************************
2016-09-15 22:30:32 +03:00
* file name : easy_graphics_scrollbar . cpp
2016-07-10 01:29:09 +03:00
* - - - - - - - - - - - - - - - - - :
* creation time : 2016 / 07 / 04
* author : Victor Zarubkin
* email : v . s . zarubkin @ gmail . com
* - - - - - - - - - - - - - - - - - :
* description : .
* - - - - - - - - - - - - - - - - - :
* change log : * 2016 / 07 / 04 Victor Zarubkin : Initial commit .
* :
* : *
* - - - - - - - - - - - - - - - - - :
2016-09-06 21:49:32 +03:00
* license : Lightweight profiler library for c + +
2017-03-30 06:55:15 +03:00
* : Copyright ( C ) 2016 - 2017 Sergey Yagovtsev , Victor Zarubkin
2016-09-06 21:49:32 +03:00
* :
2017-03-30 06:55:15 +03:00
* : Licensed under either of
* : * MIT license ( LICENSE . MIT or http : //opensource.org/licenses/MIT)
* : * Apache License , Version 2.0 , ( LICENSE . APACHE or http : //www.apache.org/licenses/LICENSE-2.0)
* : at your option .
2016-11-13 16:39:59 +03:00
* :
2017-03-30 06:55:15 +03:00
* : The MIT License
* :
* : Permission is hereby granted , free of charge , to any person obtaining a copy
* : of this software and associated documentation files ( the " Software " ) , to deal
* : in the Software without restriction , including without limitation the rights
* : to use , copy , modify , merge , publish , distribute , sublicense , and / or sell copies
* : of the Software , and to permit persons to whom the Software is furnished
* : to do so , subject to the following conditions :
* :
* : The above copyright notice and this permission notice shall be included in all
* : copies or substantial portions of the Software .
* :
* : THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR IMPLIED ,
* : INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY , FITNESS FOR A PARTICULAR
* : PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* : LIABLE FOR ANY CLAIM , DAMAGES OR OTHER LIABILITY , WHETHER IN AN ACTION OF CONTRACT ,
* : TORT OR OTHERWISE , ARISING FROM , OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* : USE OR OTHER DEALINGS IN THE SOFTWARE .
* :
* : The Apache License , Version 2.0 ( the " License " )
* :
* : You may not use this file except in compliance with the License .
2016-11-13 16:39:59 +03:00
* : You may obtain a copy of the License at
* :
* : http : //www.apache.org/licenses/LICENSE-2.0
* :
* : Unless required by applicable law or agreed to in writing , software
* : distributed under the License is distributed on an " AS IS " BASIS ,
* : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* : See the License for the specific language governing permissions and
* : limitations under the License .
2016-07-10 01:29:09 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2016-07-31 13:13:48 +03:00
# include <algorithm>
2016-08-18 23:26:41 +03:00
# include <QGraphicsScene>
2016-07-31 13:13:48 +03:00
# include <QWheelEvent>
# include <QMouseEvent>
# include <QResizeEvent>
2016-08-03 23:00:04 +03:00
# include <QContextMenuEvent>
# include <QMenu>
2016-09-15 22:30:32 +03:00
# include "easy_graphics_scrollbar.h"
2016-08-08 22:45:57 +03:00
# include "globals.h"
2016-07-10 01:29:09 +03:00
2016-12-04 16:51:27 +03:00
// TODO: use profiler_core/spin_lock.h
# if defined(_WIN32) && defined(EASY_GUI_USE_CRITICAL_SECTION)
# include <Windows.h>
# ifdef min
# undef min
# endif
# ifdef max
# undef max
# endif
namespace profiler_gui {
void spin_lock : : lock ( ) {
EnterCriticalSection ( ( CRITICAL_SECTION * ) m_lock ) ;
}
void spin_lock : : unlock ( ) {
LeaveCriticalSection ( ( CRITICAL_SECTION * ) m_lock ) ;
}
spin_lock : : spin_lock ( ) : m_lock ( new CRITICAL_SECTION ) {
InitializeCriticalSection ( ( CRITICAL_SECTION * ) m_lock ) ;
}
spin_lock : : ~ spin_lock ( ) {
DeleteCriticalSection ( ( CRITICAL_SECTION * ) m_lock ) ;
delete ( ( CRITICAL_SECTION * ) m_lock ) ;
}
}
# endif
2016-07-10 01:29:09 +03:00
//////////////////////////////////////////////////////////////////////////
2016-08-03 00:06:36 +03:00
const int DEFAULT_TOP = - 40 ;
const int DEFAULT_HEIGHT = 80 ;
2016-12-01 21:55:11 +03:00
const int INDICATOR_SIZE = 6 ;
const int INDICATOR_SIZE_x2 = INDICATOR_SIZE < < 1 ;
2017-03-07 01:09:27 +03:00
const int HIST_COLUMN_MIN_HEIGHT = 2 ;
2017-03-13 00:43:15 +03:00
const int WORKER_THREAD_CHECK_INTERVAL = 40 ;
const int BOUNDARY_TIMER_INTERVAL = 100 ;
2016-07-31 13:13:48 +03:00
//////////////////////////////////////////////////////////////////////////
2016-11-13 22:16:50 +03:00
inline qreal clamp ( qreal _minValue , qreal _value , qreal _maxValue )
2016-07-10 01:29:09 +03:00
{
return ( _value < _minValue ? _minValue : ( _value > _maxValue ? _maxValue : _value ) ) ;
2016-11-13 22:16:50 +03:00
}
inline qreal sqr ( qreal _value )
{
return _value * _value ;
}
2016-07-10 01:29:09 +03:00
2016-12-07 22:29:16 +03:00
inline qreal calculate_color1 ( qreal h , qreal , qreal k )
2016-11-16 22:17:39 +03:00
{
return : : std : : min ( h * k , 0.9999999 ) ;
}
2016-12-07 22:29:16 +03:00
inline qreal calculate_color2 ( qreal , qreal duration , qreal k )
2016-11-16 22:17:39 +03:00
{
2016-12-07 22:29:16 +03:00
return : : std : : min ( sqr ( sqr ( duration ) ) * k , 0.9999999 ) ;
2016-11-16 22:17:39 +03:00
}
2016-07-10 01:29:09 +03:00
//////////////////////////////////////////////////////////////////////////
2016-08-23 22:44:59 +03:00
EasyGraphicsSliderItem : : EasyGraphicsSliderItem ( bool _main ) : Parent ( ) , m_halfwidth ( 0 ) , m_bMain ( _main )
2016-07-10 01:29:09 +03:00
{
2016-08-23 22:44:59 +03:00
m_indicator . reserve ( 3 ) ;
if ( _main )
{
m_indicator . push_back ( QPointF ( 0 , DEFAULT_TOP + INDICATOR_SIZE ) ) ;
m_indicator . push_back ( QPointF ( - INDICATOR_SIZE , DEFAULT_TOP ) ) ;
m_indicator . push_back ( QPointF ( INDICATOR_SIZE , DEFAULT_TOP ) ) ;
}
else
{
m_indicator . push_back ( QPointF ( 0 , DEFAULT_TOP + DEFAULT_HEIGHT - INDICATOR_SIZE ) ) ;
m_indicator . push_back ( QPointF ( - INDICATOR_SIZE , DEFAULT_TOP + DEFAULT_HEIGHT ) ) ;
m_indicator . push_back ( QPointF ( INDICATOR_SIZE , DEFAULT_TOP + DEFAULT_HEIGHT ) ) ;
}
2016-08-08 23:39:37 +03:00
2016-08-03 00:06:36 +03:00
setWidth ( 1 ) ;
2016-07-10 01:29:09 +03:00
setBrush ( Qt : : SolidPattern ) ;
}
2016-08-18 23:26:41 +03:00
EasyGraphicsSliderItem : : ~ EasyGraphicsSliderItem ( )
2016-07-10 01:29:09 +03:00
{
}
2016-08-18 23:26:41 +03:00
void EasyGraphicsSliderItem : : paint ( QPainter * _painter , const QStyleOptionGraphicsItem * _option , QWidget * _widget )
2016-07-31 13:13:48 +03:00
{
2016-11-30 22:37:11 +03:00
if ( static_cast < const EasyGraphicsScrollbar * > ( scene ( ) - > parent ( ) ) - > bindMode ( ) )
{
return ;
}
2016-08-18 23:26:41 +03:00
const auto currentScale = static_cast < const EasyGraphicsScrollbar * > ( scene ( ) - > parent ( ) ) - > getWindowScale ( ) ;
2016-07-31 13:13:48 +03:00
const auto br = rect ( ) ;
qreal w = width ( ) * currentScale ;
2016-12-01 22:20:34 +03:00
QRectF r ( br . left ( ) * currentScale , br . top ( ) + INDICATOR_SIZE , w , br . height ( ) - INDICATOR_SIZE_x2 ) ;
2016-08-18 23:26:41 +03:00
const auto r_right = r . right ( ) ;
const auto r_bottom = r . bottom ( ) ;
auto b = brush ( ) ;
2016-08-06 14:50:31 +03:00
2016-07-31 13:13:48 +03:00
_painter - > save ( ) ;
_painter - > setTransform ( QTransform : : fromScale ( 1.0 / currentScale , 1 ) , true ) ;
2016-08-18 23:26:41 +03:00
_painter - > setBrush ( b ) ;
2016-08-23 22:44:59 +03:00
if ( w > 1 )
{
_painter - > setPen ( Qt : : NoPen ) ;
_painter - > drawRect ( r ) ;
// Draw left and right borders
auto cmode = _painter - > compositionMode ( ) ;
if ( m_bMain ) _painter - > setCompositionMode ( QPainter : : CompositionMode_Exclusion ) ;
_painter - > setPen ( QColor : : fromRgba ( 0xe0000000 | b . color ( ) . rgb ( ) ) ) ;
_painter - > drawLine ( QPointF ( r . left ( ) , r . top ( ) ) , QPointF ( r . left ( ) , r_bottom ) ) ;
_painter - > drawLine ( QPointF ( r_right , r . top ( ) ) , QPointF ( r_right , r_bottom ) ) ;
if ( ! m_bMain ) _painter - > setCompositionMode ( cmode ) ;
}
else
{
_painter - > setPen ( QColor : : fromRgba ( 0xe0000000 | b . color ( ) . rgb ( ) ) ) ;
_painter - > drawLine ( QPointF ( r . left ( ) , r . top ( ) ) , QPointF ( r . left ( ) , r_bottom ) ) ;
if ( m_bMain ) _painter - > setCompositionMode ( QPainter : : CompositionMode_Exclusion ) ;
}
2016-08-18 23:26:41 +03:00
2016-08-23 22:44:59 +03:00
// Draw triangle indicators for small slider
_painter - > setTransform ( QTransform : : fromTranslate ( r . left ( ) + w * 0.5 , 0 ) , true ) ;
_painter - > setPen ( b . color ( ) . rgb ( ) ) ;
_painter - > drawPolygon ( m_indicator ) ;
2016-08-08 23:39:37 +03:00
2016-07-31 13:13:48 +03:00
_painter - > restore ( ) ;
}
2016-08-18 23:26:41 +03:00
qreal EasyGraphicsSliderItem : : width ( ) const
2016-07-10 01:29:09 +03:00
{
return m_halfwidth * 2.0 ;
}
2016-08-18 23:26:41 +03:00
qreal EasyGraphicsSliderItem : : halfwidth ( ) const
2016-07-10 01:29:09 +03:00
{
return m_halfwidth ;
}
2016-08-18 23:26:41 +03:00
void EasyGraphicsSliderItem : : setWidth ( qreal _width )
2016-07-10 01:29:09 +03:00
{
m_halfwidth = _width * 0.5 ;
2016-08-03 00:06:36 +03:00
setRect ( - m_halfwidth , DEFAULT_TOP , _width , DEFAULT_HEIGHT ) ;
2016-07-10 01:29:09 +03:00
}
2016-08-18 23:26:41 +03:00
void EasyGraphicsSliderItem : : setHalfwidth ( qreal _halfwidth )
2016-07-10 01:29:09 +03:00
{
m_halfwidth = _halfwidth ;
2016-08-03 00:06:36 +03:00
setRect ( - m_halfwidth , DEFAULT_TOP , m_halfwidth * 2.0 , DEFAULT_HEIGHT ) ;
2016-07-10 01:29:09 +03:00
}
2016-08-18 23:26:41 +03:00
void EasyGraphicsSliderItem : : setColor ( QRgb _color )
2016-08-06 14:50:31 +03:00
{
setColor ( QColor : : fromRgba ( _color ) ) ;
}
2016-08-18 23:26:41 +03:00
void EasyGraphicsSliderItem : : setColor ( const QColor & _color )
2016-07-10 01:29:09 +03:00
{
auto b = brush ( ) ;
2016-08-06 14:50:31 +03:00
b . setColor ( _color ) ;
2016-07-10 01:29:09 +03:00
setBrush ( b ) ;
}
//////////////////////////////////////////////////////////////////////////
2017-03-07 00:29:34 +03:00
EasyHistogramItem : : EasyHistogramItem ( ) : Parent ( nullptr )
2016-12-04 16:51:27 +03:00
, m_threadDuration ( 0 )
2016-12-14 22:16:14 +03:00
, m_threadProfiledTime ( 0 )
, m_threadWaitTime ( 0 )
2016-12-04 16:51:27 +03:00
, m_pSource ( nullptr )
2017-03-13 20:30:57 +03:00
, m_workerImage ( nullptr )
2017-03-07 00:29:34 +03:00
, m_topDuration ( 0 )
2016-12-04 16:51:27 +03:00
, m_maxDuration ( 0 )
, m_minDuration ( 0 )
2017-03-07 19:59:57 +03:00
, m_imageOrigin ( 0 )
2017-03-13 00:43:15 +03:00
, m_imageScale ( 1 )
2017-03-13 20:30:57 +03:00
, m_workerImageOrigin ( 0 )
, m_workerImageScale ( 1 )
, m_workerTopDuration ( 0 )
, m_workerBottomDuration ( 0 )
2017-06-05 21:26:10 +03:00
, m_blockTotalDuraion ( 0 )
2016-12-04 16:51:27 +03:00
, m_timer ( : : std : : bind ( & This : : onTimeout , this ) )
2017-03-13 00:43:15 +03:00
, m_boundaryTimer ( [ this ] ( ) { updateImage ( ) ; } , true )
2016-12-12 22:28:54 +03:00
, m_pProfilerThread ( nullptr )
2016-12-04 16:51:27 +03:00
, m_threadId ( 0 )
, m_blockId ( : : profiler_gui : : numeric_max < decltype ( m_blockId ) > ( ) )
, m_timeouts ( 0 )
, m_timeUnits ( : : profiler_gui : : TimeUnits_auto )
2017-03-07 19:59:57 +03:00
, m_regime ( Hist_Pointer )
2017-03-07 00:29:34 +03:00
, m_bPermitImageUpdate ( false )
2016-08-03 00:06:36 +03:00
{
2016-12-04 16:51:27 +03:00
m_bReady = ATOMIC_VAR_INIT ( false ) ;
2016-08-03 00:06:36 +03:00
}
2017-03-07 00:29:34 +03:00
EasyHistogramItem : : ~ EasyHistogramItem ( )
2016-08-03 00:06:36 +03:00
{
2016-12-04 16:51:27 +03:00
m_bReady . store ( true , : : std : : memory_order_release ) ;
if ( m_workerThread . joinable ( ) )
m_workerThread . join ( ) ;
2017-03-13 20:30:57 +03:00
delete m_workerImage ;
2016-08-03 00:06:36 +03:00
}
2017-03-07 00:29:34 +03:00
QRectF EasyHistogramItem : : boundingRect ( ) const
2016-08-03 00:06:36 +03:00
{
return m_boundingRect ;
}
2017-03-07 00:29:34 +03:00
void EasyHistogramItem : : paint ( QPainter * _painter , const QStyleOptionGraphicsItem * _option , QWidget * _widget )
2016-08-03 00:06:36 +03:00
{
2017-03-13 00:43:15 +03:00
if ( ! m_bPermitImageUpdate | | ( m_regime = = Hist_Pointer & & m_pSource = = nullptr ) | | ( m_regime = = Hist_Id & & ( m_threadId = = 0 | | : : profiler_gui : : is_max ( m_blockId ) ) ) )
2016-12-04 16:51:27 +03:00
return ;
2017-03-07 19:59:57 +03:00
if ( m_regime = = Hist_Pointer )
2017-03-07 00:29:34 +03:00
paintByPtr ( _painter ) ;
else
paintById ( _painter ) ;
}
2016-12-04 16:51:27 +03:00
2017-03-07 00:29:34 +03:00
void EasyHistogramItem : : paintBusyIndicator ( QPainter * _painter , qreal _current_scale )
{
const auto width = m_boundingRect . width ( ) * _current_scale ;
const auto h = _painter - > fontMetrics ( ) . height ( ) ;
2016-12-04 16:51:27 +03:00
2017-03-07 00:29:34 +03:00
_painter - > setPen ( Qt : : black ) ;
_painter - > drawText ( QRectF ( 0 , m_boundingRect . top ( ) , width , m_boundingRect . height ( ) - h ) ,
Qt : : AlignCenter , " Generating image " ) ;
_painter - > drawText ( QRectF ( 0 , m_boundingRect . top ( ) + h , width , m_boundingRect . height ( ) - h ) ,
Qt : : AlignCenter , QString ( m_timeouts , QChar ( ' . ' ) ) ) ;
}
2016-12-04 16:51:27 +03:00
2017-03-07 00:29:34 +03:00
void EasyHistogramItem : : paintMouseIndicator ( QPainter * _painter , qreal _top , qreal _bottom , qreal _width , qreal _height , qreal _top_width , qreal _mouse_y , qreal _delta_time , int _font_h )
{
if ( _font_h ! = 0 & & _top < _mouse_y & & _mouse_y < _bottom )
{
const int half_font_h = _font_h > > 1 ;
2016-12-04 16:51:27 +03:00
2017-03-07 00:29:34 +03:00
_painter - > setPen ( Qt : : blue ) ;
2016-12-04 16:51:27 +03:00
2017-03-07 00:29:34 +03:00
const auto mouseStr = : : profiler_gui : : timeStringReal ( m_timeUnits , m_bottomDuration + _delta_time * ( _bottom - _mouse_y ) / _height , 3 ) ;
qreal mouseIndicatorRight = _width ;
if ( _mouse_y < _top + half_font_h )
mouseIndicatorRight = _top_width ;
2016-12-04 16:51:27 +03:00
2017-03-07 00:29:34 +03:00
qreal mouseIndicatorLeft = 0 ;
const QRectF rect ( 0 , _mouse_y - _font_h , _width , _font_h < < 1 ) ;
if ( _mouse_y > _bottom - half_font_h )
{
_painter - > drawText ( rect , Qt : : AlignLeft | Qt : : AlignTop , mouseStr ) ;
}
else if ( _mouse_y < _top + half_font_h )
{
_painter - > drawText ( rect , Qt : : AlignLeft | Qt : : AlignBottom , mouseStr ) ;
}
else
{
_painter - > drawText ( rect , Qt : : AlignLeft | Qt : : AlignVCenter , mouseStr ) ;
mouseIndicatorLeft = _painter - > fontMetrics ( ) . width ( mouseStr ) + 3 ;
}
2016-08-03 00:06:36 +03:00
2017-03-07 00:29:34 +03:00
_painter - > drawLine ( QLineF ( mouseIndicatorLeft , _mouse_y , mouseIndicatorRight , _mouse_y ) ) ;
}
2016-12-04 16:51:27 +03:00
}
2017-03-07 00:29:34 +03:00
void EasyHistogramItem : : paintByPtr ( QPainter * _painter )
2016-12-04 16:51:27 +03:00
{
2016-11-30 22:37:11 +03:00
const auto widget = static_cast < const EasyGraphicsScrollbar * > ( scene ( ) - > parent ( ) ) ;
const bool bindMode = widget - > bindMode ( ) ;
const auto currentScale = widget - > getWindowScale ( ) ;
2016-08-03 00:06:36 +03:00
const auto bottom = m_boundingRect . bottom ( ) ;
2016-12-01 21:55:11 +03:00
const auto width = m_boundingRect . width ( ) * currentScale ;
2017-03-07 00:29:34 +03:00
const auto dtime = m_topDuration - m_bottomDuration ;
const auto maxColumnHeight = m_boundingRect . height ( ) ;
2017-03-07 01:09:27 +03:00
const auto coeff = ( m_boundingRect . height ( ) - HIST_COLUMN_MIN_HEIGHT ) / ( dtime > 1e-3 ? dtime : 1. ) ;
2016-08-03 00:06:36 +03:00
QRectF rect ;
QBrush brush ( Qt : : SolidPattern ) ;
2017-04-10 22:04:09 +03:00
//QRgb previousColor = 0;
2016-08-03 00:06:36 +03:00
2016-12-04 16:51:27 +03:00
_painter - > save ( ) ;
_painter - > setTransform ( QTransform : : fromScale ( 1.0 / currentScale , 1 ) , true ) ;
2017-03-13 00:43:15 +03:00
if ( ! m_pSource - > empty ( ) )
2016-12-04 16:51:27 +03:00
{
2017-03-07 00:29:34 +03:00
_painter - > setPen ( Qt : : NoPen ) ;
2016-12-04 16:51:27 +03:00
if ( ! bindMode )
_painter - > drawImage ( 0 , m_boundingRect . top ( ) , m_mainImage ) ;
else
{
const auto range = widget - > sliderWidth ( ) ;
const auto minimum = widget - > value ( ) ;
const auto slider_k = widget - > range ( ) / range ;
2017-03-13 00:43:15 +03:00
/*if (false)//slider_k < 8)
2016-12-04 16:51:27 +03:00
{
_painter - > setTransform ( QTransform : : fromScale ( slider_k , 1 ) , true ) ;
2017-03-13 00:43:15 +03:00
_painter - > drawImage ( ( widget - > minimum ( ) - minimum ) * currentScale , m_boundingRect . top ( ) , m_mainImage ) ;
_painter - > setTransform ( QTransform : : fromScale ( 1. / slider_k , 1 ) , true ) ;
2016-12-04 16:51:27 +03:00
}
2017-03-13 00:43:15 +03:00
else */
{
const auto deltaScale = slider_k / m_imageScale ;
_painter - > setTransform ( QTransform : : fromScale ( deltaScale , 1 ) , true ) ;
_painter - > drawImage ( ( widget - > minimum ( ) + m_imageOrigin - minimum ) * currentScale * m_imageScale , m_boundingRect . top ( ) , m_mainImage ) ;
_painter - > setTransform ( QTransform : : fromScale ( 1. / deltaScale , 1 ) , true ) ;
}
/*if (false)
2016-12-04 16:51:27 +03:00
{
const bool gotFrame = EASY_GLOBALS . frame_time > 1e-6 f ;
qreal frameCoeff = 1 ;
if ( gotFrame )
{
2017-03-07 00:29:34 +03:00
if ( EASY_GLOBALS . frame_time < = m_bottomDuration )
2016-12-04 16:51:27 +03:00
frameCoeff = m_boundingRect . height ( ) ;
else
2016-12-07 22:29:16 +03:00
frameCoeff = 0.9 / EASY_GLOBALS . frame_time ;
2016-12-04 16:51:27 +03:00
}
auto const calculate_color = gotFrame ? calculate_color2 : calculate_color1 ;
2016-12-07 22:29:16 +03:00
auto const k = gotFrame ? sqr ( sqr ( frameCoeff ) ) : 1.0 / m_boundingRect . height ( ) ;
2016-12-04 16:51:27 +03:00
const auto & items = * m_pSource ;
const auto maximum = minimum + range ;
const auto realScale = currentScale * slider_k ;
const auto offset = minimum * realScale ;
auto first = : : std : : lower_bound ( items . begin ( ) , items . end ( ) , minimum , [ ] ( const : : profiler_gui : : EasyBlockItem & _item , qreal _value )
{
return _item . left ( ) < _value ;
} ) ;
if ( first ! = items . end ( ) )
{
if ( first ! = items . begin ( ) )
- - first ;
}
else
{
first = items . begin ( ) + items . size ( ) - 1 ;
}
qreal previous_x = - 1e30 , previous_h = - 1e30 ;
for ( auto it = first , end = items . end ( ) ; it ! = end ; + + it )
{
// Draw rectangle
if ( it - > left ( ) > maximum )
break ;
if ( it - > right ( ) < minimum )
continue ;
const qreal item_x = it - > left ( ) * realScale - offset ;
const qreal item_w = : : std : : max ( it - > width ( ) * realScale , 1.0 ) ;
const qreal item_r = item_x + item_w ;
2017-03-07 01:09:27 +03:00
const qreal h = it - > width ( ) < = m_bottomDuration ? HIST_COLUMN_MIN_HEIGHT :
( it - > width ( ) > m_topDuration ? maxColumnHeight : ( HIST_COLUMN_MIN_HEIGHT + ( it - > width ( ) - m_bottomDuration ) * coeff ) ) ;
2016-12-04 16:51:27 +03:00
if ( h < previous_h & & item_r < previous_x )
continue ;
2016-12-07 22:29:16 +03:00
const auto col = calculate_color ( h , it - > width ( ) , k ) ;
2016-12-04 16:51:27 +03:00
const auto color = 0x00ffffff & QColor : : fromHsvF ( ( 1.0 - col ) * 0.375 , 0.85 , 0.85 ) . rgb ( ) ;
if ( previousColor ! = color )
{
// Set background color brush for rectangle
previousColor = color ;
brush . setColor ( QColor : : fromRgba ( 0xc0000000 | color ) ) ;
_painter - > setBrush ( brush ) ;
}
rect . setRect ( item_x , bottom - h , item_w , h ) ;
_painter - > drawRect ( rect ) ;
previous_x = item_r ;
previous_h = h ;
}
2017-03-13 00:43:15 +03:00
} */
2016-12-04 16:51:27 +03:00
}
}
2017-03-13 00:43:15 +03:00
//if (!m_bReady.load(::std::memory_order_acquire))
// paintBusyIndicator(_painter, currentScale);
2017-03-07 00:29:34 +03:00
2016-12-04 16:51:27 +03:00
qreal top_width = width , bottom_width = width ;
int font_h = 0 ;
2017-03-07 00:29:34 +03:00
if ( ! m_topDurationStr . isEmpty ( ) )
2016-12-04 16:51:27 +03:00
{
rect . setRect ( 0 , m_boundingRect . top ( ) - INDICATOR_SIZE , width - 3 , m_boundingRect . height ( ) + INDICATOR_SIZE_x2 ) ;
if ( m_timeUnits ! = EASY_GLOBALS . time_units )
{
m_timeUnits = EASY_GLOBALS . time_units ;
2017-03-07 00:29:34 +03:00
m_topDurationStr = : : profiler_gui : : timeStringReal ( m_timeUnits , m_topDuration , 3 ) ;
m_bottomDurationStr = : : profiler_gui : : timeStringReal ( m_timeUnits , m_bottomDuration , 3 ) ;
2016-12-04 16:51:27 +03:00
}
auto fm = _painter - > fontMetrics ( ) ;
font_h = fm . height ( ) ;
2017-03-07 00:29:34 +03:00
//bottom_width -= fm.width(m_bottomDurationStr) + 7;
top_width - = fm . width ( m_topDurationStr ) + 7 ;
2016-12-04 16:51:27 +03:00
2017-03-13 00:43:15 +03:00
_painter - > setPen ( m_topDuration < m_maxDuration ? Qt : : darkRed : Qt : : black ) ;
2017-03-07 00:29:34 +03:00
_painter - > drawText ( rect , Qt : : AlignRight | Qt : : AlignTop , m_topDurationStr ) ;
2016-12-04 16:51:27 +03:00
rect . setRect ( 0 , bottom , width - 3 , font_h ) ;
2017-03-13 00:43:15 +03:00
_painter - > setPen ( m_bottomDuration > m_minDuration ? Qt : : darkRed : Qt : : black ) ;
2017-03-07 00:29:34 +03:00
_painter - > drawText ( rect , Qt : : AlignRight | Qt : : AlignTop , m_bottomDurationStr ) ;
2016-12-04 16:51:27 +03:00
}
_painter - > setPen ( Qt : : darkGray ) ;
_painter - > drawLine ( QLineF ( 0 , bottom , bottom_width , bottom ) ) ;
_painter - > drawLine ( QLineF ( 0 , m_boundingRect . top ( ) , top_width , m_boundingRect . top ( ) ) ) ;
2017-03-07 01:09:27 +03:00
paintMouseIndicator ( _painter , m_boundingRect . top ( ) , bottom , width , maxColumnHeight - HIST_COLUMN_MIN_HEIGHT , top_width , m_mouseY , dtime , font_h ) ;
2017-03-07 00:29:34 +03:00
if ( m_bottomDuration < EASY_GLOBALS . frame_time & & EASY_GLOBALS . frame_time < m_topDuration )
2016-12-04 16:51:27 +03:00
{
2017-03-07 00:29:34 +03:00
// Draw marker displaying expected frame_time step
2017-03-07 01:09:27 +03:00
const auto h = bottom - ( EASY_GLOBALS . frame_time - m_bottomDuration ) * coeff ;
2016-12-04 16:51:27 +03:00
_painter - > setPen ( Qt : : DashLine ) ;
auto w = width ;
const auto boundary = INDICATOR_SIZE - font_h ;
if ( h < ( m_boundingRect . top ( ) - boundary ) )
w = top_width ;
else if ( h > ( bottom + boundary ) )
w = bottom_width ;
_painter - > drawLine ( QLineF ( 0 , h , w , h ) ) ;
}
_painter - > setPen ( Qt : : black ) ;
rect . setRect ( 0 , bottom + 2 , width , widget - > defaultFontHeight ( ) ) ;
2017-03-07 00:29:34 +03:00
const auto eventsSize = m_pProfilerThread - > events . size ( ) ;
2017-06-06 20:46:06 +03:00
_painter - > drawText ( rect , Qt : : AlignHCenter | Qt : : TextDontClip , QString ( " %1 | duration: %2 | profiled: %3 (%4%) | wait: %5 (%6%) | %7 frames | %8 blocks | %9 markers " )
2017-03-07 00:29:34 +03:00
. arg ( m_threadName )
2016-12-04 16:51:27 +03:00
. arg ( : : profiler_gui : : timeStringRealNs ( EASY_GLOBALS . time_units , m_threadDuration ) )
2016-12-14 22:16:14 +03:00
. arg ( : : profiler_gui : : timeStringRealNs ( EASY_GLOBALS . time_units , m_threadProfiledTime ) )
. arg ( m_threadDuration ? QString : : number ( 100. * ( double ) m_threadProfiledTime / ( double ) m_threadDuration , ' f ' , 2 ) : QString ( " 0 " ) )
. arg ( : : profiler_gui : : timeStringRealNs ( EASY_GLOBALS . time_units , m_threadWaitTime ) )
. arg ( m_threadDuration ? QString : : number ( 100. * ( double ) m_threadWaitTime / ( double ) m_threadDuration , ' f ' , 2 ) : QString ( " 0 " ) )
2017-06-06 20:46:06 +03:00
. arg ( m_pProfilerThread - > frames_number )
2017-03-07 00:29:34 +03:00
. arg ( m_pProfilerThread - > blocks_number - eventsSize )
. arg ( eventsSize ) ) ;
2016-12-04 16:51:27 +03:00
2016-12-07 22:29:16 +03:00
_painter - > drawText ( rect , Qt : : AlignLeft , bindMode ? " MODE: zoom " : " MODE: overview " ) ;
2016-12-04 16:51:27 +03:00
_painter - > restore ( ) ;
}
2017-03-07 00:29:34 +03:00
void EasyHistogramItem : : paintById ( QPainter * _painter )
2016-12-04 16:51:27 +03:00
{
const auto widget = static_cast < const EasyGraphicsScrollbar * > ( scene ( ) - > parent ( ) ) ;
const bool bindMode = widget - > bindMode ( ) ;
const auto currentScale = widget - > getWindowScale ( ) ;
const auto bottom = m_boundingRect . bottom ( ) ;
const auto width = m_boundingRect . width ( ) * currentScale ;
2017-03-07 00:29:34 +03:00
const auto dtime = m_topDuration - m_bottomDuration ;
const auto maxColumnHeight = m_boundingRect . height ( ) ;
2017-03-07 01:09:27 +03:00
const auto coeff = ( m_boundingRect . height ( ) - HIST_COLUMN_MIN_HEIGHT ) / ( dtime > 1e-3 ? dtime : 1. ) ;
2016-12-04 16:51:27 +03:00
QRectF rect ;
QBrush brush ( Qt : : SolidPattern ) ;
2017-04-10 22:04:09 +03:00
//QRgb previousColor = 0;
2016-08-03 00:06:36 +03:00
_painter - > save ( ) ;
_painter - > setTransform ( QTransform : : fromScale ( 1.0 / currentScale , 1 ) , true ) ;
2017-03-13 00:43:15 +03:00
const auto & items = m_selectedBlocks ;
if ( ! items . empty ( ) )
2016-08-03 00:06:36 +03:00
{
2017-03-07 00:29:34 +03:00
_painter - > setPen ( Qt : : NoPen ) ;
2017-03-13 00:43:15 +03:00
if ( ! bindMode )
_painter - > drawImage ( 0 , m_boundingRect . top ( ) , m_mainImage ) ;
else
2016-11-30 22:37:11 +03:00
{
2017-03-13 00:43:15 +03:00
const auto range = widget - > sliderWidth ( ) ;
auto minimum = widget - > value ( ) ;
const auto slider_k = widget - > range ( ) / range ;
/*if (false)//slider_k < 8)
{
_painter - > setTransform ( QTransform : : fromScale ( slider_k , 1 ) , true ) ;
_painter - > drawImage ( ( widget - > minimum ( ) - minimum ) * currentScale , m_boundingRect . top ( ) , m_mainImage ) ;
_painter - > setTransform ( QTransform : : fromScale ( 1. / slider_k , 1 ) , true ) ;
}
else */
{
const auto deltaScale = slider_k / m_imageScale ;
_painter - > setTransform ( QTransform : : fromScale ( deltaScale , 1 ) , true ) ;
_painter - > drawImage ( ( widget - > minimum ( ) + m_imageOrigin - minimum ) * currentScale * m_imageScale , m_boundingRect . top ( ) , m_mainImage ) ;
_painter - > setTransform ( QTransform : : fromScale ( 1. / deltaScale , 1 ) , true ) ;
}
/*if (false)
2016-11-30 22:37:11 +03:00
{
2017-03-13 00:43:15 +03:00
minimum * = 1e3 ;
const auto maximum = minimum + range * 1e3 ;
const auto realScale = currentScale * slider_k ;
const auto offset = minimum * realScale ;
auto first = : : std : : lower_bound ( items . begin ( ) , items . end ( ) , minimum + EASY_GLOBALS . begin_time , [ ] ( : : profiler : : block_index_t _item , qreal _value )
{
return easyBlock ( _item ) . tree . node - > begin ( ) < _value ;
} ) ;
2016-11-30 22:37:11 +03:00
2017-03-13 00:43:15 +03:00
if ( first ! = items . end ( ) )
2016-12-04 16:51:27 +03:00
{
2017-03-13 00:43:15 +03:00
if ( first ! = items . begin ( ) )
- - first ;
2016-12-04 16:51:27 +03:00
}
else
{
2017-03-13 00:43:15 +03:00
first = items . begin ( ) + ( items . size ( ) - 1 ) ;
}
2016-12-27 20:53:16 +03:00
2017-03-13 00:43:15 +03:00
auto last = : : std : : upper_bound ( first , items . end ( ) , maximum + EASY_GLOBALS . begin_time , [ ] ( qreal _value , : : profiler : : block_index_t _item )
{
return _value < easyBlock ( _item ) . tree . node - > begin ( ) ;
} ) ;
2016-11-16 22:28:38 +03:00
2017-03-13 00:43:15 +03:00
const auto n = static_cast < uint32_t > ( : : std : : distance ( first , last ) ) ;
2016-12-04 19:17:28 +03:00
2017-03-13 00:43:15 +03:00
if ( n > 0 )
{
const bool gotFrame = EASY_GLOBALS . frame_time > 1e-6 f ;
qreal frameCoeff = 1 ;
if ( gotFrame )
2016-12-04 16:51:27 +03:00
{
2017-03-13 00:43:15 +03:00
if ( EASY_GLOBALS . frame_time < = m_bottomDuration )
frameCoeff = m_boundingRect . height ( ) ;
else
frameCoeff = 0.9 / EASY_GLOBALS . frame_time ;
}
2017-03-07 00:29:34 +03:00
2017-03-13 00:43:15 +03:00
auto const calculate_color = gotFrame ? calculate_color2 : calculate_color1 ;
auto const k = gotFrame ? sqr ( sqr ( frameCoeff ) ) : 1.0 / m_boundingRect . height ( ) ;
2016-12-04 16:51:27 +03:00
2017-03-13 00:43:15 +03:00
const auto draw = [ this , & previousColor , & brush , & _painter ] ( qreal x , qreal y , qreal w , qreal h , QRgb color )
2017-03-07 00:29:34 +03:00
{
2017-03-13 00:43:15 +03:00
m_spin . lock ( ) ;
if ( previousColor ! = color )
2016-12-04 16:51:27 +03:00
{
2017-03-13 00:43:15 +03:00
// Set background color brush for rectangle
previousColor = color ;
brush . setColor ( QColor : : fromRgba ( 0xc0000000 | color ) ) ;
_painter - > setBrush ( brush ) ;
2016-12-04 16:51:27 +03:00
}
2017-03-13 00:43:15 +03:00
_painter - > drawRect ( QRectF ( x , y , w , h ) ) ;
2016-12-04 16:51:27 +03:00
2017-03-13 00:43:15 +03:00
m_spin . unlock ( ) ;
} ;
: : std : : vector < : : std : : thread > threads ;
const auto n_threads = : : std : : min ( n , : : std : : thread : : hardware_concurrency ( ) ) ;
threads . reserve ( n_threads ) ;
const auto n_items = n / n_threads ;
for ( uint32_t i = 0 ; i < n_threads ; + + i )
{
auto begin = first + i * n_items ;
threads . emplace_back ( [ this , & draw , & maximum , & minimum , & realScale , & offset , & coeff , & calculate_color , & k , & bottom , & maxColumnHeight ] ( decltype ( begin ) it , decltype ( begin ) end )
2016-12-04 16:51:27 +03:00
{
2017-03-13 00:43:15 +03:00
qreal previous_x = - 1e30 , previous_h = - 1e30 ;
2016-12-04 16:51:27 +03:00
2017-03-13 00:43:15 +03:00
//for (auto it = first, end = items.end(); it != end; ++it)
for ( ; it ! = end ; + + it )
2016-12-04 16:51:27 +03:00
{
2017-03-13 00:43:15 +03:00
// Draw rectangle
const auto item = easyBlock ( * it ) . tree . node ;
const auto beginTime = item - > begin ( ) - EASY_GLOBALS . begin_time ;
if ( beginTime > maximum )
break ;
const auto endTime = item - > end ( ) - EASY_GLOBALS . begin_time ;
if ( endTime < minimum )
continue ;
const qreal duration = item - > duration ( ) * 1e-3 ;
const qreal item_x = ( beginTime * realScale - offset ) * 1e-3 ;
const qreal item_w = : : std : : max ( duration * realScale , 1.0 ) ;
const qreal item_r = item_x + item_w ;
const qreal h = duration < = m_bottomDuration ? HIST_COLUMN_MIN_HEIGHT :
( duration > m_topDuration ? maxColumnHeight : ( HIST_COLUMN_MIN_HEIGHT + ( duration - m_bottomDuration ) * coeff ) ) ;
if ( h < previous_h & & item_r < previous_x )
continue ;
const auto col = calculate_color ( h , duration , k ) ;
const auto color = 0x00ffffff & QColor : : fromHsvF ( ( 1.0 - col ) * 0.375 , 0.85 , 0.85 ) . rgb ( ) ;
draw ( item_x , bottom - h , item_w , h , color ) ;
//if (previousColor != color)
//{
// // Set background color brush for rectangle
// previousColor = color;
// brush.setColor(QColor::fromRgba(0xc0000000 | color));
// _painter->setBrush(brush);
//}
//rect.setRect(item_x, bottom - h, item_w, h);
//_painter->drawRect(rect);
previous_x = item_r ;
previous_h = h ;
2016-12-04 16:51:27 +03:00
}
2017-03-13 00:43:15 +03:00
} , begin , i = = ( n_threads - 1 ) ? items . end ( ) : begin + n_items ) ;
2017-03-07 00:29:34 +03:00
}
2017-03-13 00:43:15 +03:00
for ( auto & t : threads )
t . join ( ) ;
2016-12-04 16:51:27 +03:00
}
2017-03-13 00:43:15 +03:00
} */
2016-11-30 22:37:11 +03:00
}
2016-08-03 00:06:36 +03:00
}
2017-03-13 00:43:15 +03:00
//if (!m_bReady.load(::std::memory_order_acquire))
// paintBusyIndicator(_painter, currentScale);
2017-03-07 00:29:34 +03:00
2016-12-01 21:55:11 +03:00
qreal top_width = width , bottom_width = width ;
int font_h = 0 ;
2017-03-07 00:29:34 +03:00
if ( ! m_topDurationStr . isEmpty ( ) )
2016-12-01 21:55:11 +03:00
{
rect . setRect ( 0 , m_boundingRect . top ( ) - INDICATOR_SIZE , width - 3 , m_boundingRect . height ( ) + INDICATOR_SIZE_x2 ) ;
if ( m_timeUnits ! = EASY_GLOBALS . time_units )
{
m_timeUnits = EASY_GLOBALS . time_units ;
2017-03-07 00:29:34 +03:00
m_topDurationStr = : : profiler_gui : : timeStringReal ( m_timeUnits , m_topDuration , 3 ) ;
m_bottomDurationStr = : : profiler_gui : : timeStringReal ( m_timeUnits , m_bottomDuration , 3 ) ;
2016-12-01 21:55:11 +03:00
}
auto fm = _painter - > fontMetrics ( ) ;
font_h = fm . height ( ) ;
2017-03-07 00:29:34 +03:00
//bottom_width -= fm.width(m_bottomDurationStr) + 7;
top_width - = fm . width ( m_topDurationStr ) + 7 ;
2016-12-01 21:55:11 +03:00
_painter - > setPen ( Qt : : black ) ;
2017-03-13 00:43:15 +03:00
_painter - > setPen ( m_topDuration < m_maxDuration ? Qt : : darkRed : Qt : : black ) ;
2017-03-07 00:29:34 +03:00
_painter - > drawText ( rect , Qt : : AlignRight | Qt : : AlignTop , m_topDurationStr ) ;
2016-12-04 16:51:27 +03:00
rect . setRect ( 0 , bottom , width - 3 , font_h ) ;
2017-03-13 00:43:15 +03:00
_painter - > setPen ( m_bottomDuration > m_minDuration ? Qt : : darkRed : Qt : : black ) ;
2017-03-07 00:29:34 +03:00
_painter - > drawText ( rect , Qt : : AlignRight | Qt : : AlignTop , m_bottomDurationStr ) ;
2016-12-01 21:55:11 +03:00
}
2016-08-23 22:44:59 +03:00
_painter - > setPen ( Qt : : darkGray ) ;
2016-12-01 21:55:11 +03:00
_painter - > drawLine ( QLineF ( 0 , bottom , bottom_width , bottom ) ) ;
_painter - > drawLine ( QLineF ( 0 , m_boundingRect . top ( ) , top_width , m_boundingRect . top ( ) ) ) ;
2016-11-13 22:02:47 +03:00
2017-03-07 01:09:27 +03:00
paintMouseIndicator ( _painter , m_boundingRect . top ( ) , bottom , width , maxColumnHeight - HIST_COLUMN_MIN_HEIGHT , top_width , m_mouseY , dtime , font_h ) ;
2017-03-07 00:29:34 +03:00
if ( m_bottomDuration < EASY_GLOBALS . frame_time & & EASY_GLOBALS . frame_time < m_topDuration )
2016-11-13 22:02:47 +03:00
{
// Draw marker displaying required frame_time step
2017-03-07 01:09:27 +03:00
const auto h = bottom - ( EASY_GLOBALS . frame_time - m_bottomDuration ) * coeff ;
2016-11-16 23:13:43 +03:00
_painter - > setPen ( Qt : : DashLine ) ;
2016-12-01 21:55:11 +03:00
auto w = width ;
const auto boundary = INDICATOR_SIZE - font_h ;
if ( h < ( m_boundingRect . top ( ) - boundary ) )
w = top_width ;
2016-12-04 16:51:27 +03:00
else if ( h > ( bottom + boundary ) )
2016-12-01 21:55:11 +03:00
w = bottom_width ;
_painter - > drawLine ( QLineF ( 0 , h , w , h ) ) ;
2016-11-13 22:02:47 +03:00
}
2016-08-23 22:44:59 +03:00
2016-12-04 16:51:27 +03:00
_painter - > setPen ( Qt : : black ) ;
rect . setRect ( 0 , bottom + 2 , width , widget - > defaultFontHeight ( ) ) ;
2017-06-05 21:26:10 +03:00
if ( ! m_selectedBlocks . empty ( ) )
2016-12-04 16:51:27 +03:00
{
2017-06-05 21:26:10 +03:00
_painter - > drawText ( rect , Qt : : AlignHCenter | Qt : : TextDontClip , QString ( " %1 | %2 | %3 calls | %4% of thread profiled time " )
. arg ( m_threadName ) . arg ( m_blockName ) . arg ( m_selectedBlocks . size ( ) )
. arg ( m_threadProfiledTime ? QString : : number ( 100. * ( double ) m_blockTotalDuraion / ( double ) m_threadProfiledTime , ' f ' , 2 ) : QString ( " 100 " ) ) ) ;
2016-12-04 16:51:27 +03:00
}
else
{
2017-06-05 21:26:10 +03:00
_painter - > drawText ( rect , Qt : : AlignHCenter | Qt : : TextDontClip , QString ( " %1 | %2 | 0 calls " ) . arg ( m_threadName ) . arg ( m_blockName ) ) ;
2016-12-04 16:51:27 +03:00
}
2016-12-07 22:29:16 +03:00
_painter - > drawText ( rect , Qt : : AlignLeft , bindMode ? " MODE: zoom " : " MODE: overview " ) ;
2016-08-03 00:06:36 +03:00
_painter - > restore ( ) ;
}
2017-03-07 00:29:34 +03:00
: : profiler : : thread_id_t EasyHistogramItem : : threadId ( ) const
2016-08-03 23:00:04 +03:00
{
return m_threadId ;
}
2017-03-07 00:29:34 +03:00
void EasyHistogramItem : : setBoundingRect ( const QRectF & _rect )
2016-08-03 00:06:36 +03:00
{
m_boundingRect = _rect ;
}
2017-03-07 00:29:34 +03:00
void EasyHistogramItem : : setBoundingRect ( qreal x , qreal y , qreal w , qreal h )
2016-08-23 22:44:59 +03:00
{
m_boundingRect . setRect ( x , y , w , h ) ;
}
2017-03-07 00:29:34 +03:00
void EasyHistogramItem : : setSource ( : : profiler : : thread_id_t _thread_id , const : : profiler_gui : : EasyItems * _items )
2016-08-03 00:06:36 +03:00
{
2017-03-07 19:59:57 +03:00
if ( m_regime = = Hist_Pointer & & m_threadId = = _thread_id & & m_pSource = = _items )
2016-12-04 16:51:27 +03:00
return ;
2017-03-13 00:43:15 +03:00
m_timer . stop ( ) ;
m_boundaryTimer . stop ( ) ;
2016-12-04 16:51:27 +03:00
m_bReady . store ( true , : : std : : memory_order_release ) ;
if ( m_workerThread . joinable ( ) )
m_workerThread . join ( ) ;
2017-06-05 21:26:10 +03:00
m_blockName . clear ( ) ;
m_blockTotalDuraion = 0 ;
2017-03-13 20:30:57 +03:00
delete m_workerImage ;
m_workerImage = nullptr ;
2017-03-13 00:43:15 +03:00
m_imageOriginUpdate = m_imageOrigin = 0 ;
m_imageScaleUpdate = m_imageScale = 1 ;
2016-12-04 16:51:27 +03:00
m_selectedBlocks . clear ( ) ;
2017-06-05 21:26:10 +03:00
{ : : profiler : : BlocksTree : : children_t ( ) . swap ( m_selectedBlocks ) ; }
2016-12-04 16:51:27 +03:00
2017-03-13 00:43:15 +03:00
m_bPermitImageUpdate = false ;
2017-03-07 19:59:57 +03:00
m_regime = Hist_Pointer ;
2016-08-03 00:06:36 +03:00
m_pSource = _items ;
2016-08-03 23:00:04 +03:00
m_threadId = _thread_id ;
2016-12-04 16:51:27 +03:00
: : profiler_gui : : set_max ( m_blockId ) ;
2016-08-03 00:06:36 +03:00
2016-12-01 21:55:11 +03:00
if ( m_pSource ! = nullptr )
2016-08-03 00:06:36 +03:00
{
if ( m_pSource - > empty ( ) )
{
m_pSource = nullptr ;
}
2016-08-08 22:17:56 +03:00
else
2016-08-03 00:06:36 +03:00
{
2017-03-13 00:43:15 +03:00
const auto & root = EASY_GLOBALS . profiler_blocks [ _thread_id ] ;
2017-06-05 21:26:10 +03:00
m_threadName = : : profiler_gui : : decoratedThreadName ( EASY_GLOBALS . use_decorated_thread_name , root , EASY_GLOBALS . hex_thread_id ) ;
2017-03-13 00:43:15 +03:00
if ( root . children . empty ( ) )
m_threadDuration = 0 ;
else
m_threadDuration = easyBlock ( root . children . back ( ) ) . tree . node - > end ( ) - easyBlock ( root . children . front ( ) ) . tree . node - > begin ( ) ;
m_threadProfiledTime = root . profiled_time ;
m_threadWaitTime = root . wait_time ;
m_pProfilerThread = & root ;
m_timeUnits = EASY_GLOBALS . time_units ;
m_bReady . store ( false , : : std : : memory_order_release ) ;
m_workerThread = : : std : : thread ( [ this ] ( const : : profiler_gui : : EasyItems * _source )
2016-08-03 00:06:36 +03:00
{
2017-03-13 20:30:57 +03:00
m_maxDuration = 0 ;
m_minDuration = 1e30 ;
2017-03-13 00:43:15 +03:00
2017-03-13 20:30:57 +03:00
bool empty = true ;
2017-03-13 00:43:15 +03:00
for ( const auto & item : * _source )
{
if ( m_bReady . load ( : : std : : memory_order_acquire ) )
return ;
if ( easyDescriptor ( easyBlock ( item . block ) . tree . node - > id ( ) ) . type ( ) = = : : profiler : : BLOCK_TYPE_EVENT )
continue ;
const auto w = item . width ( ) ;
if ( w > m_maxDuration )
m_maxDuration = w ;
if ( w < m_minDuration )
m_minDuration = w ;
2017-03-13 20:30:57 +03:00
empty = false ;
}
2017-03-13 00:43:15 +03:00
2017-03-13 20:30:57 +03:00
if ( ( m_maxDuration - m_minDuration ) < 1e-3 )
{
if ( m_minDuration > 0.1 )
{
m_minDuration - = 0.1 ;
2017-03-13 00:43:15 +03:00
}
2017-03-13 20:30:57 +03:00
else
2017-03-13 00:43:15 +03:00
{
2017-03-13 20:30:57 +03:00
m_maxDuration = 0.1 ;
m_minDuration = 0 ;
2017-03-13 00:43:15 +03:00
}
}
m_topDuration = m_maxDuration ;
m_bottomDuration = m_minDuration ;
2017-03-13 20:30:57 +03:00
if ( ! empty )
{
m_topDurationStr = : : profiler_gui : : timeStringReal ( m_timeUnits , m_topDuration , 3 ) ;
m_bottomDurationStr = : : profiler_gui : : timeStringReal ( m_timeUnits , m_bottomDuration , 3 ) ;
}
else
{
m_topDurationStr . clear ( ) ;
m_bottomDurationStr . clear ( ) ;
}
2017-03-13 00:43:15 +03:00
m_bReady . store ( true , : : std : : memory_order_release ) ;
} , m_pSource ) ;
m_timeouts = 3 ;
m_timer . start ( WORKER_THREAD_CHECK_INTERVAL ) ;
show ( ) ;
2016-08-03 00:06:36 +03:00
}
}
if ( m_pSource = = nullptr )
{
2016-12-12 22:28:54 +03:00
m_pProfilerThread = nullptr ;
2017-03-07 00:29:34 +03:00
m_topDurationStr . clear ( ) ;
m_bottomDurationStr . clear ( ) ;
2016-12-04 16:51:27 +03:00
m_threadName . clear ( ) ;
2016-08-03 00:06:36 +03:00
hide ( ) ;
}
2016-12-04 16:51:27 +03:00
}
2017-03-07 00:29:34 +03:00
void EasyHistogramItem : : setSource ( : : profiler : : thread_id_t _thread_id , : : profiler : : block_id_t _block_id )
2016-12-04 16:51:27 +03:00
{
2017-03-07 19:59:57 +03:00
if ( m_regime = = Hist_Id & & m_threadId = = _thread_id & & m_blockId = = _block_id )
2016-12-04 16:51:27 +03:00
return ;
2017-03-07 00:29:34 +03:00
m_bPermitImageUpdate = false ; // Set to false because m_workerThread have to parse input data first. This will be set to true when m_workerThread finish - see onTimeout()
2017-03-07 19:59:57 +03:00
m_regime = Hist_Id ;
2016-12-04 16:51:27 +03:00
2017-03-13 00:43:15 +03:00
m_timer . stop ( ) ;
m_boundaryTimer . stop ( ) ;
2016-12-04 16:51:27 +03:00
m_bReady . store ( true , : : std : : memory_order_release ) ;
if ( m_workerThread . joinable ( ) )
m_workerThread . join ( ) ;
2017-06-05 21:26:10 +03:00
m_pSource = nullptr ;
m_topDurationStr . clear ( ) ;
m_bottomDurationStr . clear ( ) ;
m_blockName . clear ( ) ;
m_blockTotalDuraion = 0 ;
2017-03-13 20:30:57 +03:00
delete m_workerImage ;
m_workerImage = nullptr ;
2017-03-13 00:43:15 +03:00
m_imageOriginUpdate = m_imageOrigin = 0 ;
m_imageScaleUpdate = m_imageScale = 1 ;
2016-12-04 16:51:27 +03:00
m_selectedBlocks . clear ( ) ;
2017-06-05 21:26:10 +03:00
{ : : profiler : : BlocksTree : : children_t ( ) . swap ( m_selectedBlocks ) ; }
2016-12-04 16:51:27 +03:00
m_threadId = _thread_id ;
m_blockId = _block_id ;
if ( m_threadId ! = 0 & & ! : : profiler_gui : : is_max ( m_blockId ) )
{
2017-06-05 21:26:10 +03:00
m_blockName = : : profiler_gui : : toUnicode ( easyDescriptor ( m_blockId ) . name ( ) ) ;
2016-12-04 16:51:27 +03:00
const auto & root = EASY_GLOBALS . profiler_blocks [ _thread_id ] ;
2017-06-05 21:26:10 +03:00
m_threadName = : : profiler_gui : : decoratedThreadName ( EASY_GLOBALS . use_decorated_thread_name , root , EASY_GLOBALS . hex_thread_id ) ;
m_pProfilerThread = & root ;
m_timeUnits = EASY_GLOBALS . time_units ;
2016-12-04 16:51:27 +03:00
if ( root . children . empty ( ) )
2017-06-05 21:26:10 +03:00
{
2016-12-04 16:51:27 +03:00
m_threadDuration = 0 ;
2017-06-05 21:26:10 +03:00
m_threadProfiledTime = 0 ;
m_threadWaitTime = 0 ;
m_topDuration = m_maxDuration = 0 ;
m_bottomDuration = m_minDuration = 1e30 ;
m_bPermitImageUpdate = true ;
m_bReady . store ( true , : : std : : memory_order_release ) ;
}
2016-12-04 16:51:27 +03:00
else
2017-06-05 21:26:10 +03:00
{
2016-12-04 16:51:27 +03:00
m_threadDuration = easyBlock ( root . children . back ( ) ) . tree . node - > end ( ) - easyBlock ( root . children . front ( ) ) . tree . node - > begin ( ) ;
2017-06-05 21:26:10 +03:00
m_threadProfiledTime = root . profiled_time ;
m_threadWaitTime = root . wait_time ;
2017-03-13 00:43:15 +03:00
2017-06-05 21:26:10 +03:00
m_bReady . store ( false , : : std : : memory_order_release ) ;
m_workerThread = : : std : : thread ( [ this ] ( decltype ( root ) profiler_thread , : : profiler : : block_index_t selected_block )
{
typedef : : std : : vector < : : std : : pair < : : profiler : : block_index_t , : : profiler : : block_index_t > > Stack ;
2017-03-13 00:43:15 +03:00
2017-06-05 21:26:10 +03:00
m_maxDuration = 0 ;
m_minDuration = 1e30 ;
//const auto& profiler_thread = EASY_GLOBALS.profiler_blocks[m_threadId];
Stack stack ;
stack . reserve ( profiler_thread . depth ) ;
2016-12-04 16:51:27 +03:00
2017-06-05 21:26:10 +03:00
const bool has_selected_block = ! : : profiler_gui : : is_max ( selected_block ) ;
2016-12-04 16:51:27 +03:00
2017-06-05 21:26:10 +03:00
for ( auto frame : profiler_thread . children )
2016-12-04 16:51:27 +03:00
{
2017-06-05 21:26:10 +03:00
const auto & frame_block = easyBlock ( frame ) . tree ;
if ( frame_block . node - > id ( ) = = m_blockId | | ( ! has_selected_block & & m_blockId = = easyDescriptor ( frame_block . node - > id ( ) ) . id ( ) ) )
{
m_selectedBlocks . push_back ( frame ) ;
2016-12-04 16:51:27 +03:00
2017-06-05 21:26:10 +03:00
const auto w = frame_block . node - > duration ( ) ;
if ( w > m_maxDuration )
m_maxDuration = w ;
2017-03-13 00:43:15 +03:00
2017-06-05 21:26:10 +03:00
if ( w < m_minDuration )
m_minDuration = w ;
2016-12-04 16:51:27 +03:00
2017-06-05 21:26:10 +03:00
m_blockTotalDuraion + = w ;
}
2017-03-13 00:43:15 +03:00
2017-06-05 21:26:10 +03:00
stack . push_back ( : : std : : make_pair ( frame , 0U ) ) ;
while ( ! stack . empty ( ) )
2016-12-04 16:51:27 +03:00
{
2017-03-13 00:43:15 +03:00
if ( m_bReady . load ( : : std : : memory_order_acquire ) )
return ;
2017-06-05 21:26:10 +03:00
auto & top = stack . back ( ) ;
const auto & top_children = easyBlock ( top . first ) . tree . children ;
const auto stack_size = stack . size ( ) ;
for ( auto end = top_children . size ( ) ; top . second < end ; + + top . second )
2016-12-04 16:51:27 +03:00
{
2017-06-05 21:26:10 +03:00
if ( m_bReady . load ( : : std : : memory_order_acquire ) )
return ;
const auto child_index = top_children [ top . second ] ;
const auto & child = easyBlock ( child_index ) . tree ;
if ( child . node - > id ( ) = = m_blockId | | ( ! has_selected_block & & m_blockId = = easyDescriptor ( child . node - > id ( ) ) . id ( ) ) )
{
m_selectedBlocks . push_back ( child_index ) ;
const auto w = child . node - > duration ( ) ;
if ( w > m_maxDuration )
m_maxDuration = w ;
if ( w < m_minDuration )
m_minDuration = w ;
m_blockTotalDuraion + = w ;
}
2016-12-04 16:51:27 +03:00
2017-06-05 21:26:10 +03:00
if ( ! child . children . empty ( ) )
{
+ + top . second ;
stack . push_back ( : : std : : make_pair ( child_index , 0U ) ) ;
break ;
}
2016-12-04 16:51:27 +03:00
}
2017-06-05 21:26:10 +03:00
if ( stack_size = = stack . size ( ) )
2016-12-04 16:51:27 +03:00
{
2017-06-05 21:26:10 +03:00
stack . pop_back ( ) ;
2016-12-04 16:51:27 +03:00
}
}
}
2017-03-13 20:30:57 +03:00
2017-06-05 21:26:10 +03:00
if ( m_selectedBlocks . empty ( ) )
2017-03-13 20:30:57 +03:00
{
2017-06-05 21:26:10 +03:00
m_topDurationStr . clear ( ) ;
m_bottomDurationStr . clear ( ) ;
}
else
{
if ( has_selected_block )
2017-03-13 20:30:57 +03:00
{
2017-06-05 21:26:10 +03:00
const auto & item = easyBlock ( selected_block ) . tree ;
if ( * item . node - > name ( ) ! = 0 )
m_blockName = : : profiler_gui : : toUnicode ( item . node - > name ( ) ) ;
2017-03-13 20:30:57 +03:00
}
2017-06-05 21:26:10 +03:00
m_maxDuration * = 1e-3 ;
m_minDuration * = 1e-3 ;
if ( ( m_maxDuration - m_minDuration ) < 1e-3 )
2017-03-13 20:30:57 +03:00
{
2017-06-05 21:26:10 +03:00
if ( m_minDuration > 0.1 )
{
m_minDuration - = 0.1 ;
}
else
{
m_maxDuration = 0.1 ;
m_minDuration = 0 ;
}
2017-03-13 20:30:57 +03:00
}
2017-06-05 21:26:10 +03:00
m_topDurationStr = : : profiler_gui : : timeStringReal ( m_timeUnits , m_maxDuration , 3 ) ;
m_bottomDurationStr = : : profiler_gui : : timeStringReal ( m_timeUnits , m_minDuration , 3 ) ;
2017-03-13 20:30:57 +03:00
}
2016-12-04 16:51:27 +03:00
2017-03-13 20:30:57 +03:00
2017-06-05 21:26:10 +03:00
m_topDuration = m_maxDuration ;
m_bottomDuration = m_minDuration ;
2017-03-13 20:30:57 +03:00
2017-06-05 21:26:10 +03:00
m_bReady . store ( true , : : std : : memory_order_release ) ;
2017-03-07 00:29:34 +03:00
2017-06-05 21:26:10 +03:00
} , std : : ref ( root ) , EASY_GLOBALS . selected_block ) ;
2017-03-13 00:43:15 +03:00
2017-06-05 21:26:10 +03:00
m_timeouts = 3 ;
m_timer . start ( WORKER_THREAD_CHECK_INTERVAL ) ;
}
2016-12-04 16:51:27 +03:00
2017-03-13 00:43:15 +03:00
show ( ) ;
2016-12-04 16:51:27 +03:00
}
else
{
2016-12-12 22:28:54 +03:00
m_pProfilerThread = nullptr ;
2016-12-04 16:51:27 +03:00
m_threadName . clear ( ) ;
hide ( ) ;
}
}
//////////////////////////////////////////////////////////////////////////
2017-03-07 00:29:34 +03:00
void EasyHistogramItem : : validateName ( )
2016-12-14 21:47:33 +03:00
{
if ( m_threadName . isEmpty ( ) )
return ;
2017-06-05 21:26:10 +03:00
m_threadName = : : profiler_gui : : decoratedThreadName ( EASY_GLOBALS . use_decorated_thread_name , EASY_GLOBALS . profiler_blocks [ m_threadId ] , EASY_GLOBALS . hex_thread_id ) ;
2016-12-14 21:47:33 +03:00
}
//////////////////////////////////////////////////////////////////////////
2017-03-07 00:29:34 +03:00
void EasyHistogramItem : : onTimeout ( )
2016-12-04 16:51:27 +03:00
{
if ( ! isVisible ( ) )
{
2017-03-13 00:43:15 +03:00
m_timer . stop ( ) ;
2016-12-04 16:51:27 +03:00
return ;
}
if ( + + m_timeouts > 8 )
m_timeouts = 3 ;
if ( m_bReady . load ( : : std : : memory_order_acquire ) )
{
m_timer . stop ( ) ;
2017-03-07 00:29:34 +03:00
if ( ! m_bPermitImageUpdate )
2016-12-04 16:51:27 +03:00
{
2017-03-07 00:29:34 +03:00
// Worker thread have finished parsing input data (when setSource(_block_id) was called)
m_bPermitImageUpdate = true ; // From now we can update an image
2016-12-04 16:51:27 +03:00
updateImage ( ) ;
}
else
{
2017-03-07 00:29:34 +03:00
// Image updated
2017-03-07 19:59:57 +03:00
if ( m_workerThread . joinable ( ) )
m_workerThread . join ( ) ;
2017-03-13 20:30:57 +03:00
m_workerImage - > swap ( m_mainImage ) ;
delete m_workerImage ;
m_workerImage = nullptr ;
m_imageOriginUpdate = m_imageOrigin = m_workerImageOrigin ;
m_imageScaleUpdate = m_imageScale = m_workerImageScale ;
2016-12-04 16:51:27 +03:00
2017-03-13 20:30:57 +03:00
if ( EASY_GLOBALS . auto_adjust_histogram_height & & ! m_topDurationStr . isEmpty ( ) )
{
m_topDuration = m_workerTopDuration ;
m_bottomDuration = m_workerBottomDuration ;
m_topDurationStr = : : profiler_gui : : timeStringReal ( m_timeUnits , m_topDuration , 3 ) ;
m_bottomDurationStr = : : profiler_gui : : timeStringReal ( m_timeUnits , m_bottomDuration , 3 ) ;
}
2016-12-04 16:51:27 +03:00
}
}
scene ( ) - > update ( ) ;
}
//////////////////////////////////////////////////////////////////////////
2017-03-13 00:43:15 +03:00
void EasyHistogramItem : : pickTopBoundary ( qreal _y )
2017-03-07 00:29:34 +03:00
{
2017-03-13 20:30:57 +03:00
if ( m_bPermitImageUpdate & & m_boundingRect . top ( ) < _y & & _y < m_boundingRect . bottom ( ) & & ! m_topDurationStr . isEmpty ( ) )
2017-03-13 00:43:15 +03:00
{
m_topDuration = m_bottomDuration + ( m_topDuration - m_bottomDuration ) * ( m_boundingRect . bottom ( ) - _y ) / ( m_boundingRect . height ( ) - HIST_COLUMN_MIN_HEIGHT ) ;
m_topDurationStr = : : profiler_gui : : timeStringReal ( m_timeUnits , m_topDuration , 3 ) ;
m_boundaryTimer . stop ( ) ;
updateImage ( ) ;
scene ( ) - > update ( ) ; // to update top-boundary text right now
}
}
2017-03-07 00:29:34 +03:00
2017-03-13 00:43:15 +03:00
void EasyHistogramItem : : increaseTopBoundary ( )
{
2017-03-13 20:30:57 +03:00
if ( m_bPermitImageUpdate & & m_topDuration < m_maxDuration & & ! m_topDurationStr . isEmpty ( ) )
2017-03-07 00:29:34 +03:00
{
auto step = 0.05 * ( m_maxDuration - m_bottomDuration ) ;
if ( m_topDuration < ( m_bottomDuration + 1.25 * step ) )
step = 0.1 * ( m_topDuration - m_bottomDuration ) ;
m_topDuration = std : : min ( m_maxDuration , m_topDuration + step ) ;
m_topDurationStr = : : profiler_gui : : timeStringReal ( m_timeUnits , m_topDuration , 3 ) ;
updateImage ( ) ;
scene ( ) - > update ( ) ; // to update top-boundary text right now
2017-03-13 00:43:15 +03:00
m_boundaryTimer . stop ( ) ;
m_boundaryTimer . start ( BOUNDARY_TIMER_INTERVAL ) ;
2017-03-07 00:29:34 +03:00
}
}
void EasyHistogramItem : : decreaseTopBoundary ( )
2016-12-04 16:51:27 +03:00
{
2017-03-13 20:30:57 +03:00
if ( m_bPermitImageUpdate & & m_topDuration > m_bottomDuration & & ! m_topDurationStr . isEmpty ( ) )
2017-03-07 00:29:34 +03:00
{
auto step = 0.05 * ( m_maxDuration - m_bottomDuration ) ;
if ( m_topDuration < ( m_bottomDuration + 1.25 * step ) )
step = std : : max ( 0.1 * ( m_topDuration - m_bottomDuration ) , 0.3 ) ;
if ( m_topDuration > ( m_bottomDuration + 1.25 * step ) )
{
m_topDuration = std : : max ( m_bottomDuration + step , m_topDuration - step ) ;
m_topDurationStr = : : profiler_gui : : timeStringReal ( m_timeUnits , m_topDuration , 3 ) ;
scene ( ) - > update ( ) ; // to update top-boundary text right now
2017-03-13 00:43:15 +03:00
m_boundaryTimer . stop ( ) ;
m_boundaryTimer . start ( BOUNDARY_TIMER_INTERVAL ) ;
2017-03-07 00:29:34 +03:00
}
}
}
//////////////////////////////////////////////////////////////////////////
2017-03-13 00:43:15 +03:00
void EasyHistogramItem : : pickBottomBoundary ( qreal _y )
2017-03-07 00:29:34 +03:00
{
2017-03-13 20:30:57 +03:00
if ( m_bPermitImageUpdate & & m_boundingRect . top ( ) < _y & & _y < m_boundingRect . bottom ( ) & & ! m_bottomDurationStr . isEmpty ( ) )
2017-03-13 00:43:15 +03:00
{
m_bottomDuration = m_bottomDuration + ( m_topDuration - m_bottomDuration ) * ( m_boundingRect . bottom ( ) - _y ) / ( m_boundingRect . height ( ) - HIST_COLUMN_MIN_HEIGHT ) ;
m_bottomDurationStr = : : profiler_gui : : timeStringReal ( m_timeUnits , m_bottomDuration , 3 ) ;
m_boundaryTimer . stop ( ) ;
updateImage ( ) ;
scene ( ) - > update ( ) ; // to update top-boundary text right now
}
}
2017-03-07 00:29:34 +03:00
2017-03-13 00:43:15 +03:00
void EasyHistogramItem : : increaseBottomBoundary ( )
{
2017-03-13 20:30:57 +03:00
if ( m_bPermitImageUpdate & & m_bottomDuration < m_topDuration & & ! m_bottomDurationStr . isEmpty ( ) )
2017-03-07 00:29:34 +03:00
{
auto step = 0.05 * ( m_topDuration - m_minDuration ) ;
if ( m_bottomDuration > ( m_topDuration - 1.25 * step ) )
step = 0.1 * ( m_topDuration - m_bottomDuration ) ;
if ( m_bottomDuration < ( m_topDuration - 1.25 * step ) )
{
m_bottomDuration = std : : min ( m_topDuration - step , m_bottomDuration + step ) ;
m_bottomDurationStr = : : profiler_gui : : timeStringReal ( m_timeUnits , m_bottomDuration , 3 ) ;
scene ( ) - > update ( ) ; // to update bottom-boundary text right now
2017-03-13 00:43:15 +03:00
m_boundaryTimer . stop ( ) ;
m_boundaryTimer . start ( BOUNDARY_TIMER_INTERVAL ) ;
2017-03-07 00:29:34 +03:00
}
}
}
void EasyHistogramItem : : decreaseBottomBoundary ( )
{
2017-03-13 20:30:57 +03:00
if ( m_bPermitImageUpdate & & m_bottomDuration > m_minDuration & & ! m_bottomDurationStr . isEmpty ( ) )
2017-03-07 00:29:34 +03:00
{
auto step = 0.05 * ( m_topDuration - m_minDuration ) ;
if ( m_bottomDuration > ( m_topDuration - 1.25 * step ) )
step = std : : max ( 0.1 * ( m_topDuration - m_bottomDuration ) , 0.3 ) ;
m_bottomDuration = std : : max ( m_minDuration , m_bottomDuration - step ) ;
m_bottomDurationStr = : : profiler_gui : : timeStringReal ( m_timeUnits , m_bottomDuration , 3 ) ;
scene ( ) - > update ( ) ; // to update top-boundary text right now
2017-03-13 00:43:15 +03:00
m_boundaryTimer . stop ( ) ;
m_boundaryTimer . start ( BOUNDARY_TIMER_INTERVAL ) ;
2017-03-07 00:29:34 +03:00
}
}
//////////////////////////////////////////////////////////////////////////
void EasyHistogramItem : : setMouseY ( qreal _mouseY )
{
m_mouseY = _mouseY ;
}
2017-03-07 01:09:27 +03:00
void EasyHistogramItem : : pickFrameTime ( qreal _y ) const
{
2017-03-13 20:30:57 +03:00
if ( m_bPermitImageUpdate & & m_boundingRect . top ( ) < _y & & _y < m_boundingRect . bottom ( ) & & ! m_topDurationStr . isEmpty ( ) )
2017-03-07 01:09:27 +03:00
{
EASY_GLOBALS . frame_time = m_bottomDuration + ( m_topDuration - m_bottomDuration ) * ( m_boundingRect . bottom ( ) - _y ) / ( m_boundingRect . height ( ) - HIST_COLUMN_MIN_HEIGHT ) ;
2017-03-13 20:30:57 +03:00
emit EASY_GLOBALS . events . expectedFrameTimeChanged ( ) ;
2017-03-07 01:09:27 +03:00
}
}
2017-03-07 00:29:34 +03:00
//////////////////////////////////////////////////////////////////////////
2017-03-13 00:43:15 +03:00
void EasyHistogramItem : : onValueChanged ( )
{
const auto widget = static_cast < const EasyGraphicsScrollbar * > ( scene ( ) - > parent ( ) ) ;
if ( ! widget - > bindMode ( ) )
return ;
m_boundaryTimer . stop ( ) ;
const auto sliderWidth_inv = 1.0 / widget - > sliderWidth ( ) ;
const auto k = widget - > range ( ) * sliderWidth_inv ;
const auto deltaScale = m_imageScaleUpdate < k ? ( k / m_imageScaleUpdate ) : ( m_imageScaleUpdate / k ) ;
if ( deltaScale > 4 ) {
updateImage ( ) ;
return ;
}
const auto deltaOffset = ( widget - > value ( ) - m_imageOriginUpdate ) * sliderWidth_inv ;
if ( deltaOffset < 1.5 | | deltaOffset > 4.5 ) {
updateImage ( ) ;
return ;
}
m_boundaryTimer . start ( BOUNDARY_TIMER_INTERVAL ) ;
}
//////////////////////////////////////////////////////////////////////////
2017-03-13 20:30:57 +03:00
void EasyHistogramItem : : onModeChanged ( )
{
if ( ! m_bPermitImageUpdate )
return ;
const auto widget = static_cast < const EasyGraphicsScrollbar * > ( scene ( ) - > parent ( ) ) ;
if ( ! widget - > bindMode ( ) & & EASY_GLOBALS . auto_adjust_histogram_height )
{
m_topDuration = m_maxDuration ;
m_bottomDuration = m_minDuration ;
}
m_boundaryTimer . stop ( ) ;
updateImage ( ) ;
}
//////////////////////////////////////////////////////////////////////////
2017-03-13 00:43:15 +03:00
void EasyHistogramItem : : cancelImageUpdate ( )
{
if ( ! m_bPermitImageUpdate )
return ;
m_bReady . store ( true , : : std : : memory_order_release ) ;
if ( m_workerThread . joinable ( ) )
m_workerThread . join ( ) ;
m_bReady . store ( false , : : std : : memory_order_release ) ;
2017-03-13 20:30:57 +03:00
delete m_workerImage ;
m_workerImage = nullptr ;
2017-03-13 00:43:15 +03:00
m_imageOriginUpdate = m_imageOrigin ;
m_imageScaleUpdate = m_imageScale ;
m_timer . stop ( ) ;
}
2017-03-07 00:29:34 +03:00
void EasyHistogramItem : : updateImage ( )
{
if ( ! m_bPermitImageUpdate )
2016-12-04 16:51:27 +03:00
return ;
const auto widget = static_cast < const EasyGraphicsScrollbar * > ( scene ( ) - > parent ( ) ) ;
m_bReady . store ( true , : : std : : memory_order_release ) ;
if ( m_workerThread . joinable ( ) )
m_workerThread . join ( ) ;
m_bReady . store ( false , : : std : : memory_order_release ) ;
2017-03-13 20:30:57 +03:00
delete m_workerImage ;
m_workerImage = nullptr ;
2016-12-04 16:51:27 +03:00
2017-03-13 00:43:15 +03:00
m_imageScaleUpdate = widget - > range ( ) / widget - > sliderWidth ( ) ;
m_imageOriginUpdate = widget - > bindMode ( ) ? ( widget - > value ( ) - widget - > sliderWidth ( ) * 3 ) : widget - > minimum ( ) ;
m_workerThread = : : std : : thread ( [ this ] ( QRectF _boundingRect , HistRegime _regime , qreal _current_scale ,
qreal _minimum , qreal _maximum , qreal _range , qreal _value , qreal _width , qreal _top_duration , qreal _bottom_duration ,
2017-03-13 20:30:57 +03:00
bool _bindMode , float _frame_time , : : profiler : : timestamp_t _begin_time , qreal _origin , bool _autoAdjustHist )
2016-12-04 16:51:27 +03:00
{
2017-03-13 20:30:57 +03:00
updateImage ( _boundingRect , _regime , _current_scale , _minimum , _maximum , _range , _value , _width , _top_duration , _bottom_duration , _bindMode , _frame_time , _begin_time , _origin , _autoAdjustHist ) ;
2016-12-04 16:51:27 +03:00
m_bReady . store ( true , : : std : : memory_order_release ) ;
2017-03-13 00:43:15 +03:00
} , m_boundingRect , m_regime , widget - > getWindowScale ( ) , widget - > minimum ( ) , widget - > maximum ( ) , widget - > range ( ) , widget - > value ( ) , widget - > sliderWidth ( ) ,
2017-03-13 20:30:57 +03:00
m_topDuration , m_bottomDuration , widget - > bindMode ( ) , EASY_GLOBALS . frame_time , EASY_GLOBALS . begin_time , m_imageOriginUpdate , EASY_GLOBALS . auto_adjust_histogram_height ) ;
2016-12-04 16:51:27 +03:00
m_timeouts = 3 ;
2017-03-13 00:43:15 +03:00
m_timer . start ( WORKER_THREAD_CHECK_INTERVAL ) ;
2016-12-04 16:51:27 +03:00
}
2017-03-13 00:43:15 +03:00
void EasyHistogramItem : : updateImage ( QRectF _boundingRect , HistRegime _regime , qreal _current_scale ,
2016-12-04 16:51:27 +03:00
qreal _minimum , qreal _maximum , qreal _range ,
2017-03-13 00:43:15 +03:00
qreal _value , qreal _width , qreal _top_duration , qreal _bottom_duration ,
bool _bindMode , float _frame_time , : : profiler : : timestamp_t _begin_time ,
2017-03-13 20:30:57 +03:00
qreal _origin , bool _autoAdjustHist )
2017-03-13 00:43:15 +03:00
{
const auto bottom = _boundingRect . height ( ) ; //_boundingRect.bottom();
const auto screenWidth = _boundingRect . width ( ) * _current_scale ;
const auto maxColumnHeight = _boundingRect . height ( ) ;
const auto viewScale = _range / _width ;
if ( _bindMode )
{
2017-03-13 20:30:57 +03:00
m_workerImageScale = viewScale ;
m_workerImageOrigin = _value - _width * 3 ;
m_workerImage = new QImage ( screenWidth * 7 + 0.5 , _boundingRect . height ( ) , QImage : : Format_ARGB32 ) ;
2017-03-13 00:43:15 +03:00
}
else
{
2017-03-13 20:30:57 +03:00
m_workerImageScale = 1 ;
m_workerImageOrigin = _minimum ;
m_workerImage = new QImage ( screenWidth + 0.5 , _boundingRect . height ( ) , QImage : : Format_ARGB32 ) ;
2017-03-13 00:43:15 +03:00
}
2017-03-13 20:30:57 +03:00
m_workerImage - > fill ( 0 ) ;
QPainter p ( m_workerImage ) ;
2016-12-04 16:51:27 +03:00
p . setPen ( Qt : : NoPen ) ;
QRectF rect ;
QBrush brush ( Qt : : SolidPattern ) ;
QRgb previousColor = 0 ;
qreal previous_x = - 1e30 , previous_h = - 1e30 , offset = 0. ;
auto realScale = _current_scale ;
const bool gotFrame = _frame_time > 1e-6 f ;
qreal frameCoeff = 1 ;
if ( gotFrame )
{
2017-03-13 00:43:15 +03:00
if ( _frame_time < = _bottom_duration )
frameCoeff = _boundingRect . height ( ) ;
2016-12-04 16:51:27 +03:00
else
2016-12-07 22:29:16 +03:00
frameCoeff = 0.9 / _frame_time ;
2016-12-04 16:51:27 +03:00
}
auto const calculate_color = gotFrame ? calculate_color2 : calculate_color1 ;
2017-03-13 00:43:15 +03:00
auto const k = gotFrame ? sqr ( sqr ( frameCoeff ) ) : 1.0 / _boundingRect . height ( ) ;
2016-12-04 16:51:27 +03:00
2017-03-07 19:59:57 +03:00
if ( _regime = = Hist_Pointer )
2016-12-04 16:51:27 +03:00
{
const auto & items = * m_pSource ;
if ( items . empty ( ) )
return ;
2017-03-07 19:59:57 +03:00
auto first = items . begin ( ) ;
2017-03-13 00:43:15 +03:00
if ( _bindMode )
{
2017-03-13 20:30:57 +03:00
_minimum = m_workerImageOrigin ;
_maximum = m_workerImageOrigin + _width * 7 ;
2017-03-13 00:43:15 +03:00
realScale * = viewScale ;
offset = _minimum * realScale ;
first = : : std : : lower_bound ( items . begin ( ) , items . end ( ) , _minimum , [ ] ( const : : profiler_gui : : EasyBlockItem & _item , qreal _value )
{
return _item . left ( ) < _value ;
} ) ;
if ( first ! = items . end ( ) )
{
if ( first ! = items . begin ( ) )
- - first ;
}
else
{
first = items . begin ( ) + items . size ( ) - 1 ;
}
2017-03-13 20:30:57 +03:00
if ( _autoAdjustHist )
{
const auto maxVal = _value + _width ;
decltype ( _top_duration ) maxDuration = 0 ;
decltype ( _bottom_duration ) minDuration = 1e30 ;
size_t iterations = 0 ;
for ( auto it = first , end = items . end ( ) ; it ! = end ; + + it )
{
// Draw rectangle
if ( it - > left ( ) > maxVal )
break ;
if ( it - > right ( ) < _value )
continue ;
if ( maxDuration < it - > width ( ) )
maxDuration = it - > width ( ) ;
if ( minDuration > it - > width ( ) )
minDuration = it - > width ( ) ;
+ + iterations ;
}
if ( iterations )
{
_top_duration = maxDuration ;
_bottom_duration = minDuration ;
if ( ( _top_duration - _bottom_duration ) < 1e-3 )
{
if ( _bottom_duration > 0.1 )
{
_bottom_duration - = 0.1 ;
}
else
{
_top_duration = 0.1 ;
_bottom_duration = 0 ;
}
}
}
}
2017-03-13 00:43:15 +03:00
}
2016-12-04 16:51:27 +03:00
2017-03-13 20:30:57 +03:00
const auto dtime = _top_duration - _bottom_duration ;
const auto coeff = ( _boundingRect . height ( ) - HIST_COLUMN_MIN_HEIGHT ) / ( dtime > 1e-3 ? dtime : 1. ) ;
2017-03-07 19:59:57 +03:00
for ( auto it = first , end = items . end ( ) ; it ! = end ; + + it )
2016-12-04 16:51:27 +03:00
{
// Draw rectangle
2017-03-07 19:59:57 +03:00
if ( it - > left ( ) > _maximum )
2016-12-04 16:51:27 +03:00
break ;
2017-03-07 19:59:57 +03:00
if ( it - > right ( ) < _minimum )
2016-12-04 16:51:27 +03:00
continue ;
const qreal item_x = it - > left ( ) * realScale - offset ;
const qreal item_w = : : std : : max ( it - > width ( ) * realScale , 1.0 ) ;
const qreal item_r = item_x + item_w ;
2017-03-13 00:43:15 +03:00
const qreal h = it - > width ( ) < = _bottom_duration ? HIST_COLUMN_MIN_HEIGHT :
( it - > width ( ) > _top_duration ? maxColumnHeight : ( HIST_COLUMN_MIN_HEIGHT + ( it - > width ( ) - _bottom_duration ) * coeff ) ) ;
2016-12-04 16:51:27 +03:00
if ( h < previous_h & & item_r < previous_x )
continue ;
2016-12-07 22:29:16 +03:00
const auto col = calculate_color ( h , it - > width ( ) , k ) ;
2016-12-04 16:51:27 +03:00
const auto color = 0x00ffffff & QColor : : fromHsvF ( ( 1.0 - col ) * 0.375 , 0.85 , 0.85 ) . rgb ( ) ;
if ( previousColor ! = color )
{
// Set background color brush for rectangle
previousColor = color ;
brush . setColor ( QColor : : fromRgba ( 0xc0000000 | color ) ) ;
p . setBrush ( brush ) ;
}
rect . setRect ( item_x , bottom - h , item_w , h ) ;
p . drawRect ( rect ) ;
previous_x = item_r ;
previous_h = h ;
}
}
else
{
2017-03-13 00:43:15 +03:00
auto first = m_selectedBlocks . begin ( ) ;
if ( _bindMode )
{
2017-03-13 20:30:57 +03:00
_minimum = m_workerImageOrigin ;
_maximum = m_workerImageOrigin + _width * 7 ;
2017-03-13 00:43:15 +03:00
realScale * = viewScale ;
offset = _minimum * 1e3 * realScale ;
first = : : std : : lower_bound ( m_selectedBlocks . begin ( ) , m_selectedBlocks . end ( ) , _minimum * 1e3 + _begin_time , [ ] ( : : profiler : : block_index_t _item , qreal _value )
{
return easyBlock ( _item ) . tree . node - > begin ( ) < _value ;
} ) ;
if ( first ! = m_selectedBlocks . end ( ) )
{
if ( first ! = m_selectedBlocks . begin ( ) )
- - first ;
}
else
{
first = m_selectedBlocks . begin ( ) + m_selectedBlocks . size ( ) - 1 ;
}
2017-03-13 20:30:57 +03:00
_minimum * = 1e3 ;
_maximum * = 1e3 ;
if ( _autoAdjustHist )
{
const auto minVal = _value * 1e3 , maxVal = ( _value + _width ) * 1e3 ;
decltype ( _top_duration ) maxDuration = 0 ;
decltype ( _bottom_duration ) minDuration = 1e30 ;
size_t iterations = 0 ;
for ( auto it = first , end = m_selectedBlocks . end ( ) ; it ! = end ; + + it )
{
const auto item = easyBlock ( * it ) . tree . node ;
const auto beginTime = item - > begin ( ) - _begin_time ;
if ( beginTime > maxVal )
break ;
const auto endTime = item - > end ( ) - _begin_time ;
if ( endTime < minVal )
continue ;
const qreal duration = item - > duration ( ) * 1e-3 ;
if ( maxDuration < duration )
maxDuration = duration ;
if ( minDuration > duration )
minDuration = duration ;
+ + iterations ;
}
if ( iterations )
{
_top_duration = maxDuration ;
_bottom_duration = minDuration ;
if ( ( _top_duration - _bottom_duration ) < 1e-3 )
{
if ( _bottom_duration > 0.1 )
{
_bottom_duration - = 0.1 ;
}
else
{
_top_duration = 0.1 ;
_bottom_duration = 0 ;
}
}
}
}
}
else
{
_minimum * = 1e3 ;
_maximum * = 1e3 ;
2017-03-13 00:43:15 +03:00
}
2017-03-13 20:30:57 +03:00
const auto dtime = _top_duration - _bottom_duration ;
const auto coeff = ( _boundingRect . height ( ) - HIST_COLUMN_MIN_HEIGHT ) / ( dtime > 1e-3 ? dtime : 1. ) ;
2016-12-04 16:51:27 +03:00
2017-03-13 00:43:15 +03:00
for ( auto it = first , end = m_selectedBlocks . end ( ) ; it ! = end ; + + it )
2016-12-04 16:51:27 +03:00
{
// Draw rectangle
const auto item = easyBlock ( * it ) . tree . node ;
const auto beginTime = item - > begin ( ) - _begin_time ;
2017-03-07 19:59:57 +03:00
if ( beginTime > _maximum )
2016-12-04 16:51:27 +03:00
break ;
const auto endTime = item - > end ( ) - _begin_time ;
2017-03-07 19:59:57 +03:00
if ( endTime < _minimum )
2016-12-04 16:51:27 +03:00
continue ;
const qreal duration = item - > duration ( ) * 1e-3 ;
const qreal item_x = ( beginTime * realScale - offset ) * 1e-3 ;
const qreal item_w = : : std : : max ( duration * realScale , 1.0 ) ;
const qreal item_r = item_x + item_w ;
2017-03-13 00:43:15 +03:00
const auto h = duration < = _bottom_duration ? HIST_COLUMN_MIN_HEIGHT :
( duration > _top_duration ? maxColumnHeight : ( HIST_COLUMN_MIN_HEIGHT + ( duration - _bottom_duration ) * coeff ) ) ;
2016-12-04 16:51:27 +03:00
if ( h < previous_h & & item_r < previous_x )
continue ;
2016-12-07 22:29:16 +03:00
const auto col = calculate_color ( h , duration , k ) ;
2016-12-04 16:51:27 +03:00
const auto color = 0x00ffffff & QColor : : fromHsvF ( ( 1.0 - col ) * 0.375 , 0.85 , 0.85 ) . rgb ( ) ;
if ( previousColor ! = color )
{
// Set background color brush for rectangle
previousColor = color ;
brush . setColor ( QColor : : fromRgba ( 0xc0000000 | color ) ) ;
p . setBrush ( brush ) ;
}
rect . setRect ( item_x , bottom - h , item_w , h ) ;
p . drawRect ( rect ) ;
previous_x = item_r ;
previous_h = h ;
}
2016-08-03 00:06:36 +03:00
}
2017-03-13 20:30:57 +03:00
m_workerTopDuration = _top_duration ;
m_workerBottomDuration = _bottom_duration ;
2016-08-03 00:06:36 +03:00
}
//////////////////////////////////////////////////////////////////////////
2016-08-18 23:26:41 +03:00
EasyGraphicsScrollbar : : EasyGraphicsScrollbar ( QWidget * _parent )
2016-07-10 01:29:09 +03:00
: Parent ( _parent )
, m_minimumValue ( 0 )
, m_maximumValue ( 500 )
, m_value ( 10 )
2016-07-31 13:13:48 +03:00
, m_windowScale ( 1 )
, m_mouseButtons ( Qt : : NoButton )
2016-07-10 01:29:09 +03:00
, m_slider ( nullptr )
2016-08-03 00:06:36 +03:00
, m_chronometerIndicator ( nullptr )
2017-03-07 00:29:34 +03:00
, m_histogramItem ( nullptr )
2016-12-04 16:51:27 +03:00
, m_defaultFontHeight ( 0 )
2016-07-31 13:13:48 +03:00
, m_bScrolling ( false )
2016-11-30 22:37:11 +03:00
, m_bBindMode ( false )
2016-12-04 16:51:27 +03:00
, m_bLocked ( false )
2016-07-10 01:29:09 +03:00
{
setCacheMode ( QGraphicsView : : CacheNone ) ;
setTransformationAnchor ( QGraphicsView : : AnchorUnderMouse ) ;
2016-08-08 23:39:37 +03:00
//setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate);
setViewportUpdateMode ( QGraphicsView : : FullViewportUpdate ) ;
2016-07-10 01:29:09 +03:00
setOptimizationFlag ( QGraphicsView : : DontSavePainterState , true ) ;
setHorizontalScrollBarPolicy ( Qt : : ScrollBarAlwaysOff ) ;
setVerticalScrollBarPolicy ( Qt : : ScrollBarAlwaysOff ) ;
2016-08-03 00:06:36 +03:00
setContentsMargins ( 0 , 0 , 0 , 0 ) ;
2016-07-10 01:29:09 +03:00
auto selfScene = new QGraphicsScene ( this ) ;
2016-12-04 16:51:27 +03:00
m_defaultFontHeight = QFontMetrics ( selfScene - > font ( ) ) . height ( ) ;
selfScene - > setSceneRect ( 0 , DEFAULT_TOP , 500 , DEFAULT_HEIGHT + m_defaultFontHeight + 2 ) ;
setFixedHeight ( DEFAULT_HEIGHT + m_defaultFontHeight + 2 ) ;
2016-07-10 01:29:09 +03:00
setScene ( selfScene ) ;
2017-03-07 00:29:34 +03:00
m_histogramItem = new EasyHistogramItem ( ) ;
m_histogramItem - > setPos ( 0 , 0 ) ;
m_histogramItem - > setBoundingRect ( 0 , DEFAULT_TOP + INDICATOR_SIZE , scene ( ) - > width ( ) , DEFAULT_HEIGHT - INDICATOR_SIZE_x2 ) ;
selfScene - > addItem ( m_histogramItem ) ;
m_histogramItem - > hide ( ) ;
2016-07-10 01:29:09 +03:00
2016-08-18 23:26:41 +03:00
m_chronometerIndicator = new EasyGraphicsSliderItem ( false ) ;
2016-08-03 00:06:36 +03:00
m_chronometerIndicator - > setPos ( 0 , 0 ) ;
2016-08-07 19:38:31 +03:00
m_chronometerIndicator - > setColor ( 0x40000000 | : : profiler_gui : : CHRONOMETER_COLOR . rgba ( ) ) ;
2016-08-03 00:06:36 +03:00
selfScene - > addItem ( m_chronometerIndicator ) ;
m_chronometerIndicator - > hide ( ) ;
2016-08-23 22:44:59 +03:00
m_slider = new EasyGraphicsSliderItem ( true ) ;
m_slider - > setPos ( 0 , 0 ) ;
m_slider - > setColor ( 0x40c0c0c0 ) ;
selfScene - > addItem ( m_slider ) ;
2016-08-24 01:00:24 +03:00
m_slider - > hide ( ) ;
2016-08-03 00:06:36 +03:00
2017-03-13 20:30:57 +03:00
connect ( & EASY_GLOBALS . events , & : : profiler_gui : : EasyGlobalSignals : : expectedFrameTimeChanged , [ this ] ( )
2016-12-04 16:51:27 +03:00
{
2017-03-07 00:29:34 +03:00
if ( m_histogramItem - > isVisible ( ) )
2017-03-13 20:30:57 +03:00
{
2017-03-07 00:29:34 +03:00
m_histogramItem - > updateImage ( ) ;
2017-03-13 20:30:57 +03:00
scene ( ) - > update ( ) ;
}
} ) ;
connect ( & EASY_GLOBALS . events , & : : profiler_gui : : EasyGlobalSignals : : autoAdjustHistogramChanged , [ this ] ( )
{
if ( m_histogramItem - > isVisible ( ) )
m_histogramItem - > onModeChanged ( ) ;
2016-12-04 16:51:27 +03:00
} ) ;
2016-11-13 22:02:47 +03:00
2017-06-05 21:26:10 +03:00
connect ( & EASY_GLOBALS . events , & : : profiler_gui : : EasyGlobalSignals : : threadNameDecorationChanged , this , & This : : onThreadViewChanged ) ;
connect ( & EASY_GLOBALS . events , & : : profiler_gui : : EasyGlobalSignals : : hexThreadIdChanged , this , & This : : onThreadViewChanged ) ;
2016-12-14 21:47:33 +03:00
2016-07-31 13:13:48 +03:00
centerOn ( 0 , 0 ) ;
2016-07-10 01:29:09 +03:00
}
2016-08-18 23:26:41 +03:00
EasyGraphicsScrollbar : : ~ EasyGraphicsScrollbar ( )
2016-07-10 01:29:09 +03:00
{
}
//////////////////////////////////////////////////////////////////////////
2017-06-05 21:26:10 +03:00
void EasyGraphicsScrollbar : : onThreadViewChanged ( )
{
if ( m_histogramItem - > isVisible ( ) )
{
m_histogramItem - > validateName ( ) ;
scene ( ) - > update ( ) ;
}
}
//////////////////////////////////////////////////////////////////////////
2016-09-21 22:09:04 +03:00
void EasyGraphicsScrollbar : : clear ( )
{
2017-03-07 19:59:57 +03:00
setHistogramSource ( 0 , nullptr ) ;
2016-09-21 22:09:04 +03:00
hideChrono ( ) ;
setRange ( 0 , 100 ) ;
setSliderWidth ( 2 ) ;
setValue ( 0 ) ;
}
//////////////////////////////////////////////////////////////////////////
2016-11-30 22:37:11 +03:00
bool EasyGraphicsScrollbar : : bindMode ( ) const
{
return m_bBindMode ;
}
2016-08-18 23:26:41 +03:00
qreal EasyGraphicsScrollbar : : getWindowScale ( ) const
2016-07-31 13:13:48 +03:00
{
return m_windowScale ;
}
2016-12-04 16:51:27 +03:00
: : profiler : : thread_id_t EasyGraphicsScrollbar : : hystThread ( ) const
2016-08-03 23:00:04 +03:00
{
2017-03-07 00:29:34 +03:00
return m_histogramItem - > threadId ( ) ;
2016-08-03 23:00:04 +03:00
}
2016-08-18 23:26:41 +03:00
qreal EasyGraphicsScrollbar : : minimum ( ) const
2016-07-10 01:29:09 +03:00
{
return m_minimumValue ;
}
2016-08-18 23:26:41 +03:00
qreal EasyGraphicsScrollbar : : maximum ( ) const
2016-07-10 01:29:09 +03:00
{
return m_maximumValue ;
}
2016-08-18 23:26:41 +03:00
qreal EasyGraphicsScrollbar : : range ( ) const
2016-07-31 13:13:48 +03:00
{
return m_maximumValue - m_minimumValue ;
}
2016-08-18 23:26:41 +03:00
qreal EasyGraphicsScrollbar : : value ( ) const
2016-07-10 01:29:09 +03:00
{
return m_value ;
}
2016-08-18 23:26:41 +03:00
qreal EasyGraphicsScrollbar : : sliderWidth ( ) const
2016-08-08 22:17:56 +03:00
{
return m_slider - > width ( ) ;
}
2016-08-18 23:26:41 +03:00
qreal EasyGraphicsScrollbar : : sliderHalfWidth ( ) const
2016-08-08 22:17:56 +03:00
{
return m_slider - > halfwidth ( ) ;
}
2016-12-04 16:51:27 +03:00
int EasyGraphicsScrollbar : : defaultFontHeight ( ) const
{
return m_defaultFontHeight ;
}
2016-07-10 01:29:09 +03:00
//////////////////////////////////////////////////////////////////////////
2016-08-18 23:26:41 +03:00
void EasyGraphicsScrollbar : : setValue ( qreal _value )
2016-07-10 01:29:09 +03:00
{
2016-08-01 22:21:59 +03:00
m_value = clamp ( m_minimumValue , _value , : : std : : max ( m_minimumValue , m_maximumValue - m_slider - > width ( ) ) ) ;
2016-07-31 13:13:48 +03:00
m_slider - > setX ( m_value + m_slider - > halfwidth ( ) ) ;
2016-07-10 01:29:09 +03:00
emit valueChanged ( m_value ) ;
2017-03-13 00:43:15 +03:00
if ( m_histogramItem - > isVisible ( ) )
m_histogramItem - > onValueChanged ( ) ;
2016-07-10 01:29:09 +03:00
}
2016-08-18 23:26:41 +03:00
void EasyGraphicsScrollbar : : setRange ( qreal _minValue , qreal _maxValue )
2016-07-10 01:29:09 +03:00
{
2016-07-31 13:13:48 +03:00
const auto oldRange = range ( ) ;
const auto oldValue = oldRange < 1e-3 ? 0.0 : m_value / oldRange ;
2016-07-10 01:29:09 +03:00
m_minimumValue = _minValue ;
m_maximumValue = _maxValue ;
2016-12-04 16:51:27 +03:00
scene ( ) - > setSceneRect ( _minValue , DEFAULT_TOP , _maxValue - _minValue , DEFAULT_HEIGHT + m_defaultFontHeight + 4 ) ;
2017-03-13 00:43:15 +03:00
m_histogramItem - > cancelImageUpdate ( ) ;
2017-03-07 00:29:34 +03:00
m_histogramItem - > setBoundingRect ( _minValue , DEFAULT_TOP + INDICATOR_SIZE , _maxValue , DEFAULT_HEIGHT - INDICATOR_SIZE_x2 ) ;
2017-03-13 00:43:15 +03:00
2016-07-31 13:13:48 +03:00
emit rangeChanged ( ) ;
setValue ( _minValue + oldValue * range ( ) ) ;
2017-03-13 00:43:15 +03:00
2016-07-31 13:13:48 +03:00
onWindowWidthChange ( width ( ) ) ;
2017-03-13 00:43:15 +03:00
if ( m_histogramItem - > isVisible ( ) )
m_histogramItem - > updateImage ( ) ;
2016-07-31 13:13:48 +03:00
}
2016-08-18 23:26:41 +03:00
void EasyGraphicsScrollbar : : setSliderWidth ( qreal _width )
2016-07-31 13:13:48 +03:00
{
m_slider - > setWidth ( _width ) ;
2016-07-10 01:29:09 +03:00
setValue ( m_value ) ;
}
//////////////////////////////////////////////////////////////////////////
2016-07-31 13:13:48 +03:00
2016-08-18 23:26:41 +03:00
void EasyGraphicsScrollbar : : setChronoPos ( qreal _left , qreal _right )
2016-08-03 00:06:36 +03:00
{
m_chronometerIndicator - > setWidth ( _right - _left ) ;
m_chronometerIndicator - > setX ( _left + m_chronometerIndicator - > halfwidth ( ) ) ;
}
2016-08-18 23:26:41 +03:00
void EasyGraphicsScrollbar : : showChrono ( )
2016-08-03 00:06:36 +03:00
{
m_chronometerIndicator - > show ( ) ;
}
2016-08-18 23:26:41 +03:00
void EasyGraphicsScrollbar : : hideChrono ( )
2016-08-03 00:06:36 +03:00
{
m_chronometerIndicator - > hide ( ) ;
}
//////////////////////////////////////////////////////////////////////////
2017-03-07 19:59:57 +03:00
void EasyGraphicsScrollbar : : setHistogramSource ( : : profiler : : thread_id_t _thread_id , const : : profiler_gui : : EasyItems * _items )
2016-08-03 00:06:36 +03:00
{
2016-12-04 16:51:27 +03:00
if ( m_bLocked )
return ;
2017-03-07 00:29:34 +03:00
m_histogramItem - > setSource ( _thread_id , _items ) ;
m_slider - > setVisible ( m_histogramItem - > isVisible ( ) ) ;
2016-12-04 16:51:27 +03:00
scene ( ) - > update ( ) ;
}
2017-03-07 19:59:57 +03:00
void EasyGraphicsScrollbar : : setHistogramSource ( : : profiler : : thread_id_t _thread_id , : : profiler : : block_id_t _block_id )
2016-12-04 16:51:27 +03:00
{
if ( m_bLocked )
return ;
2017-03-07 00:29:34 +03:00
m_histogramItem - > setSource ( _thread_id , _block_id ) ;
m_slider - > setVisible ( m_histogramItem - > isVisible ( ) ) ;
2016-08-03 23:00:04 +03:00
scene ( ) - > update ( ) ;
2016-08-03 00:06:36 +03:00
}
//////////////////////////////////////////////////////////////////////////
2016-08-18 23:26:41 +03:00
void EasyGraphicsScrollbar : : mousePressEvent ( QMouseEvent * _event )
2016-07-31 13:13:48 +03:00
{
2017-03-07 01:09:27 +03:00
_event - > accept ( ) ;
2016-07-31 13:13:48 +03:00
m_mouseButtons = _event - > buttons ( ) ;
2017-03-07 01:09:27 +03:00
if ( m_mouseButtons & Qt : : LeftButton )
2016-11-30 22:37:11 +03:00
{
2017-03-07 01:09:27 +03:00
if ( _event - > modifiers ( ) & Qt : : ControlModifier )
{
2017-03-13 00:43:15 +03:00
m_histogramItem - > pickBottomBoundary ( mapToScene ( _event - > pos ( ) ) . y ( ) ) ;
}
else if ( _event - > modifiers ( ) & Qt : : ShiftModifier )
{
m_histogramItem - > pickTopBoundary ( mapToScene ( _event - > pos ( ) ) . y ( ) ) ;
2017-03-07 01:09:27 +03:00
}
else
{
m_bScrolling = true ;
m_mousePressPos = _event - > pos ( ) ;
if ( ! m_bBindMode )
setValue ( mapToScene ( m_mousePressPos ) . x ( ) - m_minimumValue - m_slider - > halfwidth ( ) ) ;
}
2016-11-30 22:37:11 +03:00
}
2017-03-07 01:09:27 +03:00
if ( m_mouseButtons & Qt : : RightButton )
2016-07-31 13:13:48 +03:00
{
2017-03-13 00:43:15 +03:00
if ( _event - > modifiers ( ) )
{
m_histogramItem - > pickFrameTime ( mapToScene ( _event - > pos ( ) ) . y ( ) ) ;
}
else
{
m_bBindMode = ! m_bBindMode ;
if ( m_histogramItem - > isVisible ( ) )
2017-03-13 20:30:57 +03:00
m_histogramItem - > onModeChanged ( ) ;
2017-03-13 00:43:15 +03:00
}
2016-07-31 13:13:48 +03:00
}
//QGraphicsView::mousePressEvent(_event);
}
2016-08-18 23:26:41 +03:00
void EasyGraphicsScrollbar : : mouseReleaseEvent ( QMouseEvent * _event )
2016-07-31 13:13:48 +03:00
{
m_mouseButtons = _event - > buttons ( ) ;
m_bScrolling = false ;
_event - > accept ( ) ;
//QGraphicsView::mouseReleaseEvent(_event);
}
2016-08-18 23:26:41 +03:00
void EasyGraphicsScrollbar : : mouseMoveEvent ( QMouseEvent * _event )
2016-07-31 13:13:48 +03:00
{
2017-03-07 00:29:34 +03:00
const auto pos = _event - > pos ( ) ;
2016-07-31 13:13:48 +03:00
if ( m_mouseButtons & Qt : : LeftButton )
{
const auto delta = pos - m_mousePressPos ;
m_mousePressPos = pos ;
if ( m_bScrolling )
{
2016-11-30 22:37:11 +03:00
auto realScale = m_windowScale ;
if ( m_bBindMode )
realScale * = - range ( ) / sliderWidth ( ) ;
setValue ( m_value + delta . x ( ) / realScale ) ;
2016-07-31 13:13:48 +03:00
}
}
2017-03-07 00:29:34 +03:00
if ( m_histogramItem - > isVisible ( ) )
{
m_histogramItem - > setMouseY ( mapToScene ( pos ) . y ( ) ) ;
scene ( ) - > update ( ) ;
}
2016-07-31 13:13:48 +03:00
}
2016-08-21 16:48:42 +03:00
void EasyGraphicsScrollbar : : wheelEvent ( QWheelEvent * _event )
{
_event - > accept ( ) ;
2016-11-30 22:37:11 +03:00
2017-03-07 00:29:34 +03:00
if ( _event - > modifiers ( ) & Qt : : ShiftModifier )
{
// Shift + mouse wheel will change histogram top boundary
if ( m_histogramItem - > isVisible ( ) )
{
if ( _event - > delta ( ) > 0 )
m_histogramItem - > increaseTopBoundary ( ) ;
else
m_histogramItem - > decreaseTopBoundary ( ) ;
}
return ;
}
if ( _event - > modifiers ( ) & Qt : : ControlModifier )
{
// Ctrl + mouse wheel will change histogram bottom boundary
if ( m_histogramItem - > isVisible ( ) )
{
if ( _event - > delta ( ) > 0 )
m_histogramItem - > increaseBottomBoundary ( ) ;
else
m_histogramItem - > decreaseBottomBoundary ( ) ;
}
return ;
}
2016-11-30 22:37:11 +03:00
if ( ! m_bBindMode )
{
const auto w = m_slider - > halfwidth ( ) * ( _event - > delta ( ) < 0 ? : : profiler_gui : : SCALING_COEFFICIENT : : : profiler_gui : : SCALING_COEFFICIENT_INV ) ;
setValue ( mapToScene ( _event - > pos ( ) ) . x ( ) - m_minimumValue - w ) ;
emit wheeled ( w * m_windowScale , _event - > delta ( ) ) ;
}
else
{
const auto x = ( mapToScene ( _event - > pos ( ) ) . x ( ) - m_minimumValue ) * m_windowScale ;
emit wheeled ( x , _event - > delta ( ) ) ;
}
2016-08-21 16:48:42 +03:00
}
2016-08-18 23:26:41 +03:00
void EasyGraphicsScrollbar : : resizeEvent ( QResizeEvent * _event )
2016-07-31 13:13:48 +03:00
{
onWindowWidthChange ( _event - > size ( ) . width ( ) ) ;
2017-03-13 00:43:15 +03:00
if ( m_histogramItem - > isVisible ( ) )
m_histogramItem - > updateImage ( ) ;
2016-07-31 13:13:48 +03:00
}
2016-08-03 23:00:04 +03:00
//////////////////////////////////////////////////////////////////////////
2016-08-18 23:26:41 +03:00
void EasyGraphicsScrollbar : : onWindowWidthChange ( qreal _width )
2016-07-31 13:13:48 +03:00
{
const auto oldScale = m_windowScale ;
const auto scrollingRange = range ( ) ;
if ( scrollingRange < 1e-3 )
{
m_windowScale = 1 ;
}
else
{
m_windowScale = _width / scrollingRange ;
}
scale ( m_windowScale / oldScale , 1 ) ;
}
//////////////////////////////////////////////////////////////////////////