obs-studio/UI/scene-tree.cpp

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(1);
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 && deselected.count() > 0)
setCurrentRow(deselected.indexes().front().row());
}