Compare commits

..

No commits in common. "master" and "release-1.0.0-beta1" have entirely different histories.

35 changed files with 281 additions and 654 deletions

1
.gitignore vendored
View File

@ -2,7 +2,6 @@
.clangd .clangd
.conanbuild .conanbuild
.current_build .current_build
.idea
__pycache__ __pycache__
CMakeLists.txt.user CMakeLists.txt.user
Session.vim Session.vim

7
.idea/misc.xml generated Normal file
View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
<component name="CompDBWorkspace">
<contentRoot DIR="$PROJECT_DIR$" />
</component>
</project>

6
.idea/vcs.xml generated Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

View File

@ -2,7 +2,7 @@
source: source:
- . - .
copyright_notice: |- copyright_notice: |-
Copyright 2021 - 2024 gary@drinkingtea.net Copyright 2021 - 2023 gary@drinkingtea.net
This Source Code Form is subject to the terms of the Mozilla Public This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this License, v. 2.0. If a copy of the MPL was not distributed with this

View File

@ -14,10 +14,6 @@ if(NOT MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsign-conversion") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsign-conversion")
endif() endif()
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_INSTALL_RPATH "$ORIGIN" "$ORIGIN/../") set(CMAKE_INSTALL_RPATH "$ORIGIN" "$ORIGIN/../")
if(QTDIR) if(QTDIR)
set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_RPATH} "${QTDIR}/lib") set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_RPATH} "${QTDIR}/lib")

View File

@ -3,15 +3,15 @@ BUILDCORE_PATH=deps/buildcore
VCPKG_PKGS= VCPKG_PKGS=
include ${BUILDCORE_PATH}/base.mk include ${BUILDCORE_PATH}/base.mk
ifeq ($(BC_VAR_OS),darwin) ifeq ($(OS),darwin)
PROJECT_EXECUTABLE=./build/${BC_VAR_CURRENT_BUILD}/bin/${PROJECT_NAME}.app/Contents/MacOS/SlideController PROJECT_EXECUTABLE=./dist/${CURRENT_BUILD}/${PROJECT_NAME}.app/Contents/MacOS/SlideController
else else
PROJECT_EXECUTABLE=./build/${BC_VAR_CURRENT_BUILD}/bin/${PROJECT_NAME} PROJECT_EXECUTABLE=./dist/${CURRENT_BUILD}/bin/SlideController
endif endif
.PHONY: run .PHONY: run
run: build run: install
${ENV_RUN} ${PROJECT_EXECUTABLE} ${ENV_RUN} ${PROJECT_EXECUTABLE}
.PHONY: debug .PHONY: debug
debug: build debug: install
${DEBUGGER} ${PROJECT_EXECUTABLE} ${DEBUGGER} ${PROJECT_EXECUTABLE}

View File

@ -1,19 +0,0 @@
# Slide Controller 9000
## Build Prerequisites
* Install GCC, Clang, or Visual Studio with C++20 support
* Install Python 3
* Install Ninja, Make, and CMake
* [Qt6](https://www.qt.io/download-qt-installer-oss) (Network and Widgets)
* Consider also installing ccache for faster subsequent build times
## Build
Build options: release, debug, asan
make purge configure-{release,debug,asan} install
## Run
make run

196
deps/buildcore/base.mk vendored
View File

@ -9,103 +9,89 @@
ifeq (${OS},Windows_NT) ifeq (${OS},Windows_NT)
SHELL := powershell.exe SHELL := powershell.exe
.SHELLFLAGS := -NoProfile -Command .SHELLFLAGS := -NoProfile -Command
BC_VAR_OS=windows OS=windows
BC_CMD_HOST_PY3=python HOST_ENV=${OS}
else else
BC_VAR_OS=$(shell uname | tr [:upper:] [:lower:]) OS=$(shell uname | tr [:upper:] [:lower:])
ifneq ($(shell which python3 2> /dev/null),) HOST_ENV=${OS}-$(shell uname -m)
BC_CMD_HOST_PY3=python3 endif
else
ifeq ($(shell python -c 'import sys; print(sys.version_info[0])'),3) DEVENV=devenv$(shell pwd | sed 's/\//-/g')
BC_CMD_HOST_PY3=python DEVENV_IMAGE=${PROJECT_NAME}-devenv
else ifneq ($(shell which docker 2> /dev/null),)
echo 'Please install Python3 on host' ifeq ($(shell docker inspect --format="{{.State.Status}}" ${DEVENV} 2>&1),running)
exit 1 ENV_RUN=docker exec -i -t --user $(shell id -u ${USER}) ${DEVENV}
endif
endif endif
endif endif
ifneq ($(shell ${ENV_RUN} which python3 2> /dev/null),)
ifdef BC_VAR_USE_DOCKER_DEVENV PYTHON3=python3
ifneq ($(shell which docker 2> /dev/null),)
BC_VAR_DEVENV=devenv$(shell pwd | sed 's/\//-/g')
BC_VAR_DEVENV_IMAGE=${BC_VAR_PROJECT_NAME}-devenv
ifeq ($(shell docker inspect --format="{{.State.Status}}" ${BC_VAR_DEVENV} 2>&1),running)
BC_CMD_ENVRUN=docker exec -i -t --user $(shell id -u ${USER}) ${BC_VAR_DEVENV}
endif
endif
ifneq ($(shell ${BC_CMD_ENVRUN} which python3 2> /dev/null),)
BC_CMD_PY3=${BC_CMD_ENVRUN} python3
else
ifeq ($(shell ${BC_CMD_ENVRUN} python -c 'import sys; print(sys.version_info[0])'),3)
BC_CMD_PY3=${BC_CMD_ENVRUN} python
else
echo 'Please install Python3 in devenv'
exit 1
endif
endif
ifndef BC_VAR_DEVENV_ROOT
BC_VAR_DEVENV_ROOT="."
endif
else else
BC_CMD_PY3=${BC_CMD_HOST_PY3} ifeq ($(shell ${ENV_RUN} python -c 'import sys; print(sys.version_info[0])'),3)
PYTHON3=python
endif
endif endif
BC_VAR_SCRIPTS=${BUILDCORE_PATH}/scripts SCRIPTS=${BUILDCORE_PATH}/scripts
BC_CMD_SETUP_BUILD=${BC_CMD_PY3} ${BC_VAR_SCRIPTS}/setup-build.py SETUP_BUILD=${PYTHON3} ${SCRIPTS}/setup-build.py
BC_CMD_PYBB=${BC_CMD_PY3} ${BC_VAR_SCRIPTS}/pybb.py PYBB=${PYTHON3} ${SCRIPTS}/pybb.py
BC_CMD_HOST_PYBB=${BC_CMD_HOST_PY3} ${BC_VAR_SCRIPTS}/pybb.py CMAKE_BUILD=${PYBB} cmake-build
BC_CMD_CMAKE_BUILD=${BC_CMD_PYBB} cmake-build GET_ENV=${PYBB} getenv
BC_CMD_GETENV=${BC_CMD_PYBB} getenv CTEST=${PYBB} ctest-all
BC_CMD_CTEST=${BC_CMD_PYBB} ctest-all RM_RF=${PYBB} rm
BC_CMD_RM_RF=${BC_CMD_PYBB} rm HOST=$(shell ${PYBB} hostname)
BC_CMD_MKDIR_P=${BC_CMD_PYBB} mkdir BUILDCORE_HOST_SPECIFIC_BUILDPATH=$(shell ${GET_ENV} BUILDCORE_HOST_SPECIFIC_BUILDPATH)
BC_CMD_CAT=${BC_CMD_PYBB} cat ifneq (${BUILDCORE_HOST_SPECIFIC_BUILDPATH},)
BC_CMD_DEBUGGER=${BC_CMD_PYBB} debug BUILD_PATH=build/${HOST}
BC_CMD_HOST_DEBUGGER=${BC_CMD_HOST_PYBB} debug else
BC_VAR_HOSTENV=$(shell ${BC_CMD_ENVRUN} ${BC_CMD_PYBB} hostenv) BUILD_PATH=build
BC_VAR_BUILD_PATH=build endif
BC_VAR_CURRENT_BUILD=$(BC_VAR_HOSTENV)-$(shell ${BC_CMD_ENVRUN} ${BC_CMD_CAT} .current_build) ifdef USE_VCPKG
ifndef VCPKG_DIR_BASE
VCPKG_DIR_BASE=.vcpkg
endif
ifndef VCPKG_VERSION
VCPKG_VERSION=2020.06
endif
VCPKG_TOOLCHAIN=--toolchain=${VCPKG_DIR}/scripts/buildsystems/vcpkg.cmake
endif
ifeq ($(OS),darwin)
DEBUGGER=lldb --
else
DEBUGGER=gdb --args
endif
ifdef BC_VAR_USE_VCPKG VCPKG_DIR=$(VCPKG_DIR_BASE)/$(VCPKG_VERSION)-$(HOST_ENV)
ifndef BC_VAR_VCPKG_DIR_BASE CURRENT_BUILD=$(HOST_ENV)-$(shell ${ENV_RUN} ${PYBB} cat .current_build)
BC_VAR_VCPKG_DIR_BASE=.vcpkg
endif
ifndef BC_VAR_VCPKG_VERSION
BC_VAR_VCPKG_VERSION=2023.08.09
endif
endif
.PHONY: build .PHONY: build
build: build:
${BC_CMD_CMAKE_BUILD} ${BC_VAR_BUILD_PATH} ${ENV_RUN} ${CMAKE_BUILD} ${BUILD_PATH}
.PHONY: install .PHONY: install
install: install:
${BC_CMD_CMAKE_BUILD} ${BC_VAR_BUILD_PATH} install ${ENV_RUN} ${CMAKE_BUILD} ${BUILD_PATH} install
.PHONY: clean .PHONY: clean
clean: clean:
${BC_CMD_CMAKE_BUILD} ${BC_VAR_BUILD_PATH} clean ${ENV_RUN} ${CMAKE_BUILD} ${BUILD_PATH} clean
.PHONY: purge .PHONY: purge
purge: purge:
${BC_CMD_RM_RF} .current_build ${ENV_RUN} ${RM_RF} .current_build
${BC_CMD_RM_RF} ${BC_VAR_BUILD_PATH} ${ENV_RUN} ${RM_RF} ${BUILD_PATH}
${BC_CMD_RM_RF} dist ${ENV_RUN} ${RM_RF} dist
${BC_CMD_RM_RF} compile_commands.json
.PHONY: test .PHONY: test
test: build test: build
${BC_CMD_ENVRUN} mypy ${BC_VAR_SCRIPTS} ${ENV_RUN} mypy ${SCRIPTS}
${BC_CMD_CMAKE_BUILD} ${BC_VAR_BUILD_PATH} test ${ENV_RUN} ${CMAKE_BUILD} ${BUILD_PATH} test
.PHONY: test-verbose .PHONY: test-verbose
test-verbose: build test-verbose: build
${BC_CMD_CTEST} ${BC_VAR_BUILD_PATH} --output-on-failure ${ENV_RUN} ${CTEST} ${BUILD_PATH} --output-on-failure
.PHONY: test-rerun-verbose .PHONY: test-rerun-verbose
test-rerun-verbose: build test-rerun-verbose: build
${BC_CMD_CTEST} ${BC_VAR_BUILD_PATH} --rerun-failed --output-on-failure ${ENV_RUN} ${CTEST} ${BUILD_PATH} --rerun-failed --output-on-failure
ifdef BC_VAR_USE_DOCKER_DEVENV
.PHONY: devenv-image .PHONY: devenv-image
devenv-image: devenv-image:
docker build ${BC_VAR_DEVENV_ROOT} -t ${BC_VAR_DEVENV_IMAGE} docker build . -t ${DEVENV_IMAGE}
.PHONY: devenv-create .PHONY: devenv-create
devenv-create: devenv-create:
docker run -d \ docker run -d \
@ -117,77 +103,73 @@ devenv-create:
-v $(shell pwd):/usr/src/project \ -v $(shell pwd):/usr/src/project \
-v /dev/shm:/dev/shm \ -v /dev/shm:/dev/shm \
--restart=always \ --restart=always \
--name ${BC_VAR_DEVENV} \ --name ${DEVENV} \
-t ${BC_VAR_DEVENV_IMAGE} bash -t ${DEVENV_IMAGE} bash
.PHONY: devenv-destroy .PHONY: devenv-destroy
devenv-destroy: devenv-destroy:
docker rm -f ${BC_VAR_DEVENV} docker rm -f ${DEVENV}
ifdef BC_CMD_ENVRUN ifdef ENV_RUN
.PHONY: devenv-shell .PHONY: devenv-shell
devenv-shell: devenv-shell:
${BC_CMD_ENVRUN} bash ${ENV_RUN} bash
endif
endif endif
ifdef BC_VAR_USE_VCPKG ifdef USE_VCPKG
BC_VAR_VCPKG_TOOLCHAIN=--toolchain=${BC_VAR_VCPKG_DIR}/scripts/buildsystems/vcpkg.cmake
BC_VAR_VCPKG_DIR=$(BC_VAR_VCPKG_DIR_BASE)/$(BC_VAR_VCPKG_VERSION)-$(BC_VAR_HOSTENV)
.PHONY: vcpkg .PHONY: vcpkg
vcpkg: ${BC_VAR_VCPKG_DIR} vcpkg-install vcpkg: ${VCPKG_DIR} vcpkg-install
${BC_VAR_VCPKG_DIR}: ${VCPKG_DIR}:
${BC_CMD_RM_RF} ${BC_VAR_VCPKG_DIR} ${ENV_RUN} ${RM_RF} ${VCPKG_DIR}
${BC_CMD_PYBB} mkdir ${BC_VAR_VCPKG_DIR_BASE} ${ENV_RUN} mkdir -p ${VCPKG_DIR_BASE}
${BC_CMD_ENVRUN} git clone -b release --depth 1 --branch ${BC_VAR_VCPKG_VERSION} https://github.com/microsoft/vcpkg.git ${BC_VAR_VCPKG_DIR} ${ENV_RUN} git clone -b release --depth 1 --branch ${VCPKG_VERSION} https://github.com/microsoft/vcpkg.git ${VCPKG_DIR}
ifneq (${BC_VAR_OS},windows) ifneq (${OS},windows)
${BC_CMD_ENVRUN} ${BC_VAR_VCPKG_DIR}/bootstrap-vcpkg.sh ${ENV_RUN} ${VCPKG_DIR}/bootstrap-vcpkg.sh
else else
${BC_CMD_ENVRUN} ${BC_VAR_VCPKG_DIR}/bootstrap-vcpkg.bat ${ENV_RUN} ${VCPKG_DIR}/bootstrap-vcpkg.bat
endif endif
.PHONY: vcpkg-install .PHONY: vcpkg-install
vcpkg-install: vcpkg-install:
ifneq (${BC_VAR_OS},windows) ifneq (${OS},windows)
${BC_CMD_ENVRUN} ${BC_VAR_VCPKG_DIR}/vcpkg install ${BC_VAR_VCPKG_PKGS} ${VCPKG_DIR}/vcpkg install ${VCPKG_PKGS}
else else
${BC_CMD_ENVRUN} ${BC_VAR_VCPKG_DIR}/vcpkg install --triplet x64-windows ${BC_VAR_VCPKG_PKGS} ${VCPKG_DIR}/vcpkg install --triplet x64-windows ${VCPKG_PKGS}
endif endif
else ifdef USE_CONAN # USE_VCPKG / USE_CONAN #################################### else ifdef USE_CONAN # USE_VCPKG ################################################
.PHONY: setup-conan .PHONY: setup-conan
conan-config: conan-config:
${BC_CMD_ENVRUN} conan profile new ${BC_VAR_PROJECT_NAME} --detect --force ${ENV_RUN} conan profile new ${PROJECT_NAME} --detect --force
ifeq ($(BC_VAR_OS),linux) ifeq ($(OS),linux)
${BC_CMD_ENVRUN} conan profile update settings.compiler.libcxx=libstdc++11 ${BC_VAR_PROJECT_NAME} ${ENV_RUN} conan profile update settings.compiler.libcxx=libstdc++11 ${PROJECT_NAME}
else else
${BC_CMD_ENVRUN} conan profile update settings.compiler.cppstd=20 ${BC_VAR_PROJECT_NAME} ${ENV_RUN} conan profile update settings.compiler.cppstd=20 ${PROJECT_NAME}
ifeq ($(BC_VAR_OS),windows) ifeq ($(OS),windows)
${BC_CMD_ENVRUN} conan profile update settings.compiler.runtime=static ${BC_VAR_PROJECT_NAME} ${ENV_RUN} conan profile update settings.compiler.runtime=static ${PROJECT_NAME}
endif endif
endif endif
.PHONY: conan .PHONY: conan
conan: conan:
${BC_CMD_PYBB} conan-install ${BC_VAR_PROJECT_NAME} ${ENV_RUN} ${PYBB} conan-install ${PROJECT_NAME}
endif # USE_CONAN ############################################### endif # USE_VCPKG ###############################################
ifeq (${BC_VAR_OS},darwin) ifeq (${OS},darwin)
.PHONY: configure-xcode .PHONY: configure-xcode
configure-xcode: configure-xcode:
${BC_CMD_SETUP_BUILD} ${BC_VAR_VCPKG_TOOLCHAIN} --build_tool=xcode --current_build=0 --build_root=${BC_VAR_BUILD_PATH} ${ENV_RUN} ${SETUP_BUILD} ${VCPKG_TOOLCHAIN} --build_tool=xcode --current_build=0 --build_root=${BUILD_PATH}
endif endif
.PHONY: configure-release .PHONY: configure-release
configure-release: configure-release:
${BC_CMD_SETUP_BUILD} ${BC_VAR_VCPKG_TOOLCHAIN} --build_type=release --build_root=${BC_VAR_BUILD_PATH} ${ENV_RUN} ${SETUP_BUILD} ${VCPKG_TOOLCHAIN} --build_type=release --build_root=${BUILD_PATH}
.PHONY: configure-debug .PHONY: configure-debug
configure-debug: configure-debug:
${BC_CMD_SETUP_BUILD} ${BC_VAR_VCPKG_TOOLCHAIN} --build_type=debug --build_root=${BC_VAR_BUILD_PATH} ${ENV_RUN} ${SETUP_BUILD} ${VCPKG_TOOLCHAIN} --build_type=debug --build_root=${BUILD_PATH}
.PHONY: configure-asan .PHONY: configure-asan
configure-asan: configure-asan:
${BC_CMD_SETUP_BUILD} ${BC_VAR_VCPKG_TOOLCHAIN} --build_type=asan --build_root=${BC_VAR_BUILD_PATH} ${ENV_RUN} ${SETUP_BUILD} ${VCPKG_TOOLCHAIN} --build_type=asan --build_root=${BUILD_PATH}

View File

@ -1,28 +0,0 @@
#! /usr/bin/env python3
#
# Copyright 2016 - 2022 gary@drinkingtea.net
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
import argparse
import sys
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--out-cpp', help='path to output cpp file')
parser.add_argument('--out-hpp', help='path to output hpp file')
args = parser.parse_args()
return 0
if __name__ == '__main__':
try:
err = main()
sys.exit(err)
except KeyboardInterrupt:
sys.exit(1)

View File

@ -18,20 +18,18 @@ import subprocess
import sys import sys
from typing import List, Optional from typing import List, Optional
import util
def mkdir(path: str):
if not os.path.exists(path):
os.mkdir(path)
def mkdir(path: str) -> int: # this exists because Windows is utterly incapable of providing a proper rm -rf
try: def rm(path: str):
util.mkdir_p(path) if (os.path.exists(path) or os.path.islink(path)) and not os.path.isdir(path):
except Exception: os.remove(path)
return 1 elif os.path.isdir(path):
return 0 shutil.rmtree(path)
def rm_multi(paths: List[str]):
for path in paths:
util.rm(path)
def ctest_all() -> int: def ctest_all() -> int:
@ -72,13 +70,16 @@ def conan() -> int:
err = 0 err = 0
try: try:
mkdir(conan_dir) mkdir(conan_dir)
except Exception: except:
return 1 return 1
if err != 0: if err != 0:
return err return err
args = ['conan', 'install', '../', '--build=missing', '-pr', project_name] args = ['conan', 'install', '../', '--build=missing', '-pr', project_name]
os.chdir(conan_dir) os.chdir(conan_dir)
return subprocess.run(args).returncode err = subprocess.run(args).returncode
if err != 0:
return err
return 0
def cat(paths: List[str]) -> int: def cat(paths: List[str]) -> int:
@ -86,70 +87,48 @@ def cat(paths: List[str]) -> int:
try: try:
with open(path) as f: with open(path) as f:
data = f.read() data = f.read()
print(data) sys.stdout.write(data)
except FileNotFoundError: except FileNotFoundError:
sys.stderr.write(f'cat: {path}: no such file or directory\n') sys.stderr.write('cat: {}: no such file or directory\n'.format(path))
return 1 return 1
sys.stdout.write('\n')
return 0 return 0
def debug(paths: List[str]) -> int:
if shutil.which('gdb') is not None:
args = ['gdb', '--args']
elif shutil.which('lldb') is not None:
args = ['lldb', '--']
else:
sys.stderr.write('debug: could not find a supported debugger\n')
return 1
args.extend(paths)
return subprocess.run(args).returncode
def get_env(var_name: str) -> int: def get_env(var_name: str) -> int:
if var_name not in os.environ: if var_name not in os.environ:
return 1 return 1
print(os.environ[var_name]) sys.stdout.write(os.environ[var_name])
return 0 return 0
def hostname() -> int: def hostname() -> int:
print(platform.node()) sys.stdout.write(platform.node())
return 0 return 0
def host_env() -> int:
os_name = platform.system().lower()
arch = util.get_arch()
print(f'{os_name}-{arch}')
return 0
def clarg(idx: int) -> Optional[str]:
return sys.argv[idx] if len(sys.argv) > idx else None
def main() -> int: def main() -> int:
err = 0 err = 0
if sys.argv[1] == 'mkdir': if sys.argv[1] == 'mkdir':
err = mkdir(sys.argv[2]) try:
mkdir(sys.argv[2])
except:
err = 1
elif sys.argv[1] == 'rm': elif sys.argv[1] == 'rm':
rm_multi(sys.argv[2:]) for i in range(2, len(sys.argv)):
rm(sys.argv[i])
elif sys.argv[1] == 'conan-install': elif sys.argv[1] == 'conan-install':
err = conan() err = conan()
elif sys.argv[1] == 'ctest-all': elif sys.argv[1] == 'ctest-all':
err = ctest_all() err = ctest_all()
elif sys.argv[1] == 'cmake-build': elif sys.argv[1] == 'cmake-build':
err = cmake_build(sys.argv[2], clarg(3)) err = cmake_build(sys.argv[2], sys.argv[3] if len(sys.argv) > 3 else None)
elif sys.argv[1] == 'cat': elif sys.argv[1] == 'cat':
err = cat(sys.argv[2:]) err = cat(sys.argv[2:])
elif sys.argv[1] == 'debug':
err = debug(sys.argv[2:])
elif sys.argv[1] == 'getenv': elif sys.argv[1] == 'getenv':
err = get_env(sys.argv[2]) err = get_env(sys.argv[2])
elif sys.argv[1] == 'hostname': elif sys.argv[1] == 'hostname':
err = hostname() err = hostname()
elif sys.argv[1] == 'hostenv':
err = host_env()
else: else:
sys.stderr.write('Command not found\n') sys.stderr.write('Command not found\n')
err = 1 err = 1

View File

@ -15,35 +15,18 @@ import shutil
import subprocess import subprocess
import sys import sys
import util from pybb import mkdir, rm
def main() -> int: def main() -> int:
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument( parser.add_argument('--target', help='Platform target',
'--target', default='{:s}-{:s}'.format(sys.platform, platform.machine()))
help='Platform target', parser.add_argument('--build_type', help='Build type (asan,debug,release)', default='release')
default=f'{util.get_os()}-{util.get_arch()}') parser.add_argument('--build_tool', help='Build tool (default,xcode)', default='')
parser.add_argument( parser.add_argument('--build_root', help='Path to the root of build directories (must be in project dir)', default='build')
'--build_type', parser.add_argument('--toolchain', help='Path to CMake toolchain file', default='')
help='Build type (asan,debug,release)', parser.add_argument('--current_build', help='Indicates whether or not to make this the active build', default=1)
default='release')
parser.add_argument(
'--build_tool',
help='Build tool (default,xcode)',
default='')
parser.add_argument(
'--build_root',
help='Path to the root build directory (must be in project dir)',
default='build')
parser.add_argument(
'--toolchain',
help='Path to CMake toolchain file',
default='')
parser.add_argument(
'--current_build',
help='Indicates whether or not to make this the active build',
default=1)
args = parser.parse_args() args = parser.parse_args()
if args.build_type == 'asan': if args.build_type == 'asan':
@ -81,10 +64,10 @@ def main() -> int:
return 1 return 1
project_dir = os.getcwd() project_dir = os.getcwd()
build_dir = f'{project_dir}/{args.build_root}/{build_config}' build_dir = '{:s}/{:s}/{:s}'.format(project_dir, args.build_root, build_config)
util.rm(build_dir) rm(build_dir)
cmake_cmd = [ cmake_cmd = [
'cmake', '-S', project_dir, '-B', build_dir, 'cmake', '-S', project_dir, '-B', build_dir, build_tool,
'-DCMAKE_EXPORT_COMPILE_COMMANDS=ON', '-DCMAKE_EXPORT_COMPILE_COMMANDS=ON',
'-DCMAKE_TOOLCHAIN_FILE={:s}'.format(args.toolchain), '-DCMAKE_TOOLCHAIN_FILE={:s}'.format(args.toolchain),
'-DCMAKE_BUILD_TYPE={:s}'.format(build_type_arg), '-DCMAKE_BUILD_TYPE={:s}'.format(build_type_arg),
@ -92,27 +75,22 @@ def main() -> int:
'-DBUILDCORE_BUILD_CONFIG={:s}'.format(build_config), '-DBUILDCORE_BUILD_CONFIG={:s}'.format(build_config),
'-DBUILDCORE_TARGET={:s}'.format(args.target), '-DBUILDCORE_TARGET={:s}'.format(args.target),
] ]
if build_tool != '':
cmake_cmd.append(build_tool)
if qt_path != '': if qt_path != '':
cmake_cmd.append(qt_path) cmake_cmd.append(qt_path)
if platform.system() == 'Windows' and platform.system() == 'AMD64': if platform.system() == 'Windows':
cmake_cmd.append('-A x64') cmake_cmd.append('-A x64')
cmake_err = subprocess.run(cmake_cmd).returncode subprocess.run(cmake_cmd)
if cmake_err != 0:
return cmake_err
util.mkdir_p('dist') mkdir('dist')
if int(args.current_build) != 0: if int(args.current_build) != 0:
cb = open('.current_build', 'w') cb = open('.current_build', 'w')
cb.write(args.build_type) cb.write(args.build_type)
cb.close() cb.close()
util.rm('compile_commands.json') rm('compile_commands.json')
if platform.system() != 'Windows': if platform.system() != 'Windows':
os.symlink(f'{build_dir}/compile_commands.json', os.symlink('{:s}/compile_commands.json'.format(build_dir), 'compile_commands.json')
'compile_commands.json')
return 0 return 0

View File

@ -1,38 +0,0 @@
#
# Copyright 2016 - 2021 gary@drinkingtea.net
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
import os
import platform
import shutil
def mkdir_p(path: str):
if not os.path.exists(path):
os.mkdir(path)
# this exists because Windows is utterly incapable of providing a proper rm -rf
def rm(path: str):
file_exists = os.path.exists(path)
is_link = os.path.islink(path)
is_dir = os.path.isdir(path)
if (file_exists or is_link) and not is_dir:
os.remove(path)
elif os.path.isdir(path):
shutil.rmtree(path)
def get_os() -> str:
return platform.system().lower()
def get_arch() -> str:
arch = platform.machine().lower()
if arch == 'amd64':
arch = 'x86_64'
return arch

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

View File

@ -3,7 +3,7 @@ set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON) set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOUIC ON)
find_package(QT NAMES Qt6 COMPONENTS Network Widgets REQUIRED) find_package(QT NAMES Qt6 Qt5 COMPONENTS Network Widgets REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Network Widgets REQUIRED) find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Network Widgets REQUIRED)
add_executable( add_executable(
@ -16,7 +16,6 @@ add_executable(
settingsdata.cpp settingsdata.cpp
settingsdialog.cpp settingsdialog.cpp
slideview.cpp slideview.cpp
sc9k.rc
) )
target_link_libraries( target_link_libraries(

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2021 - 2024 gary@drinkingtea.net * Copyright 2021 - 2023 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
@ -9,7 +9,6 @@
#include <QNetworkReply> #include <QNetworkReply>
#include <QSettings> #include <QSettings>
#include "consts.hpp"
#include "settingsdata.hpp" #include "settingsdata.hpp"
#include "cameraclient.hpp" #include "cameraclient.hpp"
@ -20,85 +19,27 @@ CameraClient::CameraClient(QObject *parent): QObject(parent) {
connect(m_pollingNam, &QNetworkAccessManager::finished, this, &CameraClient::handlePollResponse); connect(m_pollingNam, &QNetworkAccessManager::finished, this, &CameraClient::handlePollResponse);
} }
void CameraClient::setPresetVC(int preset, VideoConfig const&vc) {
if (preset > 0 && preset < MaxCameraPresets) {
get(QString("/cgi-bin/ptzctrl.cgi?ptzcmd&poscall&%1").arg(preset));
setBrightness(vc.brightness);
setSaturation(vc.saturation);
setContrast(vc.contrast);
setSharpness(vc.sharpness);
setHue(vc.hue);
}
}
void CameraClient::setPreset(int preset) { void CameraClient::setPreset(int preset) {
if (preset > 0 && preset < MaxCameraPresets) { if (preset > -1) {
get(QString("/cgi-bin/ptzctrl.cgi?ptzcmd&poscall&%1").arg(preset)); get(QString("/cgi-bin/ptzctrl.cgi?ptzcmd&poscall&%1").arg(preset));
auto const vc = getVideoConfig()[preset - 1];
setBrightness(vc.brightness);
setSaturation(vc.saturation);
setContrast(vc.contrast);
setSharpness(vc.sharpness);
setHue(vc.hue);
} }
} }
void CameraClient::reboot() {
post("/cgi-bin/param.cgi?post_reboot");
emit pollFailed();
}
void CameraClient::setBaseUrl() { void CameraClient::setBaseUrl() {
auto const [host, port] = getCameraConnectionData(); const auto [host, port] = getCameraConnectionData();
m_baseUrl = QString("http://%1:%2").arg(host, QString::number(port)); m_baseUrl = QString("http://%1:%2").arg(host, QString::number(port));
} }
void CameraClient::setBrightness(int val) {
if (val > -1) {
get(QString("/cgi-bin/ptzctrl.cgi?post_image_value&bright&%1").arg(val));
}
}
void CameraClient::setSaturation(int val) {
if (val > -1) {
get(QString("/cgi-bin/ptzctrl.cgi?post_image_value&saturation&%1").arg(val));
}
}
void CameraClient::setContrast(int val) {
if (val > -1) {
get(QString("/cgi-bin/ptzctrl.cgi?post_image_value&contrast&%1").arg(val));
}
}
void CameraClient::setSharpness(int val) {
if (val > -1) {
get(QString("/cgi-bin/ptzctrl.cgi?post_image_value&sharpness&%1").arg(val));
}
}
void CameraClient::setHue(int val) {
if (val > -1) {
get(QString("/cgi-bin/ptzctrl.cgi?post_image_value&hue&%1").arg(val));
}
}
void CameraClient::get(QString const&urlExt) { void CameraClient::get(QString const&urlExt) {
QUrl const url{QString{m_baseUrl} + urlExt}; QUrl url(QString(m_baseUrl) + urlExt);
QNetworkRequest rqst{url}; QNetworkRequest rqst(url);
auto const reply = m_nam->get(rqst); auto reply = m_nam->get(rqst);
connect(reply, &QIODevice::readyRead, reply, &QObject::deleteLater);
}
void CameraClient::post(QString const&urlExt) {
QNetworkRequest const rqst{QUrl{QString{m_baseUrl} + urlExt}};
auto const reply = m_nam->post(rqst, QByteArray{});
connect(reply, &QIODevice::readyRead, reply, &QObject::deleteLater); connect(reply, &QIODevice::readyRead, reply, &QObject::deleteLater);
} }
void CameraClient::poll() { void CameraClient::poll() {
QUrl const url{QString{m_baseUrl} + "/cgi-bin/param.cgi?get_device_conf"}; QUrl url(QString(m_baseUrl) + "/cgi-bin/param.cgi?get_device_conf");
QNetworkRequest const rqst{url}; QNetworkRequest rqst(url);
m_pollingNam->get(rqst); m_pollingNam->get(rqst);
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2021 - 2024 gary@drinkingtea.net * Copyright 2021 - 2023 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
@ -12,6 +12,8 @@
#include <QObject> #include <QObject>
#include <QTimer> #include <QTimer>
#include "consts.hpp"
class CameraClient: public QObject { class CameraClient: public QObject {
Q_OBJECT Q_OBJECT
private: private:
@ -23,30 +25,14 @@ class CameraClient: public QObject {
public: public:
explicit CameraClient(QObject *parent = nullptr); explicit CameraClient(QObject *parent = nullptr);
void setPresetVC(int preset, struct VideoConfig const&vc);
void setPreset(int preset); void setPreset(int preset);
void reboot();
public slots: public slots:
void setBaseUrl(); void setBaseUrl();
private: private:
void setBrightness(int val);
void setSaturation(int val);
void setContrast(int val);
void setSharpness(int val);
void setHue(int val);
void get(QString const&url); void get(QString const&url);
void post(QString const&url);
void poll(); void poll();
void handlePollResponse(QNetworkReply *reply); void handlePollResponse(QNetworkReply *reply);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2021 - 2024 gary@drinkingtea.net * Copyright 2021 - 2023 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
@ -10,5 +10,4 @@
constexpr auto MaxCameraPresets = 9; constexpr auto MaxCameraPresets = 9;
constexpr auto MaxViews = 9; constexpr auto MaxViews = 9;
constexpr auto Version = "1.0.0";

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2021 - 2024 gary@drinkingtea.net * Copyright 2021 - 2023 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
@ -13,12 +13,8 @@
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
QSettings::setDefaultFormat(QSettings::Format::IniFormat); QSettings::setDefaultFormat(QSettings::Format::IniFormat);
#ifndef __APPLE__
QApplication::setStyle("Fusion");
#endif
QApplication a(argc, argv); QApplication a(argc, argv);
QApplication::setOrganizationName("DrinkingTea"); QApplication::setApplicationName(QObject::tr("Slide Controller 9000"));
QApplication::setApplicationName("Slide Controller 9000");
MainWindow w; MainWindow w;
w.show(); w.show();
return QApplication::exec(); return QApplication::exec();

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2021 - 2024 gary@drinkingtea.net * Copyright 2021 - 2023 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
@ -22,19 +22,19 @@ MainWindow::MainWindow(QWidget *parent): QMainWindow(parent) {
setFixedSize(610, 555); setFixedSize(610, 555);
setWindowTitle(tr("Slide Controller 9000")); setWindowTitle(tr("Slide Controller 9000"));
setupMenu(); setupMenu();
auto const mainWidget = new QWidget(this); const auto mainWidget = new QWidget(this);
m_rootLyt = new QVBoxLayout; m_rootLyt = new QVBoxLayout;
auto const controlsLayout = new QGridLayout; const auto controlsLayout = new QGridLayout;
m_slideView = new SlideView(this); m_slideView = new SlideView(this);
setCentralWidget(mainWidget); setCentralWidget(mainWidget);
mainWidget->setLayout(m_rootLyt); mainWidget->setLayout(m_rootLyt);
m_rootLyt->addWidget(m_slideView); m_rootLyt->addWidget(m_slideView);
m_rootLyt->addLayout(controlsLayout); m_rootLyt->addLayout(controlsLayout);
// setup slide controls // setup slide controls
auto const btnPrevSong = new QPushButton(tr("Previous Song"), this); const auto btnPrevSong = new QPushButton(tr("Previous Song"), this);
auto const btnPrevSlide = new QPushButton(tr("Previous Slide"), this); const auto btnPrevSlide = new QPushButton(tr("Previous Slide"), this);
auto const btnNextSlide = new QPushButton(tr("Next Slide"), this); const auto btnNextSlide = new QPushButton(tr("Next Slide"), this);
auto const btnNextSong = new QPushButton(tr("Next Song"), this); const auto btnNextSong = new QPushButton(tr("Next Song"), this);
btnPrevSong->setToolTip(tr("Change to previous song (left arrow key)")); btnPrevSong->setToolTip(tr("Change to previous song (left arrow key)"));
btnPrevSlide->setToolTip(tr("Change to previous slide (up arrow key)")); btnPrevSlide->setToolTip(tr("Change to previous slide (up arrow key)"));
btnNextSong->setToolTip(tr("Change to next song (right arrow key)")); btnNextSong->setToolTip(tr("Change to next song (right arrow key)"));
@ -112,8 +112,8 @@ void MainWindow::setupMenu() {
} }
// camera preset menu // camera preset menu
{ {
auto const menu = menuBar()->addMenu(tr("&Camera")); auto const menu = menuBar()->addMenu(tr("&Camera Preset"));
for (auto i = 0; i < std::min(9, MaxCameraPresets); ++i) { for (auto i = 0; i < MaxCameraPresets; ++i) {
auto const cameraPresetAct = new QAction(tr("Camera Preset &%1").arg(i + 1), this); auto const cameraPresetAct = new QAction(tr("Camera Preset &%1").arg(i + 1), this);
cameraPresetAct->setShortcut(Qt::ALT | static_cast<Qt::Key>(Qt::Key_1 + i)); cameraPresetAct->setShortcut(Qt::ALT | static_cast<Qt::Key>(Qt::Key_1 + i));
connect(cameraPresetAct, &QAction::triggered, &m_cameraClient, [this, i] { connect(cameraPresetAct, &QAction::triggered, &m_cameraClient, [this, i] {
@ -129,19 +129,39 @@ void MainWindow::setupMenu() {
connect(aboutAct, &QAction::triggered, &m_cameraClient, [this] { connect(aboutAct, &QAction::triggered, &m_cameraClient, [this] {
QMessageBox about(this); QMessageBox about(this);
about.setText(tr( about.setText(tr(
R"(Slide Controller 9000 - %1 R"(Slide Controller 9000 - 1.0-beta1
Build date: %2 Build date: %1
Copyright 2021 - 2025 Gary Talent (gary@drinkingtea.net) Copyright 2021 - 2023 Gary Talent (gary@drinkingtea.net)
Slide Controller 9000 is released under the MPL 2.0 Slide Controller 9000 is released under the MPL 2.0
Built on Qt library under LGPL 2.0)").arg(Version, __DATE__)); Built on Qt library under LGPL 2.0)").arg(__DATE__));
about.exec(); about.exec();
}); });
menu->addAction(aboutAct); menu->addAction(aboutAct);
} }
} }
void MainWindow::setupViewControlButtons(QVector<View> const&views, QGridLayout *viewCtlLyt) { void MainWindow::setupDefaultViewControls(QGridLayout *viewCtlLyt) {
auto const mainWidget = viewCtlLyt->parentWidget();
auto const btnHideSlides = new QPushButton(tr("1. Hide"), mainWidget);
auto const btnOpenLpShowSlides = new QPushButton(tr("2. Show in OpenLP Only"), mainWidget);
auto const btnShowSlides = new QPushButton(tr("3. Show"), mainWidget);
viewCtlLyt->addWidget(btnHideSlides, 0, 0);
viewCtlLyt->addWidget(btnOpenLpShowSlides, 0, 1);
viewCtlLyt->addWidget(btnShowSlides, 0, 2);
btnHideSlides->setShortcut(Qt::Key_1);
btnOpenLpShowSlides->setShortcut(Qt::Key_2);
btnHideSlides->setToolTip(tr("Also hides slides in OBS"));
btnShowSlides->setShortcut(Qt::Key_3);
connect(btnHideSlides, &QPushButton::clicked, &m_openlpClient, &OpenLPClient::blankScreen);
connect(btnHideSlides, &QPushButton::clicked, &m_obsClient, &OBSClient::hideSlides);
connect(btnOpenLpShowSlides, &QPushButton::clicked, &m_openlpClient, &OpenLPClient::showSlides);
connect(btnOpenLpShowSlides, &QPushButton::clicked, &m_obsClient, &OBSClient::hideSlides);
connect(btnShowSlides, &QPushButton::clicked, &m_obsClient, &OBSClient::showSlides);
connect(btnShowSlides, &QPushButton::clicked, &m_openlpClient, &OpenLPClient::showSlides);
}
void MainWindow::setupCustomViewControls(QVector<View> const&views, QGridLayout *viewCtlLyt) {
constexpr auto columns = 3; constexpr auto columns = 3;
auto const parent = viewCtlLyt->parentWidget(); auto const parent = viewCtlLyt->parentWidget();
for (auto i = 0; auto const&view : views) { for (auto i = 0; auto const&view : views) {
@ -183,22 +203,25 @@ void MainWindow::setupViewControls(QVBoxLayout *rootLyt) {
.obsSlides = false, .obsSlides = false,
}); });
views.emplace_back(View{ views.emplace_back(View{
.name = tr("Show in OpenLP Only"), .name = tr("Hide in OBS"),
.slides = true, .slides = false,
.obsSlides = false, .obsSlides = false,
}); });
views.emplace_back(View{ views.emplace_back(View{
.name = tr("Show"), .name = tr("Show"),
.slides = true, .slides = false,
.obsSlides = true, .obsSlides = false,
}); });
} }
setupViewControlButtons(views, viewCtlLyt); if (views.empty()) {
setupDefaultViewControls(viewCtlLyt);
} else {
setupCustomViewControls(views, viewCtlLyt);
}
} }
void MainWindow::openSettings() { void MainWindow::openSettings() {
SettingsDialog d(this); SettingsDialog d(this);
connect(&d, &SettingsDialog::previewPreset, &m_cameraClient, &CameraClient::setPresetVC);
auto const result = d.exec(); auto const result = d.exec();
if (result == QDialog::Accepted) { if (result == QDialog::Accepted) {
m_cameraClient.setBaseUrl(); m_cameraClient.setBaseUrl();

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2021 - 2024 gary@drinkingtea.net * Copyright 2021 - 2023 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
@ -8,6 +8,8 @@
#pragma once #pragma once
#include <cstdint>
#include <QMainWindow> #include <QMainWindow>
#include "cameraclient.hpp" #include "cameraclient.hpp"
@ -38,7 +40,9 @@ class MainWindow: public QMainWindow {
private: private:
void setupMenu(); void setupMenu();
void setupViewControlButtons(QVector<View> const&views, class QGridLayout *rootLyt); void setupDefaultViewControls(class QGridLayout *rootLyt);
void setupCustomViewControls(QVector<View> const&views, class QGridLayout *rootLyt);
void setupViewControls(class QVBoxLayout *rootLyt); void setupViewControls(class QVBoxLayout *rootLyt);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2021 - 2024 gary@drinkingtea.net * Copyright 2021 - 2023 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
@ -42,7 +42,7 @@ void OBSClient::setSlidesVisible(bool state) {
} }
void OBSClient::setBaseUrl() { void OBSClient::setBaseUrl() {
auto const [host, port] = getOBSConnectionData(); const auto [host, port] = getOBSConnectionData();
m_baseUrl = QString("http://%1:%2").arg(host, QString::number(port)); m_baseUrl = QString("http://%1:%2").arg(host, QString::number(port));
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2021 - 2024 gary@drinkingtea.net * Copyright 2021 - 2023 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this

View File

@ -1,12 +1,11 @@
/* /*
* Copyright 2021 - 2024 gary@drinkingtea.net * Copyright 2021 - 2023 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
#include <QHttpPart>
#include <QJsonArray> #include <QJsonArray>
#include <QJsonDocument> #include <QJsonDocument>
#include <QJsonObject> #include <QJsonObject>
@ -29,8 +28,8 @@ OpenLPClient::OpenLPClient(QObject *parent): QObject(parent) {
} }
QString OpenLPClient::getNextSong() { QString OpenLPClient::getNextSong() {
auto const currentSong = m_songNameMap[m_currentSongId]; const auto currentSong = m_songNameMap[m_currentSongId];
auto const songIdx = m_songList.indexOf(currentSong) + 1; const auto songIdx = m_songList.indexOf(currentSong) + 1;
if (songIdx < m_songList.size()) { if (songIdx < m_songList.size()) {
return m_songList[songIdx]; return m_songList[songIdx];
} }
@ -38,19 +37,19 @@ QString OpenLPClient::getNextSong() {
} }
void OpenLPClient::nextSlide() { void OpenLPClient::nextSlide() {
post("/api/v2/controller/progress", R"({"action":"next"})"); get("/api/controller/live/next");
} }
void OpenLPClient::prevSlide() { void OpenLPClient::prevSlide() {
post("/api/v2/controller/progress", R"({"action":"previous"})"); get("/api/controller/live/previous");
} }
void OpenLPClient::nextSong() { void OpenLPClient::nextSong() {
post("/api/v2/service/progress", R"({"action":"next"})"); get("/api/service/next");
} }
void OpenLPClient::prevSong() { void OpenLPClient::prevSong() {
post("/api/v2/service/progress", R"({"action":"previous"})"); get("/api/service/previous");
} }
void OpenLPClient::blankScreen() { void OpenLPClient::blankScreen() {
@ -82,7 +81,7 @@ void OpenLPClient::changeSlide(int slide) {
} }
void OpenLPClient::setBaseUrl() { void OpenLPClient::setBaseUrl() {
auto const [host, port] = getOpenLPConnectionData(); const auto [host, port] = getOpenLPConnectionData();
m_baseUrl = QString("http://%1:%2").arg(host, QString::number(port)); m_baseUrl = QString("http://%1:%2").arg(host, QString::number(port));
} }
@ -92,12 +91,6 @@ void OpenLPClient::get(QString const&urlExt) {
m_nam->get(rqst); m_nam->get(rqst);
} }
void OpenLPClient::post(QString const&url, QString const&data) {
QNetworkRequest rqst(QUrl(m_baseUrl + url));
rqst.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
m_nam->post(rqst, data.toUtf8());
}
void OpenLPClient::requestSongList() { void OpenLPClient::requestSongList() {
QUrl url(m_baseUrl + "/api/service/list?_=1626628079579"); QUrl url(m_baseUrl + "/api/service/list?_=1626628079579");
QNetworkRequest rqst(url); QNetworkRequest rqst(url);
@ -167,7 +160,7 @@ void OpenLPClient::handleSongListResponse(QNetworkReply *reply) {
auto items = doc.object()["results"].toObject()["items"].toArray(); auto items = doc.object()["results"].toObject()["items"].toArray();
m_songNameMap.clear(); m_songNameMap.clear();
m_songList.clear(); m_songList.clear();
for (auto const &item : items) { for (const auto &item : items) {
auto song = item.toObject(); auto song = item.toObject();
auto name = song["title"].toString(); auto name = song["title"].toString();
auto id = song["id"].toString(); auto id = song["id"].toString();
@ -190,12 +183,12 @@ void OpenLPClient::handleSlideListResponse(QNetworkReply *reply) {
QStringList tagList; QStringList tagList;
auto doc = QJsonDocument::fromJson(data); auto doc = QJsonDocument::fromJson(data);
auto items = doc.object()["results"].toObject()["slides"].toArray(); auto items = doc.object()["results"].toObject()["slides"].toArray();
for (auto const&item : items) { for (const auto &item : items) {
auto const slide = item.toObject(); auto slide = item.toObject();
auto text = slide["text"].toString(); auto text = slide["text"].toString();
auto tag = slide["tag"].toString(); auto tag = slide["tag"].toString();
slideList.push_back(std::move(text)); slideList.push_back(text);
tagList.push_back(std::move(tag)); tagList.push_back(tag);
} }
emit slideListUpdate(tagList, slideList); emit slideListUpdate(tagList, slideList);
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2021 - 2024 gary@drinkingtea.net * Copyright 2021 - 2023 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
@ -60,8 +60,6 @@ class OpenLPClient: public QObject {
private: private:
void get(QString const&url); void get(QString const&url);
void post(QString const&url, QString const&data);
void requestSongList(); void requestSongList();
void requestSlideList(); void requestSlideList();

Binary file not shown.

Before

Width:  |  Height:  |  Size: 159 KiB

View File

@ -1 +0,0 @@
IDI_ICON1 ICON DISCARDABLE "sc9k.ico"

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2021 - 2024 gary@drinkingtea.net * Copyright 2021 - 2023 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
@ -8,54 +8,8 @@
#include <QSettings> #include <QSettings>
#include "consts.hpp"
#include "settingsdata.hpp" #include "settingsdata.hpp"
void setVideoConfig(QSettings &settings, QVector<VideoConfig> const&vcList) {
settings.beginGroup("Camera");
settings.beginWriteArray("VideoImageConfig");
for (auto i = 0; auto const&vc : vcList) {
settings.setArrayIndex(i);
settings.setValue("brightness", vc.brightness);
settings.setValue("saturation", vc.saturation);
settings.setValue("contrast", vc.contrast);
settings.setValue("sharpness", vc.sharpness);
settings.setValue("hue", vc.hue);
++i;
}
settings.endArray();
settings.endGroup();
}
void setVideoConfig(QVector<VideoConfig> const&vcList) {
QSettings s;
setVideoConfig(s, vcList);
}
QVector<VideoConfig> getVideoConfig(QSettings &settings) {
QVector<VideoConfig> vc(MaxCameraPresets);
settings.beginGroup("Camera");
auto const size = std::min(settings.beginReadArray("VideoImageConfig"), MaxCameraPresets);
for (auto i = 0; i < size; ++i) {
settings.setArrayIndex(i);
vc[i] = {
.brightness = settings.value("brightness").toInt(),
.saturation = settings.value("saturation").toInt(),
.contrast = settings.value("contrast").toInt(),
.sharpness = settings.value("sharpness").toInt(),
.hue = settings.value("hue").toInt(),
};
}
settings.endArray();
settings.endGroup();
return vc;
}
QVector<VideoConfig> getVideoConfig() {
QSettings s;
return getVideoConfig(s);
}
void setCameraConnectionData(QSettings &settings, ConnectionData const&cd) { void setCameraConnectionData(QSettings &settings, ConnectionData const&cd) {
settings.beginGroup("CameraClient"); settings.beginGroup("CameraClient");
settings.setValue("Host", cd.host); settings.setValue("Host", cd.host);
@ -167,7 +121,7 @@ void setViews(QVector<View> const&views) {
QVector<View> getViews(QSettings &settings) { QVector<View> getViews(QSettings &settings) {
QVector<View> out; QVector<View> out;
settings.beginGroup("Views"); settings.beginGroup("Views");
auto const size = settings.beginReadArray("Views"); const auto size = settings.beginReadArray("Views");
for (auto i = 0; i < size; ++i) { for (auto i = 0; i < size; ++i) {
settings.setArrayIndex(i); settings.setArrayIndex(i);
out.emplace_back(View{ out.emplace_back(View{

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2021 - 2024 gary@drinkingtea.net * Copyright 2021 - 2023 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
@ -8,26 +8,9 @@
#pragma once #pragma once
#include <cstdint>
#include <QString> #include <QString>
#include <QVector> #include <QVector>
struct VideoConfig {
int brightness = 6;
int saturation = 4;
int contrast = 8;
int sharpness = 3;
int hue = 7;
};
void setVideoConfig(class QSettings &settings, QVector<VideoConfig> const&vc);
void setVideoConfig(QVector<VideoConfig> const&vc);
QVector<VideoConfig> getVideoConfig(class QSettings &settings);
QVector<VideoConfig> getVideoConfig();
struct ConnectionData { struct ConnectionData {
QString host; QString host;
uint16_t port = 0; uint16_t port = 0;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2021 - 2024 gary@drinkingtea.net * Copyright 2021 - 2023 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
@ -7,7 +7,6 @@
*/ */
#include <QCheckBox> #include <QCheckBox>
#include <QComboBox>
#include <QFormLayout> #include <QFormLayout>
#include <QHeaderView> #include <QHeaderView>
#include <QIntValidator> #include <QIntValidator>
@ -16,7 +15,6 @@
#include <QPushButton> #include <QPushButton>
#include <QSettings> #include <QSettings>
#include <QSpacerItem> #include <QSpacerItem>
#include <QSpinBox>
#include <QTabWidget> #include <QTabWidget>
#include <QTableWidget> #include <QTableWidget>
#include <QVBoxLayout> #include <QVBoxLayout>
@ -33,35 +31,34 @@ enum ViewColumn {
}; };
SettingsDialog::SettingsDialog(QWidget *parent): QDialog(parent) { SettingsDialog::SettingsDialog(QWidget *parent): QDialog(parent) {
auto const lyt = new QVBoxLayout(this); const auto lyt = new QVBoxLayout(this);
auto const tabs = new QTabWidget(this); const auto tabs = new QTabWidget(this);
lyt->addWidget(tabs); lyt->addWidget(tabs);
tabs->addTab(setupViewConfig(tabs), tr("&Views")); tabs->addTab(setupViewConfig(tabs), tr("&Views"));
tabs->addTab(setupImageConfig(tabs), tr("&Image"));
tabs->addTab(setupNetworkInputs(tabs), tr("&Network")); tabs->addTab(setupNetworkInputs(tabs), tr("&Network"));
lyt->addWidget(setupButtons(this)); lyt->addWidget(setupButtons(this));
setFixedSize(440, 440); setFixedSize(440, 440);
} }
QWidget *SettingsDialog::setupNetworkInputs(QWidget *parent) { QWidget *SettingsDialog::setupNetworkInputs(QWidget *parent) {
auto const root = new QWidget(parent); const auto root = new QWidget(parent);
auto const lyt = new QFormLayout(root); const auto lyt = new QFormLayout(root);
auto const portValidator = new QIntValidator(1, 65536, this); const auto portValidator = new QIntValidator(1, 65536, this);
QSettings settings; QSettings settings;
// camera settings // camera settings
{ {
auto const c = getCameraConnectionData(settings); const auto c = getCameraConnectionData(settings);
m_cameraHostLe = new QLineEdit(root); m_cameraHostLe = new QLineEdit(root);
m_cameraPortLe = new QLineEdit(root); m_cameraPortLe = new QLineEdit(root);
m_cameraHostLe->setText(c.host); m_cameraHostLe->setText(c.host);
m_cameraPortLe->setText(QString::number(c.port)); m_cameraPortLe->setText(QString::number(c.port));
m_cameraPortLe->setValidator(portValidator); m_cameraPortLe->setValidator(portValidator);
lyt->addRow(tr("Camera &Host:"), m_cameraHostLe); lyt->addRow(tr("C&amera Host:"), m_cameraHostLe);
lyt->addRow(tr("Ca&mera Port:"), m_cameraPortLe); lyt->addRow(tr("Ca&mera Port:"), m_cameraPortLe);
} }
// OpenLP settings // OpenLP settings
{ {
auto const c = getOpenLPConnectionData(settings); const auto c = getOpenLPConnectionData(settings);
m_openLpHostLe = new QLineEdit(root); m_openLpHostLe = new QLineEdit(root);
m_openLpPortLe = new QLineEdit(root); m_openLpPortLe = new QLineEdit(root);
m_openLpHostLe->setText(c.host); m_openLpHostLe->setText(c.host);
@ -72,7 +69,7 @@ QWidget *SettingsDialog::setupNetworkInputs(QWidget *parent) {
} }
// OBS settings // OBS settings
{ {
auto const c = getOBSConnectionData(settings); const auto c = getOBSConnectionData(settings);
m_obsHostLe = new QLineEdit(root); m_obsHostLe = new QLineEdit(root);
m_obsPortLe = new QLineEdit(root); m_obsPortLe = new QLineEdit(root);
m_obsHostLe->setText(c.host); m_obsHostLe->setText(c.host);
@ -84,58 +81,13 @@ QWidget *SettingsDialog::setupNetworkInputs(QWidget *parent) {
return root; return root;
} }
QWidget *SettingsDialog::setupImageConfig(QWidget *parent) {
auto const root = new QWidget(parent);
auto const lyt = new QVBoxLayout(root);
{
auto const formRoot = new QWidget(parent);
auto const formLyt = new QFormLayout(formRoot);
lyt->addWidget(formRoot);
m_videoConfig = getVideoConfig();
auto const mkSb = [parent, formLyt](QString const&lbl) {
auto const s = new QSpinBox(parent);
s->setAlignment(Qt::AlignRight);
s->setRange(0, 14);
formLyt->addRow(lbl, s);
return s;
};
auto const presetNo = new QComboBox(parent);
connect(presetNo, &QComboBox::currentIndexChanged, this, &SettingsDialog::updateVidConfigPreset);
for (auto i = 0; i < MaxCameraPresets; ++i) {
presetNo->addItem(tr("Camera Preset %1").arg(i + 1));
}
formLyt->addRow(presetNo);
m_vidBrightness = mkSb(tr("&Brightness:"));
m_vidSaturation = mkSb(tr("&Saturation:"));
m_vidContrast = mkSb(tr("Con&trast:"));
m_vidSharpness = mkSb(tr("Sharpn&ess:"));
m_vidHue = mkSb(tr("&Hue:"));
updateVidConfigPreset(0);
}
{
auto const btnRoot = new QWidget(parent);
auto const btnLyt = new QHBoxLayout(btnRoot);
lyt->addWidget(btnRoot);
btnLyt->setAlignment(Qt::AlignRight);
auto const previewBtn = new QPushButton(tr("&Preview"), btnRoot);
btnLyt->addWidget(previewBtn);
connect(previewBtn, &QPushButton::clicked, this, [this] {
this->collectVideoConfig();
auto const &vc = m_videoConfig[m_vidCurrentPreset];
emit previewPreset(m_vidCurrentPreset + 1, vc);
});
}
return root;
}
QWidget *SettingsDialog::setupViewConfig(QWidget *parent) { QWidget *SettingsDialog::setupViewConfig(QWidget *parent) {
auto const root = new QWidget(parent); auto const root = new QWidget(parent);
auto const lyt = new QVBoxLayout(root); auto const lyt = new QVBoxLayout(root);
auto const btnsRoot = new QWidget(root); // table
m_viewTable = new QTableWidget(root); m_viewTable = new QTableWidget(parent);
lyt->addWidget(btnsRoot); {
lyt->addWidget(m_viewTable); lyt->addWidget(m_viewTable);
{ // table
QStringList columns; QStringList columns;
columns.resize(ViewColumn::Count); columns.resize(ViewColumn::Count);
columns[ViewColumn::Name] = tr("Name"); columns[ViewColumn::Name] = tr("Name");
@ -152,16 +104,19 @@ QWidget *SettingsDialog::setupViewConfig(QWidget *parent) {
m_viewTable->setColumnWidth(3, 70); m_viewTable->setColumnWidth(3, 70);
hdr->setStretchLastSection(true); hdr->setStretchLastSection(true);
} }
{ // add/removes buttons // add/removes buttons
{
auto const btnsRoot = new QWidget(root);
auto const btnsLyt = new QHBoxLayout(btnsRoot); auto const btnsLyt = new QHBoxLayout(btnsRoot);
auto const addBtn = new QPushButton("A&dd", btnsRoot); auto const addBtn = new QPushButton("+", btnsRoot);
auto const rmBtn = new QPushButton("&Remove", btnsRoot); auto const rmBtn = new QPushButton("-", btnsRoot);
addBtn->setFixedWidth(70); addBtn->setFixedWidth(20);
rmBtn->setFixedWidth(70); rmBtn->setFixedWidth(20);
rmBtn->setDisabled(true); rmBtn->setDisabled(true);
lyt->addWidget(btnsRoot);
btnsLyt->addWidget(addBtn); btnsLyt->addWidget(addBtn);
btnsLyt->addWidget(rmBtn); btnsLyt->addWidget(rmBtn);
btnsLyt->setAlignment(Qt::AlignLeft); btnsLyt->addSpacerItem(new QSpacerItem(1000, 0, QSizePolicy::Expanding, QSizePolicy::Ignored));
connect(addBtn, &QPushButton::clicked, this, [this, addBtn] { connect(addBtn, &QPushButton::clicked, this, [this, addBtn] {
auto const row = m_viewTable->rowCount(); auto const row = m_viewTable->rowCount();
m_viewTable->setRowCount(row + 1); m_viewTable->setRowCount(row + 1);
@ -177,7 +132,7 @@ QWidget *SettingsDialog::setupViewConfig(QWidget *parent) {
rmBtn->setEnabled(row > -1 && row < m_viewTable->rowCount()); rmBtn->setEnabled(row > -1 && row < m_viewTable->rowCount());
addBtn->setEnabled(m_viewTable->rowCount() < MaxViews); addBtn->setEnabled(m_viewTable->rowCount() < MaxViews);
}); });
auto const views = getViews(); const auto views = getViews();
m_viewTable->setRowCount(static_cast<int>(views.size())); m_viewTable->setRowCount(static_cast<int>(views.size()));
for (auto row = 0; auto const&view : views) { for (auto row = 0; auto const&view : views) {
setupViewRow(row, view); setupViewRow(row, view);
@ -188,29 +143,26 @@ QWidget *SettingsDialog::setupViewConfig(QWidget *parent) {
} }
QWidget *SettingsDialog::setupButtons(QWidget *parent) { QWidget *SettingsDialog::setupButtons(QWidget *parent) {
auto const root = new QWidget(parent); const auto root = new QWidget(parent);
auto const lyt = new QHBoxLayout(root); const auto lyt = new QHBoxLayout(root);
m_errLbl = new QLabel(root); m_errLbl = new QLabel(root);
auto const okBtn = new QPushButton(tr("&OK"), root); const auto okBtn = new QPushButton(tr("&OK"), root);
auto const applyBtn = new QPushButton(tr("&Apply"), root); const auto cancelBtn = new QPushButton(tr("&Cancel"), root);
auto const cancelBtn = new QPushButton(tr("&Cancel"), root);
lyt->addWidget(m_errLbl); lyt->addWidget(m_errLbl);
lyt->addSpacerItem(new QSpacerItem(1000, 0, QSizePolicy::Expanding, QSizePolicy::Ignored)); lyt->addSpacerItem(new QSpacerItem(1000, 0, QSizePolicy::Expanding, QSizePolicy::Ignored));
lyt->addWidget(okBtn); lyt->addWidget(okBtn);
lyt->addWidget(applyBtn);
lyt->addWidget(cancelBtn); lyt->addWidget(cancelBtn);
connect(okBtn, &QPushButton::clicked, this, &SettingsDialog::handleOK); connect(okBtn, &QPushButton::clicked, this, &SettingsDialog::handleOK);
connect(applyBtn, &QPushButton::clicked, this, &SettingsDialog::handleApply);
connect(cancelBtn, &QPushButton::clicked, this, &SettingsDialog::reject); connect(cancelBtn, &QPushButton::clicked, this, &SettingsDialog::reject);
return root; return root;
} }
int SettingsDialog::handleApply() { void SettingsDialog::handleOK() {
QSettings settings; QSettings settings;
QVector<View> views; QVector<View> views;
auto const viewsErr = collectViews(views); auto const viewsErr = collectViews(views);
if (viewsErr) { if (viewsErr) {
return -1; return;
} }
setViews(settings, views); setViews(settings, views);
setCameraConnectionData(settings, { setCameraConnectionData(settings, {
@ -225,31 +177,23 @@ int SettingsDialog::handleApply() {
.host = m_obsHostLe->text(), .host = m_obsHostLe->text(),
.port = m_obsPortLe->text().toUShort(), .port = m_obsPortLe->text().toUShort(),
}); });
collectVideoConfig();
setVideoConfig(settings, m_videoConfig);
return 0;
}
void SettingsDialog::handleOK() {
if (handleApply() == 0) {
accept(); accept();
}
} }
void SettingsDialog::setupViewRow(int row, View const&view) { void SettingsDialog::setupViewRow(int row, View const&view) {
// name // name
auto const nameItem = new QTableWidgetItem(view.name); const auto nameItem = new QTableWidgetItem(view.name);
m_viewTable->setItem(row, ViewColumn::Name, nameItem); m_viewTable->setItem(row, ViewColumn::Name, nameItem);
// slides // slides
auto const slidesCb = new QCheckBox(m_viewTable); const auto slidesCb = new QCheckBox(m_viewTable);
slidesCb->setChecked(view.slides); slidesCb->setChecked(view.slides);
m_viewTable->setCellWidget(row, ViewColumn::Slides, slidesCb); m_viewTable->setCellWidget(row, ViewColumn::Slides, slidesCb);
// obs slides // obs slides
auto const obsSlidesCb = new QCheckBox(m_viewTable); const auto obsSlidesCb = new QCheckBox(m_viewTable);
obsSlidesCb->setChecked(view.obsSlides); obsSlidesCb->setChecked(view.obsSlides);
m_viewTable->setCellWidget(row, ViewColumn::ObsSlides, obsSlidesCb); m_viewTable->setCellWidget(row, ViewColumn::ObsSlides, obsSlidesCb);
// camera preset // camera preset
auto const presetItem = new QTableWidgetItem(QString::number(view.cameraPreset)); const auto presetItem = new QTableWidgetItem(QString::number(view.cameraPreset));
m_viewTable->setItem(row, ViewColumn::CameraPreset, presetItem); m_viewTable->setItem(row, ViewColumn::CameraPreset, presetItem);
} }
@ -262,7 +206,7 @@ int SettingsDialog::collectViews(QVector<View> &views) const {
m_errLbl->setText(tr("View %1 has no name.").arg(viewNo)); m_errLbl->setText(tr("View %1 has no name.").arg(viewNo));
return 1; return 1;
} }
auto const cameraPreset = m_viewTable->item(row, ViewColumn::CameraPreset)->text().toInt(&ok); const auto cameraPreset = m_viewTable->item(row, ViewColumn::CameraPreset)->text().toInt(&ok);
if (!ok || cameraPreset < 1 || cameraPreset > MaxCameraPresets) { if (!ok || cameraPreset < 1 || cameraPreset > MaxCameraPresets) {
m_errLbl->setText(tr("View %1 has invalid preset (1-%2)").arg(viewNo).arg(MaxCameraPresets)); m_errLbl->setText(tr("View %1 has invalid preset (1-%2)").arg(viewNo).arg(MaxCameraPresets));
return 2; return 2;
@ -276,38 +220,3 @@ int SettingsDialog::collectViews(QVector<View> &views) const {
} }
return 0; return 0;
} }
void SettingsDialog::collectVideoConfig() {
auto &vc = m_videoConfig[m_vidCurrentPreset];
auto constexpr getVal = [](int &val, QSpinBox *src) {
if (src) {
val = src->value();
}
};
getVal(vc.brightness, m_vidBrightness);
getVal(vc.saturation, m_vidSaturation);
getVal(vc.contrast, m_vidContrast);
getVal(vc.sharpness, m_vidSharpness);
getVal(vc.hue, m_vidHue);
}
void SettingsDialog::updateVidConfigPreset(int preset) {
// update to new value
auto constexpr setVal = [](int val, QSpinBox *dst) {
if (dst) {
dst->setValue(val);
}
};
auto const&vc = m_videoConfig[preset];
setVal(vc.brightness, m_vidBrightness);
setVal(vc.saturation, m_vidSaturation);
setVal(vc.contrast, m_vidContrast);
setVal(vc.sharpness, m_vidSharpness);
setVal(vc.hue, m_vidHue);
m_vidCurrentPreset = preset;
}
void SettingsDialog::updateVidConfigPresetCollect(int preset) {
collectVideoConfig();
updateVidConfigPreset(preset);
}

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2021 - 2024 gary@drinkingtea.net * Copyright 2021 - 2023 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
@ -10,13 +10,11 @@
#include <QDialog> #include <QDialog>
#include "consts.hpp"
#include "settingsdata.hpp" #include "settingsdata.hpp"
class SettingsDialog: public QDialog { class SettingsDialog: public QDialog {
Q_OBJECT Q_OBJECT
private: private:
QVector<VideoConfig> m_videoConfig = QVector<VideoConfig>(MaxCameraPresets);
class QLabel *m_errLbl = nullptr; class QLabel *m_errLbl = nullptr;
class QLineEdit *m_cameraHostLe = nullptr; class QLineEdit *m_cameraHostLe = nullptr;
class QLineEdit *m_cameraPortLe = nullptr; class QLineEdit *m_cameraPortLe = nullptr;
@ -24,22 +22,13 @@ class SettingsDialog: public QDialog {
class QLineEdit *m_openLpPortLe = nullptr; class QLineEdit *m_openLpPortLe = nullptr;
class QLineEdit *m_obsHostLe = nullptr; class QLineEdit *m_obsHostLe = nullptr;
class QLineEdit *m_obsPortLe = nullptr; class QLineEdit *m_obsPortLe = nullptr;
class QSpinBox *m_vidBrightness = nullptr;
class QSpinBox *m_vidSaturation = nullptr;
class QSpinBox *m_vidContrast = nullptr;
class QSpinBox *m_vidSharpness = nullptr;
class QSpinBox *m_vidHue = nullptr;
int m_vidCurrentPreset = 0;
class QTableWidget *m_viewTable = nullptr; class QTableWidget *m_viewTable = nullptr;
public: public:
explicit SettingsDialog(QWidget *parent); explicit SettingsDialog(QWidget *parent);
private: private:
QWidget *setupNetworkInputs(QWidget *parent); QWidget *setupNetworkInputs(QWidget *parent);
QWidget *setupViewConfig(QWidget *parent); QWidget *setupViewConfig(QWidget *parent);
QWidget *setupImageConfig(QWidget *parent);
QWidget *setupButtons(QWidget *parent); QWidget *setupButtons(QWidget *parent);
[[nodiscard]]
int handleApply();
void handleOK(); void handleOK();
void setupViewRow(int row, View const&view = {}); void setupViewRow(int row, View const&view = {});
/** /**
@ -48,9 +37,4 @@ class SettingsDialog: public QDialog {
*/ */
[[nodiscard("Must check error code")]] [[nodiscard("Must check error code")]]
int collectViews(QVector<View> &views) const; int collectViews(QVector<View> &views) const;
void collectVideoConfig();
void updateVidConfigPreset(int preset);
void updateVidConfigPresetCollect(int preset);
signals:
void previewPreset(int, VideoConfig const&);
}; };

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2021 - 2024 gary@drinkingtea.net * Copyright 2021 - 2023 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
@ -34,8 +34,8 @@ SlideView::SlideView(QWidget *parent): QWidget(parent) {
} }
QString SlideView::getNextSong() const { QString SlideView::getNextSong() const {
auto const cnt = m_songSelector->count(); const auto cnt = m_songSelector->count();
auto const idx = m_songSelector->currentRow() + 1; const auto idx = m_songSelector->currentRow() + 1;
if (idx < cnt) { if (idx < cnt) {
return m_songSelector->currentItem()->text(); return m_songSelector->currentItem()->text();
} }
@ -43,7 +43,7 @@ QString SlideView::getNextSong() const {
} }
void SlideView::pollUpdate(QString const&songName, int slide) { void SlideView::pollUpdate(QString const&songName, int slide) {
auto const songItems = m_songSelector->findItems(songName, Qt::MatchFixedString); auto songItems = m_songSelector->findItems(songName, Qt::MatchFixedString);
if (songItems.empty()) { if (songItems.empty()) {
return; return;
} }
@ -68,14 +68,11 @@ void SlideView::changeSong(int song) {
} }
} }
void SlideView::slideListUpdate(QStringList tagList, QStringList const&slideList) { void SlideView::slideListUpdate(QStringList const&tagList, QStringList const&slideList) {
for (auto &tag : tagList) {
tag = tag.split("").join("\n");
}
m_currentSlide = 0; m_currentSlide = 0;
m_slideTable->setRowCount(static_cast<int>(slideList.size())); m_slideTable->setRowCount(static_cast<int>(slideList.size()));
for (int i = 0; i < slideList.size(); ++i) { for (int i = 0; i < slideList.size(); ++i) {
auto const& txt = slideList[i]; const auto& txt = slideList[i];
auto item = new QTableWidgetItem(txt); auto item = new QTableWidgetItem(txt);
item->setFlags(item->flags() & ~Qt::ItemIsEditable); item->setFlags(item->flags() & ~Qt::ItemIsEditable);
m_slideTable->setItem(i, 0, item); m_slideTable->setItem(i, 0, item);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2021 - 2024 gary@drinkingtea.net * Copyright 2021 - 2023 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
@ -28,7 +28,7 @@ class SlideView: public QWidget {
void songListUpdate(QStringList const&songList); void songListUpdate(QStringList const&songList);
void slideListUpdate(QStringList tagList, QStringList const&songList); void slideListUpdate(QStringList const&tagList, QStringList const&songList);
void reset(); void reset();