vulcast-vertical/sources-dock.cpp
Vulcast 0e83ab9eef Initial import from Aitum/obs-vertical-canvas v1.6.4
Forked for Vulcast branding changes.
Licensed under GPL-2.0.
2026-06-29 22:58:49 +01:00

227 lines
8.3 KiB
C++

#include "sources-dock.hpp"
#include <QMenu>
#include <QMessageBox>
#include <QToolBar>
#include <QVBoxLayout>
#include "obs-module.h"
#include "vertical-canvas.hpp"
#include "name-dialog.hpp"
CanvasSourcesDock::CanvasSourcesDock(CanvasDock *canvas_dock, QWidget *parent) : QFrame(parent), canvasDock(canvas_dock)
{
setMinimumWidth(100);
setMinimumHeight(50);
auto mainLayout = new QVBoxLayout(this);
mainLayout->setContentsMargins(0, 0, 0, 0);
sourceList = new SourceTree(canvas_dock, this);
sourceList->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
sourceList->setFrameShape(QFrame::NoFrame);
sourceList->setFrameShadow(QFrame::Plain);
sourceList->setSelectionMode(QAbstractItemView::ExtendedSelection);
sourceList->setContextMenuPolicy(Qt::CustomContextMenu);
sourceList->setDropIndicatorShown(true);
sourceList->setDragEnabled(true);
sourceList->setDragDropMode(QAbstractItemView::InternalMove);
sourceList->setDefaultDropAction(Qt::TargetMoveAction);
connect(sourceList, &SourceTree::customContextMenuRequested, [this] { ShowSourcesContextMenu(GetCurrentSceneItem()); });
QAction *renameAction = new QAction(sourceList);
#ifdef __APPLE__
renameAction->setShortcut({Qt::Key_Return});
#else
renameAction->setShortcut({Qt::Key_F2});
#endif
renameAction->setShortcutContext(Qt::WidgetWithChildrenShortcut);
connect(renameAction, &QAction::triggered, [this]() {
obs_sceneitem_t *sceneItem = GetCurrentSceneItem();
if (!sceneItem)
return;
obs_source_t *source = obs_source_get_ref(obs_sceneitem_get_source(sceneItem));
if (!source)
return;
std::string name = obs_source_get_name(source);
obs_source_t *s = nullptr;
do {
obs_source_release(s);
if (!NameDialog::AskForName(this, QString::fromUtf8(obs_module_text("SourceName")), name)) {
break;
}
s = obs_canvas_get_source_by_name(canvasDock->canvas, name.c_str());
if (s)
continue;
obs_source_set_name(source, name.c_str());
} while (s);
obs_source_release(source);
});
sourceList->addAction(renameAction);
mainLayout->addWidget(sourceList, 1);
auto toolbar = new QToolBar();
toolbar->setObjectName(QStringLiteral("scenesToolbar"));
toolbar->setIconSize(QSize(16, 16));
toolbar->setFloatable(false);
auto a = toolbar->addAction(QIcon(QString::fromUtf8(":/res/images/plus.svg")),
QString::fromUtf8(obs_frontend_get_locale_string("AddSource")), [this] {
const auto menu = canvasDock->CreateAddSourcePopupMenu();
menu->exec(QCursor::pos());
});
toolbar->widgetForAction(a)->setProperty("themeID", QVariant(QString::fromUtf8("addIconSmall")));
toolbar->widgetForAction(a)->setProperty("class", "icon-plus");
a = toolbar->addAction(
QIcon(":/res/images/minus.svg"), QString::fromUtf8(obs_frontend_get_locale_string("RemoveSource")), [this] {
std::vector<OBSSceneItem> items;
obs_scene_enum_items(canvasDock->scene, selected_items, &items);
if (!items.size())
return;
/* ------------------------------------- */
/* confirm action with user */
bool confirmed = false;
if (items.size() > 1) {
QString text = QString::fromUtf8(obs_frontend_get_locale_string("ConfirmRemove.TextMultiple"))
.arg(QString::number(items.size()));
QMessageBox remove_items(this);
remove_items.setText(text);
QPushButton *Yes = remove_items.addButton(QString::fromUtf8(obs_frontend_get_locale_string("Yes")),
QMessageBox::YesRole);
remove_items.setDefaultButton(Yes);
remove_items.addButton(QString::fromUtf8(obs_frontend_get_locale_string("No")),
QMessageBox::NoRole);
remove_items.setIcon(QMessageBox::Question);
remove_items.setWindowTitle(
QString::fromUtf8(obs_frontend_get_locale_string("ConfirmRemove.Title")));
remove_items.exec();
confirmed = Yes == remove_items.clickedButton();
} else {
OBSSceneItem &item = items[0];
obs_source_t *source = obs_sceneitem_get_source(item);
if (source) {
const char *name = obs_source_get_name(source);
QString text = QString::fromUtf8(obs_frontend_get_locale_string("ConfirmRemove.Text"))
.arg(QString::fromUtf8(name));
QMessageBox remove_source(this);
remove_source.setText(text);
QPushButton *Yes = remove_source.addButton(
QString::fromUtf8(obs_frontend_get_locale_string("Yes")), QMessageBox::YesRole);
remove_source.setDefaultButton(Yes);
remove_source.addButton(QString::fromUtf8(obs_frontend_get_locale_string("No")),
QMessageBox::NoRole);
remove_source.setIcon(QMessageBox::Question);
remove_source.setWindowTitle(
QString::fromUtf8(obs_frontend_get_locale_string("ConfirmRemove.Title")));
remove_source.exec();
confirmed = Yes == remove_source.clickedButton();
}
}
if (!confirmed)
return;
/* ----------------------------------------------- */
/* remove items */
for (auto &item : items)
obs_sceneitem_remove(item);
});
toolbar->widgetForAction(a)->setProperty("themeID", QVariant(QString::fromUtf8("removeIconSmall")));
toolbar->widgetForAction(a)->setProperty("class", "icon-minus");
a->setShortcutContext(Qt::WidgetWithChildrenShortcut);
#ifdef __APPLE__
a->setShortcut({Qt::Key_Backspace});
#else
a->setShortcut({Qt::Key_Delete});
#endif
sourceList->addAction(a);
toolbar->addSeparator();
a = toolbar->addAction(QIcon(":/res/images/filter.svg"), QString::fromUtf8(obs_frontend_get_locale_string("SourceFilters")),
[this] {
auto item = GetCurrentSceneItem();
auto source = obs_sceneitem_get_source(item);
if (source)
obs_frontend_open_source_filters(source);
});
toolbar->widgetForAction(a)->setProperty("themeID", QVariant(QString::fromUtf8("filtersIcon")));
toolbar->widgetForAction(a)->setProperty("class", "icon-filter");
a = toolbar->addAction(QIcon(":/settings/images/settings/general.svg"),
QString::fromUtf8(obs_frontend_get_locale_string("SourceProperties")), [this] {
auto item = GetCurrentSceneItem();
auto source = obs_sceneitem_get_source(item);
if (source)
obs_frontend_open_source_properties(source);
});
toolbar->widgetForAction(a)->setProperty("themeID", QVariant(QString::fromUtf8("propertiesIconSmall")));
toolbar->widgetForAction(a)->setProperty("class", "icon-gear");
toolbar->addSeparator();
a = toolbar->addAction(QIcon(":/res/images/up.svg"), QString::fromUtf8(obs_frontend_get_locale_string("MoveSourceUp")),
[this] {
auto item = GetCurrentSceneItem();
obs_sceneitem_set_order(item, OBS_ORDER_MOVE_UP);
});
toolbar->widgetForAction(a)->setProperty("themeID", QVariant(QString::fromUtf8("upArrowIconSmall")));
toolbar->widgetForAction(a)->setProperty("class", "icon-up");
a = toolbar->addAction(QIcon(":/res/images/down.svg"), QString::fromUtf8(obs_frontend_get_locale_string("MoveSourceDown")),
[this] {
auto item = GetCurrentSceneItem();
obs_sceneitem_set_order(item, OBS_ORDER_MOVE_DOWN);
});
toolbar->widgetForAction(a)->setProperty("themeID", QVariant(QString::fromUtf8("downArrowIconSmall")));
toolbar->widgetForAction(a)->setProperty("class", "icon-down");
mainLayout->addWidget(toolbar, 0);
setObjectName(QStringLiteral("contextContainer"));
setContentsMargins(0, 0, 0, 0);
mainLayout->setSpacing(0);
mainLayout->setContentsMargins(0, 0, 0, 0);
setLayout(mainLayout);
}
CanvasSourcesDock::~CanvasSourcesDock() {}
void CanvasSourcesDock::ShowSourcesContextMenu(obs_sceneitem_t *item)
{
auto menu = QMenu(this);
menu.addMenu(canvasDock->CreateAddSourcePopupMenu());
if (item) {
canvasDock->AddSceneItemMenuItems(&menu, item);
}
menu.exec(QCursor::pos());
}
bool CanvasSourcesDock::selected_items(obs_scene_t *, obs_sceneitem_t *item, void *param)
{
std::vector<OBSSceneItem> &items = *reinterpret_cast<std::vector<OBSSceneItem> *>(param);
if (obs_sceneitem_selected(item)) {
items.emplace_back(item);
} else if (obs_sceneitem_is_group(item)) {
obs_sceneitem_group_enum_items(item, selected_items, &items);
}
return true;
}
obs_sceneitem_t *CanvasSourcesDock::GetCurrentSceneItem()
{
return sourceList->Get(GetTopSelectedSourceItem());
}
int CanvasSourcesDock::GetTopSelectedSourceItem()
{
QModelIndexList selectedItems = sourceList->selectionModel()->selectedIndexes();
return selectedItems.count() ? selectedItems[0].row() : -1;
}