easy_chronometer_item.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. /************************************************************************
  2. * file name : easy_chronometer_item.cpp
  3. * ----------------- :
  4. * creation time : 2016/09/15
  5. * author : Victor Zarubkin
  6. * email : [email protected]
  7. * ----------------- :
  8. * description : The file contains implementation of EasyChronometerItem.
  9. * ----------------- :
  10. * change log : * 2016/09/15 Victor Zarubkin: moved sources from blocks_graphics_view.cpp
  11. * :
  12. * : *
  13. * ----------------- :
  14. * license : Lightweight profiler library for c++
  15. * : Copyright(C) 2016-2017 Sergey Yagovtsev, Victor Zarubkin
  16. * :
  17. * : Licensed under either of
  18. * : * MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
  19. * : * Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
  20. * : at your option.
  21. * :
  22. * : The MIT License
  23. * :
  24. * : Permission is hereby granted, free of charge, to any person obtaining a copy
  25. * : of this software and associated documentation files (the "Software"), to deal
  26. * : in the Software without restriction, including without limitation the rights
  27. * : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
  28. * : of the Software, and to permit persons to whom the Software is furnished
  29. * : to do so, subject to the following conditions:
  30. * :
  31. * : The above copyright notice and this permission notice shall be included in all
  32. * : copies or substantial portions of the Software.
  33. * :
  34. * : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
  35. * : INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  36. * : PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  37. * : LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  38. * : TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
  39. * : USE OR OTHER DEALINGS IN THE SOFTWARE.
  40. * :
  41. * : The Apache License, Version 2.0 (the "License")
  42. * :
  43. * : You may not use this file except in compliance with the License.
  44. * : You may obtain a copy of the License at
  45. * :
  46. * : http://www.apache.org/licenses/LICENSE-2.0
  47. * :
  48. * : Unless required by applicable law or agreed to in writing, software
  49. * : distributed under the License is distributed on an "AS IS" BASIS,
  50. * : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  51. * : See the License for the specific language governing permissions and
  52. * : limitations under the License.
  53. ************************************************************************/
  54. #include <QGraphicsScene>
  55. #include <QFontMetricsF>
  56. #include <math.h>
  57. #include "blocks_graphics_view.h"
  58. #include "easy_chronometer_item.h"
  59. #include "globals.h"
  60. //////////////////////////////////////////////////////////////////////////
  61. //////////////////////////////////////////////////////////////////////////
  62. const auto CHRONOMETER_FONT = ::profiler_gui::EFont("Helvetica", 16, QFont::Bold);
  63. #ifdef max
  64. #undef max
  65. #endif
  66. #ifdef min
  67. #undef min
  68. #endif
  69. //////////////////////////////////////////////////////////////////////////
  70. EasyChronometerItem::EasyChronometerItem(bool _main)
  71. : Parent()
  72. , m_color(::profiler_gui::CHRONOMETER_COLOR)
  73. , m_left(0)
  74. , m_right(0)
  75. , m_bMain(_main)
  76. , m_bReverse(false)
  77. , m_bHoverIndicator(false)
  78. , m_bHoverLeftBorder(false)
  79. , m_bHoverRightBorder(false)
  80. {
  81. m_indicator.reserve(3);
  82. }
  83. EasyChronometerItem::~EasyChronometerItem()
  84. {
  85. }
  86. QRectF EasyChronometerItem::boundingRect() const
  87. {
  88. return m_boundingRect;
  89. }
  90. void EasyChronometerItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*, QWidget*)
  91. {
  92. auto const sceneView = view();
  93. const auto currentScale = sceneView->scale();
  94. const auto offset = sceneView->offset();
  95. const auto visibleSceneRect = sceneView->visibleSceneRect();
  96. auto sceneLeft = offset, sceneRight = offset + visibleSceneRect.width() / currentScale;
  97. if (m_bMain)
  98. m_indicator.clear();
  99. if (m_left > sceneRight || m_right < sceneLeft)
  100. {
  101. // This item is out of screen
  102. if (m_bMain)
  103. {
  104. const int size = m_bHoverIndicator ? 12 : 10;
  105. auto vcenter = visibleSceneRect.top() + visibleSceneRect.height() * 0.5;
  106. auto color = QColor::fromRgb(m_color.rgb());
  107. auto pen = _painter->pen();
  108. pen.setColor(color);
  109. m_indicator.clear();
  110. if (m_left > sceneRight)
  111. {
  112. sceneRight = (sceneRight - offset) * currentScale;
  113. m_indicator.push_back(QPointF(sceneRight - size, vcenter - size));
  114. m_indicator.push_back(QPointF(sceneRight, vcenter));
  115. m_indicator.push_back(QPointF(sceneRight - size, vcenter + size));
  116. }
  117. else
  118. {
  119. sceneLeft = (sceneLeft - offset) * currentScale;
  120. m_indicator.push_back(QPointF(sceneLeft + size, vcenter - size));
  121. m_indicator.push_back(QPointF(sceneLeft, vcenter));
  122. m_indicator.push_back(QPointF(sceneLeft + size, vcenter + size));
  123. }
  124. _painter->save();
  125. _painter->setTransform(QTransform::fromTranslate(-x(), -y()), true);
  126. _painter->setBrush(m_bHoverIndicator ? QColor::fromRgb(0xffff0000) : color);
  127. _painter->setPen(pen);
  128. _painter->drawPolygon(m_indicator);
  129. _painter->restore();
  130. }
  131. return;
  132. }
  133. auto selectedInterval = width();
  134. QRectF rect((m_left - offset) * currentScale, visibleSceneRect.top(), ::std::max(selectedInterval * currentScale, 1.0), visibleSceneRect.height());
  135. selectedInterval = units2microseconds(selectedInterval);
  136. const QString text = ::profiler_gui::timeStringReal(EASY_GLOBALS.time_units, selectedInterval); // Displayed text
  137. const auto textRect = QFontMetricsF(CHRONOMETER_FONT, sceneView).boundingRect(text); // Calculate displayed text boundingRect
  138. const auto rgb = m_color.rgb() & 0x00ffffff;
  139. // Paint!--------------------------
  140. _painter->save();
  141. // instead of scrollbar we're using manual offset
  142. _painter->setTransform(QTransform::fromTranslate(-x(), -y()), true);
  143. if (m_left < sceneLeft)
  144. rect.setLeft(0);
  145. if (m_right > sceneRight)
  146. rect.setWidth((sceneRight - offset) * currentScale - rect.left());
  147. // draw transparent rectangle
  148. auto vcenter = rect.top() + rect.height() * 0.5;
  149. QLinearGradient g(rect.left(), vcenter, rect.right(), vcenter);
  150. g.setColorAt(0, m_color);
  151. g.setColorAt(0.2, QColor::fromRgba(0x14000000 | rgb));
  152. g.setColorAt(0.8, QColor::fromRgba(0x14000000 | rgb));
  153. g.setColorAt(1, m_color);
  154. _painter->setBrush(g);
  155. _painter->setPen(Qt::NoPen);
  156. _painter->drawRect(rect);
  157. // draw left and right borders
  158. _painter->setBrush(Qt::NoBrush);
  159. if (m_bMain && !m_bReverse)
  160. {
  161. QPen p(QColor::fromRgba(0xd0000000 | rgb));
  162. p.setStyle(Qt::DotLine);
  163. _painter->setPen(p);
  164. }
  165. else
  166. {
  167. _painter->setPen(QColor::fromRgba(0xd0000000 | rgb));
  168. }
  169. if (m_left > sceneLeft)
  170. {
  171. if (m_bHoverLeftBorder)
  172. {
  173. // Set bold if border is hovered
  174. QPen p = _painter->pen();
  175. p.setWidth(3);
  176. _painter->setPen(p);
  177. }
  178. _painter->drawLine(QPointF(rect.left(), rect.top()), QPointF(rect.left(), rect.bottom()));
  179. }
  180. if (m_right < sceneRight)
  181. {
  182. if (m_bHoverLeftBorder)
  183. {
  184. // Restore width
  185. QPen p = _painter->pen();
  186. p.setWidth(1);
  187. _painter->setPen(p);
  188. }
  189. else if (m_bHoverRightBorder)
  190. {
  191. // Set bold if border is hovered
  192. QPen p = _painter->pen();
  193. p.setWidth(3);
  194. _painter->setPen(p);
  195. }
  196. _painter->drawLine(QPointF(rect.right(), rect.top()), QPointF(rect.right(), rect.bottom()));
  197. // This is not necessary because another setPen() invoked for draw text
  198. //if (m_bHoverRightBorder)
  199. //{
  200. // // Restore width
  201. // QPen p = _painter->pen();
  202. // p.setWidth(1);
  203. // _painter->setPen(p);
  204. //}
  205. }
  206. // draw text
  207. _painter->setCompositionMode(QPainter::CompositionMode_Difference); // This lets the text to be visible on every background
  208. _painter->setRenderHint(QPainter::TextAntialiasing);
  209. _painter->setPen(0x00ffffff - rgb);
  210. _painter->setFont(CHRONOMETER_FONT);
  211. int textFlags = 0;
  212. switch (EASY_GLOBALS.chrono_text_position)
  213. {
  214. case ::profiler_gui::ChronoTextPosition_Top:
  215. textFlags = Qt::AlignTop | Qt::AlignHCenter;
  216. if (!m_bMain) rect.setTop(rect.top() + textRect.height() * 0.75);
  217. break;
  218. case ::profiler_gui::ChronoTextPosition_Center:
  219. textFlags = Qt::AlignCenter;
  220. if (!m_bMain) rect.setTop(rect.top() + textRect.height() * 1.5);
  221. break;
  222. case ::profiler_gui::ChronoTextPosition_Bottom:
  223. textFlags = Qt::AlignBottom | Qt::AlignHCenter;
  224. if (!m_bMain) rect.setHeight(rect.height() - textRect.height() * 0.75);
  225. break;
  226. }
  227. const auto textRect_width = textRect.width() * ::profiler_gui::FONT_METRICS_FACTOR;
  228. if (textRect_width < rect.width())
  229. {
  230. // Text will be drawed inside rectangle
  231. _painter->drawText(rect, textFlags, text);
  232. _painter->restore();
  233. return;
  234. }
  235. const auto w = textRect_width / currentScale;
  236. if (m_right + w < sceneRight)
  237. {
  238. // Text will be drawed to the right of rectangle
  239. rect.translate(rect.width(), 0);
  240. textFlags &= ~Qt::AlignHCenter;
  241. textFlags |= Qt::AlignLeft;
  242. }
  243. else if (m_left - w > sceneLeft)
  244. {
  245. // Text will be drawed to the left of rectangle
  246. rect.translate(-rect.width(), 0);
  247. textFlags &= ~Qt::AlignHCenter;
  248. textFlags |= Qt::AlignRight;
  249. }
  250. //else // Text will be drawed inside rectangle
  251. _painter->drawText(rect, textFlags | Qt::TextDontClip, text);
  252. _painter->restore();
  253. // END Paint!~~~~~~~~~~~~~~~~~~~~~~
  254. }
  255. void EasyChronometerItem::hide()
  256. {
  257. m_bHoverIndicator = false;
  258. m_bHoverLeftBorder = false;
  259. m_bHoverRightBorder = false;
  260. m_bReverse = false;
  261. Parent::hide();
  262. }
  263. bool EasyChronometerItem::indicatorContains(const QPointF& _pos) const
  264. {
  265. if (m_indicator.empty())
  266. return false;
  267. const auto itemX = toItem(_pos.x());
  268. return m_indicator.containsPoint(QPointF(itemX, _pos.y()), Qt::OddEvenFill);
  269. }
  270. void EasyChronometerItem::setHoverLeft(bool _hover)
  271. {
  272. m_bHoverLeftBorder = _hover;
  273. }
  274. void EasyChronometerItem::setHoverRight(bool _hover)
  275. {
  276. m_bHoverRightBorder = _hover;
  277. }
  278. bool EasyChronometerItem::hoverLeft(qreal _x) const
  279. {
  280. const auto dx = fabs(_x - m_left) * view()->scale();
  281. return dx < 4;
  282. }
  283. bool EasyChronometerItem::hoverRight(qreal _x) const
  284. {
  285. const auto dx = fabs(_x - m_right) * view()->scale();
  286. return dx < 4;
  287. }
  288. QPointF EasyChronometerItem::toItem(const QPointF& _pos) const
  289. {
  290. const auto sceneView = view();
  291. return QPointF((_pos.x() - sceneView->offset()) * sceneView->scale() - x(), _pos.y());
  292. }
  293. qreal EasyChronometerItem::toItem(qreal _x) const
  294. {
  295. const auto sceneView = view();
  296. return (_x - sceneView->offset()) * sceneView->scale() - x();
  297. }
  298. void EasyChronometerItem::setColor(const QColor& _color)
  299. {
  300. m_color = _color;
  301. }
  302. void EasyChronometerItem::setBoundingRect(qreal x, qreal y, qreal w, qreal h)
  303. {
  304. m_boundingRect.setRect(x, y, w, h);
  305. }
  306. void EasyChronometerItem::setBoundingRect(const QRectF& _rect)
  307. {
  308. m_boundingRect = _rect;
  309. }
  310. void EasyChronometerItem::setLeftRight(qreal _left, qreal _right)
  311. {
  312. if (_left < _right)
  313. {
  314. m_left = _left;
  315. m_right = _right;
  316. }
  317. else
  318. {
  319. m_left = _right;
  320. m_right = _left;
  321. }
  322. }
  323. void EasyChronometerItem::setReverse(bool _reverse)
  324. {
  325. m_bReverse = _reverse;
  326. }
  327. void EasyChronometerItem::setHoverIndicator(bool _hover)
  328. {
  329. m_bHoverIndicator = _hover;
  330. }
  331. const EasyGraphicsView* EasyChronometerItem::view() const
  332. {
  333. return static_cast<const EasyGraphicsView*>(scene()->parent());
  334. }
  335. EasyGraphicsView* EasyChronometerItem::view()
  336. {
  337. return static_cast<EasyGraphicsView*>(scene()->parent());
  338. }
  339. //////////////////////////////////////////////////////////////////////////
  340. //////////////////////////////////////////////////////////////////////////