Merge pull request #2211 from VodBox/scene-grid-mode

UI: Add Grid Mode to Scenes Widget
This commit is contained in:
Jim 2019-12-10 14:57:26 -08:00 committed by GitHub
commit bcddf4ddbf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 345 additions and 2 deletions

View File

@ -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

View File

@ -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"

View 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;
}

View File

@ -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 */
}

View File

@ -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;
}

View File

@ -233,3 +233,10 @@ QListWidget::item,
SourceTree::item {
height: 24px;
}
/* Scene Tree */
SceneTree {
qproperty-gridItemWidth: 150;
qproperty-gridItemHeight: 24;
}

View File

@ -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
View 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
View 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;
};

View File

@ -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;

View File

@ -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();