scene-tree.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. #include "scene-tree.hpp"
  2. #include <QSizePolicy>
  3. #include <QScrollBar>
  4. #include <QDropEvent>
  5. #include <QPushButton>
  6. #include <QTimer>
  7. #include <cmath>
  8. SceneTree::SceneTree(QWidget *parent_) : QListWidget(parent_)
  9. {
  10. installEventFilter(this);
  11. setDragDropMode(InternalMove);
  12. setMovement(QListView::Snap);
  13. }
  14. void SceneTree::SetGridMode(bool grid)
  15. {
  16. parent()->setProperty("gridMode", grid);
  17. gridMode = grid;
  18. if (gridMode) {
  19. setResizeMode(QListView::Adjust);
  20. setViewMode(QListView::IconMode);
  21. setUniformItemSizes(true);
  22. setStyleSheet("*{padding: 0; margin: 0;}");
  23. } else {
  24. setViewMode(QListView::ListMode);
  25. setResizeMode(QListView::Fixed);
  26. setStyleSheet("");
  27. }
  28. QResizeEvent event(size(), size());
  29. resizeEvent(&event);
  30. }
  31. bool SceneTree::GetGridMode()
  32. {
  33. return gridMode;
  34. }
  35. void SceneTree::SetGridItemWidth(int width)
  36. {
  37. maxWidth = width;
  38. }
  39. void SceneTree::SetGridItemHeight(int height)
  40. {
  41. itemHeight = height;
  42. }
  43. int SceneTree::GetGridItemWidth()
  44. {
  45. return maxWidth;
  46. }
  47. int SceneTree::GetGridItemHeight()
  48. {
  49. return itemHeight;
  50. }
  51. bool SceneTree::eventFilter(QObject *obj, QEvent *event)
  52. {
  53. return QObject::eventFilter(obj, event);
  54. }
  55. void SceneTree::resizeEvent(QResizeEvent *event)
  56. {
  57. if (gridMode) {
  58. int scrollWid = verticalScrollBar()->sizeHint().width();
  59. const QRect lastItem = visualItemRect(item(count() - 1));
  60. const int h = lastItem.y() + lastItem.height();
  61. if (h < height()) {
  62. setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
  63. scrollWid = 0;
  64. } else {
  65. setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
  66. }
  67. int wid = contentsRect().width() - scrollWid - 1;
  68. int items = (int)std::ceil((float)wid / maxWidth);
  69. int itemWidth = wid / items;
  70. setGridSize(QSize(itemWidth, itemHeight));
  71. for (int i = 0; i < count(); i++) {
  72. item(i)->setSizeHint(QSize(itemWidth, itemHeight));
  73. }
  74. } else {
  75. setGridSize(QSize());
  76. for (int i = 0; i < count(); i++) {
  77. item(i)->setData(Qt::SizeHintRole, QVariant());
  78. }
  79. }
  80. QListWidget::resizeEvent(event);
  81. }
  82. void SceneTree::startDrag(Qt::DropActions supportedActions)
  83. {
  84. QListWidget::startDrag(supportedActions);
  85. }
  86. void SceneTree::dropEvent(QDropEvent *event)
  87. {
  88. if (event->source() != this) {
  89. QListWidget::dropEvent(event);
  90. return;
  91. }
  92. if (gridMode) {
  93. int scrollWid = verticalScrollBar()->sizeHint().width();
  94. const QRect firstItem = visualItemRect(item(0));
  95. const QRect lastItem = visualItemRect(item(count() - 1));
  96. const int h = lastItem.y() + lastItem.height();
  97. const int firstItemY = abs(firstItem.y());
  98. if (h < height()) {
  99. setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
  100. scrollWid = 0;
  101. } else {
  102. setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
  103. }
  104. float wid = contentsRect().width() - scrollWid - 1;
  105. #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
  106. QPoint point = event->position().toPoint();
  107. #else
  108. QPoint point = event->pos();
  109. #endif
  110. int x = (float)point.x() / wid * std::ceil(wid / maxWidth);
  111. int y = (point.y() + firstItemY) / itemHeight;
  112. int r = x + y * std::ceil(wid / maxWidth);
  113. QListWidgetItem *item = takeItem(selectedIndexes()[0].row());
  114. insertItem(r, item);
  115. setCurrentItem(item);
  116. resize(size());
  117. }
  118. QListWidget::dropEvent(event);
  119. // We must call resizeEvent to correctly place all grid items.
  120. // We also do this in rowsInserted.
  121. QResizeEvent resEvent(size(), size());
  122. SceneTree::resizeEvent(&resEvent);
  123. QTimer::singleShot(100, [this]() { emit scenesReordered(); });
  124. }
  125. void SceneTree::RepositionGrid(QDragMoveEvent *event)
  126. {
  127. int scrollWid = verticalScrollBar()->sizeHint().width();
  128. const QRect firstItem = visualItemRect(item(0));
  129. const QRect lastItem = visualItemRect(item(count() - 1));
  130. const int h = lastItem.y() + lastItem.height();
  131. const int firstItemY = abs(firstItem.y());
  132. if (h < height()) {
  133. setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
  134. scrollWid = 0;
  135. } else {
  136. setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
  137. }
  138. float wid = contentsRect().width() - scrollWid - 1;
  139. if (event) {
  140. #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
  141. QPoint point = event->position().toPoint();
  142. #else
  143. QPoint point = event->pos();
  144. #endif
  145. int x = (float)point.x() / wid * std::ceil(wid / maxWidth);
  146. int y = (point.y() + firstItemY) / itemHeight;
  147. int r = x + y * std::ceil(wid / maxWidth);
  148. int orig = selectedIndexes()[0].row();
  149. for (int i = 0; i < count(); i++) {
  150. auto *wItem = item(i);
  151. if (wItem->isSelected())
  152. continue;
  153. QModelIndex index = indexFromItem(wItem);
  154. int off = (i >= r ? 1 : 0) -
  155. (i > orig && i > r ? 1 : 0) -
  156. (i > orig && i == r ? 2 : 0);
  157. int xPos = (i + off) % (int)std::ceil(wid / maxWidth);
  158. int yPos = (i + off) / (int)std::ceil(wid / maxWidth);
  159. QSize g = gridSize();
  160. QPoint position(xPos * g.width(), yPos * g.height());
  161. setPositionForIndex(position, index);
  162. }
  163. } else {
  164. for (int i = 0; i < count(); i++) {
  165. auto *wItem = item(i);
  166. if (wItem->isSelected())
  167. continue;
  168. QModelIndex index = indexFromItem(wItem);
  169. int xPos = i % (int)std::ceil(wid / maxWidth);
  170. int yPos = i / (int)std::ceil(wid / maxWidth);
  171. QSize g = gridSize();
  172. QPoint position(xPos * g.width(), yPos * g.height());
  173. setPositionForIndex(position, index);
  174. }
  175. }
  176. }
  177. void SceneTree::dragMoveEvent(QDragMoveEvent *event)
  178. {
  179. if (gridMode) {
  180. RepositionGrid(event);
  181. }
  182. QListWidget::dragMoveEvent(event);
  183. }
  184. void SceneTree::dragLeaveEvent(QDragLeaveEvent *event)
  185. {
  186. if (gridMode) {
  187. RepositionGrid();
  188. }
  189. QListWidget::dragLeaveEvent(event);
  190. }
  191. void SceneTree::rowsInserted(const QModelIndex &parent, int start, int end)
  192. {
  193. QResizeEvent event(size(), size());
  194. SceneTree::resizeEvent(&event);
  195. QListWidget::rowsInserted(parent, start, end);
  196. }
  197. #if QT_VERSION < QT_VERSION_CHECK(6, 4, 3)
  198. // Workaround for QTBUG-105870. Remove once that is solved upstream.
  199. void SceneTree::selectionChanged(const QItemSelection &selected,
  200. const QItemSelection &deselected)
  201. {
  202. if (selected.count() == 0 && deselected.count() > 0 &&
  203. !property("clearing").toBool())
  204. setCurrentRow(deselected.indexes().front().row());
  205. }
  206. #endif