The x() and y() values of coordinates for events inside a scrollable QWidget are relative to viewport's scrolled origin, the coordinates of the upper left corner of the visible space, not the widget's true origin. Since we do not allow horizontal scrolling, the value of x() is okay. However, the value of y() needs to be adjusted by an offset of the top()/y() value for the first widget in the SceneTree. When not scrolled, this offset will be 0. When scrolled down, this offset will be a negative value.
259 lines
5.9 KiB
C++
259 lines
5.9 KiB
C++
#include "obs.hpp"
|
|
#include "scene-tree.hpp"
|
|
#include "obs-app.hpp"
|
|
|
|
#include <QSizePolicy>
|
|
#include <QScrollBar>
|
|
#include <QDropEvent>
|
|
#include <QPushButton>
|
|
#include <QTimer>
|
|
|
|
SceneTree::SceneTree(QWidget *parent_) : QListWidget(parent_)
|
|
{
|
|
installEventFilter(this);
|
|
setDragDropMode(InternalMove);
|
|
setMovement(QListView::Snap);
|
|
}
|
|
|
|
void SceneTree::SetGridMode(bool grid)
|
|
{
|
|
config_set_bool(App()->GlobalConfig(), "BasicWindow", "gridMode", grid);
|
|
parent()->setProperty("gridMode", grid);
|
|
gridMode = grid;
|
|
|
|
if (gridMode) {
|
|
setResizeMode(QListView::Adjust);
|
|
setViewMode(QListView::IconMode);
|
|
setUniformItemSizes(true);
|
|
setStyleSheet("*{padding: 0; margin: 0;}");
|
|
} else {
|
|
setViewMode(QListView::ListMode);
|
|
setResizeMode(QListView::Fixed);
|
|
setStyleSheet("");
|
|
}
|
|
|
|
QResizeEvent event(size(), size());
|
|
resizeEvent(&event);
|
|
}
|
|
|
|
bool SceneTree::GetGridMode()
|
|
{
|
|
return gridMode;
|
|
}
|
|
|
|
void SceneTree::SetGridItemWidth(int width)
|
|
{
|
|
maxWidth = width;
|
|
}
|
|
|
|
void SceneTree::SetGridItemHeight(int height)
|
|
{
|
|
itemHeight = height;
|
|
}
|
|
|
|
int SceneTree::GetGridItemWidth()
|
|
{
|
|
return maxWidth;
|
|
}
|
|
|
|
int SceneTree::GetGridItemHeight()
|
|
{
|
|
return itemHeight;
|
|
}
|
|
|
|
bool SceneTree::eventFilter(QObject *obj, QEvent *event)
|
|
{
|
|
return QObject::eventFilter(obj, event);
|
|
}
|
|
|
|
void SceneTree::resizeEvent(QResizeEvent *event)
|
|
{
|
|
if (gridMode) {
|
|
int scrollWid = verticalScrollBar()->sizeHint().width();
|
|
const QRect lastItem = visualItemRect(item(count() - 1));
|
|
const int h = lastItem.y() + lastItem.height();
|
|
|
|
if (h < height()) {
|
|
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
|
scrollWid = 0;
|
|
} else {
|
|
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
|
|
}
|
|
|
|
int wid = contentsRect().width() - scrollWid - 1;
|
|
int items = (int)ceil((float)wid / maxWidth);
|
|
int itemWidth = wid / items;
|
|
|
|
setGridSize(QSize(itemWidth, itemHeight));
|
|
|
|
for (int i = 0; i < count(); i++) {
|
|
item(i)->setSizeHint(QSize(itemWidth, itemHeight));
|
|
}
|
|
} else {
|
|
setGridSize(QSize());
|
|
setSpacing(0);
|
|
for (int i = 0; i < count(); i++) {
|
|
item(i)->setData(Qt::SizeHintRole, QVariant());
|
|
}
|
|
}
|
|
|
|
QListWidget::resizeEvent(event);
|
|
}
|
|
|
|
void SceneTree::startDrag(Qt::DropActions supportedActions)
|
|
{
|
|
QListWidget::startDrag(supportedActions);
|
|
}
|
|
|
|
void SceneTree::dropEvent(QDropEvent *event)
|
|
{
|
|
if (event->source() != this) {
|
|
QListWidget::dropEvent(event);
|
|
return;
|
|
}
|
|
|
|
if (gridMode) {
|
|
int scrollWid = verticalScrollBar()->sizeHint().width();
|
|
const QRect firstItem = visualItemRect(item(0));
|
|
const QRect lastItem = visualItemRect(item(count() - 1));
|
|
const int h = lastItem.y() + lastItem.height();
|
|
const int firstItemY = abs(firstItem.y());
|
|
|
|
if (h < height()) {
|
|
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
|
scrollWid = 0;
|
|
} else {
|
|
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
|
|
}
|
|
|
|
float wid = contentsRect().width() - scrollWid - 1;
|
|
|
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
|
QPoint point = event->position().toPoint();
|
|
#else
|
|
QPoint point = event->pos();
|
|
#endif
|
|
|
|
int x = (float)point.x() / wid * ceil(wid / maxWidth);
|
|
int y = (point.y() + firstItemY) / itemHeight;
|
|
|
|
int r = x + y * ceil(wid / maxWidth);
|
|
|
|
QListWidgetItem *item = takeItem(selectedIndexes()[0].row());
|
|
insertItem(r, item);
|
|
setCurrentItem(item);
|
|
resize(size());
|
|
}
|
|
|
|
QListWidget::dropEvent(event);
|
|
|
|
// We must call resizeEvent to correctly place all grid items.
|
|
// We also do this in rowsInserted.
|
|
QResizeEvent resEvent(size(), size());
|
|
SceneTree::resizeEvent(&resEvent);
|
|
|
|
QTimer::singleShot(100, [this]() { emit scenesReordered(); });
|
|
}
|
|
|
|
void SceneTree::RepositionGrid(QDragMoveEvent *event)
|
|
{
|
|
int scrollWid = verticalScrollBar()->sizeHint().width();
|
|
const QRect firstItem = visualItemRect(item(0));
|
|
const QRect lastItem = visualItemRect(item(count() - 1));
|
|
const int h = lastItem.y() + lastItem.height();
|
|
const int firstItemY = abs(firstItem.y());
|
|
|
|
if (h < height()) {
|
|
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
|
scrollWid = 0;
|
|
} else {
|
|
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
|
|
}
|
|
|
|
float wid = contentsRect().width() - scrollWid - 1;
|
|
|
|
if (event) {
|
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
|
QPoint point = event->position().toPoint();
|
|
#else
|
|
QPoint point = event->pos();
|
|
#endif
|
|
|
|
int x = (float)point.x() / wid * ceil(wid / maxWidth);
|
|
int y = (point.y() + firstItemY) / itemHeight;
|
|
|
|
int r = x + y * ceil(wid / maxWidth);
|
|
int orig = selectedIndexes()[0].row();
|
|
|
|
for (int i = 0; i < count(); i++) {
|
|
auto *wItem = item(i);
|
|
|
|
if (wItem->isSelected())
|
|
continue;
|
|
|
|
QModelIndex index = indexFromItem(wItem);
|
|
|
|
int off = (i >= r ? 1 : 0) -
|
|
(i > orig && i > r ? 1 : 0) -
|
|
(i > orig && i == r ? 2 : 0);
|
|
|
|
int xPos = (i + off) % (int)ceil(wid / maxWidth);
|
|
int yPos = (i + off) / (int)ceil(wid / maxWidth);
|
|
QSize g = gridSize();
|
|
|
|
QPoint position(xPos * g.width(), yPos * g.height());
|
|
setPositionForIndex(position, index);
|
|
}
|
|
} else {
|
|
for (int i = 0; i < count(); i++) {
|
|
auto *wItem = item(i);
|
|
|
|
if (wItem->isSelected())
|
|
continue;
|
|
|
|
QModelIndex index = indexFromItem(wItem);
|
|
|
|
int xPos = i % (int)ceil(wid / maxWidth);
|
|
int yPos = i / (int)ceil(wid / maxWidth);
|
|
QSize g = gridSize();
|
|
|
|
QPoint position(xPos * g.width(), yPos * g.height());
|
|
setPositionForIndex(position, index);
|
|
}
|
|
}
|
|
}
|
|
|
|
void SceneTree::dragMoveEvent(QDragMoveEvent *event)
|
|
{
|
|
if (gridMode) {
|
|
RepositionGrid(event);
|
|
}
|
|
|
|
QListWidget::dragMoveEvent(event);
|
|
}
|
|
|
|
void SceneTree::dragLeaveEvent(QDragLeaveEvent *event)
|
|
{
|
|
if (gridMode) {
|
|
RepositionGrid();
|
|
}
|
|
|
|
QListWidget::dragLeaveEvent(event);
|
|
}
|
|
|
|
void SceneTree::rowsInserted(const QModelIndex &parent, int start, int end)
|
|
{
|
|
QResizeEvent event(size(), size());
|
|
SceneTree::resizeEvent(&event);
|
|
|
|
QListWidget::rowsInserted(parent, start, end);
|
|
}
|
|
|
|
// Workaround for QTBUG-105870. Remove once that is solved upstream.
|
|
void SceneTree::selectionChanged(const QItemSelection &selected,
|
|
const QItemSelection &deselected)
|
|
{
|
|
if (selected.count() == 0)
|
|
setCurrentRow(deselected.indexes().front().row());
|
|
}
|