0
0
mirror of https://github.com/yse/easy_profiler.git synced 2024-12-26 08:01:51 +08:00

Release 2.0 further work. Intermediate commit.

This commit is contained in:
Victor Zarubkin 2018-01-20 15:23:28 +03:00
parent 9cd1f62fce
commit 694497b5ca
16 changed files with 1570 additions and 1335 deletions

View File

@ -141,6 +141,7 @@ set(INCLUDE_FILES
${EASY_INCLUDE_DIR}/easy_socket.h
${EASY_INCLUDE_DIR}/profiler.h
${EASY_INCLUDE_DIR}/reader.h
${EASY_INCLUDE_DIR}/utility.h
${EASY_INCLUDE_DIR}/serialized_block.h
${EASY_INCLUDE_DIR}/details/arbitrary_value_aux.h
${EASY_INCLUDE_DIR}/details/arbitrary_value_public_types.h

View File

@ -126,13 +126,13 @@
//extern ProfileManager& MANAGER;
#define MANAGER ProfileManager::instance()
extern const ::profiler::color_t EASY_COLOR_INTERNAL_EVENT;
extern const profiler::color_t EASY_COLOR_INTERNAL_EVENT;
#ifdef __MINGW32__
::std::atomic<uint64_t> TRACING_END_TIME = ATOMIC_VAR_INIT(~0ULL);
std::atomic<uint64_t> TRACING_END_TIME = ATOMIC_VAR_INIT(~0ULL);
char KERNEL_LOGGER[] = KERNEL_LOGGER_NAME;
#else
::std::atomic_uint64_t TRACING_END_TIME = ATOMIC_VAR_INIT(~0ULL);
std::atomic_uint64_t TRACING_END_TIME = ATOMIC_VAR_INIT(~0ULL);
#endif
/**
@ -171,7 +171,7 @@ namespace profiler {
//////////////////////////////////////////////////////////////////////////
struct ProcessInfo {
std::string name;
::std::string name;
processid_t id = 0;
int8_t valid = 0;
};
@ -205,12 +205,12 @@ namespace profiler {
}
};
typedef ::std::unordered_map<decltype(CSwitch::NewThreadId), ProcessInfo*, do_not_calc_hash> thread_process_info_map;
typedef ::std::unordered_map<processid_t, ProcessInfo, do_not_calc_hash> process_info_map;
using thread_process_info_map = ::std::unordered_map<decltype(CSwitch::NewThreadId), ProcessInfo*, do_not_calc_hash>;
using process_info_map = ::std::unordered_map<processid_t, ProcessInfo, do_not_calc_hash>;
// Using static is safe because processTraceEvent() is called from one thread
process_info_map PROCESS_INFO_TABLE;
thread_process_info_map THREAD_PROCESS_INFO_TABLE = ([](){ thread_process_info_map initial; initial[0U] = nullptr; return ::std::move(initial); })();
thread_process_info_map THREAD_PROCESS_INFO_TABLE = ([] { thread_process_info_map initial; initial[0U] = nullptr; return ::std::move(initial); })();
//////////////////////////////////////////////////////////////////////////

View File

@ -23,7 +23,13 @@ namespace estd {
}
template <class T> struct hash EASY_FINAL : public ::estd::detail::hasher<T, (sizeof(T) > sizeof(void*))> {
using ::estd::detail::hasher<T, (sizeof(T) > sizeof(void*))>::operator();
using Parent = ::estd::detail::hasher<T, (sizeof(T) > sizeof(void*))>;
#if defined(_MSC_VER) && _MSC_VER >= 1910
// TODO: Try to compile "using Parent::operator();" in MSVC 2017
size_t operator () (typename Parent::type value) const { return Parent::operator () (value); }
#else
using Parent::operator();
#endif
};
template <class T> struct hash<T*> EASY_FINAL {

View File

@ -484,8 +484,8 @@ extern "C" {
int64_t file_cpu_frequency = 0LL;
inFile.read((char*)&file_cpu_frequency, sizeof(int64_t));
uint64_t cpu_frequency = file_cpu_frequency;
const double conversion_factor = static_cast<double>(TIME_FACTOR) / static_cast<double>(cpu_frequency);
const uint64_t cpu_frequency = file_cpu_frequency;
const double conversion_factor = (cpu_frequency != 0 ? static_cast<double>(TIME_FACTOR) / static_cast<double>(cpu_frequency) : 1.);
::profiler::timestamp_t begin_time = 0ULL;
::profiler::timestamp_t end_time = 0ULL;
@ -749,7 +749,7 @@ extern "C" {
/**/
EASY_BLOCK("Find children", ::profiler::colors::Blue);
auto rlower1 = ++root.children.rbegin();
for (; rlower1 != root.children.rend() && !(mt0 > blocks[*rlower1].node->begin()); ++rlower1);
for (; rlower1 != root.children.rend() && mt0 <= blocks[*rlower1].node->begin(); ++rlower1);
auto lower = rlower1.base();
::std::move(lower, root.children.end(), ::std::back_inserter(tree.children));

View File

@ -36,6 +36,10 @@ if (Qt5Widgets_FOUND)
globals.h
globals.cpp
globals_qobjects.cpp
graphics_image_item.h
graphics_image_item.cpp
graphics_slider_area.h
graphics_slider_area.cpp
main_window.h
main_window.cpp
tree_widget_item.h

View File

@ -881,7 +881,7 @@ void EasyGraphicsView::mousePressEvent(QMouseEvent* _event)
const auto mouseX = m_offset + mapToScene(m_mousePressPos).x() / m_scale;
m_chronometerItem->setLeftRight(mouseX, mouseX);
m_chronometerItem->hide();
m_pScrollbar->hideChrono();
m_pScrollbar->hideSelectionIndicator();
}
}
@ -932,7 +932,7 @@ void EasyGraphicsView::mouseReleaseEvent(QMouseEvent* _event)
if (m_chronometerItem->isVisible() && m_chronometerItem->width() < 1e-6)
{
m_chronometerItem->hide();
m_pScrollbar->hideChrono();
m_pScrollbar->hideSelectionIndicator();
}
if (!m_selectedBlocks.empty())
@ -1144,11 +1144,11 @@ void EasyGraphicsView::mouseMoveEvent(QMouseEvent* _event)
if (m_mouseButtons & Qt::RightButton)
{
bool showItem = moveChrono(m_chronometerItem, x);
m_pScrollbar->setChronoPos(m_chronometerItem->left(), m_chronometerItem->right());
m_pScrollbar->setSelectionPos(m_chronometerItem->left(), m_chronometerItem->right());
if (showItem)
{
m_pScrollbar->showChrono();
m_pScrollbar->showSelectionIndicator();
}
needUpdate = true;
@ -2006,7 +2006,7 @@ void EasyGraphicsView::onRefreshRequired()
EasyGraphicsViewWidget::EasyGraphicsViewWidget(QWidget* _parent)
: QWidget(_parent)
, m_scrollbar(new EasyGraphicsScrollbar(this))
, m_scrollbar(new EasyGraphicsScrollbar(true, 85 + (QFontMetrics(font()).height() << 1), this))
, m_view(new EasyGraphicsView(this))
, m_threadNamesWidget(new EasyThreadNamesWidget(m_view, m_scrollbar->height(), this))
{

View File

@ -77,8 +77,8 @@ class EasyTreeWidget : public QTreeWidget
{
Q_OBJECT
typedef QTreeWidget Parent;
typedef EasyTreeWidget This;
using Parent = QTreeWidget;
using This = EasyTreeWidget;
protected:
@ -100,9 +100,10 @@ protected:
public:
explicit EasyTreeWidget(QWidget* _parent = nullptr);
virtual ~EasyTreeWidget();
~EasyTreeWidget() override;
void contextMenuEvent(QContextMenuEvent* _event) override;
void dragEnterEvent(QDragEnterEvent*) override {}
void clearSilent(bool _global = false);
int findNext(const QString& _str, Qt::MatchFlags _flags);
@ -167,8 +168,8 @@ class EasyHierarchyWidget : public QWidget
{
Q_OBJECT
typedef QWidget Parent;
typedef EasyHierarchyWidget This;
using Parent = QWidget;
using This = EasyHierarchyWidget;
private:
@ -183,9 +184,11 @@ public:
// Public virtual methods
explicit EasyHierarchyWidget(QWidget* _parent = nullptr);
virtual ~EasyHierarchyWidget();
~EasyHierarchyWidget() override;
void keyPressEvent(QKeyEvent* _event) override;
void contextMenuEvent(QContextMenuEvent* _event) override;
void dragEnterEvent(QDragEnterEvent*) override {}
public:

View File

@ -67,9 +67,9 @@
class EasyFPSGraphicsItem : public QGraphicsItem
{
typedef QGraphicsItem Parent;
typedef EasyFPSGraphicsItem This;
typedef std::deque<std::pair<uint32_t, uint32_t> > FrameTimes;
using Parent = QGraphicsItem;
using This = EasyFPSGraphicsItem;
using FrameTimes = std::deque<std::pair<uint32_t, uint32_t> >;
std::vector<QPointF> m_points1, m_points2;
FrameTimes m_frames;
@ -78,10 +78,10 @@ class EasyFPSGraphicsItem : public QGraphicsItem
public:
explicit EasyFPSGraphicsItem();
virtual ~EasyFPSGraphicsItem();
~EasyFPSGraphicsItem() override;
QRectF boundingRect() const override;
void paint(QPainter* _painter, const QStyleOptionGraphicsItem* _option, QWidget* _widget = nullptr) override;
void paint(QPainter* _painter, const QStyleOptionGraphicsItem* _option, QWidget* _widget) override;
void setBoundingRect(const QRectF& _boundingRect);
void setBoundingRect(qreal x, qreal y, qreal w, qreal h);
@ -99,20 +99,21 @@ class EasyFrameRateViewer : public QGraphicsView
private:
typedef QGraphicsView Parent;
typedef EasyFrameRateViewer This;
using Parent = QGraphicsView;
using This = EasyFrameRateViewer;
EasyFPSGraphicsItem* m_fpsItem;
public:
explicit EasyFrameRateViewer(QWidget* _parent = nullptr);
virtual ~EasyFrameRateViewer();
~EasyFrameRateViewer() override;
void resizeEvent(QResizeEvent* _event) override;
void hideEvent(QHideEvent* _event) override;
void showEvent(QShowEvent* _event) override;
void contextMenuEvent(QContextMenuEvent* _event) override;
void dragEnterEvent(QDragEnterEvent*) override {}
public slots:

File diff suppressed because it is too large Load Diff

View File

@ -58,88 +58,16 @@
#include <stdlib.h>
#include <thread>
#include <atomic>
#include <QGraphicsView>
#include <QGraphicsRectItem>
#include <QAction>
#include <QPolygonF>
#include <QImage>
#include "easy_qtimer.h"
#include "common_types.h"
#include "graphics_slider_area.h"
//////////////////////////////////////////////////////////////////////////
// TODO: use profiler_core/spin_lock.h
#define EASY_GUI_USE_CRITICAL_SECTION // Use CRITICAL_SECTION instead of std::atomic_flag
#if defined(_WIN32) && defined(EASY_GUI_USE_CRITICAL_SECTION)
namespace profiler_gui {
// std::atomic_flag on Windows works slower than critical section, so we will use it instead of std::atomic_flag...
// By the way, Windows critical sections are slower than std::atomic_flag on Unix.
class spin_lock { void* m_lock; public:
void lock();
void unlock();
spin_lock();
~spin_lock();
};
#else
namespace profiler_gui {
// std::atomic_flag on Unix works fine and very fast (almost instant!)
class spin_lock {
::std::atomic_flag m_lock; public:
void lock() {
while (m_lock.test_and_set(::std::memory_order_acquire));
}
void unlock() {
m_lock.clear(::std::memory_order_release);
}
spin_lock() {
m_lock.clear();
}
};
#endif
} // END of namespace profiler_gui.
//////////////////////////////////////////////////////////////////////////
class EasyGraphicsSliderItem : public QGraphicsRectItem
class GraphicsHistogramItem : public GraphicsImageItem
{
typedef QGraphicsRectItem Parent;
typedef EasyGraphicsSliderItem This;
private:
QPolygonF m_indicator;
qreal m_halfwidth;
bool m_bMain;
public:
explicit EasyGraphicsSliderItem(bool _main);
virtual ~EasyGraphicsSliderItem();
void paint(QPainter* _painter, const QStyleOptionGraphicsItem* _option, QWidget* _widget = nullptr) override;
qreal width() const;
qreal halfwidth() const;
void setWidth(qreal _width);
void setHalfwidth(qreal _halfwidth);
void setColor(QRgb _color);
void setColor(const QColor& _color);
}; // END of class EasyGraphicsSliderItem.
//////////////////////////////////////////////////////////////////////////
class EasyHistogramItem : public QGraphicsItem
{
typedef QGraphicsItem Parent;
typedef EasyHistogramItem This;
using Parent = GraphicsImageItem;
using This = GraphicsHistogramItem;
public:
@ -147,193 +75,108 @@ public:
private:
QRectF m_boundingRect;
qreal m_topDuration;
qreal m_bottomDuration;
qreal m_maxDuration;
qreal m_minDuration;
qreal m_mouseY;
qreal m_imageOrigin;
qreal m_imageScale;
qreal m_imageOriginUpdate;
qreal m_imageScaleUpdate;
qreal m_workerImageOrigin;
qreal m_workerImageScale;
qreal m_workerTopDuration;
qreal m_workerBottomDuration;
::profiler::timestamp_t m_blockTotalDuraion;
QString m_topDurationStr;
QString m_bottomDurationStr;
QString m_threadName;
QString m_blockName;
::profiler::BlocksTree::children_t m_selectedBlocks;
QImage m_mainImage;
EasyQTimer m_timer;
EasyQTimer m_boundaryTimer;
::std::thread m_workerThread;
::profiler::timestamp_t m_threadDuration;
::profiler::timestamp_t m_threadProfiledTime;
::profiler::timestamp_t m_threadWaitTime;
const ::profiler_gui::EasyItems* m_pSource;
QImage* m_workerImage;
const ::profiler::BlocksTreeRoot* m_pProfilerThread;
::profiler::thread_id_t m_threadId;
::profiler::block_index_t m_blockId;
int m_timeouts;
::profiler_gui::TimeUnits m_timeUnits;
HistRegime m_regime;
bool m_bPermitImageUpdate; ///< Is false when m_workerThread is parsing input dataset (when setSource(_block_id) is called)
::profiler_gui::spin_lock m_spin;
::std::atomic_bool m_bReady;
qreal m_workerTopDuration;
qreal m_workerBottomDuration;
profiler::timestamp_t m_blockTotalDuraion;
QString m_topDurationStr;
QString m_bottomDurationStr;
QString m_threadName;
QString m_blockName;
profiler::BlocksTree::children_t m_selectedBlocks;
profiler::timestamp_t m_threadDuration;
profiler::timestamp_t m_threadProfiledTime;
profiler::timestamp_t m_threadWaitTime;
const profiler_gui::EasyItems* m_pSource;
const profiler::BlocksTreeRoot* m_pProfilerThread;
profiler::thread_id_t m_threadId;
profiler::block_index_t m_blockId;
profiler_gui::TimeUnits m_timeUnits;
HistRegime m_regime;
public:
explicit EasyHistogramItem();
virtual ~EasyHistogramItem();
explicit GraphicsHistogramItem();
~GraphicsHistogramItem() override;
// Public virtual methods
void paint(QPainter* _painter, const QStyleOptionGraphicsItem* _option, QWidget* _widget) override;
QRectF boundingRect() const override;
void paint(QPainter* _painter, const QStyleOptionGraphicsItem* _option, QWidget* _widget = nullptr) override;
bool updateImage() override;
void onImageUpdated() override;
bool pickTopValue() override;
bool increaseTopValue() override;
bool decreaseTopValue() override;
bool pickBottomValue() override;
bool increaseBottomValue() override;
bool decreaseBottomValue() override;
void onModeChanged() override;
void onValueChanged() override;
public:
// Public non-virtual methods
::profiler::thread_id_t threadId() const;
profiler::thread_id_t threadId() const;
void setBoundingRect(const QRectF& _rect);
void setBoundingRect(qreal x, qreal y, qreal w, qreal h);
void setSource(::profiler::thread_id_t _thread_id, const ::profiler_gui::EasyItems* _items);
void setSource(::profiler::thread_id_t _thread_id, ::profiler::block_id_t _block_id);
void setSource(profiler::thread_id_t _thread_id, const profiler_gui::EasyItems* _items);
void setSource(profiler::thread_id_t _thread_id, profiler::block_id_t _block_id);
void rebuildSource(HistRegime _regime);
void rebuildSource();
void validateName();
void updateImage();
void cancelImageUpdate();
void pickTopBoundary(qreal _y);
void increaseTopBoundary();
void decreaseTopBoundary();
void pickBottomBoundary(qreal _y);
void increaseBottomBoundary();
void decreaseBottomBoundary();
void setMouseY(qreal _mouseY);
void pickFrameTime(qreal _y) const;
void onValueChanged();
void onModeChanged();
private:
void paintBusyIndicator(QPainter* _painter, qreal _current_scale);
void paintMouseIndicator(QPainter* _painter, qreal _top, qreal _bottom, qreal _width, qreal _height, qreal _top_width, qreal _mouse_y, qreal _delta_time, int _font_h);
void paintByPtr(QPainter* _painter);
void paintById(QPainter* _painter);
void onTimeout();
void updateImage(QRectF _boundingRect, HistRegime _regime, qreal _current_scale,
qreal _minimum, qreal _maximum, qreal _range,
qreal _value, qreal _width, qreal _top_duration, qreal _bottom_duration, bool _bindMode,
float _frame_time, ::profiler::timestamp_t _begin_time, qreal _origin, bool _autoAdjustHist);
}; // END of class EasyHistogramItem.
void updateImageAsync(QRectF _boundingRect, HistRegime _regime, qreal _current_scale,
qreal _minimum, qreal _maximum, qreal _range,
qreal _value, qreal _width, qreal _top_duration, qreal _bottom_duration, bool _bindMode,
float _frame_time, profiler::timestamp_t _begin_time, bool _autoAdjustHist);
}; // END of class GraphicsHistogramItem.
//////////////////////////////////////////////////////////////////////////
class EasyGraphicsScrollbar : public QGraphicsView
class EasyGraphicsScrollbar : public GraphicsSliderArea
{
Q_OBJECT
private:
typedef QGraphicsView Parent;
typedef EasyGraphicsScrollbar This;
using Parent = GraphicsSliderArea;
using This = EasyGraphicsScrollbar;
qreal m_minimumValue;
qreal m_maximumValue;
qreal m_value;
qreal m_windowScale;
QPoint m_mousePressPos;
Qt::MouseButtons m_mouseButtons;
EasyGraphicsSliderItem* m_slider;
EasyGraphicsSliderItem* m_chronometerIndicator;
EasyHistogramItem* m_histogramItem;
int m_defaultFontHeight;
bool m_bScrolling;
bool m_bBindMode;
bool m_bLocked;
GraphicsHistogramItem* m_histogramItem = nullptr;
public:
explicit EasyGraphicsScrollbar(QWidget* _parent = nullptr);
virtual ~EasyGraphicsScrollbar();
// Public virtual methods
explicit EasyGraphicsScrollbar(bool _fixedHeight, int _height, QWidget* _parent = nullptr);
~EasyGraphicsScrollbar() override;
void clear() override;
void mousePressEvent(QMouseEvent* _event) override;
void mouseReleaseEvent(QMouseEvent* _event) override;
void mouseMoveEvent(QMouseEvent* _event) override;
void wheelEvent(QWheelEvent* _event) override;
void resizeEvent(QResizeEvent* _event) override;
void dragEnterEvent(QDragEnterEvent*) override {}
public:
// Public non-virtual methods
void clear();
profiler::thread_id_t hystThread() const;
bool bindMode() const;
qreal getWindowScale() const;
::profiler::thread_id_t hystThread() const;
qreal minimum() const;
qreal maximum() const;
qreal range() const;
qreal value() const;
qreal sliderWidth() const;
qreal sliderHalfWidth() const;
int defaultFontHeight() const;
void setValue(qreal _value);
void setRange(qreal _minValue, qreal _maxValue);
void setSliderWidth(qreal _width);
void setChronoPos(qreal _left, qreal _right);
void showChrono();
void hideChrono();
void setHistogramSource(::profiler::thread_id_t _thread_id, const::profiler_gui::EasyItems* _items);
void setHistogramSource(::profiler::thread_id_t _thread_id, ::profiler::block_id_t _block_id);
inline void setHistogramSource(::profiler::thread_id_t _thread_id, const ::profiler_gui::EasyItems& _items)
{
void setHistogramSource(profiler::thread_id_t _thread_id, const profiler_gui::EasyItems* _items);
void setHistogramSource(profiler::thread_id_t _thread_id, profiler::block_id_t _block_id);
void setHistogramSource(profiler::thread_id_t _thread_id, const profiler_gui::EasyItems& _items) {
setHistogramSource(_thread_id, &_items);
}
inline void lock()
{
m_bLocked = true;
}
inline void unlock()
{
m_bLocked = false;
}
signals:
void rangeChanged();
void valueChanged(qreal _value);
void wheeled(qreal _mouseX, int _wheelDelta);
private slots:
void onThreadViewChanged();
void onWindowWidthChange(qreal _width);
}; // END of class EasyGraphicsScrollbar.

View File

@ -60,15 +60,15 @@
EasyQTimer::EasyQTimer()
: QObject()
{
connect(&m_timer, &QTimer::timeout, [this](){ m_handler(); });
connect(&m_timer, &QTimer::timeout, [this] { m_handler(); });
}
EasyQTimer::EasyQTimer(::std::function<void()>&& _handler, bool _isSignleShot)
EasyQTimer::EasyQTimer(::std::function<void()>&& handler, bool signleShot)
: QObject()
, m_handler(::std::forward<::std::function<void()>&&>(_handler))
, m_handler(::std::forward<::std::function<void()>&&>(handler))
{
m_timer.setSingleShot(_isSignleShot);
connect(&m_timer, &QTimer::timeout, [this](){ m_handler(); });
m_timer.setSingleShot(signleShot);
connect(&m_timer, &QTimer::timeout, [this] { m_handler(); });
}
EasyQTimer::~EasyQTimer()
@ -76,9 +76,47 @@ EasyQTimer::~EasyQTimer()
}
void EasyQTimer::setHandler(::std::function<void()>&& _handler)
void EasyQTimer::setHandler(::std::function<void()>&& handler)
{
m_handler = _handler;
m_handler = handler;
}
void EasyQTimer::setSignleShot(bool singleShot)
{
m_timer.setSingleShot(singleShot);
}
bool EasyQTimer::isSingleShot() const
{
return m_timer.isSingleShot();
}
void EasyQTimer::setInterval(int msec)
{
m_timer.setInterval(msec);
}
void EasyQTimer::start(int msec)
{
stop();
m_timer.start(msec);
}
void EasyQTimer::start()
{
stop();
m_timer.start();
}
void EasyQTimer::stop()
{
if (m_timer.isActive())
m_timer.stop();
}
bool EasyQTimer::isActive() const
{
return m_timer.isActive();
}
//////////////////////////////////////////////////////////////////////////

View File

@ -72,15 +72,20 @@ private:
public:
EasyQTimer();
EasyQTimer(::std::function<void()>&& _handler, bool _isSignleShot = false);
virtual ~EasyQTimer();
explicit EasyQTimer();
explicit EasyQTimer(::std::function<void()>&& handler, bool signleShot = false);
~EasyQTimer() override;
void setHandler(::std::function<void()>&& _handler);
inline void start(int msec) { m_timer.start(msec); }
inline void stop() { if (m_timer.isActive()) m_timer.stop(); }
inline bool isActive() const { return m_timer.isActive(); }
void setSignleShot(bool singleShot);
bool isSingleShot() const;
void setInterval(int msec);
void start(int msec);
void start();
void stop();
bool isActive() const;
}; // END of class EasyQTimer.

View File

@ -0,0 +1,331 @@
#include <QGraphicsScene>
#include <QPainter>
#include "graphics_image_item.h"
#include "graphics_slider_area.h"
#include "globals.h"
EASY_CONSTEXPR int TimerInterval = 40;
EASY_CONSTEXPR int BoundaryTimerInterval = 100;
GraphicsImageItem::GraphicsImageItem() : Parent(nullptr)
, m_boundaryTimer([this] { updateImage(); }, true)
, m_workerImage(nullptr)
, m_imageOrigin(0)
, m_imageScale(1)
, m_imageOriginUpdate(0)
, m_imageScaleUpdate(1)
, m_workerImageOrigin(0)
, m_workerImageScale(1)
, m_topValue(0)
, m_bottomValue(0)
, m_maxValue(0)
, m_minValue(0)
, m_timer(::std::bind(&This::onTimeout, this))
, m_bPermitImageUpdate(true)
{
m_bReady = ATOMIC_VAR_INIT(false);
m_boundaryTimer.setInterval(BoundaryTimerInterval);
m_timer.setInterval(TimerInterval);
}
GraphicsImageItem::~GraphicsImageItem()
{
cancelAnyJob();
}
QRectF GraphicsImageItem::boundingRect() const
{
return m_boundingRect;
}
void GraphicsImageItem::setBoundingRect(const QRectF& _rect)
{
m_boundingRect = _rect;
}
void GraphicsImageItem::setBoundingRect(qreal x, qreal y, qreal w, qreal h)
{
m_boundingRect.setRect(x, y, w, h);
}
void GraphicsImageItem::setMousePos(const QPointF& pos)
{
m_mousePos = pos;
}
void GraphicsImageItem::setMousePos(qreal x, qreal y)
{
m_mousePos.setX(x);
m_mousePos.setY(y);
}
bool GraphicsImageItem::updateImage()
{
if (!cancelImageUpdate())
return false;
setReady(false);
startTimer();
return true;
}
void GraphicsImageItem::onValueChanged()
{
const auto widget = qobject_cast<const GraphicsSliderArea*>(scene()->parent());
if (widget == nullptr)
return;
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 GraphicsImageItem::onModeChanged()
{
if (!isImageUpdatePermitted())
return;
m_boundaryTimer.stop();
updateImage();
}
void GraphicsImageItem::onImageUpdated()
{
}
bool GraphicsImageItem::cancelImageUpdate()
{
if (!isImageUpdatePermitted())
return false;
cancelAnyJob();
return true;
}
bool GraphicsImageItem::pickTopValue()
{
const auto y = m_mousePos.y();
if (isImageUpdatePermitted() && m_boundingRect.top() < y && y < m_boundingRect.bottom())
{
m_topValue = m_bottomValue + (m_topValue - m_bottomValue) * (m_boundingRect.bottom() - y) / m_boundingRect.height();
m_boundaryTimer.stop();
updateImage();
return true;
}
return false;
}
bool GraphicsImageItem::increaseTopValue()
{
if (isImageUpdatePermitted() && m_topValue < m_maxValue)
{
auto step = 0.05 * (m_maxValue - m_bottomValue);
if (m_topValue < (m_bottomValue + 1.25 * step))
step = 0.1 * (m_topValue - m_bottomValue);
m_topValue = std::min(m_maxValue, m_topValue + step);
m_boundaryTimer.start();
return true;
}
return false;
}
bool GraphicsImageItem::decreaseTopValue()
{
if (isImageUpdatePermitted() && m_topValue > m_bottomValue)
{
auto step = 0.05 * (m_maxValue - m_bottomValue);
if (m_topValue < (m_bottomValue + 1.25 * step))
step = std::max(0.1 * (m_topValue - m_bottomValue), 0.3);
if (m_topValue > (m_bottomValue + 1.25 * step))
{
m_topValue = std::max(m_bottomValue + step, m_topValue - step);
m_boundaryTimer.start();
return true;
}
}
return false;
}
bool GraphicsImageItem::pickBottomValue()
{
const auto y = m_mousePos.y();
if (isImageUpdatePermitted() && m_boundingRect.top() < y && y < m_boundingRect.bottom())
{
m_bottomValue = m_bottomValue + (m_topValue - m_bottomValue) * (m_boundingRect.bottom() - y) / m_boundingRect.height();
m_boundaryTimer.stop();
updateImage();
return true;
}
return false;
}
bool GraphicsImageItem::increaseBottomValue()
{
if (isImageUpdatePermitted() && m_bottomValue < m_topValue)
{
auto step = 0.05 * (m_topValue - m_minValue);
if (m_bottomValue > (m_topValue - 1.25 * step))
step = 0.1 * (m_topValue - m_bottomValue);
if (m_bottomValue < (m_topValue - 1.25 * step))
{
m_bottomValue = std::min(m_topValue - step, m_bottomValue + step);
m_boundaryTimer.start();
return true;
}
}
return false;
}
bool GraphicsImageItem::decreaseBottomValue()
{
if (isImageUpdatePermitted() && m_bottomValue > m_minValue)
{
auto step = 0.05 * (m_topValue - m_minValue);
if (m_bottomValue > (m_topValue - 1.25 * step))
step = std::max(0.1 * (m_topValue - m_bottomValue), 0.3);
m_bottomValue = std::max(m_minValue, m_bottomValue - step);
m_boundaryTimer.start();
return true;
}
return false;
}
void GraphicsImageItem::paintImage(QPainter* _painter)
{
_painter->setPen(Qt::NoPen);
_painter->drawImage(0, m_boundingRect.top(), m_image);
}
void GraphicsImageItem::paintImage(QPainter* _painter, qreal _scale, qreal _sceneLeft, qreal _sceneRight,
qreal _visibleRegionLeft, qreal _visibleRegionWidth)
{
const auto dscale = (_sceneRight - _sceneLeft) / (_visibleRegionWidth * m_imageScale);
_painter->setPen(Qt::NoPen);
_painter->setTransform(QTransform::fromScale(dscale, 1), true);
_painter->drawImage(QPointF {(_sceneLeft + m_imageOrigin - _visibleRegionLeft) * _scale * m_imageScale, m_boundingRect.top()}, m_image);
_painter->setTransform(QTransform::fromScale(1. / dscale, 1), true);
}
void GraphicsImageItem::onTimeout()
{
if (!isVisible())
{
stopTimer();
return;
}
if (isReady())
{
stopTimer();
if (!isImageUpdatePermitted())
{
// Worker thread have finished parsing input data (when setSource(_block_id) was called)
setImageUpdatePermitted(true); // From now we can update an image
updateImage();
}
else
{
// Image updated
if (m_workerThread.joinable())
m_workerThread.join();
m_workerImage->swap(m_image);
delete m_workerImage;
m_workerImage = nullptr;
m_imageOriginUpdate = m_imageOrigin = m_workerImageOrigin;
m_imageScaleUpdate = m_imageScale = m_workerImageScale;
onImageUpdated();
scene()->update();
}
}
}
void GraphicsImageItem::setImageUpdatePermitted(bool _permit)
{
m_bPermitImageUpdate = _permit;
}
bool GraphicsImageItem::isImageUpdatePermitted() const
{
return m_bPermitImageUpdate;
}
void GraphicsImageItem::cancelAnyJob()
{
setReady(true);
if (m_workerThread.joinable())
m_workerThread.join();
//setReady(false);
delete m_workerImage;
m_workerImage = nullptr;
m_imageOriginUpdate = m_imageOrigin;
m_imageScaleUpdate = m_imageScale;
stopTimer();
}
void GraphicsImageItem::resetTopBottomValues()
{
m_topValue = m_maxValue;
m_bottomValue = m_minValue;
}
bool GraphicsImageItem::isReady() const
{
return m_bReady.load(std::memory_order_acquire);
}
void GraphicsImageItem::setReady(bool _ready)
{
m_bReady.store(_ready, std::memory_order_release);
}
void GraphicsImageItem::startTimer()
{
m_timer.start();
}
void GraphicsImageItem::stopTimer()
{
m_timer.stop();
}

View File

@ -0,0 +1,96 @@
#ifndef EASY_PROFILER_GRAPHICS_IMAGE_ITEM_H
#define EASY_PROFILER_GRAPHICS_IMAGE_ITEM_H
#include <QGraphicsItem>
#include <thread>
#include <atomic>
#include "easy_qtimer.h"
class GraphicsImageItem : public QGraphicsItem
{
protected:
using Parent = QGraphicsItem;
using This = GraphicsImageItem;
QRectF m_boundingRect;
QImage m_image;
EasyQTimer m_boundaryTimer;
std::thread m_workerThread;
QPointF m_mousePos;
QImage* m_workerImage;
qreal m_imageOrigin;
qreal m_imageScale;
qreal m_imageOriginUpdate;
qreal m_imageScaleUpdate;
qreal m_workerImageOrigin;
qreal m_workerImageScale;
qreal m_topValue;
qreal m_bottomValue;
qreal m_maxValue;
qreal m_minValue;
private:
EasyQTimer m_timer;
std::atomic_bool m_bReady;
bool m_bPermitImageUpdate; ///< Is false when m_workerThread is parsing input dataset (when setSource(_block_id) is called)
public:
explicit GraphicsImageItem();
~GraphicsImageItem() override;
QRectF boundingRect() const override;
virtual bool pickTopValue();
virtual bool increaseTopValue();
virtual bool decreaseTopValue();
virtual bool pickBottomValue();
virtual bool increaseBottomValue();
virtual bool decreaseBottomValue();
virtual bool updateImage();
virtual void onModeChanged();
virtual void onValueChanged();
protected:
virtual void onImageUpdated();
public:
void setMousePos(const QPointF& pos);
void setMousePos(qreal x, qreal y);
void setBoundingRect(const QRectF& _rect);
void setBoundingRect(qreal x, qreal y, qreal w, qreal h);
bool cancelImageUpdate();
protected:
void paintImage(QPainter* _painter);
void paintImage(QPainter* _painter, qreal _scale, qreal _sceneLeft, qreal _sceneRight,
qreal _visibleRegionLeft, qreal _visibleRegionWidth);
void setImageUpdatePermitted(bool _permit);
bool isImageUpdatePermitted() const;
void cancelAnyJob();
void resetTopBottomValues();
bool isReady() const;
void setReady(bool _ready);
void startTimer();
void stopTimer();
private:
void onTimeout();
}; // end of class GraphicsImageItem.
#endif //EASY_PROFILER_GRAPHICS_IMAGE_ITEM_H

View File

@ -0,0 +1,521 @@
/**
Lightweight profiler library for c++
Copyright(C) 2016-2018 Sergey Yagovtsev, Victor Zarubkin
Licensed under either of
* MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
at your option.
The MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
The Apache License, Version 2.0 (the "License");
You may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
**/
#include <algorithm>
#include <QGraphicsScene>
#include <QWheelEvent>
#include <QMouseEvent>
#include <QResizeEvent>
#include <easy/utility.h>
#include "graphics_slider_area.h"
#include "globals.h"
//////////////////////////////////////////////////////////////////////////
GraphicsSliderItem::GraphicsSliderItem(int _size, bool _main)
: Parent()
, m_halfwidth(0.5)
, m_bMain(_main)
{
const int sizeHalf = 1 + (_size >> 1);
if (_main)
_size = -_size;
m_indicator.reserve(3);
m_indicator.push_back(QPointF(0, 0));
m_indicator.push_back(QPointF(-sizeHalf, _size));
m_indicator.push_back(QPointF(sizeHalf, _size));
setBrush(Qt::SolidPattern);
}
GraphicsSliderItem::~GraphicsSliderItem()
{
}
void GraphicsSliderItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem* /* _option */, QWidget* /* _widget */)
{
const auto view = static_cast<const GraphicsSliderArea*>(scene()->parent());
if (view->bindMode())
return;
const auto currentScale = view->getWindowScale();
const qreal w = width() * currentScale;
const auto br = rect();
const QRectF r(br.left() * currentScale, br.top() + view->margin(), w, br.height() - view->margins() - 1);
const auto r_right = r.right();
const auto r_bottom = r.bottom();
const auto b = brush();
_painter->save();
_painter->setTransform(QTransform::fromScale(1.0 / currentScale, 1), true);
_painter->setBrush(b);
if (w > 1)
{
_painter->setPen(Qt::NoPen);
_painter->drawRect(r);
// Draw left and right borders
if (m_bMain) _painter->setCompositionMode(QPainter::CompositionMode_Exclusion);
_painter->setPen(QColor::fromRgba(0xe0000000 | b.color().rgb()));
_painter->drawLine(QPointF(r.left(), r.top()), QPointF(r.left(), r_bottom));
_painter->drawLine(QPointF(r_right, r.top()), QPointF(r_right, r_bottom));
}
else
{
if (m_bMain) _painter->setCompositionMode(QPainter::CompositionMode_Exclusion);
_painter->setPen(QColor::fromRgba(0xe0000000 | b.color().rgb()));
_painter->drawLine(QPointF(r.left(), r.top()), QPointF(r.left(), r_bottom));
}
// Draw triangle indicators for small slider
if (m_bMain)
_painter->setTransform(QTransform::fromTranslate(r.left() + w * 0.5, br.top() + view->margin()), true);
else
_painter->setTransform(QTransform::fromTranslate(r.left() + w * 0.5, br.bottom() - view->margin() - 1), true);
_painter->setPen(b.color().rgb());
_painter->drawPolygon(m_indicator);
_painter->restore();
}
qreal GraphicsSliderItem::width() const
{
return m_halfwidth * 2.0;
}
qreal GraphicsSliderItem::halfwidth() const
{
return m_halfwidth;
}
void GraphicsSliderItem::setWidth(qreal _width)
{
const auto sceneRect = scene()->sceneRect();
m_halfwidth = _width * 0.5;
setRect(-m_halfwidth, sceneRect.top(), _width, sceneRect.height());
}
void GraphicsSliderItem::setHalfwidth(qreal _halfwidth)
{
const auto sceneRect = scene()->sceneRect();
m_halfwidth = _halfwidth;
setRect(-m_halfwidth, sceneRect.top(), width(), sceneRect.height());
}
void GraphicsSliderItem::setColor(QRgb _color)
{
setColor(QColor::fromRgba(_color));
}
void GraphicsSliderItem::setColor(const QColor& _color)
{
auto b = brush();
b.setColor(_color);
setBrush(b);
}
//////////////////////////////////////////////////////////////////////////
GraphicsSliderArea::GraphicsSliderArea(QWidget* _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_fontHeight(0)
, m_bScrolling(false)
, m_bBindMode(false)
, m_bLocked(false)
{
setCacheMode(QGraphicsView::CacheNone);
setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
//setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate);
setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
setOptimizationFlag(QGraphicsView::DontSavePainterState, true);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setContentsMargins(0, 0, 0, 0);
setScene(new QGraphicsScene(this));
m_fontHeight = QFontMetrics(font()).height();
EASY_CONSTEXPR int SceneHeight = 500;
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);
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::threadNameDecorationChanged, this, &This::onThreadViewChanged);
connect(&EASY_GLOBALS.events, &profiler_gui::EasyGlobalSignals::hexThreadIdChanged, this, &This::onThreadViewChanged);
centerOn(0, 0);
}
GraphicsSliderArea::~GraphicsSliderArea()
{
}
//////////////////////////////////////////////////////////////////////////
void GraphicsSliderArea::clear()
{
m_selectionIndicator->hide();
setRange(0, 100);
setSliderWidth(2);
setValue(0);
}
//////////////////////////////////////////////////////////////////////////
bool GraphicsSliderArea::bindMode() const
{
return m_bBindMode;
}
qreal GraphicsSliderArea::getWindowScale() const
{
return m_windowScale;
}
qreal GraphicsSliderArea::minimum() const
{
return m_minimumValue;
}
qreal GraphicsSliderArea::maximum() const
{
return m_maximumValue;
}
qreal GraphicsSliderArea::range() const
{
return m_maximumValue - m_minimumValue;
}
qreal GraphicsSliderArea::value() const
{
return m_value;
}
qreal GraphicsSliderArea::sliderWidth() const
{
return m_slider->width();
}
qreal GraphicsSliderArea::sliderHalfWidth() const
{
return m_slider->halfwidth();
}
int GraphicsSliderArea::fontHeight() const
{
return m_fontHeight;
}
int GraphicsSliderArea::margin() const
{
return m_fontHeight + 2;
}
int GraphicsSliderArea::margins() const
{
return margin() << 1;
}
//////////////////////////////////////////////////////////////////////////
void GraphicsSliderArea::setValue(qreal _value)
{
using estd::clamp;
m_value = clamp(m_minimumValue, _value, std::max(m_minimumValue, m_maximumValue - m_slider->width()));
m_slider->setX(m_value + m_slider->halfwidth());
emit valueChanged(m_value);
if (m_imageItem->isVisible())
m_imageItem->onValueChanged();
}
void GraphicsSliderArea::setRange(qreal _minValue, qreal _maxValue)
{
const auto oldRange = range();
const auto oldValue = oldRange < 1e-3 ? 0.0 : m_value / oldRange;
m_minimumValue = _minValue;
m_maximumValue = _maxValue;
const auto range = this->range();
const auto sceneRect = scene()->sceneRect();
scene()->setSceneRect(_minValue, sceneRect.top(), range, sceneRect.height());
const auto histogramRect = m_imageItem->boundingRect();
m_imageItem->cancelImageUpdate();
m_imageItem->setBoundingRect(_minValue, histogramRect.top(), range, histogramRect.height());
emit rangeChanged();
setValue(_minValue + oldValue * range);
onWindowWidthChange(width());
if (m_imageItem->isVisible())
m_imageItem->updateImage();
}
void GraphicsSliderArea::setSliderWidth(qreal _width)
{
m_slider->setWidth(_width);
setValue(m_value);
}
//////////////////////////////////////////////////////////////////////////
void GraphicsSliderArea::setSelectionPos(qreal _left, qreal _right)
{
m_selectionIndicator->setWidth(_right - _left);
m_selectionIndicator->setX(_left + m_selectionIndicator->halfwidth());
}
void GraphicsSliderArea::showSelectionIndicator()
{
if (!m_selectionIndicator->isVisible())
{
m_selectionIndicator->show();
scene()->update();
}
}
void GraphicsSliderArea::hideSelectionIndicator()
{
if (m_selectionIndicator->isVisible())
{
m_selectionIndicator->hide();
scene()->update();
}
}
//////////////////////////////////////////////////////////////////////////
void GraphicsSliderArea::mousePressEvent(QMouseEvent* _event)
{
_event->accept();
m_mouseButtons = _event->buttons();
if (m_mouseButtons & Qt::LeftButton)
{
if (_event->modifiers() & Qt::ControlModifier)
{
m_imageItem->pickBottomValue();
}
else if (_event->modifiers() & Qt::ShiftModifier)
{
m_imageItem->pickTopValue();
}
else
{
m_bScrolling = true;
m_mousePressPos = _event->pos();
if (!m_bBindMode)
setValue(mapToScene(m_mousePressPos).x() - m_minimumValue - m_slider->halfwidth());
}
}
if (m_mouseButtons & Qt::RightButton)
{
if (!_event->modifiers())
{
m_bBindMode = !m_bBindMode;
if (m_imageItem->isVisible())
m_imageItem->onModeChanged();
}
}
//Parent::mousePressEvent(_event);
}
void GraphicsSliderArea::mouseReleaseEvent(QMouseEvent* _event)
{
m_mouseButtons = _event->buttons();
m_bScrolling = false;
_event->accept();
//Parent::mouseReleaseEvent(_event);
}
void GraphicsSliderArea::mouseMoveEvent(QMouseEvent* _event)
{
const auto pos = _event->pos();
if (m_mouseButtons & Qt::LeftButton)
{
const auto delta = pos - m_mousePressPos;
m_mousePressPos = pos;
if (m_bScrolling)
{
auto realScale = m_windowScale;
if (bindMode())
realScale *= -range() / sliderWidth();
setValue(m_value + delta.x() / realScale);
}
}
m_imageItem->setMousePos(mapToScene(pos));
if (m_imageItem->isVisible())
scene()->update();
}
void GraphicsSliderArea::wheelEvent(QWheelEvent* _event)
{
_event->accept();
if (_event->modifiers() & Qt::ShiftModifier)
{
// Shift + mouse wheel will change histogram top boundary
if (m_imageItem->isVisible())
{
if (_event->delta() > 0)
m_imageItem->increaseTopValue();
else
m_imageItem->decreaseTopValue();
}
return;
}
if (_event->modifiers() & Qt::ControlModifier)
{
// Ctrl + mouse wheel will change histogram bottom boundary
if (m_imageItem->isVisible())
{
if (_event->delta() > 0)
m_imageItem->increaseBottomValue();
else
m_imageItem->decreaseBottomValue();
}
return;
}
if (!bindMode())
{
const auto w = m_slider->halfwidth() * (_event->delta() < 0 ? profiler_gui::SCALING_COEFFICIENT : profiler_gui::SCALING_COEFFICIENT_INV);
setValue(mapToScene(_event->pos()).x() - m_minimumValue - w);
emit wheeled(w * m_windowScale, _event->delta());
}
else
{
const auto x = (mapToScene(_event->pos()).x() - m_minimumValue) * m_windowScale;
emit wheeled(x, _event->delta());
}
}
void GraphicsSliderArea::resizeEvent(QResizeEvent* _event)
{
const int h = _event->size().height();
if (_event->oldSize().height() != h)
{
const int sceneHeight = h - 2;
scene()->setSceneRect(0, -(sceneHeight >> 1), 500, sceneHeight);
const auto br = m_imageItem->boundingRect();
m_imageItem->setBoundingRect(br.left(), scene()->sceneRect().top() + margin(), br.width(), sceneHeight - margins() - 1);
}
onWindowWidthChange(_event->size().width());
if (m_imageItem->isVisible())
m_imageItem->updateImage();
}
//////////////////////////////////////////////////////////////////////////
void GraphicsSliderArea::onWindowWidthChange(qreal _width)
{
const auto oldScale = m_windowScale;
const auto scrollingRange = range();
if (scrollingRange < 1e-3)
{
m_windowScale = 1;
}
else
{
m_windowScale = _width / scrollingRange;
}
scale(m_windowScale / oldScale, 1);
}

View File

@ -0,0 +1,173 @@
/**
Lightweight profiler library for c++
Copyright(C) 2016-2018 Sergey Yagovtsev, Victor Zarubkin
Licensed under either of
* MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
at your option.
The MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
The Apache License, Version 2.0 (the "License");
You may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
**/
#ifndef EASY_PROFILER_GRAPHICS_SLIDER_AREA_H
#define EASY_PROFILER_GRAPHICS_SLIDER_AREA_H
#include <stdlib.h>
#include <QGraphicsView>
#include <QGraphicsRectItem>
#include <QAction>
#include <QPolygonF>
#include "common_types.h"
#include "graphics_image_item.h"
//////////////////////////////////////////////////////////////////////////
class GraphicsSliderItem : public QGraphicsRectItem
{
using Parent = QGraphicsRectItem;
using This = GraphicsSliderItem;
private:
QPolygonF m_indicator;
qreal m_halfwidth;
bool m_bMain;
public:
explicit GraphicsSliderItem(int _size, bool _main);
~GraphicsSliderItem() override;
void paint(QPainter* _painter, const QStyleOptionGraphicsItem* _option, QWidget* _widget) override;
qreal width() const;
qreal halfwidth() const;
void setWidth(qreal _width);
void setHalfwidth(qreal _halfwidth);
void setColor(QRgb _color);
void setColor(const QColor& _color);
}; // END of class GraphicsSliderItem.
//////////////////////////////////////////////////////////////////////////
class GraphicsSliderArea : public QGraphicsView
{
Q_OBJECT
using Parent = QGraphicsView;
using This = GraphicsSliderArea;
protected:
qreal m_minimumValue;
qreal m_maximumValue;
qreal m_value;
qreal m_windowScale;
QPoint m_mousePressPos;
Qt::MouseButtons m_mouseButtons;
GraphicsSliderItem* m_slider;
GraphicsSliderItem* m_selectionIndicator;
GraphicsHistogramItem* m_histogramItem;
GraphicsImageItem* m_imageItem;
int m_fontHeight;
bool m_bScrolling;
bool m_bBindMode;
bool m_bLocked;
public:
explicit GraphicsSliderArea(QWidget* _parent = nullptr);
~GraphicsSliderArea() override;
// Public virtual methods
void mousePressEvent(QMouseEvent* _event) override;
void mouseReleaseEvent(QMouseEvent* _event) override;
void mouseMoveEvent(QMouseEvent* _event) override;
void wheelEvent(QWheelEvent* _event) override;
void resizeEvent(QResizeEvent* _event) override;
void dragEnterEvent(QDragEnterEvent*) override {}
virtual void clear();
public:
// Public non-virtual methods
bool bindMode() const;
qreal getWindowScale() const;
qreal minimum() const;
qreal maximum() const;
qreal range() const;
qreal value() const;
qreal sliderWidth() const;
qreal sliderHalfWidth() const;
int fontHeight() const;
int margin() const;
int margins() const;
void setValue(qreal _value);
void setRange(qreal _minValue, qreal _maxValue);
void setSliderWidth(qreal _width);
void setSelectionPos(qreal _left, qreal _right);
void showSelectionIndicator();
void hideSelectionIndicator();
inline void lock() {
m_bLocked = true;
}
inline void unlock() {
m_bLocked = false;
}
signals:
void rangeChanged();
void valueChanged(qreal _value);
void wheeled(qreal _mouseX, int _wheelDelta);
protected slots:
void onWindowWidthChange(qreal _width);
}; // END of class GraphicsSliderArea.
//////////////////////////////////////////////////////////////////////////
#endif //EASY_PROFILER_GRAPHICS_SLIDER_AREA_H