mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-08-29 04:36:21 -05:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9bcced524b | ||
|
|
3bb2ddfaac | ||
|
|
50e26aba72 | ||
|
|
267ab6a7c1 | ||
|
|
65ea7987c7 | ||
|
|
a6839666ce | ||
|
|
e5843de4fc | ||
|
|
a330378c16 | ||
|
|
ddb7888e61 | ||
|
|
73aef4f0b2 | ||
|
|
67c3b73e10 | ||
|
|
9a3d381cf0 | ||
|
|
8b8829f7df | ||
|
|
6fff3b54e6 |
30
.github/workflows/main.yml
vendored
30
.github/workflows/main.yml
vendored
@@ -92,21 +92,21 @@ jobs:
|
||||
if [[ '${{ secrets.MACOS_SIGNING_APPLICATION_IDENTITY }}' != '' && \
|
||||
'${{ secrets.MACOS_SIGNING_INSTALLER_IDENTITY }}' != '' && \
|
||||
'${{ secrets.MACOS_SIGNING_CERT }}' != '' ]] {
|
||||
print '::set-output name=haveCodesignIdent::true'
|
||||
print 'haveCodesignIdent=true' >> $GITHUB_OUTPUT
|
||||
} else {
|
||||
print '::set-output name=haveCodesignIdent::false'
|
||||
print 'haveCodesignIdent=false' >> $GITHUB_OUTPUT
|
||||
}
|
||||
|
||||
if [[ '${{ secrets.MACOS_NOTARIZATION_USERNAME }}' != '' && \
|
||||
'${{ secrets.MACOS_NOTARIZATION_PASSWORD }}' != '' ]] {
|
||||
print '::set-output name=haveNotarizationUser::true'
|
||||
print 'haveNotarizationUser=true' >> $GITHUB_OUTPUT
|
||||
} else {
|
||||
print '::set-output name=haveNotarizationUser::false'
|
||||
print 'haveNotarizationUser=false' >> $GITHUB_OUTPUT
|
||||
}
|
||||
print '::endgroup::'
|
||||
|
||||
print "::set-output name=ccacheDate::$(date +"%Y-%m-%d")"
|
||||
print "::set-output name=commitHash::${"$(git rev-parse HEAD)"[0,9]}"
|
||||
print "ccacheDate=$(date +"%Y-%m-%d")" >> $GITHUB_OUTPUT
|
||||
print "commitHash=${"$(git rev-parse HEAD)"[0,9]}" >> $GITHUB_OUTPUT
|
||||
echo "$PWD/.github/scripts" >> $GITHUB_PATH
|
||||
|
||||
- name: Restore Compilation Cache
|
||||
@@ -123,9 +123,9 @@ jobs:
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
run: |
|
||||
if [[ -n "$(curl -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" -s "${{ github.event.pull_request.url }}" | jq -e '.labels[] | select(.name == "Seeking Testers")')" ]] {
|
||||
print '::set-output name=found::true'
|
||||
print 'found=true' >> $GITHUB_OUTPUT
|
||||
} else {
|
||||
print '::set-output name=found::false'
|
||||
print 'found=false' >> $GITHUB_OUTPUT
|
||||
}
|
||||
|
||||
- name: Install Apple Developer Certificate
|
||||
@@ -206,8 +206,8 @@ jobs:
|
||||
id: setup
|
||||
run: |
|
||||
## SETUP ENVIRONMENT SCRIPT
|
||||
echo "::set-output name=ccacheDate::$(date +"%Y-%m-%d")"
|
||||
echo "::set-output name=commitHash::$(git rev-parse HEAD | cut -c1-9)"
|
||||
echo "ccacheDate=$(date +"%Y-%m-%d")" >> $GITHUB_OUTPUT
|
||||
echo "commitHash=$(git rev-parse HEAD | cut -c1-9)" >> $GITHUB_OUTPUT
|
||||
echo "$PWD/.github/scripts" >> $GITHUB_PATH
|
||||
|
||||
- name: Restore Compilation Cache
|
||||
@@ -225,9 +225,9 @@ jobs:
|
||||
run: |
|
||||
## GITHUB LABEL SCRIPT
|
||||
if [[ -n "$(curl -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" -s "${{ github.event.pull_request.url }}" | jq -e '.labels[] | select(.name == "Seeking Testers")')" ]]; then
|
||||
echo '::set-output name=found::true'
|
||||
echo 'found=true' >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo '::set-output name=found::false'
|
||||
echo 'found=false' >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Build Plugin
|
||||
@@ -295,7 +295,7 @@ jobs:
|
||||
run: |
|
||||
## SETUP ENVIRONMENT SCRIPT
|
||||
$CommitHash = (git rev-parse HEAD)[0..8] -join ''
|
||||
Write-Output "::set-output name=commitHash::${CommitHash}"
|
||||
"commitHash=${CommitHash}" >> $env:GITHUB_OUTPUT
|
||||
|
||||
- name: Check for GitHub Labels
|
||||
id: seekingTesters
|
||||
@@ -316,7 +316,7 @@ jobs:
|
||||
$false
|
||||
}
|
||||
|
||||
Write-Output "::set-output name=found::$(([string]${LabelFound}).ToLower())"
|
||||
"found=$(([string]${LabelFound}).ToLower())" >> $env:GITHUB_OUTPUT
|
||||
|
||||
- name: Build Plugin
|
||||
uses: ./plugin/.github/actions/build-plugin
|
||||
@@ -367,7 +367,7 @@ jobs:
|
||||
id: metadata
|
||||
run: |
|
||||
## METADATA SCRIPT
|
||||
echo "::set-output name=version::${GITHUB_REF/refs\/tags\//}"
|
||||
echo "version=${GITHUB_REF/refs\/tags\//}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Download build artifacts
|
||||
uses: actions/download-artifact@v3
|
||||
|
||||
120
BUILDING.md
120
BUILDING.md
@@ -15,7 +15,7 @@ cd obs-studio/UI/frontend-plugins/
|
||||
git clone --recursive https://github.com/WarmUpTill/SceneSwitcher.git
|
||||
```
|
||||
|
||||
Then modify the obs-studio/UI/frontend-plugins/CMakeLists.txt file and add an entry for the scene switcher:
|
||||
Then modify the obs-studio/UI/frontend-plugins/CMakeLists.txt Example and add an entry for the scene switcher:
|
||||
```
|
||||
add_subdirectory(SceneSwitcher)
|
||||
```
|
||||
@@ -66,11 +66,123 @@ Finally, start the plugin build using your provided generator. (E.g. Ninja on Li
|
||||
|
||||
Contributions to the plugin are always welcome and if you need any assistance do not hesitate to reach out.
|
||||
|
||||
If you would like to expand upon the macro system by adding a new condition or action type have a loot at the examples in `src/macro-core`.
|
||||
In general changes in the `src/legacy` folder should be avoided.
|
||||
|
||||
If you would like to expand upon the macro system by adding a new condition or action type have a loot at the examples in `src/macro-core`.
|
||||
The key functions to add conditions or are the Register() functions.
|
||||
## Macro condition
|
||||
Macro conditions should inherit from the `MacroCondition` class and must implement the following functions:
|
||||
|
||||
```
|
||||
class MacroConditionExample : public MacroCondition {
|
||||
public:
|
||||
MacroConditionExample(Macro *m) : MacroCondition(m) {}
|
||||
// This function should perfrom the condition check
|
||||
bool CheckCondition();
|
||||
// This function should store the required condition data to "obj"
|
||||
// For example called on OBS shutdown
|
||||
bool Save(obs_data_t *obj);
|
||||
// This function should load the condition data from "obj"
|
||||
// For example called on OBS startup
|
||||
bool Load(obs_data_t *obj);
|
||||
// This function should return a unique id for this condition type
|
||||
// The _id is defined below
|
||||
std::string GetId() { return _id; };
|
||||
// Helper function called when new conditions are created
|
||||
// Will be used later when regeistering the new condition type
|
||||
static std::shared_ptr<MacroCondition> Create(Macro *m)
|
||||
{
|
||||
return std::make_shared<MacroConditionExample>(m);
|
||||
}
|
||||
|
||||
private:
|
||||
// Used to register new condition type
|
||||
static bool _registered;
|
||||
// Unique id identifying this condition type
|
||||
static const std::string _id;
|
||||
};
|
||||
```
|
||||
When defining the widget used to control the settings of the condition type, it is important to add a static `Create()` method.
|
||||
It will be called whenever a new condition MacroConditionExample is created. (See `MacroConditionFactory::Register()`)
|
||||
```
|
||||
class MacroConditionExampleEdit : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
// ...
|
||||
MacroConditionExampleEdit(
|
||||
QWidget *parent,
|
||||
std::shared_ptr<MacroConditionExample> cond = nullptr);
|
||||
|
||||
// Function will be used to create the widget for editing the settings of the condition
|
||||
static QWidget *Create(QWidget *parent,
|
||||
std::shared_ptr<MacroCondition> cond)
|
||||
{
|
||||
return new MacroConditionExampleEdit(
|
||||
parent,
|
||||
std::dynamic_pointer_cast<MacroConditionExample>(cond));
|
||||
}
|
||||
// ...
|
||||
};
|
||||
```
|
||||
|
||||
To finally register the new condition type you will have to add the following call to `MacroConditionFactory::Register()`.
|
||||
|
||||
```
|
||||
bool MacroConditionExample::_registered = MacroConditionFactory::Register(
|
||||
MacroConditionExample::id, // Unique string identifying this condition type
|
||||
{
|
||||
MacroConditionExample::Create, // Function called to create the object performing the condition
|
||||
MacroConditionExampleEdit::Create, // Function called to create the widget configure the condition
|
||||
"AdvSceneSwitcher.condition.example", // User facing name of the condition type (will be translated)
|
||||
true // Condition type supports duration modifiers (default true)
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
## Macro action
|
||||
|
||||
The process of adding a new action type is very similar to adding a new condition.
|
||||
The differences are highlighted in the comments below.
|
||||
|
||||
```
|
||||
class MacroActionExample : public MacroAction {
|
||||
public:
|
||||
MacroActionExample(Macro *m) : MacroAction(m) {}
|
||||
// This function should perfrom the action
|
||||
// If false is returned the macro will aborted
|
||||
bool PerformAction();
|
||||
bool Save(obs_data_t *obj);
|
||||
bool Load(obs_data_t *obj);
|
||||
std::string GetId() { return _id; };
|
||||
static std::shared_ptr<MacroAction> Create(Macro *m)
|
||||
{
|
||||
return std::make_shared<MacroActionExample>(m);
|
||||
}
|
||||
|
||||
private:
|
||||
static bool _registered;
|
||||
static const std::string _id;
|
||||
};
|
||||
```
|
||||
```
|
||||
class MacroActionExampleEdit : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
// ...
|
||||
MacroActionExampleEdit(
|
||||
QWidget *parent,
|
||||
std::shared_ptr<MacroActionExample> entryData = nullptr);
|
||||
static QWidget *Create(QWidget *parent,
|
||||
std::shared_ptr<MacroAction> action)
|
||||
{
|
||||
return new MacroActionExampleEdit(
|
||||
parent,
|
||||
std::dynamic_pointer_cast<MacroActionExample>(action));
|
||||
}
|
||||
// ...
|
||||
};
|
||||
```
|
||||
```
|
||||
MacroActionFactory::Register(
|
||||
MacroActionExample::id, // Unique string identifying this action type
|
||||
@@ -81,6 +193,6 @@ MacroActionFactory::Register(
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
## External dependencies
|
||||
If your intention is to add macro functionality which depends on external libraries, which is likely not to exist on all user setups, try to follow the examples under `src/macro-external`.
|
||||
These are basically plugins themselves that get attempted to be loaded on startup of the advanced scene switcher.
|
||||
|
||||
@@ -346,8 +346,7 @@ else()
|
||||
set(CPACK_PACKAGE_NAME "${CMAKE_PROJECT_NAME}")
|
||||
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "${LINUX_MAINTAINER_EMAIL}")
|
||||
set(CPACK_PACKAGE_VERSION "${CMAKE_PROJECT_VERSION}")
|
||||
set(CPACK_PACKAGE_FILE_NAME
|
||||
"${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-linux-x86_64")
|
||||
set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-linux-x86_64")
|
||||
|
||||
set(CPACK_GENERATOR "DEB")
|
||||
if(${QT_VERSION} STREQUAL "6")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#define MyAppName "@CMAKE_PROJECT_NAME@"
|
||||
#define MyAppVersion "@CMAKE_PROJECT_VERSION@"
|
||||
#define MyAppVersion "@GIT_TAG@"
|
||||
#define MyAppPublisher "@PLUGIN_AUTHOR@"
|
||||
#define MyAppURL "http://www.mywebsite.com"
|
||||
|
||||
|
||||
@@ -51,13 +51,13 @@ AdvSceneSwitcher.generalTab.priority.media="Medien"
|
||||
AdvSceneSwitcher.generalTab.priority.time="Zeit"
|
||||
AdvSceneSwitcher.generalTab.priority.audio="Audio"
|
||||
AdvSceneSwitcher.generalTab.priority.video="Video"
|
||||
AdvSceneSwitcher.generalTab.setTransitionBy="Beim Ändern des Szenenübergangs:"
|
||||
AdvSceneSwitcher.generalTab.transitionOverride="Verwende Übergangsüberschreibungen"
|
||||
AdvSceneSwitcher.generalTab.adjustActiveTransitionType="Wechsle den aktiven Szenenübergangtyp"
|
||||
AdvSceneSwitcher.generalTab.transitionBehaviorSelectionError="Mindestens eine Option muss aktiv sein:\n\n - Verwende Übergangsüberschreibungen\n\n - Wechsle den aktiven Szenenübergangtyp"
|
||||
|
||||
; Transition Tab
|
||||
AdvSceneSwitcher.transitionTab.title="Szenenübergänge"
|
||||
AdvSceneSwitcher.transitionTab.setTransitionBy="Beim Ändern des Szenenübergangs:"
|
||||
AdvSceneSwitcher.transitionTab.transitionOverride="Verwende Übergangsüberschreibungen"
|
||||
AdvSceneSwitcher.transitionTab.adjustActiveTransitionType="Wechsle den aktiven Szenenübergangtyp"
|
||||
AdvSceneSwitcher.transitionTab.transitionBehaviorSelectionError="Mindestens eine Option muss aktiv sein:\n\n - Verwende Übergangsüberschreibungen\n\n - Wechsle den aktiven Szenenübergangtyp"
|
||||
AdvSceneSwitcher.transitionTab.transitionForAToB="Szenenübergänge für automatisierte Szenenwechsel von Szene A zu Szene B"
|
||||
AdvSceneSwitcher.transitionTab.transitionsHelp="<html><head/><body><p>Diese Einstellungen beeinflussen <span style=\"font-style:italic;\">nur</span> vom Szenenwechsler ausgelöste Szenenübergänge - Siehe <a href=\"https://obsproject.com/forum/resources/transition-table.1174/\"><span style=\" text-decoration: underline; color:#268bd2;\">Transition Table</span></a> um auch manuelle Szenenübergänge zu konfigurieren.<br/>Einstellungen auf diesem Tab haben Vorrang, vor denen welche auf den übrigen Tabs konfiguriert wurden.<br/><br/>Klicke auf das Plus Symbol, um einen neuen Eintrag hinzuzufügen.</p></body></html>"
|
||||
AdvSceneSwitcher.transitionTab.defaultTransition="Ändere den Szenenübergang wenn eine Szene aktiv ist"
|
||||
|
||||
@@ -55,6 +55,11 @@ AdvSceneSwitcher.generalTab.priority.time="Time"
|
||||
AdvSceneSwitcher.generalTab.priority.audio="Audio"
|
||||
AdvSceneSwitcher.generalTab.priority.video="Video"
|
||||
AdvSceneSwitcher.generalTab.priority.macro="Macro"
|
||||
AdvSceneSwitcher.generalTab.transition="Transitions"
|
||||
AdvSceneSwitcher.generalTab.setTransitionBy="When changing transitions:"
|
||||
AdvSceneSwitcher.generalTab.transitionOverride="Set transition overrides"
|
||||
AdvSceneSwitcher.generalTab.adjustActiveTransitionType="Change active transition type"
|
||||
AdvSceneSwitcher.generalTab.transitionBehaviorSelectionError="At least one option must be enabled:\n\n - Use transition overrides\n\n - Change active transition type"
|
||||
|
||||
; Macro Tab
|
||||
AdvSceneSwitcher.macroTab.title="Macro"
|
||||
@@ -128,6 +133,7 @@ AdvSceneSwitcher.condition.scene.entry.line2="{{useTransitionTargetScene}}"
|
||||
AdvSceneSwitcher.condition.window="Window"
|
||||
AdvSceneSwitcher.condition.window.entry.line1="{{windows}} exist and ..."
|
||||
AdvSceneSwitcher.condition.window.entry.line2="... is {{fullscreen}} fullscreen {{maximized}} maximized {{focused}} focused {{windowFocusChanged}} foreground window changed"
|
||||
AdvSceneSwitcher.condition.window.entry.line3="Current foreground window: {{focusWindow}}"
|
||||
AdvSceneSwitcher.condition.file="File"
|
||||
AdvSceneSwitcher.condition.file.type.match="matches"
|
||||
AdvSceneSwitcher.condition.file.type.contentChange="content changed"
|
||||
@@ -149,6 +155,7 @@ AdvSceneSwitcher.condition.video.condition.hasNotChanged="has not changed"
|
||||
AdvSceneSwitcher.condition.video.condition.noImage="has no output"
|
||||
AdvSceneSwitcher.condition.video.condition.pattern="matches pattern"
|
||||
AdvSceneSwitcher.condition.video.condition.object="contains object"
|
||||
AdvSceneSwitcher.condition.video.condition.brightness="brightness"
|
||||
AdvSceneSwitcher.condition.video.askFileAction="Do you want to use an existing file or create a screenshot of the currently selected source?"
|
||||
AdvSceneSwitcher.condition.video.askFileAction.file="Use existing file"
|
||||
AdvSceneSwitcher.condition.video.askFileAction.screenshot="Create screenshot"
|
||||
@@ -159,6 +166,9 @@ AdvSceneSwitcher.condition.video.usePatternForChangedCheck.tooltip="This will al
|
||||
AdvSceneSwitcher.condition.video.patternThreshold="Threshold: "
|
||||
AdvSceneSwitcher.condition.video.patternThresholdDescription="A higher threshold value means that the pattern needs to match the video source more closely."
|
||||
AdvSceneSwitcher.condition.video.patternThresholdUseAlphaAsMask="Use alpha channel as mask for pattern."
|
||||
AdvSceneSwitcher.condition.video.brightnessThreshold="Average brightness:"
|
||||
AdvSceneSwitcher.condition.video.brightnessThresholdDescription="A high value is indicating a bright image and a low one a darker one."
|
||||
AdvSceneSwitcher.condition.video.currentBrightness="Current average brightness: %1"
|
||||
AdvSceneSwitcher.condition.video.objectScaleThreshold="Scale factor: "
|
||||
AdvSceneSwitcher.condition.video.objectScaleThresholdDescription="A lower scale factor will lead to more matches but higher CPU load."
|
||||
AdvSceneSwitcher.condition.video.minNeighborDescription="A higher minimum neighbors value will result in fewer but higher quality matches."
|
||||
@@ -196,6 +206,7 @@ AdvSceneSwitcher.condition.record.state.stop="Recording stopped"
|
||||
AdvSceneSwitcher.condition.record.entry="{{recordState}}"
|
||||
AdvSceneSwitcher.condition.process="Process"
|
||||
AdvSceneSwitcher.condition.process.entry="{{processes}} is running {{focused}} and is focused"
|
||||
AdvSceneSwitcher.condition.process.entry.focus="Current foreground process: {{focusProcess}}"
|
||||
AdvSceneSwitcher.condition.idle="Idle"
|
||||
AdvSceneSwitcher.condition.idle.entry="No keyboard or mouse inputs for {{duration}}"
|
||||
AdvSceneSwitcher.condition.pluginState="Plugin state"
|
||||
@@ -537,10 +548,6 @@ AdvSceneSwitcher.action.variable.entry="{{actions}}{{variables}}{{variables2}}{{
|
||||
|
||||
; Transition Tab
|
||||
AdvSceneSwitcher.transitionTab.title="Transition"
|
||||
AdvSceneSwitcher.transitionTab.setTransitionBy="When changing transitions:"
|
||||
AdvSceneSwitcher.transitionTab.transitionOverride="Set transition overrides"
|
||||
AdvSceneSwitcher.transitionTab.adjustActiveTransitionType="Change active transition type"
|
||||
AdvSceneSwitcher.transitionTab.transitionBehaviorSelectionError="At least one option must be enabled:\n\n - Use transition overrides\n\n - Change active transition type"
|
||||
AdvSceneSwitcher.transitionTab.transitionForAToB="Use transition for automated scene switch from scene A to scene B"
|
||||
AdvSceneSwitcher.transitionTab.transitionsHelp="<html><head/><body><p>These settings <span style=\"font-style:italic;\">only</span> affect transitions caused by the scene switcher - Check out <a href=\"https://obsproject.com/forum/resources/transition-table.1174/\"><span style=\" text-decoration: underline; color:#268bd2;\">Transition Table</span></a> if you want to configure this for manual scene changes.<br/>Settings defined here take priority over transition settings configured elsewhere in the scene switcher.<br/><br/>Click the plus symbol below to add a new entry.</p></body></html>"
|
||||
AdvSceneSwitcher.transitionTab.defaultTransition="Change transition if scene is active"
|
||||
|
||||
@@ -54,6 +54,10 @@ AdvSceneSwitcher.generalTab.priority.time="Tiempo"
|
||||
AdvSceneSwitcher.generalTab.priority.audio="Audio"
|
||||
AdvSceneSwitcher.generalTab.priority.video="Video"
|
||||
AdvSceneSwitcher.generalTab.priority.macro="Macro"
|
||||
AdvSceneSwitcher.generalTab.setTransitionBy="Al cambiar las transiciones:"
|
||||
AdvSceneSwitcher.generalTab.transitionOverride="Establecer anulaciones de transición"
|
||||
AdvSceneSwitcher.generalTab.adjustActiveTransitionType="Cambiar tipo de transición activa"
|
||||
AdvSceneSwitcher.generalTab.transitionBehaviorSelectionError="Al menos una opción debe estar habilitada:\n\n - Usar anulaciones de transición\n\n - Cambiar el tipo de transición activo"
|
||||
|
||||
; Macro Tab
|
||||
AdvSceneSwitcher.macroTab.title="Macro"
|
||||
@@ -478,10 +482,6 @@ AdvSceneSwitcher.action.sequence.continueFrom="Continuar con el elemento selecci
|
||||
|
||||
; Transition Tab
|
||||
AdvSceneSwitcher.transitionTab.title="Transición"
|
||||
AdvSceneSwitcher.transitionTab.setTransitionBy="Al cambiar las transiciones:"
|
||||
AdvSceneSwitcher.transitionTab.transitionOverride="Establecer anulaciones de transición"
|
||||
AdvSceneSwitcher.transitionTab.adjustActiveTransitionType="Cambiar tipo de transición activa"
|
||||
AdvSceneSwitcher.transitionTab.transitionBehaviorSelectionError="Al menos una opción debe estar habilitada:\n\n - Usar anulaciones de transición\n\n - Cambiar el tipo de transición activo"
|
||||
AdvSceneSwitcher.transitionTab.transitionForAToB="Utiliza la transición para el cambio de escena automatizado de la escena A a la escena B"
|
||||
AdvSceneSwitcher.transitionTab.transitionsHelp="<html><head/><body> <p> Estos ajustes <span style =\"font-style: italic; \"> solo </span> surgió a las transiciones causadas por el selector de escenas - Echa un vistazo a <a href =\"https://obsproject.com/forum/resources/transition-table.1174/\"> <span style=\" texto-decoración: subrayado; color: # 268bd2; \"> Tabla de transición </span> </a> si desea configurar esto para cambios de escena manuales. <br/> Los definiciones definidos aquí tienen prioridad sobre los ajustes de transición configurados en cualquier otro lugar del selector de escenas. < br/> <br/> Haz clic en el símbolo más a continuación para agregar una nueva entrada. </p></body></html>"
|
||||
AdvSceneSwitcher.transitionTab.defaultTransition="Cambiar transición si la escena está activa"
|
||||
|
||||
@@ -52,6 +52,10 @@ AdvSceneSwitcher.generalTab.priority.time="Время"
|
||||
AdvSceneSwitcher.generalTab.priority.audio="Аудио"
|
||||
AdvSceneSwitcher.generalTab.priority.video="Видео"
|
||||
AdvSceneSwitcher.generalTab.priority.macro="Макрос"
|
||||
AdvSceneSwitcher.generalTab.setTransitionBy="При изменении переходов:"
|
||||
AdvSceneSwitcher.generalTab.transitionOverride="Установить переопределение переходов"
|
||||
AdvSceneSwitcher.generalTab.adjustActiveTransitionType="Изменить тип активного перехода"
|
||||
AdvSceneSwitcher.generalTab.transitionBehaviorSelectionError="Должна быть включена хотя бы одна опция:\n\n - Использовать переопределения переходов\n\n - Изменить тип активного перехода"
|
||||
|
||||
; Macro Tab
|
||||
AdvSceneSwitcher.macroTab.title="Макрос"
|
||||
@@ -147,10 +151,6 @@ AdvSceneSwitcher.action.run="Запустить"
|
||||
|
||||
; Transition Tab
|
||||
AdvSceneSwitcher.transitionTab.title="Переход"
|
||||
AdvSceneSwitcher.transitionTab.setTransitionBy="При изменении переходов:"
|
||||
AdvSceneSwitcher.transitionTab.transitionOverride="Установить переопределение переходов"
|
||||
AdvSceneSwitcher.transitionTab.adjustActiveTransitionType="Изменить тип активного перехода"
|
||||
AdvSceneSwitcher.transitionTab.transitionBehaviorSelectionError="Должна быть включена хотя бы одна опция:\n\n - Использовать переопределения переходов\n\n - Изменить тип активного перехода"
|
||||
AdvSceneSwitcher.transitionTab.transitionForAToB="Использовать переход для автоматического переключения сцены со сцены A на сцену B"
|
||||
AdvSceneSwitcher.transitionTab.transitionsHelp="<html><head/><body><p>Эти настройки <span style=\"font-style:italic;\">только</span> влияют на переходы, вызванные переключателем сцен - Проверьте <a href=\"https://obsproject.com/forum/resources/transition-table.1174/\"><span style=\" text-decoration: underline; color:#268bd2;\">Transition Table</span></a> если вы хотите настроить его для ручного изменения сцены.<br/>Настройки, определенные здесь, имеют приоритет над настройками перехода, сконфигурированными в других местах переключателя сцен.<br/><br/>Нажмите на символ плюса ниже, чтобы добавить новую запись.</p></body></html>"
|
||||
AdvSceneSwitcher.transitionTab.defaultTransition="Изменить переход, если сцена активна"
|
||||
|
||||
@@ -53,6 +53,10 @@ AdvSceneSwitcher.generalTab.priority.time="Zaman"
|
||||
AdvSceneSwitcher.generalTab.priority.audio="Ses"
|
||||
AdvSceneSwitcher.generalTab.priority.video="Video"
|
||||
AdvSceneSwitcher.generalTab.priority.macro="Makro"
|
||||
AdvSceneSwitcher.generalTab.setTransitionBy="Geçişleri değiştirirken:"
|
||||
AdvSceneSwitcher.generalTab.transitionOverride="Geçiş geçersiz kılmaları ayarla"
|
||||
AdvSceneSwitcher.generalTab.adjustActiveTransitionType="Etkin geçiş türünü değiştir"
|
||||
AdvSceneSwitcher.generalTab.transitionBehaviorSelectionError="En az bir seçenek etkinleştirilmelidir: \n\n - Geçiş geçersiz kılmalarını kullan \n\n - Etkin geçiş türünü değiştir"
|
||||
|
||||
; Macro Tab
|
||||
AdvSceneSwitcher.macroTab.title="Makro"
|
||||
@@ -391,10 +395,6 @@ AdvSceneSwitcher.action.sceneCollection.warning="Not: Değişen sahne koleksiyon
|
||||
|
||||
; Transition Tab
|
||||
AdvSceneSwitcher.transitionTab.title="Geçiş"
|
||||
AdvSceneSwitcher.transitionTab.setTransitionBy="Geçişleri değiştirirken:"
|
||||
AdvSceneSwitcher.transitionTab.transitionOverride="Geçiş geçersiz kılmaları ayarla"
|
||||
AdvSceneSwitcher.transitionTab.adjustActiveTransitionType="Etkin geçiş türünü değiştir"
|
||||
AdvSceneSwitcher.transitionTab.transitionBehaviorSelectionError="En az bir seçenek etkinleştirilmelidir: \n\n - Geçiş geçersiz kılmalarını kullan \n\n - Etkin geçiş türünü değiştir"
|
||||
AdvSceneSwitcher.transitionTab.transitionForAToB="Sahne A'dan sahne B'ye otomatik sahne geçişi için geçişi kullanın"
|
||||
AdvSceneSwitcher.transitionTab.transitionsHelp="<html><head/><body><p>Bu ayarlar <span style=\"font-style:italic;\">yalnızca</span>, sahne değiştiricinin neden olduğu geçişleri etkiler - <a href=\ Göz atın "https://obsproject.com/forum/resources/transition-table.1174/\"><span style=\" text-decoration: underline; color:#268bd2;\">Geçiş Tablosu</span></ a> bunu manuel sahne değişiklikleri için yapılandırmak istiyorsanız.<br/>Burada tanımlanan ayarlar, sahne değiştiricide başka bir yerde yapılandırılmış geçiş ayarlarına göre önceliklidir.<br/><br/>Yeni bir giriş eklemek için aşağıdaki artı simgesini tıklayın. .</p></body></html>"
|
||||
AdvSceneSwitcher.transitionTab.defaultTransition="Sahne aktifse geçişi değiştir"
|
||||
|
||||
@@ -54,6 +54,9 @@ AdvSceneSwitcher.generalTab.priority.time="时间"
|
||||
AdvSceneSwitcher.generalTab.priority.audio="音频"
|
||||
AdvSceneSwitcher.generalTab.priority.video="视频"
|
||||
AdvSceneSwitcher.generalTab.priority.macro="宏"
|
||||
AdvSceneSwitcher.generalTab.setTransitionBy="更改转场特效时:"
|
||||
AdvSceneSwitcher.generalTab.transitionOverride="在场景切换器中设定的转场特效优先级高于场景设定的转场特效"
|
||||
AdvSceneSwitcher.generalTab.adjustActiveTransitionType="更改激活转场特效类型"
|
||||
|
||||
; Macro Tab
|
||||
AdvSceneSwitcher.macroTab.title="宏"
|
||||
@@ -437,9 +440,6 @@ AdvSceneSwitcher.action.sequence.continueFrom="继续所选项目"
|
||||
|
||||
; Transition Tab
|
||||
AdvSceneSwitcher.transitionTab.title="转场特效"
|
||||
AdvSceneSwitcher.transitionTab.setTransitionBy="更改转场特效时:"
|
||||
AdvSceneSwitcher.transitionTab.transitionOverride="在场景切换器中设定的转场特效优先级高于场景设定的转场特效"
|
||||
AdvSceneSwitcher.transitionTab.adjustActiveTransitionType="更改激活转场特效类型"
|
||||
AdvSceneSwitcher.transitionTab.transitionForAToB="当自动从场景A切换到场景B时使用的转场特效"
|
||||
AdvSceneSwitcher.transitionTab.transitionsHelp="<html><head/><body><p>这里的设定<span style=\"font-style:bold;\">只影响由场景切换器引起的转场有效</span>,不影响你手动的引起的转场。<br/>在这里设定的转场特效优先级高于场景切换器其他地方设置的<br/><br/>单击加号添加项目.</p></body></html>"
|
||||
AdvSceneSwitcher.transitionTab.defaultTransition="当切换到这个场景时修改默认转场特效"
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>957</width>
|
||||
<height>817</height>
|
||||
<height>905</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_19">
|
||||
@@ -419,6 +419,49 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="transitionBox">
|
||||
<property name="title">
|
||||
<string>AdvSceneSwitcher.generalTab.transition</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="transitionLayout">
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="adjustActiveTransitionType">
|
||||
<property name="text">
|
||||
<string>AdvSceneSwitcher.generalTab.adjustActiveTransitionType</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="text">
|
||||
<string>AdvSceneSwitcher.generalTab.setTransitionBy</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="transitionOverridecheckBox">
|
||||
<property name="text">
|
||||
<string>AdvSceneSwitcher.generalTab.transitionOverride</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<spacer name="horizontalSpacer_9">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="priorityBox">
|
||||
<property name="title">
|
||||
@@ -610,7 +653,7 @@
|
||||
<enum>Qt::MoveAction</enum>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<number>1</number>
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="sortingEnabled">
|
||||
<bool>false</bool>
|
||||
@@ -763,7 +806,7 @@
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_33">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_18" stretch="0,0,0,0,0,0,0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_18" stretch="0,0,0,0,0,0,0,0,0">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_20">
|
||||
<property name="text">
|
||||
@@ -783,16 +826,36 @@
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="runMacroInParallel">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>AdvSceneSwitcher.macroTab.runInParallel</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="runMacroOnChange">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_18">
|
||||
<property name="text">
|
||||
<string>AdvSceneSwitcher.macroTab.onChange</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
@@ -1710,44 +1773,6 @@
|
||||
<string>AdvSceneSwitcher.transitionTab.title</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_15">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_5">
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="adjustActiveTransitionType">
|
||||
<property name="text">
|
||||
<string>AdvSceneSwitcher.transitionTab.adjustActiveTransitionType</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="text">
|
||||
<string>AdvSceneSwitcher.transitionTab.setTransitionBy</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="transitionOverridecheckBox">
|
||||
<property name="text">
|
||||
<string>AdvSceneSwitcher.transitionTab.transitionOverride</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<spacer name="horizontalSpacer_9">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="transitionsGroup">
|
||||
<property name="title">
|
||||
|
||||
@@ -280,6 +280,9 @@ void SwitcherData::setPreconditions()
|
||||
}
|
||||
currentTitle = title;
|
||||
|
||||
// Process name
|
||||
GetForegroundProcessName(currentForegroundProcess);
|
||||
|
||||
// Cursor
|
||||
std::pair<int, int> cursorPos = getCursorPos();
|
||||
cursorPosChanged = cursorPos.first != switcher->lastCursorPos.first ||
|
||||
|
||||
@@ -496,6 +496,39 @@ void AdvSceneSwitcher::on_tabWidget_currentChanged(int)
|
||||
SetShowFrames();
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_transitionOverridecheckBox_stateChanged(int state)
|
||||
{
|
||||
if (loading) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!state && !switcher->adjustActiveTransitionType) {
|
||||
DisplayMessage(obs_module_text(
|
||||
"AdvSceneSwitcher.generalTab.transitionBehaviorSelectionError"));
|
||||
ui->adjustActiveTransitionType->setChecked(true);
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->transitionOverrideOverride = state;
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_adjustActiveTransitionType_stateChanged(int state)
|
||||
{
|
||||
if (loading) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This option only makes sense if we are allowed to use transition overrides
|
||||
if (!state && !switcher->transitionOverrideOverride) {
|
||||
DisplayMessage(obs_module_text(
|
||||
"AdvSceneSwitcher.generalTab.transitionBehaviorSelectionError"));
|
||||
ui->transitionOverridecheckBox->setChecked(true);
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->adjustActiveTransitionType = state;
|
||||
}
|
||||
|
||||
void SwitcherData::loadSettings(obs_data_t *obj)
|
||||
{
|
||||
if (!obj) {
|
||||
@@ -599,6 +632,13 @@ void SwitcherData::saveGeneralSettings(obs_data_t *obj)
|
||||
obs_data_set_int(obj, "priority10", functionNamesByPriority[10]);
|
||||
|
||||
obs_data_set_int(obj, "threadPriority", threadPriority);
|
||||
|
||||
obs_data_set_bool(obj, "tansitionOverrideOverride",
|
||||
transitionOverrideOverride);
|
||||
obs_data_set_default_bool(obj, "adjustActiveTransitionType",
|
||||
adjustActiveTransitionType);
|
||||
obs_data_set_bool(obj, "adjustActiveTransitionType",
|
||||
adjustActiveTransitionType);
|
||||
}
|
||||
|
||||
void SwitcherData::loadGeneralSettings(obs_data_t *obj)
|
||||
@@ -674,6 +714,11 @@ void SwitcherData::loadGeneralSettings(obs_data_t *obj)
|
||||
obs_data_set_default_int(obj, "threadPriority",
|
||||
QThread::NormalPriority);
|
||||
threadPriority = obs_data_get_int(obj, "threadPriority");
|
||||
|
||||
transitionOverrideOverride =
|
||||
obs_data_get_bool(obj, "tansitionOverrideOverride");
|
||||
adjustActiveTransitionType =
|
||||
obs_data_get_bool(obj, "adjustActiveTransitionType");
|
||||
}
|
||||
|
||||
void saveSplitterPos(QList<int> &sizes, obs_data_t *obj, const std::string name)
|
||||
|
||||
@@ -169,39 +169,6 @@ void SwitcherData::checkDefaultSceneTransitions()
|
||||
}
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_transitionOverridecheckBox_stateChanged(int state)
|
||||
{
|
||||
if (loading) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!state && !switcher->adjustActiveTransitionType) {
|
||||
DisplayMessage(obs_module_text(
|
||||
"AdvSceneSwitcher.transitionTab.transitionBehaviorSelectionError"));
|
||||
ui->adjustActiveTransitionType->setChecked(true);
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->transitionOverrideOverride = state;
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_adjustActiveTransitionType_stateChanged(int state)
|
||||
{
|
||||
if (loading) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This option only makes sense if we are allowed to use transition overrides
|
||||
if (!state && !switcher->transitionOverrideOverride) {
|
||||
DisplayMessage(obs_module_text(
|
||||
"AdvSceneSwitcher.transitionTab.transitionBehaviorSelectionError"));
|
||||
ui->transitionOverridecheckBox->setChecked(true);
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->adjustActiveTransitionType = state;
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::defTransitionDelayValueChanged(int value)
|
||||
{
|
||||
if (loading) {
|
||||
@@ -335,13 +302,6 @@ void SwitcherData::saveSceneTransitions(obs_data_t *obj)
|
||||
}
|
||||
obs_data_set_array(obj, "defaultTransitions", defaultTransitionsArray);
|
||||
obs_data_array_release(defaultTransitionsArray);
|
||||
|
||||
obs_data_set_bool(obj, "tansitionOverrideOverride",
|
||||
transitionOverrideOverride);
|
||||
obs_data_set_default_bool(obj, "adjustActiveTransitionType",
|
||||
adjustActiveTransitionType);
|
||||
obs_data_set_bool(obj, "adjustActiveTransitionType",
|
||||
adjustActiveTransitionType);
|
||||
obs_data_set_default_int(obj, "defTransitionDelay",
|
||||
default_def_transition_dealy);
|
||||
obs_data_set_int(obj, "defTransitionDelay",
|
||||
@@ -380,11 +340,6 @@ void SwitcherData::loadSceneTransitions(obs_data_t *obj)
|
||||
}
|
||||
obs_data_array_release(defaultTransitionsArray);
|
||||
|
||||
transitionOverrideOverride =
|
||||
obs_data_get_bool(obj, "tansitionOverrideOverride");
|
||||
adjustActiveTransitionType =
|
||||
obs_data_get_bool(obj, "adjustActiveTransitionType");
|
||||
|
||||
// Check for invalid config
|
||||
if (!transitionOverrideOverride && !adjustActiveTransitionType) {
|
||||
adjustActiveTransitionType = true;
|
||||
|
||||
@@ -434,10 +434,24 @@ std::string getProcNameFromPid(int pid)
|
||||
return buffer.str();
|
||||
}
|
||||
|
||||
bool isInFocus(const QString &executable)
|
||||
void GetForegroundProcessName(QString &proc)
|
||||
{
|
||||
std::string temp;
|
||||
GetForegroundProcessName(temp);
|
||||
proc = QString::fromStdString(temp);
|
||||
}
|
||||
|
||||
void GetForegroundProcessName(std::string &proc)
|
||||
{
|
||||
proc.resize(0);
|
||||
auto pid = getForegroundProcessPid();
|
||||
std::string current = getProcNameFromPid(pid);
|
||||
}
|
||||
|
||||
bool isInFocus(const QString &executable)
|
||||
{
|
||||
std::string current;
|
||||
GetForegroundProcessName(current);
|
||||
|
||||
// True if executable switch equals current window
|
||||
bool equals = (executable.toStdString() == current);
|
||||
|
||||
@@ -67,6 +67,26 @@ bool MacroConditionDate::CheckDayOfWeek(int64_t msSinceLastCheck)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MacroConditionDate::CheckBetween(QDateTime &now)
|
||||
{
|
||||
// In the case of ignoring the date component treat the "left" value as
|
||||
// the start of the time range and the "right" value as the end
|
||||
if (_ignoreDate) {
|
||||
if (_dateTime2 >= _dateTime) {
|
||||
return now >= _dateTime && now <= _dateTime2;
|
||||
}
|
||||
// Assume that the end / start value should be shifted by 24h
|
||||
// as otherwise the condition would never be true
|
||||
return (now >= _dateTime && now <= _dateTime2.addDays(1)) ||
|
||||
(now >= _dateTime.addDays(-1) && now <= _dateTime2);
|
||||
}
|
||||
|
||||
if (_dateTime2 >= _dateTime) {
|
||||
return now >= _dateTime && now <= _dateTime2;
|
||||
}
|
||||
return now >= _dateTime2 && now <= _dateTime;
|
||||
}
|
||||
|
||||
bool MacroConditionDate::CheckRegularDate(int64_t msSinceLastCheck)
|
||||
{
|
||||
bool match = false;
|
||||
@@ -92,11 +112,7 @@ bool MacroConditionDate::CheckRegularDate(int64_t msSinceLastCheck)
|
||||
match = cur <= _dateTime;
|
||||
break;
|
||||
case DateCondition::BETWEEN:
|
||||
if (_dateTime2 > _dateTime) {
|
||||
match = cur >= _dateTime && cur <= _dateTime2;
|
||||
} else {
|
||||
match = cur >= _dateTime2 && cur <= _dateTime;
|
||||
}
|
||||
match = CheckBetween(cur);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -232,12 +248,12 @@ void MacroConditionDate::SetTime2(const QTime &time)
|
||||
|
||||
QDateTime MacroConditionDate::GetDateTime1()
|
||||
{
|
||||
return _updateOnRepeat ? _dateTime : _origDateTime;
|
||||
return _repeat && _updateOnRepeat ? _dateTime : _origDateTime;
|
||||
}
|
||||
|
||||
QDateTime MacroConditionDate::GetDateTime2()
|
||||
{
|
||||
return _updateOnRepeat ? _dateTime2 : _origDateTime2;
|
||||
return _repeat && _updateOnRepeat ? _dateTime2 : _origDateTime2;
|
||||
}
|
||||
|
||||
QDateTime MacroConditionDate::GetNextMatchDateTime()
|
||||
@@ -576,12 +592,12 @@ void MacroConditionDateEdit::UpdateEntryData()
|
||||
_dayOfWeek->setCurrentIndex(
|
||||
static_cast<int>(static_cast<int>(_entryData->_dayOfWeek)));
|
||||
_ignoreWeekTime->setChecked(!_entryData->_ignoreTime);
|
||||
_weekTime->setDateTime(_entryData->GetDateTime1());
|
||||
_weekTime->setTime(_entryData->GetDateTime1().time());
|
||||
_condition->setCurrentIndex(static_cast<int>(_entryData->_condition));
|
||||
_date->setDateTime(_entryData->GetDateTime1());
|
||||
_time->setDateTime(_entryData->GetDateTime1());
|
||||
_date2->setDateTime(_entryData->GetDateTime2());
|
||||
_time2->setDateTime(_entryData->GetDateTime2());
|
||||
_date->setDate(_entryData->GetDateTime1().date());
|
||||
_time->setTime(_entryData->GetDateTime1().time());
|
||||
_date2->setDate(_entryData->GetDateTime2().date());
|
||||
_time2->setTime(_entryData->GetDateTime2().time());
|
||||
_ignoreDate->setChecked(!_entryData->_ignoreDate);
|
||||
_ignoreTime->setChecked(!_entryData->_ignoreTime);
|
||||
_repeat->setChecked(_entryData->_repeat);
|
||||
|
||||
@@ -58,6 +58,7 @@ public:
|
||||
private:
|
||||
bool CheckDayOfWeek(int64_t);
|
||||
bool CheckRegularDate(int64_t);
|
||||
bool CheckBetween(QDateTime &now);
|
||||
|
||||
QDateTime _dateTime = QDateTime::currentDateTime();
|
||||
QDateTime _dateTime2 = QDateTime::currentDateTime();
|
||||
|
||||
@@ -10,39 +10,40 @@ bool MacroConditionMedia::_registered = MacroConditionFactory::Register(
|
||||
{MacroConditionMedia::Create, MacroConditionMediaEdit::Create,
|
||||
"AdvSceneSwitcher.condition.media"});
|
||||
|
||||
static std::map<MediaTimeRestriction, std::string> mediaTimeRestrictions = {
|
||||
{MediaTimeRestriction::TIME_RESTRICTION_NONE,
|
||||
static std::map<MacroConditionMedia::Time, std::string> mediaTimeRestrictions = {
|
||||
{MacroConditionMedia::Time::TIME_RESTRICTION_NONE,
|
||||
"AdvSceneSwitcher.mediaTab.timeRestriction.none"},
|
||||
{MediaTimeRestriction::TIME_RESTRICTION_SHORTER,
|
||||
{MacroConditionMedia::Time::TIME_RESTRICTION_SHORTER,
|
||||
"AdvSceneSwitcher.mediaTab.timeRestriction.shorter"},
|
||||
{MediaTimeRestriction::TIME_RESTRICTION_LONGER,
|
||||
{MacroConditionMedia::Time::TIME_RESTRICTION_LONGER,
|
||||
"AdvSceneSwitcher.mediaTab.timeRestriction.longer"},
|
||||
{MediaTimeRestriction::TIME_RESTRICTION_REMAINING_SHORTER,
|
||||
{MacroConditionMedia::Time::TIME_RESTRICTION_REMAINING_SHORTER,
|
||||
"AdvSceneSwitcher.mediaTab.timeRestriction.remainShorter"},
|
||||
{MediaTimeRestriction::TIME_RESTRICTION_REMAINING_LONGER,
|
||||
{MacroConditionMedia::Time::TIME_RESTRICTION_REMAINING_LONGER,
|
||||
"AdvSceneSwitcher.mediaTab.timeRestriction.remainLonger"},
|
||||
};
|
||||
|
||||
static std::map<MediaState, std::string> mediaStates = {
|
||||
{MediaState::OBS_MEDIA_STATE_NONE,
|
||||
static std::map<MacroConditionMedia::State, std::string> mediaStates = {
|
||||
{MacroConditionMedia::State::OBS_MEDIA_STATE_NONE,
|
||||
"AdvSceneSwitcher.mediaTab.states.none"},
|
||||
{MediaState::OBS_MEDIA_STATE_PLAYING,
|
||||
{MacroConditionMedia::State::OBS_MEDIA_STATE_PLAYING,
|
||||
"AdvSceneSwitcher.mediaTab.states.playing"},
|
||||
{MediaState::OBS_MEDIA_STATE_OPENING,
|
||||
{MacroConditionMedia::State::OBS_MEDIA_STATE_OPENING,
|
||||
"AdvSceneSwitcher.mediaTab.states.opening"},
|
||||
{MediaState::OBS_MEDIA_STATE_BUFFERING,
|
||||
{MacroConditionMedia::State::OBS_MEDIA_STATE_BUFFERING,
|
||||
"AdvSceneSwitcher.mediaTab.states.buffering"},
|
||||
{MediaState::OBS_MEDIA_STATE_PAUSED,
|
||||
{MacroConditionMedia::State::OBS_MEDIA_STATE_PAUSED,
|
||||
"AdvSceneSwitcher.mediaTab.states.paused"},
|
||||
{MediaState::OBS_MEDIA_STATE_STOPPED,
|
||||
{MacroConditionMedia::State::OBS_MEDIA_STATE_STOPPED,
|
||||
"AdvSceneSwitcher.mediaTab.states.stopped"},
|
||||
{MediaState::OBS_MEDIA_STATE_ENDED,
|
||||
{MacroConditionMedia::State::OBS_MEDIA_STATE_ENDED,
|
||||
"AdvSceneSwitcher.mediaTab.states.ended"},
|
||||
{MediaState::OBS_MEDIA_STATE_ERROR,
|
||||
{MacroConditionMedia::State::OBS_MEDIA_STATE_ERROR,
|
||||
"AdvSceneSwitcher.mediaTab.states.error"},
|
||||
{MediaState::PLAYLIST_ENDED,
|
||||
{MacroConditionMedia::State::PLAYLIST_ENDED,
|
||||
"AdvSceneSwitcher.mediaTab.states.playlistEnd"},
|
||||
{MediaState::ANY, "AdvSceneSwitcher.mediaTab.states.any"},
|
||||
{MacroConditionMedia::State::ANY,
|
||||
"AdvSceneSwitcher.mediaTab.states.any"},
|
||||
};
|
||||
|
||||
MacroConditionMedia::~MacroConditionMedia()
|
||||
@@ -65,20 +66,20 @@ bool MacroConditionMedia::CheckTime()
|
||||
bool match = false;
|
||||
|
||||
switch (_restriction) {
|
||||
case MediaTimeRestriction::TIME_RESTRICTION_NONE:
|
||||
case Time::TIME_RESTRICTION_NONE:
|
||||
match = true;
|
||||
break;
|
||||
case MediaTimeRestriction::TIME_RESTRICTION_SHORTER:
|
||||
case Time::TIME_RESTRICTION_SHORTER:
|
||||
match = currentTime < _time.seconds * 1000;
|
||||
break;
|
||||
case MediaTimeRestriction::TIME_RESTRICTION_LONGER:
|
||||
case Time::TIME_RESTRICTION_LONGER:
|
||||
match = currentTime > _time.seconds * 1000;
|
||||
break;
|
||||
case MediaTimeRestriction::TIME_RESTRICTION_REMAINING_SHORTER:
|
||||
case Time::TIME_RESTRICTION_REMAINING_SHORTER:
|
||||
match = duration > currentTime &&
|
||||
duration - currentTime < _time.seconds * 1000;
|
||||
break;
|
||||
case MediaTimeRestriction::TIME_RESTRICTION_REMAINING_LONGER:
|
||||
case Time::TIME_RESTRICTION_REMAINING_LONGER:
|
||||
match = duration > currentTime &&
|
||||
duration - currentTime > _time.seconds * 1000;
|
||||
break;
|
||||
@@ -100,24 +101,24 @@ bool MacroConditionMedia::CheckState()
|
||||
int expectedState = static_cast<int>(_state);
|
||||
|
||||
switch (_state) {
|
||||
case MediaState::OBS_MEDIA_STATE_STOPPED:
|
||||
case State::OBS_MEDIA_STATE_STOPPED:
|
||||
match = _stopped || currentState == OBS_MEDIA_STATE_STOPPED;
|
||||
break;
|
||||
case MediaState::OBS_MEDIA_STATE_ENDED:
|
||||
case State::OBS_MEDIA_STATE_ENDED:
|
||||
match = _ended || currentState == OBS_MEDIA_STATE_ENDED;
|
||||
break;
|
||||
case MediaState::PLAYLIST_ENDED:
|
||||
case State::PLAYLIST_ENDED:
|
||||
match = CheckPlaylistEnd(currentState);
|
||||
break;
|
||||
case MediaState::ANY:
|
||||
case State::ANY:
|
||||
match = true;
|
||||
break;
|
||||
case MediaState::OBS_MEDIA_STATE_NONE:
|
||||
case MediaState::OBS_MEDIA_STATE_PLAYING:
|
||||
case MediaState::OBS_MEDIA_STATE_OPENING:
|
||||
case MediaState::OBS_MEDIA_STATE_BUFFERING:
|
||||
case MediaState::OBS_MEDIA_STATE_PAUSED:
|
||||
case MediaState::OBS_MEDIA_STATE_ERROR:
|
||||
case State::OBS_MEDIA_STATE_NONE:
|
||||
case State::OBS_MEDIA_STATE_PLAYING:
|
||||
case State::OBS_MEDIA_STATE_OPENING:
|
||||
case State::OBS_MEDIA_STATE_BUFFERING:
|
||||
case State::OBS_MEDIA_STATE_PAUSED:
|
||||
case State::OBS_MEDIA_STATE_ERROR:
|
||||
match = currentState == expectedState;
|
||||
break;
|
||||
default:
|
||||
@@ -148,7 +149,7 @@ bool MacroConditionMedia::CheckMediaMatch()
|
||||
bool match = false;
|
||||
bool matched = CheckState() && CheckTime();
|
||||
|
||||
if (matched && !(_onlyMatchonChagne && _alreadyMatched)) {
|
||||
if (matched && !(_onlyMatchOnChagne && _alreadyMatched)) {
|
||||
match = true;
|
||||
}
|
||||
_alreadyMatched = matched;
|
||||
@@ -161,16 +162,22 @@ bool MacroConditionMedia::CheckMediaMatch()
|
||||
return match;
|
||||
}
|
||||
|
||||
void MacroConditionMedia::HandleSceneChange()
|
||||
{
|
||||
UpdateMediaSourcesOfSceneList();
|
||||
_lastConfigureScene = switcher->currentScene;
|
||||
}
|
||||
|
||||
bool MacroConditionMedia::CheckCondition()
|
||||
{
|
||||
bool match = false;
|
||||
switch (_sourceType) {
|
||||
case MediaSourceType::ANY:
|
||||
case Type::ANY:
|
||||
for (auto &source : _sources) {
|
||||
match = match || source.CheckCondition();
|
||||
}
|
||||
break;
|
||||
case MediaSourceType::ALL: {
|
||||
case Type::ALL: {
|
||||
bool res = true;
|
||||
for (auto &source : _sources) {
|
||||
res = res && source.CheckCondition();
|
||||
@@ -178,12 +185,17 @@ bool MacroConditionMedia::CheckCondition()
|
||||
match = res;
|
||||
break;
|
||||
}
|
||||
case MediaSourceType::SOURCE:
|
||||
case Type::SOURCE:
|
||||
match = CheckMediaMatch();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (_lastConfigureScene != switcher->currentScene) {
|
||||
HandleSceneChange();
|
||||
}
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
@@ -196,7 +208,7 @@ bool MacroConditionMedia::Save(obs_data_t *obj)
|
||||
obs_data_set_int(obj, "state", static_cast<int>(_state));
|
||||
obs_data_set_int(obj, "restriction", static_cast<int>(_restriction));
|
||||
_time.Save(obj);
|
||||
obs_data_set_bool(obj, "matchOnChagne", _onlyMatchonChagne);
|
||||
obs_data_set_bool(obj, "matchOnChagne", _onlyMatchOnChagne);
|
||||
obs_data_set_int(obj, "version", 0);
|
||||
return true;
|
||||
}
|
||||
@@ -222,22 +234,24 @@ static bool enumSceneItem(obs_scene_t *, obs_sceneitem_t *item, void *ptr)
|
||||
return true;
|
||||
}
|
||||
|
||||
void forMediaSourceOnSceneAddMediaCondition(
|
||||
OBSWeakSource sceneWeakSource, MacroConditionMedia *origCond,
|
||||
std::vector<MacroConditionMedia> &conditions)
|
||||
void MacroConditionMedia::UpdateMediaSourcesOfSceneList()
|
||||
{
|
||||
conditions.clear();
|
||||
_sources.clear();
|
||||
if (!_scene.GetScene(false)) {
|
||||
return;
|
||||
}
|
||||
std::vector<OBSWeakSource> mediaSources;
|
||||
auto s = obs_weak_source_get_source(sceneWeakSource);
|
||||
auto s = obs_weak_source_get_source(_scene.GetScene(false));
|
||||
auto scene = obs_scene_from_source(s);
|
||||
obs_scene_enum_items(scene, enumSceneItem, &mediaSources);
|
||||
obs_source_release(s);
|
||||
_sources.reserve(mediaSources.size());
|
||||
|
||||
for (auto &source : mediaSources) {
|
||||
MacroConditionMedia cond(*origCond);
|
||||
cond._sourceType = MediaSourceType::SOURCE;
|
||||
MacroConditionMedia cond(*this);
|
||||
cond._sourceType = Type::SOURCE;
|
||||
cond._source = source;
|
||||
conditions.push_back(cond);
|
||||
_sources.push_back(cond);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,15 +261,15 @@ bool MacroConditionMedia::Load(obs_data_t *obj)
|
||||
const char *sourceName = obs_data_get_string(obj, "source");
|
||||
_source = GetWeakSourceByName(sourceName);
|
||||
_scene.Load(obj);
|
||||
_sourceType = static_cast<MediaSourceType>(
|
||||
obs_data_get_int(obj, "sourceType"));
|
||||
_state = static_cast<MediaState>(obs_data_get_int(obj, "state"));
|
||||
_restriction = static_cast<MediaTimeRestriction>(
|
||||
_sourceType = static_cast<Type>(obs_data_get_int(obj, "sourceType"));
|
||||
_state = static_cast<MacroConditionMedia::State>(
|
||||
obs_data_get_int(obj, "state"));
|
||||
_restriction = static_cast<MacroConditionMedia::Time>(
|
||||
obs_data_get_int(obj, "restriction"));
|
||||
_time.Load(obj);
|
||||
_onlyMatchonChagne = obs_data_get_bool(obj, "matchOnChagne");
|
||||
_onlyMatchOnChagne = obs_data_get_bool(obj, "matchOnChagne");
|
||||
|
||||
if (_sourceType == MediaSourceType::SOURCE) {
|
||||
if (_sourceType == Type::SOURCE) {
|
||||
obs_source_t *mediasource = obs_weak_source_get_source(_source);
|
||||
signal_handler_t *sh =
|
||||
obs_source_get_signal_handler(mediasource);
|
||||
@@ -265,11 +279,11 @@ bool MacroConditionMedia::Load(obs_data_t *obj)
|
||||
obs_source_release(mediasource);
|
||||
}
|
||||
|
||||
forMediaSourceOnSceneAddMediaCondition(_scene.GetScene(), this,
|
||||
_sources);
|
||||
UpdateMediaSourcesOfSceneList();
|
||||
if (!obs_data_has_user_value(obj, "version")) {
|
||||
if (_state == MediaState::OBS_MEDIA_STATE_ENDED) {
|
||||
_state = MediaState::PLAYLIST_ENDED;
|
||||
if (_state ==
|
||||
MacroConditionMedia::State::OBS_MEDIA_STATE_ENDED) {
|
||||
_state = MacroConditionMedia::State::PLAYLIST_ENDED;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@@ -278,20 +292,20 @@ bool MacroConditionMedia::Load(obs_data_t *obj)
|
||||
std::string MacroConditionMedia::GetShortDesc()
|
||||
{
|
||||
switch (_sourceType) {
|
||||
case MediaSourceType::SOURCE:
|
||||
case Type::SOURCE:
|
||||
if (_source) {
|
||||
return GetWeakSourceName(_source);
|
||||
}
|
||||
break;
|
||||
case MediaSourceType::ANY:
|
||||
if (_scene.GetScene()) {
|
||||
case Type::ANY:
|
||||
if (_scene.GetScene(false)) {
|
||||
return obs_module_text(
|
||||
"AdvSceneSwitcher.condition.media.anyOnScene") +
|
||||
std::string(" ") + _scene.ToString();
|
||||
}
|
||||
break;
|
||||
case MediaSourceType::ALL:
|
||||
if (_scene.GetScene()) {
|
||||
case Type::ALL:
|
||||
if (_scene.GetScene(false)) {
|
||||
return obs_module_text(
|
||||
"AdvSceneSwitcher.condition.media.allOnScene") +
|
||||
std::string(" ") + _scene.ToString();
|
||||
@@ -356,7 +370,7 @@ void MacroConditionMedia::MediaNext(void *data, calldata_t *)
|
||||
media->_next = true;
|
||||
}
|
||||
|
||||
static void populateMediaTimeRestrictions(QComboBox *list)
|
||||
static void populateMediaTimes(QComboBox *list)
|
||||
{
|
||||
for (auto entry : mediaTimeRestrictions) {
|
||||
list->addItem(obs_module_text(entry.second.c_str()));
|
||||
@@ -383,7 +397,8 @@ static void addAnyAndAllStates(QComboBox *list)
|
||||
MacroConditionMediaEdit::MacroConditionMediaEdit(
|
||||
QWidget *parent, std::shared_ptr<MacroConditionMedia> entryData)
|
||||
: QWidget(parent),
|
||||
_scenes(new SceneSelectionWidget(window())),
|
||||
_scenes(new SceneSelectionWidget(window(), true, true, true, true,
|
||||
true)),
|
||||
_mediaSources(new QComboBox()),
|
||||
_states(new QComboBox()),
|
||||
_timeRestrictions(new QComboBox()),
|
||||
@@ -414,7 +429,7 @@ MacroConditionMediaEdit::MacroConditionMediaEdit(
|
||||
populateMediaSelection(_mediaSources);
|
||||
addAnyAndAllStates(_mediaSources);
|
||||
populateMediaStates(_states);
|
||||
populateMediaTimeRestrictions(_timeRestrictions);
|
||||
populateMediaTimes(_timeRestrictions);
|
||||
|
||||
QHBoxLayout *entryLayout = new QHBoxLayout;
|
||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
@@ -446,14 +461,14 @@ void MacroConditionMediaEdit::SourceChanged(const QString &text)
|
||||
|
||||
if (text ==
|
||||
obs_module_text("AdvSceneSwitcher.condition.media.anyOnScene")) {
|
||||
_entryData->_sourceType = MediaSourceType::ANY;
|
||||
_entryData->_sourceType = MacroConditionMedia::Type::ANY;
|
||||
} else if (text ==
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.condition.media.allOnScene")) {
|
||||
_entryData->_sourceType = MediaSourceType::ALL;
|
||||
_entryData->_sourceType = MacroConditionMedia::Type::ALL;
|
||||
} else {
|
||||
_entryData->_sources.clear();
|
||||
_entryData->_sourceType = MediaSourceType::SOURCE;
|
||||
_entryData->_sourceType = MacroConditionMedia::Type::SOURCE;
|
||||
}
|
||||
|
||||
_entryData->ClearSignalHandler();
|
||||
@@ -473,21 +488,21 @@ void MacroConditionMediaEdit::SceneChanged(const SceneSelection &s)
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
_entryData->_scene = s;
|
||||
forMediaSourceOnSceneAddMediaCondition(_entryData->_scene.GetScene(),
|
||||
_entryData.get(),
|
||||
_entryData->_sources);
|
||||
_entryData->UpdateMediaSourcesOfSceneList();
|
||||
emit HeaderInfoChanged(
|
||||
QString::fromStdString(_entryData->GetShortDesc()));
|
||||
}
|
||||
|
||||
MediaState getMediaStateFromIdx(int idx)
|
||||
MacroConditionMedia::State getMediaStateFromIdx(int idx)
|
||||
{
|
||||
if (idx < static_cast<int>(MediaState::LAST_OBS_MEDIA_STATE)) {
|
||||
return static_cast<MediaState>(idx);
|
||||
if (idx < static_cast<int>(
|
||||
MacroConditionMedia::State::LAST_OBS_MEDIA_STATE)) {
|
||||
return static_cast<MacroConditionMedia::State>(idx);
|
||||
} else {
|
||||
return static_cast<MediaState>(
|
||||
return static_cast<MacroConditionMedia::State>(
|
||||
idx -
|
||||
static_cast<int>(MediaState::LAST_OBS_MEDIA_STATE) +
|
||||
static_cast<int>(
|
||||
MacroConditionMedia::State::LAST_OBS_MEDIA_STATE) +
|
||||
custom_media_states_offset);
|
||||
}
|
||||
}
|
||||
@@ -500,10 +515,8 @@ void MacroConditionMediaEdit::StateChanged(int index)
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
_entryData->_state = getMediaStateFromIdx(index);
|
||||
if (_entryData->_sourceType != MediaSourceType::SOURCE) {
|
||||
forMediaSourceOnSceneAddMediaCondition(
|
||||
_entryData->_scene.GetScene(), _entryData.get(),
|
||||
_entryData->_sources);
|
||||
if (_entryData->_sourceType != MacroConditionMedia::Type::SOURCE) {
|
||||
_entryData->UpdateMediaSourcesOfSceneList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -513,19 +526,18 @@ void MacroConditionMediaEdit::TimeRestrictionChanged(int index)
|
||||
return;
|
||||
}
|
||||
|
||||
if (static_cast<MediaTimeRestriction>(index) ==
|
||||
MediaTimeRestriction::TIME_RESTRICTION_NONE) {
|
||||
if (static_cast<MacroConditionMedia::Time>(index) ==
|
||||
MacroConditionMedia::Time::TIME_RESTRICTION_NONE) {
|
||||
_time->setDisabled(true);
|
||||
} else {
|
||||
_time->setDisabled(false);
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
_entryData->_restriction = static_cast<MediaTimeRestriction>(index);
|
||||
if (_entryData->_sourceType != MediaSourceType::SOURCE) {
|
||||
forMediaSourceOnSceneAddMediaCondition(
|
||||
_entryData->_scene.GetScene(), _entryData.get(),
|
||||
_entryData->_sources);
|
||||
_entryData->_restriction =
|
||||
static_cast<MacroConditionMedia::Time>(index);
|
||||
if (_entryData->_sourceType != MacroConditionMedia::Type::SOURCE) {
|
||||
_entryData->UpdateMediaSourcesOfSceneList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -537,10 +549,8 @@ void MacroConditionMediaEdit::TimeChanged(double seconds)
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
_entryData->_time.seconds = seconds;
|
||||
if (_entryData->_sourceType != MediaSourceType::SOURCE) {
|
||||
forMediaSourceOnSceneAddMediaCondition(
|
||||
_entryData->_scene.GetScene(), _entryData.get(),
|
||||
_entryData->_sources);
|
||||
if (_entryData->_sourceType != MacroConditionMedia::Type::SOURCE) {
|
||||
_entryData->UpdateMediaSourcesOfSceneList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -552,10 +562,8 @@ void MacroConditionMediaEdit::TimeUnitChanged(DurationUnit unit)
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
_entryData->_time.displayUnit = unit;
|
||||
if (_entryData->_sourceType != MediaSourceType::SOURCE) {
|
||||
forMediaSourceOnSceneAddMediaCondition(
|
||||
_entryData->_scene.GetScene(), _entryData.get(),
|
||||
_entryData->_sources);
|
||||
if (_entryData->_sourceType != MacroConditionMedia::Type::SOURCE) {
|
||||
_entryData->UpdateMediaSourcesOfSceneList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -566,29 +574,29 @@ void MacroConditionMediaEdit::OnChangeChanged(int value)
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
_entryData->_onlyMatchonChagne = value;
|
||||
if (_entryData->_sourceType != MediaSourceType::SOURCE) {
|
||||
forMediaSourceOnSceneAddMediaCondition(
|
||||
_entryData->_scene.GetScene(), _entryData.get(),
|
||||
_entryData->_sources);
|
||||
_entryData->_onlyMatchOnChagne = value;
|
||||
if (_entryData->_sourceType != MacroConditionMedia::Type::SOURCE) {
|
||||
_entryData->UpdateMediaSourcesOfSceneList();
|
||||
}
|
||||
}
|
||||
|
||||
void MacroConditionMediaEdit::SetWidgetVisibility()
|
||||
{
|
||||
_scenes->setVisible(_entryData->_sourceType != MediaSourceType::SOURCE);
|
||||
_scenes->setVisible(_entryData->_sourceType !=
|
||||
MacroConditionMedia::Type::SOURCE);
|
||||
if (!_onChange->isChecked()) {
|
||||
_onChange->hide();
|
||||
}
|
||||
}
|
||||
|
||||
int getIdxFromMediaState(MediaState state)
|
||||
int getIdxFromMediaState(MacroConditionMedia::State state)
|
||||
{
|
||||
if (state < MediaState::LAST_OBS_MEDIA_STATE) {
|
||||
if (state < MacroConditionMedia::State::LAST_OBS_MEDIA_STATE) {
|
||||
return static_cast<int>(state);
|
||||
} else {
|
||||
return static_cast<int>(state) - custom_media_states_offset +
|
||||
static_cast<int>(MediaState::LAST_OBS_MEDIA_STATE);
|
||||
static_cast<int>(
|
||||
MacroConditionMedia::State::LAST_OBS_MEDIA_STATE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -599,15 +607,15 @@ void MacroConditionMediaEdit::UpdateEntryData()
|
||||
}
|
||||
|
||||
switch (_entryData->_sourceType) {
|
||||
case MediaSourceType::ANY:
|
||||
case MacroConditionMedia::Type::ANY:
|
||||
_mediaSources->setCurrentText(obs_module_text(
|
||||
"AdvSceneSwitcher.condition.media.anyOnScene"));
|
||||
break;
|
||||
case MediaSourceType::ALL:
|
||||
case MacroConditionMedia::Type::ALL:
|
||||
_mediaSources->setCurrentText(obs_module_text(
|
||||
"AdvSceneSwitcher.condition.media.allOnScene"));
|
||||
break;
|
||||
case MediaSourceType::SOURCE:
|
||||
case MacroConditionMedia::Type::SOURCE:
|
||||
_mediaSources->setCurrentText(
|
||||
GetWeakSourceName(_entryData->_source).c_str());
|
||||
break;
|
||||
@@ -621,9 +629,9 @@ void MacroConditionMediaEdit::UpdateEntryData()
|
||||
static_cast<int>(_entryData->_restriction));
|
||||
_time->SetDuration(_entryData->_time);
|
||||
if (_entryData->_restriction ==
|
||||
MediaTimeRestriction::TIME_RESTRICTION_NONE) {
|
||||
MacroConditionMedia::Time::TIME_RESTRICTION_NONE) {
|
||||
_time->setDisabled(true);
|
||||
}
|
||||
_onChange->setChecked(_entryData->_onlyMatchonChagne);
|
||||
_onChange->setChecked(_entryData->_onlyMatchOnChagne);
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
@@ -8,39 +8,8 @@
|
||||
#include "duration-control.hpp"
|
||||
#include "scene-selection.hpp"
|
||||
|
||||
enum class MediaTimeRestriction {
|
||||
TIME_RESTRICTION_NONE,
|
||||
TIME_RESTRICTION_SHORTER,
|
||||
TIME_RESTRICTION_LONGER,
|
||||
TIME_RESTRICTION_REMAINING_SHORTER,
|
||||
TIME_RESTRICTION_REMAINING_LONGER,
|
||||
};
|
||||
|
||||
constexpr auto custom_media_states_offset = 100;
|
||||
|
||||
enum class MediaState {
|
||||
// OBS's internal states
|
||||
OBS_MEDIA_STATE_NONE,
|
||||
OBS_MEDIA_STATE_PLAYING,
|
||||
OBS_MEDIA_STATE_OPENING,
|
||||
OBS_MEDIA_STATE_BUFFERING,
|
||||
OBS_MEDIA_STATE_PAUSED,
|
||||
OBS_MEDIA_STATE_STOPPED,
|
||||
OBS_MEDIA_STATE_ENDED,
|
||||
OBS_MEDIA_STATE_ERROR,
|
||||
// Just a marker
|
||||
LAST_OBS_MEDIA_STATE,
|
||||
// states added for use in the plugin
|
||||
PLAYLIST_ENDED = custom_media_states_offset,
|
||||
ANY,
|
||||
};
|
||||
|
||||
enum class MediaSourceType {
|
||||
SOURCE,
|
||||
ANY,
|
||||
ALL,
|
||||
};
|
||||
|
||||
class MacroConditionMedia : public MacroCondition {
|
||||
public:
|
||||
MacroConditionMedia(Macro *m) : MacroCondition(m) {}
|
||||
@@ -56,25 +25,57 @@ public:
|
||||
}
|
||||
void ClearSignalHandler();
|
||||
void ResetSignalHandler();
|
||||
void UpdateMediaSourcesOfSceneList();
|
||||
static void MediaStopped(void *data, calldata_t *);
|
||||
static void MediaEnded(void *data, calldata_t *);
|
||||
static void MediaNext(void *data, calldata_t *);
|
||||
|
||||
MediaSourceType _sourceType = MediaSourceType::SOURCE;
|
||||
enum class Type {
|
||||
SOURCE,
|
||||
ANY,
|
||||
ALL,
|
||||
};
|
||||
Type _sourceType = Type::SOURCE;
|
||||
|
||||
enum class State {
|
||||
// OBS's internal states
|
||||
OBS_MEDIA_STATE_NONE,
|
||||
OBS_MEDIA_STATE_PLAYING,
|
||||
OBS_MEDIA_STATE_OPENING,
|
||||
OBS_MEDIA_STATE_BUFFERING,
|
||||
OBS_MEDIA_STATE_PAUSED,
|
||||
OBS_MEDIA_STATE_STOPPED,
|
||||
OBS_MEDIA_STATE_ENDED,
|
||||
OBS_MEDIA_STATE_ERROR,
|
||||
// Just a marker
|
||||
LAST_OBS_MEDIA_STATE,
|
||||
// states added for use in the plugin
|
||||
PLAYLIST_ENDED = custom_media_states_offset,
|
||||
ANY,
|
||||
};
|
||||
State _state = State::OBS_MEDIA_STATE_NONE;
|
||||
|
||||
enum class Time {
|
||||
TIME_RESTRICTION_NONE,
|
||||
TIME_RESTRICTION_SHORTER,
|
||||
TIME_RESTRICTION_LONGER,
|
||||
TIME_RESTRICTION_REMAINING_SHORTER,
|
||||
TIME_RESTRICTION_REMAINING_LONGER,
|
||||
};
|
||||
Time _restriction = Time::TIME_RESTRICTION_NONE;
|
||||
|
||||
SceneSelection _scene;
|
||||
OBSWeakSource _source = nullptr;
|
||||
std::vector<MacroConditionMedia> _sources;
|
||||
MediaState _state = MediaState::OBS_MEDIA_STATE_NONE;
|
||||
MediaTimeRestriction _restriction =
|
||||
MediaTimeRestriction::TIME_RESTRICTION_NONE;
|
||||
Duration _time;
|
||||
bool _onlyMatchonChagne = false;
|
||||
bool _onlyMatchOnChagne = false;
|
||||
|
||||
private:
|
||||
bool CheckTime();
|
||||
bool CheckState();
|
||||
bool CheckPlaylistEnd(const obs_media_state);
|
||||
bool CheckMediaMatch();
|
||||
void HandleSceneChange();
|
||||
|
||||
bool _stopped = false;
|
||||
bool _ended = false;
|
||||
@@ -84,6 +85,8 @@ private:
|
||||
bool _alreadyMatched = false;
|
||||
// Workaround to enable use of "ended" to specify end of VLC playlist
|
||||
bool _previousStateEnded = false;
|
||||
// Used to keep track of scene changes
|
||||
OBSWeakSource _lastConfigureScene;
|
||||
|
||||
static bool _registered;
|
||||
static const std::string id;
|
||||
|
||||
@@ -48,36 +48,48 @@ std::string MacroConditionProcess::GetShortDesc()
|
||||
|
||||
MacroConditionProcessEdit::MacroConditionProcessEdit(
|
||||
QWidget *parent, std::shared_ptr<MacroConditionProcess> entryData)
|
||||
: QWidget(parent)
|
||||
: QWidget(parent),
|
||||
_processSelection(new QComboBox()),
|
||||
_focused(new QCheckBox()),
|
||||
_focusProcess(new QLabel()),
|
||||
_focusLayout(new QHBoxLayout())
|
||||
{
|
||||
_processSelection = new QComboBox();
|
||||
_processSelection->setEditable(true);
|
||||
_processSelection->setMaxVisibleItems(20);
|
||||
|
||||
_focused = new QCheckBox();
|
||||
|
||||
QWidget::connect(_processSelection,
|
||||
SIGNAL(currentTextChanged(const QString &)), this,
|
||||
SLOT(ProcessChanged(const QString &)));
|
||||
QWidget::connect(_focused, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(FocusChanged(int)));
|
||||
QWidget::connect(&_timer, SIGNAL(timeout()), this,
|
||||
SLOT(UpdateFocusProcess()));
|
||||
|
||||
populateProcessSelection(_processSelection);
|
||||
|
||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{processes}}", _processSelection},
|
||||
{"{{focused}}", _focused},
|
||||
{"{{focusProcess}}", _focusProcess},
|
||||
};
|
||||
|
||||
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||
auto entryLayout = new QHBoxLayout;
|
||||
placeWidgets(
|
||||
obs_module_text("AdvSceneSwitcher.condition.process.entry"),
|
||||
mainLayout, widgetPlaceholders);
|
||||
entryLayout, widgetPlaceholders);
|
||||
placeWidgets(obs_module_text(
|
||||
"AdvSceneSwitcher.condition.process.entry.focus"),
|
||||
_focusLayout, widgetPlaceholders);
|
||||
auto mainLayout = new QVBoxLayout;
|
||||
mainLayout->addLayout(entryLayout);
|
||||
mainLayout->addLayout(_focusLayout);
|
||||
setLayout(mainLayout);
|
||||
|
||||
_entryData = entryData;
|
||||
UpdateEntryData();
|
||||
_loading = false;
|
||||
|
||||
_timer.start(1000);
|
||||
}
|
||||
|
||||
void MacroConditionProcessEdit::ProcessChanged(const QString &text)
|
||||
@@ -100,6 +112,22 @@ void MacroConditionProcessEdit::FocusChanged(int state)
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
_entryData->_focus = state;
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroConditionProcessEdit::UpdateFocusProcess()
|
||||
{
|
||||
_focusProcess->setText(
|
||||
QString::fromStdString(switcher->currentForegroundProcess));
|
||||
}
|
||||
|
||||
void MacroConditionProcessEdit::SetWidgetVisibility()
|
||||
{
|
||||
if (!_entryData) {
|
||||
return;
|
||||
}
|
||||
setLayoutVisible(_focusLayout, _entryData->_focus);
|
||||
adjustSize();
|
||||
}
|
||||
|
||||
void MacroConditionProcessEdit::UpdateEntryData()
|
||||
@@ -110,4 +138,5 @@ void MacroConditionProcessEdit::UpdateEntryData()
|
||||
|
||||
_processSelection->setCurrentText(_entryData->_process.c_str());
|
||||
_focused->setChecked(_entryData->_focus);
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
@@ -44,14 +44,20 @@ public:
|
||||
private slots:
|
||||
void ProcessChanged(const QString &text);
|
||||
void FocusChanged(int state);
|
||||
void UpdateFocusProcess();
|
||||
signals:
|
||||
void HeaderInfoChanged(const QString &);
|
||||
|
||||
protected:
|
||||
QComboBox *_processSelection;
|
||||
QCheckBox *_focused;
|
||||
QLabel *_focusProcess;
|
||||
QHBoxLayout *_focusLayout;
|
||||
QTimer _timer;
|
||||
std::shared_ptr<MacroConditionProcess> _entryData;
|
||||
|
||||
private:
|
||||
void SetWidgetVisibility();
|
||||
|
||||
bool _loading = true;
|
||||
};
|
||||
|
||||
@@ -13,7 +13,7 @@ bool MacroConditionWindow::_registered = MacroConditionFactory::Register(
|
||||
"AdvSceneSwitcher.condition.window"});
|
||||
|
||||
bool MacroConditionWindow::CheckWindowTitleSwitchDirect(
|
||||
std::string ¤tWindowTitle)
|
||||
const std::string ¤tWindowTitle)
|
||||
{
|
||||
bool focus = (!_focus || _window == currentWindowTitle);
|
||||
bool fullscreen = (!_fullscreen || isFullscreen(_window));
|
||||
@@ -23,7 +23,8 @@ bool MacroConditionWindow::CheckWindowTitleSwitchDirect(
|
||||
}
|
||||
|
||||
bool MacroConditionWindow::CheckWindowTitleSwitchRegex(
|
||||
std::string ¤tWindowTitle, std::vector<std::string> &windowList)
|
||||
const std::string ¤tWindowTitle,
|
||||
const std::vector<std::string> &windowList)
|
||||
{
|
||||
bool match = false;
|
||||
for (auto &window : windowList) {
|
||||
@@ -54,7 +55,7 @@ bool foregroundWindowChanged()
|
||||
|
||||
bool MacroConditionWindow::CheckCondition()
|
||||
{
|
||||
std::string currentWindowTitle = switcher->currentTitle;
|
||||
const std::string ¤tWindowTitle = switcher->currentTitle;
|
||||
std::vector<std::string> windowList;
|
||||
GetWindowList(windowList);
|
||||
|
||||
@@ -101,17 +102,18 @@ std::string MacroConditionWindow::GetShortDesc()
|
||||
|
||||
MacroConditionWindowEdit::MacroConditionWindowEdit(
|
||||
QWidget *parent, std::shared_ptr<MacroConditionWindow> entryData)
|
||||
: QWidget(parent)
|
||||
: QWidget(parent),
|
||||
_windowSelection(new QComboBox()),
|
||||
_fullscreen(new QCheckBox()),
|
||||
_maximized(new QCheckBox()),
|
||||
_focused(new QCheckBox()),
|
||||
_windowFocusChanged(new QCheckBox()),
|
||||
_focusWindow(new QLabel()),
|
||||
_focusLayout(new QHBoxLayout())
|
||||
{
|
||||
_windowSelection = new QComboBox();
|
||||
_windowSelection->setEditable(true);
|
||||
_windowSelection->setMaxVisibleItems(20);
|
||||
|
||||
_fullscreen = new QCheckBox();
|
||||
_maximized = new QCheckBox();
|
||||
_focused = new QCheckBox();
|
||||
_windowFocusChanged = new QCheckBox();
|
||||
|
||||
QWidget::connect(_windowSelection,
|
||||
SIGNAL(currentTextChanged(const QString &)), this,
|
||||
SLOT(WindowChanged(const QString &)));
|
||||
@@ -123,6 +125,8 @@ MacroConditionWindowEdit::MacroConditionWindowEdit(
|
||||
SLOT(FocusedChanged(int)));
|
||||
QWidget::connect(_windowFocusChanged, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(WindowFocusChanged(int)));
|
||||
QWidget::connect(&_timer, SIGNAL(timeout()), this,
|
||||
SLOT(UpdateFocusWindow()));
|
||||
|
||||
populateWindowSelection(_windowSelection);
|
||||
|
||||
@@ -132,24 +136,31 @@ MacroConditionWindowEdit::MacroConditionWindowEdit(
|
||||
{"{{maximized}}", _maximized},
|
||||
{"{{focused}}", _focused},
|
||||
{"{{windowFocusChanged}}", _windowFocusChanged},
|
||||
{"{{focusWindow}}", _focusWindow},
|
||||
};
|
||||
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||
QHBoxLayout *line1Layout = new QHBoxLayout;
|
||||
QHBoxLayout *line2Layout = new QHBoxLayout;
|
||||
auto *line1Layout = new QHBoxLayout;
|
||||
placeWidgets(obs_module_text(
|
||||
"AdvSceneSwitcher.condition.window.entry.line1"),
|
||||
line1Layout, widgetPlaceholders);
|
||||
auto *line2Layout = new QHBoxLayout;
|
||||
placeWidgets(obs_module_text(
|
||||
"AdvSceneSwitcher.condition.window.entry.line2"),
|
||||
line2Layout, widgetPlaceholders);
|
||||
placeWidgets(obs_module_text(
|
||||
"AdvSceneSwitcher.condition.window.entry.line3"),
|
||||
_focusLayout, widgetPlaceholders);
|
||||
auto *mainLayout = new QVBoxLayout;
|
||||
mainLayout->addLayout(line1Layout);
|
||||
mainLayout->addLayout(line2Layout);
|
||||
mainLayout->addLayout(_focusLayout);
|
||||
setLayout(mainLayout);
|
||||
|
||||
_entryData = entryData;
|
||||
UpdateEntryData();
|
||||
_loading = false;
|
||||
|
||||
_timer.start(1000);
|
||||
}
|
||||
|
||||
void MacroConditionWindowEdit::WindowChanged(const QString &text)
|
||||
@@ -192,6 +203,7 @@ void MacroConditionWindowEdit::FocusedChanged(int state)
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
_entryData->_focus = state;
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroConditionWindowEdit::WindowFocusChanged(int state)
|
||||
@@ -202,6 +214,22 @@ void MacroConditionWindowEdit::WindowFocusChanged(int state)
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
_entryData->_windowFocusChanged = state;
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroConditionWindowEdit::UpdateFocusWindow()
|
||||
{
|
||||
_focusWindow->setText(QString::fromStdString(switcher->currentTitle));
|
||||
}
|
||||
|
||||
void MacroConditionWindowEdit::SetWidgetVisibility()
|
||||
{
|
||||
if (!_entryData) {
|
||||
return;
|
||||
}
|
||||
setLayoutVisible(_focusLayout,
|
||||
_entryData->_focus || _entryData->_windowFocusChanged);
|
||||
adjustSize();
|
||||
}
|
||||
|
||||
void MacroConditionWindowEdit::UpdateEntryData()
|
||||
@@ -215,4 +243,5 @@ void MacroConditionWindowEdit::UpdateEntryData()
|
||||
_maximized->setChecked(_entryData->_maximized);
|
||||
_focused->setChecked(_entryData->_focus);
|
||||
_windowFocusChanged->setChecked(_entryData->_windowFocusChanged);
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
@@ -18,9 +18,11 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
bool CheckWindowTitleSwitchDirect(std::string ¤tWindowTitle);
|
||||
bool CheckWindowTitleSwitchRegex(std::string ¤tWindowTitle,
|
||||
std::vector<std::string> &windowList);
|
||||
bool
|
||||
CheckWindowTitleSwitchDirect(const std::string ¤tWindowTitle);
|
||||
bool
|
||||
CheckWindowTitleSwitchRegex(const std::string ¤tWindowTitle,
|
||||
const std::vector<std::string> &windowList);
|
||||
|
||||
public:
|
||||
std::string _window;
|
||||
@@ -56,6 +58,7 @@ private slots:
|
||||
void MaximizedChanged(int state);
|
||||
void FocusedChanged(int state);
|
||||
void WindowFocusChanged(int state);
|
||||
void UpdateFocusWindow();
|
||||
signals:
|
||||
void HeaderInfoChanged(const QString &);
|
||||
|
||||
@@ -65,8 +68,13 @@ protected:
|
||||
QCheckBox *_maximized;
|
||||
QCheckBox *_focused;
|
||||
QCheckBox *_windowFocusChanged;
|
||||
QLabel *_focusWindow;
|
||||
QHBoxLayout *_focusLayout;
|
||||
QTimer _timer;
|
||||
std::shared_ptr<MacroConditionWindow> _entryData;
|
||||
|
||||
private:
|
||||
void SetWidgetVisibility();
|
||||
|
||||
bool _loading = true;
|
||||
};
|
||||
|
||||
@@ -33,6 +33,8 @@ static std::map<VideoCondition, std::string> conditionTypes = {
|
||||
"AdvSceneSwitcher.condition.video.condition.pattern"},
|
||||
{VideoCondition::OBJECT,
|
||||
"AdvSceneSwitcher.condition.video.condition.object"},
|
||||
{VideoCondition::BRIGHTNESS,
|
||||
"AdvSceneSwitcher.condition.video.condition.brightness"},
|
||||
};
|
||||
|
||||
cv::CascadeClassifier initObjectCascade(std::string &path)
|
||||
@@ -116,6 +118,7 @@ bool MacroConditionVideo::Save(obs_data_t *obj)
|
||||
_usePatternForChangedCheck);
|
||||
obs_data_set_double(obj, "threshold", _patternThreshold);
|
||||
obs_data_set_bool(obj, "useAlphaAsMask", _useAlphaAsMask);
|
||||
obs_data_set_double(obj, "brightness", _brightnessThreshold);
|
||||
obs_data_set_string(obj, "modelDataPath", _modelDataPath.c_str());
|
||||
obs_data_set_double(obj, "scaleFactor", _scaleFactor);
|
||||
obs_data_set_int(obj, "minNeighbors", _minNeighbors);
|
||||
@@ -155,6 +158,7 @@ bool MacroConditionVideo::Load(obs_data_t *obj)
|
||||
obs_data_get_bool(obj, "usePatternForChangedCheck");
|
||||
_patternThreshold = obs_data_get_double(obj, "threshold");
|
||||
_useAlphaAsMask = obs_data_get_bool(obj, "useAlphaAsMask");
|
||||
_brightnessThreshold = obs_data_get_double(obj, "brightness");
|
||||
_modelDataPath = obs_data_get_string(obj, "modelDataPath");
|
||||
_scaleFactor = obs_data_get_double(obj, "scaleFactor");
|
||||
if (!isScaleFactorValid(_scaleFactor)) {
|
||||
@@ -255,6 +259,12 @@ bool MacroConditionVideo::ScreenshotContainsObject()
|
||||
return objects.size() > 0;
|
||||
}
|
||||
|
||||
bool MacroConditionVideo::CheckBrightnessThreshold()
|
||||
{
|
||||
_currentBrigthness = getAvgBrightness(_screenshotData.image) / 255.;
|
||||
return _currentBrigthness > _brightnessThreshold;
|
||||
}
|
||||
|
||||
bool MacroConditionVideo::Compare()
|
||||
{
|
||||
if (_checkAreaEnable && _condition != VideoCondition::NO_IMAGE) {
|
||||
@@ -278,6 +288,8 @@ bool MacroConditionVideo::Compare()
|
||||
return ScreenshotContainsPattern();
|
||||
case VideoCondition::OBJECT:
|
||||
return ScreenshotContainsObject();
|
||||
case VideoCondition::BRIGHTNESS:
|
||||
return CheckBrightnessThreshold();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -309,6 +321,13 @@ MacroConditionVideoEdit::MacroConditionVideoEdit(
|
||||
"AdvSceneSwitcher.condition.video.patternThresholdDescription"))),
|
||||
_useAlphaAsMask(new QCheckBox(obs_module_text(
|
||||
"AdvSceneSwitcher.condition.video.patternThresholdUseAlphaAsMask"))),
|
||||
_brightnessThreshold(new ThresholdSlider(
|
||||
0., 1.,
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.condition.video.brightnessThreshold"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.condition.video.brightnessThresholdDescription"))),
|
||||
_currentBrightness(new QLabel),
|
||||
_modelDataPath(new FileSelection()),
|
||||
_modelPathLayout(new QHBoxLayout),
|
||||
_objectScaleThreshold(new ThresholdSlider(
|
||||
@@ -366,6 +385,9 @@ MacroConditionVideoEdit::MacroConditionVideoEdit(
|
||||
this, SLOT(PatternThresholdChanged(double)));
|
||||
QWidget::connect(_useAlphaAsMask, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(UseAlphaAsMaskChanged(int)));
|
||||
QWidget::connect(_brightnessThreshold,
|
||||
SIGNAL(DoubleValueChanged(double)), this,
|
||||
SLOT(BrightnessThresholdChanged(double)));
|
||||
QWidget::connect(_objectScaleThreshold,
|
||||
SIGNAL(DoubleValueChanged(double)), this,
|
||||
SLOT(ObjectScaleThresholdChanged(double)));
|
||||
@@ -451,6 +473,8 @@ MacroConditionVideoEdit::MacroConditionVideoEdit(
|
||||
mainLayout->addWidget(_usePatternForChangedCheck);
|
||||
mainLayout->addWidget(_patternThreshold);
|
||||
mainLayout->addWidget(_useAlphaAsMask);
|
||||
mainLayout->addWidget(_brightnessThreshold);
|
||||
mainLayout->addWidget(_currentBrightness);
|
||||
mainLayout->addLayout(_modelPathLayout);
|
||||
mainLayout->addWidget(_objectScaleThreshold);
|
||||
mainLayout->addLayout(_neighborsControlLayout);
|
||||
@@ -465,6 +489,10 @@ MacroConditionVideoEdit::MacroConditionVideoEdit(
|
||||
_entryData = entryData;
|
||||
UpdateEntryData();
|
||||
_loading = false;
|
||||
|
||||
connect(&_updateBrightnessTimer, &QTimer::timeout, this,
|
||||
&MacroConditionVideoEdit::UpdateCurrentBrightness);
|
||||
_updateBrightnessTimer.start(1000);
|
||||
}
|
||||
|
||||
void MacroConditionVideoEdit::UpdatePreviewTooltip()
|
||||
@@ -673,6 +701,16 @@ void MacroConditionVideoEdit::UseAlphaAsMaskChanged(int value)
|
||||
_entryData->LoadImageFromFile();
|
||||
}
|
||||
|
||||
void MacroConditionVideoEdit::BrightnessThresholdChanged(double value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(GetSwitcher()->m);
|
||||
_entryData->_brightnessThreshold = value;
|
||||
}
|
||||
|
||||
void MacroConditionVideoEdit::ObjectScaleThresholdChanged(double value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
@@ -774,6 +812,14 @@ void MacroConditionVideoEdit::ShowMatchClicked()
|
||||
_previewDialog.ShowMatch();
|
||||
}
|
||||
|
||||
void MacroConditionVideoEdit::UpdateCurrentBrightness()
|
||||
{
|
||||
QString text = obs_module_text(
|
||||
"AdvSceneSwitcher.condition.video.currentBrightness");
|
||||
_currentBrightness->setText(
|
||||
text.arg(_entryData->GetCurrentBrightness()));
|
||||
}
|
||||
|
||||
void MacroConditionVideoEdit::SelectAreaClicked()
|
||||
{
|
||||
_previewDialog.show();
|
||||
@@ -843,6 +889,10 @@ void MacroConditionVideoEdit::SetWidgetVisibility()
|
||||
_patternThreshold->setVisible(needsThreshold(_entryData->_condition));
|
||||
_useAlphaAsMask->setVisible(_entryData->_condition ==
|
||||
VideoCondition::PATTERN);
|
||||
_brightnessThreshold->setVisible(_entryData->_condition ==
|
||||
VideoCondition::BRIGHTNESS);
|
||||
_currentBrightness->setVisible(_entryData->_condition ==
|
||||
VideoCondition::BRIGHTNESS);
|
||||
_showMatch->setVisible(needsShowMatch(_entryData->_condition));
|
||||
_objectScaleThreshold->setVisible(
|
||||
needsObjectControls(_entryData->_condition));
|
||||
@@ -884,6 +934,7 @@ void MacroConditionVideoEdit::UpdateEntryData()
|
||||
_entryData->_usePatternForChangedCheck);
|
||||
_patternThreshold->SetDoubleValue(_entryData->_patternThreshold);
|
||||
_useAlphaAsMask->setChecked(_entryData->_useAlphaAsMask);
|
||||
_brightnessThreshold->SetDoubleValue(_entryData->_brightnessThreshold);
|
||||
_modelDataPath->SetPath(_entryData->GetModelDataPath().c_str());
|
||||
_objectScaleThreshold->SetDoubleValue(_entryData->_scaleFactor);
|
||||
_minNeighbors->setValue(_entryData->_minNeighbors);
|
||||
|
||||
@@ -25,6 +25,7 @@ enum class VideoCondition {
|
||||
NO_IMAGE,
|
||||
PATTERN,
|
||||
OBJECT,
|
||||
BRIGHTNESS,
|
||||
};
|
||||
|
||||
class MacroConditionVideo : public MacroCondition {
|
||||
@@ -45,6 +46,7 @@ public:
|
||||
bool LoadModelData(std::string &path);
|
||||
std::string GetModelDataPath() { return _modelDataPath; }
|
||||
void ResetLastMatch() { _lastMatchResult = false; }
|
||||
double GetCurrentBrightness() { return _currentBrigthness; }
|
||||
|
||||
VideoSelection _video;
|
||||
VideoCondition _condition = VideoCondition::MATCH;
|
||||
@@ -60,6 +62,7 @@ public:
|
||||
bool _usePatternForChangedCheck = false;
|
||||
PatternMatchData _patternData;
|
||||
double _patternThreshold = 0.8;
|
||||
double _brightnessThreshold = 0.5;
|
||||
cv::CascadeClassifier _objectCascade;
|
||||
double _scaleFactor = 1.1;
|
||||
int _minNeighbors = minMinNeighbors;
|
||||
@@ -76,6 +79,7 @@ private:
|
||||
bool OutputChanged();
|
||||
bool ScreenshotContainsPattern();
|
||||
bool ScreenshotContainsObject();
|
||||
bool CheckBrightnessThreshold();
|
||||
bool Compare();
|
||||
bool CheckShouldBeSkipped();
|
||||
|
||||
@@ -88,6 +92,7 @@ private:
|
||||
"/res/cascadeClassifiers/haarcascade_frontalface_alt.xml");
|
||||
bool _lastMatchResult = false;
|
||||
int _runCount = 0;
|
||||
double _currentBrigthness = 0.;
|
||||
|
||||
static bool _registered;
|
||||
static const std::string id;
|
||||
@@ -123,6 +128,8 @@ private slots:
|
||||
void PatternThresholdChanged(double);
|
||||
void UseAlphaAsMaskChanged(int value);
|
||||
|
||||
void BrightnessThresholdChanged(double);
|
||||
|
||||
void ModelPathChanged(const QString &text);
|
||||
void ObjectScaleThresholdChanged(double);
|
||||
void MinNeighborsChanged(int value);
|
||||
@@ -137,6 +144,8 @@ private slots:
|
||||
void ThrottleEnableChanged(int value);
|
||||
void ThrottleCountChanged(int value);
|
||||
void ShowMatchClicked();
|
||||
|
||||
void UpdateCurrentBrightness();
|
||||
signals:
|
||||
void HeaderInfoChanged(const QString &);
|
||||
|
||||
@@ -152,6 +161,9 @@ protected:
|
||||
ThresholdSlider *_patternThreshold;
|
||||
QCheckBox *_useAlphaAsMask;
|
||||
|
||||
ThresholdSlider *_brightnessThreshold;
|
||||
QLabel *_currentBrightness;
|
||||
|
||||
FileSelection *_modelDataPath;
|
||||
QHBoxLayout *_modelPathLayout;
|
||||
ThresholdSlider *_objectScaleThreshold;
|
||||
@@ -177,6 +189,8 @@ protected:
|
||||
std::shared_ptr<MacroConditionVideo> _entryData;
|
||||
|
||||
private:
|
||||
QTimer _updateBrightnessTimer;
|
||||
|
||||
void SetWidgetVisibility();
|
||||
bool _loading = true;
|
||||
};
|
||||
|
||||
@@ -77,6 +77,21 @@ std::vector<cv::Rect> matchObject(QImage &img, cv::CascadeClassifier &cascade,
|
||||
return objects;
|
||||
}
|
||||
|
||||
uchar getAvgBrightness(QImage &img)
|
||||
{
|
||||
auto i = QImageToMat(img);
|
||||
cv::Mat hsvImage, rgbImage;
|
||||
cv::cvtColor(i, rgbImage, cv::COLOR_RGBA2RGB);
|
||||
cv::cvtColor(rgbImage, hsvImage, cv::COLOR_RGB2HSV);
|
||||
long long brightnessSum = 0;
|
||||
for (int i = 0; i < hsvImage.rows; ++i) {
|
||||
for (int j = 0; j < hsvImage.cols; ++j) {
|
||||
brightnessSum += hsvImage.at<cv::Vec3b>(i, j)[2];
|
||||
}
|
||||
}
|
||||
return brightnessSum / (hsvImage.rows * hsvImage.cols);
|
||||
}
|
||||
|
||||
// Assumption is that QImage uses Format_RGBA8888.
|
||||
// Conversion from: https://github.com/dbzhang800/QtOpenCV
|
||||
cv::Mat QImageToMat(const QImage &img)
|
||||
|
||||
@@ -20,5 +20,6 @@ void matchPattern(QImage &img, QImage &pattern, double threshold,
|
||||
std::vector<cv::Rect> matchObject(QImage &img, cv::CascadeClassifier &cascade,
|
||||
double scaleFactor, int minNeighbors,
|
||||
cv::Size minSize, cv::Size maxSize);
|
||||
uchar getAvgBrightness(QImage &img);
|
||||
cv::Mat QImageToMat(const QImage &img);
|
||||
QImage MatToQImage(const cv::Mat &mat);
|
||||
|
||||
@@ -288,10 +288,38 @@ void GetProcessList(QStringList &list)
|
||||
}
|
||||
}
|
||||
|
||||
void GetForegroundProcessName(std::string &proc)
|
||||
{
|
||||
proc.resize(0);
|
||||
@autoreleasepool {
|
||||
NSWorkspace *ws = [NSWorkspace sharedWorkspace];
|
||||
NSArray *array = [ws runningApplications];
|
||||
for (NSRunningApplication *app in array) {
|
||||
if (!app.isActive) {
|
||||
continue;
|
||||
}
|
||||
NSString *name = app.localizedName;
|
||||
if (!name) {
|
||||
break;
|
||||
}
|
||||
const char *str = name.UTF8String;
|
||||
proc = std::string(str);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GetForegroundProcessName(QString &proc)
|
||||
{
|
||||
std::string temp;
|
||||
GetForegroundProcessName(temp);
|
||||
proc = QString::fromStdString(temp);
|
||||
}
|
||||
|
||||
bool isInFocus(const QString &executable)
|
||||
{
|
||||
std::string current;
|
||||
GetCurrentWindowTitle(current);
|
||||
GetForegroundProcessName(current);
|
||||
|
||||
// True if executable switch equals current window
|
||||
bool equals = (executable.toStdString() == current);
|
||||
|
||||
@@ -13,6 +13,7 @@ bool isMaximized(const std::string &title);
|
||||
std::pair<int, int> getCursorPos();
|
||||
int secondsSinceLastInput();
|
||||
void GetProcessList(QStringList &processes);
|
||||
void GetForegroundProcessName(std::string &name);
|
||||
bool isInFocus(const QString &executable);
|
||||
void PressKeys(const std::vector<HotkeyType> keys, int duration);
|
||||
void PlatformInit();
|
||||
|
||||
@@ -148,6 +148,7 @@ struct SwitcherData {
|
||||
std::vector<std::string> ignoreIdleWindows;
|
||||
std::string lastTitle;
|
||||
std::string currentTitle;
|
||||
std::string currentForegroundProcess;
|
||||
|
||||
std::deque<ScreenRegionSwitch> screenRegionSwitches;
|
||||
std::pair<int, int> lastCursorPos = {0, 0};
|
||||
|
||||
@@ -13,7 +13,7 @@ void SceneItemSelection::Save(obs_data_t *obj, const char *name) const
|
||||
obs_data_set_int(data, typeSaveName.data(), static_cast<int>(_type));
|
||||
obs_data_set_int(data, idxTypeSaveName.data(),
|
||||
static_cast<int>(_idxType));
|
||||
if (_idxType != IdxType::INDIVIDUAL) {
|
||||
if (_idxType == IdxType::INDIVIDUAL) {
|
||||
obs_data_set_int(data, idxSaveName.data(), _idx);
|
||||
} else {
|
||||
obs_data_set_int(data, idxSaveName.data(), 0);
|
||||
@@ -160,7 +160,7 @@ SceneItemSelection::GetSceneItems(SceneSelection &sceneSelection)
|
||||
}
|
||||
name = var->Value();
|
||||
} else {
|
||||
auto name = GetWeakSourceName(_sceneItem);
|
||||
name = GetWeakSourceName(_sceneItem);
|
||||
}
|
||||
int count = getCountOfSceneItemOccurance(sceneSelection, name, false);
|
||||
auto items = getSceneItemsWithName(scene, name);
|
||||
|
||||
@@ -238,7 +238,7 @@ void GetProcessList(QStringList &processes)
|
||||
CloseHandle(procSnapshot);
|
||||
}
|
||||
|
||||
bool isInFocus(const QString &executable)
|
||||
void GetForegroundProcessName(QString &proc)
|
||||
{
|
||||
// only checks if the current foreground window is from the same executable,
|
||||
// may return true for any window from a program
|
||||
@@ -249,21 +249,36 @@ bool isInFocus(const QString &executable)
|
||||
HANDLE process = OpenProcess(
|
||||
PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processId);
|
||||
if (process == NULL) {
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
WCHAR executablePath[600];
|
||||
GetModuleFileNameEx(process, 0, executablePath, 600);
|
||||
CloseHandle(process);
|
||||
|
||||
QString file = QString::fromWCharArray(executablePath)
|
||||
.split(QRegularExpression("(/|\\\\)"))
|
||||
.back();
|
||||
proc = QString::fromWCharArray(executablePath)
|
||||
.split(QRegularExpression("(/|\\\\)"))
|
||||
.back();
|
||||
}
|
||||
|
||||
void GetForegroundProcessName(std::string &proc)
|
||||
{
|
||||
QString temp;
|
||||
GetForegroundProcessName(temp);
|
||||
proc = temp.toStdString();
|
||||
}
|
||||
|
||||
bool isInFocus(const QString &executable)
|
||||
{
|
||||
// only checks if the current foreground window is from the same executable,
|
||||
// may return true for any window from a program
|
||||
QString foregroundProc;
|
||||
GetForegroundProcessName(foregroundProc);
|
||||
|
||||
// True if executable switch equals current window
|
||||
bool equals = (executable == file);
|
||||
bool equals = (executable == foregroundProc);
|
||||
// True if executable switch matches current window
|
||||
bool matches = file.contains(QRegularExpression(executable));
|
||||
bool matches = foregroundProc.contains(QRegularExpression(executable));
|
||||
|
||||
return (equals || matches);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user