mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-08-29 04:36:21 -05:00
Compare commits
25 Commits
1.29.3
...
1.30.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f13beaead2 | ||
|
|
13dba6527d | ||
|
|
b78a6510a9 | ||
|
|
6c22f438b6 | ||
|
|
347abe6c84 | ||
|
|
230863adda | ||
|
|
f59478fac7 | ||
|
|
8adac79cd8 | ||
|
|
ea93c44db7 | ||
|
|
9e20b341d8 | ||
|
|
232cbb06f6 | ||
|
|
e9d57a0f4a | ||
|
|
9633a61a65 | ||
|
|
0643b250e1 | ||
|
|
b52738881f | ||
|
|
470d5ba3d7 | ||
|
|
8326e72047 | ||
|
|
12ab4d8cf9 | ||
|
|
295ec9eb81 | ||
|
|
4c5dbd4b7c | ||
|
|
5568f92ad0 | ||
|
|
7c4c0056ce | ||
|
|
d2b4b1cc07 | ||
|
|
a3ca22d238 | ||
|
|
c73542a3cc |
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -31,3 +31,6 @@
|
||||
[submodule "deps/date"]
|
||||
path = deps/date
|
||||
url = https://github.com/HowardHinnant/date.git
|
||||
[submodule "deps/jsoncons"]
|
||||
path = deps/jsoncons
|
||||
url = https://github.com/danielaparker/jsoncons.git
|
||||
|
||||
@@ -195,6 +195,8 @@ target_sources(
|
||||
lib/utils/help-icon.cpp
|
||||
lib/utils/item-selection-helpers.cpp
|
||||
lib/utils/item-selection-helpers.hpp
|
||||
lib/utils/json-helpers.cpp
|
||||
lib/utils/json-helpers.hpp
|
||||
lib/utils/layout-helpers.cpp
|
||||
lib/utils/layout-helpers.hpp
|
||||
lib/utils/list-controls.cpp
|
||||
@@ -358,6 +360,21 @@ else()
|
||||
endif()
|
||||
target_link_libraries(${LIB_NAME} PUBLIC nlohmann_json::nlohmann_json)
|
||||
|
||||
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/deps/jsoncons/CMakeLists.txt")
|
||||
# Don't build jsoncons unit tests as they are causing compilation issues and
|
||||
# won't be executed either way
|
||||
if(OS_MACOS)
|
||||
cmake_policy(SET CMP0077 NEW)
|
||||
endif()
|
||||
set(JSONCONS_BUILD_TESTS
|
||||
OFF
|
||||
CACHE BOOL "" FORCE)
|
||||
|
||||
add_subdirectory(deps/jsoncons EXCLUDE_FROM_ALL)
|
||||
target_link_libraries(${LIB_NAME} PRIVATE jsoncons)
|
||||
target_compile_definitions(${LIB_NAME} PRIVATE JSONPATH_SUPPORT=1)
|
||||
endif()
|
||||
|
||||
find_package(CURL QUIET)
|
||||
find_package(Libcurl QUIET)
|
||||
if(CURL_FOUND)
|
||||
|
||||
@@ -19,6 +19,8 @@ The **Snap** package manager offers an OBS Studio installation which is bundled
|
||||
sudo snap install obs-studio
|
||||
```
|
||||
|
||||
More information can be found [here](https://github.com/WarmUpTill/SceneSwitcher/wiki/Installation).
|
||||
|
||||
## Contributing
|
||||
|
||||
- If you wish to contribute code to the project, have a look at this [section](BUILDING.md) describing how to compile the plugin.
|
||||
|
||||
@@ -26,7 +26,6 @@ AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.switchToRandom="Wechsle zu
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.switchTo="Wechsle zu:"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.cooldown="Nach Ausführen von Aktionen überspringe das Ausführen von Aktionen für"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.cooldownHint="In diesem Zeitraum werden potentielle erfüllte Bedingungen ignoriert!"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.verboseLogging="Ausführliches Logging"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.saveWindowGeo="Fensterposition und -größe speichern"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.showTrayNotifications="Benachrichtigungen im System-Tray anzeigen"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.disableUIHints="Deaktiviere UI Tipps"
|
||||
|
||||
@@ -29,11 +29,11 @@ AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.switchTo="Switch to:"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.cooldown="After performing actions skip performing actions for"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.cooldownHint="During this time potential matches will be ignored!"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.logLevel="Log level:"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.logLevel.disable="Disable logging"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.logLevel.default="Default"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.logLevel.logMacro="Log executed macros"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.logLevel.logAction="Log performed actions"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.logLevel.verbose="Verbose logging"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.verboseLogging="Enable verbose logging"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.saveWindowGeo="Save window position and size"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.showTrayNotifications="Show system tray notifications"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.disableUIHints="Disable UI hints"
|
||||
@@ -199,8 +199,11 @@ AdvSceneSwitcher.macroTab.highlightTrueConditions="Highlight conditions of curre
|
||||
AdvSceneSwitcher.macroTab.highlightPerformedActions="Highlight recently performed actions of currently selected macro"
|
||||
AdvSceneSwitcher.macroTab.newMacroRegisterHotkey="Register hotkeys to control the pause state of new macros"
|
||||
AdvSceneSwitcher.macroTab.newMacroUseShortCircuitEvaluation="Enable short circuit evaluation of macro conditions for new macros"
|
||||
AdvSceneSwitcher.macroTab.saveSettingsOnMacroChange="Save settings when selecting a new macro"
|
||||
AdvSceneSwitcher.macroTab.newMacroCheckInParallel="Evaluate conditions of new macros in parallel to other macros"
|
||||
AdvSceneSwitcher.macroTab.checkInParallel.tooltip="If this option is not enabled, this macro's conditions will be evaluated after the preceeding macro's condition check has completed.\nSo, if there are three macros - Macro A, Macro B, and Macro C - in the macro list the order the conditions in are evaluated is:\n • Macro A's conditions\n • Macro B's conditions\n • Macro C's conditions\nIf this option is enabled, the order might differ.\nEnabling this option can be useful for scenarios in which you have multiple long running condition checks, which you don't want to result in \"blocking\" other macros."
|
||||
AdvSceneSwitcher.macroTab.saveSettingsOnMacroChange="Save settings when switching between macros"
|
||||
AdvSceneSwitcher.macroTab.saveSettingsOnMacroChange.tooltip="Saving the settings can be an expensive operation if you are working with a very large scene collection.\nIn this case, it might make sense to disable this option."
|
||||
AdvSceneSwitcher.macroTab.currentCheckInParallel="Evaluate conditions of selected macro in parallel to other macros"
|
||||
AdvSceneSwitcher.macroTab.currentRegisterHotkeys="Register hotkeys to control the pause state of selected macro"
|
||||
AdvSceneSwitcher.macroTab.currentUseShortCircuitEvaluation="Enable short circuit evaluation of macro conditions for currently selected macro"
|
||||
AdvSceneSwitcher.macroTab.shortCircuit.tooltip="Enabling short circuit evaluation might improve the performance, as some condition checks are skipped, if the overall macro cannot be evaluated to \"true\" anymore.\nHowever, please note that condition checks, which are skipped over, will also not update their duration modifier checks."
|
||||
@@ -1087,7 +1090,10 @@ AdvSceneSwitcher.action.variable.type.askForValue="Get user input"
|
||||
AdvSceneSwitcher.action.variable.type.environmentVariable="Set to environment variable value"
|
||||
AdvSceneSwitcher.action.variable.type.sceneItemCount="Set to scene item count of scene"
|
||||
AdvSceneSwitcher.action.variable.type.stringLength="Set to length of string"
|
||||
AdvSceneSwitcher.action.variable.type.extractJson="Extract json field with name"
|
||||
AdvSceneSwitcher.action.variable.type.extractJsonField="Extract JSON field with name"
|
||||
AdvSceneSwitcher.action.variable.type.queryJson="Query JSON"
|
||||
AdvSceneSwitcher.action.variable.type.queryJson.info="You can use \"JSONPath\" (RFC 9535) syntax here.\nSo, for example:\n\n • $['books'][0]['category']\n • $.books[0].category\n\nIf the query or the JSON should be invalid, the variable value will not be changed.\nIf the input is valid, the result of the query will always be a JSON array."
|
||||
AdvSceneSwitcher.action.variable.type.accessJsonArray="Access JSON array at index"
|
||||
AdvSceneSwitcher.action.variable.type.setToTempvar="Set to macro property"
|
||||
AdvSceneSwitcher.action.variable.type.setToTempvar.help="This action type will allow you to extract values out of segments of the current macro and assign those values to the selected variable.\nFor example, you can get the current scene name from a scene condition and assign this name to a variable."
|
||||
AdvSceneSwitcher.action.variable.type.sceneItemName="Set to scene item name at index"
|
||||
@@ -1116,15 +1122,15 @@ AdvSceneSwitcher.action.variable.invalidSelection="Invalid selection!"
|
||||
AdvSceneSwitcher.action.variable.actionNoVariableSupport="Getting variable values from %1 actions is not supported!"
|
||||
AdvSceneSwitcher.action.variable.conditionNoVariableSupport="Getting variable values from %1 conditions is not supported!"
|
||||
AdvSceneSwitcher.action.variable.currentSegmentValue="Current value:"
|
||||
AdvSceneSwitcher.action.variable.entry.other="{{actions}}{{variables}}{{variables2}}{{strValue}}{{numValue}}{{segmentIndex}}{{mathExpression}}{{envVariableName}}{{scenes}}{{tempVars}}{{tempVarsHelp}}{{sceneItemIndex}}{{direction}}{{stringLength}}{{paddingCharSelection}}{{caseType}}"
|
||||
AdvSceneSwitcher.action.variable.entry.pad="{{actions}}of{{variables}}to length{{stringLength}}by adding{{paddingCharSelection}}to the{{direction}}"
|
||||
AdvSceneSwitcher.action.variable.entry.truncate="{{actions}}of{{variables}}to length{{stringLength}}by removing characters from the{{direction}}"
|
||||
AdvSceneSwitcher.action.variable.entry.substringIndex="Substring start:{{subStringStart}}Substring size:{{subStringSize}}"
|
||||
AdvSceneSwitcher.action.variable.entry.substringRegex="Assign value of{{regexMatchIdx}}match using regular expression:"
|
||||
AdvSceneSwitcher.action.variable.entry.findAndReplace="{{findStr}}{{findRegex}}{{replaceStr}}"
|
||||
AdvSceneSwitcher.action.variable.entry.userInput.customPrompt="{{useCustomPrompt}}Use custom prompt{{inputPrompt}}"
|
||||
AdvSceneSwitcher.action.variable.entry.userInput.placeholder="{{useInputPlaceholder}}Fill with placeholder{{inputPlaceholder}}"
|
||||
AdvSceneSwitcher.action.variable.entry.randomNumber="Generate random number in range from{{randomNumberStart}}to{{randomNumberEnd}}"
|
||||
AdvSceneSwitcher.action.variable.layout.other="{{actions}}{{variables}}{{variables2}}{{strValue}}{{numValue}}{{segmentIndex}}{{mathExpression}}{{envVariableName}}{{scenes}}{{tempVars}}{{tempVarsHelp}}{{sceneItemIndex}}{{direction}}{{stringLength}}{{paddingCharSelection}}{{caseType}}{{jsonQuery}}{{jsonQueryHelp}}{{jsonIndex}}"
|
||||
AdvSceneSwitcher.action.variable.layout.pad="{{actions}}of{{variables}}to length{{stringLength}}by adding{{paddingCharSelection}}to the{{direction}}"
|
||||
AdvSceneSwitcher.action.variable.layout.truncate="{{actions}}of{{variables}}to length{{stringLength}}by removing characters from the{{direction}}"
|
||||
AdvSceneSwitcher.action.variable.layout.substringIndex="Substring start:{{subStringStart}}Substring size:{{subStringSize}}"
|
||||
AdvSceneSwitcher.action.variable.layout.substringRegex="Assign value of{{regexMatchIdx}}match using regular expression:"
|
||||
AdvSceneSwitcher.action.variable.layout.findAndReplace="{{findStr}}{{findRegex}}{{replaceStr}}"
|
||||
AdvSceneSwitcher.action.variable.layout.userInput.customPrompt="{{useCustomPrompt}}Use custom prompt{{inputPrompt}}"
|
||||
AdvSceneSwitcher.action.variable.layout.userInput.placeholder="{{useInputPlaceholder}}Fill with placeholder{{inputPlaceholder}}"
|
||||
AdvSceneSwitcher.action.variable.layout.randomNumber="Generate random number in range from{{randomNumberStart}}to{{randomNumberEnd}}"
|
||||
AdvSceneSwitcher.action.projector="Projector"
|
||||
AdvSceneSwitcher.action.projector.action.open="Open"
|
||||
AdvSceneSwitcher.action.projector.action.close="Close"
|
||||
@@ -1409,6 +1415,7 @@ AdvSceneSwitcher.twitchToken.moderator.chat.settings.manage="Manage channel's ch
|
||||
AdvSceneSwitcher.twitchToken.user.whispers.manage="Manage user's whispers."
|
||||
AdvSceneSwitcher.twitchToken.chat.read="View live stream chat messages."
|
||||
AdvSceneSwitcher.twitchToken.chat.edit="Send live stream chat messages."
|
||||
AdvSceneSwitcher.twitchToken.validateTimestamps="Validate timestamps of received Twitch event messages. (Recommended)"
|
||||
|
||||
AdvSceneSwitcher.twitch.selection.channel.open="Open channel"
|
||||
AdvSceneSwitcher.twitch.selection.channel.open.tooltip.details="Open channel in external application handling the HTTPS protocol."
|
||||
|
||||
@@ -25,7 +25,6 @@ AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.dontSwitch="No cambiar"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.switchToRandom="Cambiar a una escena aleatoria"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.switchTo="Cambiar a:"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.cooldownHint="¡Durante este tiempo, se ignorarán las posibles coincidencias!"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.verboseLogging="Habilitar el registro detallado"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.saveWindowGeo="Guardar la posición y el tamaño de la ventana"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.showTrayNotifications="Mostrar notificaciones del sistema"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.disableUIHints="Deshabilitar sugerencias de interfaz de usuario"
|
||||
|
||||
@@ -26,7 +26,6 @@ AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.switchToRandom="Basculer v
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.switchTo="Basculer vers :"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.cooldown="Après avoir effectué des actions, sauter l'exécution d'actions pendant"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.cooldownHint="Pendant cette période, les correspondances potentielles seront ignorées !"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.verboseLogging="Activer les journaux détaillés"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.saveWindowGeo="Enregistrer la position et la taille de la fenêtre"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.showTrayNotifications="Afficher les notifications dans la zone de notification système"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.disableUIHints="Désactiver les indications de l'interface utilisateur"
|
||||
@@ -704,10 +703,10 @@ AdvSceneSwitcher.action.variable.invalidSelection="Sélection invalide !"
|
||||
AdvSceneSwitcher.action.variable.actionNoVariableSupport="La récupération de valeurs de variables à partir d'actions %1 n'est pas prise en charge !"
|
||||
AdvSceneSwitcher.action.variable.conditionNoVariableSupport="La récupération de valeurs de variables à partir de conditions %1 n'est pas prise en charge !"
|
||||
AdvSceneSwitcher.action.variable.currentSegmentValue="Valeur actuelle :"
|
||||
AdvSceneSwitcher.action.variable.entry.substringIndex="Début de la sous-chaîne :{{subStringStart}}Taille de la sous-chaîne :{{subStringSize}}"
|
||||
AdvSceneSwitcher.action.variable.entry.substringRegex="Attribuer la valeur du match{{regexMatchIdx}}en utilisant une expression régulière :"
|
||||
AdvSceneSwitcher.action.variable.entry.userInput.customPrompt="{{useCustomPrompt}}Utiliser un message personnalisé{{inputPrompt}}"
|
||||
AdvSceneSwitcher.action.variable.entry.userInput.placeholder="{{useInputPlaceholder}}Remplir avec un indicateur de position{{inputPlaceholder}}"
|
||||
AdvSceneSwitcher.action.variable.layout.substringIndex="Début de la sous-chaîne :{{subStringStart}}Taille de la sous-chaîne :{{subStringSize}}"
|
||||
AdvSceneSwitcher.action.variable.layout.substringRegex="Attribuer la valeur du match{{regexMatchIdx}}en utilisant une expression régulière :"
|
||||
AdvSceneSwitcher.action.variable.layout.userInput.customPrompt="{{useCustomPrompt}}Utiliser un message personnalisé{{inputPrompt}}"
|
||||
AdvSceneSwitcher.action.variable.layout.userInput.placeholder="{{useInputPlaceholder}}Remplir avec un indicateur de position{{inputPlaceholder}}"
|
||||
AdvSceneSwitcher.action.projector="Projecteur"
|
||||
AdvSceneSwitcher.action.projector.type.source="Source"
|
||||
AdvSceneSwitcher.action.projector.type.scene="Scène"
|
||||
|
||||
@@ -30,7 +30,6 @@ AdvSceneSwitcher.generalTab.generalBehavior.logLevel="ログレベル:"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.logLevel.default="デフォルト"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.logLevel.logAction="実行されたアクションのログ"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.logLevel.verbose="詳細ログ(Verbose)"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.verboseLogging="詳細ログを有効にする(生成されるログファイルのサイズが増加します)"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.saveWindowGeo="ウィンドウのサイズと位置を記憶する"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.showTrayNotifications="システムトレイ通知を表示"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.disableUIHints="UIヒントを無効にする"
|
||||
@@ -1030,7 +1029,7 @@ AdvSceneSwitcher.action.variable.type.askForValue="入力ダイアログを表
|
||||
AdvSceneSwitcher.action.variable.type.environmentVariable="特定の環境変数の値に設定します"
|
||||
AdvSceneSwitcher.action.variable.type.sceneItemCount="特定のシーンのシーン項目の数の値にします"
|
||||
AdvSceneSwitcher.action.variable.type.stringLength="変数値を指定された入力文字列の長さに設定"
|
||||
AdvSceneSwitcher.action.variable.type.extractJson="変数から json フィールドを抽出する"
|
||||
AdvSceneSwitcher.action.variable.type.extractJsonField="変数から json フィールドを抽出する"
|
||||
AdvSceneSwitcher.action.variable.type.setToTempvar="マクロプロパティに設定"
|
||||
AdvSceneSwitcher.action.variable.type.setToTempvar.help="このアクション タイプを使用すると、現在のマクロのセグメントから値を抽出し、それらの値を選択した変数に割り当てることができます。\nたとえば、シーン条件から現在のシーン名を取得し、この名前を変数に割り当てることができます。"
|
||||
AdvSceneSwitcher.action.variable.type.sceneItemName="インデックスのシーン項目名に設定"
|
||||
@@ -1050,14 +1049,14 @@ AdvSceneSwitcher.action.variable.invalidSelection="選択が無効です!"
|
||||
AdvSceneSwitcher.action.variable.actionNoVariableSupport="%1 アクションからの変数値の取得はサポートされていません!"
|
||||
AdvSceneSwitcher.action.variable.conditionNoVariableSupport="%1 条件からの変数値の取得はサポートされていません!"
|
||||
AdvSceneSwitcher.action.variable.currentSegmentValue="現在値:"
|
||||
; AdvSceneSwitcher.action.variable.entry.other="{{actions}}{{variables}}{{variables2}}{{strValue}}{{numValue}}{{segmentIndex}}{{mathExpression}}{{envVariableName}}{{scenes}}{{tempVars}}{{tempVarsHelp}}{{sceneItemIndex}}{{direction}}{{stringLength}}{{paddingCharSelection}}"
|
||||
AdvSceneSwitcher.action.variable.entry.pad="{{actions}}の{{variables}}の長さを{{stringLength}}にするには、{{paddingCharSelection}}を{{direction}}に追加します。"
|
||||
AdvSceneSwitcher.action.variable.entry.truncate="{{actions}}の{{variables}}の長さを{{stringLength}}にするには、{{direction}}から文字を削除します。"
|
||||
AdvSceneSwitcher.action.variable.entry.substringIndex="部分文字列の開始:{{subStringStart}}部分文字列のサイズ:{{subStringSize}}"
|
||||
AdvSceneSwitcher.action.variable.entry.substringRegex="正規表現を使用して{{regexMatchIdx}}一致の値を割り当てます:"
|
||||
; AdvSceneSwitcher.action.variable.entry.findAndReplace="{{findStr}}{{findRegex}}{{replaceStr}}"
|
||||
AdvSceneSwitcher.action.variable.entry.userInput.customPrompt="{{useCustomPrompt}}カスタム プロンプトを使用する{{inputPrompt}}"
|
||||
AdvSceneSwitcher.action.variable.entry.userInput.placeholder="{{useInputPlaceholder}}プレースホルダーを入力{{inputPlaceholder}}"
|
||||
; AdvSceneSwitcher.action.variable.layout.other="{{actions}}{{variables}}{{variables2}}{{strValue}}{{numValue}}{{segmentIndex}}{{mathExpression}}{{envVariableName}}{{scenes}}{{tempVars}}{{tempVarsHelp}}{{sceneItemIndex}}{{direction}}{{stringLength}}{{paddingCharSelection}}"
|
||||
AdvSceneSwitcher.action.variable.layout.pad="{{actions}}の{{variables}}の長さを{{stringLength}}にするには、{{paddingCharSelection}}を{{direction}}に追加します。"
|
||||
AdvSceneSwitcher.action.variable.layout.truncate="{{actions}}の{{variables}}の長さを{{stringLength}}にするには、{{direction}}から文字を削除します。"
|
||||
AdvSceneSwitcher.action.variable.layout.substringIndex="部分文字列の開始:{{subStringStart}}部分文字列のサイズ:{{subStringSize}}"
|
||||
AdvSceneSwitcher.action.variable.layout.substringRegex="正規表現を使用して{{regexMatchIdx}}一致の値を割り当てます:"
|
||||
; AdvSceneSwitcher.action.variable.layout.findAndReplace="{{findStr}}{{findRegex}}{{replaceStr}}"
|
||||
AdvSceneSwitcher.action.variable.layout.userInput.customPrompt="{{useCustomPrompt}}カスタム プロンプトを使用する{{inputPrompt}}"
|
||||
AdvSceneSwitcher.action.variable.layout.userInput.placeholder="{{useInputPlaceholder}}プレースホルダーを入力{{inputPlaceholder}}"
|
||||
AdvSceneSwitcher.action.projector="プロジェクター"
|
||||
AdvSceneSwitcher.action.projector.type.source="ソース"
|
||||
AdvSceneSwitcher.action.projector.type.scene="シーン"
|
||||
|
||||
@@ -30,7 +30,6 @@ AdvSceneSwitcher.generalTab.generalBehavior.logLevel="Nível de log:"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.logLevel.default="Padrão"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.logLevel.logAction="Registrar ações executadas"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.logLevel.verbose="Registro detalhado"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.verboseLogging="Ativar registro detalhado"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.saveWindowGeo="Salvar posição e tamanho da janela"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.showTrayNotifications="Mostrar notificações na área de notificação"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.disableUIHints="Desativar dicas de interface"
|
||||
@@ -1012,7 +1011,7 @@ AdvSceneSwitcher.action.variable.type.askForValue="Obter entrada do usuário"
|
||||
AdvSceneSwitcher.action.variable.type.environmentVariable="Definir valor da variável de ambiente"
|
||||
AdvSceneSwitcher.action.variable.type.sceneItemCount="Definir para contagem de itens de cena"
|
||||
AdvSceneSwitcher.action.variable.type.stringLength="Definir comprimento da string"
|
||||
AdvSceneSwitcher.action.variable.type.extractJson="Extrair campo json com nome"
|
||||
AdvSceneSwitcher.action.variable.type.extractJsonField="Extrair campo json com nome"
|
||||
AdvSceneSwitcher.action.variable.type.setToTempvar="Definir para propriedade da macro"
|
||||
AdvSceneSwitcher.action.variable.type.setToTempvar.help="Este tipo de ação permite extrair valores de segmentos da macro atual e atribuir esses valores à variável selecionada.\nPor exemplo, você pode obter o nome da cena atual de uma condição de cena e atribuir esse nome a uma variável."
|
||||
AdvSceneSwitcher.action.variable.type.sceneItemName="Definir para nome do item de cena no índice"
|
||||
@@ -1032,13 +1031,13 @@ AdvSceneSwitcher.action.variable.invalidSelection="Seleção inválida!"
|
||||
AdvSceneSwitcher.action.variable.actionNoVariableSupport="Obter valores de variáveis das ações %1 não é suportado!"
|
||||
AdvSceneSwitcher.action.variable.conditionNoVariableSupport="Obter valores de variáveis das condições %1 não é suportado!"
|
||||
AdvSceneSwitcher.action.variable.currentSegmentValue="Valor atual:"
|
||||
AdvSceneSwitcher.action.variable.entry.pad="{{actions}}de{{variables}}para comprimento{{stringLength}}adicionando{{paddingCharSelection}}ao{{direction}}"
|
||||
AdvSceneSwitcher.action.variable.entry.truncate="{{actions}}de{{variables}}para comprimento{{stringLength}}removendo caracteres da{{direction}}"
|
||||
AdvSceneSwitcher.action.variable.entry.substringIndex="Início da substring:{{subStringStart}}Tamanho da substring:{{subStringSize}}"
|
||||
AdvSceneSwitcher.action.variable.entry.substringRegex="Atribuir valor do{{regexMatchIdx}}correspondência usando expressão regular:"
|
||||
AdvSceneSwitcher.action.variable.entry.findAndReplace="{{findStr}}{{findRegex}}{{replaceStr}}"
|
||||
AdvSceneSwitcher.action.variable.entry.userInput.customPrompt="{{useCustomPrompt}}Usar prompt personalizado{{inputPrompt}}"
|
||||
AdvSceneSwitcher.action.variable.entry.userInput.placeholder="{{useInputPlaceholder}}Preencher com placeholder{{inputPlaceholder}}"
|
||||
AdvSceneSwitcher.action.variable.layout.pad="{{actions}}de{{variables}}para comprimento{{stringLength}}adicionando{{paddingCharSelection}}ao{{direction}}"
|
||||
AdvSceneSwitcher.action.variable.layout.truncate="{{actions}}de{{variables}}para comprimento{{stringLength}}removendo caracteres da{{direction}}"
|
||||
AdvSceneSwitcher.action.variable.layout.substringIndex="Início da substring:{{subStringStart}}Tamanho da substring:{{subStringSize}}"
|
||||
AdvSceneSwitcher.action.variable.layout.substringRegex="Atribuir valor do{{regexMatchIdx}}correspondência usando expressão regular:"
|
||||
AdvSceneSwitcher.action.variable.layout.findAndReplace="{{findStr}}{{findRegex}}{{replaceStr}}"
|
||||
AdvSceneSwitcher.action.variable.layout.userInput.customPrompt="{{useCustomPrompt}}Usar prompt personalizado{{inputPrompt}}"
|
||||
AdvSceneSwitcher.action.variable.layout.userInput.placeholder="{{useInputPlaceholder}}Preencher com placeholder{{inputPlaceholder}}"
|
||||
AdvSceneSwitcher.action.projector="Projetor"
|
||||
AdvSceneSwitcher.action.projector.type.source="Fonte"
|
||||
AdvSceneSwitcher.action.projector.type.scene="Cena"
|
||||
|
||||
@@ -25,7 +25,6 @@ AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.dontSwitch="Не пере
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.switchToRandom="Переключиться на любую сцену на вкладке Random"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.switchTo="Переключиться на:"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.cooldownHint="В течение этого времени потенциальные совпадения будут игнорироваться!"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.verboseLogging="Включить ведение подробного журнала"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.saveWindowGeo="Сохранять положение и размер окна"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.disableUIHints="Отключить подсказки пользовательского интерфейса"
|
||||
AdvSceneSwitcher.generalTab.priority="Приоритет"
|
||||
|
||||
@@ -26,7 +26,6 @@ AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.switchToRandom="Rastgele s
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.switchTo="Değiştirmek:"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.cooldown="Bir eşleşmeden sonra aşağıdakiler için işlem yapmayın:"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.cooldownHint="Bu süre zarfında olası eşleşmeler göz ardı edilecektir!"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.verboseLogging="Ayrıntılı günlük kaydını etkinleştir"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.saveWindowGeo="Pencere konumunu ve boyutunu kaydet"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.showTrayNotifications="Sistem tepsisi bildirimlerini göster"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.disableUIHints="UI ipuçlarını devre dışı bırak"
|
||||
|
||||
@@ -33,7 +33,6 @@ AdvSceneSwitcher.generalTab.generalBehavior.logLevel.default="默认"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.logLevel.logMacro="记录已执行的宏"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.logLevel.logAction="记录已执行的操作"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.logLevel.verbose="记录所有信息"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.verboseLogging="详细日志输出"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.saveWindowGeo="保存窗口位置和大小"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.showTrayNotifications="显示系统托盘通知"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.disableUIHints="禁用UI提示"
|
||||
@@ -1073,7 +1072,7 @@ AdvSceneSwitcher.action.variable.type.askForValue="获取用户输入内容"
|
||||
AdvSceneSwitcher.action.variable.type.environmentVariable="设置为环境变量值"
|
||||
AdvSceneSwitcher.action.variable.type.sceneItemCount="设置为场景内的场景项目计数"
|
||||
AdvSceneSwitcher.action.variable.type.stringLength="设置为字符串长度"
|
||||
AdvSceneSwitcher.action.variable.type.extractJson="取JSON内字段的值"
|
||||
AdvSceneSwitcher.action.variable.type.extractJsonField="取JSON内字段的值"
|
||||
AdvSceneSwitcher.action.variable.type.setToTempvar="设置为宏属性"
|
||||
AdvSceneSwitcher.action.variable.type.setToTempvar.help="此操作类型将允许您从当前宏的部分中提取值,并将这些值分配给所选变量.\n例如,可以从场景条件中获取当前场景名称,并将该名称分配给变量."
|
||||
AdvSceneSwitcher.action.variable.type.sceneItemName="设置为场景项目索引的名称"
|
||||
@@ -1102,15 +1101,14 @@ AdvSceneSwitcher.action.variable.invalidSelection="无效选择!"
|
||||
AdvSceneSwitcher.action.variable.actionNoVariableSupport="不支持从 %1 操作中获取变量值!"
|
||||
AdvSceneSwitcher.action.variable.conditionNoVariableSupport="不支持从 %1 条件中获取变量值!"
|
||||
AdvSceneSwitcher.action.variable.currentSegmentValue="当前值:"
|
||||
AdvSceneSwitcher.action.variable.entry.other="{{actions}}{{variables}}{{variables2}}{{strValue}}{{numValue}}{{segmentIndex}}{{mathExpression}}{{envVariableName}}{{scenes}}{{tempVars}}{{tempVarsHelp}}{{sceneItemIndex}}{{direction}}{{stringLength}}{{paddingCharSelection}}{{caseType}}"
|
||||
AdvSceneSwitcher.action.variable.entry.pad="{{actions}}于{{variables}}的{{direction}}起,内容为{{paddingCharSelection}}将其变量值长度增加至{{stringLength}}."
|
||||
AdvSceneSwitcher.action.variable.entry.truncate="{{actions}}于{{variables}}的{{direction}}起,将变量长度缩减至{{stringLength}}"
|
||||
AdvSceneSwitcher.action.variable.entry.substringIndex="截取字符串开始位置:{{subStringStart}} 截取字符串长度:{{subStringSize}}"
|
||||
AdvSceneSwitcher.action.variable.entry.substringRegex="使用正则表达式为 {{regexMatchIdx}} 匹配的值:"
|
||||
AdvSceneSwitcher.action.variable.entry.findAndReplace="{{findStr}}{{findRegex}}{{replaceStr}}"
|
||||
AdvSceneSwitcher.action.variable.entry.userInput.customPrompt="{{useCustomPrompt}}使用自定义提示{{inputPrompt}}"
|
||||
AdvSceneSwitcher.action.variable.entry.userInput.placeholder="{{useInputPlaceholder}}用占位符填充{{inputPlaceholder}}"
|
||||
AdvSceneSwitcher.action.variable.entry.randomNumber="在以下范围内生成随机数{{randomNumberStart}}到{{randomNumberEnd}}"
|
||||
AdvSceneSwitcher.action.variable.layout.pad="{{actions}}于{{variables}}的{{direction}}起,内容为{{paddingCharSelection}}将其变量值长度增加至{{stringLength}}."
|
||||
AdvSceneSwitcher.action.variable.layout.truncate="{{actions}}于{{variables}}的{{direction}}起,将变量长度缩减至{{stringLength}}"
|
||||
AdvSceneSwitcher.action.variable.layout.substringIndex="截取字符串开始位置:{{subStringStart}} 截取字符串长度:{{subStringSize}}"
|
||||
AdvSceneSwitcher.action.variable.layout.substringRegex="使用正则表达式为 {{regexMatchIdx}} 匹配的值:"
|
||||
AdvSceneSwitcher.action.variable.layout.findAndReplace="{{findStr}}{{findRegex}}{{replaceStr}}"
|
||||
AdvSceneSwitcher.action.variable.layout.userInput.customPrompt="{{useCustomPrompt}}使用自定义提示{{inputPrompt}}"
|
||||
AdvSceneSwitcher.action.variable.layout.userInput.placeholder="{{useInputPlaceholder}}用占位符填充{{inputPlaceholder}}"
|
||||
AdvSceneSwitcher.action.variable.layout.randomNumber="在以下范围内生成随机数{{randomNumberStart}}到{{randomNumberEnd}}"
|
||||
AdvSceneSwitcher.action.projector="投影仪"
|
||||
AdvSceneSwitcher.action.projector.type.source="源"
|
||||
AdvSceneSwitcher.action.projector.type.scene="场景"
|
||||
|
||||
1
deps/jsoncons
vendored
Submodule
1
deps/jsoncons
vendored
Submodule
Submodule deps/jsoncons added at 64b9da1e9f
@@ -182,26 +182,6 @@
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="logLevel">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>AdvSceneSwitcher.generalTab.generalBehavior.logLevel.default</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>AdvSceneSwitcher.generalTab.generalBehavior.logLevel.logMacro</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>AdvSceneSwitcher.generalTab.generalBehavior.logLevel.logAction</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>AdvSceneSwitcher.generalTab.generalBehavior.logLevel.verbose</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
|
||||
@@ -82,19 +82,21 @@ public:
|
||||
void RemoveMacro(std::shared_ptr<Macro> &);
|
||||
void RemoveSelectedMacros();
|
||||
void RenameMacro(std::shared_ptr<Macro> &, const QString &name);
|
||||
std::shared_ptr<Macro> GetSelectedMacro();
|
||||
std::vector<std::shared_ptr<Macro>> GetSelectedMacros();
|
||||
std::shared_ptr<Macro> GetSelectedMacro() const;
|
||||
std::vector<std::shared_ptr<Macro>> GetSelectedMacros() const;
|
||||
void SetEditMacro(Macro &m);
|
||||
void SetMacroEditAreaDisabled(bool);
|
||||
void HighlightAction(int idx, QColor color = QColor(Qt::green));
|
||||
void HighlightElseAction(int idx, QColor color = QColor(Qt::green));
|
||||
void HighlightCondition(int idx, QColor color = QColor(Qt::green));
|
||||
void SetMacroEditAreaDisabled(bool) const;
|
||||
void HighlightAction(int idx, QColor color = QColor(Qt::green)) const;
|
||||
void HighlightElseAction(int idx,
|
||||
QColor color = QColor(Qt::green)) const;
|
||||
void HighlightCondition(int idx,
|
||||
QColor color = QColor(Qt::green)) const;
|
||||
void PopulateMacroActions(Macro &m, uint32_t afterIdx = 0);
|
||||
void PopulateMacroElseActions(Macro &m, uint32_t afterIdx = 0);
|
||||
void PopulateMacroConditions(Macro &m, uint32_t afterIdx = 0);
|
||||
void SetActionData(Macro &m);
|
||||
void SetElseActionData(Macro &m);
|
||||
void SetConditionData(Macro &m);
|
||||
void SetActionData(Macro &m) const;
|
||||
void SetElseActionData(Macro &m) const;
|
||||
void SetConditionData(Macro &m) const;
|
||||
void SwapActions(Macro *m, int pos1, int pos2);
|
||||
void SwapConditions(Macro *m, int pos1, int pos2);
|
||||
void HighlightMacroSettingsButton(bool enable = true);
|
||||
@@ -102,11 +104,11 @@ public:
|
||||
public slots:
|
||||
void on_macroAdd_clicked();
|
||||
void on_macroRemove_clicked();
|
||||
void on_macroUp_clicked();
|
||||
void on_macroDown_clicked();
|
||||
void on_macroUp_clicked() const;
|
||||
void on_macroDown_clicked() const;
|
||||
void on_macroName_editingFinished();
|
||||
void on_runMacroInParallel_stateChanged(int value);
|
||||
void on_runMacroOnChange_stateChanged(int value);
|
||||
void on_runMacroInParallel_stateChanged(int value) const;
|
||||
void on_runMacroOnChange_stateChanged(int value) const;
|
||||
void on_conditionAdd_clicked();
|
||||
void on_conditionRemove_clicked();
|
||||
void on_conditionTop_clicked();
|
||||
@@ -119,14 +121,14 @@ public slots:
|
||||
void on_actionUp_clicked();
|
||||
void on_actionDown_clicked();
|
||||
void on_actionBottom_clicked();
|
||||
void on_toggleElseActions_clicked();
|
||||
void on_toggleElseActions_clicked() const;
|
||||
void on_elseActionAdd_clicked();
|
||||
void on_elseActionRemove_clicked();
|
||||
void on_elseActionTop_clicked();
|
||||
void on_elseActionUp_clicked();
|
||||
void on_elseActionDown_clicked();
|
||||
void on_elseActionBottom_clicked();
|
||||
void MacroSelectionAboutToChange();
|
||||
void MacroSelectionAboutToChange() const;
|
||||
void MacroSelectionChanged();
|
||||
void UpMacroSegementHotkey();
|
||||
void DownMacroSegementHotkey();
|
||||
@@ -137,22 +139,22 @@ public slots:
|
||||
void ShowMacroConditionsContextMenu(const QPoint &);
|
||||
void CopyMacro();
|
||||
void RenameSelectedMacro();
|
||||
void ExportMacros();
|
||||
void ExportMacros() const;
|
||||
void ImportMacros();
|
||||
void ExpandAllActions();
|
||||
void ExpandAllElseActions();
|
||||
void ExpandAllConditions();
|
||||
void CollapseAllActions();
|
||||
void CollapseAllElseActions();
|
||||
void CollapseAllConditions();
|
||||
void MinimizeActions();
|
||||
void MaximizeActions();
|
||||
void MinimizeElseActions();
|
||||
void MaximizeElseActions();
|
||||
void MinimizeConditions();
|
||||
void MaximizeConditions();
|
||||
void SetElseActionsStateToHidden();
|
||||
void SetElseActionsStateToVisible();
|
||||
void ExpandAllActions() const;
|
||||
void ExpandAllElseActions() const;
|
||||
void ExpandAllConditions() const;
|
||||
void CollapseAllActions() const;
|
||||
void CollapseAllElseActions() const;
|
||||
void CollapseAllConditions() const;
|
||||
void MinimizeActions() const;
|
||||
void MaximizeActions() const;
|
||||
void MinimizeElseActions() const;
|
||||
void MaximizeElseActions() const;
|
||||
void MinimizeConditions() const;
|
||||
void MaximizeConditions() const;
|
||||
void SetElseActionsStateToHidden() const;
|
||||
void SetElseActionsStateToVisible() const;
|
||||
void MacroActionSelectionChanged(int idx);
|
||||
void MacroActionReorder(int to, int target);
|
||||
void AddMacroAction(Macro *macro, int idx, const std::string &id,
|
||||
@@ -178,8 +180,8 @@ public slots:
|
||||
void RemoveMacroCondition(int idx);
|
||||
void MoveMacroConditionUp(int idx);
|
||||
void MoveMacroConditionDown(int idx);
|
||||
void HighlightControls();
|
||||
void HighlightOnChange();
|
||||
void HighlightControls() const;
|
||||
void HighlightOnChange() const;
|
||||
void on_macroSettings_clicked();
|
||||
void CopyMacroSegment();
|
||||
void PasteMacroSegment();
|
||||
|
||||
@@ -113,12 +113,12 @@ void AdvSceneSwitcher::on_startupBehavior_currentIndexChanged(int index)
|
||||
static_cast<SwitcherData::StartupBehavior>(index);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_logLevel_currentIndexChanged(int value)
|
||||
void AdvSceneSwitcher::on_logLevel_currentIndexChanged(int idx)
|
||||
{
|
||||
if (loading) {
|
||||
return;
|
||||
}
|
||||
switcher->logLevel = static_cast<SwitcherData::LogLevel>(value);
|
||||
SetLogLevel(static_cast<LogLevel>(ui->logLevel->itemData(idx).toInt()));
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_autoStartEvent_currentIndexChanged(int index)
|
||||
@@ -383,6 +383,7 @@ void AdvSceneSwitcher::CheckFirstTimeSetup()
|
||||
switcher->firstBoot = false;
|
||||
DisplayMessage(
|
||||
obs_module_text("AdvSceneSwitcher.firstBootMessage"));
|
||||
switcher->Start();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -529,8 +530,8 @@ void SwitcherData::SaveGeneralSettings(obs_data_t *obj)
|
||||
obs_data_set_int(obj, "autoStartEvent",
|
||||
static_cast<int>(autoStartEvent));
|
||||
|
||||
obs_data_set_int(obj, "logLevel", static_cast<int>(logLevel));
|
||||
obs_data_set_int(obj, "logLevelVersion", 1);
|
||||
SaveLogLevel(obj);
|
||||
|
||||
obs_data_set_bool(obj, "showSystemTrayNotifications",
|
||||
showSystemTrayNotifications);
|
||||
obs_data_set_bool(obj, "disableHints", disableHints);
|
||||
@@ -586,25 +587,7 @@ void SwitcherData::LoadGeneralSettings(obs_data_t *obj)
|
||||
autoStartEvent =
|
||||
static_cast<AutoStart>(obs_data_get_int(obj, "autoStartEvent"));
|
||||
|
||||
logLevel = static_cast<LogLevel>(obs_data_get_int(obj, "logLevel"));
|
||||
if (obs_data_get_int(obj, "logLevelVersion") < 1) {
|
||||
enum OldLogLevel { DEFAULT, LOG_ACTION, VERBOSE };
|
||||
OldLogLevel oldLogLevel = static_cast<OldLogLevel>(
|
||||
obs_data_get_int(obj, "logLevel"));
|
||||
switch (oldLogLevel) {
|
||||
case DEFAULT:
|
||||
logLevel = LogLevel::DEFAULT;
|
||||
break;
|
||||
case LOG_ACTION:
|
||||
logLevel = LogLevel::LOG_ACTION;
|
||||
break;
|
||||
case VERBOSE:
|
||||
logLevel = LogLevel::VERBOSE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
LoadLogLevel(obj);
|
||||
|
||||
showSystemTrayNotifications =
|
||||
obs_data_get_bool(obj, "showSystemTrayNotifications");
|
||||
@@ -894,7 +877,9 @@ void AdvSceneSwitcher::SetupGeneralTab()
|
||||
SIGNAL(DurationChanged(const Duration &)), this,
|
||||
SLOT(CooldownDurationChanged(const Duration &)));
|
||||
|
||||
ui->logLevel->setCurrentIndex(static_cast<int>(switcher->logLevel));
|
||||
PopulateLogLevelSelection(ui->logLevel);
|
||||
ui->logLevel->setCurrentIndex(
|
||||
ui->logLevel->findData(static_cast<int>(GetLogLevel())));
|
||||
|
||||
ui->saveWindowGeo->setChecked(switcher->saveWindowGeo);
|
||||
ui->showTrayNotifications->setChecked(
|
||||
|
||||
@@ -61,12 +61,40 @@ MacroActionEdit::MacroActionEdit(QWidget *parent,
|
||||
setLayout(mainLayout);
|
||||
|
||||
_entryData = entryData;
|
||||
UpdateEntryData(id);
|
||||
SetupWidgets(true);
|
||||
|
||||
_actionStateTimer.start(300);
|
||||
_loading = false;
|
||||
}
|
||||
|
||||
void MacroActionEdit::SetupWidgets(bool basicSetup)
|
||||
{
|
||||
if (_allWidgetsAreSetup) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto id = (*_entryData)->GetId();
|
||||
_actionSelection->setCurrentText(
|
||||
obs_module_text(MacroActionFactory::GetActionName(id).c_str()));
|
||||
const bool enabled = (*_entryData)->Enabled();
|
||||
_enable->setChecked(enabled);
|
||||
SetDisableEffect(!enabled);
|
||||
HeaderInfoChanged(
|
||||
QString::fromStdString((*_entryData)->GetShortDesc()));
|
||||
|
||||
if (basicSetup) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto widget = MacroActionFactory::CreateWidget(id, this, *_entryData);
|
||||
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
|
||||
this, SLOT(HeaderInfoChanged(const QString &)));
|
||||
_section->SetContent(widget, (*_entryData)->GetCollapsed());
|
||||
SetFocusPolicyOfWidgets();
|
||||
|
||||
_allWidgetsAreSetup = true;
|
||||
}
|
||||
|
||||
void MacroActionEdit::ActionSelectionChanged(const QString &text)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
@@ -96,22 +124,6 @@ void MacroActionEdit::ActionSelectionChanged(const QString &text)
|
||||
SetFocusPolicyOfWidgets();
|
||||
}
|
||||
|
||||
void MacroActionEdit::UpdateEntryData(const std::string &id)
|
||||
{
|
||||
_actionSelection->setCurrentText(
|
||||
obs_module_text(MacroActionFactory::GetActionName(id).c_str()));
|
||||
const bool enabled = (*_entryData)->Enabled();
|
||||
_enable->setChecked(enabled);
|
||||
SetDisableEffect(!enabled);
|
||||
auto widget = MacroActionFactory::CreateWidget(id, this, *_entryData);
|
||||
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
|
||||
this, SLOT(HeaderInfoChanged(const QString &)));
|
||||
HeaderInfoChanged(
|
||||
QString::fromStdString((*_entryData)->GetShortDesc()));
|
||||
_section->SetContent(widget, (*_entryData)->GetCollapsed());
|
||||
SetFocusPolicyOfWidgets();
|
||||
}
|
||||
|
||||
void MacroActionEdit::SetEntryData(std::shared_ptr<MacroAction> *data)
|
||||
{
|
||||
_entryData = data;
|
||||
|
||||
@@ -17,7 +17,7 @@ public:
|
||||
QWidget *parent = nullptr,
|
||||
std::shared_ptr<MacroAction> * = nullptr,
|
||||
const std::string &id = MacroAction::GetDefaultID().data());
|
||||
void UpdateEntryData(const std::string &id);
|
||||
void SetupWidgets(bool basicSetup = false);
|
||||
void SetEntryData(std::shared_ptr<MacroAction> *);
|
||||
|
||||
private slots:
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
#include "macro-action-variable.hpp"
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "json-helpers.hpp"
|
||||
#include "layout-helpers.hpp"
|
||||
#include "math-helpers.hpp"
|
||||
#include "macro-condition-edit.hpp"
|
||||
#include "macro.hpp"
|
||||
#include "non-modal-dialog.hpp"
|
||||
#include "source-helpers.hpp"
|
||||
#include "ui-helpers.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
#include <random>
|
||||
@@ -385,6 +387,22 @@ bool MacroActionVariable::PerformAction()
|
||||
var->SetValue(*value);
|
||||
return true;
|
||||
}
|
||||
case Action::QUERY_JSON: {
|
||||
auto value = QueryJson(var->Value(), _jsonQuery);
|
||||
if (!value.has_value()) {
|
||||
return true;
|
||||
}
|
||||
var->SetValue(*value);
|
||||
return true;
|
||||
}
|
||||
case Action::ARRAY_JSON: {
|
||||
auto value = AccessJsonArrayIndex(var->Value(), _jsonIndex);
|
||||
if (!value.has_value()) {
|
||||
return true;
|
||||
}
|
||||
var->SetValue(*value);
|
||||
return true;
|
||||
}
|
||||
case Action::SET_TO_TEMPVAR: {
|
||||
auto tempVar = _tempVar.GetTempVariable(GetMacro());
|
||||
if (!tempVar) {
|
||||
@@ -471,6 +489,8 @@ bool MacroActionVariable::Save(obs_data_t *obj) const
|
||||
_randomNumberStart.Save(obj, "randomNumberStart");
|
||||
_randomNumberEnd.Save(obj, "randomNumberEnd");
|
||||
obs_data_set_bool(obj, "generateInteger", _generateInteger);
|
||||
_jsonQuery.Save(obj, "jsonQuery");
|
||||
_jsonIndex.Save(obj, "jsonIndex");
|
||||
|
||||
obs_data_set_int(obj, "version", 1);
|
||||
|
||||
@@ -527,6 +547,8 @@ bool MacroActionVariable::Load(obs_data_t *obj)
|
||||
_randomNumberStart.Load(obj, "randomNumberStart");
|
||||
_randomNumberEnd.Load(obj, "randomNumberEnd");
|
||||
_generateInteger = obs_data_get_bool(obj, "generateInteger");
|
||||
_jsonQuery.Load(obj, "jsonQuery");
|
||||
_jsonIndex.Load(obj, "jsonIndex");
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -626,6 +648,8 @@ void MacroActionVariable::ResolveVariablesToFixedValues()
|
||||
_envVariableName.ResolveVariables();
|
||||
_scene.ResolveVariables();
|
||||
_sceneItemIndex.ResolveVariables();
|
||||
_jsonQuery.ResolveVariables();
|
||||
_jsonIndex.ResolveVariables();
|
||||
}
|
||||
|
||||
void MacroActionVariable::DecrementCurrentSegmentVariableRef()
|
||||
@@ -655,8 +679,6 @@ static inline void populateActionSelection(QComboBox *list)
|
||||
"AdvSceneSwitcher.action.variable.type.subString"},
|
||||
{MacroActionVariable::Action::FIND_AND_REPLACE,
|
||||
"AdvSceneSwitcher.action.variable.type.findAndReplace"},
|
||||
{MacroActionVariable::Action::EXTRACT_JSON,
|
||||
"AdvSceneSwitcher.action.variable.type.extractJson"},
|
||||
{MacroActionVariable::Action::STRING_LENGTH,
|
||||
"AdvSceneSwitcher.action.variable.type.stringLength"},
|
||||
{MacroActionVariable::Action::TRIM,
|
||||
@@ -665,6 +687,14 @@ static inline void populateActionSelection(QComboBox *list)
|
||||
"AdvSceneSwitcher.action.variable.type.changeCase"},
|
||||
{true, ""}, // Separator
|
||||
|
||||
{MacroActionVariable::Action::EXTRACT_JSON,
|
||||
"AdvSceneSwitcher.action.variable.type.extractJsonField"},
|
||||
{MacroActionVariable::Action::QUERY_JSON,
|
||||
"AdvSceneSwitcher.action.variable.type.queryJson"},
|
||||
{MacroActionVariable::Action::ARRAY_JSON,
|
||||
"AdvSceneSwitcher.action.variable.type.accessJsonArray"},
|
||||
{true, ""}, // Separator
|
||||
|
||||
{MacroActionVariable::Action::SET_TO_TEMPVAR,
|
||||
"AdvSceneSwitcher.action.variable.type.setToTempvar"},
|
||||
{MacroActionVariable::Action::SET_CONDITION_VALUE,
|
||||
@@ -797,6 +827,9 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
||||
"AdvSceneSwitcher.action.variable.generateInteger"),
|
||||
this)),
|
||||
_randomLayout(new QVBoxLayout()),
|
||||
_jsonQuery(new VariableLineEdit(this)),
|
||||
_jsonQueryHelp(new QLabel(this)),
|
||||
_jsonIndex(new VariableSpinBox(this)),
|
||||
_entryLayout(new QHBoxLayout())
|
||||
{
|
||||
_numValue->setMinimum(-9999999999);
|
||||
@@ -826,6 +859,15 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
||||
_randomNumberStart->setMaximum(9999999999);
|
||||
_randomNumberEnd->setMinimum(-9999999999);
|
||||
_randomNumberEnd->setMaximum(9999999999);
|
||||
const QString path = GetThemeTypeName() == "Light"
|
||||
? ":/res/images/help.svg"
|
||||
: ":/res/images/help_light.svg";
|
||||
const QIcon icon(path);
|
||||
const QPixmap pixmap = icon.pixmap(QSize(16, 16));
|
||||
_jsonQueryHelp->setPixmap(pixmap);
|
||||
_jsonQueryHelp->setToolTip(obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.type.queryJson.info"));
|
||||
_jsonIndex->setMaximum(999);
|
||||
|
||||
QWidget::connect(_variables, SIGNAL(SelectionChanged(const QString &)),
|
||||
this, SLOT(VariableChanged(const QString &)));
|
||||
@@ -912,6 +954,12 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
||||
SLOT(RandomNumberEndChanged(const NumberVariable<double> &)));
|
||||
QWidget::connect(_generateInteger, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(GenerateIntegerChanged(int)));
|
||||
QWidget::connect(_jsonQuery, SIGNAL(editingFinished()), this,
|
||||
SLOT(JsonQueryChanged()));
|
||||
QWidget::connect(
|
||||
_jsonIndex,
|
||||
SIGNAL(NumberVariableChanged(const NumberVariable<int> &)),
|
||||
this, SLOT(JsonIndexChanged(const NumberVariable<int> &)));
|
||||
|
||||
const std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{variables}}", _variables},
|
||||
@@ -943,39 +991,42 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
||||
{"{{randomNumberStart}}", _randomNumberStart},
|
||||
{"{{randomNumberEnd}}", _randomNumberEnd},
|
||||
{"{{generateInteger}}", _generateInteger},
|
||||
{"{{jsonQuery}}", _jsonQuery},
|
||||
{"{{jsonQueryHelp}}", _jsonQueryHelp},
|
||||
{"{{jsonIndex}}", _jsonIndex},
|
||||
};
|
||||
PlaceWidgets(
|
||||
obs_module_text("AdvSceneSwitcher.action.variable.entry.other"),
|
||||
_entryLayout, widgetPlaceholders);
|
||||
PlaceWidgets(obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.layout.other"),
|
||||
_entryLayout, widgetPlaceholders);
|
||||
|
||||
PlaceWidgets(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.entry.substringIndex"),
|
||||
"AdvSceneSwitcher.action.variable.layout.substringIndex"),
|
||||
_subStringIndexEntryLayout, widgetPlaceholders);
|
||||
|
||||
PlaceWidgets(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.entry.substringRegex"),
|
||||
"AdvSceneSwitcher.action.variable.layout.substringRegex"),
|
||||
_subStringRegexEntryLayout, widgetPlaceholders);
|
||||
|
||||
PlaceWidgets(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.entry.findAndReplace"),
|
||||
"AdvSceneSwitcher.action.variable.layout.findAndReplace"),
|
||||
_findReplaceLayout, widgetPlaceholders, false);
|
||||
|
||||
PlaceWidgets(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.entry.userInput.customPrompt"),
|
||||
"AdvSceneSwitcher.action.variable.layout.userInput.customPrompt"),
|
||||
_promptLayout, widgetPlaceholders);
|
||||
PlaceWidgets(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.entry.userInput.placeholder"),
|
||||
"AdvSceneSwitcher.action.variable.layout.userInput.placeholder"),
|
||||
_placeholderLayout, widgetPlaceholders);
|
||||
|
||||
auto randomLayout = new QHBoxLayout();
|
||||
PlaceWidgets(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.entry.randomNumber"),
|
||||
"AdvSceneSwitcher.action.variable.layout.randomNumber"),
|
||||
randomLayout, widgetPlaceholders);
|
||||
_randomLayout->addLayout(randomLayout);
|
||||
_randomLayout->addWidget(_generateInteger);
|
||||
@@ -1057,17 +1108,15 @@ void MacroActionVariableEdit::UpdateEntryData()
|
||||
_randomNumberStart->SetValue(_entryData->_randomNumberStart);
|
||||
_randomNumberEnd->SetValue(_entryData->_randomNumberEnd);
|
||||
_generateInteger->setChecked(_entryData->_generateInteger);
|
||||
_jsonQuery->setText(_entryData->_jsonQuery);
|
||||
_jsonIndex->SetValue(_entryData->_jsonIndex);
|
||||
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::VariableChanged(const QString &text)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_variable = GetWeakVariableByQString(text);
|
||||
emit HeaderInfoChanged(
|
||||
QString::fromStdString(_entryData->GetShortDesc()));
|
||||
@@ -1075,11 +1124,7 @@ void MacroActionVariableEdit::VariableChanged(const QString &text)
|
||||
|
||||
void MacroActionVariableEdit::Variable2Changed(const QString &text)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_variable2 = GetWeakVariableByQString(text);
|
||||
}
|
||||
|
||||
@@ -1105,11 +1150,7 @@ void MacroActionVariableEdit::ActionChanged(int idx)
|
||||
|
||||
void MacroActionVariableEdit::StrValueChanged()
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_strValue = _strValue->toPlainText().toStdString();
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
@@ -1118,21 +1159,13 @@ void MacroActionVariableEdit::StrValueChanged()
|
||||
void MacroActionVariableEdit::NumValueChanged(
|
||||
const NumberVariable<double> &value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_numValue = value;
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::SegmentIndexChanged(const IntVariable &val)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->SetSegmentIndexValue(val - 1);
|
||||
}
|
||||
|
||||
@@ -1238,32 +1271,20 @@ void MacroActionVariableEdit::MacroSegmentOrderChanged()
|
||||
void MacroActionVariableEdit::SubStringStartChanged(
|
||||
const NumberVariable<int> &start)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_subStringStart = start;
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::SubStringSizeChanged(
|
||||
const NumberVariable<int> &size)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_subStringSize = size;
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::SubStringRegexChanged(const RegexConfig &conf)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_subStringRegex = conf;
|
||||
|
||||
SetWidgetVisibility();
|
||||
@@ -1271,11 +1292,7 @@ void MacroActionVariableEdit::SubStringRegexChanged(const RegexConfig &conf)
|
||||
|
||||
void MacroActionVariableEdit::RegexPatternChanged()
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_regexPattern = _regexPattern->toPlainText().toStdString();
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
@@ -1284,21 +1301,13 @@ void MacroActionVariableEdit::RegexPatternChanged()
|
||||
void MacroActionVariableEdit::RegexMatchIdxChanged(
|
||||
const NumberVariable<int> &index)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_regexMatchIdx = index;
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::FindStrValueChanged()
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_findStr = _findStr->toPlainText().toStdString();
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
@@ -1306,11 +1315,7 @@ void MacroActionVariableEdit::FindStrValueChanged()
|
||||
|
||||
void MacroActionVariableEdit::FindRegexChanged(const RegexConfig &conf)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_findRegex = conf;
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
@@ -1318,11 +1323,7 @@ void MacroActionVariableEdit::FindRegexChanged(const RegexConfig &conf)
|
||||
|
||||
void MacroActionVariableEdit::ReplaceStrValueChanged()
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_replaceStr = _replaceStr->toPlainText().toStdString();
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
@@ -1330,11 +1331,7 @@ void MacroActionVariableEdit::ReplaceStrValueChanged()
|
||||
|
||||
void MacroActionVariableEdit::MathExpressionChanged()
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_mathExpression = _mathExpression->text().toStdString();
|
||||
|
||||
// In case of invalid expression display an error
|
||||
@@ -1352,73 +1349,45 @@ void MacroActionVariableEdit::MathExpressionChanged()
|
||||
|
||||
void MacroActionVariableEdit::UseCustomPromptChanged(int value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_useCustomPrompt = value;
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::InputPromptChanged()
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_inputPrompt = _inputPrompt->text().toStdString();
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::UseInputPlaceholderChanged(int value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_useInputPlaceholder = value;
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::InputPlaceholderChanged()
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_inputPlaceholder = _inputPlaceholder->text().toStdString();
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::EnvVariableChanged()
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_envVariableName = _envVariable->text().toStdString();
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::SceneChanged(const SceneSelection &scene)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_scene = scene;
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::SelectionChanged(const TempVariableRef &var)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_tempVar = var;
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
@@ -1426,21 +1395,13 @@ void MacroActionVariableEdit::SelectionChanged(const TempVariableRef &var)
|
||||
void MacroActionVariableEdit::SceneItemIndexChanged(
|
||||
const NumberVariable<int> &value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_sceneItemIndex = value;
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::DirectionChanged(int value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_direction =
|
||||
static_cast<MacroActionVariable::Direction>(value);
|
||||
}
|
||||
@@ -1448,21 +1409,13 @@ void MacroActionVariableEdit::DirectionChanged(int value)
|
||||
void MacroActionVariableEdit::StringLengthChanged(
|
||||
const NumberVariable<int> &value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_stringLength = value;
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::CharSelectionChanged(const QString &character)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
if (character.isEmpty()) {
|
||||
_entryData->_paddingChar = ' ';
|
||||
} else {
|
||||
@@ -1472,11 +1425,7 @@ void MacroActionVariableEdit::CharSelectionChanged(const QString &character)
|
||||
|
||||
void MacroActionVariableEdit::CaseTypeChanged(int index)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_caseType = static_cast<MacroActionVariable::CaseType>(
|
||||
_caseType->itemData(index).toInt());
|
||||
}
|
||||
@@ -1501,6 +1450,18 @@ void MacroActionVariableEdit::GenerateIntegerChanged(int value)
|
||||
_entryData->_generateInteger = value;
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::JsonQueryChanged()
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_jsonQuery = _jsonQuery->text().toStdString();
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::JsonIndexChanged(const NumberVariable<int> &value)
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_jsonIndex = value;
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::SetWidgetVisibility()
|
||||
{
|
||||
if (!_entryData) {
|
||||
@@ -1524,19 +1485,22 @@ void MacroActionVariableEdit::SetWidgetVisibility()
|
||||
{"{{stringLength}}", _stringLength},
|
||||
{"{{paddingCharSelection}}", _paddingCharSelection},
|
||||
{"{{caseType}}", _caseType},
|
||||
{"{{jsonQuery}}", _jsonQuery},
|
||||
{"{{jsonQueryHelp}}", _jsonQueryHelp},
|
||||
{"{{jsonIndex}}", _jsonIndex},
|
||||
};
|
||||
|
||||
const char *layoutString = "";
|
||||
if (_entryData->_action == MacroActionVariable::Action::PAD) {
|
||||
layoutString = obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.entry.pad");
|
||||
"AdvSceneSwitcher.action.variable.layout.pad");
|
||||
} else if (_entryData->_action ==
|
||||
MacroActionVariable::Action::TRUNCATE) {
|
||||
layoutString = obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.entry.truncate");
|
||||
"AdvSceneSwitcher.action.variable.layout.truncate");
|
||||
} else {
|
||||
layoutString = obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.entry.other");
|
||||
"AdvSceneSwitcher.action.variable.layout.other");
|
||||
}
|
||||
|
||||
for (const auto &[_, widget] : widgetPlaceholders) {
|
||||
@@ -1552,7 +1516,8 @@ void MacroActionVariableEdit::SetWidgetVisibility()
|
||||
MacroActionVariable::Action::MATH_EXPRESSION ||
|
||||
_entryData->_action == MacroActionVariable::Action::ENV_VARIABLE ||
|
||||
_entryData->_action == MacroActionVariable::Action::STRING_LENGTH ||
|
||||
_entryData->_action == MacroActionVariable::Action::EXTRACT_JSON) {
|
||||
_entryData->_action == MacroActionVariable::Action::EXTRACT_JSON ||
|
||||
_entryData->_action == MacroActionVariable::Action::QUERY_JSON) {
|
||||
RemoveStretchIfPresent(_entryLayout);
|
||||
} else {
|
||||
AddStretchIfNecessary(_entryLayout);
|
||||
@@ -1664,6 +1629,12 @@ void MacroActionVariableEdit::SetWidgetVisibility()
|
||||
SetLayoutVisible(_randomLayout,
|
||||
_entryData->_action ==
|
||||
MacroActionVariable::Action::RANDOM_NUMBER);
|
||||
_jsonQuery->setVisible(_entryData->_action ==
|
||||
MacroActionVariable::Action::QUERY_JSON);
|
||||
_jsonQueryHelp->setVisible(_entryData->_action ==
|
||||
MacroActionVariable::Action::QUERY_JSON);
|
||||
_jsonIndex->setVisible(_entryData->_action ==
|
||||
MacroActionVariable::Action::ARRAY_JSON);
|
||||
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
|
||||
@@ -53,6 +53,8 @@ public:
|
||||
TRIM,
|
||||
CHANGE_CASE,
|
||||
RANDOM_NUMBER,
|
||||
QUERY_JSON,
|
||||
ARRAY_JSON,
|
||||
};
|
||||
|
||||
Action _action = Action::SET_VALUE;
|
||||
@@ -104,6 +106,9 @@ public:
|
||||
DoubleVariable _randomNumberEnd = 100;
|
||||
bool _generateInteger = true;
|
||||
|
||||
StringVariable _jsonQuery = "$.some.nested.value";
|
||||
IntVariable _jsonIndex = 0;
|
||||
|
||||
private:
|
||||
void DecrementCurrentSegmentVariableRef();
|
||||
void HandleIndexSubString(Variable *);
|
||||
@@ -169,6 +174,8 @@ private slots:
|
||||
void RandomNumberStartChanged(const NumberVariable<double> &);
|
||||
void RandomNumberEndChanged(const NumberVariable<double> &);
|
||||
void GenerateIntegerChanged(int);
|
||||
void JsonQueryChanged();
|
||||
void JsonIndexChanged(const NumberVariable<int> &);
|
||||
|
||||
signals:
|
||||
void HeaderInfoChanged(const QString &);
|
||||
@@ -218,6 +225,9 @@ private:
|
||||
VariableDoubleSpinBox *_randomNumberEnd;
|
||||
QCheckBox *_generateInteger;
|
||||
QVBoxLayout *_randomLayout;
|
||||
VariableLineEdit *_jsonQuery;
|
||||
QLabel *_jsonQueryHelp;
|
||||
VariableSpinBox *_jsonIndex;
|
||||
QHBoxLayout *_entryLayout;
|
||||
|
||||
std::shared_ptr<MacroActionVariable> _entryData;
|
||||
|
||||
@@ -138,7 +138,7 @@ MacroConditionEdit::MacroConditionEdit(
|
||||
mainLayout->addWidget(_frame);
|
||||
setLayout(mainLayout);
|
||||
|
||||
UpdateEntryData(id);
|
||||
SetupWidgets(true);
|
||||
_loading = false;
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ void MacroConditionEdit::LogicSelectionChanged(int idx)
|
||||
SetEnableAppearance(logic != Logic::Type::NONE);
|
||||
}
|
||||
|
||||
bool MacroConditionEdit::IsRootNode()
|
||||
bool MacroConditionEdit::IsRootNode() const
|
||||
{
|
||||
return _isRoot;
|
||||
}
|
||||
@@ -178,23 +178,36 @@ void MacroConditionEdit::SetRootNode(bool root)
|
||||
SetLogicSelection();
|
||||
}
|
||||
|
||||
void MacroConditionEdit::UpdateEntryData(const std::string &id)
|
||||
void MacroConditionEdit::SetupWidgets(bool basicSetup)
|
||||
{
|
||||
if (_allWidgetsAreSetup) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto id = (*_entryData)->GetId();
|
||||
_conditionSelection->setCurrentText(obs_module_text(
|
||||
MacroConditionFactory::GetConditionName(id).c_str()));
|
||||
auto widget =
|
||||
MacroConditionFactory::CreateWidget(id, this, *_entryData);
|
||||
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
|
||||
this, SLOT(HeaderInfoChanged(const QString &)));
|
||||
|
||||
HeaderInfoChanged(
|
||||
QString::fromStdString((*_entryData)->GetShortDesc()));
|
||||
SetLogicSelection();
|
||||
_section->SetContent(widget, (*_entryData)->GetCollapsed());
|
||||
|
||||
_dur->setVisible(MacroConditionFactory::UsesDurationModifier(id));
|
||||
auto modifier = (*_entryData)->GetDurationModifier();
|
||||
_dur->SetValue(modifier);
|
||||
|
||||
if (basicSetup) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto widget =
|
||||
MacroConditionFactory::CreateWidget(id, this, *_entryData);
|
||||
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
|
||||
this, SLOT(HeaderInfoChanged(const QString &)));
|
||||
_section->SetContent(widget, (*_entryData)->GetCollapsed());
|
||||
SetFocusPolicyOfWidgets();
|
||||
|
||||
_allWidgetsAreSetup = true;
|
||||
}
|
||||
|
||||
void MacroConditionEdit::SetEntryData(std::shared_ptr<MacroCondition> *data)
|
||||
|
||||
@@ -39,9 +39,9 @@ public:
|
||||
std::shared_ptr<MacroCondition> * = nullptr,
|
||||
const std::string &id = MacroCondition::GetDefaultID().data(),
|
||||
bool root = true);
|
||||
bool IsRootNode();
|
||||
bool IsRootNode() const;
|
||||
void SetRootNode(bool);
|
||||
void UpdateEntryData(const std::string &id);
|
||||
void SetupWidgets(bool basicSetup = false);
|
||||
void SetEntryData(std::shared_ptr<MacroCondition> *);
|
||||
|
||||
private slots:
|
||||
|
||||
@@ -35,6 +35,9 @@ MacroSegmentList::MacroSegmentList(QWidget *parent)
|
||||
setWidget(wrapper);
|
||||
setWidgetResizable(true);
|
||||
setAcceptDrops(true);
|
||||
|
||||
connect(verticalScrollBar(), &QScrollBar::valueChanged, this,
|
||||
[this]() { SetupVisibleMacroSegmentWidgets(); });
|
||||
}
|
||||
|
||||
MacroSegmentList::~MacroSegmentList()
|
||||
@@ -98,16 +101,18 @@ void MacroSegmentList::SetHelpMsgVisible(bool visible) const
|
||||
_helpMsg->setVisible(visible);
|
||||
}
|
||||
|
||||
void MacroSegmentList::Insert(int idx, MacroSegmentEdit *widget)
|
||||
void MacroSegmentList::Insert(int idx, QWidget *widget)
|
||||
{
|
||||
widget->installEventFilter(this);
|
||||
_contentLayout->insertWidget(idx, widget);
|
||||
SetupVisibleMacroSegmentWidgets();
|
||||
}
|
||||
|
||||
void MacroSegmentList::Add(QWidget *widget)
|
||||
{
|
||||
widget->installEventFilter(this);
|
||||
_contentLayout->addWidget(widget);
|
||||
SetupVisibleMacroSegmentWidgets();
|
||||
}
|
||||
|
||||
void MacroSegmentList::Remove(int idx) const
|
||||
@@ -322,6 +327,36 @@ QRect MacroSegmentList::GetContentItemRectWithPadding(int idx) const
|
||||
return rect;
|
||||
}
|
||||
|
||||
void MacroSegmentList::SetVisibilityCheckEnable(bool enable)
|
||||
{
|
||||
_checkVisibility = enable;
|
||||
|
||||
if (_checkVisibility) {
|
||||
QTimer::singleShot(0, this, [this]() {
|
||||
SetupVisibleMacroSegmentWidgets();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void MacroSegmentList::SetupVisibleMacroSegmentWidgets()
|
||||
{
|
||||
if (!_checkVisibility) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto viewportRect = viewport()->rect();
|
||||
|
||||
for (auto segment : widget()->findChildren<MacroSegmentEdit *>()) {
|
||||
const auto pos = segment->mapTo(viewport(), QPoint(0, 0));
|
||||
const QRect rect(pos, segment->size());
|
||||
if (!viewportRect.intersects(rect)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
segment->SetupWidgets();
|
||||
}
|
||||
}
|
||||
|
||||
int MacroSegmentList::GetSegmentIndexFromPos(const QPoint &pos) const
|
||||
{
|
||||
int idx = -1;
|
||||
@@ -455,4 +490,10 @@ void MacroSegmentList::dropEvent(QDropEvent *event)
|
||||
_dragPosition = -1;
|
||||
}
|
||||
|
||||
void MacroSegmentList::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
QWidget::resizeEvent(event);
|
||||
SetupVisibleMacroSegmentWidgets();
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -20,7 +20,7 @@ public:
|
||||
MacroSegmentEdit *WidgetAt(int idx) const;
|
||||
MacroSegmentEdit *WidgetAt(const QPoint &) const;
|
||||
int IndexAt(const QPoint &) const;
|
||||
void Insert(int idx, MacroSegmentEdit *widget);
|
||||
void Insert(int idx, QWidget *widget);
|
||||
void Add(QWidget *widget);
|
||||
void Remove(int idx) const;
|
||||
void Clear(int idx = 0) const; // Clear all elements >= idx
|
||||
@@ -28,6 +28,7 @@ public:
|
||||
void SetCollapsed(bool) const;
|
||||
void SetSelection(int idx) const;
|
||||
QVBoxLayout *ContentLayout() const { return _contentLayout; }
|
||||
void SetVisibilityCheckEnable(bool enable);
|
||||
|
||||
signals:
|
||||
void SelectionChanged(int idx);
|
||||
@@ -42,8 +43,10 @@ protected:
|
||||
void dragEnterEvent(QDragEnterEvent *event);
|
||||
void dragMoveEvent(QDragMoveEvent *event);
|
||||
void dropEvent(QDropEvent *event);
|
||||
void resizeEvent(QResizeEvent *event);
|
||||
|
||||
private:
|
||||
void SetupVisibleMacroSegmentWidgets();
|
||||
int GetSegmentIndexFromPos(const QPoint &) const;
|
||||
int GetDragIndex(const QPoint &) const;
|
||||
int GetDropIndex(const QPoint &) const;
|
||||
@@ -62,6 +65,8 @@ private:
|
||||
QVBoxLayout *_layout;
|
||||
QVBoxLayout *_contentLayout;
|
||||
QLabel *_helpMsg;
|
||||
|
||||
bool _checkVisibility = true;
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -324,7 +324,7 @@ void MacroSegmentEdit::HeaderInfoChanged(const QString &text)
|
||||
_headerInfo->setText(text);
|
||||
}
|
||||
|
||||
void MacroSegmentEdit::Collapsed(bool collapsed)
|
||||
void MacroSegmentEdit::Collapsed(bool collapsed) const
|
||||
{
|
||||
if (Data()) {
|
||||
Data()->SetCollapsed(collapsed);
|
||||
|
||||
@@ -48,7 +48,7 @@ protected:
|
||||
friend void IncrementVariableRef(MacroSegment *);
|
||||
friend void DecrementVariableRef(MacroSegment *);
|
||||
void SetVariableValue(const std::string &value);
|
||||
bool IsReferencedInVars() { return _variableRefs != 0; }
|
||||
bool IsReferencedInVars() const { return _variableRefs != 0; }
|
||||
|
||||
virtual void SetupTempVars();
|
||||
void AddTempvar(const std::string &id, const std::string &name,
|
||||
@@ -106,12 +106,13 @@ public:
|
||||
void SetCollapsed(bool collapsed);
|
||||
void SetSelected(bool);
|
||||
virtual std::shared_ptr<MacroSegment> Data() const = 0;
|
||||
virtual void SetupWidgets(bool basicSetup = false) = 0;
|
||||
|
||||
public slots:
|
||||
void HeaderInfoChanged(const QString &);
|
||||
|
||||
protected slots:
|
||||
void Collapsed(bool);
|
||||
void Collapsed(bool) const;
|
||||
signals:
|
||||
void MacroAdded(const QString &name);
|
||||
void MacroRemoved(const QString &name);
|
||||
@@ -130,6 +131,7 @@ protected:
|
||||
QLabel *_headerInfo;
|
||||
QWidget *_frame;
|
||||
QVBoxLayout *_contentLayout;
|
||||
bool _allWidgetsAreSetup = false;
|
||||
|
||||
private:
|
||||
enum class DropLineState {
|
||||
|
||||
@@ -19,6 +19,8 @@ void GlobalMacroSettings::Save(obs_data_t *obj) const
|
||||
obs_data_set_bool(data, "highlightExecuted", _highlightExecuted);
|
||||
obs_data_set_bool(data, "highlightConditions", _highlightConditions);
|
||||
obs_data_set_bool(data, "highlightActions", _highlightActions);
|
||||
obs_data_set_bool(data, "newMacroCheckInParallel",
|
||||
_newMacroCheckInParallel);
|
||||
obs_data_set_bool(data, "newMacroRegisterHotkey",
|
||||
_newMacroRegisterHotkeys);
|
||||
obs_data_set_bool(data, "newMacroUseShortCircuitEvaluation",
|
||||
@@ -41,6 +43,8 @@ void GlobalMacroSettings::Load(obs_data_t *obj)
|
||||
_highlightExecuted = obs_data_get_bool(data, "highlightExecuted");
|
||||
_highlightConditions = obs_data_get_bool(data, "highlightConditions");
|
||||
_highlightActions = obs_data_get_bool(data, "highlightActions");
|
||||
_newMacroCheckInParallel =
|
||||
obs_data_get_bool(data, "newMacroCheckInParallel");
|
||||
_newMacroRegisterHotkeys =
|
||||
obs_data_get_bool(data, "newMacroRegisterHotkey");
|
||||
_newMacroUseShortCircuitEvaluation =
|
||||
@@ -62,12 +66,16 @@ MacroSettingsDialog::MacroSettingsDialog(QWidget *parent,
|
||||
"AdvSceneSwitcher.macroTab.highlightTrueConditions"))),
|
||||
_highlightActions(new QCheckBox(obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.highlightPerformedActions"))),
|
||||
_newMacroCheckInParallel(new QCheckBox(obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.newMacroCheckInParallel"))),
|
||||
_newMacroRegisterHotkeys(new QCheckBox(obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.newMacroRegisterHotkey"))),
|
||||
_newMacroUseShortCircuitEvaluation(new QCheckBox(obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.newMacroUseShortCircuitEvaluation"))),
|
||||
_saveSettingsOnMacroChange(new QCheckBox(obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.saveSettingsOnMacroChange"))),
|
||||
_currentCheckInParallel(new QCheckBox(obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.currentCheckInParallel"))),
|
||||
_currentMacroRegisterHotkeys(new QCheckBox(obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.currentRegisterHotkeys"))),
|
||||
_currentUseShortCircuitEvaluation(new QCheckBox(obs_module_text(
|
||||
@@ -107,6 +115,11 @@ MacroSettingsDialog::MacroSettingsDialog(QWidget *parent,
|
||||
setWindowModality(Qt::WindowModality::WindowModal);
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
|
||||
_newMacroCheckInParallel->setToolTip(obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.checkInParallel.tooltip"));
|
||||
_currentCheckInParallel->setToolTip(obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.checkInParallel.tooltip"));
|
||||
|
||||
_newMacroUseShortCircuitEvaluation->setToolTip(obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.shortCircuit.tooltip"));
|
||||
_saveSettingsOnMacroChange->setToolTip(obs_module_text(
|
||||
@@ -146,6 +159,8 @@ MacroSettingsDialog::MacroSettingsDialog(QWidget *parent,
|
||||
obs_module_text("AdvSceneSwitcher.macroTab.generalSettings"));
|
||||
auto generalLayout = new QVBoxLayout;
|
||||
generalLayout->addWidget(_saveSettingsOnMacroChange);
|
||||
generalLayout->addWidget(_currentCheckInParallel);
|
||||
generalLayout->addWidget(_newMacroCheckInParallel);
|
||||
generalLayout->addWidget(_currentSkipOnStartup);
|
||||
generalLayout->addWidget(_currentStopActionsIfNotDone);
|
||||
generalLayout->addWidget(_currentUseShortCircuitEvaluation);
|
||||
@@ -273,6 +288,7 @@ MacroSettingsDialog::MacroSettingsDialog(QWidget *parent,
|
||||
_highlightExecutedMacros->setChecked(settings._highlightExecuted);
|
||||
_highlightConditions->setChecked(settings._highlightConditions);
|
||||
_highlightActions->setChecked(settings._highlightActions);
|
||||
_newMacroCheckInParallel->setChecked(settings._newMacroCheckInParallel);
|
||||
_newMacroRegisterHotkeys->setChecked(settings._newMacroRegisterHotkeys);
|
||||
_newMacroUseShortCircuitEvaluation->setChecked(
|
||||
settings._newMacroUseShortCircuitEvaluation);
|
||||
@@ -280,20 +296,23 @@ MacroSettingsDialog::MacroSettingsDialog(QWidget *parent,
|
||||
settings._saveSettingsOnMacroChange);
|
||||
|
||||
if (!macro || macro->IsGroup()) {
|
||||
hotkeyOptions->hide();
|
||||
|
||||
// General group
|
||||
_currentSkipOnStartup->hide();
|
||||
_currentStopActionsIfNotDone->hide();
|
||||
_currentUseShortCircuitEvaluation->hide();
|
||||
_currentCheckInParallel->hide();
|
||||
SetLayoutVisible(customConditionIntervalLayout, false);
|
||||
SetLayoutVisible(pauseStateSaveBehavorLayout, false);
|
||||
|
||||
// Hotkey group
|
||||
_currentMacroRegisterHotkeys->hide();
|
||||
|
||||
inputOptions->hide();
|
||||
_dockOptions->hide();
|
||||
return;
|
||||
}
|
||||
|
||||
_currentCheckInParallel->setChecked(macro->CheckInParallel());
|
||||
_currentMacroRegisterHotkeys->setChecked(macro->PauseHotkeysEnabled());
|
||||
_currentUseShortCircuitEvaluation->setChecked(
|
||||
macro->ShortCircuitEvaluationEnabled());
|
||||
@@ -431,6 +450,8 @@ bool MacroSettingsDialog::AskForSettings(QWidget *parent,
|
||||
userInput._highlightConditions =
|
||||
dialog._highlightConditions->isChecked();
|
||||
userInput._highlightActions = dialog._highlightActions->isChecked();
|
||||
userInput._newMacroCheckInParallel =
|
||||
dialog._newMacroCheckInParallel->isChecked();
|
||||
userInput._newMacroRegisterHotkeys =
|
||||
dialog._newMacroRegisterHotkeys->isChecked();
|
||||
userInput._newMacroUseShortCircuitEvaluation =
|
||||
@@ -441,6 +462,7 @@ bool MacroSettingsDialog::AskForSettings(QWidget *parent,
|
||||
return true;
|
||||
}
|
||||
|
||||
macro->SetCheckInParallel(dialog._currentCheckInParallel->isChecked());
|
||||
macro->EnablePauseHotkeys(
|
||||
dialog._currentMacroRegisterHotkeys->isChecked());
|
||||
macro->SetShortCircuitEvaluation(
|
||||
|
||||
@@ -20,9 +20,10 @@ public:
|
||||
void Save(obs_data_t *obj) const;
|
||||
void Load(obs_data_t *obj);
|
||||
|
||||
bool _highlightExecuted = false;
|
||||
bool _highlightConditions = false;
|
||||
bool _highlightActions = false;
|
||||
bool _highlightExecuted = true;
|
||||
bool _highlightConditions = true;
|
||||
bool _highlightActions = true;
|
||||
bool _newMacroCheckInParallel = false;
|
||||
bool _newMacroRegisterHotkeys = true;
|
||||
bool _newMacroUseShortCircuitEvaluation = false;
|
||||
bool _saveSettingsOnMacroChange = true;
|
||||
@@ -52,10 +53,12 @@ private:
|
||||
QCheckBox *_highlightExecutedMacros;
|
||||
QCheckBox *_highlightConditions;
|
||||
QCheckBox *_highlightActions;
|
||||
QCheckBox *_newMacroCheckInParallel;
|
||||
QCheckBox *_newMacroRegisterHotkeys;
|
||||
QCheckBox *_newMacroUseShortCircuitEvaluation;
|
||||
QCheckBox *_saveSettingsOnMacroChange;
|
||||
// Current macro specific settings
|
||||
QCheckBox *_currentCheckInParallel;
|
||||
QCheckBox *_currentMacroRegisterHotkeys;
|
||||
QCheckBox *_currentUseShortCircuitEvaluation;
|
||||
QCheckBox *_currentUseCustomConditionCheckInterval;
|
||||
|
||||
@@ -27,6 +27,14 @@ namespace advss {
|
||||
static QObject *addPulse = nullptr;
|
||||
static QTimer onChangeHighlightTimer;
|
||||
|
||||
static void disableAddButtonHighlight()
|
||||
{
|
||||
if (addPulse) {
|
||||
addPulse->deleteLater();
|
||||
addPulse = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static bool macroNameExists(const std::string &name)
|
||||
{
|
||||
return !!GetMacroByName(name.c_str());
|
||||
@@ -86,9 +94,7 @@ bool AdvSceneSwitcher::AddNewMacro(std::shared_ptr<Macro> &res,
|
||||
return false;
|
||||
}
|
||||
|
||||
res = std::make_shared<Macro>(
|
||||
name, GetGlobalMacroSettings()._newMacroRegisterHotkeys,
|
||||
GetGlobalMacroSettings()._newMacroUseShortCircuitEvaluation);
|
||||
res = std::make_shared<Macro>(name, GetGlobalMacroSettings());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -100,10 +106,7 @@ void AdvSceneSwitcher::on_macroAdd_clicked()
|
||||
return;
|
||||
}
|
||||
|
||||
if (addPulse) {
|
||||
addPulse->deleteLater();
|
||||
addPulse = nullptr;
|
||||
}
|
||||
disableAddButtonHighlight();
|
||||
|
||||
auto selectedMacro = GetSelectedMacro();
|
||||
if (!selectedMacro) {
|
||||
@@ -160,7 +163,7 @@ void AdvSceneSwitcher::RemoveSelectedMacros()
|
||||
if (macroCount == 1) {
|
||||
QString deleteWarning = obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.removeSingleMacroPopup.text");
|
||||
auto macro = macros.at(0);
|
||||
auto ¯o = macros.at(0);
|
||||
deleteWarning = deleteWarning.arg(
|
||||
QString::fromStdString(macro->Name()));
|
||||
|
||||
@@ -200,7 +203,7 @@ void AdvSceneSwitcher::on_macroRemove_clicked()
|
||||
RemoveSelectedMacros();
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_macroUp_clicked()
|
||||
void AdvSceneSwitcher::on_macroUp_clicked() const
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
@@ -209,7 +212,7 @@ void AdvSceneSwitcher::on_macroUp_clicked()
|
||||
ui->macros->Up(macro);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_macroDown_clicked()
|
||||
void AdvSceneSwitcher::on_macroDown_clicked() const
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
@@ -279,7 +282,7 @@ static void addGroupSubitems(std::vector<std::shared_ptr<Macro>> ¯os,
|
||||
macros.insert(it, subitems.begin(), subitems.end());
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::ExportMacros()
|
||||
void AdvSceneSwitcher::ExportMacros() const
|
||||
{
|
||||
auto selectedMacros = GetSelectedMacros();
|
||||
auto macros = selectedMacros;
|
||||
@@ -490,6 +493,7 @@ void AdvSceneSwitcher::ImportMacros()
|
||||
|
||||
ui->macros->Reset(GetMacros(),
|
||||
GetGlobalMacroSettings()._highlightExecuted);
|
||||
disableAddButtonHighlight();
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_macroName_editingFinished()
|
||||
@@ -510,7 +514,7 @@ void AdvSceneSwitcher::on_macroName_editingFinished()
|
||||
RenameMacro(macro, newName);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_runMacroInParallel_stateChanged(int value)
|
||||
void AdvSceneSwitcher::on_runMacroInParallel_stateChanged(int value) const
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
@@ -520,7 +524,7 @@ void AdvSceneSwitcher::on_runMacroInParallel_stateChanged(int value)
|
||||
macro->SetRunInParallel(value);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_runMacroOnChange_stateChanged(int value)
|
||||
void AdvSceneSwitcher::on_runMacroOnChange_stateChanged(int value) const
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
@@ -533,29 +537,56 @@ void AdvSceneSwitcher::on_runMacroOnChange_stateChanged(int value)
|
||||
void AdvSceneSwitcher::PopulateMacroActions(Macro &m, uint32_t afterIdx)
|
||||
{
|
||||
auto &actions = m.Actions();
|
||||
|
||||
// The layout system has not completed geometry propagation yet, so we
|
||||
// can skip those checks for now
|
||||
ui->actionsList->SetVisibilityCheckEnable(false);
|
||||
|
||||
for (; afterIdx < actions.size(); afterIdx++) {
|
||||
auto newEntry = new MacroActionEdit(this, &actions[afterIdx],
|
||||
actions[afterIdx]->GetId());
|
||||
ui->actionsList->Add(newEntry);
|
||||
}
|
||||
ui->actionsList->SetHelpMsgVisible(actions.size() == 0);
|
||||
|
||||
// Give the layout system time before enabling the visibility checks and
|
||||
// fully constructing the visible macro segments
|
||||
QTimer::singleShot(0, this, [this]() {
|
||||
ui->actionsList->SetVisibilityCheckEnable(true);
|
||||
});
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::PopulateMacroElseActions(Macro &m, uint32_t afterIdx)
|
||||
{
|
||||
auto &actions = m.ElseActions();
|
||||
|
||||
// The layout system has not completed geometry propagation yet, so we
|
||||
// can skip those checks for now
|
||||
ui->elseActionsList->SetVisibilityCheckEnable(false);
|
||||
|
||||
for (; afterIdx < actions.size(); afterIdx++) {
|
||||
auto newEntry = new MacroActionEdit(this, &actions[afterIdx],
|
||||
actions[afterIdx]->GetId());
|
||||
ui->elseActionsList->Add(newEntry);
|
||||
}
|
||||
ui->elseActionsList->SetHelpMsgVisible(actions.size() == 0);
|
||||
|
||||
// Give the layout system time before enabling the visibility checks and
|
||||
// fully constructing the visible macro segments
|
||||
QTimer::singleShot(0, this, [this]() {
|
||||
ui->elseActionsList->SetVisibilityCheckEnable(true);
|
||||
});
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::PopulateMacroConditions(Macro &m, uint32_t afterIdx)
|
||||
{
|
||||
bool root = afterIdx == 0;
|
||||
auto &conditions = m.Conditions();
|
||||
|
||||
// The layout system has not completed geometry propagation yet, so we
|
||||
// can skip those checks for now
|
||||
ui->conditionsList->SetVisibilityCheckEnable(false);
|
||||
|
||||
for (; afterIdx < conditions.size(); afterIdx++) {
|
||||
auto newEntry = new MacroConditionEdit(
|
||||
this, &conditions[afterIdx],
|
||||
@@ -564,9 +595,15 @@ void AdvSceneSwitcher::PopulateMacroConditions(Macro &m, uint32_t afterIdx)
|
||||
root = false;
|
||||
}
|
||||
ui->conditionsList->SetHelpMsgVisible(conditions.size() == 0);
|
||||
|
||||
// Give the layout system time before enabling the visibility checks and
|
||||
// fully constructing the visible macro segments
|
||||
QTimer::singleShot(0, this, [this]() {
|
||||
ui->conditionsList->SetVisibilityCheckEnable(true);
|
||||
});
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::SetActionData(Macro &m)
|
||||
void AdvSceneSwitcher::SetActionData(Macro &m) const
|
||||
{
|
||||
auto &actions = m.Actions();
|
||||
for (int idx = 0; idx < ui->actionsList->ContentLayout()->count();
|
||||
@@ -583,7 +620,7 @@ void AdvSceneSwitcher::SetActionData(Macro &m)
|
||||
}
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::SetElseActionData(Macro &m)
|
||||
void AdvSceneSwitcher::SetElseActionData(Macro &m) const
|
||||
{
|
||||
auto &actions = m.ElseActions();
|
||||
for (int idx = 0; idx < ui->elseActionsList->ContentLayout()->count();
|
||||
@@ -600,7 +637,7 @@ void AdvSceneSwitcher::SetElseActionData(Macro &m)
|
||||
}
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::SetConditionData(Macro &m)
|
||||
void AdvSceneSwitcher::SetConditionData(Macro &m) const
|
||||
{
|
||||
auto &conditions = m.Conditions();
|
||||
for (int idx = 0; idx < ui->conditionsList->ContentLayout()->count();
|
||||
@@ -678,7 +715,7 @@ void AdvSceneSwitcher::SetEditMacro(Macro &m)
|
||||
m.GetElseActionSplitterPosition());
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::SetMacroEditAreaDisabled(bool disable)
|
||||
void AdvSceneSwitcher::SetMacroEditAreaDisabled(bool disable) const
|
||||
{
|
||||
ui->macroName->setDisabled(disable);
|
||||
ui->runMacro->setDisabled(disable);
|
||||
@@ -689,32 +726,32 @@ void AdvSceneSwitcher::SetMacroEditAreaDisabled(bool disable)
|
||||
ui->macroActionConditionSplitter->setDisabled(disable);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::HighlightAction(int idx, QColor color)
|
||||
void AdvSceneSwitcher::HighlightAction(int idx, QColor color) const
|
||||
{
|
||||
ui->actionsList->Highlight(idx, color);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::HighlightElseAction(int idx, QColor color)
|
||||
void AdvSceneSwitcher::HighlightElseAction(int idx, QColor color) const
|
||||
{
|
||||
ui->elseActionsList->Highlight(idx, color);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::HighlightCondition(int idx, QColor color)
|
||||
void AdvSceneSwitcher::HighlightCondition(int idx, QColor color) const
|
||||
{
|
||||
ui->conditionsList->Highlight(idx, color);
|
||||
}
|
||||
|
||||
std::shared_ptr<Macro> AdvSceneSwitcher::GetSelectedMacro()
|
||||
std::shared_ptr<Macro> AdvSceneSwitcher::GetSelectedMacro() const
|
||||
{
|
||||
return ui->macros->GetCurrentMacro();
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<Macro>> AdvSceneSwitcher::GetSelectedMacros()
|
||||
std::vector<std::shared_ptr<Macro>> AdvSceneSwitcher::GetSelectedMacros() const
|
||||
{
|
||||
return ui->macros->GetCurrentMacros();
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::MacroSelectionAboutToChange()
|
||||
void AdvSceneSwitcher::MacroSelectionAboutToChange() const
|
||||
{
|
||||
if (loading) {
|
||||
return;
|
||||
@@ -770,7 +807,7 @@ void AdvSceneSwitcher::MacroSelectionChanged()
|
||||
}
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::HighlightOnChange()
|
||||
void AdvSceneSwitcher::HighlightOnChange() const
|
||||
{
|
||||
if (!GetGlobalMacroSettings()._highlightActions &&
|
||||
!GetGlobalMacroSettings()._highlightExecuted) {
|
||||
@@ -1299,15 +1336,12 @@ void AdvSceneSwitcher::CopyMacro()
|
||||
Macro::PrepareMoveToGroup(macro->Parent(), newMacro);
|
||||
|
||||
ui->macros->Add(newMacro, macro);
|
||||
if (addPulse) {
|
||||
addPulse->deleteLater();
|
||||
addPulse = nullptr;
|
||||
}
|
||||
disableAddButtonHighlight();
|
||||
emit MacroAdded(QString::fromStdString(name));
|
||||
}
|
||||
|
||||
void setCollapsedHelper(const std::shared_ptr<Macro> &m, MacroSegmentList *list,
|
||||
bool collapsed)
|
||||
static void setCollapsedHelper(const std::shared_ptr<Macro> &m,
|
||||
MacroSegmentList *list, bool collapsed)
|
||||
{
|
||||
if (!m) {
|
||||
return;
|
||||
@@ -1315,32 +1349,32 @@ void setCollapsedHelper(const std::shared_ptr<Macro> &m, MacroSegmentList *list,
|
||||
list->SetCollapsed(collapsed);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::ExpandAllActions()
|
||||
void AdvSceneSwitcher::ExpandAllActions() const
|
||||
{
|
||||
setCollapsedHelper(GetSelectedMacro(), ui->actionsList, false);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::ExpandAllElseActions()
|
||||
void AdvSceneSwitcher::ExpandAllElseActions() const
|
||||
{
|
||||
setCollapsedHelper(GetSelectedMacro(), ui->elseActionsList, false);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::ExpandAllConditions()
|
||||
void AdvSceneSwitcher::ExpandAllConditions() const
|
||||
{
|
||||
setCollapsedHelper(GetSelectedMacro(), ui->conditionsList, false);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::CollapseAllActions()
|
||||
void AdvSceneSwitcher::CollapseAllActions() const
|
||||
{
|
||||
setCollapsedHelper(GetSelectedMacro(), ui->actionsList, true);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::CollapseAllElseActions()
|
||||
void AdvSceneSwitcher::CollapseAllElseActions() const
|
||||
{
|
||||
setCollapsedHelper(GetSelectedMacro(), ui->elseActionsList, true);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::CollapseAllConditions()
|
||||
void AdvSceneSwitcher::CollapseAllConditions() const
|
||||
{
|
||||
setCollapsedHelper(GetSelectedMacro(), ui->conditionsList, true);
|
||||
}
|
||||
@@ -1355,7 +1389,7 @@ static void reduceSizeOfSplitterIdx(QSplitter *splitter, int idx)
|
||||
splitter->setSizes(sizes);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::MinimizeActions()
|
||||
void AdvSceneSwitcher::MinimizeActions() const
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
@@ -1369,13 +1403,13 @@ void AdvSceneSwitcher::MinimizeActions()
|
||||
}
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::MaximizeActions()
|
||||
void AdvSceneSwitcher::MaximizeActions() const
|
||||
{
|
||||
MinimizeElseActions();
|
||||
MinimizeConditions();
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::MinimizeElseActions()
|
||||
void AdvSceneSwitcher::MinimizeElseActions() const
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
@@ -1388,24 +1422,24 @@ void AdvSceneSwitcher::MinimizeElseActions()
|
||||
}
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::MaximizeElseActions()
|
||||
void AdvSceneSwitcher::MaximizeElseActions() const
|
||||
{
|
||||
MinimizeConditions();
|
||||
reduceSizeOfSplitterIdx(ui->macroElseActionSplitter, 0);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::MinimizeConditions()
|
||||
void AdvSceneSwitcher::MinimizeConditions() const
|
||||
{
|
||||
reduceSizeOfSplitterIdx(ui->macroActionConditionSplitter, 0);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::MaximizeConditions()
|
||||
void AdvSceneSwitcher::MaximizeConditions() const
|
||||
{
|
||||
MinimizeElseActions();
|
||||
MinimizeActions();
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_toggleElseActions_clicked()
|
||||
void AdvSceneSwitcher::on_toggleElseActions_clicked() const
|
||||
{
|
||||
auto elsePosition = ui->macroElseActionSplitter->sizes();
|
||||
if (elsePosition[1] == 0) {
|
||||
@@ -1416,14 +1450,14 @@ void AdvSceneSwitcher::on_toggleElseActions_clicked()
|
||||
maximizeFirstSplitterEntry(ui->macroElseActionSplitter);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::SetElseActionsStateToHidden()
|
||||
void AdvSceneSwitcher::SetElseActionsStateToHidden() const
|
||||
{
|
||||
ui->toggleElseActions->setToolTip(obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.toggleElseActions.show.tooltip"));
|
||||
ui->toggleElseActions->setChecked(false);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::SetElseActionsStateToVisible()
|
||||
void AdvSceneSwitcher::SetElseActionsStateToVisible() const
|
||||
{
|
||||
ui->toggleElseActions->setToolTip(obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.toggleElseActions.hide.tooltip"));
|
||||
@@ -1601,7 +1635,7 @@ static void fadeWidgets(const std::vector<QWidget *> &widgets, bool fadeOut)
|
||||
}
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::HighlightControls()
|
||||
void AdvSceneSwitcher::HighlightControls() const
|
||||
{
|
||||
const std::vector<QWidget *> conditionControls{
|
||||
ui->conditionAdd, ui->conditionRemove, ui->conditionTop,
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "macro-condition-factory.hpp"
|
||||
#include "macro-dock.hpp"
|
||||
#include "macro-helpers.hpp"
|
||||
#include "macro-settings.hpp"
|
||||
#include "plugin-state-helpers.hpp"
|
||||
#include "splitter-helpers.hpp"
|
||||
#include "sync-helpers.hpp"
|
||||
@@ -76,15 +77,21 @@ namespace advss {
|
||||
|
||||
static std::deque<std::shared_ptr<Macro>> macros;
|
||||
|
||||
Macro::Macro(const std::string &name, const bool addHotkey,
|
||||
const bool shortCircuitEvaluation)
|
||||
Macro::Macro(const std::string &name)
|
||||
{
|
||||
SetName(name);
|
||||
if (addHotkey) {
|
||||
}
|
||||
|
||||
Macro::Macro(const std::string &name, const GlobalMacroSettings &settings)
|
||||
: Macro(name)
|
||||
{
|
||||
if (settings._newMacroRegisterHotkeys) {
|
||||
SetupHotkeys();
|
||||
}
|
||||
_registerHotkeys = addHotkey;
|
||||
_useShortCircuitEvaluation = shortCircuitEvaluation;
|
||||
_registerHotkeys = settings._newMacroRegisterHotkeys;
|
||||
_checkInParallel = settings._newMacroCheckInParallel;
|
||||
_useShortCircuitEvaluation =
|
||||
settings._newMacroUseShortCircuitEvaluation;
|
||||
}
|
||||
|
||||
Macro::~Macro()
|
||||
@@ -104,7 +111,8 @@ std::shared_ptr<Macro>
|
||||
Macro::CreateGroup(const std::string &name,
|
||||
std::vector<std::shared_ptr<Macro>> &children)
|
||||
{
|
||||
auto group = std::make_shared<Macro>(name, false);
|
||||
auto group = std::make_shared<Macro>(name);
|
||||
group->_registerHotkeys = false;
|
||||
for (auto &c : children) {
|
||||
c->SetParent(group);
|
||||
}
|
||||
@@ -244,19 +252,52 @@ bool Macro::CheckConditions(bool ignorePause)
|
||||
return false;
|
||||
}
|
||||
|
||||
_stop = false;
|
||||
_matched = false;
|
||||
for (auto &condition : _conditions) {
|
||||
if (!condition) {
|
||||
continue;
|
||||
}
|
||||
const auto checkConditionsTask =
|
||||
[this,
|
||||
ignorePause](const std::deque<std::shared_ptr<MacroCondition>>
|
||||
&conditions) {
|
||||
for (auto &condition : conditions) {
|
||||
if (!condition) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_paused && !ignorePause) {
|
||||
vblog(LOG_INFO, "Macro %s is paused", _name.c_str());
|
||||
if (_paused && !ignorePause) {
|
||||
vblog(LOG_INFO, "Macro %s is paused",
|
||||
_name.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
_matched = CheckConditionHelper(condition);
|
||||
}
|
||||
return _matched;
|
||||
};
|
||||
|
||||
if (CheckInParallel()) {
|
||||
if (!_conditionCheckFuture.valid()) {
|
||||
_stop = false;
|
||||
_matched = false;
|
||||
_conditionCheckFuture = std::async(
|
||||
std::launch::async,
|
||||
[this, checkConditionsTask]() {
|
||||
// Copy to avoid settings modifications
|
||||
// causing issues
|
||||
const auto conditionsCopy = _conditions;
|
||||
checkConditionsTask(conditionsCopy);
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
_matched = CheckConditionHelper(condition);
|
||||
if (_conditionCheckFuture.wait_for(std::chrono::seconds(0)) !=
|
||||
std::future_status::ready) {
|
||||
vblog(LOG_INFO,
|
||||
"Macro %s still waiting for condition check result",
|
||||
_name.c_str());
|
||||
return false;
|
||||
}
|
||||
_conditionCheckFuture.get();
|
||||
} else {
|
||||
_stop = false;
|
||||
_matched = false;
|
||||
_matched = checkConditionsTask(_conditions);
|
||||
}
|
||||
|
||||
vblog(LOG_INFO, "Macro %s returned %d", _name.c_str(), _matched);
|
||||
@@ -273,7 +314,9 @@ bool Macro::CheckConditions(bool ignorePause)
|
||||
|
||||
bool Macro::PerformActions(bool match, bool forceParallel, bool ignorePause)
|
||||
{
|
||||
if (!_done) {
|
||||
if (_actionRunFuture.valid() &&
|
||||
_actionRunFuture.wait_for(std::chrono::seconds(0)) !=
|
||||
std::future_status::ready) {
|
||||
vblog(LOG_INFO, "Macro %s already running", _name.c_str());
|
||||
|
||||
if (!_stopActionsIfNotDone) {
|
||||
@@ -291,14 +334,15 @@ bool Macro::PerformActions(bool match, bool forceParallel, bool ignorePause)
|
||||
: std::bind(&Macro::RunElseActions, this,
|
||||
std::placeholders::_1);
|
||||
_stop = false;
|
||||
_done = false;
|
||||
bool ret = true;
|
||||
if (_runInParallel || forceParallel) {
|
||||
if (_backgroundThread.joinable()) {
|
||||
_backgroundThread.join();
|
||||
if (_actionRunFuture.valid()) {
|
||||
_actionRunFuture.get();
|
||||
}
|
||||
_backgroundThread = std::thread(
|
||||
[this, runFunc, ignorePause] { runFunc(ignorePause); });
|
||||
_actionRunFuture = std::async(std::launch::async,
|
||||
[this, runFunc, ignorePause] {
|
||||
runFunc(ignorePause);
|
||||
});
|
||||
} else {
|
||||
ret = runFunc(ignorePause);
|
||||
}
|
||||
@@ -336,6 +380,13 @@ bool Macro::ConditionsShouldBeChecked() const
|
||||
|
||||
bool Macro::ShouldRunActions() const
|
||||
{
|
||||
if (CheckInParallel() && _conditionCheckFuture.valid()) {
|
||||
vblog(LOG_INFO,
|
||||
"%s not ready to perform actions as condition check is still running",
|
||||
_name.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool hasActionsToExecute =
|
||||
!_paused && (_matched || _elseActions.size() > 0) &&
|
||||
(!_performActionsOnChange || _conditionSateChanged);
|
||||
@@ -408,7 +459,6 @@ bool Macro::RunActionsHelper(
|
||||
action->EnableHighlight();
|
||||
}
|
||||
}
|
||||
_done = true;
|
||||
return actionsExecutedSuccessfully;
|
||||
}
|
||||
|
||||
@@ -508,9 +558,35 @@ void Macro::Stop()
|
||||
t.join();
|
||||
}
|
||||
}
|
||||
if (_backgroundThread.joinable()) {
|
||||
_backgroundThread.join();
|
||||
if (_actionRunFuture.valid()) {
|
||||
_actionRunFuture.get();
|
||||
}
|
||||
if (_conditionCheckFuture.valid()) {
|
||||
_conditionCheckFuture.get();
|
||||
}
|
||||
}
|
||||
|
||||
void Macro::SetCheckInParallel(bool parallel)
|
||||
{
|
||||
_checkInParallel = parallel;
|
||||
_conditionCheckFuture = {};
|
||||
}
|
||||
|
||||
bool Macro::ParallelTasksCompleted() const
|
||||
{
|
||||
// A parallel action run might be triggered by RunInParallel() or the
|
||||
// "Run Macro" button, so checking just for RunInParallel() will not
|
||||
// suffice
|
||||
if (!CheckInParallel() && !_actionRunFuture.valid()) {
|
||||
return true;
|
||||
}
|
||||
if (_actionRunFuture.valid()) {
|
||||
return false;
|
||||
}
|
||||
if (CheckInParallel() && _conditionCheckFuture.valid()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
MacroInputVariables Macro::GetInputVariables() const
|
||||
@@ -712,6 +788,7 @@ bool Macro::Save(obs_data_t *obj, bool saveForCopy) const
|
||||
static_cast<int>(_pauseSaveBehavior));
|
||||
obs_data_set_bool(obj, "pause", _paused);
|
||||
obs_data_set_bool(obj, "parallel", _runInParallel);
|
||||
obs_data_set_bool(obj, "checkConditionsInParallel", _checkInParallel);
|
||||
obs_data_set_bool(obj, "onChange", _performActionsOnChange);
|
||||
obs_data_set_bool(obj, "skipExecOnStart", _skipExecOnStart);
|
||||
obs_data_set_bool(obj, "stopActionsIfNotDone", _stopActionsIfNotDone);
|
||||
@@ -797,6 +874,7 @@ bool Macro::Load(obs_data_t *obj)
|
||||
break;
|
||||
}
|
||||
_runInParallel = obs_data_get_bool(obj, "parallel");
|
||||
_checkInParallel = obs_data_get_bool(obj, "checkConditionsInParallel");
|
||||
_performActionsOnChange = obs_data_get_bool(obj, "onChange");
|
||||
_skipExecOnStart = obs_data_get_bool(obj, "skipExecOnStart");
|
||||
_stopActionsIfNotDone = obs_data_get_bool(obj, "stopActionsIfNotDone");
|
||||
@@ -1468,6 +1546,14 @@ std::weak_ptr<Macro> GetWeakMacroByName(const char *name)
|
||||
void InvalidateMacroTempVarValues()
|
||||
{
|
||||
for (const auto &m : macros) {
|
||||
// Do not invalidate the temp vars set during condition checks
|
||||
// or action executions running in parallel to the "main" macro
|
||||
// loop, as otherwise access to the information stored in those
|
||||
// variables might get lost while those checks or actions are
|
||||
// still ongoing.
|
||||
if (!m->ParallelTasksCompleted()) {
|
||||
continue;
|
||||
}
|
||||
m->InvalidateTempVarValues();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "variable-string.hpp"
|
||||
#include "temp-variable.hpp"
|
||||
|
||||
#include <future>
|
||||
#include <QString>
|
||||
#include <QByteArray>
|
||||
#include <string>
|
||||
@@ -20,6 +21,7 @@
|
||||
namespace advss {
|
||||
|
||||
class MacroDock;
|
||||
class GlobalMacroSettings;
|
||||
|
||||
class Macro {
|
||||
using TimePoint = std::chrono::high_resolution_clock::time_point;
|
||||
@@ -27,8 +29,8 @@ class Macro {
|
||||
public:
|
||||
enum class PauseStateSaveBehavior { PERSIST, PAUSE, UNPAUSE };
|
||||
|
||||
Macro(const std::string &name = "", const bool addHotkey = false,
|
||||
const bool shortCircuitEvaluation = false);
|
||||
Macro(const std::string &name = "");
|
||||
Macro(const std::string &name, const GlobalMacroSettings &settings);
|
||||
~Macro();
|
||||
|
||||
std::string Name() const { return _name; }
|
||||
@@ -77,6 +79,9 @@ public:
|
||||
void AddHelperThread(std::thread &&);
|
||||
void SetRunInParallel(bool parallel) { _runInParallel = parallel; }
|
||||
bool RunInParallel() const { return _runInParallel; }
|
||||
bool CheckInParallel() const { return _checkInParallel; }
|
||||
void SetCheckInParallel(bool parallel);
|
||||
bool ParallelTasksCompleted() const;
|
||||
|
||||
// Input variables
|
||||
MacroInputVariables GetInputVariables() const;
|
||||
@@ -182,11 +187,10 @@ private:
|
||||
std::string _name = "";
|
||||
bool _die = false;
|
||||
bool _stop = false;
|
||||
bool _done = true;
|
||||
std::future<void> _actionRunFuture;
|
||||
TimePoint _lastCheckTime{};
|
||||
TimePoint _lastUnpauseTime{};
|
||||
TimePoint _lastExecutionTime{};
|
||||
std::thread _backgroundThread;
|
||||
std::vector<std::thread> _helperThreads;
|
||||
|
||||
std::deque<std::shared_ptr<MacroCondition>> _conditions;
|
||||
@@ -204,7 +208,9 @@ private:
|
||||
bool _conditionSateChanged = false;
|
||||
|
||||
bool _runInParallel = false;
|
||||
bool _checkInParallel = false;
|
||||
bool _matched = false;
|
||||
std::future<void> _conditionCheckFuture;
|
||||
bool _lastMatched = false;
|
||||
bool _performActionsOnChange = true;
|
||||
bool _skipExecOnStart = false;
|
||||
|
||||
@@ -132,9 +132,6 @@ public:
|
||||
bool transitionOverrideOverride = false;
|
||||
bool adjustActiveTransitionType = true;
|
||||
|
||||
enum class LogLevel { DEFAULT, LOG_MACRO, LOG_ACTION, VERBOSE };
|
||||
LogLevel logLevel = LogLevel::DEFAULT;
|
||||
|
||||
/* --- End of General tab section --- */
|
||||
|
||||
std::string lastTitle;
|
||||
|
||||
102
lib/utils/json-helpers.cpp
Normal file
102
lib/utils/json-helpers.cpp
Normal file
@@ -0,0 +1,102 @@
|
||||
#include "json-helpers.hpp"
|
||||
|
||||
#ifdef JSONPATH_SUPPORT
|
||||
#include <jsoncons/json.hpp>
|
||||
#include <jsoncons_ext/jsonpath/jsonpath.hpp>
|
||||
#endif
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <QJsonDocument>
|
||||
|
||||
namespace advss {
|
||||
|
||||
QString FormatJsonString(std::string s)
|
||||
{
|
||||
return FormatJsonString(QString::fromStdString(s));
|
||||
}
|
||||
|
||||
QString FormatJsonString(QString json)
|
||||
{
|
||||
QJsonDocument doc = QJsonDocument::fromJson(json.toUtf8());
|
||||
if (doc.isNull()) {
|
||||
return "";
|
||||
}
|
||||
return QString::fromUtf8(doc.toJson(QJsonDocument::Indented));
|
||||
}
|
||||
|
||||
bool MatchJson(const std::string &json1, const std::string &json2,
|
||||
const RegexConfig ®ex)
|
||||
{
|
||||
auto j1 = FormatJsonString(json1).toStdString();
|
||||
auto j2 = FormatJsonString(json2).toStdString();
|
||||
|
||||
if (j1.empty()) {
|
||||
j1 = json1;
|
||||
}
|
||||
if (j2.empty()) {
|
||||
j2 = json2;
|
||||
}
|
||||
|
||||
if (regex.Enabled()) {
|
||||
return regex.Matches(j1, j2);
|
||||
}
|
||||
return j1 == j2;
|
||||
}
|
||||
|
||||
std::optional<std::string> GetJsonField(const std::string &jsonStr,
|
||||
const std::string &fieldToExtract)
|
||||
{
|
||||
try {
|
||||
nlohmann::json json = nlohmann::json::parse(jsonStr);
|
||||
auto it = json.find(fieldToExtract);
|
||||
if (it == json.end()) {
|
||||
return {};
|
||||
}
|
||||
if (it->is_string()) {
|
||||
return it->get<std::string>();
|
||||
}
|
||||
return it->dump();
|
||||
} catch (const nlohmann::json::exception &) {
|
||||
return {};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
std::optional<std::string> QueryJson(const std::string &jsonStr,
|
||||
const std::string &query)
|
||||
{
|
||||
#ifdef JSONPATH_SUPPORT
|
||||
try {
|
||||
auto json = jsoncons::json::parse(jsonStr);
|
||||
auto result = jsoncons::jsonpath::json_query(json, query);
|
||||
return result.as_string();
|
||||
} catch (const jsoncons::json_exception &) {
|
||||
return {};
|
||||
} catch (const jsoncons::json_errc &) {
|
||||
return {};
|
||||
}
|
||||
#else
|
||||
return {};
|
||||
#endif
|
||||
}
|
||||
|
||||
std::optional<std::string> AccessJsonArrayIndex(const std::string &jsonStr,
|
||||
const int index)
|
||||
{
|
||||
try {
|
||||
nlohmann::json json = nlohmann::json::parse(jsonStr);
|
||||
if (!json.is_array() || index >= (int)json.size() ||
|
||||
index < 0) {
|
||||
return {};
|
||||
}
|
||||
auto result = json.at(index);
|
||||
if (result.is_string()) {
|
||||
return result.get<std::string>();
|
||||
}
|
||||
return result.dump();
|
||||
} catch (const nlohmann::json::exception &) {
|
||||
return {};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
21
lib/utils/json-helpers.hpp
Normal file
21
lib/utils/json-helpers.hpp
Normal file
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
#include "export-symbol-helper.hpp"
|
||||
#include "regex-config.hpp"
|
||||
|
||||
#include <QString>
|
||||
#include <string>
|
||||
|
||||
namespace advss {
|
||||
|
||||
EXPORT QString FormatJsonString(std::string);
|
||||
EXPORT QString FormatJsonString(QString);
|
||||
EXPORT bool MatchJson(const std::string &json1, const std::string &json2,
|
||||
const RegexConfig ®ex);
|
||||
EXPORT std::optional<std::string> GetJsonField(const std::string &json,
|
||||
const std::string &id);
|
||||
EXPORT std::optional<std::string> QueryJson(const std::string &json,
|
||||
const std::string &query);
|
||||
EXPORT std::optional<std::string> AccessJsonArrayIndex(const std::string &json,
|
||||
const int index);
|
||||
|
||||
} // namespace advss
|
||||
@@ -1,26 +1,97 @@
|
||||
#include "log-helper.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "obs-module-helper.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <obs-data.h>
|
||||
#include <QComboBox>
|
||||
#include <string>
|
||||
|
||||
namespace advss {
|
||||
|
||||
static LogLevel logLevel = LogLevel::DEFAULT;
|
||||
|
||||
bool VerboseLoggingEnabled()
|
||||
{
|
||||
return GetSwitcher() &&
|
||||
GetSwitcher()->logLevel == SwitcherData::LogLevel::VERBOSE;
|
||||
return logLevel == LogLevel::VERBOSE;
|
||||
}
|
||||
|
||||
bool ActionLoggingEnabled()
|
||||
{
|
||||
return GetSwitcher() &&
|
||||
(GetSwitcher()->logLevel == SwitcherData::LogLevel::LOG_ACTION ||
|
||||
VerboseLoggingEnabled());
|
||||
return logLevel == LogLevel::LOG_ACTION || VerboseLoggingEnabled();
|
||||
}
|
||||
|
||||
bool MacroLoggingEnabled()
|
||||
{
|
||||
return GetSwitcher() &&
|
||||
(GetSwitcher()->logLevel == SwitcherData::LogLevel::LOG_MACRO ||
|
||||
ActionLoggingEnabled());
|
||||
return logLevel == LogLevel::LOG_MACRO || ActionLoggingEnabled();
|
||||
}
|
||||
|
||||
bool LoggingEnabled()
|
||||
{
|
||||
return logLevel != LogLevel::DISABLE;
|
||||
}
|
||||
|
||||
void SetLogLevel(LogLevel newLogLevel)
|
||||
{
|
||||
logLevel = newLogLevel;
|
||||
}
|
||||
|
||||
LogLevel GetLogLevel()
|
||||
{
|
||||
return logLevel;
|
||||
}
|
||||
|
||||
void SaveLogLevel(void *data)
|
||||
{
|
||||
auto obj = static_cast<obs_data_t *>(data);
|
||||
obs_data_set_int(obj, "logLevel", static_cast<int>(logLevel));
|
||||
obs_data_set_int(obj, "logLevelVersion", 1);
|
||||
}
|
||||
|
||||
void LoadLogLevel(void *data)
|
||||
{
|
||||
auto obj = static_cast<obs_data_t *>(data);
|
||||
logLevel = static_cast<LogLevel>(obs_data_get_int(obj, "logLevel"));
|
||||
if (obs_data_get_int(obj, "logLevelVersion") < 1) {
|
||||
enum OldLogLevel { DEFAULT, LOG_ACTION, VERBOSE };
|
||||
OldLogLevel oldLogLevel = static_cast<OldLogLevel>(
|
||||
obs_data_get_int(obj, "logLevel"));
|
||||
switch (oldLogLevel) {
|
||||
case DEFAULT:
|
||||
logLevel = LogLevel::DEFAULT;
|
||||
break;
|
||||
case LOG_ACTION:
|
||||
logLevel = LogLevel::LOG_ACTION;
|
||||
break;
|
||||
case VERBOSE:
|
||||
logLevel = LogLevel::VERBOSE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PopulateLogLevelSelection(void *sel)
|
||||
{
|
||||
auto selection = static_cast<QComboBox *>(sel);
|
||||
static const std::map<LogLevel, std::string> logLevels = {
|
||||
{LogLevel::DISABLE,
|
||||
"AdvSceneSwitcher.generalTab.generalBehavior.logLevel.disable"},
|
||||
{LogLevel::DEFAULT,
|
||||
"AdvSceneSwitcher.generalTab.generalBehavior.logLevel.default"},
|
||||
{LogLevel::LOG_MACRO,
|
||||
"AdvSceneSwitcher.generalTab.generalBehavior.logLevel.logMacro"},
|
||||
{LogLevel::LOG_ACTION,
|
||||
"AdvSceneSwitcher.generalTab.generalBehavior.logLevel.logAction"},
|
||||
{LogLevel::VERBOSE,
|
||||
"AdvSceneSwitcher.generalTab.generalBehavior.logLevel.verbose"},
|
||||
};
|
||||
|
||||
selection->clear();
|
||||
for (const auto &[value, name] : logLevels) {
|
||||
selection->addItem(obs_module_text(name.c_str()),
|
||||
static_cast<int>(value));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -12,7 +12,13 @@ namespace advss {
|
||||
#else
|
||||
|
||||
// Print log with "[adv-ss] " prefix
|
||||
#define blog(level, msg, ...) blog(level, "[adv-ss] " msg, ##__VA_ARGS__)
|
||||
#define blog(level, msg, ...) \
|
||||
do { \
|
||||
if (LoggingEnabled()) { \
|
||||
blog(level, "[adv-ss] " msg, ##__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// Print log with "[adv-ss] " if log level is set to "verbose"
|
||||
#define vblog(level, msg, ...) \
|
||||
do { \
|
||||
@@ -43,5 +49,15 @@ EXPORT bool VerboseLoggingEnabled();
|
||||
EXPORT bool ActionLoggingEnabled();
|
||||
// Returns true if log level is set to "macro", "action" or "verbose"
|
||||
EXPORT bool MacroLoggingEnabled();
|
||||
// Returns true if logging is enabled and false otherwise
|
||||
EXPORT bool LoggingEnabled();
|
||||
|
||||
enum class LogLevel { DISABLE = -1, DEFAULT, LOG_MACRO, LOG_ACTION, VERBOSE };
|
||||
|
||||
void SetLogLevel(LogLevel);
|
||||
LogLevel GetLogLevel();
|
||||
void SaveLogLevel(void *data);
|
||||
void LoadLogLevel(void *data);
|
||||
void PopulateLogLevelSelection(void *);
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -47,6 +47,12 @@ void Section::Collapse(bool collapse)
|
||||
_toggleButton->setChecked(collapse);
|
||||
_toggleButton->setArrowType(collapse ? Qt::ArrowType::RightArrow
|
||||
: Qt::ArrowType::DownArrow);
|
||||
if (!_toggleAnimation) {
|
||||
_collapsed = collapse;
|
||||
emit Collapsed(collapse);
|
||||
return;
|
||||
}
|
||||
|
||||
_toggleAnimation->setDirection(collapse ? QAbstractAnimation::Backward
|
||||
: QAbstractAnimation::Forward);
|
||||
_transitioning = true;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "utility.hpp"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <QTextStream>
|
||||
#include <sstream>
|
||||
|
||||
@@ -28,25 +27,6 @@ bool ReplaceAll(std::string &str, const std::string &from,
|
||||
return somethingWasReplaced;
|
||||
}
|
||||
|
||||
std::optional<std::string> GetJsonField(const std::string &jsonStr,
|
||||
const std::string &fieldToExtract)
|
||||
{
|
||||
try {
|
||||
nlohmann::json json = nlohmann::json::parse(jsonStr);
|
||||
auto it = json.find(fieldToExtract);
|
||||
if (it == json.end()) {
|
||||
return {};
|
||||
}
|
||||
if (it->is_string()) {
|
||||
return it->get<std::string>();
|
||||
}
|
||||
return it->dump();
|
||||
} catch (const nlohmann::json::exception &) {
|
||||
return {};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
bool CompareIgnoringLineEnding(QString &s1, QString &s2)
|
||||
{
|
||||
// Let QT deal with different types of lineendings
|
||||
|
||||
@@ -15,8 +15,6 @@ EXPORT std::pair<int, int> GetCursorPos();
|
||||
|
||||
bool ReplaceAll(std::string &str, const std::string &from,
|
||||
const std::string &to);
|
||||
EXPORT std::optional<std::string> GetJsonField(const std::string &json,
|
||||
const std::string &id);
|
||||
EXPORT bool CompareIgnoringLineEnding(QString &s1, QString &s2);
|
||||
std::string ToString(double value);
|
||||
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
#include "websocket-api.hpp"
|
||||
#include "log-helper.hpp"
|
||||
#include "obs-websocket-api.h"
|
||||
#include "plugin-state-helpers.hpp"
|
||||
|
||||
// Must be after "obs-websocket-api.h" to avoid logging function conflict
|
||||
#include "log-helper.hpp"
|
||||
|
||||
#include <mutex>
|
||||
|
||||
namespace advss {
|
||||
|
||||
@@ -42,6 +42,7 @@ void StringVariable::operator=(const char *value)
|
||||
void StringVariable::Load(obs_data_t *obj, const char *name)
|
||||
{
|
||||
_value = obs_data_get_string(obj, name);
|
||||
_lastResolve = {};
|
||||
Resolve();
|
||||
}
|
||||
|
||||
|
||||
@@ -152,8 +152,6 @@ target_sources(
|
||||
utils/filter-selection.hpp
|
||||
utils/hotkey-helpers.cpp
|
||||
utils/hotkey-helpers.hpp
|
||||
utils/json-helpers.cpp
|
||||
utils/json-helpers.hpp
|
||||
utils/monitor-helpers.cpp
|
||||
utils/monitor-helpers.hpp
|
||||
utils/osc-helpers.cpp
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
#include "json-helpers.hpp"
|
||||
|
||||
#include <QJsonDocument>
|
||||
|
||||
namespace advss {
|
||||
|
||||
QString FormatJsonString(std::string s)
|
||||
{
|
||||
return FormatJsonString(QString::fromStdString(s));
|
||||
}
|
||||
|
||||
QString FormatJsonString(QString json)
|
||||
{
|
||||
QJsonDocument doc = QJsonDocument::fromJson(json.toUtf8());
|
||||
if (doc.isNull()) {
|
||||
return "";
|
||||
}
|
||||
return QString::fromUtf8(doc.toJson(QJsonDocument::Indented));
|
||||
}
|
||||
|
||||
bool MatchJson(const std::string &json1, const std::string &json2,
|
||||
const RegexConfig ®ex)
|
||||
{
|
||||
auto j1 = FormatJsonString(json1).toStdString();
|
||||
auto j2 = FormatJsonString(json2).toStdString();
|
||||
|
||||
if (j1.empty()) {
|
||||
j1 = json1;
|
||||
}
|
||||
if (j2.empty()) {
|
||||
j2 = json2;
|
||||
}
|
||||
|
||||
if (regex.Enabled()) {
|
||||
return regex.Matches(j1, j2);
|
||||
}
|
||||
return j1 == j2;
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
@@ -1,13 +0,0 @@
|
||||
#pragma once
|
||||
#include <QString>
|
||||
#include <string>
|
||||
#include <regex-config.hpp>
|
||||
|
||||
namespace advss {
|
||||
|
||||
QString FormatJsonString(std::string);
|
||||
QString FormatJsonString(QString);
|
||||
bool MatchJson(const std::string &json1, const std::string &json2,
|
||||
const RegexConfig ®ex);
|
||||
|
||||
} // namespace advss
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "source-setting.hpp"
|
||||
#include "json-helpers.hpp"
|
||||
#include "obs-module-helper.hpp"
|
||||
#include "math-helpers.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <QLayout>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#include "transform-setting.hpp"
|
||||
#include "json-helpers.hpp"
|
||||
#include "obs-module-helper.hpp"
|
||||
#include "math-helpers.hpp"
|
||||
#include "scene-item-transform-helpers.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <QLayout>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "websocket-helpers.hpp"
|
||||
#include "connection-manager.hpp"
|
||||
#include "log-helper.hpp"
|
||||
#include "plugin-state-helpers.hpp"
|
||||
#include "sync-helpers.hpp"
|
||||
#include "websocket-api.hpp"
|
||||
@@ -8,6 +7,9 @@
|
||||
#include <QCryptographicHash>
|
||||
#include <obs-websocket-api.h>
|
||||
|
||||
// Must be after "obs-websocket-api.h" to avoid logging function conflict
|
||||
#include "log-helper.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
||||
using websocketpp::lib::placeholders::_1;
|
||||
|
||||
@@ -47,7 +47,7 @@ static httplib::Params getParams(const StringList &strings)
|
||||
static void setTimeout(httplib::Client &client, const Duration &timeout)
|
||||
{
|
||||
const time_t seconds = timeout.Seconds();
|
||||
const time_t usecs = timeout.Milliseconds() * 1000;
|
||||
const time_t usecs = timeout.Milliseconds() - (seconds * 1000);
|
||||
client.set_read_timeout(seconds, usecs);
|
||||
client.set_write_timeout(seconds, usecs);
|
||||
}
|
||||
@@ -73,35 +73,53 @@ bool MacroActionHttp::PerformAction()
|
||||
const auto headers = _setHeaders ? getHeaders(_headers)
|
||||
: httplib::Headers();
|
||||
|
||||
// This copy is necessary for some reason for MacOS but not Linux or
|
||||
// Windows.
|
||||
// Without it all requests fail with "Invalid argument" or
|
||||
// "Failed to write connection" when sending out the data.
|
||||
std::string path = _path;
|
||||
|
||||
httplib::Result response;
|
||||
switch (_method) {
|
||||
case MacroActionHttp::Method::GET:
|
||||
response = cli.Get(_path, params, headers);
|
||||
response = cli.Get(path, params, headers);
|
||||
break;
|
||||
case MacroActionHttp::Method::POST: {
|
||||
const auto path = httplib::append_query_params(_path, params);
|
||||
response = cli.Post(path, headers, _body, _contentType);
|
||||
const auto pathWithParam =
|
||||
httplib::append_query_params(path, params);
|
||||
response =
|
||||
cli.Post(pathWithParam, headers, _body, _contentType);
|
||||
break;
|
||||
}
|
||||
case MacroActionHttp::Method::PUT: {
|
||||
const auto path = httplib::append_query_params(_path, params);
|
||||
response = cli.Put(path, headers, _body, _contentType);
|
||||
const auto pathWithParam =
|
||||
httplib::append_query_params(path, params);
|
||||
response = cli.Put(pathWithParam, headers, _body, _contentType);
|
||||
break;
|
||||
}
|
||||
case MacroActionHttp::Method::PATCH: {
|
||||
const auto path = httplib::append_query_params(_path, params);
|
||||
response = cli.Patch(path, headers, _body, _contentType);
|
||||
const auto pathWithParam =
|
||||
httplib::append_query_params(path, params);
|
||||
response =
|
||||
cli.Patch(pathWithParam, headers, _body, _contentType);
|
||||
break;
|
||||
}
|
||||
case MacroActionHttp::Method::DELETE: {
|
||||
const auto path = httplib::append_query_params(_path, params);
|
||||
response = cli.Delete(path, headers, _body, _contentType);
|
||||
const auto pathWithParam =
|
||||
httplib::append_query_params(path, params);
|
||||
response =
|
||||
cli.Delete(pathWithParam, headers, _body, _contentType);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (VerboseLoggingEnabled() && !response) {
|
||||
blog(LOG_INFO, "HTTP action error: %s",
|
||||
httplib::to_string(response.error()).c_str());
|
||||
}
|
||||
|
||||
SetTempVarValue("status",
|
||||
response ? std::to_string(response->status) : "");
|
||||
SetTempVarValue("body", response ? response->body : "");
|
||||
@@ -140,6 +158,7 @@ static std::string stringListToString(const StringList &list)
|
||||
result += std::string(string) + ", ";
|
||||
}
|
||||
result.pop_back();
|
||||
result.pop_back();
|
||||
return result + "]";
|
||||
}
|
||||
|
||||
|
||||
@@ -22,19 +22,15 @@ if(OS_WINDOWS)
|
||||
target_compile_options(
|
||||
libremidi
|
||||
PRIVATE /wd4018
|
||||
/wd4068
|
||||
/wd4100
|
||||
/wd4101
|
||||
/wd4189
|
||||
/wd4244
|
||||
/wd4251
|
||||
/wd4267
|
||||
/wd4275
|
||||
/wd4389
|
||||
/wd4505
|
||||
/wd4702)
|
||||
target_compile_options(${PROJECT_NAME} PRIVATE /wd4017 /wd4068 /wd4100
|
||||
/wd4101 /wd4244)
|
||||
/wd4702
|
||||
PUBLIC /wd4068 /wd4100 /wd4101 /wd4244)
|
||||
target_compile_options(${PROJECT_NAME} PRIVATE /wd4017)
|
||||
endif()
|
||||
else()
|
||||
target_compile_options(
|
||||
@@ -47,21 +43,6 @@ else()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(OS_MACOS)
|
||||
set(PATCH_FILE
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/remove-bit-cast-for-macos-build.patch")
|
||||
execute_process(
|
||||
COMMAND git apply ${PATCH_FILE}
|
||||
WORKING_DIRECTORY ${LIBREMIDI_DIR}
|
||||
RESULT_VARIABLE PATCH_RESULT)
|
||||
if(PATCH_RESULT EQUAL 0)
|
||||
message("Libremidi patch \"${PATCH_FILE}\" applied successfully!")
|
||||
else()
|
||||
message(
|
||||
WARNING "Libremidi patch \"${PATCH_FILE}\" did NOT apply successfully!")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
target_sources(
|
||||
${PROJECT_NAME}
|
||||
PRIVATE macro-condition-midi.cpp macro-condition-midi.hpp
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
diff --git a/include/libremidi/backends/coremidi/helpers.hpp b/include/libremidi/backends/coremidi/helpers.hpp
|
||||
index 08e62ff..ba35ec7 100644
|
||||
--- a/include/libremidi/backends/coremidi/helpers.hpp
|
||||
+++ b/include/libremidi/backends/coremidi/helpers.hpp
|
||||
@@ -207,7 +207,8 @@ inline CFStringRef ConnectedEndpointName(MIDIEndpointRef endpoint)
|
||||
inline MIDIObjectRef
|
||||
locate_object(auto& self, const port_information& info, MIDIObjectType requested_type)
|
||||
{
|
||||
- auto uid = std::bit_cast<std::int32_t>((uint32_t)info.port);
|
||||
+ std::int32_t uid;
|
||||
+ std::memcpy(&uid, &(info.port), sizeof(uint32_t));
|
||||
MIDIObjectRef object{};
|
||||
MIDIObjectType type{};
|
||||
auto ret = MIDIObjectFindByUniqueID(uid, &object, &type);
|
||||
diff --git a/include/libremidi/backends/coremidi/observer.hpp b/include/libremidi/backends/coremidi/observer.hpp
|
||||
index defe623..12a936a 100644
|
||||
--- a/include/libremidi/backends/coremidi/observer.hpp
|
||||
+++ b/include/libremidi/backends/coremidi/observer.hpp
|
||||
@@ -78,13 +78,16 @@ public:
|
||||
if (!ok)
|
||||
return {};
|
||||
|
||||
- return std::conditional_t<Input, input_port, output_port>{
|
||||
- {.client = (std::uintptr_t)this->client,
|
||||
- .port = std::bit_cast<uint32_t>(get_int_property(obj, kMIDIPropertyUniqueID)),
|
||||
- .manufacturer = get_string_property(obj, kMIDIPropertyManufacturer),
|
||||
- .device_name = get_string_property(obj, kMIDIPropertyModel),
|
||||
- .port_name = get_string_property(obj, kMIDIPropertyName),
|
||||
- .display_name = get_string_property(obj, kMIDIPropertyDisplayName)}};
|
||||
+ std::conditional_t<Input, input_port, output_port> ret{
|
||||
+ {.client = (std::uintptr_t)this->client,
|
||||
+ .port = 0,
|
||||
+ .manufacturer = get_string_property(obj, kMIDIPropertyManufacturer),
|
||||
+ .device_name = get_string_property(obj, kMIDIPropertyModel),
|
||||
+ .port_name = get_string_property(obj, kMIDIPropertyName),
|
||||
+ .display_name = get_string_property(obj, kMIDIPropertyDisplayName)}};
|
||||
+ auto prop = get_int_property(obj, kMIDIPropertyUniqueID);
|
||||
+ std::memcpy(&ret.port, &(prop), sizeof(prop));
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
std::vector<libremidi::input_port> get_input_ports() const noexcept override
|
||||
@@ -31,6 +31,11 @@ void TwitchChannel::Save(obs_data_t *obj) const
|
||||
std::string TwitchChannel::GetUserID(const TwitchToken &token) const
|
||||
{
|
||||
static std::map<std::string, std::string> userIDCache;
|
||||
if (!token.IsValid()) {
|
||||
vblog(LOG_INFO, "%s() failed: token invalid", __func__);
|
||||
return "invalid";
|
||||
}
|
||||
|
||||
auto it = userIDCache.find(std::string(_name));
|
||||
if (it != userIDCache.end()) {
|
||||
return it->second;
|
||||
@@ -47,7 +52,7 @@ std::string TwitchChannel::GetUserID(const TwitchToken &token) const
|
||||
}
|
||||
|
||||
if (res.status != 200) {
|
||||
blog(LOG_INFO, "failed to get Twitch user id from token! (%d)",
|
||||
blog(LOG_INFO, "failed to get Twitch user id for channel! (%d)",
|
||||
res.status);
|
||||
return "invalid";
|
||||
}
|
||||
@@ -90,7 +95,7 @@ getStringArrayHelper(const OBSDataAutoRelease &data, const std::string &value)
|
||||
}
|
||||
try {
|
||||
auto json = nlohmann::json::parse(jsonStr);
|
||||
auto array = json[value];
|
||||
auto &array = json[value];
|
||||
if (!array.is_array()) {
|
||||
return result;
|
||||
}
|
||||
@@ -104,7 +109,7 @@ getStringArrayHelper(const OBSDataAutoRelease &data, const std::string &value)
|
||||
}
|
||||
|
||||
std::optional<ChannelLiveInfo>
|
||||
TwitchChannel::GetLiveInfo(const TwitchToken &token)
|
||||
TwitchChannel::GetLiveInfo(const TwitchToken &token) const
|
||||
{
|
||||
auto id = GetUserID(token);
|
||||
if (!IsValid(id)) {
|
||||
@@ -146,7 +151,8 @@ TwitchChannel::GetLiveInfo(const TwitchToken &token)
|
||||
return info;
|
||||
}
|
||||
|
||||
std::optional<ChannelInfo> TwitchChannel::GetInfo(const TwitchToken &token)
|
||||
std::optional<ChannelInfo>
|
||||
TwitchChannel::GetInfo(const TwitchToken &token) const
|
||||
{
|
||||
auto id = GetUserID(token);
|
||||
if (!IsValid(id)) {
|
||||
|
||||
@@ -51,8 +51,8 @@ struct TwitchChannel {
|
||||
StringVariable GetName() const { return _name; }
|
||||
std::string GetUserID(const TwitchToken &token) const;
|
||||
bool IsValid(const std::string &id) const;
|
||||
std::optional<ChannelLiveInfo> GetLiveInfo(const TwitchToken &);
|
||||
std::optional<ChannelInfo> GetInfo(const TwitchToken &);
|
||||
std::optional<ChannelLiveInfo> GetLiveInfo(const TwitchToken &) const;
|
||||
std::optional<ChannelInfo> GetInfo(const TwitchToken &) const;
|
||||
void ResolveVariables();
|
||||
|
||||
private:
|
||||
|
||||
@@ -127,6 +127,11 @@ void EventSub::ClearActiveSubscriptions()
|
||||
_activeSubscriptions.clear();
|
||||
}
|
||||
|
||||
void EventSub::EnableTimestampValidation(bool enable)
|
||||
{
|
||||
_validateTimestamps = enable;
|
||||
}
|
||||
|
||||
void EventSub::Disconnect()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_connectMtx);
|
||||
@@ -191,7 +196,7 @@ static obs_data_t *copyData(const OBSData &data)
|
||||
return obs_data_create_from_json(json);
|
||||
}
|
||||
|
||||
std::string EventSub::AddEventSubscribtion(std::shared_ptr<TwitchToken> token,
|
||||
std::string EventSub::AddEventSubscription(std::shared_ptr<TwitchToken> token,
|
||||
Subscription subscription)
|
||||
{
|
||||
auto eventSub = token->GetEventSub();
|
||||
@@ -318,7 +323,7 @@ void EventSub::OnMessage(connection_hdl, EventSubWSClient::message_ptr message)
|
||||
OBSDataAutoRelease metadata = obs_data_get_obj(json, "metadata");
|
||||
std::string timestamp =
|
||||
obs_data_get_string(metadata, "message_timestamp");
|
||||
if (!isValidTimestamp(timestamp)) {
|
||||
if (_validateTimestamps && !isValidTimestamp(timestamp)) {
|
||||
blog(LOG_WARNING,
|
||||
"Discarding Twitch EventSub with invalid timestamp %s",
|
||||
timestamp.c_str());
|
||||
@@ -341,7 +346,7 @@ void EventSub::OnMessage(connection_hdl, EventSubWSClient::message_ptr message)
|
||||
} else if (messageType == "session_reconnect") {
|
||||
HandleReconnect(payloadJson);
|
||||
} else if (messageType == "revocation") {
|
||||
HanldeRevocation(payloadJson);
|
||||
HandleRevocation(payloadJson);
|
||||
} else {
|
||||
vblog(LOG_INFO, "ignoring message of unknown type '%s'",
|
||||
messageType.c_str());
|
||||
@@ -387,7 +392,7 @@ void EventSub::HandleReconnect(obs_data_t *data)
|
||||
"Twitch EventSub reconnecting", ec);
|
||||
}
|
||||
|
||||
void EventSub::HanldeRevocation(obs_data_t *data)
|
||||
void EventSub::HandleRevocation(obs_data_t *data)
|
||||
{
|
||||
OBSDataAutoRelease subscription =
|
||||
obs_data_get_obj(data, "subscription");
|
||||
|
||||
@@ -55,9 +55,10 @@ public:
|
||||
void Disconnect();
|
||||
[[nodiscard]] EventSubMessageBuffer RegisterForEvents();
|
||||
bool SubscriptionIsActive(const std::string &id);
|
||||
static std::string AddEventSubscribtion(std::shared_ptr<TwitchToken>,
|
||||
static std::string AddEventSubscription(std::shared_ptr<TwitchToken>,
|
||||
Subscription);
|
||||
void ClearActiveSubscriptions();
|
||||
void EnableTimestampValidation(bool enable);
|
||||
|
||||
private:
|
||||
void OnOpen(connection_hdl hdl);
|
||||
@@ -74,7 +75,7 @@ private:
|
||||
void HandleKeepAlive() const;
|
||||
void HandleNotification(obs_data_t *);
|
||||
void HandleReconnect(obs_data_t *);
|
||||
void HanldeRevocation(obs_data_t *);
|
||||
void HandleRevocation(obs_data_t *);
|
||||
|
||||
void RegisterInstance();
|
||||
void UnregisterInstance();
|
||||
@@ -89,6 +90,7 @@ private:
|
||||
std::atomic_bool _disconnect{false};
|
||||
std::string _url;
|
||||
std::string _sessionID;
|
||||
bool _validateTimestamps = true;
|
||||
|
||||
std::deque<std::string> _messageIDs;
|
||||
std::mutex _subscriptionMtx;
|
||||
|
||||
@@ -1008,7 +1008,7 @@ waitForSubscription(const std::shared_ptr<TwitchToken> &token,
|
||||
const Subscription &subscription)
|
||||
{
|
||||
return std::async(std::launch::async, [token, subscription]() {
|
||||
auto id = EventSub::AddEventSubscribtion(token, subscription);
|
||||
auto id = EventSub::AddEventSubscription(token, subscription);
|
||||
return id;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ const std::unordered_map<std::string, std::string> TokenOption::_apiIdToLocale{
|
||||
static void saveConnections(obs_data_t *obj);
|
||||
static void loadConnections(obs_data_t *obj);
|
||||
|
||||
bool setupTwitchTokenSupport()
|
||||
static bool setupTwitchTokenSupport()
|
||||
{
|
||||
AddSaveStep(saveConnections);
|
||||
AddLoadStep(loadConnections);
|
||||
@@ -153,11 +153,37 @@ bool TokenOption::operator<(const TokenOption &other) const
|
||||
return apiId < other.apiId;
|
||||
}
|
||||
|
||||
TwitchToken::TwitchToken(const TwitchToken &other)
|
||||
: Item(other._name),
|
||||
_token(other._token),
|
||||
_lastValidityCheckTime(),
|
||||
_lastValidityCheckValue(),
|
||||
_lastValidityCheckResult(false),
|
||||
_userID(other._userID),
|
||||
_tokenOptions(other._tokenOptions),
|
||||
_eventSub(),
|
||||
_validateEventSubTimestamps(other._validateEventSubTimestamps)
|
||||
{
|
||||
}
|
||||
|
||||
TwitchToken &TwitchToken::operator=(const TwitchToken &other)
|
||||
{
|
||||
_name = other._name;
|
||||
_token = other._token;
|
||||
_userID = other._userID;
|
||||
_tokenOptions = other._tokenOptions;
|
||||
_validateEventSubTimestamps = other._validateEventSubTimestamps;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void TwitchToken::Load(obs_data_t *obj)
|
||||
{
|
||||
Item::Load(obj);
|
||||
_token = obs_data_get_string(obj, "token");
|
||||
_userID = obs_data_get_string(obj, "userID");
|
||||
obs_data_set_default_bool(obj, "validateEventSubTimestamps", true);
|
||||
_validateEventSubTimestamps =
|
||||
obs_data_get_bool(obj, "validateEventSubTimestamps");
|
||||
_tokenOptions.clear();
|
||||
OBSDataArrayAutoRelease options = obs_data_get_array(obj, "options");
|
||||
size_t count = obs_data_array_count(options);
|
||||
@@ -174,6 +200,8 @@ void TwitchToken::Save(obs_data_t *obj) const
|
||||
Item::Save(obj);
|
||||
obs_data_set_string(obj, "token", _token.c_str());
|
||||
obs_data_set_string(obj, "userID", _userID.c_str());
|
||||
obs_data_set_bool(obj, "validateEventSubTimestamps",
|
||||
_validateEventSubTimestamps);
|
||||
OBSDataArrayAutoRelease options = obs_data_array_create();
|
||||
for (auto &option : _tokenOptions) {
|
||||
OBSDataAutoRelease arrayObj = obs_data_create();
|
||||
@@ -260,45 +288,46 @@ std::shared_ptr<EventSub> TwitchToken::GetEventSub()
|
||||
{
|
||||
if (!_eventSub) {
|
||||
_eventSub = std::make_shared<EventSub>();
|
||||
_eventSub->EnableTimestampValidation(
|
||||
_validateEventSubTimestamps);
|
||||
}
|
||||
return _eventSub;
|
||||
}
|
||||
|
||||
bool TwitchToken::IsValid(bool forceUpdate) const
|
||||
{
|
||||
static std::chrono::system_clock::time_point queryTime;
|
||||
static std::string lastQueryToken;
|
||||
static httplib::Result response;
|
||||
static httplib::Client cli("https://id.twitch.tv");
|
||||
httplib::Headers headers{{"Authorization", "OAuth " + _token}};
|
||||
|
||||
std::scoped_lock<std::mutex> lock(_cacheMutex);
|
||||
|
||||
auto currentTime = std::chrono::system_clock::now();
|
||||
auto diff = currentTime - queryTime;
|
||||
auto diff = currentTime - _lastValidityCheckTime;
|
||||
const bool cacheIsTooOld = diff >= std::chrono::hours(1);
|
||||
|
||||
const bool tokenChanged = lastQueryToken != _token;
|
||||
if (tokenChanged) {
|
||||
response =
|
||||
const auto checkToken = [&]() -> bool {
|
||||
const auto response =
|
||||
cli.Get("/oauth2/validate", httplib::Params{}, headers);
|
||||
queryTime = std::chrono::system_clock::now();
|
||||
lastQueryToken = _token;
|
||||
return response && response->status == 200;
|
||||
_lastValidityCheckTime = std::chrono::system_clock::now();
|
||||
_lastValidityCheckValue = _token;
|
||||
_lastValidityCheckResult = response && response->status == 200;
|
||||
if (!_lastValidityCheckResult) {
|
||||
blog(LOG_INFO, "Twitch token %s is not valid!",
|
||||
_name.c_str());
|
||||
}
|
||||
return _lastValidityCheckResult;
|
||||
};
|
||||
|
||||
const bool tokenChanged = _lastValidityCheckValue != _token;
|
||||
if (tokenChanged) {
|
||||
return checkToken();
|
||||
}
|
||||
|
||||
// No point in checking again as token will not become valid again
|
||||
if (!forceUpdate && response && response->status != 200) {
|
||||
blog(LOG_INFO, "Twitch token %s is not valid!", _name.c_str());
|
||||
return false;
|
||||
if (!forceUpdate && !cacheIsTooOld) {
|
||||
return _lastValidityCheckResult;
|
||||
}
|
||||
|
||||
if (!forceUpdate && !cacheIsTooOld && response) {
|
||||
return response->status == 200;
|
||||
}
|
||||
|
||||
response = cli.Get("/oauth2/validate", httplib::Params{}, headers);
|
||||
queryTime = std::chrono::system_clock::now();
|
||||
lastQueryToken = _token;
|
||||
return response && response->status == 200;
|
||||
return checkToken();
|
||||
}
|
||||
|
||||
TwitchToken *GetTwitchTokenByName(const QString &name)
|
||||
@@ -445,7 +474,9 @@ TwitchTokenSettingsDialog::TwitchTokenSettingsDialog(
|
||||
_showToken(new QPushButton()),
|
||||
_currentTokenValue(new QLineEdit()),
|
||||
_tokenStatus(new QLabel()),
|
||||
_generalSettingsGrid(new QGridLayout())
|
||||
_generalSettingsGrid(new QGridLayout()),
|
||||
_validateTimestamps(new QCheckBox(obs_module_text(
|
||||
"AdvSceneSwitcher.twitchToken.validateTimestamps")))
|
||||
{
|
||||
_showToken->setMaximumWidth(22);
|
||||
_showToken->setFlat(true);
|
||||
@@ -511,6 +542,7 @@ TwitchTokenSettingsDialog::TwitchTokenSettingsDialog(
|
||||
auto layout = new QVBoxLayout(contentWidget);
|
||||
layout->addLayout(_generalSettingsGrid);
|
||||
layout->addWidget(optionsBox);
|
||||
layout->addWidget(_validateTimestamps);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
scrollArea->setWidget(contentWidget);
|
||||
|
||||
@@ -532,6 +564,8 @@ TwitchTokenSettingsDialog::TwitchTokenSettingsDialog(
|
||||
true);
|
||||
}
|
||||
|
||||
_validateTimestamps->setChecked(settings._validateEventSubTimestamps);
|
||||
|
||||
_currentToken = settings;
|
||||
|
||||
QWidget::connect(&_validationTimer, &QTimer::timeout, this,
|
||||
@@ -737,6 +771,12 @@ bool TwitchTokenSettingsDialog::AskForSettings(QWidget *parent,
|
||||
|
||||
settings = dialog._currentToken;
|
||||
settings._tokenOptions = dialog.GetEnabledOptions();
|
||||
settings._validateEventSubTimestamps =
|
||||
dialog._validateTimestamps->isChecked();
|
||||
if (settings._eventSub) {
|
||||
settings._eventSub->EnableTimestampValidation(
|
||||
settings._validateEventSubTimestamps);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,10 @@ private:
|
||||
|
||||
class TwitchToken : public Item {
|
||||
public:
|
||||
TwitchToken() = default;
|
||||
TwitchToken(const TwitchToken &);
|
||||
TwitchToken &operator=(const TwitchToken &);
|
||||
|
||||
static std::shared_ptr<Item> Create()
|
||||
{
|
||||
return std::make_shared<TwitchToken>();
|
||||
@@ -49,14 +53,20 @@ public:
|
||||
std::optional<std::string> GetToken() const;
|
||||
std::string GetUserID() const { return _userID; }
|
||||
std::shared_ptr<EventSub> GetEventSub();
|
||||
bool ValidateTimestamps() const { return _validateEventSubTimestamps; }
|
||||
bool IsValid(bool forceUpdate = false) const;
|
||||
size_t PermissionCount() const { return _tokenOptions.size(); }
|
||||
|
||||
private:
|
||||
std::string _token;
|
||||
mutable std::mutex _cacheMutex;
|
||||
mutable std::string _lastValidityCheckValue;
|
||||
mutable bool _lastValidityCheckResult = false;
|
||||
mutable std::chrono::system_clock::time_point _lastValidityCheckTime;
|
||||
std::string _userID;
|
||||
std::set<TokenOption> _tokenOptions = TokenOption::GetAllTokenOptions();
|
||||
std::shared_ptr<EventSub> _eventSub;
|
||||
bool _validateEventSubTimestamps = false;
|
||||
|
||||
static bool _setup;
|
||||
|
||||
@@ -120,6 +130,7 @@ private:
|
||||
TokenGrabberThread _tokenGrabber;
|
||||
TwitchToken _currentToken;
|
||||
std::unordered_map<std::string, QCheckBox *> _optionWidgets;
|
||||
QCheckBox *_validateTimestamps;
|
||||
QTimer _validationTimer;
|
||||
};
|
||||
|
||||
|
||||
@@ -64,9 +64,14 @@ target_sources(
|
||||
|
||||
# --- json --- #
|
||||
|
||||
if(TARGET jsoncons)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE jsoncons)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE JSONPATH_SUPPORT=1)
|
||||
endif()
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC nlohmann_json::nlohmann_json)
|
||||
target_sources(
|
||||
${PROJECT_NAME}
|
||||
PRIVATE test-json.cpp ${ADVSS_SOURCE_DIR}/plugins/base/utils/json-helpers.cpp)
|
||||
${PROJECT_NAME} PRIVATE test-json.cpp
|
||||
${ADVSS_SOURCE_DIR}/lib/utils/json-helpers.cpp)
|
||||
|
||||
# --- math --- #
|
||||
|
||||
@@ -95,8 +100,6 @@ target_sources(
|
||||
|
||||
# --- utility --- #
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC nlohmann_json::nlohmann_json)
|
||||
|
||||
target_sources(
|
||||
${PROJECT_NAME} PRIVATE test-utility.cpp
|
||||
${ADVSS_SOURCE_DIR}/lib/utils/utility.cpp)
|
||||
|
||||
@@ -51,3 +51,55 @@ TEST_CASE("MatchJson", "[json-helpers]")
|
||||
result = advss::MatchJson("{\n \"test\": true\n}\n", "(", regex);
|
||||
REQUIRE(result == false);
|
||||
}
|
||||
|
||||
TEST_CASE("GetJsonField", "[json-helpers]")
|
||||
{
|
||||
auto result = advss::GetJsonField("{}", "");
|
||||
REQUIRE_FALSE(result);
|
||||
|
||||
result = advss::GetJsonField("{}", "not there");
|
||||
REQUIRE_FALSE(result);
|
||||
|
||||
result = advss::GetJsonField("invalid json", "not there");
|
||||
REQUIRE_FALSE(result);
|
||||
|
||||
result = advss::GetJsonField("{ \"test\": 1 }", "test");
|
||||
REQUIRE(*result == "1");
|
||||
}
|
||||
|
||||
TEST_CASE("QueryJson", "[json-helpers]")
|
||||
{
|
||||
auto result = advss::QueryJson("{}", "");
|
||||
REQUIRE_FALSE(result);
|
||||
|
||||
result = advss::QueryJson("invalid json", "$.test");
|
||||
REQUIRE_FALSE(result);
|
||||
|
||||
result = advss::QueryJson("{}", "invalid query");
|
||||
REQUIRE_FALSE(result);
|
||||
|
||||
result = advss::QueryJson("{}", "$.test");
|
||||
REQUIRE(*result == "[]");
|
||||
|
||||
result = advss::QueryJson("{ \"test\": { \"something\" : 1 } }",
|
||||
"$.test.something");
|
||||
REQUIRE(*result == "[1]");
|
||||
}
|
||||
|
||||
TEST_CASE("AccessJsonArrayIndex", "[json-helpers]")
|
||||
{
|
||||
auto result = advss::AccessJsonArrayIndex("{}", 0);
|
||||
REQUIRE_FALSE(result);
|
||||
|
||||
result = advss::AccessJsonArrayIndex("invalid json", 0);
|
||||
REQUIRE_FALSE(result);
|
||||
|
||||
result = advss::AccessJsonArrayIndex("[]", 0);
|
||||
REQUIRE_FALSE(result);
|
||||
|
||||
result = advss::AccessJsonArrayIndex("[\"1\", \"2\"]", -1);
|
||||
REQUIRE_FALSE(result);
|
||||
|
||||
result = advss::AccessJsonArrayIndex("[\"1\", \"2\"]", 1);
|
||||
REQUIRE(*result == "2");
|
||||
}
|
||||
|
||||
@@ -20,21 +20,6 @@ TEST_CASE("ReplaceAll", "[utility]")
|
||||
REQUIRE(input == "sleeping");
|
||||
}
|
||||
|
||||
TEST_CASE("GetJsonField", "[utility]")
|
||||
{
|
||||
auto result = advss::GetJsonField("{}", "");
|
||||
REQUIRE_FALSE(result);
|
||||
|
||||
result = advss::GetJsonField("{}", "not there");
|
||||
REQUIRE_FALSE(result);
|
||||
|
||||
result = advss::GetJsonField("invalid json", "not there");
|
||||
REQUIRE_FALSE(result);
|
||||
|
||||
result = advss::GetJsonField("{ \"test\": 1 }", "test");
|
||||
REQUIRE(*result == "1");
|
||||
}
|
||||
|
||||
TEST_CASE("CompareIgnoringLineEnding", "[utility]")
|
||||
{
|
||||
QString s1;
|
||||
|
||||
Reference in New Issue
Block a user