Merge pull request #2211 from VodBox/scene-grid-mode
UI: Add Grid Mode to Scenes Widget
This commit is contained in:
commit
bcddf4ddbf
@ -236,6 +236,7 @@ set(obs_SOURCES
|
||||
window-remux.cpp
|
||||
auth-base.cpp
|
||||
source-tree.cpp
|
||||
scene-tree.cpp
|
||||
properties-view.cpp
|
||||
focus-list.cpp
|
||||
menu-button.cpp
|
||||
@ -288,6 +289,7 @@ set(obs_HEADERS
|
||||
window-remux.hpp
|
||||
auth-base.hpp
|
||||
source-tree.hpp
|
||||
scene-tree.hpp
|
||||
properties-view.hpp
|
||||
properties-view.moc.hpp
|
||||
display-helpers.hpp
|
||||
|
@ -530,6 +530,8 @@ Basic.Main.ForceStopStreaming="Stop Streaming (discard delay)"
|
||||
Basic.Main.Group="Group %1"
|
||||
Basic.Main.GroupItems="Group Selected Items"
|
||||
Basic.Main.Ungroup="Ungroup"
|
||||
Basic.Main.GridMode="Grid Mode"
|
||||
Basic.Main.ListMode="List Mode"
|
||||
|
||||
# basic mode file menu
|
||||
Basic.MainMenu.File="&File"
|
||||
|
@ -1022,3 +1022,25 @@ OBSBasic {
|
||||
qproperty-sceneIcon: url(./Dark/sources/scene.svg);
|
||||
qproperty-defaultIcon: url(./Dark/sources/default.svg);
|
||||
}
|
||||
|
||||
/* Scene Tree */
|
||||
|
||||
SceneTree#scenes {
|
||||
qproperty-gridItemWidth: 180;
|
||||
qproperty-gridItemHeight: 35;
|
||||
}
|
||||
|
||||
*[gridMode="true"] SceneTree#scenes {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
*[gridMode="false"] SceneTree#scenes {
|
||||
border-bottom: 2px solid #2f2f2f;
|
||||
}
|
||||
|
||||
*[gridMode="true"] SceneTree::item {
|
||||
padding: 4px;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
margin: 0px;
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
|
||||
/* GNU General Public License for more details. */
|
||||
/* */
|
||||
/* */
|
||||
/* You should have received a copy of the GNU General Public License */
|
||||
/* along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
/******************************************************************************/
|
||||
@ -774,3 +775,37 @@ OBSBasic {
|
||||
qproperty-sceneIcon: url(./Dark/sources/scene.svg);
|
||||
qproperty-defaultIcon: url(./Dark/sources/default.svg);
|
||||
}
|
||||
|
||||
/* Scene Tree */
|
||||
|
||||
SceneTree {
|
||||
qproperty-gridItemWidth: 150;
|
||||
qproperty-gridItemHeight: 27;
|
||||
}
|
||||
|
||||
*[gridMode="true"] SceneTree::item {
|
||||
color: rgb(225,224,225); /* veryLight */
|
||||
background-color: rgb(76,76,76);
|
||||
border: none;
|
||||
border-radius: 3px;
|
||||
padding: 4px;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
margin: 1px;
|
||||
}
|
||||
|
||||
*[gridMode="true"] SceneTree::item:selected {
|
||||
background-color: rgb(122,121,122); /* light */
|
||||
}
|
||||
|
||||
*[gridMode="true"] SceneTree::item:hover {
|
||||
background-color: rgb(122,121,122); /* light */
|
||||
}
|
||||
|
||||
*[gridMode="true"] SceneTree::item:pressed {
|
||||
background-color: rgb(31,30,31); /* veryDark */
|
||||
}
|
||||
|
||||
*[gridMode="true"] SceneTree::item:checked {
|
||||
background-color: rgb(122,121,122); /* light */
|
||||
}
|
||||
|
@ -1365,3 +1365,10 @@ OBSBasic {
|
||||
qproperty-sceneIcon: url(./Dark/sources/scene.svg);
|
||||
qproperty-defaultIcon: url(./Dark/sources/default.svg);
|
||||
}
|
||||
|
||||
/* Scene Tree */
|
||||
|
||||
SceneTree#scenes {
|
||||
qproperty-gridItemWidth: 150;
|
||||
qproperty-gridItemHeight: 30;
|
||||
}
|
||||
|
@ -233,3 +233,10 @@ QListWidget::item,
|
||||
SourceTree::item {
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
/* Scene Tree */
|
||||
|
||||
SceneTree {
|
||||
qproperty-gridItemWidth: 150;
|
||||
qproperty-gridItemHeight: 24;
|
||||
}
|
||||
|
@ -474,7 +474,7 @@
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QListWidget" name="scenes">
|
||||
<widget class="SceneTree" name="scenes">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
@ -1818,6 +1818,11 @@
|
||||
<extends>QListView</extends>
|
||||
<header>source-tree.hpp</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>SceneTree</class>
|
||||
<extends>QListWidget</extends>
|
||||
<header>scene-tree.hpp</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>OBSDock</class>
|
||||
<extends>QDockWidget</extends>
|
||||
|
188
UI/scene-tree.cpp
Normal file
188
UI/scene-tree.cpp
Normal file
@ -0,0 +1,188 @@
|
||||
#include "obs.hpp"
|
||||
#include "scene-tree.hpp"
|
||||
#include "obs-app.hpp"
|
||||
|
||||
#include <QSizePolicy>
|
||||
#include <QScrollBar>
|
||||
#include <QDropEvent>
|
||||
#include <QPushButton>
|
||||
|
||||
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("");
|
||||
}
|
||||
|
||||
resizeEvent(new QResizeEvent(size(), size()));
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
QListWidget::resizeEvent(event);
|
||||
|
||||
if (gridMode) {
|
||||
int scrollWid = verticalScrollBar()->sizeHint().width();
|
||||
int h = visualItemRect(item(count() - 1)).bottom();
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SceneTree::startDrag(Qt::DropActions supportedActions)
|
||||
{
|
||||
QListWidget::startDrag(supportedActions);
|
||||
}
|
||||
|
||||
void SceneTree::dropEvent(QDropEvent *event)
|
||||
{
|
||||
QListWidget::dropEvent(event);
|
||||
if (event->source() == this && gridMode) {
|
||||
int scrollWid = verticalScrollBar()->sizeHint().width();
|
||||
int h = visualItemRect(item(count() - 1)).bottom();
|
||||
|
||||
if (h < height()) {
|
||||
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
scrollWid = 0;
|
||||
} else {
|
||||
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
|
||||
}
|
||||
|
||||
float wid = contentsRect().width() - scrollWid - 1;
|
||||
|
||||
QPoint point = event->pos();
|
||||
|
||||
int x = (float)point.x() / wid * ceil(wid / maxWidth);
|
||||
int y = point.y() / itemHeight;
|
||||
|
||||
int r = x + y * ceil(wid / maxWidth);
|
||||
|
||||
QListWidgetItem *item = takeItem(selectedIndexes()[0].row());
|
||||
insertItem(r, item);
|
||||
setCurrentItem(item);
|
||||
resize(size());
|
||||
}
|
||||
}
|
||||
|
||||
void SceneTree::dragMoveEvent(QDragMoveEvent *event)
|
||||
{
|
||||
if (gridMode) {
|
||||
int scrollWid = verticalScrollBar()->sizeHint().width();
|
||||
int h = visualItemRect(item(count() - 1)).bottom();
|
||||
|
||||
if (h < height()) {
|
||||
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
scrollWid = 0;
|
||||
} else {
|
||||
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
|
||||
}
|
||||
|
||||
float wid = contentsRect().width() - scrollWid - 1;
|
||||
|
||||
QPoint point = event->pos();
|
||||
|
||||
int x = (float)point.x() / wid * ceil(wid / maxWidth);
|
||||
int y = point.y() / 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 {
|
||||
QListWidget::dragMoveEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
void SceneTree::rowsInserted(const QModelIndex &parent, int start, int end)
|
||||
{
|
||||
QListWidget::rowsInserted(parent, start, end);
|
||||
|
||||
QResizeEvent *event = new QResizeEvent(size(), size());
|
||||
SceneTree::resizeEvent(event);
|
||||
}
|
37
UI/scene-tree.hpp
Normal file
37
UI/scene-tree.hpp
Normal file
@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include <QListWidget>
|
||||
#include <QEvent>
|
||||
#include <QItemDelegate>
|
||||
|
||||
class SceneTree : public QListWidget {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int gridItemWidth READ GetGridItemWidth WRITE
|
||||
SetGridItemWidth DESIGNABLE true)
|
||||
Q_PROPERTY(int gridItemHeight READ GetGridItemHeight WRITE
|
||||
SetGridItemHeight DESIGNABLE true)
|
||||
|
||||
bool gridMode = false;
|
||||
int maxWidth = 150;
|
||||
int itemHeight = 24;
|
||||
|
||||
public:
|
||||
void SetGridMode(bool grid);
|
||||
bool GetGridMode();
|
||||
|
||||
void SetGridItemWidth(int width);
|
||||
void SetGridItemHeight(int height);
|
||||
int GetGridItemWidth();
|
||||
int GetGridItemHeight();
|
||||
|
||||
explicit SceneTree(QWidget *parent = nullptr);
|
||||
|
||||
protected:
|
||||
virtual bool eventFilter(QObject *obj, QEvent *event) override;
|
||||
virtual void resizeEvent(QResizeEvent *event) override;
|
||||
virtual void startDrag(Qt::DropActions supportedActions) override;
|
||||
virtual void dropEvent(QDropEvent *event) override;
|
||||
virtual void dragMoveEvent(QDragMoveEvent *event) override;
|
||||
virtual void rowsInserted(const QModelIndex &parent, int start,
|
||||
int end) override;
|
||||
};
|
@ -28,6 +28,7 @@
|
||||
#include <QScreen>
|
||||
#include <QColorDialog>
|
||||
#include <QSizePolicy>
|
||||
#include <QScrollBar>
|
||||
|
||||
#include <util/dstr.h>
|
||||
#include <util/util.hpp>
|
||||
@ -94,7 +95,6 @@ template<typename OBSRef> struct SignalContainer {
|
||||
OBSRef ref;
|
||||
vector<shared_ptr<OBSSignal>> handlers;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
extern volatile long insideEventLoop;
|
||||
@ -105,6 +105,18 @@ Q_DECLARE_METATYPE(OBSSource);
|
||||
Q_DECLARE_METATYPE(obs_order_movement);
|
||||
Q_DECLARE_METATYPE(SignalContainer<OBSScene>);
|
||||
|
||||
QDataStream &operator<<(QDataStream &out, const SignalContainer<OBSScene> &v)
|
||||
{
|
||||
out << v.ref;
|
||||
return out;
|
||||
}
|
||||
|
||||
QDataStream &operator>>(QDataStream &in, SignalContainer<OBSScene> &v)
|
||||
{
|
||||
in >> v.ref;
|
||||
return in;
|
||||
}
|
||||
|
||||
template<typename T> static T GetOBSRef(QListWidgetItem *item)
|
||||
{
|
||||
return item->data(static_cast<int>(QtDataRole::OBSRef)).value<T>();
|
||||
@ -195,6 +207,9 @@ extern void RegisterRestreamAuth();
|
||||
OBSBasic::OBSBasic(QWidget *parent)
|
||||
: OBSMainWindow(parent), ui(new Ui::OBSBasic)
|
||||
{
|
||||
qRegisterMetaTypeStreamOperators<SignalContainer<OBSScene>>(
|
||||
"SignalContainer<OBSScene>");
|
||||
|
||||
setAttribute(Qt::WA_NativeWindow);
|
||||
|
||||
#if TWITCH_ENABLED
|
||||
@ -252,6 +267,10 @@ OBSBasic::OBSBasic(QWidget *parent)
|
||||
ui->scenes->setAttribute(Qt::WA_MacShowFocusRect, false);
|
||||
ui->sources->setAttribute(Qt::WA_MacShowFocusRect, false);
|
||||
|
||||
bool sceneGrid = config_get_bool(App()->GlobalConfig(), "BasicWindow",
|
||||
"gridMode");
|
||||
ui->scenes->SetGridMode(sceneGrid);
|
||||
|
||||
ui->scenes->setItemDelegate(new SceneRenameDelegate(ui->scenes));
|
||||
|
||||
auto displayResize = [this]() {
|
||||
@ -4051,6 +4070,7 @@ void OBSBasic::on_scenes_customContextMenuRequested(const QPoint &pos)
|
||||
|
||||
QMenu popup(this);
|
||||
QMenu order(QTStr("Basic.MainMenu.Edit.Order"), this);
|
||||
|
||||
popup.addAction(QTStr("Add"), this,
|
||||
SLOT(on_actionAddScene_triggered()));
|
||||
|
||||
@ -4132,9 +4152,26 @@ void OBSBasic::on_scenes_customContextMenuRequested(const QPoint &pos)
|
||||
std::bind(showInMultiview, data));
|
||||
}
|
||||
|
||||
popup.addSeparator();
|
||||
|
||||
bool grid = ui->scenes->GetGridMode();
|
||||
|
||||
QAction *gridAction = new QAction(grid ? QTStr("Basic.Main.ListMode")
|
||||
: QTStr("Basic.Main.GridMode"),
|
||||
this);
|
||||
connect(gridAction, SIGNAL(triggered()), this,
|
||||
SLOT(on_actionGridMode_triggered()));
|
||||
popup.addAction(gridAction);
|
||||
|
||||
popup.exec(QCursor::pos());
|
||||
}
|
||||
|
||||
void OBSBasic::on_actionGridMode_triggered()
|
||||
{
|
||||
bool gridMode = !ui->scenes->GetGridMode();
|
||||
ui->scenes->SetGridMode(gridMode);
|
||||
}
|
||||
|
||||
void OBSBasic::on_actionAddScene_triggered()
|
||||
{
|
||||
string name;
|
||||
|
@ -816,6 +816,7 @@ private slots:
|
||||
void on_scenes_currentItemChanged(QListWidgetItem *current,
|
||||
QListWidgetItem *prev);
|
||||
void on_scenes_customContextMenuRequested(const QPoint &pos);
|
||||
void on_actionGridMode_triggered();
|
||||
void on_actionAddScene_triggered();
|
||||
void on_actionRemoveScene_triggered();
|
||||
void on_actionSceneUp_triggered();
|
||||
|
Loading…
x
Reference in New Issue
Block a user