| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084 |
- /************************************************************************
- * file name : easy_graphics_scrollbar.cpp
- * ----------------- :
- * creation time : 2016/07/04
- * author : Victor Zarubkin
- * email : [email protected]
- * ----------------- :
- * description : .
- * ----------------- :
- * change log : * 2016/07/04 Victor Zarubkin: Initial commit.
- * :
- * : *
- * ----------------- :
- * license : Lightweight profiler library for c++
- * : Copyright(C) 2016-2017 Sergey Yagovtsev, Victor Zarubkin
- * :
- * : 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.
- * :
- * : 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.
- * : 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.
- ************************************************************************/
- #include <algorithm>
- #include <QGraphicsScene>
- #include <QWheelEvent>
- #include <QMouseEvent>
- #include <QResizeEvent>
- #include <QContextMenuEvent>
- #include <QMenu>
- #include "easy_graphics_scrollbar.h"
- #include "globals.h"
- // 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
- //////////////////////////////////////////////////////////////////////////
- const int DEFAULT_TOP = -40;
- const int DEFAULT_HEIGHT = 80;
- const int INDICATOR_SIZE = 6;
- const int INDICATOR_SIZE_x2 = INDICATOR_SIZE << 1;
- const int HIST_COLUMN_MIN_HEIGHT = 2;
- const int WORKER_THREAD_CHECK_INTERVAL = 40;
- const int BOUNDARY_TIMER_INTERVAL = 100;
- //////////////////////////////////////////////////////////////////////////
- inline qreal clamp(qreal _minValue, qreal _value, qreal _maxValue)
- {
- return (_value < _minValue ? _minValue : (_value > _maxValue ? _maxValue : _value));
- }
- inline qreal sqr(qreal _value)
- {
- return _value * _value;
- }
- inline qreal calculate_color1(qreal h, qreal, qreal k)
- {
- return ::std::min(h * k, 0.9999999);
- }
- inline qreal calculate_color2(qreal, qreal duration, qreal k)
- {
- return ::std::min(sqr(sqr(duration)) * k, 0.9999999);
- }
- //////////////////////////////////////////////////////////////////////////
- EasyGraphicsSliderItem::EasyGraphicsSliderItem(bool _main) : Parent(), m_halfwidth(0), m_bMain(_main)
- {
- 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));
- }
- setWidth(1);
- setBrush(Qt::SolidPattern);
- }
- EasyGraphicsSliderItem::~EasyGraphicsSliderItem()
- {
- }
- void EasyGraphicsSliderItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* _option, QWidget* _widget)
- {
- if (static_cast<const EasyGraphicsScrollbar*>(scene()->parent())->bindMode())
- {
- return;
- }
- const auto currentScale = static_cast<const EasyGraphicsScrollbar*>(scene()->parent())->getWindowScale();
- const auto br = rect();
- qreal w = width() * currentScale;
- QRectF r(br.left() * currentScale, br.top() + INDICATOR_SIZE, w, br.height() - INDICATOR_SIZE_x2);
- const auto r_right = r.right();
- const auto r_bottom = r.bottom();
- auto b = brush();
- _painter->save();
- _painter->setTransform(QTransform::fromScale(1.0 / currentScale, 1), true);
- _painter->setBrush(b);
-
- 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);
- }
- // 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);
- _painter->restore();
- }
- qreal EasyGraphicsSliderItem::width() const
- {
- return m_halfwidth * 2.0;
- }
- qreal EasyGraphicsSliderItem::halfwidth() const
- {
- return m_halfwidth;
- }
- void EasyGraphicsSliderItem::setWidth(qreal _width)
- {
- m_halfwidth = _width * 0.5;
- setRect(-m_halfwidth, DEFAULT_TOP, _width, DEFAULT_HEIGHT);
- }
- void EasyGraphicsSliderItem::setHalfwidth(qreal _halfwidth)
- {
- m_halfwidth = _halfwidth;
- setRect(-m_halfwidth, DEFAULT_TOP, m_halfwidth * 2.0, DEFAULT_HEIGHT);
- }
- void EasyGraphicsSliderItem::setColor(QRgb _color)
- {
- setColor(QColor::fromRgba(_color));
- }
- void EasyGraphicsSliderItem::setColor(const QColor& _color)
- {
- auto b = brush();
- b.setColor(_color);
- setBrush(b);
- }
- //////////////////////////////////////////////////////////////////////////
- EasyHistogramItem::EasyHistogramItem() : Parent(nullptr)
- , m_threadDuration(0)
- , m_threadProfiledTime(0)
- , m_threadWaitTime(0)
- , m_pSource(nullptr)
- , m_workerImage(nullptr)
- , m_topDuration(0)
- , m_maxDuration(0)
- , m_minDuration(0)
- , m_imageOrigin(0)
- , m_imageScale(1)
- , m_workerImageOrigin(0)
- , m_workerImageScale(1)
- , m_workerTopDuration(0)
- , m_workerBottomDuration(0)
- , m_blockTotalDuraion(0)
- , m_timer(::std::bind(&This::onTimeout, this))
- , m_boundaryTimer([this](){ updateImage(); }, true)
- , m_pProfilerThread(nullptr)
- , m_threadId(0)
- , m_blockId(::profiler_gui::numeric_max<decltype(m_blockId)>())
- , m_timeouts(0)
- , m_timeUnits(::profiler_gui::TimeUnits_auto)
- , m_regime(Hist_Pointer)
- , m_bPermitImageUpdate(false)
- {
- m_bReady = ATOMIC_VAR_INIT(false);
- }
- EasyHistogramItem::~EasyHistogramItem()
- {
- m_bReady.store(true, ::std::memory_order_release);
- if (m_workerThread.joinable())
- m_workerThread.join();
- delete m_workerImage;
- }
- QRectF EasyHistogramItem::boundingRect() const
- {
- return m_boundingRect;
- }
- void EasyHistogramItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* _option, QWidget* _widget)
- {
- if (!m_bPermitImageUpdate || (m_regime == Hist_Pointer && m_pSource == nullptr) || (m_regime == Hist_Id && (m_threadId == 0 || ::profiler_gui::is_max(m_blockId))))
- return;
- if (m_regime == Hist_Pointer)
- paintByPtr(_painter);
- else
- paintById(_painter);
- }
- void EasyHistogramItem::paintBusyIndicator(QPainter* _painter, qreal _current_scale)
- {
- const auto width = m_boundingRect.width() * _current_scale;
- const auto h = _painter->fontMetrics().height();
- _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('.')));
- }
- 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;
- _painter->setPen(Qt::blue);
- 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;
- 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;
- }
- _painter->drawLine(QLineF(mouseIndicatorLeft, _mouse_y, mouseIndicatorRight, _mouse_y));
- }
- }
- void EasyHistogramItem::paintByPtr(QPainter* _painter)
- {
- 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;
- const auto dtime = m_topDuration - m_bottomDuration;
- const auto maxColumnHeight = m_boundingRect.height();
- const auto coeff = (m_boundingRect.height() - HIST_COLUMN_MIN_HEIGHT) / (dtime > 1e-3 ? dtime : 1.);
- QRectF rect;
- QBrush brush(Qt::SolidPattern);
- //QRgb previousColor = 0;
- _painter->save();
- _painter->setTransform(QTransform::fromScale(1.0 / currentScale, 1), true);
- if (!m_pSource->empty())
- {
- _painter->setPen(Qt::NoPen);
- 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;
- /*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)
- {
- const bool gotFrame = EASY_GLOBALS.frame_time > 1e-6f;
- qreal frameCoeff = 1;
- if (gotFrame)
- {
- if (EASY_GLOBALS.frame_time <= m_bottomDuration)
- frameCoeff = m_boundingRect.height();
- else
- frameCoeff = 0.9 / EASY_GLOBALS.frame_time;
- }
- auto const calculate_color = gotFrame ? calculate_color2 : calculate_color1;
- auto const k = gotFrame ? sqr(sqr(frameCoeff)) : 1.0 / m_boundingRect.height();
- 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;
- 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));
- if (h < previous_h && item_r < previous_x)
- continue;
- const auto col = calculate_color(h, it->width(), k);
- 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;
- }
- }*/
- }
- }
- //if (!m_bReady.load(::std::memory_order_acquire))
- // paintBusyIndicator(_painter, currentScale);
- qreal top_width = width, bottom_width = width;
- int font_h = 0;
- if (!m_topDurationStr.isEmpty())
- {
- 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;
- m_topDurationStr = ::profiler_gui::timeStringReal(m_timeUnits, m_topDuration, 3);
- m_bottomDurationStr = ::profiler_gui::timeStringReal(m_timeUnits, m_bottomDuration, 3);
- }
- auto fm = _painter->fontMetrics();
- font_h = fm.height();
- //bottom_width -= fm.width(m_bottomDurationStr) + 7;
- top_width -= fm.width(m_topDurationStr) + 7;
- _painter->setPen(m_topDuration < m_maxDuration ? Qt::darkRed : Qt::black);
- _painter->drawText(rect, Qt::AlignRight | Qt::AlignTop, m_topDurationStr);
- rect.setRect(0, bottom, width - 3, font_h);
- _painter->setPen(m_bottomDuration > m_minDuration ? Qt::darkRed : Qt::black);
- _painter->drawText(rect, Qt::AlignRight | Qt::AlignTop, m_bottomDurationStr);
- }
- _painter->setPen(Qt::darkGray);
- _painter->drawLine(QLineF(0, bottom, bottom_width, bottom));
- _painter->drawLine(QLineF(0, m_boundingRect.top(), top_width, m_boundingRect.top()));
- paintMouseIndicator(_painter, m_boundingRect.top(), bottom, width, maxColumnHeight - HIST_COLUMN_MIN_HEIGHT, top_width, m_mouseY, dtime, font_h);
- if (m_bottomDuration < EASY_GLOBALS.frame_time && EASY_GLOBALS.frame_time < m_topDuration)
- {
- // Draw marker displaying expected frame_time step
- const auto h = bottom - (EASY_GLOBALS.frame_time - m_bottomDuration) * coeff;
- _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());
- const auto eventsSize = m_pProfilerThread->events.size();
- _painter->drawText(rect, Qt::AlignHCenter | Qt::TextDontClip, QString("%1 | duration: %2 | profiled: %3 (%4%) | wait: %5 (%6%) | %7 frames | %8 blocks | %9 markers")
- .arg(m_threadName)
- .arg(::profiler_gui::timeStringRealNs(EASY_GLOBALS.time_units, m_threadDuration))
- .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"))
- .arg(m_pProfilerThread->frames_number)
- .arg(m_pProfilerThread->blocks_number - eventsSize)
- .arg(eventsSize));
- _painter->drawText(rect, Qt::AlignLeft, bindMode ? " MODE: zoom" : " MODE: overview");
- _painter->restore();
- }
- void EasyHistogramItem::paintById(QPainter* _painter)
- {
- 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;
- const auto dtime = m_topDuration - m_bottomDuration;
- const auto maxColumnHeight = m_boundingRect.height();
- const auto coeff = (m_boundingRect.height() - HIST_COLUMN_MIN_HEIGHT) / (dtime > 1e-3 ? dtime : 1.);
- QRectF rect;
- QBrush brush(Qt::SolidPattern);
- //QRgb previousColor = 0;
- _painter->save();
- _painter->setTransform(QTransform::fromScale(1.0 / currentScale, 1), true);
- const auto& items = m_selectedBlocks;
- if (!items.empty())
- {
- _painter->setPen(Qt::NoPen);
- if (!bindMode)
- _painter->drawImage(0, m_boundingRect.top(), m_mainImage);
- else
- {
- 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)
- {
- 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;
- });
- if (first != items.end())
- {
- if (first != items.begin())
- --first;
- }
- else
- {
- first = items.begin() + (items.size() - 1);
- }
- 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();
- });
- const auto n = static_cast<uint32_t>(::std::distance(first, last));
- if (n > 0)
- {
- const bool gotFrame = EASY_GLOBALS.frame_time > 1e-6f;
- qreal frameCoeff = 1;
- if (gotFrame)
- {
- if (EASY_GLOBALS.frame_time <= m_bottomDuration)
- frameCoeff = m_boundingRect.height();
- else
- frameCoeff = 0.9 / EASY_GLOBALS.frame_time;
- }
- auto const calculate_color = gotFrame ? calculate_color2 : calculate_color1;
- auto const k = gotFrame ? sqr(sqr(frameCoeff)) : 1.0 / m_boundingRect.height();
- const auto draw = [this, &previousColor, &brush, &_painter](qreal x, qreal y, qreal w, qreal h, QRgb color)
- {
- m_spin.lock();
- if (previousColor != color)
- {
- // Set background color brush for rectangle
- previousColor = color;
- brush.setColor(QColor::fromRgba(0xc0000000 | color));
- _painter->setBrush(brush);
- }
- _painter->drawRect(QRectF(x, y, w, h));
- 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)
- {
- qreal previous_x = -1e30, previous_h = -1e30;
- //for (auto it = first, end = items.end(); it != end; ++it)
- for (; it != end; ++it)
- {
- // 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;
- }
- }, begin, i == (n_threads - 1) ? items.end() : begin + n_items);
- }
- for (auto& t : threads)
- t.join();
- }
- }*/
- }
- }
- //if (!m_bReady.load(::std::memory_order_acquire))
- // paintBusyIndicator(_painter, currentScale);
- qreal top_width = width, bottom_width = width;
- int font_h = 0;
- if (!m_topDurationStr.isEmpty())
- {
- 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;
- m_topDurationStr = ::profiler_gui::timeStringReal(m_timeUnits, m_topDuration, 3);
- m_bottomDurationStr = ::profiler_gui::timeStringReal(m_timeUnits, m_bottomDuration, 3);
- }
- auto fm = _painter->fontMetrics();
- font_h = fm.height();
- //bottom_width -= fm.width(m_bottomDurationStr) + 7;
- top_width -= fm.width(m_topDurationStr) + 7;
- _painter->setPen(Qt::black);
- _painter->setPen(m_topDuration < m_maxDuration ? Qt::darkRed : Qt::black);
- _painter->drawText(rect, Qt::AlignRight | Qt::AlignTop, m_topDurationStr);
- rect.setRect(0, bottom, width - 3, font_h);
- _painter->setPen(m_bottomDuration > m_minDuration ? Qt::darkRed : Qt::black);
- _painter->drawText(rect, Qt::AlignRight | Qt::AlignTop, m_bottomDurationStr);
- }
- _painter->setPen(Qt::darkGray);
- _painter->drawLine(QLineF(0, bottom, bottom_width, bottom));
- _painter->drawLine(QLineF(0, m_boundingRect.top(), top_width, m_boundingRect.top()));
- paintMouseIndicator(_painter, m_boundingRect.top(), bottom, width, maxColumnHeight - HIST_COLUMN_MIN_HEIGHT, top_width, m_mouseY, dtime, font_h);
- if (m_bottomDuration < EASY_GLOBALS.frame_time && EASY_GLOBALS.frame_time < m_topDuration)
- {
- // Draw marker displaying required frame_time step
- const auto h = bottom - (EASY_GLOBALS.frame_time - m_bottomDuration) * coeff;
- _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());
- if (!m_selectedBlocks.empty())
- {
- _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")));
- }
- else
- {
- _painter->drawText(rect, Qt::AlignHCenter | Qt::TextDontClip, QString("%1 | %2 | 0 calls").arg(m_threadName).arg(m_blockName));
- }
- _painter->drawText(rect, Qt::AlignLeft, bindMode ? " MODE: zoom" : " MODE: overview");
- _painter->restore();
- }
- ::profiler::thread_id_t EasyHistogramItem::threadId() const
- {
- return m_threadId;
- }
- void EasyHistogramItem::setBoundingRect(const QRectF& _rect)
- {
- m_boundingRect = _rect;
- }
- void EasyHistogramItem::setBoundingRect(qreal x, qreal y, qreal w, qreal h)
- {
- m_boundingRect.setRect(x, y, w, h);
- }
- void EasyHistogramItem::rebuildSource(HistRegime _regime)
- {
- if (m_regime == _regime)
- rebuildSource();
- }
- void EasyHistogramItem::rebuildSource()
- {
- if (m_regime == Hist_Id)
- {
- m_regime = Hist_Pointer;
- setSource(m_threadId, m_blockId);
- }
- else
- {
- m_regime = Hist_Id;
- setSource(m_threadId, m_pSource);
- }
- }
- void EasyHistogramItem::setSource(::profiler::thread_id_t _thread_id, const ::profiler_gui::EasyItems* _items)
- {
- if (m_regime == Hist_Pointer && m_threadId == _thread_id && m_pSource == _items)
- return;
- m_timer.stop();
- m_boundaryTimer.stop();
- m_bReady.store(true, ::std::memory_order_release);
- if (m_workerThread.joinable())
- m_workerThread.join();
- m_blockName.clear();
- m_blockTotalDuraion = 0;
- delete m_workerImage;
- m_workerImage = nullptr;
- m_imageOriginUpdate = m_imageOrigin = 0;
- m_imageScaleUpdate = m_imageScale = 1;
- m_selectedBlocks.clear();
- { ::profiler::BlocksTree::children_t().swap(m_selectedBlocks); }
- m_bPermitImageUpdate = false;
- m_regime = Hist_Pointer;
- m_pSource = _items;
- m_threadId = _thread_id;
- ::profiler_gui::set_max(m_blockId);
- if (m_pSource != nullptr)
- {
- if (m_pSource->empty())
- {
- m_pSource = nullptr;
- }
- else
- {
- const auto& root = EASY_GLOBALS.profiler_blocks[_thread_id];
- m_threadName = ::profiler_gui::decoratedThreadName(EASY_GLOBALS.use_decorated_thread_name, root, EASY_GLOBALS.hex_thread_id);
- 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)
- {
- m_maxDuration = 0;
- m_minDuration = 1e30;
- bool empty = true;
- 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;
- empty = false;
- }
- if ((m_maxDuration - m_minDuration) < 1e-3)
- {
- if (m_minDuration > 0.1)
- {
- m_minDuration -= 0.1;
- }
- else
- {
- m_maxDuration = 0.1;
- m_minDuration = 0;
- }
- }
- m_topDuration = m_maxDuration;
- m_bottomDuration = m_minDuration;
- 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();
- }
- m_bReady.store(true, ::std::memory_order_release);
- }, m_pSource);
- m_timeouts = 3;
- m_timer.start(WORKER_THREAD_CHECK_INTERVAL);
- show();
- }
- }
- if (m_pSource == nullptr)
- {
- m_pProfilerThread = nullptr;
- m_topDurationStr.clear();
- m_bottomDurationStr.clear();
- m_threadName.clear();
- hide();
- }
- }
- void EasyHistogramItem::setSource(::profiler::thread_id_t _thread_id, ::profiler::block_id_t _block_id)
- {
- if (m_regime == Hist_Id && m_threadId == _thread_id && m_blockId == _block_id)
- return;
- 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()
- m_regime = Hist_Id;
- m_timer.stop();
- m_boundaryTimer.stop();
- m_bReady.store(true, ::std::memory_order_release);
- if (m_workerThread.joinable())
- m_workerThread.join();
- m_pSource = nullptr;
- m_topDurationStr.clear();
- m_bottomDurationStr.clear();
- m_blockName.clear();
- m_blockTotalDuraion = 0;
- delete m_workerImage;
- m_workerImage = nullptr;
- m_imageOriginUpdate = m_imageOrigin = 0;
- m_imageScaleUpdate = m_imageScale = 1;
- m_selectedBlocks.clear();
- { ::profiler::BlocksTree::children_t().swap(m_selectedBlocks); }
- m_threadId = _thread_id;
- m_blockId = _block_id;
- if (m_threadId != 0 && !::profiler_gui::is_max(m_blockId))
- {
- m_blockName = ::profiler_gui::toUnicode(easyDescriptor(m_blockId).name());
- const auto& root = EASY_GLOBALS.profiler_blocks[_thread_id];
- 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;
- if (root.children.empty())
- {
- m_threadDuration = 0;
- 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);
- }
- 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_bReady.store(false, ::std::memory_order_release);
- m_workerThread = ::std::thread([this](decltype(root) profiler_thread, ::profiler::block_index_t selected_block, bool _showOnlyTopLevelBlocks)
- {
- typedef ::std::vector<::std::pair<::profiler::block_index_t, ::profiler::block_index_t> > Stack;
- m_maxDuration = 0;
- m_minDuration = 1e30;
- //const auto& profiler_thread = EASY_GLOBALS.profiler_blocks[m_threadId];
- Stack stack;
- stack.reserve(profiler_thread.depth);
- const bool has_selected_block = !::profiler_gui::is_max(selected_block);
- for (auto frame : profiler_thread.children)
- {
- 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);
- const auto w = frame_block.node->duration();
- if (w > m_maxDuration)
- m_maxDuration = w;
- if (w < m_minDuration)
- m_minDuration = w;
- m_blockTotalDuraion += w;
- }
- if (_showOnlyTopLevelBlocks)
- continue;
- stack.push_back(::std::make_pair(frame, 0U));
- while (!stack.empty())
- {
- if (m_bReady.load(::std::memory_order_acquire))
- return;
- 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)
- {
- 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;
- }
- if (!child.children.empty())
- {
- ++top.second;
- stack.push_back(::std::make_pair(child_index, 0U));
- break;
- }
- }
- if (stack_size == stack.size())
- {
- stack.pop_back();
- }
- }
- }
- if (m_selectedBlocks.empty())
- {
- m_topDurationStr.clear();
- m_bottomDurationStr.clear();
- }
- else
- {
- if (has_selected_block)
- {
- const auto& item = easyBlock(selected_block).tree;
- if (*item.node->name() != 0)
- m_blockName = ::profiler_gui::toUnicode(item.node->name());
- }
- m_maxDuration *= 1e-3;
- m_minDuration *= 1e-3;
- if ((m_maxDuration - m_minDuration) < 1e-3)
- {
- if (m_minDuration > 0.1)
- {
- m_minDuration -= 0.1;
- }
- else
- {
- m_maxDuration = 0.1;
- m_minDuration = 0;
- }
- }
- m_topDurationStr = ::profiler_gui::timeStringReal(m_timeUnits, m_maxDuration, 3);
- m_bottomDurationStr = ::profiler_gui::timeStringReal(m_timeUnits, m_minDuration, 3);
- }
- m_topDuration = m_maxDuration;
- m_bottomDuration = m_minDuration;
- m_bReady.store(true, ::std::memory_order_release);
- }, std::ref(root), EASY_GLOBALS.selected_block, EASY_GLOBALS.display_only_frames_on_histogram);
- m_timeouts = 3;
- m_timer.start(WORKER_THREAD_CHECK_INTERVAL);
- }
- show();
- }
- else
- {
- m_pProfilerThread = nullptr;
- m_threadName.clear();
- hide();
- }
- }
- //////////////////////////////////////////////////////////////////////////
- void EasyHistogramItem::validateName()
- {
- if (m_threadName.isEmpty())
- return;
- m_threadName = ::profiler_gui::decoratedThreadName(EASY_GLOBALS.use_decorated_thread_name, EASY_GLOBALS.profiler_blocks[m_threadId], EASY_GLOBALS.hex_thread_id);
- }
- //////////////////////////////////////////////////////////////////////////
- void EasyHistogramItem::onTimeout()
- {
- if (!isVisible())
- {
- m_timer.stop();
- return;
- }
- if (++m_timeouts > 8)
- m_timeouts = 3;
- if (m_bReady.load(::std::memory_order_acquire))
- {
- m_timer.stop();
- if (!m_bPermitImageUpdate)
- {
- // Worker thread have finished parsing input data (when setSource(_block_id) was called)
- m_bPermitImageUpdate = true; // From now we can update an image
- updateImage();
- }
- else
- {
- // Image updated
- if (m_workerThread.joinable())
- m_workerThread.join();
- m_workerImage->swap(m_mainImage);
- delete m_workerImage;
- m_workerImage = nullptr;
- m_imageOriginUpdate = m_imageOrigin = m_workerImageOrigin;
- m_imageScaleUpdate = m_imageScale = m_workerImageScale;
- 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);
- }
- }
- }
- scene()->update();
- }
- //////////////////////////////////////////////////////////////////////////
- void EasyHistogramItem::pickTopBoundary(qreal _y)
- {
- if (m_bPermitImageUpdate && m_boundingRect.top() < _y && _y < m_boundingRect.bottom() && !m_topDurationStr.isEmpty())
- {
- 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
- }
- }
- void EasyHistogramItem::increaseTopBoundary()
- {
- if (m_bPermitImageUpdate && m_topDuration < m_maxDuration && !m_topDurationStr.isEmpty())
- {
- 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
- m_boundaryTimer.stop();
- m_boundaryTimer.start(BOUNDARY_TIMER_INTERVAL);
- }
- }
- void EasyHistogramItem::decreaseTopBoundary()
- {
- if (m_bPermitImageUpdate && m_topDuration > m_bottomDuration && !m_topDurationStr.isEmpty())
- {
- 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
- m_boundaryTimer.stop();
- m_boundaryTimer.start(BOUNDARY_TIMER_INTERVAL);
- }
- }
- }
- //////////////////////////////////////////////////////////////////////////
- void EasyHistogramItem::pickBottomBoundary(qreal _y)
- {
- if (m_bPermitImageUpdate && m_boundingRect.top() < _y && _y < m_boundingRect.bottom() && !m_bottomDurationStr.isEmpty())
- {
- 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
- }
- }
- void EasyHistogramItem::increaseBottomBoundary()
- {
- if (m_bPermitImageUpdate && m_bottomDuration < m_topDuration && !m_bottomDurationStr.isEmpty())
- {
- 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
- m_boundaryTimer.stop();
- m_boundaryTimer.start(BOUNDARY_TIMER_INTERVAL);
- }
- }
- }
- void EasyHistogramItem::decreaseBottomBoundary()
- {
- if (m_bPermitImageUpdate && m_bottomDuration > m_minDuration && !m_bottomDurationStr.isEmpty())
- {
- 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
- m_boundaryTimer.stop();
- m_boundaryTimer.start(BOUNDARY_TIMER_INTERVAL);
- }
- }
- //////////////////////////////////////////////////////////////////////////
- void EasyHistogramItem::setMouseY(qreal _mouseY)
- {
- m_mouseY = _mouseY;
- }
- void EasyHistogramItem::pickFrameTime(qreal _y) const
- {
- if (m_bPermitImageUpdate && m_boundingRect.top() < _y && _y < m_boundingRect.bottom() && !m_topDurationStr.isEmpty())
- {
- EASY_GLOBALS.frame_time = m_bottomDuration + (m_topDuration - m_bottomDuration) * (m_boundingRect.bottom() - _y) / (m_boundingRect.height() - HIST_COLUMN_MIN_HEIGHT);
- emit EASY_GLOBALS.events.expectedFrameTimeChanged();
- }
- }
- //////////////////////////////////////////////////////////////////////////
- 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);
- }
- //////////////////////////////////////////////////////////////////////////
- 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();
- }
- //////////////////////////////////////////////////////////////////////////
- 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);
- delete m_workerImage;
- m_workerImage = nullptr;
- m_imageOriginUpdate = m_imageOrigin;
- m_imageScaleUpdate = m_imageScale;
- m_timer.stop();
- }
- void EasyHistogramItem::updateImage()
- {
- if (!m_bPermitImageUpdate)
- 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);
- delete m_workerImage;
- m_workerImage = nullptr;
- 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,
- bool _bindMode, float _frame_time, ::profiler::timestamp_t _begin_time, qreal _origin, bool _autoAdjustHist)
- {
- updateImage(_boundingRect, _regime, _current_scale, _minimum, _maximum, _range, _value, _width, _top_duration, _bottom_duration, _bindMode, _frame_time, _begin_time, _origin, _autoAdjustHist);
- m_bReady.store(true, ::std::memory_order_release);
- }, m_boundingRect, m_regime, widget->getWindowScale(), widget->minimum(), widget->maximum(), widget->range(), widget->value(), widget->sliderWidth(),
- m_topDuration, m_bottomDuration, widget->bindMode(), EASY_GLOBALS.frame_time, EASY_GLOBALS.begin_time, m_imageOriginUpdate, EASY_GLOBALS.auto_adjust_histogram_height);
- m_timeouts = 3;
- m_timer.start(WORKER_THREAD_CHECK_INTERVAL);
- }
- void EasyHistogramItem::updateImage(QRectF _boundingRect, HistRegime _regime, qreal _current_scale,
- qreal _minimum, qreal _maximum, qreal _range,
- qreal _value, qreal _width, qreal _top_duration, qreal _bottom_duration,
- bool _bindMode, float _frame_time, ::profiler::timestamp_t _begin_time,
- qreal _origin, bool _autoAdjustHist)
- {
- 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)
- {
- m_workerImageScale = viewScale;
- m_workerImageOrigin = _value - _width * 3;
- m_workerImage = new QImage(screenWidth * 7 + 0.5, _boundingRect.height(), QImage::Format_ARGB32);
- }
- else
- {
- m_workerImageScale = 1;
- m_workerImageOrigin = _minimum;
- m_workerImage = new QImage(screenWidth + 0.5, _boundingRect.height(), QImage::Format_ARGB32);
- }
- m_workerImage->fill(0);
- QPainter p(m_workerImage);
- 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-6f;
- qreal frameCoeff = 1;
- if (gotFrame)
- {
- if (_frame_time <= _bottom_duration)
- frameCoeff = _boundingRect.height();
- else
- frameCoeff = 0.9 / _frame_time;
- }
- auto const calculate_color = gotFrame ? calculate_color2 : calculate_color1;
- auto const k = gotFrame ? sqr(sqr(frameCoeff)) : 1.0 / _boundingRect.height();
- if (_regime == Hist_Pointer)
- {
- const auto& items = *m_pSource;
- if (items.empty())
- return;
- auto first = items.begin();
- if (_bindMode)
- {
- _minimum = m_workerImageOrigin;
- _maximum = m_workerImageOrigin + _width * 7;
- 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;
- }
- 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;
- }
- }
- }
- }
- }
- const auto dtime = _top_duration - _bottom_duration;
- const auto coeff = (_boundingRect.height() - HIST_COLUMN_MIN_HEIGHT) / (dtime > 1e-3 ? dtime : 1.);
- 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;
- 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));
- if (h < previous_h && item_r < previous_x)
- continue;
- const auto col = calculate_color(h, it->width(), k);
- 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
- {
- auto first = m_selectedBlocks.begin();
- if (_bindMode)
- {
- _minimum = m_workerImageOrigin;
- _maximum = m_workerImageOrigin + _width * 7;
- 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;
- }
- _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;
- }
- const auto dtime = _top_duration - _bottom_duration;
- const auto coeff = (_boundingRect.height() - HIST_COLUMN_MIN_HEIGHT) / (dtime > 1e-3 ? dtime : 1.);
- for (auto it = first, end = m_selectedBlocks.end(); it != end; ++it)
- {
- // Draw rectangle
- const auto item = easyBlock(*it).tree.node;
- const auto beginTime = item->begin() - _begin_time;
- if (beginTime > _maximum)
- break;
- const auto endTime = item->end() - _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 auto h = duration <= _bottom_duration ? HIST_COLUMN_MIN_HEIGHT :
- (duration > _top_duration ? maxColumnHeight : (HIST_COLUMN_MIN_HEIGHT + (duration - _bottom_duration) * 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();
- 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;
- }
- }
- m_workerTopDuration = _top_duration;
- m_workerBottomDuration = _bottom_duration;
- }
- //////////////////////////////////////////////////////////////////////////
- EasyGraphicsScrollbar::EasyGraphicsScrollbar(QWidget* _parent)
- : Parent(_parent)
- , m_minimumValue(0)
- , m_maximumValue(500)
- , m_value(10)
- , m_windowScale(1)
- , m_mouseButtons(Qt::NoButton)
- , m_slider(nullptr)
- , m_chronometerIndicator(nullptr)
- , m_histogramItem(nullptr)
- , m_defaultFontHeight(0)
- , m_bScrolling(false)
- , m_bBindMode(false)
- , m_bLocked(false)
- {
- setCacheMode(QGraphicsView::CacheNone);
- setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
- //setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate);
- setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
- setOptimizationFlag(QGraphicsView::DontSavePainterState, true);
- setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
- setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
- setContentsMargins(0, 0, 0, 0);
- auto selfScene = new QGraphicsScene(this);
- m_defaultFontHeight = QFontMetrics(selfScene->font()).height();
- selfScene->setSceneRect(0, DEFAULT_TOP, 500, DEFAULT_HEIGHT + m_defaultFontHeight + 2);
- setFixedHeight(DEFAULT_HEIGHT + m_defaultFontHeight + 2);
- setScene(selfScene);
- 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();
- m_chronometerIndicator = new EasyGraphicsSliderItem(false);
- m_chronometerIndicator->setPos(0, 0);
- m_chronometerIndicator->setColor(0x40000000 | ::profiler_gui::CHRONOMETER_COLOR.rgba());
- selfScene->addItem(m_chronometerIndicator);
- m_chronometerIndicator->hide();
- m_slider = new EasyGraphicsSliderItem(true);
- m_slider->setPos(0, 0);
- m_slider->setColor(0x40c0c0c0);
- selfScene->addItem(m_slider);
- m_slider->hide();
- connect(&EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::expectedFrameTimeChanged, [this]()
- {
- if (m_histogramItem->isVisible())
- {
- m_histogramItem->updateImage();
- scene()->update();
- }
- });
- connect(&EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::autoAdjustHistogramChanged, [this]()
- {
- if (m_histogramItem->isVisible())
- m_histogramItem->onModeChanged();
- });
- connect(&EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::displayOnlyFramesOnHistogramChanged, [this]()
- {
- if (m_histogramItem->isVisible())
- m_histogramItem->rebuildSource(EasyHistogramItem::Hist_Id);
- });
- connect(&EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::threadNameDecorationChanged, this, &This::onThreadViewChanged);
- connect(&EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::hexThreadIdChanged, this, &This::onThreadViewChanged);
- centerOn(0, 0);
- }
- EasyGraphicsScrollbar::~EasyGraphicsScrollbar()
- {
- }
- //////////////////////////////////////////////////////////////////////////
- void EasyGraphicsScrollbar::onThreadViewChanged()
- {
- if (m_histogramItem->isVisible())
- {
- m_histogramItem->validateName();
- scene()->update();
- }
- }
- //////////////////////////////////////////////////////////////////////////
- void EasyGraphicsScrollbar::clear()
- {
- setHistogramSource(0, nullptr);
- hideChrono();
- setRange(0, 100);
- setSliderWidth(2);
- setValue(0);
- }
- //////////////////////////////////////////////////////////////////////////
- bool EasyGraphicsScrollbar::bindMode() const
- {
- return m_bBindMode;
- }
- qreal EasyGraphicsScrollbar::getWindowScale() const
- {
- return m_windowScale;
- }
- ::profiler::thread_id_t EasyGraphicsScrollbar::hystThread() const
- {
- return m_histogramItem->threadId();
- }
- qreal EasyGraphicsScrollbar::minimum() const
- {
- return m_minimumValue;
- }
- qreal EasyGraphicsScrollbar::maximum() const
- {
- return m_maximumValue;
- }
- qreal EasyGraphicsScrollbar::range() const
- {
- return m_maximumValue - m_minimumValue;
- }
- qreal EasyGraphicsScrollbar::value() const
- {
- return m_value;
- }
- qreal EasyGraphicsScrollbar::sliderWidth() const
- {
- return m_slider->width();
- }
- qreal EasyGraphicsScrollbar::sliderHalfWidth() const
- {
- return m_slider->halfwidth();
- }
- int EasyGraphicsScrollbar::defaultFontHeight() const
- {
- return m_defaultFontHeight;
- }
- //////////////////////////////////////////////////////////////////////////
- void EasyGraphicsScrollbar::setValue(qreal _value)
- {
- m_value = clamp(m_minimumValue, _value, ::std::max(m_minimumValue, m_maximumValue - m_slider->width()));
- m_slider->setX(m_value + m_slider->halfwidth());
- emit valueChanged(m_value);
- if (m_histogramItem->isVisible())
- m_histogramItem->onValueChanged();
- }
- void EasyGraphicsScrollbar::setRange(qreal _minValue, qreal _maxValue)
- {
- const auto oldRange = range();
- const auto oldValue = oldRange < 1e-3 ? 0.0 : m_value / oldRange;
- m_minimumValue = _minValue;
- m_maximumValue = _maxValue;
- scene()->setSceneRect(_minValue, DEFAULT_TOP, _maxValue - _minValue, DEFAULT_HEIGHT + m_defaultFontHeight + 4);
- m_histogramItem->cancelImageUpdate();
- m_histogramItem->setBoundingRect(_minValue, DEFAULT_TOP + INDICATOR_SIZE, _maxValue, DEFAULT_HEIGHT - INDICATOR_SIZE_x2);
- emit rangeChanged();
- setValue(_minValue + oldValue * range());
- onWindowWidthChange(width());
- if (m_histogramItem->isVisible())
- m_histogramItem->updateImage();
- }
- void EasyGraphicsScrollbar::setSliderWidth(qreal _width)
- {
- m_slider->setWidth(_width);
- setValue(m_value);
- }
- //////////////////////////////////////////////////////////////////////////
- void EasyGraphicsScrollbar::setChronoPos(qreal _left, qreal _right)
- {
- m_chronometerIndicator->setWidth(_right - _left);
- m_chronometerIndicator->setX(_left + m_chronometerIndicator->halfwidth());
- }
- void EasyGraphicsScrollbar::showChrono()
- {
- m_chronometerIndicator->show();
- }
- void EasyGraphicsScrollbar::hideChrono()
- {
- m_chronometerIndicator->hide();
- }
- //////////////////////////////////////////////////////////////////////////
- void EasyGraphicsScrollbar::setHistogramSource(::profiler::thread_id_t _thread_id, const ::profiler_gui::EasyItems* _items)
- {
- if (m_bLocked)
- return;
- m_histogramItem->setSource(_thread_id, _items);
- m_slider->setVisible(m_histogramItem->isVisible());
- scene()->update();
- }
- void EasyGraphicsScrollbar::setHistogramSource(::profiler::thread_id_t _thread_id, ::profiler::block_id_t _block_id)
- {
- if (m_bLocked)
- return;
- m_histogramItem->setSource(_thread_id, _block_id);
- m_slider->setVisible(m_histogramItem->isVisible());
- scene()->update();
- }
- //////////////////////////////////////////////////////////////////////////
- void EasyGraphicsScrollbar::mousePressEvent(QMouseEvent* _event)
- {
- _event->accept();
- m_mouseButtons = _event->buttons();
- if (m_mouseButtons & Qt::LeftButton)
- {
- if (_event->modifiers() & Qt::ControlModifier)
- {
- m_histogramItem->pickBottomBoundary(mapToScene(_event->pos()).y());
- }
- else if (_event->modifiers() & Qt::ShiftModifier)
- {
- m_histogramItem->pickTopBoundary(mapToScene(_event->pos()).y());
- }
- else
- {
- m_bScrolling = true;
- m_mousePressPos = _event->pos();
- if (!m_bBindMode)
- setValue(mapToScene(m_mousePressPos).x() - m_minimumValue - m_slider->halfwidth());
- }
- }
- if (m_mouseButtons & Qt::RightButton)
- {
- if (_event->modifiers())
- {
- m_histogramItem->pickFrameTime(mapToScene(_event->pos()).y());
- }
- else
- {
- m_bBindMode = !m_bBindMode;
- if (m_histogramItem->isVisible())
- m_histogramItem->onModeChanged();
- }
- }
- //QGraphicsView::mousePressEvent(_event);
- }
- void EasyGraphicsScrollbar::mouseReleaseEvent(QMouseEvent* _event)
- {
- m_mouseButtons = _event->buttons();
- m_bScrolling = false;
- _event->accept();
- //QGraphicsView::mouseReleaseEvent(_event);
- }
- void EasyGraphicsScrollbar::mouseMoveEvent(QMouseEvent* _event)
- {
- const auto pos = _event->pos();
- if (m_mouseButtons & Qt::LeftButton)
- {
- const auto delta = pos - m_mousePressPos;
- m_mousePressPos = pos;
- if (m_bScrolling)
- {
- auto realScale = m_windowScale;
- if (m_bBindMode)
- realScale *= -range() / sliderWidth();
- setValue(m_value + delta.x() / realScale);
- }
- }
- if (m_histogramItem->isVisible())
- {
- m_histogramItem->setMouseY(mapToScene(pos).y());
- scene()->update();
- }
- }
- void EasyGraphicsScrollbar::wheelEvent(QWheelEvent* _event)
- {
- _event->accept();
- 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;
- }
- 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());
- }
- }
- void EasyGraphicsScrollbar::resizeEvent(QResizeEvent* _event)
- {
- onWindowWidthChange(_event->size().width());
- if (m_histogramItem->isVisible())
- m_histogramItem->updateImage();
- }
- //////////////////////////////////////////////////////////////////////////
- void EasyGraphicsScrollbar::onWindowWidthChange(qreal _width)
- {
- 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);
- }
- //////////////////////////////////////////////////////////////////////////
|