0
0
mirror of https://github.com/yse/easy_profiler.git synced 2024-12-27 00:31:02 +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}/easy_socket.h
${EASY_INCLUDE_DIR}/profiler.h ${EASY_INCLUDE_DIR}/profiler.h
${EASY_INCLUDE_DIR}/reader.h ${EASY_INCLUDE_DIR}/reader.h
${EASY_INCLUDE_DIR}/utility.h
${EASY_INCLUDE_DIR}/serialized_block.h ${EASY_INCLUDE_DIR}/serialized_block.h
${EASY_INCLUDE_DIR}/details/arbitrary_value_aux.h ${EASY_INCLUDE_DIR}/details/arbitrary_value_aux.h
${EASY_INCLUDE_DIR}/details/arbitrary_value_public_types.h ${EASY_INCLUDE_DIR}/details/arbitrary_value_public_types.h

View File

@ -126,13 +126,13 @@
//extern ProfileManager& MANAGER; //extern ProfileManager& MANAGER;
#define MANAGER ProfileManager::instance() #define MANAGER ProfileManager::instance()
extern const ::profiler::color_t EASY_COLOR_INTERNAL_EVENT; extern const profiler::color_t EASY_COLOR_INTERNAL_EVENT;
#ifdef __MINGW32__ #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; char KERNEL_LOGGER[] = KERNEL_LOGGER_NAME;
#else #else
::std::atomic_uint64_t TRACING_END_TIME = ATOMIC_VAR_INIT(~0ULL); std::atomic_uint64_t TRACING_END_TIME = ATOMIC_VAR_INIT(~0ULL);
#endif #endif
/** /**
@ -171,7 +171,7 @@ namespace profiler {
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
struct ProcessInfo { struct ProcessInfo {
std::string name; ::std::string name;
processid_t id = 0; processid_t id = 0;
int8_t valid = 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; using thread_process_info_map = ::std::unordered_map<decltype(CSwitch::NewThreadId), ProcessInfo*, do_not_calc_hash>;
typedef ::std::unordered_map<processid_t, ProcessInfo, do_not_calc_hash> process_info_map; 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 // Using static is safe because processTraceEvent() is called from one thread
process_info_map PROCESS_INFO_TABLE; 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*))> { 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 { template <class T> struct hash<T*> EASY_FINAL {

View File

@ -484,8 +484,8 @@ extern "C" {
int64_t file_cpu_frequency = 0LL; int64_t file_cpu_frequency = 0LL;
inFile.read((char*)&file_cpu_frequency, sizeof(int64_t)); inFile.read((char*)&file_cpu_frequency, sizeof(int64_t));
uint64_t cpu_frequency = file_cpu_frequency; const uint64_t cpu_frequency = file_cpu_frequency;
const double conversion_factor = static_cast<double>(TIME_FACTOR) / static_cast<double>(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 begin_time = 0ULL;
::profiler::timestamp_t end_time = 0ULL; ::profiler::timestamp_t end_time = 0ULL;
@ -749,7 +749,7 @@ extern "C" {
/**/ /**/
EASY_BLOCK("Find children", ::profiler::colors::Blue); EASY_BLOCK("Find children", ::profiler::colors::Blue);
auto rlower1 = ++root.children.rbegin(); 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(); auto lower = rlower1.base();
::std::move(lower, root.children.end(), ::std::back_inserter(tree.children)); ::std::move(lower, root.children.end(), ::std::back_inserter(tree.children));

View File

@ -36,6 +36,10 @@ if (Qt5Widgets_FOUND)
globals.h globals.h
globals.cpp globals.cpp
globals_qobjects.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.h
main_window.cpp main_window.cpp
tree_widget_item.h 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; const auto mouseX = m_offset + mapToScene(m_mousePressPos).x() / m_scale;
m_chronometerItem->setLeftRight(mouseX, mouseX); m_chronometerItem->setLeftRight(mouseX, mouseX);
m_chronometerItem->hide(); 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) if (m_chronometerItem->isVisible() && m_chronometerItem->width() < 1e-6)
{ {
m_chronometerItem->hide(); m_chronometerItem->hide();
m_pScrollbar->hideChrono(); m_pScrollbar->hideSelectionIndicator();
} }
if (!m_selectedBlocks.empty()) if (!m_selectedBlocks.empty())
@ -1144,11 +1144,11 @@ void EasyGraphicsView::mouseMoveEvent(QMouseEvent* _event)
if (m_mouseButtons & Qt::RightButton) if (m_mouseButtons & Qt::RightButton)
{ {
bool showItem = moveChrono(m_chronometerItem, x); 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) if (showItem)
{ {
m_pScrollbar->showChrono(); m_pScrollbar->showSelectionIndicator();
} }
needUpdate = true; needUpdate = true;
@ -2006,7 +2006,7 @@ void EasyGraphicsView::onRefreshRequired()
EasyGraphicsViewWidget::EasyGraphicsViewWidget(QWidget* _parent) EasyGraphicsViewWidget::EasyGraphicsViewWidget(QWidget* _parent)
: 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_view(new EasyGraphicsView(this))
, m_threadNamesWidget(new EasyThreadNamesWidget(m_view, m_scrollbar->height(), this)) , m_threadNamesWidget(new EasyThreadNamesWidget(m_view, m_scrollbar->height(), this))
{ {

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -58,88 +58,16 @@
#include <stdlib.h> #include <stdlib.h>
#include <thread> #include <thread>
#include <atomic> #include <atomic>
#include <QGraphicsView>
#include <QGraphicsRectItem>
#include <QAction>
#include <QPolygonF>
#include <QImage> #include <QImage>
#include "easy_qtimer.h" #include "easy_qtimer.h"
#include "common_types.h" #include "graphics_slider_area.h"
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// TODO: use profiler_core/spin_lock.h class GraphicsHistogramItem : public GraphicsImageItem
#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
{ {
typedef QGraphicsRectItem Parent; using Parent = GraphicsImageItem;
typedef EasyGraphicsSliderItem This; using This = GraphicsHistogramItem;
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;
public: public:
@ -147,193 +75,108 @@ public:
private: private:
QRectF m_boundingRect; qreal m_workerTopDuration;
qreal m_topDuration; qreal m_workerBottomDuration;
qreal m_bottomDuration; profiler::timestamp_t m_blockTotalDuraion;
qreal m_maxDuration; QString m_topDurationStr;
qreal m_minDuration; QString m_bottomDurationStr;
qreal m_mouseY; QString m_threadName;
qreal m_imageOrigin; QString m_blockName;
qreal m_imageScale; profiler::BlocksTree::children_t m_selectedBlocks;
qreal m_imageOriginUpdate; profiler::timestamp_t m_threadDuration;
qreal m_imageScaleUpdate; profiler::timestamp_t m_threadProfiledTime;
qreal m_workerImageOrigin; profiler::timestamp_t m_threadWaitTime;
qreal m_workerImageScale; const profiler_gui::EasyItems* m_pSource;
qreal m_workerTopDuration; const profiler::BlocksTreeRoot* m_pProfilerThread;
qreal m_workerBottomDuration; profiler::thread_id_t m_threadId;
::profiler::timestamp_t m_blockTotalDuraion; profiler::block_index_t m_blockId;
QString m_topDurationStr; profiler_gui::TimeUnits m_timeUnits;
QString m_bottomDurationStr; HistRegime m_regime;
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;
public: public:
explicit EasyHistogramItem(); explicit GraphicsHistogramItem();
virtual ~EasyHistogramItem(); ~GraphicsHistogramItem() override;
// Public virtual methods void paint(QPainter* _painter, const QStyleOptionGraphicsItem* _option, QWidget* _widget) override;
QRectF boundingRect() const override; bool updateImage() override;
void paint(QPainter* _painter, const QStyleOptionGraphicsItem* _option, QWidget* _widget = nullptr) 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:
// Public non-virtual methods // Public non-virtual methods
::profiler::thread_id_t threadId() const; profiler::thread_id_t threadId() const;
void setBoundingRect(const QRectF& _rect); void setSource(profiler::thread_id_t _thread_id, const profiler_gui::EasyItems* _items);
void setBoundingRect(qreal x, qreal y, qreal w, qreal h); 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(HistRegime _regime);
void rebuildSource(); void rebuildSource();
void validateName(); 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 pickFrameTime(qreal _y) const;
void onValueChanged();
void onModeChanged();
private: 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 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 paintByPtr(QPainter* _painter);
void paintById(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 Q_OBJECT
private: private:
typedef QGraphicsView Parent; using Parent = GraphicsSliderArea;
typedef EasyGraphicsScrollbar This; using This = EasyGraphicsScrollbar;
qreal m_minimumValue; GraphicsHistogramItem* m_histogramItem = nullptr;
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;
public: public:
explicit EasyGraphicsScrollbar(QWidget* _parent = nullptr); explicit EasyGraphicsScrollbar(bool _fixedHeight, int _height, QWidget* _parent = nullptr);
virtual ~EasyGraphicsScrollbar(); ~EasyGraphicsScrollbar() override;
// Public virtual methods
void clear() override;
void mousePressEvent(QMouseEvent* _event) 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:
// Public non-virtual methods // Public non-virtual methods
void clear(); profiler::thread_id_t hystThread() const;
bool bindMode() const; void setHistogramSource(profiler::thread_id_t _thread_id, const profiler_gui::EasyItems* _items);
qreal getWindowScale() const; void setHistogramSource(profiler::thread_id_t _thread_id, profiler::block_id_t _block_id);
::profiler::thread_id_t hystThread() const; void setHistogramSource(profiler::thread_id_t _thread_id, const profiler_gui::EasyItems& _items) {
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)
{
setHistogramSource(_thread_id, &_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: private slots:
void onThreadViewChanged(); void onThreadViewChanged();
void onWindowWidthChange(qreal _width);
}; // END of class EasyGraphicsScrollbar. }; // END of class EasyGraphicsScrollbar.

View File

@ -60,15 +60,15 @@
EasyQTimer::EasyQTimer() EasyQTimer::EasyQTimer()
: QObject() : 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() : QObject()
, m_handler(::std::forward<::std::function<void()>&&>(_handler)) , m_handler(::std::forward<::std::function<void()>&&>(handler))
{ {
m_timer.setSingleShot(_isSignleShot); m_timer.setSingleShot(signleShot);
connect(&m_timer, &QTimer::timeout, [this](){ m_handler(); }); connect(&m_timer, &QTimer::timeout, [this] { m_handler(); });
} }
EasyQTimer::~EasyQTimer() 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: public:
EasyQTimer(); explicit EasyQTimer();
EasyQTimer(::std::function<void()>&& _handler, bool _isSignleShot = false); explicit EasyQTimer(::std::function<void()>&& handler, bool signleShot = false);
virtual ~EasyQTimer(); ~EasyQTimer() override;
void setHandler(::std::function<void()>&& _handler); void setHandler(::std::function<void()>&& _handler);
inline void start(int msec) { m_timer.start(msec); } void setSignleShot(bool singleShot);
inline void stop() { if (m_timer.isActive()) m_timer.stop(); } bool isSingleShot() const;
inline bool isActive() const { return m_timer.isActive(); }
void setInterval(int msec);
void start(int msec);
void start();
void stop();
bool isActive() const;
}; // END of class EasyQTimer. }; // 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