diff --git a/UI/CMakeLists.txt b/UI/CMakeLists.txt
index 1b244abb8..f41448831 100644
--- a/UI/CMakeLists.txt
+++ b/UI/CMakeLists.txt
@@ -236,6 +236,7 @@ set(obs_UI
forms/AutoConfigVideoPage.ui
forms/AutoConfigStreamPage.ui
forms/AutoConfigTestPage.ui
+ forms/ColorSelect.ui
forms/OBSLicenseAgreement.ui
forms/OBSLogReply.ui
forms/OBSBasic.ui
diff --git a/UI/data/locale/en-US.ini b/UI/data/locale/en-US.ini
index 4c594c880..8a7bb1996 100644
--- a/UI/data/locale/en-US.ini
+++ b/UI/data/locale/en-US.ini
@@ -850,3 +850,7 @@ FinalScene.Text="There needs to be at least one scene."
NoSources.Title="No Sources"
NoSources.Text="It looks like you haven't added any video sources yet, so you will only be outputting a blank screen. Are you sure you want to do this?"
NoSources.Text.AddSource="You can add sources by clicking the + icon under the Sources box in the main window at any time."
+
+# Scene item color selection
+ChangeBG="Set Color"
+CustomColor="Custom Color"
diff --git a/UI/forms/ColorSelect.ui b/UI/forms/ColorSelect.ui
new file mode 100644
index 000000000..b07e1f968
--- /dev/null
+++ b/UI/forms/ColorSelect.ui
@@ -0,0 +1,265 @@
+
+
+ ColorSelect
+
+
+
+ 0
+ 0
+ 98
+ 61
+
+
+
+
+ 0
+ 0
+
+
+
+ Form
+
+
+ QPushButton {
+ border: 1px solid black;
+}
+
+
+ -
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 16
+ 16
+
+
+
+
+ 16
+ 16
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 16
+ 16
+
+
+
+
+ 16
+ 16
+
+
+
+
+
+
+ 2
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 16
+ 16
+
+
+
+
+ 16
+ 16
+
+
+
+
+
+
+ 3
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 16
+ 16
+
+
+
+
+ 16
+ 16
+
+
+
+
+
+
+ 4
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 16
+ 16
+
+
+
+
+ 16
+ 16
+
+
+
+
+
+
+ 5
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 16
+ 16
+
+
+
+
+ 16
+ 16
+
+
+
+
+
+
+ 6
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 16
+ 16
+
+
+
+
+ 16
+ 16
+
+
+
+
+
+
+ 7
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 16
+ 16
+
+
+
+
+ 16
+ 16
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/UI/source-tree.cpp b/UI/source-tree.cpp
index 87443bc06..20dfd5bb3 100644
--- a/UI/source-tree.cpp
+++ b/UI/source-tree.cpp
@@ -39,6 +39,23 @@ SourceTreeItem::SourceTreeItem(SourceTree *tree_, OBSSceneItem sceneitem_)
obs_source_t *source = obs_sceneitem_get_source(sceneitem);
const char *name = obs_source_get_name(source);
+ obs_data_t *privData = obs_sceneitem_get_private_settings(sceneitem);
+ int preset = obs_data_get_int(privData, "color-preset");
+
+ if (preset == 1) {
+ const char *color = obs_data_get_string(privData, "color");
+ std::string col = "background: ";
+ col += color;
+ setStyleSheet(col.c_str());
+ } else if (preset > 1) {
+ setStyleSheet("");
+ setProperty("bgColor", preset - 1);
+ } else {
+ setStyleSheet("background: none");
+ }
+
+ obs_data_release(privData);
+
vis = new VisibilityCheckBox();
vis->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
vis->setMaximumSize(16, 16);
@@ -88,6 +105,16 @@ SourceTreeItem::SourceTreeItem(SourceTree *tree_, OBSSceneItem sceneitem_)
connect(lock, &QAbstractButton::clicked, setItemLocked);
}
+void SourceTreeItem::paintEvent(QPaintEvent *event)
+{
+ QStyleOption opt;
+ opt.init(this);
+ QPainter p(this);
+ style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
+
+ QWidget::paintEvent(event);
+}
+
void SourceTreeItem::DisconnectSignals()
{
sceneRemoveSignal.Disconnect();
@@ -836,6 +863,15 @@ SourceTree::SourceTree(QWidget *parent_) : QListView(parent_)
{
SourceTreeModel *stm_ = new SourceTreeModel(this);
setModel(stm_);
+ setStyleSheet(QString(
+ "*[bgColor=\"1\"]{background-color:rgba(255,68,68,33%);}" \
+ "*[bgColor=\"2\"]{background-color:rgba(255,255,68,33%);}" \
+ "*[bgColor=\"3\"]{background-color:rgba(68,255,68,33%);}" \
+ "*[bgColor=\"4\"]{background-color:rgba(68,255,255,33%);}" \
+ "*[bgColor=\"5\"]{background-color:rgba(68,68,255,33%);}" \
+ "*[bgColor=\"6\"]{background-color:rgba(255,68,255,33%);}" \
+ "*[bgColor=\"7\"]{background-color:rgba(68,68,68,33%);}" \
+ "*[bgColor=\"8\"]{background-color:rgba(255,255,255,33%);}"));
}
void SourceTree::ResetWidgets()
diff --git a/UI/source-tree.hpp b/UI/source-tree.hpp
index a5c441f09..452654915 100644
--- a/UI/source-tree.hpp
+++ b/UI/source-tree.hpp
@@ -67,6 +67,8 @@ private:
OBSSignal renameSignal;
OBSSignal removeSignal;
+ virtual void paintEvent(QPaintEvent* event) override;
+
private slots:
void EnterEditMode();
void ExitEditMode(bool save);
@@ -134,13 +136,13 @@ class SourceTree : public QListView {
return reinterpret_cast(model());
}
+public:
inline SourceTreeItem *GetItemWidget(int idx)
{
QWidget *widget = indexWidget(GetStm()->createIndex(idx, 0));
return reinterpret_cast(widget);
}
-public:
explicit SourceTree(QWidget *parent = nullptr);
inline bool IgnoreReorder() const {return ignoreReorder;}
diff --git a/UI/window-basic-main.cpp b/UI/window-basic-main.cpp
index f71a20346..9487c921f 100644
--- a/UI/window-basic-main.cpp
+++ b/UI/window-basic-main.cpp
@@ -27,6 +27,9 @@
#include
#include
#include
+#include
+#include
+#include
#include
#include
@@ -61,6 +64,7 @@
#endif
#include "ui_OBSBasic.h"
+#include "ui_ColorSelect.h"
#include
#include
@@ -3959,6 +3963,63 @@ QMenu *OBSBasic::AddScaleFilteringMenu(obs_sceneitem_t *item)
return menu;
}
+QMenu *OBSBasic::AddBackgroundColorMenu(obs_sceneitem_t *item)
+{
+ QMenu *menu = new QMenu(QTStr("ChangeBG"));
+ QAction *action;
+
+ menu->setStyleSheet(QString(
+ "*[bgColor=\"1\"]{background-color:rgba(255,68,68,33%);}" \
+ "*[bgColor=\"2\"]{background-color:rgba(255,255,68,33%);}" \
+ "*[bgColor=\"3\"]{background-color:rgba(68,255,68,33%);}" \
+ "*[bgColor=\"4\"]{background-color:rgba(68,255,255,33%);}" \
+ "*[bgColor=\"5\"]{background-color:rgba(68,68,255,33%);}" \
+ "*[bgColor=\"6\"]{background-color:rgba(255,68,255,33%);}" \
+ "*[bgColor=\"7\"]{background-color:rgba(68,68,68,33%);}" \
+ "*[bgColor=\"8\"]{background-color:rgba(255,255,255,33%);}"));
+
+ obs_data_t *privData = obs_sceneitem_get_private_settings(item);
+ obs_data_release(privData);
+
+ obs_data_set_default_int(privData, "color-preset", 0);
+ int preset = obs_data_get_int(privData, "color-preset");
+
+ action = menu->addAction(QTStr("Clear"), this,
+ + SLOT(ColorChange()));
+ action->setCheckable(true);
+ action->setProperty("bgColor", 0);
+ action->setChecked(preset == 0);
+
+ action = menu->addAction(QTStr("CustomColor"), this,
+ + SLOT(ColorChange()));
+ action->setCheckable(true);
+ action->setProperty("bgColor", 1);
+ action->setChecked(preset == 1);
+
+ menu->addSeparator();
+
+ QWidgetAction *widgetAction = new QWidgetAction(menu);
+ ColorSelect *select = new ColorSelect(menu);
+ widgetAction->setDefaultWidget(select);
+
+ for (int i = 1; i < 9; i++) {
+ stringstream button;
+ button << "preset" << i;
+ QPushButton *colorButton = select->findChild(
+ button.str().c_str());
+ if (preset == i + 1)
+ colorButton->setStyleSheet("border: 2px solid black");
+
+ colorButton->setProperty("bgColor", i);
+ select->connect(colorButton, SIGNAL(released()), this,
+ SLOT(ColorChange()));
+ }
+
+ menu->addAction(widgetAction);
+
+ return menu;
+}
+
void OBSBasic::CreateSourcePopupMenu(int idx, bool preview)
{
QMenu popup(this);
@@ -4035,6 +4096,7 @@ void OBSBasic::CreateSourcePopupMenu(int idx, bool preview)
OBS_SOURCE_AUDIO;
QAction *action;
+ popup.addMenu(AddBackgroundColorMenu(sceneItem));
popup.addAction(QTStr("Rename"), this,
SLOT(EditSceneItemName()));
popup.addAction(QTStr("Remove"), this,
@@ -6327,6 +6389,180 @@ void OBSBasic::on_actionPasteFilters_triggered()
obs_source_copy_filters(dstSource, source);
}
+static void ConfirmColor(SourceTree *sources, const QColor &color,
+ QModelIndexList selectedItems)
+{
+ for (int x = 0; x < selectedItems.count(); x++) {
+ SourceTreeItem *treeItem = sources
+ ->GetItemWidget(selectedItems[x].row());
+ treeItem->setStyleSheet("background: "
+ + color.name(QColor::HexArgb));
+ treeItem->style()->unpolish(treeItem);
+ treeItem->style()->polish(treeItem);
+
+ OBSSceneItem sceneItem = sources->Get(
+ selectedItems[x].row());
+ obs_data_t *privData =
+ obs_sceneitem_get_private_settings(sceneItem);
+ obs_data_set_int(privData, "color-preset", 1);
+ obs_data_set_string(privData, "color",
+ QT_TO_UTF8(color.name(
+ QColor::HexArgb)));
+ obs_data_release(privData);
+ }
+}
+
+void OBSBasic::ColorChange()
+{
+ QModelIndexList selectedItems =
+ ui->sources->selectionModel()->selectedIndexes();
+ QAction *action = qobject_cast(sender());
+ QPushButton *colorButton = qobject_cast(sender());
+
+ if (selectedItems.count() == 0)
+ return;
+
+ if (colorButton) {
+ int preset = colorButton->property("bgColor").value();
+
+ for (int x = 0; x < selectedItems.count(); x++) {
+ SourceTreeItem *treeItem = ui->sources
+ ->GetItemWidget(selectedItems[x].row());
+ treeItem->setStyleSheet("");
+ treeItem->setProperty("bgColor", preset);
+ treeItem->style()->unpolish(treeItem);
+ treeItem->style()->polish(treeItem);
+
+ OBSSceneItem sceneItem = ui->sources->Get(
+ selectedItems[x].row());
+ obs_data_t *privData =
+ obs_sceneitem_get_private_settings(sceneItem);
+ obs_data_set_int(privData, "color-preset", preset + 1);
+ obs_data_set_string(privData, "color", "");
+ obs_data_release(privData);
+ }
+
+ for (int i = 1; i < 9; i++) {
+ stringstream button;
+ button << "preset" << i;
+ QPushButton *cButton = colorButton->parentWidget()
+ ->findChild(button.str().c_str());
+ cButton->setStyleSheet("border: 1px solid black");
+ }
+
+ colorButton->setStyleSheet("border: 2px solid black");
+ } else if (action) {
+ int preset = action->property("bgColor").value();
+
+ if (preset == 1) {
+ OBSSceneItem curSceneItem = GetCurrentSceneItem();
+ SourceTreeItem *curTreeItem =
+ GetItemWidgetFromSceneItem(curSceneItem);
+ obs_data_t *curPrivData =
+ obs_sceneitem_get_private_settings(curSceneItem);
+
+ int oldPreset = obs_data_get_int(
+ curPrivData, "color-preset");
+ const QString oldSheet = curTreeItem->styleSheet();
+
+ auto liveChangeColor = [=](const QColor &color) {
+ if (color.isValid()) {
+ curTreeItem->setStyleSheet(
+ "background: "
+ + color.name(QColor::HexArgb));
+ }
+ };
+
+ auto changedColor = [=](const QColor &color) {
+ if (color.isValid()) {
+ ConfirmColor(ui->sources, color,
+ selectedItems);
+ }
+ };
+
+ auto rejected = [=]() {
+ if (oldPreset == 1) {
+ curTreeItem->setStyleSheet(oldSheet);
+ curTreeItem->setProperty("bgColor", 0);
+ } else if (oldPreset == 0) {
+ curTreeItem->setStyleSheet(
+ "background: none");
+ curTreeItem->setProperty("bgColor", 0);
+ } else {
+ curTreeItem->setStyleSheet("");
+ curTreeItem->setProperty("bgColor",
+ oldPreset - 1);
+ }
+
+ curTreeItem->style()->unpolish(curTreeItem);
+ curTreeItem->style()->polish(curTreeItem);
+ };
+
+ QColorDialog::ColorDialogOptions options =
+ QColorDialog::ShowAlphaChannel;
+
+ const char *oldColor = obs_data_get_string(curPrivData,
+ "color");
+ const char *customColor = *oldColor != 0 ? oldColor
+ : "#55FF0000";
+#ifdef __APPLE__
+ options |= QColorDialog::DontUseNativeDialog;
+#endif
+
+ QColorDialog *colorDialog = new QColorDialog(this);
+ colorDialog->setOptions(options);
+ colorDialog->setCurrentColor(
+ QColor(customColor));
+ connect(colorDialog, &QColorDialog::currentColorChanged,
+ liveChangeColor);
+ connect(colorDialog, &QColorDialog::colorSelected,
+ changedColor);
+ connect(colorDialog, &QColorDialog::rejected,
+ rejected);
+ colorDialog->open();
+
+ obs_data_release(curPrivData);
+ } else {
+ for (int x = 0; x < selectedItems.count(); x++) {
+ SourceTreeItem *treeItem = ui->sources
+ ->GetItemWidget(selectedItems[x].row());
+ treeItem->setStyleSheet("background: none");
+ treeItem->setProperty("bgColor", preset);
+ treeItem->style()->unpolish(treeItem);
+ treeItem->style()->polish(treeItem);
+
+ OBSSceneItem sceneItem = ui->sources->Get(
+ selectedItems[x].row());
+ obs_data_t *privData =
+ obs_sceneitem_get_private_settings(
+ sceneItem);
+ obs_data_set_int(privData, "color-preset",
+ preset);
+ obs_data_set_string(privData, "color", "");
+ obs_data_release(privData);
+ }
+ }
+ }
+}
+
+SourceTreeItem *OBSBasic::GetItemWidgetFromSceneItem(
+ obs_sceneitem_t *sceneItem)
+{
+ int i = 0;
+ SourceTreeItem *treeItem = ui->sources->GetItemWidget(i);
+ OBSSceneItem item = ui->sources->Get(i);
+ int64_t id = obs_sceneitem_get_id(sceneItem);
+ while (treeItem && obs_sceneitem_get_id(item) != id) {
+ i++;
+ treeItem = ui->sources->GetItemWidget(i);
+ item = ui->sources->Get(i);
+ }
+ if(treeItem)
+ return treeItem;
+
+ return nullptr;
+}
+
void OBSBasic::on_autoConfigure_triggered()
{
AutoConfig test(this);
@@ -6348,3 +6584,10 @@ void OBSBasic::on_stats_triggered()
statsDlg->show();
stats = statsDlg;
}
+
+ColorSelect::ColorSelect(QWidget *parent)
+ : QWidget(parent),
+ ui(new Ui::ColorSelect)
+{
+ ui->setupUi(this);
+}
diff --git a/UI/window-basic-main.hpp b/UI/window-basic-main.hpp
index 29f33b587..a5dbff07e 100644
--- a/UI/window-basic-main.hpp
+++ b/UI/window-basic-main.hpp
@@ -46,6 +46,7 @@ class QNetworkReply;
class OBSBasicStats;
#include "ui_OBSBasic.h"
+#include "ui_ColorSelect.h"
#define DESKTOP_AUDIO_1 Str("DesktopAudioDevice1")
#define DESKTOP_AUDIO_2 Str("DesktopAudioDevice2")
@@ -473,6 +474,10 @@ private slots:
void on_actionCopyFilters_triggered();
void on_actionPasteFilters_triggered();
+ void ColorChange();
+
+ SourceTreeItem *GetItemWidgetFromSceneItem(obs_sceneitem_t *sceneItem);
+
private:
/* OBS Callbacks */
static void SceneReordered(void *data, calldata_t *params);
@@ -563,6 +568,7 @@ public:
QMenu *AddDeinterlacingMenu(obs_source_t *source);
QMenu *AddScaleFilteringMenu(obs_sceneitem_t *item);
+ QMenu *AddBackgroundColorMenu(obs_sceneitem_t *item);
void CreateSourcePopupMenu(int idx, bool preview);
void UpdateTitleBar();
@@ -745,3 +751,12 @@ public:
private:
std::unique_ptr ui;
};
+
+class ColorSelect : public QWidget {
+
+public:
+ explicit ColorSelect(QWidget *parent = 0);
+
+private:
+ std::unique_ptr ui;
+};