0
0
mirror of https://github.com/yse/easy_profiler.git synced 2024-12-27 08:41:02 +08:00

#31 [Gui] Big update for arbitrary values viewer. It is now viable and can be used to inspect user metrics. Currently arbitrary values viewer is built into blocks list widget.

This commit is contained in:
Victor Zarubkin 2018-01-21 19:37:44 +03:00
parent 694497b5ca
commit a7a58acd1d
22 changed files with 951 additions and 528 deletions

View File

@ -303,9 +303,11 @@ EASY_FORCE_INLINE T unaligned_load64(const void* ptr, T* val)
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
template <uint16_t N> template <const uint16_t N>
class chunk_allocator class chunk_allocator
{ {
static_assert(N != 0, "chunk_allocator<N> N must be a positive value");
struct chunk { EASY_ALIGNED(char, data[N], EASY_ALIGNMENT_SIZE); chunk* prev = nullptr; }; struct chunk { EASY_ALIGNED(char, data[N], EASY_ALIGNMENT_SIZE); chunk* prev = nullptr; };
struct chunk_list struct chunk_list
@ -380,8 +382,8 @@ class chunk_allocator
}; };
// Used in serialize(): workaround for no constexpr support in MSVC 2013. // Used in serialize(): workaround for no constexpr support in MSVC 2013.
EASY_STATIC_CONSTEXPR int_fast32_t MAX_CHUNK_OFFSET = N - sizeof(uint16_t); EASY_STATIC_CONSTEXPR int_fast32_t MaxChunkOffset = N - sizeof(uint16_t);
EASY_STATIC_CONSTEXPR uint16_t N_MINUS_ONE = N - 1; EASY_STATIC_CONSTEXPR uint16_t OneBeforeN = static_cast<uint16_t>(N - 1);
chunk_list m_chunks; ///< List of chunks. chunk_list m_chunks; ///< List of chunks.
chunk* m_markedChunk; ///< Chunk marked by last closed frame chunk* m_markedChunk; ///< Chunk marked by last closed frame
@ -421,7 +423,7 @@ public:
// If there is enough space for at least another payload size, // If there is enough space for at least another payload size,
// set it to zero. // set it to zero.
if (chunkOffset < N_MINUS_ONE) if (chunkOffset < OneBeforeN)
unaligned_zero16(data + n); unaligned_zero16(data + n);
return data; return data;
@ -503,7 +505,7 @@ public:
isMarked = (current == m_markedChunk); isMarked = (current == m_markedChunk);
const char* data = current->data; const char* data = current->data;
const int_fast32_t maxOffset = isMarked ? m_markedChunkOffset : MAX_CHUNK_OFFSET; const int_fast32_t maxOffset = isMarked ? m_markedChunkOffset : MaxChunkOffset;
int_fast32_t chunkOffset = 0; // signed int so overflow is not checked. int_fast32_t chunkOffset = 0; // signed int so overflow is not checked.
auto payloadSize = unaligned_load16<uint16_t>(data); auto payloadSize = unaligned_load16<uint16_t>(data);
@ -555,7 +557,7 @@ public:
// If there is enough space for at least another payload size, // If there is enough space for at least another payload size,
// set it to zero. // set it to zero.
if (chunkOffset < N_MINUS_ONE) if (chunkOffset < OneBeforeN)
unaligned_zero16(data + n); unaligned_zero16(data + n);
if (marked == m_chunks.last && chunkOffset > m_chunkOffset) if (marked == m_chunks.last && chunkOffset > m_chunkOffset)

View File

@ -95,6 +95,9 @@ public:
EASY_CONSTEXPR uint16_t SIZEOF_BLOCK = sizeof(profiler::BaseBlockData) + 1 + sizeof(uint16_t); // SerializedBlock stores BaseBlockData + at least 1 character for name ('\0') + 2 bytes for size of serialized data EASY_CONSTEXPR uint16_t SIZEOF_BLOCK = sizeof(profiler::BaseBlockData) + 1 + sizeof(uint16_t); // SerializedBlock stores BaseBlockData + at least 1 character for name ('\0') + 2 bytes for size of serialized data
EASY_CONSTEXPR uint16_t SIZEOF_CSWITCH = sizeof(profiler::CSwitchEvent) + 1 + sizeof(uint16_t); // SerializedCSwitch also stores additional 4 bytes to be able to save 64-bit thread_id EASY_CONSTEXPR uint16_t SIZEOF_CSWITCH = sizeof(profiler::CSwitchEvent) + 1 + sizeof(uint16_t); // SerializedCSwitch also stores additional 4 bytes to be able to save 64-bit thread_id
static_assert((int)SIZEOF_BLOCK * 128 < 65536, "Chunk size for profiler::Block must be less than 65536");
static_assert((int)SIZEOF_CSWITCH * 128 < 65536, "Chunk size for CSwitchBlock must be less than 65536");
struct ThreadStorage EASY_FINAL struct ThreadStorage EASY_FINAL
{ {
StackBuffer<NonscopedBlock> nonscopedBlocks; StackBuffer<NonscopedBlock> nonscopedBlocks;

View File

@ -57,8 +57,10 @@
#include <QColor> #include <QColor>
#include <QHeaderView> #include <QHeaderView>
#include <QVBoxLayout> #include <QVBoxLayout>
#include <QSplitter>
#include <QResizeEvent> #include <QResizeEvent>
#include <QVariant> #include <QVariant>
#include <QSettings>
#include <list> #include <list>
#include "arbitrary_value_inspector.h" #include "arbitrary_value_inspector.h"
#include "treeview_first_column_delegate.h" #include "treeview_first_column_delegate.h"
@ -387,269 +389,504 @@ QPointF ArbitraryValuesCollection::point(const profiler::ArbitraryValue& _value)
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
EasyArbitraryValuesChartItem::EasyArbitraryValuesChartItem() ArbitraryValuesChartItem::ArbitraryValuesChartItem()
: Parent(nullptr) : Parent()
, m_workerMaxValue(0)
, m_workerMinValue(0)
{ {
} }
EasyArbitraryValuesChartItem::~EasyArbitraryValuesChartItem() ArbitraryValuesChartItem::~ArbitraryValuesChartItem()
{ {
} }
void EasyArbitraryValuesChartItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*, QWidget*) void ArbitraryValuesChartItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*, QWidget*)
{ {
if (m_collections.empty()) const auto widget = static_cast<const GraphicsSliderArea*>(scene()->parent());
return; const auto currentScale = widget->getWindowScale();
const bool bindMode = widget->bindMode();
const auto& chart = *reinterpret_cast<const EasyGraphicsChart*>(scene()->parent()); const auto bottom = m_boundingRect.bottom();
const auto scale = chart.xscale(); const auto width = m_boundingRect.width() * currentScale;
qreal minValue = 1e300, maxValue = -1e300;
for (const auto& c : m_collections)
{
const auto& collection = *c.ptr;
if (minValue > collection.minValue())
minValue = collection.minValue();
if (maxValue < collection.maxValue())
maxValue = collection.maxValue();
}
const qreal height = std::max(maxValue - minValue, 1.);
auto r = scene()->sceneRect();
_painter->save(); _painter->save();
_painter->setTransform(QTransform::fromScale(1.0 / currentScale, 1), true);
for (const auto& c : m_collections) if (!bindMode)
{ paintImage(_painter);
const auto& points = c.ptr->points();
if (points.empty())
continue;
if (c.selected)
{
auto pen = _painter->pen();
pen.setColor(QColor::fromRgba(c.color));
pen.setWidth(3);
_painter->setPen(pen);
}
else else
paintImage(_painter, currentScale, widget->minimum(), widget->maximum(), widget->value(), widget->sliderWidth());
const auto font_h = widget->fontHeight();
QRectF rect(0, m_boundingRect.top() - widget->margin(), width - 3, m_boundingRect.height() + widget->margins());
_painter->setPen(profiler_gui::TEXT_COLOR);
_painter->drawText(rect, Qt::AlignLeft | Qt::AlignTop, bindMode ? " Mode: Zoom" : " Mode: Overview");
if (!EASY_GLOBALS.scene.empty)
{ {
_painter->setPen(QColor::fromRgba(c.color)); const auto range = bindMode ? widget->sliderWidth() : widget->range();
paintMouseIndicator(_painter, m_boundingRect.top(), bottom, width, m_boundingRect.height(), font_h,
widget->value(), range);
} }
if (points.size() == 1) _painter->setPen(Qt::darkGray);
_painter->drawPoint(points.front()); _painter->drawLine(QLineF(0, bottom, width, bottom));
else _painter->drawLine(QLineF(0, m_boundingRect.top(), width, m_boundingRect.top()));
{
auto gety = [&r, &minValue, &maxValue, &height] (qreal y)
{
y = maxValue - y;
y /= height;
y *= r.height() - 10;
y += r.top() + 5;
return y;
};
if (c.chartType == ChartType::Points)
{
for (const auto& p : points)
_painter->drawPoint(QPointF {p.x() * scale, gety(p.y())});
}
else
{
QPointF p1 = points.front();
for (int i = 1; i < points.size(); ++i)
{
const auto& p2 = points[i];
_painter->drawLine(QPointF {p1.x() * scale, gety(p1.y())}, QPointF {p2.x() * scale, gety(p2.y())});
p1 = p2;
}
}
//_painter->drawPolyline(points.data(), static_cast<int>(points.size()));
}
}
_painter->restore(); _painter->restore();
} }
QRectF EasyArbitraryValuesChartItem::boundingRect() const void ArbitraryValuesChartItem::paintMouseIndicator(QPainter* _painter, qreal _top, qreal _bottom, qreal _width, qreal _height,
int _font_h, qreal _visibleRegionLeft, qreal _visibleRegionWidth)
{ {
return m_boundingRect; if (_font_h == 0)
return;
const auto x = m_mousePos.x();
const auto y = m_mousePos.y();
// Horizontal
const bool visibleY = (_top < y && y < _bottom);
if (visibleY)
{
const int half_font_h = _font_h >> 1;
const auto value = m_minValue + ((_bottom - 2 - y) / (_height - 4)) * (m_maxValue - m_minValue);
const auto mouseStr = QString::number(value, 'f', 3);
const int textWidth = _painter->fontMetrics().width(mouseStr) + 3;
const QRectF rect(0, y - _font_h - 2, _width, 4 + (_font_h << 1));
_painter->setPen(Qt::blue);
qreal left = 0, right = _width;
const Qt::AlignmentFlag alignment = x < textWidth ? Qt::AlignRight : Qt::AlignLeft;
if (y > _bottom - half_font_h)
{
_painter->drawText(rect, alignment | Qt::AlignTop, mouseStr);
}
else if (y < _top + half_font_h)
{
_painter->drawText(rect, alignment | Qt::AlignBottom, mouseStr);
}
else
{
_painter->drawText(rect, alignment | Qt::AlignVCenter, mouseStr);
if (x < textWidth)
right = _width - textWidth;
else
left = textWidth;
}
_painter->drawLine(QLineF(left, y, right, y));
}
// Vertical
if (0 < x && x < m_boundingRect.width())
{
const auto value = _visibleRegionLeft + _visibleRegionWidth * x / _width;
const auto mouseStr = profiler_gui::timeStringReal(EASY_GLOBALS.time_units, value, 3);
const int textWidth = _painter->fontMetrics().width(mouseStr) + 6;
const int textWidthHalf = textWidth >> 1;
qreal left = x - textWidthHalf;
if (x < textWidthHalf)
left = 0;
else if (x > (_width - textWidthHalf))
left = _width - textWidth;
if (!visibleY)
_painter->setPen(Qt::blue);
const QRectF rect(left, _bottom + 2, textWidth, _font_h);
_painter->drawText(rect, Qt::AlignCenter, mouseStr);
_painter->drawLine(QLineF(x, _top, x, _bottom));
}
} }
void EasyArbitraryValuesChartItem::setBoundingRect(const QRectF& _rect) bool ArbitraryValuesChartItem::updateImage()
{ {
m_boundingRect = _rect; if (!Parent::updateImage())
return false;
const auto widget = static_cast<const GraphicsSliderArea*>(scene()->parent());
m_imageScaleUpdate = widget->range() / widget->sliderWidth();
m_imageOriginUpdate = widget->bindMode() ? (widget->value() - widget->sliderWidth() * 3) : widget->minimum();
m_workerThread = std::thread(&This::updateImageAsync, this, m_boundingRect, widget->getWindowScale(),
widget->minimum(), widget->maximum(), widget->range(), widget->value(), widget->sliderWidth(),
widget->bindMode(), EASY_GLOBALS.begin_time, EASY_GLOBALS.auto_adjust_chart_height);
return true;
} }
void EasyArbitraryValuesChartItem::setBoundingRect(qreal _left, qreal _top, qreal _width, qreal _height) void ArbitraryValuesChartItem::onImageUpdated()
{ {
m_boundingRect.setRect(_left, _top, _width, _height); m_maxValue = m_workerMaxValue;
m_minValue = m_workerMinValue;
} }
void EasyArbitraryValuesChartItem::update(Collections _collections) void ArbitraryValuesChartItem::updateImageAsync(QRectF _boundingRect, qreal _current_scale, qreal _minimum, qreal _maximum, qreal _range,
qreal _value, qreal _width, bool _bindMode, profiler::timestamp_t _begin_time, bool _autoAdjust)
{ {
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.setBrush(Qt::NoBrush);
p.setRenderHint(QPainter::Antialiasing, true);
// Draw grid
{
auto pen = p.pen();
pen.setColor(Qt::darkGray);
pen.setStyle(Qt::DotLine);
p.setPen(pen);
const int left = 0;
const int top = 0;
const int w = m_workerImage->width();
const int h = m_workerImage->height();
const int hlines = h / 20;
for (int i = 0; i < hlines; ++i)
{
const auto y = top + 20 + i * 20;
p.drawLine(left, y, left + w, y);
}
const int vlines = w / 20;
for (int i = 0; i < vlines; ++i)
{
const auto x = left + 20 + i * 20;
p.drawLine(x, top, x, top + h);
}
p.setPen(Qt::SolidLine);
}
if (m_collections.empty() || isReady())
{
setReady(true);
return;
}
using LeftBounds = std::vector<Points::const_iterator>;
qreal realScale = _current_scale, offset = 0;
LeftBounds leftBounds;
leftBounds.reserve(m_collections.size());
if (_bindMode)
{
_minimum = m_workerImageOrigin;
_maximum = m_workerImageOrigin + _width * 7;
realScale *= viewScale;
offset = _minimum * realScale;
}
const auto right = std::min(_value + _width, _maximum);
qreal minValue = 1e300, maxValue = -1e300;
for (const auto& c : m_collections)
{
if (isReady())
return;
const auto& collection = *c.ptr;
const auto& points = collection.points();
if (points.empty())
{
leftBounds.emplace_back(points.end());
continue;
}
if (_bindMode)
{
auto first = std::lower_bound(points.begin(), points.end(), _minimum, [](const QPointF& point, qreal x)
{
return point.x() < x;
});
if (first != points.end())
{
if (first != points.begin())
--first;
}
else
{
first = points.begin() + points.size() - 1;
}
leftBounds.emplace_back(first);
if (_autoAdjust)
{
for (auto it = first; it != points.end() && it->x() < right; ++it)
{
if (it->x() < _value)
continue;
const auto value = it->y();
if (minValue > value)
minValue = value;
if (maxValue < value)
maxValue = value;
}
continue;
}
}
else
{
leftBounds.emplace_back(points.begin());
}
if (minValue > collection.minValue())
minValue = collection.minValue();
if (maxValue < collection.maxValue())
maxValue = collection.maxValue();
}
if (minValue > maxValue)
{
// No points
m_workerMinValue = 0;
m_workerMaxValue = 0;
setReady(true);
return;
}
m_workerMinValue = minValue;
m_workerMaxValue = maxValue;
if (isReady())
return;
const bool singleValue = fabs(maxValue - minValue) < 2 * std::numeric_limits<qreal>::epsilon();
const auto middle = _boundingRect.height() * 0.5;
const qreal height = std::max(maxValue - minValue, 0.01);
const auto gety = [&_boundingRect, maxValue, height, singleValue, middle] (qreal y)
{
if (singleValue)
{
y = middle;
}
else
{
y = maxValue - y;
y /= height;
y *= _boundingRect.height() - 4;
y += 2;
}
return y;
};
size_t i = 0;
for (const auto& c : m_collections)
{
if (isReady())
return;
const auto& points = c.ptr->points();
if (points.empty())
{
++i;
continue;
}
if (c.selected)
{
auto pen = p.pen();
pen.setColor(QColor::fromRgba(c.color));
pen.setWidth(2);
p.setPen(pen);
}
else
{
p.setPen(QColor::fromRgba(c.color));
}
const auto first = leftBounds[i];
if (c.chartType == ChartType::Points)
{
for (auto it = first; it != points.end() && it->x() < _maximum; ++it)
{
if (it->x() < _minimum)
continue;
if (isReady())
return;
const qreal x = it->x() * realScale - offset;
const qreal y = gety(it->y());
p.drawPoint(QPointF {x, y});
}
}
else if (first != points.end() && first->x() < _maximum)
{
QPointF p1 = *first;
qreal x = p1.x() * realScale - offset;
qreal y = gety(p1.y());
p1.setX(x);
p1.setY(y);
auto it = first;
for (++it; it != points.end(); ++it)
{
if (isReady())
return;
QPointF p2 = *it;
x = p2.x() * realScale - offset;
y = gety(p2.y());
p2.setX(x);
p2.setY(y);
if (it->x() >= _minimum)
p.drawLine(p1, p2);
if (it->x() >= _maximum)
break;
p1 = p2;
}
}
if (c.selected)
{
auto color = profiler_gui::darken(c.color, 0.65f);
if (profiler_gui::alpha(color) < 0xc0)
p.setPen(QColor::fromRgba(profiler::colors::modify_alpha32(0xc0000000, color)));
else
p.setPen(QColor::fromRgba(color));
p.setBrush(QColor::fromRgba(0xc0ffffff));
qreal prevX = -offset * 2, prevY = -500;
for (auto it = first; it != points.end() && it->x() < _maximum; ++it)
{
if (it->x() < _minimum)
continue;
if (isReady())
return;
const qreal x = it->x() * realScale - offset;
const qreal y = gety(it->y());
const auto dx = x - prevX, dy = y - prevY;
const auto delta = estd::sqr(dx) + estd::sqr(dy);
if (delta > 25)
{
p.drawEllipse(QPointF {x, y}, 3, 3);
prevX = x;
prevY = y;
}
}
}
++i;
}
setReady(true);
}
void ArbitraryValuesChartItem::clear()
{
cancelAnyJob();
m_boundaryTimer.stop();
m_collections.clear();
m_minValue = m_maxValue = 0;
}
void ArbitraryValuesChartItem::update(Collections _collections)
{
cancelImageUpdate();
m_collections = std::move(_collections); m_collections = std::move(_collections);
updateImage();
} }
void EasyArbitraryValuesChartItem::update(const ArbitraryValuesCollection* _selected) void ArbitraryValuesChartItem::update(const ArbitraryValuesCollection* _selected)
{ {
cancelImageUpdate();
for (auto& collection : m_collections) for (auto& collection : m_collections)
collection.selected = collection.ptr == _selected; collection.selected = collection.ptr == _selected;
updateImage();
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
EasyGraphicsChart::EasyGraphicsChart(QWidget* _parent) GraphicsChart::GraphicsChart(QWidget* _parent)
: Parent(_parent) : Parent(_parent)
, m_chartItem(new EasyArbitraryValuesChartItem()) , m_chartItem(new ArbitraryValuesChartItem())
, m_left(0)
, m_right(100)
, m_offset(0)
, m_xscale(1)
, m_visibleRegionWidth(100)
, m_bBindMode(false)
{ {
setCacheMode(QGraphicsView::CacheNone); m_imageItem = m_chartItem;
setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
//setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate);
setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
setOptimizationFlag(QGraphicsView::DontSavePainterState, true);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setContentsMargins(0, 0, 0, 0);
setScene(new QGraphicsScene(this));
scene()->setSceneRect(0, -250, 500, 500);
scene()->addItem(m_chartItem); scene()->addItem(m_chartItem);
connect(&EASY_GLOBALS.events, &profiler_gui::EasyGlobalSignals::sceneSizeChanged, const auto rect = scene()->sceneRect();
this, &This::onSceneSizeChanged, Qt::QueuedConnection); m_chartItem->setPos(0, 0);
m_chartItem->setBoundingRect(0, rect.top() + margin(), scene()->width(), rect.height() - margins() - 1);
onSceneSizeChanged(); connect(&EASY_GLOBALS.events, &profiler_gui::EasyGlobalSignals::autoAdjustChartChanged, [this]
{
if (m_chartItem->isVisible())
m_chartItem->onModeChanged();
});
if (!EASY_GLOBALS.scene.empty)
{
setRange(EASY_GLOBALS.scene.left, EASY_GLOBALS.scene.right);
setSliderWidth(EASY_GLOBALS.scene.window);
setValue(EASY_GLOBALS.scene.offset);
m_slider->show();
}
m_chartItem->updateImage();
} }
EasyGraphicsChart::~EasyGraphicsChart() GraphicsChart::~GraphicsChart()
{ {
} }
void EasyGraphicsChart::onSceneSizeChanged() void GraphicsChart::clear()
{ {
setRange(EASY_GLOBALS.scene_left, EASY_GLOBALS.scene_right); m_chartItem->clear();
Parent::clear();
} }
void EasyGraphicsChart::resizeEvent(QResizeEvent* _event) void GraphicsChart::update(Collections _collections)
{
auto size = _event->size();
onWindowSizeChanged(size.width(), size.height());
scene()->update();
}
void EasyGraphicsChart::clear()
{
m_chartItem->update(Collections {});
}
bool EasyGraphicsChart::bindMode() const
{
return m_bBindMode;
}
qreal EasyGraphicsChart::xscale() const
{
return m_xscale;
}
qreal EasyGraphicsChart::left() const
{
return m_left;
}
qreal EasyGraphicsChart::right() const
{
return m_right;
}
qreal EasyGraphicsChart::range() const
{
return m_right - m_left;
}
qreal EasyGraphicsChart::offset() const
{
return m_bBindMode ? m_offset : 0;
}
qreal EasyGraphicsChart::region() const
{
return m_bBindMode ? m_visibleRegionWidth : range();
}
void EasyGraphicsChart::setOffset(qreal _offset)
{
m_offset = std::min(std::max(m_left, m_offset), m_right - m_visibleRegionWidth);
}
void EasyGraphicsChart::setRange(qreal _left, qreal _right)
{
const auto oldRange = range();
const auto oldOffsetPart = oldRange < 1e-3 ? 0.0 : m_offset / oldRange;
m_left = _left;
m_right = _right;
if (m_left > m_right)
std::swap(m_left, m_right);
const auto sceneRange = range();
//scene()->setSceneRect(m_left, -(height() >> 1), sceneRange, height());
//m_chartItem->setBoundingRect(scene()->sceneRect());
m_offset = m_left + oldOffsetPart * sceneRange;
m_visibleRegionWidth = std::min(m_visibleRegionWidth, sceneRange);
//const auto oldXScale = m_xscale;
m_xscale = sceneRange < 1e-3 ? 1.0 : width() / sceneRange;
//scale(m_xscale / oldXScale, 1);
scene()->update();
}
void EasyGraphicsChart::setRegion(qreal _visibleRegionWidth)
{
m_visibleRegionWidth = std::min(_visibleRegionWidth, range());
setOffset(m_offset);
}
void EasyGraphicsChart::onWindowSizeChanged(qreal _width, qreal _height)
{
//const auto oldXScale = m_xscale;
const auto sceneRange = range();
m_xscale = sceneRange < 1e-3 ? 1.0 : _width / sceneRange;
scene()->setSceneRect(0, -_height * 0.5, _width, _height);
//scene()->setSceneRect(m_left, -_height * 0.5, sceneRange, _height);
m_chartItem->setBoundingRect(scene()->sceneRect());
//scale(m_xscale / oldXScale, 1);
}
void EasyGraphicsChart::update(Collections _collections)
{ {
m_chartItem->update(std::move(_collections)); m_chartItem->update(std::move(_collections));
scene()->update();
} }
void EasyGraphicsChart::update(const ArbitraryValuesCollection* _selected) void GraphicsChart::update(const ArbitraryValuesCollection* _selected)
{ {
m_chartItem->update(_selected); m_chartItem->update(_selected);
scene()->update();
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -669,13 +906,13 @@ EASY_CONSTEXPR auto StdItemType = QTreeWidgetItem::UserType;
EASY_CONSTEXPR auto ValueItemType = QTreeWidgetItem::UserType + 1; EASY_CONSTEXPR auto ValueItemType = QTreeWidgetItem::UserType + 1;
struct UsedValueTypes { struct UsedValueTypes {
EasyArbitraryTreeWidgetItem* items[int_cast(profiler::DataType::TypesCount)]; ArbitraryTreeWidgetItem* items[int_cast(profiler::DataType::TypesCount)];
UsedValueTypes(int = 0) { memset(items, 0, sizeof(items)); } UsedValueTypes(int = 0) { memset(items, 0, sizeof(items)); }
}; };
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
EasyArbitraryTreeWidgetItem::EasyArbitraryTreeWidgetItem(QTreeWidgetItem* _parent, profiler::color_t _color, profiler::vin_t _vin) ArbitraryTreeWidgetItem::ArbitraryTreeWidgetItem(QTreeWidgetItem* _parent, profiler::color_t _color, profiler::vin_t _vin)
: Parent(_parent, ValueItemType) : Parent(_parent, ValueItemType)
, m_vin(_vin) , m_vin(_vin)
, m_color(_color) , m_color(_color)
@ -685,29 +922,29 @@ EasyArbitraryTreeWidgetItem::EasyArbitraryTreeWidgetItem(QTreeWidgetItem* _paren
setCheckState(CheckColumn, Qt::Unchecked); setCheckState(CheckColumn, Qt::Unchecked);
} }
EasyArbitraryTreeWidgetItem::~EasyArbitraryTreeWidgetItem() ArbitraryTreeWidgetItem::~ArbitraryTreeWidgetItem()
{ {
} }
QVariant EasyArbitraryTreeWidgetItem::data(int _column, int _role) const QVariant ArbitraryTreeWidgetItem::data(int _column, int _role) const
{ {
if (_column == CheckColumn && _role == Qt::SizeHintRole) if (_column == CheckColumn && _role == Qt::SizeHintRole)
return QSize(m_widthHint, 26); return QSize(m_widthHint, 26);
return Parent::data(_column, _role); return Parent::data(_column, _role);
} }
void EasyArbitraryTreeWidgetItem::setWidthHint(int _width) void ArbitraryTreeWidgetItem::setWidthHint(int _width)
{ {
m_widthHint = _width; m_widthHint = _width;
} }
const ArbitraryValuesCollection* EasyArbitraryTreeWidgetItem::collection() const const ArbitraryValuesCollection* ArbitraryTreeWidgetItem::collection() const
{ {
return m_collection.get(); return m_collection.get();
} }
void EasyArbitraryTreeWidgetItem::collectValues(profiler::thread_id_t _threadId) void ArbitraryTreeWidgetItem::collectValues(profiler::thread_id_t _threadId)
{ {
if (!m_collection) if (!m_collection)
m_collection = CollectionPtr(new ArbitraryValuesCollection); m_collection = CollectionPtr(new ArbitraryValuesCollection);
@ -717,7 +954,7 @@ void EasyArbitraryTreeWidgetItem::collectValues(profiler::thread_id_t _threadId)
m_collection->collectValues(_threadId, m_vin, text(int_cast(ArbitraryColumns::Name)).toStdString().c_str(), EASY_GLOBALS.begin_time); m_collection->collectValues(_threadId, m_vin, text(int_cast(ArbitraryColumns::Name)).toStdString().c_str(), EASY_GLOBALS.begin_time);
} }
void EasyArbitraryTreeWidgetItem::interrupt() void ArbitraryTreeWidgetItem::interrupt()
{ {
if (!m_collection) if (!m_collection)
return; return;
@ -726,24 +963,29 @@ void EasyArbitraryTreeWidgetItem::interrupt()
m_collection.release(); m_collection.release();
} }
profiler::color_t EasyArbitraryTreeWidgetItem::color() const profiler::color_t ArbitraryTreeWidgetItem::color() const
{ {
return m_color; return m_color;
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
EasyArbitraryValuesWidget::EasyArbitraryValuesWidget(QWidget* _parent) ArbitraryValuesWidget::ArbitraryValuesWidget(QWidget* _parent)
: Parent(_parent) : Parent(_parent)
, m_splitter(new QSplitter(Qt::Horizontal, this))
, m_treeWidget(new QTreeWidget(this)) , m_treeWidget(new QTreeWidget(this))
, m_chart(new EasyGraphicsChart(this)) , m_chart(new GraphicsChart(this))
{ {
auto layout = new QHBoxLayout(this); m_splitter->setHandleWidth(1);
m_splitter->setContentsMargins(0, 0, 0, 0);
m_splitter->addWidget(m_treeWidget);
m_splitter->addWidget(m_chart);
m_splitter->setStretchFactor(0, 1);
m_splitter->setStretchFactor(1, 1);
auto layout = new QVBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0); layout->setContentsMargins(0, 0, 0, 0);
layout->addWidget(m_treeWidget); layout->addWidget(m_splitter);
layout->addWidget(m_chart);
layout->setStretch(0, 1);
layout->setStretch(1, 1);
m_treeWidget->setAutoFillBackground(false); m_treeWidget->setAutoFillBackground(false);
m_treeWidget->setAlternatingRowColors(true); m_treeWidget->setAlternatingRowColors(true);
@ -761,10 +1003,6 @@ EasyArbitraryValuesWidget::EasyArbitraryValuesWidget(QWidget* _parent)
headerItem->setText(int_cast(ArbitraryColumns::Vin), "ID"); headerItem->setText(int_cast(ArbitraryColumns::Vin), "ID");
m_treeWidget->setHeaderItem(headerItem); m_treeWidget->setHeaderItem(headerItem);
// auto mainLayout = new QVBoxLayout(this);
// mainLayout->setContentsMargins(1, 1, 1, 1);
// mainLayout->addWidget(m_treeWidget);
connect(&m_timer, &QTimer::timeout, this, &This::rebuild); connect(&m_timer, &QTimer::timeout, this, &This::rebuild);
connect(&m_collectionsTimer, &QTimer::timeout, this, &This::onCollectionsTimeout); connect(&m_collectionsTimer, &QTimer::timeout, this, &This::onCollectionsTimeout);
@ -775,14 +1013,16 @@ EasyArbitraryValuesWidget::EasyArbitraryValuesWidget(QWidget* _parent)
connect(&EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::selectedThreadChanged, this, &This::onSelectedThreadChanged); connect(&EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::selectedThreadChanged, this, &This::onSelectedThreadChanged);
connect(&EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::selectedBlockChanged, this, &This::onSelectedBlockChanged); connect(&EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::selectedBlockChanged, this, &This::onSelectedBlockChanged);
connect(&EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::selectedBlockIdChanged, this, &This::onSelectedBlockIdChanged); connect(&EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::selectedBlockIdChanged, this, &This::onSelectedBlockIdChanged);
loadSettings();
} }
EasyArbitraryValuesWidget::~EasyArbitraryValuesWidget() ArbitraryValuesWidget::~ArbitraryValuesWidget()
{ {
saveSettings();
} }
void EasyArbitraryValuesWidget::clear() void ArbitraryValuesWidget::clear()
{ {
if (m_collectionsTimer.isActive()) if (m_collectionsTimer.isActive())
m_collectionsTimer.stop(); m_collectionsTimer.stop();
@ -792,25 +1032,25 @@ void EasyArbitraryValuesWidget::clear()
m_treeWidget->clear(); m_treeWidget->clear();
} }
void EasyArbitraryValuesWidget::onSelectedThreadChanged(::profiler::thread_id_t) void ArbitraryValuesWidget::onSelectedThreadChanged(::profiler::thread_id_t)
{ {
if (!m_timer.isActive()) if (!m_timer.isActive())
m_timer.start(100); m_timer.start(100);
} }
void EasyArbitraryValuesWidget::onSelectedBlockChanged(uint32_t) void ArbitraryValuesWidget::onSelectedBlockChanged(uint32_t)
{ {
if (!m_timer.isActive()) if (!m_timer.isActive())
m_timer.start(100); m_timer.start(100);
} }
void EasyArbitraryValuesWidget::onSelectedBlockIdChanged(::profiler::block_id_t) void ArbitraryValuesWidget::onSelectedBlockIdChanged(::profiler::block_id_t)
{ {
if (!m_timer.isActive()) if (!m_timer.isActive())
m_timer.start(100); m_timer.start(100);
} }
void EasyArbitraryValuesWidget::onItemDoubleClicked(QTreeWidgetItem* _item, int) void ArbitraryValuesWidget::onItemDoubleClicked(QTreeWidgetItem* _item, int)
{ {
if (_item == nullptr || _item->type() != ValueItemType) if (_item == nullptr || _item->type() != ValueItemType)
return; return;
@ -818,12 +1058,12 @@ void EasyArbitraryValuesWidget::onItemDoubleClicked(QTreeWidgetItem* _item, int)
_item->setCheckState(CheckColumn, _item->checkState(CheckColumn) == Qt::Checked ? Qt::Unchecked : Qt::Checked); _item->setCheckState(CheckColumn, _item->checkState(CheckColumn) == Qt::Checked ? Qt::Unchecked : Qt::Checked);
} }
void EasyArbitraryValuesWidget::onItemChanged(QTreeWidgetItem* _item, int _column) void ArbitraryValuesWidget::onItemChanged(QTreeWidgetItem* _item, int _column)
{ {
if (_item == nullptr || _item->type() != ValueItemType || _column != CheckColumn) if (_item == nullptr || _item->type() != ValueItemType || _column != CheckColumn)
return; return;
auto item = static_cast<EasyArbitraryTreeWidgetItem*>(_item); auto item = static_cast<ArbitraryTreeWidgetItem*>(_item);
if (item->checkState(CheckColumn) == Qt::Checked) if (item->checkState(CheckColumn) == Qt::Checked)
{ {
@ -840,7 +1080,7 @@ void EasyArbitraryValuesWidget::onItemChanged(QTreeWidgetItem* _item, int _colum
} }
} }
void EasyArbitraryValuesWidget::onCurrentItemChanged(QTreeWidgetItem* _current, QTreeWidgetItem*) void ArbitraryValuesWidget::onCurrentItemChanged(QTreeWidgetItem* _current, QTreeWidgetItem*)
{ {
if (_current == nullptr || _current->type() != ValueItemType) if (_current == nullptr || _current->type() != ValueItemType)
{ {
@ -848,11 +1088,11 @@ void EasyArbitraryValuesWidget::onCurrentItemChanged(QTreeWidgetItem* _current,
return; return;
} }
auto item = static_cast<const EasyArbitraryTreeWidgetItem*>(_current); auto item = static_cast<const ArbitraryTreeWidgetItem*>(_current);
m_chart->update(item->collection()); m_chart->update(item->collection());
} }
void EasyArbitraryValuesWidget::rebuild() void ArbitraryValuesWidget::rebuild()
{ {
clear(); clear();
@ -863,7 +1103,7 @@ void EasyArbitraryValuesWidget::rebuild()
m_treeWidget->resizeColumnToContents(i); m_treeWidget->resizeColumnToContents(i);
} }
void EasyArbitraryValuesWidget::onCollectionsTimeout() void ArbitraryValuesWidget::onCollectionsTimeout()
{ {
if (m_checkedItems.isEmpty()) if (m_checkedItems.isEmpty())
{ {
@ -879,7 +1119,7 @@ void EasyArbitraryValuesWidget::onCollectionsTimeout()
{ {
if (item->collection()->status() != ArbitraryValuesCollection::InProgress) if (item->collection()->status() != ArbitraryValuesCollection::InProgress)
{ {
collections.push_back(EasyCollectionPaintData {item->collection(), item->color(), collections.push_back(CollectionPaintData {item->collection(), item->color(),
ChartType::Line, item == m_treeWidget->currentItem()}); ChartType::Line, item == m_treeWidget->currentItem()});
} }
} }
@ -892,7 +1132,7 @@ void EasyArbitraryValuesWidget::onCollectionsTimeout()
} }
} }
void EasyArbitraryValuesWidget::buildTree(profiler::thread_id_t _threadId, profiler::block_index_t _blockIndex, profiler::block_id_t _blockId) void ArbitraryValuesWidget::buildTree(profiler::thread_id_t _threadId, profiler::block_index_t _blockIndex, profiler::block_id_t _blockId)
{ {
m_treeWidget->clear(); m_treeWidget->clear();
m_treeWidget->setColumnHidden(int_cast(ArbitraryColumns::Value), profiler_gui::is_max(_blockIndex)); m_treeWidget->setColumnHidden(int_cast(ArbitraryColumns::Value), profiler_gui::is_max(_blockIndex));
@ -916,7 +1156,7 @@ void EasyArbitraryValuesWidget::buildTree(profiler::thread_id_t _threadId, profi
} }
} }
QTreeWidgetItem* EasyArbitraryValuesWidget::buildTreeForThread(const profiler::BlocksTreeRoot& _threadRoot, profiler::block_index_t _blockIndex, profiler::block_id_t _blockId) QTreeWidgetItem* ArbitraryValuesWidget::buildTreeForThread(const profiler::BlocksTreeRoot& _threadRoot, profiler::block_index_t _blockIndex, profiler::block_id_t _blockId)
{ {
auto fm = m_treeWidget->fontMetrics(); auto fm = m_treeWidget->fontMetrics();
@ -932,7 +1172,7 @@ QTreeWidgetItem* EasyArbitraryValuesWidget::buildTreeForThread(const profiler::B
const auto& desc = easyDescriptor(block.node->id()); const auto& desc = easyDescriptor(block.node->id());
if (desc.type() == profiler::BlockType::Value) if (desc.type() == profiler::BlockType::Value)
{ {
auto valueItem = new EasyArbitraryTreeWidgetItem(rootItem, desc.color(), block.value->value_id()); auto valueItem = new ArbitraryTreeWidgetItem(rootItem, desc.color(), block.value->value_id());
valueItem->setText(int_cast(ArbitraryColumns::Type), profiler_gui::valueTypeString(*block.value)); valueItem->setText(int_cast(ArbitraryColumns::Type), profiler_gui::valueTypeString(*block.value));
valueItem->setText(int_cast(ArbitraryColumns::Name), desc.name()); valueItem->setText(int_cast(ArbitraryColumns::Name), desc.name());
valueItem->setText(int_cast(ArbitraryColumns::Vin), QString("0x%1").arg(block.value->value_id(), 0, 16)); valueItem->setText(int_cast(ArbitraryColumns::Vin), QString("0x%1").arg(block.value->value_id(), 0, 16));
@ -1005,8 +1245,8 @@ QTreeWidgetItem* EasyArbitraryValuesWidget::buildTreeForThread(const profiler::B
const auto typeIndex = int_cast(child.value->type()); const auto typeIndex = int_cast(child.value->type());
auto vin = child.value->value_id(); auto vin = child.value->value_id();
EasyArbitraryTreeWidgetItem** usedItems = nullptr; ArbitraryTreeWidgetItem** usedItems = nullptr;
EasyArbitraryTreeWidgetItem* valueItem = nullptr; ArbitraryTreeWidgetItem* valueItem = nullptr;
if (vin == 0) if (vin == 0)
{ {
auto result = names.emplace(desc.name(), 0); auto result = names.emplace(desc.name(), 0);
@ -1030,7 +1270,7 @@ QTreeWidgetItem* EasyArbitraryValuesWidget::buildTreeForThread(const profiler::B
} }
} }
valueItem = new EasyArbitraryTreeWidgetItem(blockItem, desc.color(), vin); valueItem = new ArbitraryTreeWidgetItem(blockItem, desc.color(), vin);
valueItem->setText(int_cast(ArbitraryColumns::Type), profiler_gui::valueTypeString(*child.value)); valueItem->setText(int_cast(ArbitraryColumns::Type), profiler_gui::valueTypeString(*child.value));
valueItem->setText(int_cast(ArbitraryColumns::Name), desc.name()); valueItem->setText(int_cast(ArbitraryColumns::Name), desc.name());
valueItem->setText(int_cast(ArbitraryColumns::Vin), QString("0x%1").arg(vin, 0, 16)); valueItem->setText(int_cast(ArbitraryColumns::Vin), QString("0x%1").arg(vin, 0, 16));
@ -1058,3 +1298,27 @@ QTreeWidgetItem* EasyArbitraryValuesWidget::buildTreeForThread(const profiler::B
return rootItem; return rootItem;
} }
void ArbitraryValuesWidget::loadSettings()
{
QSettings settings(::profiler_gui::ORGANAZATION_NAME, ::profiler_gui::APPLICATION_NAME);
settings.beginGroup("ArbitraryValuesWidget");
auto geometry = settings.value("hsplitter/geometry").toByteArray();
if (!geometry.isEmpty())
m_splitter->restoreGeometry(geometry);
auto state = settings.value("hsplitter/state").toByteArray();
if (!state.isEmpty())
m_splitter->restoreState(state);
settings.endGroup();
}
void ArbitraryValuesWidget::saveSettings()
{
QSettings settings(::profiler_gui::ORGANAZATION_NAME, ::profiler_gui::APPLICATION_NAME);
settings.beginGroup("ArbitraryValuesWidget");
settings.setValue("hsplitter/geometry", m_splitter->saveGeometry());
settings.setValue("hsplitter/state", m_splitter->saveState());
settings.endGroup();
}

View File

@ -58,8 +58,6 @@
#include <QWidget> #include <QWidget>
#include <QTreeWidget> #include <QTreeWidget>
#include <QTreeWidgetItem> #include <QTreeWidgetItem>
#include <QGraphicsItem>
#include <QGraphicsView>
#include <QTimer> #include <QTimer>
#include <QPointF> #include <QPointF>
#include <QList> #include <QList>
@ -72,6 +70,7 @@
#include <thread> #include <thread>
#include <atomic> #include <atomic>
#include <memory> #include <memory>
#include "graphics_slider_area.h"
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -136,7 +135,7 @@ enum class ChartType : uint8_t
Points Points
}; };
struct EasyCollectionPaintData EASY_FINAL struct CollectionPaintData EASY_FINAL
{ {
const ArbitraryValuesCollection* ptr; const ArbitraryValuesCollection* ptr;
QRgb color; QRgb color;
@ -144,44 +143,58 @@ struct EasyCollectionPaintData EASY_FINAL
bool selected; bool selected;
}; };
using Collections = std::vector<EasyCollectionPaintData>; using Collections = std::vector<CollectionPaintData>;
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
class EasyArbitraryValuesChartItem : public QGraphicsItem class ArbitraryValuesChartItem : public GraphicsImageItem
{ {
using Parent = QGraphicsItem; using Parent = GraphicsImageItem;
using This = EasyArbitraryValuesChartItem; using This = ArbitraryValuesChartItem;
Collections m_collections; Collections m_collections;
QRectF m_boundingRect; qreal m_workerMaxValue;
qreal m_workerMinValue;
public: public:
explicit EasyArbitraryValuesChartItem(); explicit ArbitraryValuesChartItem();
~EasyArbitraryValuesChartItem() override; ~ArbitraryValuesChartItem() override;
void paint(QPainter* _painter, const QStyleOptionGraphicsItem* _option, QWidget* _widget = nullptr) override; void paint(QPainter* _painter, const QStyleOptionGraphicsItem* _option, QWidget* _widget) override;
QRectF boundingRect() const override; bool updateImage() override;
void setBoundingRect(const QRectF& _rect);
void setBoundingRect(qreal _left, qreal _top, qreal _width, qreal _height);
protected:
void onImageUpdated() override;
public:
void clear();
void update(Collections _collections); void update(Collections _collections);
void update(const ArbitraryValuesCollection* _selected); void update(const ArbitraryValuesCollection* _selected);
}; // end of class EasyArbitraryValuesChartItem. private:
class EasyGraphicsChart : public QGraphicsView void paintMouseIndicator(QPainter* _painter, qreal _top, qreal _bottom, qreal _width, qreal _height, int _font_h,
qreal _visibleRegionLeft, qreal _visibleRegionWidth);
void updateImageAsync(QRectF _boundingRect, qreal _current_scale, qreal _minimum, qreal _maximum, qreal _range,
qreal _value, qreal _width, bool _bindMode, profiler::timestamp_t _begin_time, bool _autoAdjust);
}; // end of class ArbitraryValuesChartItem.
class GraphicsChart : public GraphicsSliderArea
{ {
Q_OBJECT Q_OBJECT
private: private:
using Parent = QGraphicsView; using Parent = GraphicsSliderArea;
using This = EasyGraphicsChart; using This = GraphicsChart;
EasyArbitraryValuesChartItem* m_chartItem; ArbitraryValuesChartItem* m_chartItem;
qreal m_left; qreal m_left;
qreal m_right; qreal m_right;
qreal m_offset; qreal m_offset;
@ -191,42 +204,24 @@ private:
public: public:
explicit EasyGraphicsChart(QWidget* _parent = nullptr); explicit GraphicsChart(QWidget* _parent = nullptr);
~EasyGraphicsChart() override; ~GraphicsChart() override;
void resizeEvent(QResizeEvent* _event) override; void clear() override;
void clear(); public:
bool bindMode() const;
qreal xscale() const;
qreal left() const;
qreal right() const;
qreal range() const;
qreal offset() const;
qreal region() const;
void setOffset(qreal _offset);
void setRange(qreal _left, qreal _right);
void setRegion(qreal _visibleRegionWidth);
void update(Collections _collections); void update(Collections _collections);
void update(const ArbitraryValuesCollection* _selected); void update(const ArbitraryValuesCollection* _selected);
private slots: }; // end of class GraphicsChart.
void onSceneSizeChanged();
void onWindowSizeChanged(qreal _width, qreal _height);
}; // end of class EasyGraphicsChart.
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
class EasyArbitraryTreeWidgetItem : public QTreeWidgetItem class ArbitraryTreeWidgetItem : public QTreeWidgetItem
{ {
using Parent = QTreeWidgetItem; using Parent = QTreeWidgetItem;
using This = EasyArbitraryTreeWidgetItem; using This = ArbitraryTreeWidgetItem;
using CollectionPtr = std::unique_ptr<ArbitraryValuesCollection>; using CollectionPtr = std::unique_ptr<ArbitraryValuesCollection>;
CollectionPtr m_collection; CollectionPtr m_collection;
@ -236,8 +231,8 @@ class EasyArbitraryTreeWidgetItem : public QTreeWidgetItem
public: public:
explicit EasyArbitraryTreeWidgetItem(QTreeWidgetItem* _parent, profiler::color_t _color, profiler::vin_t _vin = 0); explicit ArbitraryTreeWidgetItem(QTreeWidgetItem* _parent, profiler::color_t _color, profiler::vin_t _vin = 0);
~EasyArbitraryTreeWidgetItem() override; ~ArbitraryTreeWidgetItem() override;
QVariant data(int _column, int _role) const override; QVariant data(int _column, int _role) const override;
@ -249,27 +244,28 @@ public:
profiler::color_t color() const; profiler::color_t color() const;
}; // end of class EasyArbitraryTreeWidgetItem. }; // end of class ArbitraryTreeWidgetItem.
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
class EasyArbitraryValuesWidget : public QWidget class ArbitraryValuesWidget : public QWidget
{ {
Q_OBJECT Q_OBJECT
using Parent = QWidget; using Parent = QWidget;
using This = EasyArbitraryValuesWidget; using This = ArbitraryValuesWidget;
QTimer m_timer; QTimer m_timer;
QTimer m_collectionsTimer; QTimer m_collectionsTimer;
QList<EasyArbitraryTreeWidgetItem*> m_checkedItems; QList<ArbitraryTreeWidgetItem*> m_checkedItems;
class QSplitter* m_splitter;
QTreeWidget* m_treeWidget; QTreeWidget* m_treeWidget;
EasyGraphicsChart* m_chart; GraphicsChart* m_chart;
public: public:
explicit EasyArbitraryValuesWidget(QWidget* _parent = nullptr); explicit ArbitraryValuesWidget(QWidget* _parent = nullptr);
~EasyArbitraryValuesWidget() override; ~ArbitraryValuesWidget() override;
void clear(); void clear();
@ -292,7 +288,10 @@ private:
void buildTree(profiler::thread_id_t _threadId, profiler::block_index_t _blockIndex, profiler::block_id_t _blockId); void buildTree(profiler::thread_id_t _threadId, profiler::block_index_t _blockIndex, profiler::block_id_t _blockId);
QTreeWidgetItem* buildTreeForThread(const profiler::BlocksTreeRoot& _threadRoot, profiler::block_index_t _blockIndex, profiler::block_id_t _blockId); QTreeWidgetItem* buildTreeForThread(const profiler::BlocksTreeRoot& _threadRoot, profiler::block_index_t _blockIndex, profiler::block_id_t _blockId);
}; // end of class EasyArbitraryValuesWidget. void loadSettings();
void saveSettings();
}; // end of class ArbitraryValuesWidget.
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////

View File

@ -72,9 +72,12 @@
#include <QKeyEvent> #include <QKeyEvent>
#include <QScrollBar> #include <QScrollBar>
#include <QGridLayout> #include <QGridLayout>
#include <QHBoxLayout>
#include <QSplitter>
#include <QDebug> #include <QDebug>
#include <QSignalBlocker> #include <QSignalBlocker>
#include <QGraphicsDropShadowEffect> #include <QGraphicsDropShadowEffect>
#include <QSettings>
#include "blocks_graphics_view.h" #include "blocks_graphics_view.h"
#include "easy_graphics_item.h" #include "easy_graphics_item.h"
#include "easy_chronometer_item.h" #include "easy_chronometer_item.h"
@ -286,6 +289,7 @@ EasyGraphicsView::EasyGraphicsView(QWidget* _parent)
, m_sceneWidth(0) , m_sceneWidth(0)
, m_scale(1) , m_scale(1)
, m_offset(0) , m_offset(0)
, m_visibleRegionWidth(0)
, m_timelineStep(0) , m_timelineStep(0)
, m_idleTime(0) , m_idleTime(0)
, m_mouseButtons(Qt::NoButton) , m_mouseButtons(Qt::NoButton)
@ -389,21 +393,64 @@ void EasyGraphicsView::clear()
m_bEmpty = true; m_bEmpty = true;
m_sceneWidth = 10; m_sceneWidth = 10;
m_visibleRegionWidth = 10;
setSceneRect(0, 0, 10, 10); setSceneRect(0, 0, 10, 10);
auto& sceneData = EASY_GLOBALS.scene;
sceneData.left = 0;
sceneData.right = m_sceneWidth;
sceneData.window = m_visibleRegionWidth;
sceneData.offset = m_offset;
sceneData.empty = true;
// notify ProfTreeWidget that selection was reset // notify ProfTreeWidget that selection was reset
emit intervalChanged(m_selectedBlocks, m_beginTime, 0, 0, false); emit intervalChanged(m_selectedBlocks, m_beginTime, 0, 0, false);
EASY_GLOBALS.selected_thread = 0;
emit EASY_GLOBALS.events.selectedThreadChanged(0);
}
void EasyGraphicsView::notifySceneSizeChange()
{
EASY_GLOBALS.scene.left = 0;
EASY_GLOBALS.scene.right = m_sceneWidth;
emit EASY_GLOBALS.events.sceneSizeChanged(0, m_sceneWidth);
}
void EasyGraphicsView::notifyVisibleRegionSizeChange()
{
auto vbar = verticalScrollBar();
const int vbar_width = (vbar != nullptr && vbar->isVisible() ? vbar->width() + 2 : 0);
notifyVisibleRegionSizeChange((m_visibleSceneRect.width() + vbar_width) / m_scale);
}
void EasyGraphicsView::notifyVisibleRegionSizeChange(qreal _size)
{
m_visibleRegionWidth = _size;
EASY_GLOBALS.scene.window = _size;
emit EASY_GLOBALS.events.sceneVisibleRegionSizeChanged(_size);
}
void EasyGraphicsView::notifyVisibleRegionPosChange()
{
EASY_GLOBALS.scene.offset = m_offset;
emit EASY_GLOBALS.events.sceneVisibleRegionPosChanged(m_offset);
}
void EasyGraphicsView::notifyVisibleRegionPosChange(qreal _pos)
{
m_offset = estd::clamp(0., _pos, m_sceneWidth - m_visibleRegionWidth);
notifyVisibleRegionPosChange();
} }
void EasyGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocksTree) void EasyGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocksTree)
{ {
// clear scene // clear scene
clear(); clear();
emit EASY_GLOBALS.events.sceneCleared();
if (_blocksTree.empty()) if (_blocksTree.empty())
{
return; return;
}
auto bgItem = new EasyBackgroundItem(); auto bgItem = new EasyBackgroundItem();
scene()->addItem(bgItem); scene()->addItem(bgItem);
@ -515,14 +562,14 @@ void EasyGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocksTr
// Calculating scene rect // Calculating scene rect
m_sceneWidth = time2position(finish); m_sceneWidth = time2position(finish);
setSceneRect(0, 0, m_sceneWidth, y + TIMELINE_ROW_SIZE); setSceneRect(0, 0, m_sceneWidth, y + TIMELINE_ROW_SIZE);
EASY_GLOBALS.scene.empty = false;
EASY_GLOBALS.scene_left = 0;
EASY_GLOBALS.scene_right = m_sceneWidth;
emit EASY_GLOBALS.events.sceneSizeChanged();
// Center view on the beginning of the scene // Center view on the beginning of the scene
updateVisibleSceneRect(); updateVisibleSceneRect();
setScrollbar(m_pScrollbar); //setScrollbar(m_pScrollbar);
notifySceneSizeChange();
notifyVisibleRegionSizeChange();
// Create new chronometer item (previous item was destroyed by scene on scene()->clear()). // Create new chronometer item (previous item was destroyed by scene on scene()->clear()).
// It will be shown on mouse right button click. // It will be shown on mouse right button click.
@ -543,9 +590,7 @@ void EasyGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocksTr
emit treeChanged(); emit treeChanged();
if (mainThreadItem != nullptr) if (mainThreadItem != nullptr)
{
longestItem = mainThreadItem; longestItem = mainThreadItem;
}
if (longestItem != nullptr) if (longestItem != nullptr)
{ {
@ -555,7 +600,7 @@ void EasyGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocksTr
scrollTo(longestItem); scrollTo(longestItem);
m_pScrollbar->setHistogramSource(longestItem->threadId(), longestItem->items(0)); m_pScrollbar->setHistogramSource(longestItem->threadId(), longestItem->items(0));
if (!longestItem->items(0).empty()) if (!longestItem->items(0).empty())
m_pScrollbar->setValue(longestItem->items(0).front().left() - m_pScrollbar->sliderWidth() * 0.25); notifyVisibleRegionPosChange(longestItem->items(0).front().left() - m_visibleRegionWidth * 0.25);
} }
m_idleTimer.start(IDLE_TIMER_INTERVAL); m_idleTimer.start(IDLE_TIMER_INTERVAL);
@ -683,11 +728,8 @@ void EasyGraphicsView::setScrollbar(EasyGraphicsScrollbar* _scrollbar)
auto const prevScrollbar = m_pScrollbar; auto const prevScrollbar = m_pScrollbar;
const bool makeConnect = prevScrollbar == nullptr || prevScrollbar != _scrollbar; const bool makeConnect = prevScrollbar == nullptr || prevScrollbar != _scrollbar;
if (prevScrollbar != nullptr && prevScrollbar != _scrollbar) disconnect(&EASY_GLOBALS.events, &profiler_gui::EasyGlobalSignals::chartSliderChanged, this, &This::onGraphicsScrollbarValueChange);
{ disconnect(&EASY_GLOBALS.events, &profiler_gui::EasyGlobalSignals::chartWheeled, this, &This::onGraphicsScrollbarWheel);
disconnect(prevScrollbar, &EasyGraphicsScrollbar::valueChanged, this, &This::onGraphicsScrollbarValueChange);
disconnect(prevScrollbar, &EasyGraphicsScrollbar::wheeled, this, &This::onGraphicsScrollbarWheel);
}
m_pScrollbar = _scrollbar; m_pScrollbar = _scrollbar;
m_pScrollbar->clear(); m_pScrollbar->clear();
@ -697,11 +739,8 @@ void EasyGraphicsView::setScrollbar(EasyGraphicsScrollbar* _scrollbar)
const int vbar_width = (vbar != nullptr && vbar->isVisible() ? vbar->width() + 2 : 0); const int vbar_width = (vbar != nullptr && vbar->isVisible() ? vbar->width() + 2 : 0);
m_pScrollbar->setSliderWidth(m_visibleSceneRect.width() + vbar_width); m_pScrollbar->setSliderWidth(m_visibleSceneRect.width() + vbar_width);
if (makeConnect) connect(&EASY_GLOBALS.events, &profiler_gui::EasyGlobalSignals::chartSliderChanged, this, &This::onGraphicsScrollbarValueChange);
{ connect(&EASY_GLOBALS.events, &profiler_gui::EasyGlobalSignals::chartWheeled, this, &This::onGraphicsScrollbarWheel);
connect(m_pScrollbar, &EasyGraphicsScrollbar::valueChanged, this, &This::onGraphicsScrollbarValueChange);
connect(m_pScrollbar, &EasyGraphicsScrollbar::wheeled, this, &This::onGraphicsScrollbarWheel);
}
EASY_GLOBALS.selected_thread = 0; EASY_GLOBALS.selected_thread = 0;
emit EASY_GLOBALS.events.selectedThreadChanged(0); emit EASY_GLOBALS.events.selectedThreadChanged(0);
@ -768,7 +807,7 @@ void EasyGraphicsView::scaleTo(qreal _scale)
// Update slider width for scrollbar // Update slider width for scrollbar
const auto windowWidth = (m_visibleSceneRect.width() + vbar_width) / m_scale; const auto windowWidth = (m_visibleSceneRect.width() + vbar_width) / m_scale;
m_pScrollbar->setSliderWidth(windowWidth); notifyVisibleRegionSizeChange(windowWidth);
updateTimelineStep(windowWidth); updateTimelineStep(windowWidth);
repaintScene(); repaintScene();
@ -803,7 +842,7 @@ void EasyGraphicsView::scrollTo(const EasyGraphicsItem* _item)
{ {
m_bUpdatingRect = true; m_bUpdatingRect = true;
auto vbar = verticalScrollBar(); auto vbar = verticalScrollBar();
vbar->setValue(_item->y() + (_item->boundingRect().height() - vbar->pageStep()) * 0.5); vbar->setValue(static_cast<int>(_item->y() + (_item->boundingRect().height() - vbar->pageStep()) * 0.5));
m_bUpdatingRect = false; m_bUpdatingRect = false;
} }
@ -822,21 +861,18 @@ void EasyGraphicsView::onWheel(qreal _mouseX, int _wheelDelta)
//updateVisibleSceneRect(); // Update scene rect //updateVisibleSceneRect(); // Update scene rect
// Update slider width for scrollbar // Update slider width for scrollbar
auto vbar = verticalScrollBar(); notifyVisibleRegionSizeChange();
const int vbar_width = (vbar != nullptr && vbar->isVisible() ? vbar->width() + 2 : 0);
const auto windowWidth = (m_visibleSceneRect.width() + vbar_width) / m_scale;
m_pScrollbar->setSliderWidth(windowWidth);
// Calculate new offset to simulate QGraphicsView::AnchorUnderMouse scaling behavior // Calculate new offset to simulate QGraphicsView::AnchorUnderMouse scaling behavior
m_offset = clamp(0., mousePosition - _mouseX / m_scale, m_sceneWidth - windowWidth); m_offset = clamp(0., mousePosition - _mouseX / m_scale, m_sceneWidth - m_visibleRegionWidth);
// Update slider position // Update slider position
m_bUpdatingRect = true; // To be sure that updateVisibleSceneRect will not be called by scrollbar change profiler_gui::BoolFlagGuard guard(m_bUpdatingRect, true); // To be sure that updateVisibleSceneRect will not be called by scrollbar change
m_pScrollbar->setValue(m_offset); notifyVisibleRegionPosChange();
m_bUpdatingRect = false; guard.restore();
updateVisibleSceneRect(); // Update scene rect updateVisibleSceneRect(); // Update scene rect
updateTimelineStep(windowWidth); updateTimelineStep(m_visibleRegionWidth);
repaintScene(); // repaint scene repaintScene(); // repaint scene
} }
@ -975,7 +1011,7 @@ void EasyGraphicsView::mouseReleaseEvent(QMouseEvent* _event)
// Jump to selected zone // Jump to selected zone
clicked = true; clicked = true;
m_flickerSpeedX = m_flickerSpeedY = 0; m_flickerSpeedX = m_flickerSpeedY = 0;
m_pScrollbar->setValue(m_chronometerItem->left() + m_chronometerItem->width() * 0.5 - m_pScrollbar->sliderHalfWidth()); notifyVisibleRegionPosChange(m_chronometerItem->left() + (m_chronometerItem->width() - m_visibleRegionWidth) * 0.5);
} }
if (!clicked && m_mouseMovePath.manhattanLength() < 5) if (!clicked && m_mouseMovePath.manhattanLength() < 5)
@ -993,7 +1029,7 @@ void EasyGraphicsView::mouseReleaseEvent(QMouseEvent* _event)
{ {
::profiler::block_index_t i = ~0U; ::profiler::block_index_t i = ~0U;
auto block = item->intersect(mouseClickPos, i); auto block = item->intersect(mouseClickPos, i);
if (block) if (block != nullptr)
{ {
changedSelectedItem = true; changedSelectedItem = true;
selectedBlock = block; selectedBlock = block;
@ -1026,23 +1062,26 @@ void EasyGraphicsView::mouseReleaseEvent(QMouseEvent* _event)
if (changedSelectedItem) if (changedSelectedItem)
{ {
m_bUpdatingRect = true; profiler_gui::BoolFlagGuard guard(m_bUpdatingRect, true);
if (selectedBlock != nullptr && previouslySelectedBlock == EASY_GLOBALS.selected_block && !selectedBlock->tree.children.empty()) if (selectedBlock != nullptr && previouslySelectedBlock == EASY_GLOBALS.selected_block && !selectedBlock->tree.children.empty())
{ {
EASY_GLOBALS.gui_blocks[previouslySelectedBlock].expanded = !EASY_GLOBALS.gui_blocks[previouslySelectedBlock].expanded; EASY_GLOBALS.gui_blocks[previouslySelectedBlock].expanded = !EASY_GLOBALS.gui_blocks[previouslySelectedBlock].expanded;
emit EASY_GLOBALS.events.itemsExpandStateChanged(); emit EASY_GLOBALS.events.itemsExpandStateChanged();
} }
emit EASY_GLOBALS.events.selectedBlockChanged(EASY_GLOBALS.selected_block); emit EASY_GLOBALS.events.selectedBlockChanged(EASY_GLOBALS.selected_block);
if (EASY_GLOBALS.selecting_block_changes_thread && selectedBlock != nullptr && EASY_GLOBALS.selected_thread != selectedBlockThread) if (EASY_GLOBALS.selecting_block_changes_thread && selectedBlock != nullptr && EASY_GLOBALS.selected_thread != selectedBlockThread)
{ {
EASY_GLOBALS.selected_thread = selectedBlockThread; EASY_GLOBALS.selected_thread = selectedBlockThread;
m_pScrollbar->lock(); emit EASY_GLOBALS.events.lockCharts();
emit EASY_GLOBALS.events.selectedThreadChanged(EASY_GLOBALS.selected_thread); emit EASY_GLOBALS.events.selectedThreadChanged(EASY_GLOBALS.selected_thread);
m_pScrollbar->unlock(); emit EASY_GLOBALS.events.unlockCharts();
} }
m_bUpdatingRect = false;
guard.restore();
if (selectedBlock != nullptr && selectedBlockThread == EASY_GLOBALS.selected_thread) if (selectedBlock != nullptr && selectedBlockThread == EASY_GLOBALS.selected_thread)
m_pScrollbar->setHistogramSource(EASY_GLOBALS.selected_thread, EASY_GLOBALS.selected_block_id); m_pScrollbar->setHistogramSource(EASY_GLOBALS.selected_thread, EASY_GLOBALS.selected_block_id);
@ -1164,10 +1203,10 @@ void EasyGraphicsView::mouseMoveEvent(QMouseEvent* _event)
{ {
auto vbar = verticalScrollBar(); auto vbar = verticalScrollBar();
m_bUpdatingRect = true; // Block scrollbars from updating scene rect to make it possible to do it only once profiler_gui::BoolFlagGuard guard(m_bUpdatingRect, true); // Block scrollbars from updating scene rect to make it possible to do it only once
vbar->setValue(vbar->value() - delta.y()); vbar->setValue(vbar->value() - delta.y());
m_pScrollbar->setValue(m_pScrollbar->value() - delta.x() / m_scale); notifyVisibleRegionPosChange(m_offset - delta.x() / m_scale);
m_bUpdatingRect = false; guard.restore();
// Seems like an ugly stub, but QSignalBlocker is also a bad decision // Seems like an ugly stub, but QSignalBlocker is also a bad decision
// because if scrollbar does not emit valueChanged signal then viewport does not move // because if scrollbar does not emit valueChanged signal then viewport does not move
@ -1243,14 +1282,14 @@ void EasyGraphicsView::keyPressEvent(QKeyEvent* _event)
case Qt::Key_Right: case Qt::Key_Right:
case Qt::Key_6: case Qt::Key_6:
{ {
m_pScrollbar->setValue(m_pScrollbar->value() + KeyStep / m_scale); notifyVisibleRegionPosChange(m_offset + KeyStep / m_scale);
break; break;
} }
case Qt::Key_Left: case Qt::Key_Left:
case Qt::Key_4: case Qt::Key_4:
{ {
m_pScrollbar->setValue(m_pScrollbar->value() - KeyStep / m_scale); notifyVisibleRegionPosChange(m_offset - KeyStep / m_scale);
break; break;
} }
@ -1308,16 +1347,16 @@ void EasyGraphicsView::resizeEvent(QResizeEvent* _event)
// Update slider width for scrollbar // Update slider width for scrollbar
const auto windowWidth = (m_visibleSceneRect.width() + vbar_width) / m_scale; const auto windowWidth = (m_visibleSceneRect.width() + vbar_width) / m_scale;
m_pScrollbar->setSliderWidth(windowWidth); notifyVisibleRegionSizeChange(windowWidth);
// Calculate new offset to save old screen center // Calculate new offset to save old screen center
const auto deltaWidth = m_visibleSceneRect.width() - previousRect.width(); const auto deltaWidth = m_visibleSceneRect.width() - previousRect.width();
m_offset = clamp(0., m_offset - deltaWidth * 0.5 / m_scale, m_sceneWidth - windowWidth); m_offset = clamp(0., m_offset - deltaWidth * 0.5 / m_scale, m_sceneWidth - windowWidth);
// Update slider position // Update slider position
m_bUpdatingRect = true; // To be sure that updateVisibleSceneRect will not be called by scrollbar change profiler_gui::BoolFlagGuard guard(m_bUpdatingRect, true); // To be sure that updateVisibleSceneRect will not be called by scrollbar change
m_pScrollbar->setValue(m_offset); notifyVisibleRegionPosChange();
m_bUpdatingRect = false; guard.restore();
repaintScene(); // repaint scene repaintScene(); // repaint scene
} }
@ -1379,6 +1418,9 @@ void EasyGraphicsView::initMode()
if (!m_selectedBlocks.empty()) if (!m_selectedBlocks.empty())
emit intervalChanged(m_selectedBlocks, m_beginTime, position2time(m_chronometerItem->left()), position2time(m_chronometerItem->right()), m_chronometerItem->reverse()); emit intervalChanged(m_selectedBlocks, m_beginTime, position2time(m_chronometerItem->left()), position2time(m_chronometerItem->right()), m_chronometerItem->reverse());
}); });
connect(globalSignals, &profiler_gui::EasyGlobalSignals::chartSliderChanged, this, &This::onGraphicsScrollbarValueChange);
connect(globalSignals, &profiler_gui::EasyGlobalSignals::chartWheeled, this, &This::onGraphicsScrollbarWheel);
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -1444,10 +1486,10 @@ void EasyGraphicsView::onFlickerTimeout()
auto vbar = verticalScrollBar(); auto vbar = verticalScrollBar();
m_bUpdatingRect = true; // Block scrollbars from updating scene rect to make it possible to do it only once profiler_gui::BoolFlagGuard guard(m_bUpdatingRect, true); // Block scrollbars from updating scene rect to make it possible to do it only once
m_pScrollbar->setValue(m_pScrollbar->value() - m_flickerSpeedX / m_scale); notifyVisibleRegionPosChange(m_offset - m_flickerSpeedX / m_scale);
vbar->setValue(vbar->value() - m_flickerSpeedY); vbar->setValue(vbar->value() - m_flickerSpeedY);
m_bUpdatingRect = false; guard.restore();
// Seems like an ugly stub, but QSignalBlocker is also a bad decision // Seems like an ugly stub, but QSignalBlocker is also a bad decision
// because if scrollbar does not emit valueChanged signal then viewport does not move // because if scrollbar does not emit valueChanged signal then viewport does not move
@ -1954,22 +1996,20 @@ void EasyGraphicsView::onSelectedBlockChange(unsigned int _block_index)
m_flickerSpeedX = m_flickerSpeedY = 0; m_flickerSpeedX = m_flickerSpeedY = 0;
m_bUpdatingRect = true; const profiler_gui::BoolFlagGuard guard(m_bUpdatingRect, true);
verticalScrollBar()->setValue(static_cast<int>(thread_item->levelY(guiblock.graphics_item_level) - m_visibleSceneRect.height() * 0.5)); verticalScrollBar()->setValue(static_cast<int>(thread_item->levelY(guiblock.graphics_item_level) - m_visibleSceneRect.height() * 0.5));
m_pScrollbar->setValue(item.left() + item.width() * 0.5 - m_pScrollbar->sliderHalfWidth()); notifyVisibleRegionPosChange(item.left() + (item.width() - m_visibleRegionWidth) * 0.5);
if (EASY_GLOBALS.selecting_block_changes_thread && EASY_GLOBALS.selected_thread != thread_item->threadId()) if (EASY_GLOBALS.selecting_block_changes_thread && EASY_GLOBALS.selected_thread != thread_item->threadId())
{ {
EASY_GLOBALS.selected_thread = thread_item->threadId(); EASY_GLOBALS.selected_thread = thread_item->threadId();
m_pScrollbar->lock(); emit EASY_GLOBALS.events.lockCharts();
emit EASY_GLOBALS.events.selectedThreadChanged(EASY_GLOBALS.selected_thread); emit EASY_GLOBALS.events.selectedThreadChanged(EASY_GLOBALS.selected_thread);
m_pScrollbar->unlock(); emit EASY_GLOBALS.events.unlockCharts();
} }
m_pScrollbar->setHistogramSource(EASY_GLOBALS.selected_thread, guiblock.tree.node->id()); m_pScrollbar->setHistogramSource(EASY_GLOBALS.selected_thread, guiblock.tree.node->id());
m_bUpdatingRect = false;
} }
else if (EASY_GLOBALS.selected_thread != 0) else if (EASY_GLOBALS.selected_thread != 0)
{ {
@ -2006,7 +2046,8 @@ void EasyGraphicsView::onRefreshRequired()
EasyGraphicsViewWidget::EasyGraphicsViewWidget(QWidget* _parent) EasyGraphicsViewWidget::EasyGraphicsViewWidget(QWidget* _parent)
: QWidget(_parent) : QWidget(_parent)
, m_scrollbar(new EasyGraphicsScrollbar(true, 85 + (QFontMetrics(font()).height() << 1), this)) , m_splitter(new QSplitter(Qt::Vertical, this))
, m_scrollbar(new EasyGraphicsScrollbar(85 + (QFontMetrics(font()).height() << 1), this))
, m_view(new EasyGraphicsView(this)) , m_view(new EasyGraphicsView(this))
, m_threadNamesWidget(new EasyThreadNamesWidget(m_view, m_scrollbar->height(), this)) , m_threadNamesWidget(new EasyThreadNamesWidget(m_view, m_scrollbar->height(), this))
{ {
@ -2015,13 +2056,18 @@ EasyGraphicsViewWidget::EasyGraphicsViewWidget(QWidget* _parent)
void EasyGraphicsViewWidget::initWidget() void EasyGraphicsViewWidget::initWidget()
{ {
auto lay = new QGridLayout(this); m_splitter->setHandleWidth(1);
m_splitter->setContentsMargins(0, 0, 0, 0);
m_splitter->addWidget(m_view);
m_splitter->addWidget(m_scrollbar);
m_splitter->setStretchFactor(0, 500);
m_splitter->setStretchFactor(1, 1);
auto lay = new QHBoxLayout(this);
lay->setContentsMargins(0, 0, 0, 0); lay->setContentsMargins(0, 0, 0, 0);
lay->setSpacing(1); lay->setSpacing(1);
lay->addWidget(m_threadNamesWidget, 0, 0, 2, 1); lay->addWidget(m_threadNamesWidget);
lay->addWidget(m_view, 0, 1); lay->addWidget(m_splitter);
lay->addWidget(m_scrollbar, 1, 1);
setLayout(lay);
m_view->setScrollbar(m_scrollbar); m_view->setScrollbar(m_scrollbar);
} }
@ -2043,6 +2089,23 @@ void EasyGraphicsViewWidget::clear()
m_view->clear(); m_view->clear();
} }
void EasyGraphicsViewWidget::save(QSettings& settings)
{
settings.setValue("diagram/vsplitter/geometry", m_splitter->saveGeometry());
settings.setValue("diagram/vsplitter/state", m_splitter->saveState());
}
void EasyGraphicsViewWidget::restore(QSettings& settings)
{
auto geometry = settings.value("diagram/vsplitter/geometry").toByteArray();
if (!geometry.isEmpty())
m_splitter->restoreGeometry(geometry);
auto state = settings.value("diagram/vsplitter/state").toByteArray();
if (!state.isEmpty())
m_splitter->restoreState(state);
}
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -2117,6 +2180,9 @@ void EasyThreadNameItem::paint(QPainter* _painter, const QStyleOptionGraphicsIte
_painter->drawRect(rect); _painter->drawRect(rect);
} }
if (h + 2 >= parentView->height())
return;
// Draw separator between thread names area and information area // Draw separator between thread names area and information area
_painter->setPen(::profiler_gui::SYSTEM_BORDER_COLOR); _painter->setPen(::profiler_gui::SYSTEM_BORDER_COLOR);
_painter->drawLine(QLineF(0, h, w, h)); _painter->drawLine(QLineF(0, h, w, h));

View File

@ -136,6 +136,7 @@ private:
qreal m_sceneWidth; ///< qreal m_sceneWidth; ///<
qreal m_scale; ///< Current scale qreal m_scale; ///< Current scale
qreal m_offset; ///< Have to use manual offset for all scene content instead of using scrollbars because QScrollBar::value is 32-bit integer :( qreal m_offset; ///< Have to use manual offset for all scene content instead of using scrollbars because QScrollBar::value is 32-bit integer :(
qreal m_visibleRegionWidth; ///< Visible scene rectangle in scene coordinates + width of vertical scrollbar (if visible)
qreal m_timelineStep; ///< qreal m_timelineStep; ///<
uint64_t m_idleTime; ///< uint64_t m_idleTime; ///<
QPoint m_mousePressPos; ///< Last mouse global position (used by mousePressEvent and mouseMoveEvent) QPoint m_mousePressPos; ///< Last mouse global position (used by mousePressEvent and mouseMoveEvent)
@ -156,7 +157,7 @@ private:
public: public:
explicit EasyGraphicsView(QWidget* _parent = nullptr); explicit EasyGraphicsView(QWidget* _parent = nullptr);
virtual ~EasyGraphicsView(); ~EasyGraphicsView() override;
// Public virtual methods // Public virtual methods
@ -198,6 +199,12 @@ private:
// Private non-virtual methods // Private non-virtual methods
void notifySceneSizeChange();
void notifyVisibleRegionSizeChange();
void notifyVisibleRegionSizeChange(qreal _size);
void notifyVisibleRegionPosChange();
void notifyVisibleRegionPosChange(qreal _pos);
void removePopup(bool _removeFromScene = false); void removePopup(bool _removeFromScene = false);
EasyChronometerItem* createChronometer(bool _main = true); EasyChronometerItem* createChronometer(bool _main = true);
@ -230,33 +237,33 @@ public:
// Public inline methods // Public inline methods
inline qreal scale() const qreal scale() const
{ {
return m_scale; return m_scale;
} }
inline qreal offset() const qreal offset() const
{ {
return m_offset; return m_offset;
} }
inline const QRectF& visibleSceneRect() const const QRectF& visibleSceneRect() const
{ {
return m_visibleSceneRect; return m_visibleSceneRect;
} }
inline qreal timelineStep() const qreal timelineStep() const
{ {
return m_timelineStep; return m_timelineStep;
} }
inline qreal time2position(const profiler::timestamp_t& _time) const qreal time2position(const profiler::timestamp_t& _time) const
{ {
return PROF_MICROSECONDS(qreal(_time - m_beginTime)); return PROF_MICROSECONDS(qreal(_time - m_beginTime));
//return PROF_MILLISECONDS(qreal(_time - m_beginTime)); //return PROF_MILLISECONDS(qreal(_time - m_beginTime));
} }
inline ::profiler::timestamp_t position2time(qreal _pos) const ::profiler::timestamp_t position2time(qreal _pos) const
{ {
return PROF_FROM_MICROSECONDS(_pos); return PROF_FROM_MICROSECONDS(_pos);
//return PROF_FROM_MILLISECONDS(_pos); //return PROF_FROM_MILLISECONDS(_pos);
@ -272,8 +279,8 @@ class EasyThreadNamesWidget : public QGraphicsView
private: private:
typedef QGraphicsView Parent; using Parent = QGraphicsView;
typedef EasyThreadNamesWidget This; using This = EasyThreadNamesWidget;
QTimer m_idleTimer; ///< QTimer m_idleTimer; ///<
uint64_t m_idleTime; ///< uint64_t m_idleTime; ///<
@ -285,7 +292,7 @@ private:
public: public:
explicit EasyThreadNamesWidget(EasyGraphicsView* _view, int _additionalHeight, QWidget* _parent = nullptr); explicit EasyThreadNamesWidget(EasyGraphicsView* _view, int _additionalHeight, QWidget* _parent = nullptr);
virtual ~EasyThreadNamesWidget(); ~EasyThreadNamesWidget() override;
void mousePressEvent(QMouseEvent* _event) override; void mousePressEvent(QMouseEvent* _event) override;
void mouseDoubleClickEvent(QMouseEvent* _event) override; void mouseDoubleClickEvent(QMouseEvent* _event) override;
@ -325,6 +332,7 @@ class EasyGraphicsViewWidget : public QWidget
private: private:
class QSplitter* m_splitter;
EasyGraphicsScrollbar* m_scrollbar; EasyGraphicsScrollbar* m_scrollbar;
EasyGraphicsView* m_view; EasyGraphicsView* m_view;
EasyThreadNamesWidget* m_threadNamesWidget; EasyThreadNamesWidget* m_threadNamesWidget;
@ -332,11 +340,14 @@ private:
public: public:
explicit EasyGraphicsViewWidget(QWidget* _parent = nullptr); explicit EasyGraphicsViewWidget(QWidget* _parent = nullptr);
virtual ~EasyGraphicsViewWidget(); ~EasyGraphicsViewWidget() override;
EasyGraphicsView* view(); EasyGraphicsView* view();
void clear(); void clear();
void save(class QSettings& settings);
void restore(class QSettings& settings);
private: private:
void initWidget(); void initWidget();

View File

@ -128,6 +128,10 @@ void set_max(T& _value) {
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
inline EASY_CONSTEXPR_FCN QRgb alpha(::profiler::color_t _color) {
return (_color & 0xff000000) >> 24;
}
inline EASY_CONSTEXPR_FCN QRgb toRgb(uint32_t _red, uint32_t _green, uint32_t _blue) { inline EASY_CONSTEXPR_FCN QRgb toRgb(uint32_t _red, uint32_t _green, uint32_t _blue) {
return (_red << 16) + (_green << 8) + _blue; return (_red << 16) + (_green << 8) + _blue;
} }
@ -136,6 +140,13 @@ inline EASY_CONSTEXPR_FCN QRgb fromProfilerRgb(uint32_t _red, uint32_t _green, u
return _red == 0 && _green == 0 && _blue == 0 ? ::profiler::colors::Default : toRgb(_red, _green, _blue) | 0x00141414; return _red == 0 && _green == 0 && _blue == 0 ? ::profiler::colors::Default : toRgb(_red, _green, _blue) | 0x00141414;
} }
inline QRgb darken(::profiler::color_t _color, float _part) {
const uint32_t r = (_color & 0x00ff0000) >> 16;
const uint32_t g = (_color & 0x0000ff00) >> 8;
const uint32_t b = _color & 0x000000ff;
return (_color & 0xff000000) | toRgb(r - static_cast<uint32_t>(r * _part), g - static_cast<uint32_t>(g * _part), b - static_cast<uint32_t>(b * _part));
}
EASY_FORCE_INLINE EASY_CONSTEXPR_FCN qreal colorSum(::profiler::color_t _color) { EASY_FORCE_INLINE EASY_CONSTEXPR_FCN qreal colorSum(::profiler::color_t _color) {
return 255. - (((_color & 0x00ff0000) >> 16) * 0.299 + ((_color & 0x0000ff00) >> 8) * 0.587 + (_color & 0x000000ff) * 0.114); return 255. - (((_color & 0x00ff0000) >> 16) * 0.299 + ((_color & 0x0000ff00) >> 8) * 0.587 + (_color & 0x000000ff) * 0.114);
} }

View File

@ -165,6 +165,20 @@ enum TimeUnits : int8_t
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
class BoolFlagGuard EASY_FINAL
{
bool& m_ref;
bool m_restore;
public:
explicit BoolFlagGuard(bool& flag) : m_ref(flag), m_restore(!flag) {}
explicit BoolFlagGuard(bool& flag, bool value) : m_ref(flag), m_restore(!value) { m_ref = value; }
~BoolFlagGuard() { restore(); }
void restore() { m_ref = m_restore; }
};
} // END of namespace profiler_gui. } // END of namespace profiler_gui.
template <typename ... Args> template <typename ... Args>

View File

@ -67,6 +67,7 @@
#include <QToolBar> #include <QToolBar>
#include <QVBoxLayout> #include <QVBoxLayout>
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QSplitter>
#include <QVariant> #include <QVariant>
#include <QTimer> #include <QTimer>
#include <thread> #include <thread>
@ -765,14 +766,20 @@ int EasyDescTreeWidget::findPrev(const QString& _str, Qt::MatchFlags _flags)
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
EasyDescWidget::EasyDescWidget(QWidget* _parent) : Parent(_parent) EasyDescWidget::EasyDescWidget(QWidget* _parent) : Parent(_parent)
, m_splitter(new QSplitter(Qt::Vertical, this))
, m_tree(new EasyDescTreeWidget(this)) , m_tree(new EasyDescTreeWidget(this))
, m_values(new EasyArbitraryValuesWidget(this)) , m_values(new ArbitraryValuesWidget(this))
, m_searchBox(new QLineEdit(this)) , m_searchBox(new QLineEdit(this))
, m_foundNumber(new QLabel("Found 0 matches", this)) , m_foundNumber(new QLabel("Found 0 matches", this))
, m_searchButton(nullptr) , m_searchButton(nullptr)
, m_bCaseSensitiveSearch(false) , m_bCaseSensitiveSearch(false)
{ {
loadSettings(); m_splitter->setHandleWidth(1);
m_splitter->setContentsMargins(0, 0, 0, 0);
m_splitter->addWidget(m_tree);
m_splitter->addWidget(m_values);
m_splitter->setStretchFactor(0, 1);
m_splitter->setStretchFactor(1, 1);
m_searchBox->setFixedWidth(300); m_searchBox->setFixedWidth(300);
m_searchBox->setContentsMargins(5, 0, 0, 0); m_searchBox->setContentsMargins(5, 0, 0, 0);
@ -812,6 +819,7 @@ EasyDescWidget::EasyDescWidget(QWidget* _parent) : Parent(_parent)
a->setChecked(m_bCaseSensitiveSearch); a->setChecked(m_bCaseSensitiveSearch);
connect(a, &QAction::triggered, [this](bool _checked){ m_bCaseSensitiveSearch = _checked; }); connect(a, &QAction::triggered, [this](bool _checked){ m_bCaseSensitiveSearch = _checked; });
menu->addAction(a); menu->addAction(a);
QAction* caseSensitiveSwitch = a;
menu->addSeparator(); menu->addSeparator();
auto headerItem = m_tree->headerItem(); auto headerItem = m_tree->headerItem();
@ -845,11 +853,13 @@ EasyDescWidget::EasyDescWidget(QWidget* _parent) : Parent(_parent)
auto lay = new QVBoxLayout(this); auto lay = new QVBoxLayout(this);
lay->setContentsMargins(1, 1, 1, 1); lay->setContentsMargins(1, 1, 1, 1);
lay->addLayout(searchbox); lay->addLayout(searchbox);
lay->addWidget(m_tree); lay->addWidget(m_splitter);
lay->addWidget(m_values);
connect(m_searchBox, &QLineEdit::returnPressed, this, &This::onSeachBoxReturnPressed); connect(m_searchBox, &QLineEdit::returnPressed, this, &This::onSeachBoxReturnPressed);
connect(&EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::connectionChanged, refreshButton, &QAction::setEnabled); connect(&EASY_GLOBALS.events, &::profiler_gui::EasyGlobalSignals::connectionChanged, refreshButton, &QAction::setEnabled);
loadSettings();
caseSensitiveSwitch->setChecked(m_bCaseSensitiveSearch);
} }
EasyDescWidget::~EasyDescWidget() EasyDescWidget::~EasyDescWidget()
@ -866,6 +876,14 @@ void EasyDescWidget::loadSettings()
if (!val.isNull()) if (!val.isNull())
m_bCaseSensitiveSearch = val.toBool(); m_bCaseSensitiveSearch = val.toBool();
auto geometry = settings.value("vsplitter/geometry").toByteArray();
if (!geometry.isEmpty())
m_splitter->restoreGeometry(geometry);
auto state = settings.value("vsplitter/state").toByteArray();
if (!state.isEmpty())
m_splitter->restoreState(state);
settings.endGroup(); settings.endGroup();
} }
@ -874,6 +892,8 @@ void EasyDescWidget::saveSettings()
QSettings settings(::profiler_gui::ORGANAZATION_NAME, ::profiler_gui::APPLICATION_NAME); QSettings settings(::profiler_gui::ORGANAZATION_NAME, ::profiler_gui::APPLICATION_NAME);
settings.beginGroup("EasyDescWidget"); settings.beginGroup("EasyDescWidget");
settings.setValue("case_sensitive", m_bCaseSensitiveSearch); settings.setValue("case_sensitive", m_bCaseSensitiveSearch);
settings.setValue("vsplitter/geometry", m_splitter->saveGeometry());
settings.setValue("vsplitter/state", m_splitter->saveState());
settings.endGroup(); settings.endGroup();
} }

View File

@ -90,7 +90,7 @@ private:
public: public:
explicit EasyDescWidgetItem(::profiler::block_id_t _desc, Parent* _parent = nullptr); explicit EasyDescWidgetItem(::profiler::block_id_t _desc, Parent* _parent = nullptr);
virtual ~EasyDescWidgetItem(); ~EasyDescWidgetItem() override;
bool operator < (const Parent& _other) const override; bool operator < (const Parent& _other) const override;
QVariant data(int _column, int _role) const override; QVariant data(int _column, int _role) const override;
@ -99,12 +99,12 @@ public:
// Public inline methods // Public inline methods
inline ::profiler::block_id_t desc() const ::profiler::block_id_t desc() const
{ {
return m_desc; return m_desc;
} }
inline void setType(Type _type) void setType(Type _type)
{ {
m_type = _type; m_type = _type;
} }
@ -117,12 +117,12 @@ class EasyDescTreeWidget : public QTreeWidget
{ {
Q_OBJECT Q_OBJECT
typedef QTreeWidget Parent; using Parent = QTreeWidget;
typedef EasyDescTreeWidget This; using This = EasyDescTreeWidget;
typedef ::std::vector<EasyDescWidgetItem*> Items; using Items = ::std::vector<EasyDescWidgetItem*>;
typedef ::std::vector<QTreeWidgetItem*> TreeItems; using TreeItems = ::std::vector<QTreeWidgetItem*>;
typedef ::std::unordered_set<::std::string> ExpandedFiles; using ExpandedFiles = ::std::unordered_set<::std::string>;
protected: protected:
@ -140,7 +140,7 @@ public:
// Public virtual methods // Public virtual methods
explicit EasyDescTreeWidget(QWidget* _parent = nullptr); explicit EasyDescTreeWidget(QWidget* _parent = nullptr);
virtual ~EasyDescTreeWidget(); ~EasyDescTreeWidget() override;
void contextMenuEvent(QContextMenuEvent* _event) override; void contextMenuEvent(QContextMenuEvent* _event) override;
public: public:
@ -183,13 +183,14 @@ class EasyDescWidget : public QWidget
{ {
Q_OBJECT Q_OBJECT
typedef QWidget Parent; using Parent = QWidget;
typedef EasyDescWidget This; using This = EasyDescWidget;
private: private:
class QSplitter* m_splitter;
EasyDescTreeWidget* m_tree; EasyDescTreeWidget* m_tree;
class EasyArbitraryValuesWidget* m_values; class ArbitraryValuesWidget* m_values;
class QLineEdit* m_searchBox; class QLineEdit* m_searchBox;
class QLabel* m_foundNumber; class QLabel* m_foundNumber;
class QAction* m_searchButton; class QAction* m_searchButton;
@ -200,7 +201,7 @@ public:
// Public virtual methods // Public virtual methods
explicit EasyDescWidget(QWidget* _parent = nullptr); explicit EasyDescWidget(QWidget* _parent = nullptr);
virtual ~EasyDescWidget(); ~EasyDescWidget() override;
void keyPressEvent(QKeyEvent* _event) override; void keyPressEvent(QKeyEvent* _event) override;
void contextMenuEvent(QContextMenuEvent* _event) override; void contextMenuEvent(QContextMenuEvent* _event) override;

View File

@ -772,44 +772,12 @@ void GraphicsHistogramItem::pickFrameTime(qreal _y) const
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
void GraphicsHistogramItem::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();
}
//////////////////////////////////////////////////////////////////////////
void GraphicsHistogramItem::onModeChanged() void GraphicsHistogramItem::onModeChanged()
{ {
if (!isImageUpdatePermitted()) if (!isImageUpdatePermitted())
return; return;
const auto widget = static_cast<const EasyGraphicsScrollbar*>(scene()->parent()); const auto widget = static_cast<const EasyGraphicsScrollbar*>(scene()->parent());
if (!widget->bindMode() && EASY_GLOBALS.auto_adjust_histogram_height) if (!widget->bindMode() && EASY_GLOBALS.auto_adjust_histogram_height)
{ {
m_topValue = m_maxValue; m_topValue = m_maxValue;
@ -827,7 +795,7 @@ bool GraphicsHistogramItem::updateImage()
if (!Parent::updateImage()) if (!Parent::updateImage())
return false; return false;
const auto widget = static_cast<const EasyGraphicsScrollbar*>(scene()->parent()); const auto widget = static_cast<const GraphicsSliderArea*>(scene()->parent());
m_imageScaleUpdate = widget->range() / widget->sliderWidth(); m_imageScaleUpdate = widget->range() / widget->sliderWidth();
m_imageOriginUpdate = widget->bindMode() ? (widget->value() - widget->sliderWidth() * 3) : widget->minimum(); m_imageOriginUpdate = widget->bindMode() ? (widget->value() - widget->sliderWidth() * 3) : widget->minimum();
@ -1151,62 +1119,21 @@ void GraphicsHistogramItem::updateImageAsync(QRectF _boundingRect, HistRegime _r
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
EasyGraphicsScrollbar::EasyGraphicsScrollbar(bool _fixedHeight, int _height, QWidget* _parent) EasyGraphicsScrollbar::EasyGraphicsScrollbar(int _initialHeight, QWidget* _parent)
: Parent(_parent) : Parent(_parent)
, m_minimumValue(0)
, m_maximumValue(500)
, m_value(10)
, m_windowScale(1)
, m_mouseButtons(Qt::NoButton)
, m_slider(nullptr)
, m_selectionIndicator(nullptr)
, m_histogramItem(nullptr) , m_histogramItem(nullptr)
, m_fontHeight(0)
, m_bScrolling(false)
, m_bBindMode(false)
, m_bLocked(false)
{ {
setCacheMode(QGraphicsView::CacheNone); const int sceneHeight = _initialHeight - 2;
setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
//setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate);
setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
setOptimizationFlag(QGraphicsView::DontSavePainterState, true);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setContentsMargins(0, 0, 0, 0);
setScene(new QGraphicsScene(this));
m_fontHeight = QFontMetrics(font()).height();
const int sceneHeight = _height - 2;
scene()->setSceneRect(0, -(sceneHeight >> 1), 500, sceneHeight); scene()->setSceneRect(0, -(sceneHeight >> 1), 500, sceneHeight);
if (_fixedHeight)
setFixedHeight(_height);
m_histogramItem = new GraphicsHistogramItem(); m_histogramItem = new GraphicsHistogramItem();
m_imageItem = m_histogramItem;
scene()->addItem(m_histogramItem); scene()->addItem(m_histogramItem);
m_histogramItem->setPos(0, 0); m_histogramItem->setPos(0, 0);
m_histogramItem->setBoundingRect(0, scene()->sceneRect().top() + margin(), scene()->width(), sceneHeight - margins() - 1); m_histogramItem->setBoundingRect(0, scene()->sceneRect().top() + margin(), scene()->width(), sceneHeight - margins() - 1);
m_histogramItem->hide(); m_histogramItem->hide();
m_selectionIndicator = new GraphicsSliderItem(6, false);
scene()->addItem(m_selectionIndicator);
m_selectionIndicator->setPos(0, 0);
m_selectionIndicator->setColor(0x40000000 | profiler_gui::CHRONOMETER_COLOR.rgba());
m_selectionIndicator->hide();
m_slider = new GraphicsSliderItem(6, true);
scene()->addItem(m_slider);
m_slider->setPos(0, 0);
m_slider->setColor(0x40c0c0c0);
m_slider->hide();
connect(&EASY_GLOBALS.events, &profiler_gui::EasyGlobalSignals::expectedFrameTimeChanged, [this]() connect(&EASY_GLOBALS.events, &profiler_gui::EasyGlobalSignals::expectedFrameTimeChanged, [this]()
{ {
if (m_histogramItem->isVisible()) if (m_histogramItem->isVisible())
@ -1231,7 +1158,13 @@ EasyGraphicsScrollbar::EasyGraphicsScrollbar(bool _fixedHeight, int _height, QWi
connect(&EASY_GLOBALS.events, &profiler_gui::EasyGlobalSignals::threadNameDecorationChanged, this, &This::onThreadViewChanged); connect(&EASY_GLOBALS.events, &profiler_gui::EasyGlobalSignals::threadNameDecorationChanged, this, &This::onThreadViewChanged);
connect(&EASY_GLOBALS.events, &profiler_gui::EasyGlobalSignals::hexThreadIdChanged, this, &This::onThreadViewChanged); connect(&EASY_GLOBALS.events, &profiler_gui::EasyGlobalSignals::hexThreadIdChanged, this, &This::onThreadViewChanged);
centerOn(0, 0); if (!EASY_GLOBALS.scene.empty)
{
setRange(EASY_GLOBALS.scene.left, EASY_GLOBALS.scene.right);
setSliderWidth(EASY_GLOBALS.scene.window);
setValue(EASY_GLOBALS.scene.offset);
m_slider->show();
}
} }
EasyGraphicsScrollbar::~EasyGraphicsScrollbar() EasyGraphicsScrollbar::~EasyGraphicsScrollbar()

View File

@ -112,7 +112,6 @@ public:
bool decreaseBottomValue() override; bool decreaseBottomValue() override;
void onModeChanged() override; void onModeChanged() override;
void onValueChanged() override;
public: public:
@ -156,7 +155,7 @@ private:
public: public:
explicit EasyGraphicsScrollbar(bool _fixedHeight, int _height, QWidget* _parent = nullptr); explicit EasyGraphicsScrollbar(int _initialHeight, QWidget* _parent = nullptr);
~EasyGraphicsScrollbar() override; ~EasyGraphicsScrollbar() override;
void clear() override; void clear() override;

View File

@ -75,8 +75,6 @@ namespace profiler_gui {
, chronometer_font(::profiler_gui::EFont("DejaVu Sans", 16, QFont::Bold)) , chronometer_font(::profiler_gui::EFont("DejaVu Sans", 16, QFont::Bold))
, items_font(::profiler_gui::EFont("DejaVu Sans", 10, QFont::Medium)) , items_font(::profiler_gui::EFont("DejaVu Sans", 10, QFont::Medium))
, selected_item_font(::profiler_gui::EFont("DejaVu Sans", 10, QFont::Medium)) , selected_item_font(::profiler_gui::EFont("DejaVu Sans", 10, QFont::Medium))
, scene_left(0)
, scene_right(100)
, begin_time(0) , begin_time(0)
, selected_thread(0U) , selected_thread(0U)
, selected_block(::profiler_gui::numeric_max<decltype(selected_block)>()) , selected_block(::profiler_gui::numeric_max<decltype(selected_block)>())
@ -109,6 +107,7 @@ namespace profiler_gui {
, highlight_blocks_with_same_id(true) , highlight_blocks_with_same_id(true)
, selecting_block_changes_thread(true) , selecting_block_changes_thread(true)
, auto_adjust_histogram_height(true) , auto_adjust_histogram_height(true)
, auto_adjust_chart_height(true)
, display_only_frames_on_histogram(false) , display_only_frames_on_histogram(false)
, bind_scene_and_tree_expand_status(true) , bind_scene_and_tree_expand_status(true)
{ {

View File

@ -162,6 +162,15 @@ namespace profiler_gui {
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
struct SceneData Q_DECL_FINAL
{
qreal left = 0;
qreal right = 100;
qreal window = 100;
qreal offset = 0;
bool empty = true;
};
struct EasyGlobals Q_DECL_FINAL struct EasyGlobals Q_DECL_FINAL
{ {
static EasyGlobals& instance(); static EasyGlobals& instance();
@ -177,8 +186,7 @@ namespace profiler_gui {
QFont items_font; ///< Font for easy_graphics_item QFont items_font; ///< Font for easy_graphics_item
QFont selected_item_font; ///< Font for easy_graphics_item QFont selected_item_font; ///< Font for easy_graphics_item
double scene_left; ///< Graphics scene left boundary SceneData scene; ///<
double scene_right; ///< Graphics scene right boundary
::profiler::timestamp_t begin_time; ///< ::profiler::timestamp_t begin_time; ///<
::profiler::thread_id_t selected_thread; ///< Current selected thread id ::profiler::thread_id_t selected_thread; ///< Current selected thread id
::profiler::block_index_t selected_block; ///< Current selected profiler block index ::profiler::block_index_t selected_block; ///< Current selected profiler block index
@ -211,6 +219,7 @@ namespace profiler_gui {
bool highlight_blocks_with_same_id; ///< Highlight all blocks with same id on diagram bool highlight_blocks_with_same_id; ///< Highlight all blocks with same id on diagram
bool selecting_block_changes_thread; ///< If true then current selected thread will change every time you select block bool selecting_block_changes_thread; ///< If true then current selected thread will change every time you select block
bool auto_adjust_histogram_height; ///< Automatically adjust histogram height to the visible region bool auto_adjust_histogram_height; ///< Automatically adjust histogram height to the visible region
bool auto_adjust_chart_height; ///< Automatically adjust arbitrary value chart height to the visible region
bool display_only_frames_on_histogram; ///< Display only top-level blocks on histogram when drawing histogram by block id bool display_only_frames_on_histogram; ///< Display only top-level blocks on histogram when drawing histogram by block id
bool bind_scene_and_tree_expand_status; /** \brief If true then items on graphics scene and in the tree (blocks hierarchy) are binded on each other bool bind_scene_and_tree_expand_status; /** \brief If true then items on graphics scene and in the tree (blocks hierarchy) are binded on each other
so expanding/collapsing items on scene also expands/collapse items in the tree. */ so expanding/collapsing items on scene also expands/collapse items in the tree. */

View File

@ -67,7 +67,7 @@ namespace profiler_gui {
public: public:
EasyGlobalSignals(); EasyGlobalSignals();
virtual ~EasyGlobalSignals(); ~EasyGlobalSignals() Q_DECL_OVERRIDE;
signals: signals:
@ -80,13 +80,23 @@ namespace profiler_gui {
void blocksRefreshRequired(bool); void blocksRefreshRequired(bool);
void expectedFrameTimeChanged(); void expectedFrameTimeChanged();
void autoAdjustHistogramChanged(); void autoAdjustHistogramChanged();
void autoAdjustChartChanged();
void displayOnlyFramesOnHistogramChanged(); void displayOnlyFramesOnHistogramChanged();
void hierarchyFlagChanged(bool); void hierarchyFlagChanged(bool);
void threadNameDecorationChanged(); void threadNameDecorationChanged();
void hexThreadIdChanged(); void hexThreadIdChanged();
void refreshRequired(); void refreshRequired();
void blocksTreeModeChanged(); void blocksTreeModeChanged();
void sceneSizeChanged();
void sceneCleared();
void sceneSizeChanged(qreal left, qreal right);
void sceneVisibleRegionSizeChanged(qreal width);
void sceneVisibleRegionPosChanged(qreal pos);
void lockCharts();
void unlockCharts();
void chartWheeled(qreal pos, int delta);
void chartSliderChanged(qreal pos);
}; // END of class EasyGlobalSignals. }; // END of class EasyGlobalSignals.

View File

@ -71,14 +71,10 @@ bool GraphicsImageItem::updateImage()
return true; return true;
} }
void GraphicsImageItem::onValueChanged() void GraphicsImageItem::onValueChanged()
{ {
const auto widget = qobject_cast<const GraphicsSliderArea*>(scene()->parent()); const auto widget = qobject_cast<const GraphicsSliderArea*>(scene()->parent());
if (widget == nullptr) if (widget == nullptr || !widget->bindMode())
return;
if (!widget->bindMode())
return; return;
m_boundaryTimer.stop(); m_boundaryTimer.stop();

View File

@ -55,7 +55,6 @@ public:
virtual bool updateImage(); virtual bool updateImage();
virtual void onModeChanged(); virtual void onModeChanged();
virtual void onValueChanged();
protected: protected:
@ -63,6 +62,7 @@ protected:
public: public:
void onValueChanged();
void setMousePos(const QPointF& pos); void setMousePos(const QPointF& pos);
void setMousePos(qreal x, qreal y); void setMousePos(qreal x, qreal y);
void setBoundingRect(const QRectF& _rect); void setBoundingRect(const QRectF& _rect);

View File

@ -172,11 +172,13 @@ GraphicsSliderArea::GraphicsSliderArea(QWidget* _parent)
, m_mouseButtons(Qt::NoButton) , m_mouseButtons(Qt::NoButton)
, m_slider(nullptr) , m_slider(nullptr)
, m_selectionIndicator(nullptr) , m_selectionIndicator(nullptr)
, m_histogramItem(nullptr) , m_imageItem(nullptr)
, m_fontHeight(0) , m_fontHeight(0)
, m_bScrolling(false) , m_bScrolling(false)
, m_bBindMode(false) , m_bBindMode(false)
, m_bLocked(false) , m_bLocked(false)
, m_bUpdatingPos(false)
, m_bEmitChange(true)
{ {
setCacheMode(QGraphicsView::CacheNone); setCacheMode(QGraphicsView::CacheNone);
setTransformationAnchor(QGraphicsView::AnchorUnderMouse); setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
@ -191,19 +193,13 @@ GraphicsSliderArea::GraphicsSliderArea(QWidget* _parent)
setScene(new QGraphicsScene(this)); setScene(new QGraphicsScene(this));
m_fontHeight = QFontMetrics(font()).height(); m_fontHeight = QFontMetrics(font()).height() + 1;
EASY_CONSTEXPR int SceneHeight = 500; EASY_CONSTEXPR int SceneHeight = 500;
scene()->setSceneRect(0, -(SceneHeight >> 1), 500, SceneHeight); scene()->setSceneRect(0, -(SceneHeight >> 1), 500, SceneHeight);
m_histogramItem = new GraphicsHistogramItem();
scene()->addItem(m_histogramItem);
m_histogramItem->setPos(0, 0);
m_histogramItem->setBoundingRect(0, scene()->sceneRect().top() + margin(), scene()->width(), SceneHeight - margins() - 1);
m_histogramItem->hide();
m_selectionIndicator = new GraphicsSliderItem(6, false); m_selectionIndicator = new GraphicsSliderItem(6, false);
m_selectionIndicator->setZValue(1);
scene()->addItem(m_selectionIndicator); scene()->addItem(m_selectionIndicator);
m_selectionIndicator->setPos(0, 0); m_selectionIndicator->setPos(0, 0);
@ -211,16 +207,38 @@ GraphicsSliderArea::GraphicsSliderArea(QWidget* _parent)
m_selectionIndicator->hide(); m_selectionIndicator->hide();
m_slider = new GraphicsSliderItem(6, true); m_slider = new GraphicsSliderItem(6, true);
m_slider->setZValue(2);
scene()->addItem(m_slider); scene()->addItem(m_slider);
m_slider->setPos(0, 0); m_slider->setPos(0, 0);
m_slider->setColor(0x40c0c0c0); m_slider->setColor(0x40c0c0c0);
m_slider->hide(); m_slider->hide();
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); centerOn(0, 0);
auto globalEvents = &EASY_GLOBALS.events;
connect(globalEvents, &profiler_gui::EasyGlobalSignals::sceneCleared, this, &This::clear);
connect(globalEvents, &profiler_gui::EasyGlobalSignals::sceneVisibleRegionSizeChanged, this, &This::setSliderWidth);
connect(globalEvents, &profiler_gui::EasyGlobalSignals::sceneVisibleRegionPosChanged, this, &This::setValue);
connect(globalEvents, &profiler_gui::EasyGlobalSignals::chartSliderChanged, [this] (qreal pos)
{
if (!m_bUpdatingPos)
{
m_bEmitChange = false;
setValue(pos);
m_bEmitChange = true;
}
});
connect(globalEvents, &profiler_gui::EasyGlobalSignals::sceneSizeChanged, [this] (qreal left, qreal right)
{
setRange(left, right);
m_slider->show();
});
connect(globalEvents, &profiler_gui::EasyGlobalSignals::lockCharts, this, &This::lock);
connect(globalEvents, &profiler_gui::EasyGlobalSignals::unlockCharts, this, &This::unlock);
} }
GraphicsSliderArea::~GraphicsSliderArea() GraphicsSliderArea::~GraphicsSliderArea()
@ -232,10 +250,11 @@ GraphicsSliderArea::~GraphicsSliderArea()
void GraphicsSliderArea::clear() void GraphicsSliderArea::clear()
{ {
m_selectionIndicator->hide();
setRange(0, 100); setRange(0, 100);
setSliderWidth(2); setSliderWidth(2);
setValue(0); setValue(0);
m_selectionIndicator->hide();
m_slider->hide();
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -299,10 +318,18 @@ int GraphicsSliderArea::margins() const
void GraphicsSliderArea::setValue(qreal _value) void GraphicsSliderArea::setValue(qreal _value)
{ {
using estd::clamp; if (m_bUpdatingPos)
m_value = clamp(m_minimumValue, _value, std::max(m_minimumValue, m_maximumValue - m_slider->width())); return;
const profiler_gui::BoolFlagGuard guard(m_bUpdatingPos, true);
m_value = estd::clamp(m_minimumValue, _value, std::max(m_minimumValue, m_maximumValue - m_slider->width()));
m_slider->setX(m_value + m_slider->halfwidth()); m_slider->setX(m_value + m_slider->halfwidth());
emit valueChanged(m_value);
if (m_bEmitChange)
{
emit EASY_GLOBALS.events.chartSliderChanged(m_value);
}
if (m_imageItem->isVisible()) if (m_imageItem->isVisible())
m_imageItem->onValueChanged(); m_imageItem->onValueChanged();
@ -324,8 +351,6 @@ void GraphicsSliderArea::setRange(qreal _minValue, qreal _maxValue)
m_imageItem->cancelImageUpdate(); m_imageItem->cancelImageUpdate();
m_imageItem->setBoundingRect(_minValue, histogramRect.top(), range, histogramRect.height()); m_imageItem->setBoundingRect(_minValue, histogramRect.top(), range, histogramRect.height());
emit rangeChanged();
setValue(_minValue + oldValue * range); setValue(_minValue + oldValue * range);
onWindowWidthChange(width()); onWindowWidthChange(width());
@ -432,7 +457,7 @@ void GraphicsSliderArea::mouseMoveEvent(QMouseEvent* _event)
} }
} }
m_imageItem->setMousePos(mapToScene(pos)); m_imageItem->setMousePos(pos.x(), mapToScene(pos).y());
if (m_imageItem->isVisible()) if (m_imageItem->isVisible())
scene()->update(); scene()->update();
} }
@ -475,28 +500,52 @@ void GraphicsSliderArea::wheelEvent(QWheelEvent* _event)
{ {
const auto w = m_slider->halfwidth() * (_event->delta() < 0 ? profiler_gui::SCALING_COEFFICIENT : profiler_gui::SCALING_COEFFICIENT_INV); 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); setValue(mapToScene(_event->pos()).x() - m_minimumValue - w);
emit wheeled(w * m_windowScale, _event->delta()); emit EASY_GLOBALS.events.chartWheeled(w * m_windowScale, _event->delta());
} }
else else
{ {
const auto x = (mapToScene(_event->pos()).x() - m_minimumValue) * m_windowScale; const auto x = (mapToScene(_event->pos()).x() - m_minimumValue) * m_windowScale;
emit wheeled(x, _event->delta()); emit EASY_GLOBALS.events.chartWheeled(x, _event->delta());
} }
} }
void GraphicsSliderArea::resizeEvent(QResizeEvent* _event) void GraphicsSliderArea::resizeEvent(QResizeEvent* _event)
{ {
const int h = _event->size().height(); const int h = _event->size().height();
if (h == 0)
{
if (m_imageItem->isVisible())
m_imageItem->cancelImageUpdate();
onWindowWidthChange(_event->size().width());
return;
}
if (_event->oldSize().height() != h) if (_event->oldSize().height() != h)
{ {
auto rect = scene()->sceneRect();
const int sceneHeight = h - 2; const int sceneHeight = h - 2;
scene()->setSceneRect(0, -(sceneHeight >> 1), 500, sceneHeight); const int top = -(sceneHeight >> 1);
scene()->setSceneRect(rect.left(), top, rect.width(), sceneHeight);
const auto br = m_imageItem->boundingRect(); const auto br = m_imageItem->boundingRect();
m_imageItem->setBoundingRect(br.left(), scene()->sceneRect().top() + margin(), br.width(), sceneHeight - margins() - 1); m_imageItem->setBoundingRect(br.left(), top + margin(), br.width(), sceneHeight - margins() - 1);
rect = m_slider->rect();
m_slider->setRect(rect.left(), top, rect.width(), sceneHeight);
if (m_selectionIndicator->isVisible())
{
rect = m_selectionIndicator->rect();
m_selectionIndicator->setRect(rect.left(), top, rect.width(), sceneHeight);
}
} }
onWindowWidthChange(_event->size().width()); onWindowWidthChange(_event->size().width());
if (m_imageItem->isVisible()) if (m_imageItem->isVisible())
m_imageItem->updateImage(); m_imageItem->updateImage();
} }

View File

@ -101,12 +101,13 @@ protected:
Qt::MouseButtons m_mouseButtons; Qt::MouseButtons m_mouseButtons;
GraphicsSliderItem* m_slider; GraphicsSliderItem* m_slider;
GraphicsSliderItem* m_selectionIndicator; GraphicsSliderItem* m_selectionIndicator;
GraphicsHistogramItem* m_histogramItem;
GraphicsImageItem* m_imageItem; GraphicsImageItem* m_imageItem;
int m_fontHeight; int m_fontHeight;
bool m_bScrolling; bool m_bScrolling;
bool m_bBindMode; bool m_bBindMode;
bool m_bLocked; bool m_bLocked;
bool m_bUpdatingPos;
bool m_bEmitChange;
public: public:
@ -121,6 +122,7 @@ public:
void wheelEvent(QWheelEvent* _event) override; void wheelEvent(QWheelEvent* _event) override;
void resizeEvent(QResizeEvent* _event) override; void resizeEvent(QResizeEvent* _event) override;
void dragEnterEvent(QDragEnterEvent*) override {} void dragEnterEvent(QDragEnterEvent*) override {}
void contextMenuEvent(QContextMenuEvent*) override {}
virtual void clear(); virtual void clear();
@ -148,19 +150,10 @@ public:
void showSelectionIndicator(); void showSelectionIndicator();
void hideSelectionIndicator(); void hideSelectionIndicator();
inline void lock() { public slots:
m_bLocked = true;
}
inline void unlock() { void lock() { m_bLocked = true; }
m_bLocked = false; void unlock() { m_bLocked = false; }
}
signals:
void rangeChanged();
void valueChanged(qreal _value);
void wheeled(qreal _mouseX, int _wheelDelta);
protected slots: protected slots:

View File

@ -215,6 +215,7 @@ EasyMainWindow::EasyMainWindow() : Parent(), m_theme("default"), m_lastAddress("
m_graphicsView->setAllowedAreas(Qt::AllDockWidgetAreas); m_graphicsView->setAllowedAreas(Qt::AllDockWidgetAreas);
auto graphicsView = new EasyGraphicsViewWidget(this); auto graphicsView = new EasyGraphicsViewWidget(this);
graphicsView->setObjectName("ProfilerGUI_Diagram_GraphicsView");
m_graphicsView->setWidget(graphicsView); m_graphicsView->setWidget(graphicsView);
m_treeWidget = new EasyDockWidget("Hierarchy", this); m_treeWidget = new EasyDockWidget("Hierarchy", this);
@ -449,6 +450,16 @@ EasyMainWindow::EasyMainWindow() : Parent(), m_theme("default"), m_lastAddress("
emit EASY_GLOBALS.events.autoAdjustHistogramChanged(); emit EASY_GLOBALS.events.autoAdjustHistogramChanged();
}); });
action = submenu->addAction("Automatically adjust chart height");
action->setToolTip("Same as similar option for histogram\nbut used for arbitrary values charts.");
action->setCheckable(true);
action->setChecked(EASY_GLOBALS.auto_adjust_chart_height);
connect(action, &QAction::triggered, [](bool _checked)
{
EASY_GLOBALS.auto_adjust_chart_height = _checked;
emit EASY_GLOBALS.events.autoAdjustChartChanged();
});
action = submenu->addAction("Use decorated thread names"); action = submenu->addAction("Use decorated thread names");
action->setToolTip("Add \'Thread\' word into thread name if there is no one already.\nExamples: \'Render\' will change to \'Render Thread\'\n\'WorkerThread\' will not change."); action->setToolTip("Add \'Thread\' word into thread name if there is no one already.\nExamples: \'Render\' will change to \'Render Thread\'\n\'WorkerThread\' will not change.");
action->setCheckable(true); action->setCheckable(true);
@ -1236,7 +1247,6 @@ void EasyMainWindow::onEditBlocksClicked(bool)
m_descTreeDialog = new QDialog(); m_descTreeDialog = new QDialog();
m_descTreeDialog->setAttribute(Qt::WA_DeleteOnClose, true); m_descTreeDialog->setAttribute(Qt::WA_DeleteOnClose, true);
m_descTreeDialog->setWindowTitle(EASY_DEFAULT_WINDOW_TITLE); m_descTreeDialog->setWindowTitle(EASY_DEFAULT_WINDOW_TITLE);
m_descTreeDialog->resize(800, 600);
connect(m_descTreeDialog, &QDialog::finished, this, &This::onDescTreeDialogClose); connect(m_descTreeDialog, &QDialog::finished, this, &This::onDescTreeDialogClose);
auto l = new QVBoxLayout(m_descTreeDialog); auto l = new QVBoxLayout(m_descTreeDialog);
@ -1379,6 +1389,10 @@ void EasyMainWindow::loadSettings()
if (!flag.isNull()) if (!flag.isNull())
EASY_GLOBALS.auto_adjust_histogram_height = flag.toBool(); EASY_GLOBALS.auto_adjust_histogram_height = flag.toBool();
flag = settings.value("auto_adjust_chart_height");
if (!flag.isNull())
EASY_GLOBALS.auto_adjust_chart_height = flag.toBool();
flag = settings.value("display_only_frames_on_histogram"); flag = settings.value("display_only_frames_on_histogram");
if (!flag.isNull()) if (!flag.isNull())
EASY_GLOBALS.display_only_frames_on_histogram = flag.toBool(); EASY_GLOBALS.display_only_frames_on_histogram = flag.toBool();
@ -1434,6 +1448,16 @@ void EasyMainWindow::loadGeometry()
if (!geometry.isEmpty()) if (!geometry.isEmpty())
restoreGeometry(geometry); restoreGeometry(geometry);
geometry = settings.value("fpsGeometry").toByteArray();
if (!geometry.isEmpty())
m_fpsViewer->restoreGeometry(geometry);
geometry = settings.value("diagramGeometry").toByteArray();
if (!geometry.isEmpty())
m_graphicsView->restoreGeometry(geometry);
static_cast<EasyGraphicsViewWidget*>(m_graphicsView->widget())->restore(settings);
auto state = settings.value("windowState").toByteArray(); auto state = settings.value("windowState").toByteArray();
if (!state.isEmpty()) if (!state.isEmpty())
restoreState(state); restoreState(state);
@ -1447,7 +1471,12 @@ void EasyMainWindow::saveSettingsAndGeometry()
settings.beginGroup("main"); settings.beginGroup("main");
settings.setValue("geometry", this->saveGeometry()); settings.setValue("geometry", this->saveGeometry());
settings.setValue("fpsGeometry", m_fpsViewer->saveGeometry());
settings.setValue("diagramGeometry", m_graphicsView->saveGeometry());
static_cast<EasyGraphicsViewWidget*>(m_graphicsView->widget())->save(settings);
settings.setValue("windowState", this->saveState()); settings.setValue("windowState", this->saveState());
settings.setValue("last_files", m_lastFiles); settings.setValue("last_files", m_lastFiles);
settings.setValue("ip_address", m_lastAddress); settings.setValue("ip_address", m_lastAddress);
settings.setValue("port", (quint32)m_lastPort); settings.setValue("port", (quint32)m_lastPort);
@ -1470,6 +1499,7 @@ void EasyMainWindow::saveSettingsAndGeometry()
settings.setValue("selecting_block_changes_thread", EASY_GLOBALS.selecting_block_changes_thread); settings.setValue("selecting_block_changes_thread", EASY_GLOBALS.selecting_block_changes_thread);
settings.setValue("enable_event_indicators", EASY_GLOBALS.enable_event_markers); settings.setValue("enable_event_indicators", EASY_GLOBALS.enable_event_markers);
settings.setValue("auto_adjust_histogram_height", EASY_GLOBALS.auto_adjust_histogram_height); settings.setValue("auto_adjust_histogram_height", EASY_GLOBALS.auto_adjust_histogram_height);
settings.setValue("auto_adjust_chart_height", EASY_GLOBALS.auto_adjust_chart_height);
settings.setValue("display_only_frames_on_histogram", EASY_GLOBALS.display_only_frames_on_histogram); settings.setValue("display_only_frames_on_histogram", EASY_GLOBALS.display_only_frames_on_histogram);
settings.setValue("use_decorated_thread_name", EASY_GLOBALS.use_decorated_thread_name); settings.setValue("use_decorated_thread_name", EASY_GLOBALS.use_decorated_thread_name);
settings.setValue("hex_thread_id", EASY_GLOBALS.hex_thread_id); settings.setValue("hex_thread_id", EASY_GLOBALS.hex_thread_id);

View File

@ -30,6 +30,12 @@ QToolTip {
QGraphicsView { QGraphicsView {
border: 1px solid #cccccc; } border: 1px solid #cccccc; }
QSplitter::handle:hover {
background-color: rgba(244, 67, 54, 0.5); }
QSplitter::handle:pressed {
background-color: #f44336; }
/* ****************************************************************************************************************** */ /* ****************************************************************************************************************** */
QLineEdit, QComboBox, QSpinBox { QLineEdit, QComboBox, QSpinBox {
height: 24px; height: 24px;

View File

@ -55,6 +55,14 @@ QGraphicsView {
border: 1px solid $BorderColor; border: 1px solid $BorderColor;
} }
QSplitter::handle:hover {
background-color: rgb_a($MainColor, 0.5);
}
QSplitter::handle:pressed {
background-color: $MainColor;
}
/* ****************************************************************************************************************** */ /* ****************************************************************************************************************** */
QLineEdit, QComboBox, QSpinBox { QLineEdit, QComboBox, QSpinBox {
height: $DefaultHeight; height: $DefaultHeight;