/code/qttoolkit/contentbrowser/code/widgets/particles/particlecurvewidget.cc

https://github.com/gscept/nebula-trifid · C++ · 351 lines · 229 code · 48 blank · 74 comment · 22 complexity · 695c47fe8a590026436d1da083d4e1b1 MD5 · raw file

  1. //------------------------------------------------------------------------------
  2. // particlecurvewidget.cc
  3. // (C) 2012 Gustav Sterbrant
  4. //------------------------------------------------------------------------------
  5. #include "stdneb.h"
  6. #include "particlecurvewidget.h"
  7. #include <QPainter>
  8. #include <QLineF>
  9. #include <QMouseEvent>
  10. #include <QtOpenGL/QGLWidget>
  11. #define POINTSIZE 12
  12. #define LINEWIDTH 2
  13. #define POINTCOUNT 4
  14. #define HALFSIZE QPointF(POINTSIZE/2, POINTSIZE/2)
  15. QColor baseFillColor = qRgb(255, 153, 51);
  16. QColor highlightedColor = qRgb(235, 135, 45);
  17. QColor lineColor = qRgb(255, 255, 255);
  18. namespace Particles
  19. {
  20. //------------------------------------------------------------------------------
  21. /**
  22. */
  23. ParticleCurveWidget::ParticleCurveWidget(QWidget* parent) :
  24. QGraphicsView(parent),
  25. dragItem(0)
  26. {
  27. this->activePoint = -1;
  28. this->selectedPoint = 0;
  29. this->isDragging = false;
  30. this->setRenderHint(QPainter::Antialiasing);
  31. // create scene
  32. QGraphicsScene* scene = new QGraphicsScene;
  33. this->setScene(scene);
  34. this->setSceneRect(this->rect());
  35. QRectF rect = this->rect();
  36. this->percentPoints.clear();
  37. this->update();
  38. const QPalette& palette = this->palette();
  39. //const QPalette& palette = ((QWidget*)(parent->parent()))->palette();
  40. baseFillColor = palette.button().color();
  41. highlightedColor = palette.light().color();
  42. // create pens for ellipses
  43. QPen stroke(lineColor);
  44. stroke.setWidth(LINEWIDTH);
  45. QBrush fill(baseFillColor);
  46. int i;
  47. for (i = 0; i < POINTCOUNT; i++)
  48. {
  49. this->percentPoints << QPointF(i / (float)(POINTCOUNT-1), 0);
  50. this->dataPoints << this->ConvertPoint(FromPercent, this->percentPoints[i]);
  51. this->uiPoints << this->mapToScene(this->dataPoints[i].toPoint());
  52. QGraphicsEllipseItem* item = this->scene()->addEllipse(QRectF(0, 0, POINTSIZE, POINTSIZE), stroke, fill);
  53. item->setZValue(1);
  54. item->setPos(this->uiPoints[i] - HALFSIZE);
  55. this->pointItems << item;
  56. }
  57. // create lines
  58. for (int i = 0; i < POINTCOUNT-1; i++)
  59. {
  60. // get points
  61. QPointF pos1 = this->pointItems[i]->pos() + HALFSIZE;
  62. QPointF pos2 = this->pointItems[i+1]->pos() + HALFSIZE;
  63. QGraphicsLineItem* item = this->scene()->addLine(QLineF(pos1, pos2), stroke);
  64. item->setZValue(0);
  65. this->lineItems << item;
  66. }
  67. }
  68. //------------------------------------------------------------------------------
  69. /**
  70. */
  71. ParticleCurveWidget::~ParticleCurveWidget()
  72. {
  73. // empty
  74. }
  75. //------------------------------------------------------------------------------
  76. /**
  77. */
  78. void
  79. ParticleCurveWidget::Setup( QPointF point0, QPointF point1, QPointF point2, QPointF point3 )
  80. {
  81. // calculate percental points
  82. this->percentPoints.clear();
  83. this->percentPoints << point0
  84. << point1
  85. << point2
  86. << point3;
  87. // setup actual data
  88. this->dataPoints.clear();
  89. this->dataPoints << this->ConvertPoint(FromPercent, point0)
  90. << this->ConvertPoint(FromPercent, point1)
  91. << this->ConvertPoint(FromPercent, point2)
  92. << this->ConvertPoint(FromPercent, point3);
  93. // setup ui points
  94. this->uiPoints.clear();
  95. this->uiPoints << this->mapToScene(dataPoints[0].toPoint())
  96. << this->mapToScene(dataPoints[1].toPoint())
  97. << this->mapToScene(dataPoints[2].toPoint())
  98. << this->mapToScene(dataPoints[3].toPoint());
  99. // calculate positions of items
  100. int i;
  101. for (i = 0; i < 4; i++)
  102. {
  103. this->pointItems[i]->setPos(this->uiPoints[i] - HALFSIZE);
  104. }
  105. // finally update lines
  106. this->UpdateLines();
  107. }
  108. //------------------------------------------------------------------------------
  109. /**
  110. */
  111. void
  112. ParticleCurveWidget::mousePressEvent( QMouseEvent* e )
  113. {
  114. this->activePoint = -1;
  115. // recolor old point
  116. if (this->selectedPoint != -1)
  117. {
  118. // create pen
  119. QPen pen(lineColor);
  120. pen.setWidth(LINEWIDTH);
  121. // set color
  122. this->pointItems[this->selectedPoint]->setPen(pen);
  123. }
  124. // find item
  125. QGraphicsItem* item = this->scene()->itemAt(this->mapToScene(e->pos()));
  126. // test if it's a point
  127. QGraphicsEllipseItem* point = dynamic_cast<QGraphicsEllipseItem*>(item);
  128. // if we have a point
  129. if (point)
  130. {
  131. // get index of point
  132. int pointIndex = this->pointItems.indexOf(point);
  133. // create pen
  134. QPen pen(highlightedColor);
  135. pen.setWidth(LINEWIDTH);
  136. // color point differently
  137. point->setPen(pen);
  138. // set point index, point item and notify that we are dragging
  139. this->activePoint = this->selectedPoint = pointIndex;
  140. this->dragItem = point;
  141. this->isDragging = true;
  142. // emit signal
  143. emit this->PointSelected(this->activePoint);
  144. }
  145. else
  146. {
  147. this->isDragging = false;
  148. }
  149. }
  150. //------------------------------------------------------------------------------
  151. /**
  152. */
  153. void
  154. ParticleCurveWidget::mouseMoveEvent( QMouseEvent* e )
  155. {
  156. if (this->isDragging)
  157. {
  158. // get position
  159. QPointF pos = e->pos();
  160. // handle first point and last point specially
  161. if (this->activePoint == 0)
  162. {
  163. pos.setX(0);
  164. }
  165. else if (this->activePoint == POINTCOUNT-1)
  166. {
  167. pos.setX(this->width());
  168. }
  169. else
  170. {
  171. // get next point
  172. QPointF nextPos = this->dataPoints[this->activePoint+1];
  173. QPointF prevPos = this->dataPoints[this->activePoint-1];
  174. // clamp X
  175. if (pos.x() < prevPos.x() - 0.01f)
  176. {
  177. pos.setX(prevPos.x() - 0.01f);
  178. }
  179. else if (pos.x() > nextPos.x() + 0.01f)
  180. {
  181. pos.setX(nextPos.x() + 0.01f);
  182. }
  183. }
  184. // clamp Y
  185. if (pos.y() > this->height())
  186. {
  187. pos.setY(this->height());
  188. }
  189. else if (pos.y() < 0)
  190. {
  191. pos.setY(0);
  192. }
  193. // convert to percent
  194. this->percentPoints[this->activePoint] = this->ConvertPoint(ToPercent, pos);
  195. this->dataPoints[this->activePoint] = this->ConvertPoint(FromPercent, this->percentPoints[this->activePoint]);
  196. this->uiPoints[this->activePoint] = this->mapToScene(this->dataPoints[this->activePoint].toPoint());
  197. // update position of graphics
  198. this->pointItems[this->activePoint]->setPos(this->uiPoints[this->activePoint] - HALFSIZE);
  199. // update lines
  200. this->UpdateLines();
  201. }
  202. }
  203. //------------------------------------------------------------------------------
  204. /**
  205. */
  206. void
  207. ParticleCurveWidget::resizeEvent( QResizeEvent* e )
  208. {
  209. // resize window
  210. QGraphicsView::resizeEvent(e);
  211. // then move points again
  212. int i;
  213. for (i = 0; i < POINTCOUNT; i++)
  214. {
  215. this->dataPoints[i] = this->ConvertPoint(FromPercent, this->percentPoints[i]);
  216. this->uiPoints[i] = this->mapToScene(this->dataPoints[i].toPoint());
  217. this->pointItems[i]->setPos(this->uiPoints[i] - HALFSIZE);
  218. }
  219. // update lines
  220. this->UpdateLines();
  221. }
  222. //------------------------------------------------------------------------------
  223. /**
  224. */
  225. void
  226. ParticleCurveWidget::mouseReleaseEvent( QMouseEvent* e )
  227. {
  228. // emit signal if a point has been dragged
  229. if (this->dragItem)
  230. {
  231. emit this->PointUpdated(this->percentPoints[this->activePoint]);
  232. }
  233. this->isDragging = false;
  234. this->activePoint = -1;
  235. this->dragItem = 0;
  236. }
  237. //------------------------------------------------------------------------------
  238. /**
  239. */
  240. void
  241. ParticleCurveWidget::SelectedPointValueChanged( QPointF point )
  242. {
  243. this->percentPoints[this->selectedPoint] = point;
  244. this->dataPoints[this->selectedPoint] = ConvertPoint(FromPercent, this->percentPoints[this->selectedPoint]);
  245. this->uiPoints[this->selectedPoint] = this->mapToScene(this->dataPoints[this->selectedPoint].toPoint());
  246. // get point and move
  247. this->pointItems[this->selectedPoint]->setPos(this->uiPoints[this->selectedPoint] - HALFSIZE);
  248. // also update lines
  249. this->UpdateLines();
  250. }
  251. //------------------------------------------------------------------------------
  252. /**
  253. In the actual widget, we simply treat our points as a percentual representation of the width of the widget.
  254. So here we convert between percentages and their actual position...
  255. */
  256. QPointF
  257. ParticleCurveWidget::ConvertPoint( ConversionMode mode, QPointF point )
  258. {
  259. int height = this->height();
  260. int width = this->width();
  261. switch (mode)
  262. {
  263. case FromPercent:
  264. {
  265. float x = point.x();
  266. float y = 1 - point.y();
  267. x *= width;
  268. y *= height;
  269. return QPointF(x, y);
  270. }
  271. break;
  272. case ToPercent:
  273. {
  274. float x = point.x();
  275. float y = point.y();
  276. x /= width;
  277. y /= height;
  278. y = 1 - y;
  279. return QPointF(x, y);
  280. }
  281. break;
  282. }
  283. // bullshit MSVC
  284. return QPointF();
  285. }
  286. //------------------------------------------------------------------------------
  287. /**
  288. */
  289. void
  290. ParticleCurveWidget::UpdateLines()
  291. {
  292. int i;
  293. for (i = 0; i < POINTCOUNT-1; i++)
  294. {
  295. // get points
  296. QPointF pos1 = this->pointItems[i]->pos() + HALFSIZE;
  297. QPointF pos2 = this->pointItems[i+1]->pos() + HALFSIZE;
  298. QGraphicsLineItem* item = this->lineItems[i];
  299. item->setLine(QLineF(pos1, pos2));
  300. item->setZValue(0);
  301. }
  302. }
  303. } // namespace Particles