mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-03-21 17:34:57 -05:00
467 lines
11 KiB
C++
467 lines
11 KiB
C++
#include "advanced-scene-switcher.hpp"
|
|
#include "layout-helpers.hpp"
|
|
#include "selection-helpers.hpp"
|
|
#include "source-helpers.hpp"
|
|
#include "switcher-data.hpp"
|
|
#include "ui-helpers.hpp"
|
|
#include "utility.hpp"
|
|
|
|
#include <QTimer>
|
|
|
|
namespace advss {
|
|
|
|
bool ScreenRegionSwitch::pause = false;
|
|
static QMetaObject::Connection addPulse;
|
|
|
|
void AdvSceneSwitcher::ClearFrames(QListWidget *list)
|
|
{
|
|
for (int i = 0; i < list->count(); ++i) {
|
|
ScreenRegionWidget *sw =
|
|
(ScreenRegionWidget *)list->itemWidget(list->item(i));
|
|
sw->hideFrame();
|
|
}
|
|
}
|
|
|
|
void showCurrentFrame(QListWidget *list)
|
|
{
|
|
QListWidgetItem *item = list->currentItem();
|
|
|
|
if (!item) {
|
|
return;
|
|
}
|
|
|
|
ScreenRegionWidget *sw = (ScreenRegionWidget *)list->itemWidget(item);
|
|
sw->showFrame();
|
|
}
|
|
|
|
void AdvSceneSwitcher::SetShowFrames()
|
|
{
|
|
ui->showFrame->setText(obs_module_text(
|
|
"AdvSceneSwitcher.screenRegionTab.showGuideFrames"));
|
|
}
|
|
|
|
void AdvSceneSwitcher::SetHideFrames()
|
|
{
|
|
ui->showFrame->setText(obs_module_text(
|
|
"AdvSceneSwitcher.screenRegionTab.hideGuideFrames"));
|
|
}
|
|
|
|
void AdvSceneSwitcher::on_showFrame_clicked()
|
|
{
|
|
switcher->showFrame = !switcher->showFrame;
|
|
|
|
if (switcher->showFrame) {
|
|
SetHideFrames();
|
|
showCurrentFrame(ui->screenRegionSwitches);
|
|
} else {
|
|
SetShowFrames();
|
|
ClearFrames(ui->screenRegionSwitches);
|
|
}
|
|
}
|
|
|
|
void AdvSceneSwitcher::on_screenRegionSwitches_currentRowChanged(int idx)
|
|
{
|
|
if (loading || idx == -1) {
|
|
return;
|
|
}
|
|
|
|
if (switcher->showFrame) {
|
|
ClearFrames(ui->screenRegionSwitches);
|
|
showCurrentFrame(ui->screenRegionSwitches);
|
|
}
|
|
}
|
|
|
|
void AdvSceneSwitcher::on_screenRegionAdd_clicked()
|
|
{
|
|
std::lock_guard<std::mutex> lock(switcher->m);
|
|
switcher->screenRegionSwitches.emplace_back();
|
|
|
|
listAddClicked(ui->screenRegionSwitches,
|
|
new ScreenRegionWidget(
|
|
this, &switcher->screenRegionSwitches.back()),
|
|
ui->screenRegionAdd, &addPulse);
|
|
|
|
ui->regionHelp->setVisible(false);
|
|
}
|
|
|
|
void AdvSceneSwitcher::on_screenRegionRemove_clicked()
|
|
{
|
|
QListWidgetItem *item = ui->screenRegionSwitches->currentItem();
|
|
if (!item) {
|
|
return;
|
|
}
|
|
|
|
{
|
|
std::lock_guard<std::mutex> lock(switcher->m);
|
|
int idx = ui->screenRegionSwitches->currentRow();
|
|
auto &switches = switcher->screenRegionSwitches;
|
|
switches.erase(switches.begin() + idx);
|
|
}
|
|
|
|
delete item;
|
|
}
|
|
|
|
void AdvSceneSwitcher::on_screenRegionUp_clicked()
|
|
{
|
|
int index = ui->screenRegionSwitches->currentRow();
|
|
if (!listMoveUp(ui->screenRegionSwitches)) {
|
|
return;
|
|
}
|
|
|
|
ScreenRegionWidget *s1 =
|
|
(ScreenRegionWidget *)ui->screenRegionSwitches->itemWidget(
|
|
ui->screenRegionSwitches->item(index));
|
|
ScreenRegionWidget *s2 =
|
|
(ScreenRegionWidget *)ui->screenRegionSwitches->itemWidget(
|
|
ui->screenRegionSwitches->item(index - 1));
|
|
ScreenRegionWidget::swapSwitchData(s1, s2);
|
|
|
|
std::lock_guard<std::mutex> lock(switcher->m);
|
|
|
|
std::swap(switcher->screenRegionSwitches[index],
|
|
switcher->screenRegionSwitches[index - 1]);
|
|
}
|
|
|
|
void AdvSceneSwitcher::on_screenRegionDown_clicked()
|
|
{
|
|
int index = ui->screenRegionSwitches->currentRow();
|
|
|
|
if (!listMoveDown(ui->screenRegionSwitches)) {
|
|
return;
|
|
}
|
|
|
|
ScreenRegionWidget *s1 =
|
|
(ScreenRegionWidget *)ui->screenRegionSwitches->itemWidget(
|
|
ui->screenRegionSwitches->item(index));
|
|
ScreenRegionWidget *s2 =
|
|
(ScreenRegionWidget *)ui->screenRegionSwitches->itemWidget(
|
|
ui->screenRegionSwitches->item(index + 1));
|
|
ScreenRegionWidget::swapSwitchData(s1, s2);
|
|
|
|
std::lock_guard<std::mutex> lock(switcher->m);
|
|
|
|
std::swap(switcher->screenRegionSwitches[index],
|
|
switcher->screenRegionSwitches[index + 1]);
|
|
}
|
|
|
|
bool shouldIgnoreSceneSwitch(ScreenRegionSwitch &matchingRegion)
|
|
{
|
|
if (!matchingRegion.excludeScene) {
|
|
return false;
|
|
}
|
|
|
|
return matchingRegion.excludeScene == switcher->currentScene;
|
|
}
|
|
|
|
bool SwitcherData::checkScreenRegionSwitch(OBSWeakSource &scene,
|
|
OBSWeakSource &transition)
|
|
{
|
|
if (ScreenRegionSwitch::pause) {
|
|
return false;
|
|
}
|
|
|
|
std::pair<int, int> cursorPos = GetCursorPos();
|
|
int minRegionSize = 99999;
|
|
bool match = false;
|
|
|
|
for (auto &s : screenRegionSwitches) {
|
|
if (!s.initialized()) {
|
|
continue;
|
|
}
|
|
|
|
if (cursorPos.first >= s.minX && cursorPos.second >= s.minY &&
|
|
cursorPos.first <= s.maxX && cursorPos.second <= s.maxY) {
|
|
int regionSize = (s.maxX - s.minX) + (s.maxY - s.minY);
|
|
if (regionSize < minRegionSize) {
|
|
if (shouldIgnoreSceneSwitch(s)) {
|
|
// We technically have a match.
|
|
// But just ignore it.
|
|
return false;
|
|
}
|
|
match = true;
|
|
scene = s.getScene();
|
|
transition = s.transition;
|
|
minRegionSize = regionSize;
|
|
|
|
if (verbose) {
|
|
s.logMatch();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return match;
|
|
}
|
|
|
|
void AdvSceneSwitcher::updateScreenRegionCursorPos()
|
|
{
|
|
std::pair<int, int> position = GetCursorPos();
|
|
ui->cursorXPosition->setText(QString::number(position.first));
|
|
ui->cursorYPosition->setText(QString::number(position.second));
|
|
}
|
|
|
|
void SwitcherData::saveScreenRegionSwitches(obs_data_t *obj)
|
|
{
|
|
obs_data_array_t *screenRegionArray = obs_data_array_create();
|
|
for (ScreenRegionSwitch &s : screenRegionSwitches) {
|
|
obs_data_t *array_obj = obs_data_create();
|
|
|
|
s.save(array_obj);
|
|
obs_data_array_push_back(screenRegionArray, array_obj);
|
|
|
|
obs_data_release(array_obj);
|
|
}
|
|
obs_data_set_array(obj, "screenRegion", screenRegionArray);
|
|
obs_data_array_release(screenRegionArray);
|
|
}
|
|
|
|
void SwitcherData::loadScreenRegionSwitches(obs_data_t *obj)
|
|
{
|
|
screenRegionSwitches.clear();
|
|
|
|
obs_data_array_t *screenRegionArray =
|
|
obs_data_get_array(obj, "screenRegion");
|
|
size_t count = obs_data_array_count(screenRegionArray);
|
|
|
|
for (size_t i = 0; i < count; i++) {
|
|
obs_data_t *array_obj =
|
|
obs_data_array_item(screenRegionArray, i);
|
|
|
|
screenRegionSwitches.emplace_back();
|
|
screenRegionSwitches.back().load(array_obj);
|
|
|
|
obs_data_release(array_obj);
|
|
}
|
|
obs_data_array_release(screenRegionArray);
|
|
}
|
|
|
|
void AdvSceneSwitcher::SetupRegionTab()
|
|
{
|
|
for (auto &s : switcher->screenRegionSwitches) {
|
|
QListWidgetItem *item;
|
|
item = new QListWidgetItem(ui->screenRegionSwitches);
|
|
ui->screenRegionSwitches->addItem(item);
|
|
ScreenRegionWidget *sw = new ScreenRegionWidget(this, &s);
|
|
item->setSizeHint(sw->minimumSizeHint());
|
|
ui->screenRegionSwitches->setItemWidget(item, sw);
|
|
}
|
|
|
|
if (switcher->screenRegionSwitches.size() == 0) {
|
|
if (!switcher->disableHints) {
|
|
addPulse = PulseWidget(ui->screenRegionAdd,
|
|
QColor(Qt::green));
|
|
}
|
|
ui->regionHelp->setVisible(true);
|
|
} else {
|
|
ui->regionHelp->setVisible(false);
|
|
}
|
|
|
|
// screen region cursor position
|
|
QTimer *screenRegionTimer = new QTimer(this);
|
|
connect(screenRegionTimer, SIGNAL(timeout()), this,
|
|
SLOT(updateScreenRegionCursorPos()));
|
|
screenRegionTimer->start(1000);
|
|
}
|
|
|
|
void ScreenRegionSwitch::save(obs_data_t *obj)
|
|
{
|
|
SceneSwitcherEntry::save(obj);
|
|
|
|
obs_data_set_string(obj, "excludeScene",
|
|
GetWeakSourceName(excludeScene).c_str());
|
|
|
|
obs_data_set_int(obj, "minX", minX);
|
|
obs_data_set_int(obj, "minY", minY);
|
|
obs_data_set_int(obj, "maxX", maxX);
|
|
obs_data_set_int(obj, "maxY", maxY);
|
|
}
|
|
|
|
void ScreenRegionSwitch::load(obs_data_t *obj)
|
|
{
|
|
SceneSwitcherEntry::load(obj);
|
|
|
|
const char *excludeSceneName = obs_data_get_string(obj, "excludeScene");
|
|
excludeScene = GetWeakSourceByName(excludeSceneName);
|
|
|
|
minX = obs_data_get_int(obj, "minX");
|
|
minY = obs_data_get_int(obj, "minY");
|
|
maxX = obs_data_get_int(obj, "maxX");
|
|
maxY = obs_data_get_int(obj, "maxY");
|
|
}
|
|
|
|
ScreenRegionWidget::ScreenRegionWidget(QWidget *parent, ScreenRegionSwitch *s)
|
|
: SwitchWidget(parent, s, true, true)
|
|
{
|
|
excludeScenes = new QComboBox();
|
|
minX = new QSpinBox();
|
|
minY = new QSpinBox();
|
|
maxX = new QSpinBox();
|
|
maxY = new QSpinBox();
|
|
|
|
minX->setPrefix("Min X: ");
|
|
minY->setPrefix("Min Y: ");
|
|
maxX->setPrefix("Max X: ");
|
|
maxY->setPrefix("Max Y: ");
|
|
|
|
minX->setMinimum(-1000000);
|
|
minY->setMinimum(-1000000);
|
|
maxX->setMinimum(-1000000);
|
|
maxY->setMinimum(-1000000);
|
|
|
|
minX->setMaximum(1000000);
|
|
minY->setMaximum(1000000);
|
|
maxX->setMaximum(1000000);
|
|
maxY->setMaximum(1000000);
|
|
|
|
QWidget::connect(excludeScenes,
|
|
SIGNAL(currentTextChanged(const QString &)), this,
|
|
SLOT(ExcludeSceneChanged(const QString &)));
|
|
QWidget::connect(minX, SIGNAL(valueChanged(int)), this,
|
|
SLOT(MinXChanged(int)));
|
|
QWidget::connect(minY, SIGNAL(valueChanged(int)), this,
|
|
SLOT(MinYChanged(int)));
|
|
QWidget::connect(maxX, SIGNAL(valueChanged(int)), this,
|
|
SLOT(MaxXChanged(int)));
|
|
QWidget::connect(maxY, SIGNAL(valueChanged(int)), this,
|
|
SLOT(MaxYChanged(int)));
|
|
|
|
PopulateSceneSelection(
|
|
excludeScenes, false, false, false, false, nullptr, true,
|
|
obs_module_text(
|
|
"AdvSceneSwitcher.screenRegionTab.excludeScenes.None"),
|
|
true);
|
|
|
|
if (s) {
|
|
excludeScenes->setCurrentText(
|
|
GetWeakSourceName(s->excludeScene).c_str());
|
|
minX->setValue(s->minX);
|
|
minY->setValue(s->minY);
|
|
maxX->setValue(s->maxX);
|
|
maxY->setValue(s->maxY);
|
|
}
|
|
|
|
QHBoxLayout *mainLayout = new QHBoxLayout;
|
|
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
|
{"{{minX}}", minX},
|
|
{"{{minY}}", minY},
|
|
{"{{maxX}}", maxX},
|
|
{"{{maxY}}", maxY},
|
|
{"{{scenes}}", scenes},
|
|
{"{{transitions}}", transitions},
|
|
{"{{excludeScenes}}", excludeScenes}};
|
|
PlaceWidgets(obs_module_text("AdvSceneSwitcher.screenRegionTab.entry"),
|
|
mainLayout, widgetPlaceholders);
|
|
setLayout(mainLayout);
|
|
|
|
switchData = s;
|
|
|
|
loading = false;
|
|
}
|
|
|
|
ScreenRegionSwitch *ScreenRegionWidget::getSwitchData()
|
|
{
|
|
return switchData;
|
|
}
|
|
|
|
void ScreenRegionWidget::setSwitchData(ScreenRegionSwitch *s)
|
|
{
|
|
switchData = s;
|
|
}
|
|
|
|
void ScreenRegionWidget::swapSwitchData(ScreenRegionWidget *s1,
|
|
ScreenRegionWidget *s2)
|
|
{
|
|
SwitchWidget::swapSwitchData(s1, s2);
|
|
|
|
ScreenRegionSwitch *t = s1->getSwitchData();
|
|
s1->setSwitchData(s2->getSwitchData());
|
|
s2->setSwitchData(t);
|
|
}
|
|
|
|
void ScreenRegionWidget::showFrame()
|
|
{
|
|
drawFrame();
|
|
helperFrame.show();
|
|
}
|
|
|
|
void ScreenRegionWidget::hideFrame()
|
|
{
|
|
helperFrame.hide();
|
|
}
|
|
|
|
void ScreenRegionWidget::ExcludeSceneChanged(const QString &text)
|
|
{
|
|
if (loading || !switchData) {
|
|
return;
|
|
}
|
|
|
|
std::lock_guard<std::mutex> lock(switcher->m);
|
|
switchData->excludeScene = GetWeakSourceByQString(text);
|
|
}
|
|
|
|
void ScreenRegionWidget::MinXChanged(int pos)
|
|
{
|
|
if (loading || !switchData) {
|
|
return;
|
|
}
|
|
|
|
std::lock_guard<std::mutex> lock(switcher->m);
|
|
switchData->minX = pos;
|
|
|
|
drawFrame();
|
|
}
|
|
|
|
void ScreenRegionWidget::MinYChanged(int pos)
|
|
{
|
|
if (loading || !switchData) {
|
|
return;
|
|
}
|
|
|
|
std::lock_guard<std::mutex> lock(switcher->m);
|
|
switchData->minY = pos;
|
|
|
|
drawFrame();
|
|
}
|
|
|
|
void ScreenRegionWidget::MaxXChanged(int pos)
|
|
{
|
|
if (loading || !switchData) {
|
|
return;
|
|
}
|
|
|
|
std::lock_guard<std::mutex> lock(switcher->m);
|
|
switchData->maxX = pos;
|
|
|
|
drawFrame();
|
|
}
|
|
|
|
void ScreenRegionWidget::MaxYChanged(int pos)
|
|
{
|
|
if (loading || !switchData) {
|
|
return;
|
|
}
|
|
|
|
std::lock_guard<std::mutex> lock(switcher->m);
|
|
switchData->maxY = pos;
|
|
|
|
drawFrame();
|
|
}
|
|
|
|
void ScreenRegionWidget::drawFrame()
|
|
{
|
|
helperFrame.setFrameStyle(QFrame::Box | QFrame::Plain);
|
|
helperFrame.setWindowFlags(Qt::FramelessWindowHint | Qt::Tool |
|
|
Qt::WindowTransparentForInput |
|
|
Qt::WindowDoesNotAcceptFocus |
|
|
Qt::WindowStaysOnTopHint);
|
|
helperFrame.setAttribute(Qt::WA_TranslucentBackground, true);
|
|
|
|
if (switchData) {
|
|
helperFrame.setGeometry(switchData->minX, switchData->minY,
|
|
switchData->maxX - switchData->minX,
|
|
switchData->maxY - switchData->minY);
|
|
}
|
|
}
|
|
|
|
} // namespace advss
|