diff --git a/src/main/kotlin/net/eksb/obsdc/Op.kt b/src/main/kotlin/net/eksb/obsdc/Op.kt index 7b33282..891c05a 100644 --- a/src/main/kotlin/net/eksb/obsdc/Op.kt +++ b/src/main/kotlin/net/eksb/obsdc/Op.kt @@ -3,6 +3,12 @@ package net.eksb.obsdc enum class Op { /** If in studio mode, transition between scenes. */ STUDIO_TRANSITION, + /** Enable/disable studio mode. */ + STUDIO_MODE_TOGGLE, + /** Activate the previous scene. */ + SCENE_PREV, + /** Activate the next scene. */ + SCENE_NEXT, /** Activate the first scene. */ SCENE_1, /** Activate the second scene. */ diff --git a/src/main/kotlin/net/eksb/obsdc/OpRunner.kt b/src/main/kotlin/net/eksb/obsdc/OpRunner.kt index bb9a2a9..70ffbb3 100644 --- a/src/main/kotlin/net/eksb/obsdc/OpRunner.kt +++ b/src/main/kotlin/net/eksb/obsdc/OpRunner.kt @@ -20,17 +20,43 @@ class OpRunner(private val obs:Obs) { private val controller = obs.controller + /** + * Run the specified [Op]. + */ fun run(op:Op) { obs.submit { controller -> when(op) { - Op.SCENE_1 -> scene { scenes -> scenes.firstOrNull() } - Op.SCENE_2 -> scene { scenes -> scenes.asSequence().drop(1).firstOrNull() } - Op.SCENE_3 -> scene { scenes -> scenes.asSequence().drop(2).firstOrNull() } + Op.SCENE_NEXT -> scene { scenes, current -> + if (current != null) { + scenes.asSequence() + .dropWhile { scene -> scene != current } + .drop(1) + .firstOrNull() + ?: scenes.firstOrNull() + } else { + null + } + } + Op.SCENE_PREV -> scene { scenes, current -> + if (current != null) { + scenes.reversed().asSequence() + .dropWhile { scene -> scene != current } + .drop(1) + .firstOrNull() + ?: scenes.lastOrNull() + } else { + null + } + } + Op.SCENE_1 -> scene { scenes, current -> scenes.firstOrNull() } + Op.SCENE_2 -> scene { scenes, current -> scenes.asSequence().drop(1).firstOrNull() } + Op.SCENE_3 -> scene { scenes, current -> scenes.asSequence().drop(2).firstOrNull() } Op.STUDIO_TRANSITION -> { controller.triggerStudioModeTransition { response -> log.debug("studio transitioned: ${response.isSuccessful}") } } + Op.STUDIO_MODE_TOGGLE -> studioModeToggle() Op.PAN_UP -> transform { old -> positionY(old.positionY - panAmount ) } Op.PAN_DOWN -> transform { old -> positionY(old.positionY + panAmount ) } Op.PAN_LEFT -> transform { old -> positionX(old.positionX - panAmount ) } @@ -39,17 +65,37 @@ class OpRunner(private val obs:Obs) { } } + private fun studioModeToggle() { + controller.getStudioModeEnabled { response -> + if (response.isSuccessful) { + val enable = !response.studioModeEnabled + log.debug("toggle studio mode: ${!enable}") + controller.setStudioModeEnabled(enable) { response -> + log.debug("toggled studio mode: ${enable}") + } + } + } + } + /** * Select a scene from the scene list with the supplied [selector] and set the selected scene (if any) * as the current program scene. + * + * @param selector Lambda that takes as arguments the list of scenes and the current scene (or null if the current + * scene is unknown), and returns the scene to select, or null to not change the scene. */ - private fun scene(selector:(List)->Scene?) { - controller.getSceneList { response -> - val scene = selector(response.scenes.sortedBy(Scene::getSceneIndex).reversed()) - log.debug("select scene ${scene?.sceneName} index:${scene?.sceneIndex}") - if (scene != null) { - controller.setCurrentProgramScene(scene.sceneName) { response -> - log.debug("selected scene ${scene.sceneName}: ${response.isSuccessful}") + private fun scene(selector:(List,Scene?)->Scene?) { + controller.getCurrentProgramScene { response -> + val currentSceneName = response.currentProgramSceneName + controller.getSceneList { response -> + val scenes = response.scenes.sortedBy(Scene::getSceneIndex).reversed() + val currentScene = scenes.find { scene -> scene.sceneName == currentSceneName } + val scene = selector(response.scenes.sortedBy(Scene::getSceneIndex).reversed(), currentScene) + log.debug("select scene ${scene?.sceneName} index:${scene?.sceneIndex}") + if (scene != null) { + controller.setCurrentProgramScene(scene.sceneName) { response -> + log.debug("selected scene ${scene.sceneName}: ${response.isSuccessful}") + } } } }