scene-tree.cpp 5.9 KB

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