1 /************************************************************************
2 * file name         : blocks_graphics_view.h
3 * ----------------- :
4 * creation time     : 2016/06/26
5 * author            : Victor Zarubkin
6 * email             : v.s.zarubkin@gmail.com
7 * ----------------- :
8 * description       : The file contains declaration of GraphicsScene and GraphicsView and
9 *                   : it's auxiliary classes for displyaing easy_profiler blocks tree.
10 * ----------------- :
11 * change log        : * 2016/06/26 Victor Zarubkin: moved sources from graphics_view.h
12 *                   :       and renamed classes from My* to Prof*.
13 *                   :
14 *                   : * 2016/06/29 Victor Zarubkin: Highly optimized painting performance and memory consumption.
15 *                   :
16 *                   : * 2016/06/30 Victor Zarubkin: Replaced doubles with floats (in ProfBlockItem) for less memory consumption.
17 *                   :
18 *                   : * 2016/09/15 Victor Zarubkin: Moved sources of EasyGraphicsItem and EasyChronometerItem to separate files.
19 *                   :
20 *                   : *
21 * ----------------- :
22 * license           : Lightweight profiler library for c++
23 *                   : Copyright(C) 2016-2017  Sergey Yagovtsev, Victor Zarubkin
24 *                   :
25 *                   : Licensed under either of
26 *                   :     * MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
27 *                   :     * Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
28 *                   : at your option.
29 *                   :
30 *                   : The MIT License
31 *                   :
32 *                   : Permission is hereby granted, free of charge, to any person obtaining a copy
33 *                   : of this software and associated documentation files (the "Software"), to deal
34 *                   : in the Software without restriction, including without limitation the rights
35 *                   : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
36 *                   : of the Software, and to permit persons to whom the Software is furnished
37 *                   : to do so, subject to the following conditions:
38 *                   :
39 *                   : The above copyright notice and this permission notice shall be included in all
40 *                   : copies or substantial portions of the Software.
41 *                   :
42 *                   : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
43 *                   : INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
44 *                   : PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
45 *                   : LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
46 *                   : TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
47 *                   : USE OR OTHER DEALINGS IN THE SOFTWARE.
48 *                   :
49 *                   : The Apache License, Version 2.0 (the "License")
50 *                   :
51 *                   : You may not use this file except in compliance with the License.
52 *                   : You may obtain a copy of the License at
53 *                   :
54 *                   : http://www.apache.org/licenses/LICENSE-2.0
55 *                   :
56 *                   : Unless required by applicable law or agreed to in writing, software
57 *                   : distributed under the License is distributed on an "AS IS" BASIS,
58 *                   : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
59 *                   : See the License for the specific language governing permissions and
60 *                   : limitations under the License.
61 ************************************************************************/
62 
63 #ifndef EASY_GRAPHICS_VIEW_H
64 #define EASY_GRAPHICS_VIEW_H
65 
66 #include <stdlib.h>
67 #include <unordered_set>
68 
69 #include <QGraphicsView>
70 #include <QGraphicsItem>
71 #include <QPoint>
72 #include <QRectF>
73 #include <QTimer>
74 #include <QLabel>
75 
76 #include <easy/reader.h>
77 
78 #include "common_functions.h"
79 
80 //////////////////////////////////////////////////////////////////////////
81 //////////////////////////////////////////////////////////////////////////
82 
83 class QGraphicsProxyWidget;
84 class EasyGraphicsView;
85 class EasyGraphicsItem;
86 class EasyGraphicsScrollbar;
87 class EasyChronometerItem;
88 
89 //////////////////////////////////////////////////////////////////////////
90 
91 #define EASY_QGRAPHICSITEM(ClassName) \
92 class ClassName : public QGraphicsItem { \
93     QRectF m_boundingRect; \
94 public: \
95     ClassName() : QGraphicsItem() {} \
96     virtual ~ClassName() {} \
97     void paint(QPainter* _painter, const QStyleOptionGraphicsItem* _option, QWidget* _widget = nullptr) override; \
98     QRectF boundingRect() const override { return m_boundingRect; } \
99     void setBoundingRect(qreal x, qreal y, qreal w, qreal h) { m_boundingRect.setRect(x, y, w, h); } \
100     void setBoundingRect(const QRectF& _rect) { m_boundingRect = _rect; } \
101 }
102 
103 EASY_QGRAPHICSITEM(EasyBackgroundItem);
104 EASY_QGRAPHICSITEM(EasyTimelineIndicatorItem);
105 EASY_QGRAPHICSITEM(EasyThreadNameItem);
106 
107 #undef EASY_QGRAPHICSITEM
108 
109 //////////////////////////////////////////////////////////////////////////
110 
111 struct EasyBoldLabel : public QLabel {
112     EasyBoldLabel(const QString& _text, QWidget* _parent = nullptr);
113     virtual ~EasyBoldLabel();
114 };
115 
116 //////////////////////////////////////////////////////////////////////////
117 
118 class EasyGraphicsView : public QGraphicsView
119 {
120     Q_OBJECT
121 
122 private:
123 
124     using Parent = QGraphicsView;
125     using This = EasyGraphicsView;
126     using Items = ::std::vector<EasyGraphicsItem*>;
127     //using Keys = ::std::unordered_set<int, ::estd::hash<int> >;
128 
129     Items                               m_items; ///< Array of all EasyGraphicsItem items
130     //Keys                                 m_keys; ///< Pressed keyboard keys
131     ::profiler_gui::TreeBlocks m_selectedBlocks; ///< Array of items which were selected by selection zone (EasyChronometerItem)
132     QTimer                       m_flickerTimer; ///< Timer for flicking behavior
133     QTimer                          m_idleTimer; ///<
134     QRectF                   m_visibleSceneRect; ///< Visible scene rectangle
135     ::profiler::timestamp_t         m_beginTime; ///< Begin time of profiler session. Used to reduce values of all begin and end times of profiler blocks.
136     qreal                          m_sceneWidth; ///<
137     qreal                               m_scale; ///< Current scale
138     qreal                              m_offset; ///< Have to use manual offset for all scene content instead of using scrollbars because QScrollBar::value is 32-bit integer :(
139     qreal                        m_timelineStep; ///<
140     uint64_t                         m_idleTime; ///<
141     QPoint                      m_mousePressPos; ///< Last mouse global position (used by mousePressEvent and mouseMoveEvent)
142     QPoint                      m_mouseMovePath; ///< Mouse move path between press and release of any button
143     Qt::MouseButtons             m_mouseButtons; ///< Pressed mouse buttons
144     EasyGraphicsScrollbar*         m_pScrollbar; ///< Pointer to the graphics scrollbar widget
145     EasyChronometerItem*      m_chronometerItem; ///< Pointer to the EasyChronometerItem which is displayed when you press right mouse button and move mouse left or right. This item is used to select blocks to display in tree widget.
146     EasyChronometerItem*   m_chronometerItemAux; ///< Pointer to the EasyChronometerItem which is displayed when you double click left mouse button and move mouse left or right. This item is used only to measure time.
147     QGraphicsProxyWidget*         m_popupWidget; ///<
148     int                         m_flickerSpeedX; ///< Current flicking speed x
149     int                         m_flickerSpeedY; ///< Current flicking speed y
150     int                       m_flickerCounterX;
151     int                       m_flickerCounterY;
152     bool                         m_bDoubleClick; ///< Is mouse buttons double clicked
153     bool                        m_bUpdatingRect; ///< Stub flag which is used to avoid excess calculations on some scene update (flicking, scaling and so on)
154     bool                               m_bEmpty; ///< Indicates whether scene is empty and has no items
155 
156 public:
157 
158     explicit EasyGraphicsView(QWidget* _parent = nullptr);
159     virtual ~EasyGraphicsView();
160 
161     // Public virtual methods
162 
163     void wheelEvent(QWheelEvent* _event) override;
164     void mousePressEvent(QMouseEvent* _event) override;
165     void mouseDoubleClickEvent(QMouseEvent* _event) override;
166     void mouseReleaseEvent(QMouseEvent* _event) override;
167     void mouseMoveEvent(QMouseEvent* _event) override;
168     void keyPressEvent(QKeyEvent* _event) override;
169     void keyReleaseEvent(QKeyEvent* _event) override;
170     void resizeEvent(QResizeEvent* _event) override;
171 
dragEnterEvent(QDragEnterEvent *)172     void dragEnterEvent(QDragEnterEvent*) override {}
173 
174 public:
175 
176     // Public non-virtual methods
177 
178     qreal sceneWidth() const;
179     qreal chronoTime() const;
180     qreal chronoTimeAux() const;
181 
182     void setScrollbar(EasyGraphicsScrollbar* _scrollbar);
183     void clear();
184 
185     void setTree(const ::profiler::thread_blocks_tree_t& _blocksTree);
186 
187     const Items& getItems() const;
188 
189 signals:
190 
191     // Signals
192 
193     void sceneUpdated();
194     void treeChanged();
195     void intervalChanged(const ::profiler_gui::TreeBlocks& _blocks, ::profiler::timestamp_t _session_begin_time, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict);
196 
197 private:
198 
199     // Private non-virtual methods
200 
201     void removePopup(bool _removeFromScene = false);
202 
203     EasyChronometerItem* createChronometer(bool _main = true);
204     bool moveChrono(EasyChronometerItem* _chronometerItem, qreal _mouseX);
205     void initMode();
206     int updateVisibleSceneRect();
207     void updateTimelineStep(qreal _windowWidth);
208     void scaleTo(qreal _scale);
209     void scrollTo(const EasyGraphicsItem* _item);
210     void onWheel(qreal _mouseX, int _wheelDelta);
211     qreal setTree(EasyGraphicsItem* _item, const ::profiler::BlocksTree::children_t& _children, qreal& _height, uint32_t& _maxDepthChild, qreal _y, short _level);
212 
213 private slots:
214 
215     // Private Slots
216 
217     void repaintScene();
218     void onGraphicsScrollbarWheel(qreal _mouseX, int _wheelDelta);
219     void onScrollbarValueChange(int);
220     void onGraphicsScrollbarValueChange(qreal);
221     void onFlickerTimeout();
222     void onIdleTimeout();
223     void onHierarchyFlagChange(bool _value);
224     void onSelectedThreadChange(::profiler::thread_id_t _id);
225     void onSelectedBlockChange(unsigned int _block_index);
226     void onRefreshRequired();
227     void onThreadViewChanged();
228 
229 public:
230 
231     // Public inline methods
232 
scale()233     inline qreal scale() const
234     {
235         return m_scale;
236     }
237 
offset()238     inline qreal offset() const
239     {
240         return m_offset;
241     }
242 
visibleSceneRect()243     inline const QRectF& visibleSceneRect() const
244     {
245         return m_visibleSceneRect;
246     }
247 
timelineStep()248     inline qreal timelineStep() const
249     {
250         return m_timelineStep;
251     }
252 
time2position(const profiler::timestamp_t & _time)253     inline qreal time2position(const profiler::timestamp_t& _time) const
254     {
255         return PROF_MICROSECONDS(qreal(_time - m_beginTime));
256         //return PROF_MILLISECONDS(qreal(_time - m_beginTime));
257     }
258 
position2time(qreal _pos)259     inline ::profiler::timestamp_t position2time(qreal _pos) const
260     {
261         return PROF_FROM_MICROSECONDS(_pos);
262         //return PROF_FROM_MILLISECONDS(_pos);
263     }
264 
265 }; // END of class EasyGraphicsView.
266 
267 //////////////////////////////////////////////////////////////////////////
268 
269 class EasyThreadNamesWidget : public QGraphicsView
270 {
271     Q_OBJECT
272 
273 private:
274 
275     typedef QGraphicsView Parent;
276     typedef EasyThreadNamesWidget This;
277 
278     QTimer                  m_idleTimer; ///<
279     uint64_t                 m_idleTime; ///<
280     EasyGraphicsView*            m_view; ///<
281     QGraphicsProxyWidget* m_popupWidget; ///<
282     int                     m_maxLength; ///<
283     const int        m_additionalHeight; ///<
284 
285 public:
286 
287     explicit EasyThreadNamesWidget(EasyGraphicsView* _view, int _additionalHeight, QWidget* _parent = nullptr);
288     virtual ~EasyThreadNamesWidget();
289 
290     void mousePressEvent(QMouseEvent* _event) override;
291     void mouseDoubleClickEvent(QMouseEvent* _event) override;
292     void mouseReleaseEvent(QMouseEvent* _event) override;
293     void mouseMoveEvent(QMouseEvent* _event) override;
294     void keyPressEvent(QKeyEvent* _event) override;
295     void keyReleaseEvent(QKeyEvent* _event) override;
296     void wheelEvent(QWheelEvent* _event) override;
297 
dragEnterEvent(QDragEnterEvent *)298     void dragEnterEvent(QDragEnterEvent*) override {}
299 
300     void clear();
301 
view()302     const EasyGraphicsView* view() const
303     {
304         return m_view;
305     }
306 
307 private:
308 
309     void removePopup(bool _removeFromScene = false);
310 
311 private slots:
312 
313     void setVerticalScrollbarRange(int _minValue, int _maxValue);
314     void onTreeChange();
315     void onIdleTimeout();
316     void repaintScene();
317 
318 }; // END of class EasyThreadNamesWidget.
319 
320 //////////////////////////////////////////////////////////////////////////
321 
322 class EasyGraphicsViewWidget : public QWidget
323 {
324     Q_OBJECT
325 
326 private:
327 
328     EasyGraphicsScrollbar*         m_scrollbar;
329     EasyGraphicsView*                   m_view;
330     EasyThreadNamesWidget* m_threadNamesWidget;
331 
332 public:
333 
334     explicit EasyGraphicsViewWidget(QWidget* _parent = nullptr);
335     virtual ~EasyGraphicsViewWidget();
336 
337     EasyGraphicsView* view();
338     void clear();
339 
340 private:
341 
342     void initWidget();
343 
344 }; // END of class EasyGraphicsViewWidget.
345 
346 //////////////////////////////////////////////////////////////////////////
347 //////////////////////////////////////////////////////////////////////////
348 
349 #endif // EASY_GRAPHICS_VIEW_H
350