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