mirror of
https://github.com/OpenMW/openmw.git
synced 2025-04-18 03:06:45 +00:00
Merge branch 'master' into menuscripts
This commit is contained in:
commit
d1268acf95
702 changed files with 10885 additions and 6094 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -28,6 +28,7 @@ Doxygen
|
||||||
.idea
|
.idea
|
||||||
cmake-build-*
|
cmake-build-*
|
||||||
files/windows/*.aps
|
files/windows/*.aps
|
||||||
|
.cache/clangd
|
||||||
## qt-creator
|
## qt-creator
|
||||||
CMakeLists.txt.user*
|
CMakeLists.txt.user*
|
||||||
.vs
|
.vs
|
||||||
|
|
|
@ -142,7 +142,7 @@ Ubuntu_GCC:
|
||||||
variables:
|
variables:
|
||||||
CC: gcc
|
CC: gcc
|
||||||
CXX: g++
|
CXX: g++
|
||||||
CCACHE_SIZE: 4G
|
CCACHE_SIZE: 3G
|
||||||
# When CCache doesn't exist (e.g. first build on a fork), build takes more than 1h, which is the default for forks.
|
# When CCache doesn't exist (e.g. first build on a fork), build takes more than 1h, which is the default for forks.
|
||||||
timeout: 2h
|
timeout: 2h
|
||||||
|
|
||||||
|
@ -193,7 +193,7 @@ Ubuntu_GCC_Debug:
|
||||||
variables:
|
variables:
|
||||||
CC: gcc
|
CC: gcc
|
||||||
CXX: g++
|
CXX: g++
|
||||||
CCACHE_SIZE: 4G
|
CCACHE_SIZE: 3G
|
||||||
CMAKE_BUILD_TYPE: Debug
|
CMAKE_BUILD_TYPE: Debug
|
||||||
CMAKE_CXX_FLAGS_DEBUG: -O0
|
CMAKE_CXX_FLAGS_DEBUG: -O0
|
||||||
# When CCache doesn't exist (e.g. first build on a fork), build takes more than 1h, which is the default for forks.
|
# When CCache doesn't exist (e.g. first build on a fork), build takes more than 1h, which is the default for forks.
|
||||||
|
|
46
CHANGELOG.md
46
CHANGELOG.md
|
@ -8,10 +8,17 @@
|
||||||
Bug #4204: Dead slaughterfish doesn't float to water surface after loading saved game
|
Bug #4204: Dead slaughterfish doesn't float to water surface after loading saved game
|
||||||
Bug #4207: RestoreHealth/Fatigue spells have a huge priority even if a success chance is near 0
|
Bug #4207: RestoreHealth/Fatigue spells have a huge priority even if a success chance is near 0
|
||||||
Bug #4382: Sound output device does not change when it should
|
Bug #4382: Sound output device does not change when it should
|
||||||
|
Bug #4508: Can't stack enchantment buffs from different instances of the same self-cast generic magic apparel
|
||||||
Bug #4610: Casting a Bound Weapon spell cancels the casting animation by equipping the weapon prematurely
|
Bug #4610: Casting a Bound Weapon spell cancels the casting animation by equipping the weapon prematurely
|
||||||
|
Bug #4683: Disposition decrease when player commits crime is not implemented properly
|
||||||
|
Bug #4742: Actors with wander never stop walking after Loopgroup Walkforward
|
||||||
|
Bug #4743: PlayGroup doesn't play non-looping animations correctly
|
||||||
Bug #4754: Stack of ammunition cannot be equipped partially
|
Bug #4754: Stack of ammunition cannot be equipped partially
|
||||||
Bug #4816: GetWeaponDrawn returns 1 before weapon is attached
|
Bug #4816: GetWeaponDrawn returns 1 before weapon is attached
|
||||||
|
Bug #4822: Non-weapon equipment and body parts can't inherit time from parent animation
|
||||||
Bug #5057: Weapon swing sound plays at same pitch whether it hits or misses
|
Bug #5057: Weapon swing sound plays at same pitch whether it hits or misses
|
||||||
|
Bug #5062: Root bone rotations for NPC animation don't work the same as for creature animation
|
||||||
|
Bug #5066: Quirks with starting and stopping scripted animations
|
||||||
Bug #5129: Stuttering animation on Centurion Archer
|
Bug #5129: Stuttering animation on Centurion Archer
|
||||||
Bug #5280: Unskinned shapes in skinned equipment are rendered in the wrong place
|
Bug #5280: Unskinned shapes in skinned equipment are rendered in the wrong place
|
||||||
Bug #5371: Keyframe animation tracks are used for any file that begins with an X
|
Bug #5371: Keyframe animation tracks are used for any file that begins with an X
|
||||||
|
@ -22,6 +29,7 @@
|
||||||
Bug #5977: Fatigueless NPCs' corpse underwater changes animation on game load
|
Bug #5977: Fatigueless NPCs' corpse underwater changes animation on game load
|
||||||
Bug #6025: Subrecords cannot overlap records
|
Bug #6025: Subrecords cannot overlap records
|
||||||
Bug #6027: Collisionshape becomes spiderweb-like when the mesh is too complex
|
Bug #6027: Collisionshape becomes spiderweb-like when the mesh is too complex
|
||||||
|
Bug #6190: Unintuitive sun specularity time of day dependence
|
||||||
Bug #6222: global map cell size can crash openmw if set to too high a value
|
Bug #6222: global map cell size can crash openmw if set to too high a value
|
||||||
Bug #6313: Followers with high Fight can turn hostile
|
Bug #6313: Followers with high Fight can turn hostile
|
||||||
Bug #6427: Enemy health bar disappears before damaging effect ends
|
Bug #6427: Enemy health bar disappears before damaging effect ends
|
||||||
|
@ -30,6 +38,8 @@
|
||||||
Bug #6657: Distant terrain tiles become black when using FWIW mod
|
Bug #6657: Distant terrain tiles become black when using FWIW mod
|
||||||
Bug #6661: Saved games that have no preview screenshot cause issues or crashes
|
Bug #6661: Saved games that have no preview screenshot cause issues or crashes
|
||||||
Bug #6716: mwscript comparison operator handling is too restrictive
|
Bug #6716: mwscript comparison operator handling is too restrictive
|
||||||
|
Bug #6754: Beast to Non-beast transformation mod is not working on OpenMW
|
||||||
|
Bug #6758: Main menu background video can be stopped by opening the options menu
|
||||||
Bug #6807: Ultimate Galleon is not working properly
|
Bug #6807: Ultimate Galleon is not working properly
|
||||||
Bug #6893: Lua: Inconsistent behavior with actors affected by Disable and SetDelete commands
|
Bug #6893: Lua: Inconsistent behavior with actors affected by Disable and SetDelete commands
|
||||||
Bug #6894: Added item combines with equipped stack instead of creating a new unequipped stack
|
Bug #6894: Added item combines with equipped stack instead of creating a new unequipped stack
|
||||||
|
@ -63,32 +73,63 @@
|
||||||
Bug #7229: Error marker loading failure is not handled
|
Bug #7229: Error marker loading failure is not handled
|
||||||
Bug #7243: Supporting loading external files from VFS from esm files
|
Bug #7243: Supporting loading external files from VFS from esm files
|
||||||
Bug #7284: "Your weapon has no effect." message doesn't always show when the player character attempts to attack
|
Bug #7284: "Your weapon has no effect." message doesn't always show when the player character attempts to attack
|
||||||
|
Bug #7292: Weather settings for disabling or enabling snow and rain ripples don't work
|
||||||
Bug #7298: Water ripples from projectiles sometimes are not spawned
|
Bug #7298: Water ripples from projectiles sometimes are not spawned
|
||||||
Bug #7307: Alchemy "Magic Effect" search string does not match on tool tip for effects related to attributes
|
Bug #7307: Alchemy "Magic Effect" search string does not match on tool tip for effects related to attributes
|
||||||
|
Bug #7309: Sunlight scattering is visible in inappropriate situations
|
||||||
Bug #7322: Shadows don't cover groundcover depending on the view angle and perspective with compute scene bounds = primitives
|
Bug #7322: Shadows don't cover groundcover depending on the view angle and perspective with compute scene bounds = primitives
|
||||||
|
Bug #7354: Disabling post processing in-game causes a crash
|
||||||
|
Bug #7364: Post processing is not reflected in savegame previews
|
||||||
|
Bug #7380: NiZBufferProperty issue
|
||||||
Bug #7413: Generated wilderness cells don't spawn fish
|
Bug #7413: Generated wilderness cells don't spawn fish
|
||||||
Bug #7415: Unbreakable lock discrepancies
|
Bug #7415: Unbreakable lock discrepancies
|
||||||
|
Bug #7416: Modpccrimelevel is different from vanilla
|
||||||
Bug #7428: AutoCalc flag is not used to calculate enchantment costs
|
Bug #7428: AutoCalc flag is not used to calculate enchantment costs
|
||||||
Bug #7450: Evading obstacles does not work for actors missing certain animations
|
Bug #7450: Evading obstacles does not work for actors missing certain animations
|
||||||
Bug #7459: Icons get stacked on the cursor when picking up multiple items simultaneously
|
Bug #7459: Icons get stacked on the cursor when picking up multiple items simultaneously
|
||||||
Bug #7472: Crash when enchanting last projectiles
|
Bug #7472: Crash when enchanting last projectiles
|
||||||
|
Bug #7475: Equipping a constant effect item doesn't update the magic menu
|
||||||
Bug #7502: Data directories dialog (0.48.0) forces adding subdirectory instead of intended directory
|
Bug #7502: Data directories dialog (0.48.0) forces adding subdirectory instead of intended directory
|
||||||
Bug #7505: Distant terrain does not support sample size greater than cell size
|
Bug #7505: Distant terrain does not support sample size greater than cell size
|
||||||
Bug #7553: Faction reaction loading is incorrect
|
Bug #7553: Faction reaction loading is incorrect
|
||||||
Bug #7557: Terrain::ChunkManager::createChunk is called twice for the same position, lod on initial loading
|
Bug #7557: Terrain::ChunkManager::createChunk is called twice for the same position, lod on initial loading
|
||||||
Bug #7573: Drain Fatigue can't bring fatigue below zero by default
|
Bug #7573: Drain Fatigue can't bring fatigue below zero by default
|
||||||
|
Bug #7585: Difference in interior lighting between OpenMW with legacy lighting method enabled and vanilla Morrowind
|
||||||
Bug #7603: Scripts menu size is not updated properly
|
Bug #7603: Scripts menu size is not updated properly
|
||||||
Bug #7604: Goblins Grunt becomes idle once injured
|
Bug #7604: Goblins Grunt becomes idle once injured
|
||||||
Bug #7609: ForceGreeting should not open dialogue for werewolves
|
Bug #7609: ForceGreeting should not open dialogue for werewolves
|
||||||
Bug #7611: Beast races' idle animations slide after turning or jumping in place
|
Bug #7611: Beast races' idle animations slide after turning or jumping in place
|
||||||
|
Bug #7619: Long map notes may get cut off
|
||||||
Bug #7630: Charm can be cast on creatures
|
Bug #7630: Charm can be cast on creatures
|
||||||
Bug #7631: Cannot trade with/talk to Creeper or Mudcrab Merchant when they're fleeing
|
Bug #7631: Cannot trade with/talk to Creeper or Mudcrab Merchant when they're fleeing
|
||||||
|
Bug #7636: Animations bug out when switching between 1st and 3rd person, while playing a scripted animation
|
||||||
|
Bug #7637: Actors can sometimes move while playing scripted animations
|
||||||
Bug #7639: NPCs don't use hand-to-hand if their other melee skills were damaged during combat
|
Bug #7639: NPCs don't use hand-to-hand if their other melee skills were damaged during combat
|
||||||
|
Bug #7641: loopgroup loops the animation one time too many for actors
|
||||||
|
Bug #7642: Items in repair and recharge menus aren't sorted alphabetically
|
||||||
|
Bug #7643: Can't enchant items with constant effect on self magic effects for non-player character
|
||||||
|
Bug #7646: Follower voices pain sounds when attacked with magic
|
||||||
Bug #7647: NPC walk cycle bugs after greeting player
|
Bug #7647: NPC walk cycle bugs after greeting player
|
||||||
|
Bug #7654: Tooltips for enchantments with invalid effects cause crashes
|
||||||
|
Bug #7660: Some inconsistencies regarding Invisibility breaking
|
||||||
|
Bug #7661: Player followers should stop attacking newly recruited actors
|
||||||
|
Bug #7665: Alchemy menu is missing the ability to deselect and choose different qualities of an apparatus
|
||||||
|
Bug #7675: Successful lock spell doesn't produce a sound
|
||||||
|
Bug #7676: Incorrect magic effect order in alchemy
|
||||||
|
Bug #7679: Scene luminance value flashes when toggling shaders
|
||||||
|
Bug #7685: Corky sometimes doesn't follow Llovyn Andus
|
||||||
|
Bug #7712: Casting doesn't support spells and enchantments with no effects
|
||||||
|
Bug #7723: Assaulting vampires and werewolves shouldn't be a crime
|
||||||
|
Bug #7724: Guards don't help vs werewolves
|
||||||
|
Bug #7742: Governing attribute training limit should use the modified attribute
|
||||||
|
Bug #7758: Water walking is not taken into account to compute path cost on the water
|
||||||
|
Feature #2566: Handle NAM9 records for manual cell references
|
||||||
Feature #3537: Shader-based water ripples
|
Feature #3537: Shader-based water ripples
|
||||||
|
Feature #5173: Support for NiFogProperty
|
||||||
Feature #5492: Let rain and snow collide with statics
|
Feature #5492: Let rain and snow collide with statics
|
||||||
Feature #6149: Dehardcode Lua API_REVISION
|
Feature #6149: Dehardcode Lua API_REVISION
|
||||||
Feature #6152: Playing music via lua scripts
|
Feature #6152: Playing music via lua scripts
|
||||||
|
Feature #6188: Specular lighting from point light sources
|
||||||
Feature #6447: Add LOD support to Object Paging
|
Feature #6447: Add LOD support to Object Paging
|
||||||
Feature #6491: Add support for Qt6
|
Feature #6491: Add support for Qt6
|
||||||
Feature #6556: Lua API for sounds
|
Feature #6556: Lua API for sounds
|
||||||
|
@ -113,12 +154,17 @@
|
||||||
Feature #7477: NegativeLight Magic Effect flag
|
Feature #7477: NegativeLight Magic Effect flag
|
||||||
Feature #7499: OpenMW-CS: Generate record filters by drag & dropping cell content to the filters field
|
Feature #7499: OpenMW-CS: Generate record filters by drag & dropping cell content to the filters field
|
||||||
Feature #7546: Start the game on Fredas
|
Feature #7546: Start the game on Fredas
|
||||||
|
Feature #7554: Controller binding for tab for menu navigation
|
||||||
Feature #7568: Uninterruptable scripted music
|
Feature #7568: Uninterruptable scripted music
|
||||||
|
Feature #7608: Make the missing dependencies warning when loading a savegame more helpful
|
||||||
Feature #7618: Show the player character's health in the save details
|
Feature #7618: Show the player character's health in the save details
|
||||||
Feature #7625: Add some missing console error outputs
|
Feature #7625: Add some missing console error outputs
|
||||||
Feature #7634: Support NiParticleBomb
|
Feature #7634: Support NiParticleBomb
|
||||||
Feature #7652: Sort inactive post processing shaders list properly
|
Feature #7652: Sort inactive post processing shaders list properly
|
||||||
|
Feature #7698: Implement sAbsorb, sDamage, sDrain, sFortify and sRestore
|
||||||
|
Feature #7709: Improve resolution selection in Launcher
|
||||||
Task #5896: Do not use deprecated MyGUI properties
|
Task #5896: Do not use deprecated MyGUI properties
|
||||||
|
Task #6624: Drop support for saves made prior to 0.45
|
||||||
Task #7113: Move from std::atoi to std::from_char
|
Task #7113: Move from std::atoi to std::from_char
|
||||||
Task #7117: Replace boost::scoped_array with std::vector
|
Task #7117: Replace boost::scoped_array with std::vector
|
||||||
Task #7151: Do not use std::strerror to get errno error message
|
Task #7151: Do not use std::strerror to get errno error message
|
||||||
|
|
|
@ -1,22 +1,18 @@
|
||||||
#!/bin/sh -ex
|
#!/bin/sh -ex
|
||||||
|
|
||||||
export HOMEBREW_NO_EMOJI=1
|
export HOMEBREW_NO_EMOJI=1
|
||||||
|
export HOMEBREW_NO_INSTALL_CLEANUP=1
|
||||||
|
export HOMEBREW_AUTOREMOVE=1
|
||||||
|
|
||||||
brew uninstall --ignore-dependencies python@3.8 || true
|
# workaround for gitlab's pre-installed brew
|
||||||
brew uninstall --ignore-dependencies python@3.9 || true
|
# purge large and unnecessary packages that get in our way and have caused issues
|
||||||
brew uninstall --ignore-dependencies qt@6 || true
|
brew uninstall ruby php openjdk node postgresql maven curl || true
|
||||||
brew uninstall --ignore-dependencies jpeg || true
|
|
||||||
|
|
||||||
brew tap --repair
|
brew tap --repair
|
||||||
brew update --quiet
|
brew update --quiet
|
||||||
|
|
||||||
# Some of these tools can come from places other than brew, so check before installing
|
# Some of these tools can come from places other than brew, so check before installing
|
||||||
brew reinstall xquartz fontconfig freetype harfbuzz brotli
|
brew install curl xquartz gd fontconfig freetype harfbuzz brotli
|
||||||
|
|
||||||
# Fix: can't open file: @loader_path/libbrotlicommon.1.dylib (No such file or directory)
|
|
||||||
BREW_LIB_PATH="$(brew --prefix)/lib"
|
|
||||||
install_name_tool -change "@loader_path/libbrotlicommon.1.dylib" "${BREW_LIB_PATH}/libbrotlicommon.1.dylib" ${BREW_LIB_PATH}/libbrotlidec.1.dylib
|
|
||||||
install_name_tool -change "@loader_path/libbrotlicommon.1.dylib" "${BREW_LIB_PATH}/libbrotlicommon.1.dylib" ${BREW_LIB_PATH}/libbrotlienc.1.dylib
|
|
||||||
|
|
||||||
command -v ccache >/dev/null 2>&1 || brew install ccache
|
command -v ccache >/dev/null 2>&1 || brew install ccache
|
||||||
command -v cmake >/dev/null 2>&1 || brew install cmake
|
command -v cmake >/dev/null 2>&1 || brew install cmake
|
||||||
|
|
|
@ -902,8 +902,6 @@ printf "Qt ${QT_VER}... "
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cd $QT_SDK
|
cd $QT_SDK
|
||||||
add_cmake_opts -DQT_QMAKE_EXECUTABLE="${QT_SDK}/bin/qmake.exe" \
|
|
||||||
-DCMAKE_PREFIX_PATH="$QT_SDK"
|
|
||||||
for CONFIGURATION in ${CONFIGURATIONS[@]}; do
|
for CONFIGURATION in ${CONFIGURATIONS[@]}; do
|
||||||
if [ $CONFIGURATION == "Debug" ]; then
|
if [ $CONFIGURATION == "Debug" ]; then
|
||||||
DLLSUFFIX="d"
|
DLLSUFFIX="d"
|
||||||
|
@ -930,7 +928,7 @@ printf "SDL 2.24.0... "
|
||||||
rm -rf SDL2-2.24.0
|
rm -rf SDL2-2.24.0
|
||||||
eval 7z x -y SDL2-devel-2.24.0-VC.zip $STRIP
|
eval 7z x -y SDL2-devel-2.24.0-VC.zip $STRIP
|
||||||
fi
|
fi
|
||||||
export SDL2DIR="$(real_pwd)/SDL2-2.24.0"
|
SDL2DIR="$(real_pwd)/SDL2-2.24.0"
|
||||||
for config in ${CONFIGURATIONS[@]}; do
|
for config in ${CONFIGURATIONS[@]}; do
|
||||||
add_runtime_dlls $config "$(pwd)/SDL2-2.24.0/lib/x${ARCHSUFFIX}/SDL2.dll"
|
add_runtime_dlls $config "$(pwd)/SDL2-2.24.0/lib/x${ARCHSUFFIX}/SDL2.dll"
|
||||||
done
|
done
|
||||||
|
@ -1025,6 +1023,8 @@ printf "zlib 1.2.11... "
|
||||||
echo Done.
|
echo Done.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
add_cmake_opts -DCMAKE_PREFIX_PATH="\"${QT_SDK};${SDL2DIR}\""
|
||||||
|
|
||||||
echo
|
echo
|
||||||
cd $DEPS_INSTALL/..
|
cd $DEPS_INSTALL/..
|
||||||
echo
|
echo
|
||||||
|
|
|
@ -19,6 +19,7 @@ apps/openmw_test_suite/lua/test_serialization.cpp
|
||||||
apps/openmw_test_suite/lua/test_storage.cpp
|
apps/openmw_test_suite/lua/test_storage.cpp
|
||||||
apps/openmw_test_suite/lua/test_ui_content.cpp
|
apps/openmw_test_suite/lua/test_ui_content.cpp
|
||||||
apps/openmw_test_suite/lua/test_utilpackage.cpp
|
apps/openmw_test_suite/lua/test_utilpackage.cpp
|
||||||
|
apps/openmw_test_suite/lua/test_inputactions.cpp
|
||||||
apps/openmw_test_suite/misc/test_endianness.cpp
|
apps/openmw_test_suite/misc/test_endianness.cpp
|
||||||
apps/openmw_test_suite/misc/test_resourcehelpers.cpp
|
apps/openmw_test_suite/misc/test_resourcehelpers.cpp
|
||||||
apps/openmw_test_suite/misc/test_stringops.cpp
|
apps/openmw_test_suite/misc/test_stringops.cpp
|
||||||
|
|
|
@ -86,7 +86,7 @@ declare -rA GROUPED_DEPS=(
|
||||||
libswresample3
|
libswresample3
|
||||||
libswscale5
|
libswscale5
|
||||||
libtinyxml2.6.2v5
|
libtinyxml2.6.2v5
|
||||||
libyaml-cpp0.7
|
libyaml-cpp0.8
|
||||||
python3-pip
|
python3-pip
|
||||||
xvfb
|
xvfb
|
||||||
"
|
"
|
||||||
|
@ -125,3 +125,4 @@ add-apt-repository -y ppa:openmw/openmw
|
||||||
add-apt-repository -y ppa:openmw/openmw-daily
|
add-apt-repository -y ppa:openmw/openmw-daily
|
||||||
add-apt-repository -y ppa:openmw/staging
|
add-apt-repository -y ppa:openmw/staging
|
||||||
apt-get -qq -o dir::cache::archives="$APT_CACHE_DIR" install -y --no-install-recommends "${deps[@]}" >/dev/null
|
apt-get -qq -o dir::cache::archives="$APT_CACHE_DIR" install -y --no-install-recommends "${deps[@]}" >/dev/null
|
||||||
|
apt list --installed
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
set -e
|
#!/bin/bash -e
|
||||||
|
|
||||||
docs/source/install_luadocumentor_in_docker.sh
|
docs/source/install_luadocumentor_in_docker.sh
|
||||||
PATH=$PATH:~/luarocks/bin
|
PATH=$PATH:~/luarocks/bin
|
||||||
|
|
|
@ -71,7 +71,8 @@ message(STATUS "Configuring OpenMW...")
|
||||||
set(OPENMW_VERSION_MAJOR 0)
|
set(OPENMW_VERSION_MAJOR 0)
|
||||||
set(OPENMW_VERSION_MINOR 49)
|
set(OPENMW_VERSION_MINOR 49)
|
||||||
set(OPENMW_VERSION_RELEASE 0)
|
set(OPENMW_VERSION_RELEASE 0)
|
||||||
set(OPENMW_LUA_API_REVISION 50)
|
set(OPENMW_LUA_API_REVISION 51)
|
||||||
|
set(OPENMW_POSTPROCESSING_API_REVISION 1)
|
||||||
|
|
||||||
set(OPENMW_VERSION_COMMITHASH "")
|
set(OPENMW_VERSION_COMMITHASH "")
|
||||||
set(OPENMW_VERSION_TAGHASH "")
|
set(OPENMW_VERSION_TAGHASH "")
|
||||||
|
@ -113,7 +114,6 @@ include(WholeArchive)
|
||||||
configure_file ("${OpenMW_SOURCE_DIR}/docs/mainpage.hpp.cmake" "${OpenMW_BINARY_DIR}/docs/mainpage.hpp")
|
configure_file ("${OpenMW_SOURCE_DIR}/docs/mainpage.hpp.cmake" "${OpenMW_BINARY_DIR}/docs/mainpage.hpp")
|
||||||
|
|
||||||
option(BOOST_STATIC "Link static build of Boost into the binaries" FALSE)
|
option(BOOST_STATIC "Link static build of Boost into the binaries" FALSE)
|
||||||
option(SDL2_STATIC "Link static build of SDL into the binaries" FALSE)
|
|
||||||
option(QT_STATIC "Link static build of Qt into the binaries" FALSE)
|
option(QT_STATIC "Link static build of Qt into the binaries" FALSE)
|
||||||
|
|
||||||
option(OPENMW_USE_SYSTEM_BULLET "Use system provided bullet physics library" ON)
|
option(OPENMW_USE_SYSTEM_BULLET "Use system provided bullet physics library" ON)
|
||||||
|
@ -179,6 +179,8 @@ if (MSVC)
|
||||||
# there should be no relevant downsides to having it on:
|
# there should be no relevant downsides to having it on:
|
||||||
# https://docs.microsoft.com/en-us/cpp/build/reference/bigobj-increase-number-of-sections-in-dot-obj-file
|
# https://docs.microsoft.com/en-us/cpp/build/reference/bigobj-increase-number-of-sections-in-dot-obj-file
|
||||||
add_compile_options(/bigobj)
|
add_compile_options(/bigobj)
|
||||||
|
|
||||||
|
add_compile_options(/Zc:__cplusplus)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Set up common paths
|
# Set up common paths
|
||||||
|
@ -480,7 +482,6 @@ set(SOL_CONFIG_DIR ${OpenMW_SOURCE_DIR}/extern/sol_config)
|
||||||
include_directories(
|
include_directories(
|
||||||
BEFORE SYSTEM
|
BEFORE SYSTEM
|
||||||
"."
|
"."
|
||||||
${SDL2_INCLUDE_DIR}
|
|
||||||
${Boost_INCLUDE_DIR}
|
${Boost_INCLUDE_DIR}
|
||||||
${MyGUI_INCLUDE_DIRS}
|
${MyGUI_INCLUDE_DIRS}
|
||||||
${OPENAL_INCLUDE_DIR}
|
${OPENAL_INCLUDE_DIR}
|
||||||
|
@ -492,7 +493,7 @@ include_directories(
|
||||||
${ICU_INCLUDE_DIRS}
|
${ICU_INCLUDE_DIRS}
|
||||||
)
|
)
|
||||||
|
|
||||||
link_directories(${SDL2_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS} ${COLLADA_DOM_LIBRARY_DIRS})
|
link_directories(${Boost_LIBRARY_DIRS} ${COLLADA_DOM_LIBRARY_DIRS})
|
||||||
|
|
||||||
if(MYGUI_STATIC)
|
if(MYGUI_STATIC)
|
||||||
add_definitions(-DMYGUI_STATIC)
|
add_definitions(-DMYGUI_STATIC)
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <components/esm3/loadland.hpp>
|
#include <components/esm3/loadland.hpp>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <iterator>
|
||||||
#include <random>
|
#include <random>
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
|
@ -24,29 +25,25 @@ namespace
|
||||||
PreparedNavMeshData mValue;
|
PreparedNavMeshData mValue;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Random>
|
osg::Vec2i generateVec2i(int max, auto& random)
|
||||||
osg::Vec2i generateVec2i(int max, Random& random)
|
|
||||||
{
|
{
|
||||||
std::uniform_int_distribution<int> distribution(0, max);
|
std::uniform_int_distribution<int> distribution(0, max);
|
||||||
return osg::Vec2i(distribution(random), distribution(random));
|
return osg::Vec2i(distribution(random), distribution(random));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Random>
|
osg::Vec3f generateAgentHalfExtents(float min, float max, auto& random)
|
||||||
osg::Vec3f generateAgentHalfExtents(float min, float max, Random& random)
|
|
||||||
{
|
{
|
||||||
std::uniform_int_distribution<int> distribution(min, max);
|
std::uniform_int_distribution<int> distribution(min, max);
|
||||||
return osg::Vec3f(distribution(random), distribution(random), distribution(random));
|
return osg::Vec3f(distribution(random), distribution(random), distribution(random));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename OutputIterator, typename Random>
|
void generateVertices(std::output_iterator<int> auto out, std::size_t number, auto& random)
|
||||||
void generateVertices(OutputIterator out, std::size_t number, Random& random)
|
|
||||||
{
|
{
|
||||||
std::uniform_real_distribution<float> distribution(0.0, 1.0);
|
std::uniform_real_distribution<float> distribution(0.0, 1.0);
|
||||||
std::generate_n(out, 3 * (number - number % 3), [&] { return distribution(random); });
|
std::generate_n(out, 3 * (number - number % 3), [&] { return distribution(random); });
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename OutputIterator, typename Random>
|
void generateIndices(std::output_iterator<int> auto out, int max, std::size_t number, auto& random)
|
||||||
void generateIndices(OutputIterator out, int max, std::size_t number, Random& random)
|
|
||||||
{
|
{
|
||||||
std::uniform_int_distribution<int> distribution(0, max);
|
std::uniform_int_distribution<int> distribution(0, max);
|
||||||
std::generate_n(out, number - number % 3, [&] { return distribution(random); });
|
std::generate_n(out, number - number % 3, [&] { return distribution(random); });
|
||||||
|
@ -70,21 +67,18 @@ namespace
|
||||||
return AreaType_null;
|
return AreaType_null;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Random>
|
AreaType generateAreaType(auto& random)
|
||||||
AreaType generateAreaType(Random& random)
|
|
||||||
{
|
{
|
||||||
std::uniform_int_distribution<int> distribution(0, 4);
|
std::uniform_int_distribution<int> distribution(0, 4);
|
||||||
return toAreaType(distribution(random));
|
return toAreaType(distribution(random));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename OutputIterator, typename Random>
|
void generateAreaTypes(std::output_iterator<AreaType> auto out, std::size_t triangles, auto& random)
|
||||||
void generateAreaTypes(OutputIterator out, std::size_t triangles, Random& random)
|
|
||||||
{
|
{
|
||||||
std::generate_n(out, triangles, [&] { return generateAreaType(random); });
|
std::generate_n(out, triangles, [&] { return generateAreaType(random); });
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename OutputIterator, typename Random>
|
void generateWater(std::output_iterator<CellWater> auto out, std::size_t count, auto& random)
|
||||||
void generateWater(OutputIterator out, std::size_t count, Random& random)
|
|
||||||
{
|
{
|
||||||
std::uniform_real_distribution<float> distribution(0.0, 1.0);
|
std::uniform_real_distribution<float> distribution(0.0, 1.0);
|
||||||
std::generate_n(out, count, [&] {
|
std::generate_n(out, count, [&] {
|
||||||
|
@ -92,8 +86,7 @@ namespace
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Random>
|
Mesh generateMesh(std::size_t triangles, auto& random)
|
||||||
Mesh generateMesh(std::size_t triangles, Random& random)
|
|
||||||
{
|
{
|
||||||
std::uniform_real_distribution<float> distribution(0.0, 1.0);
|
std::uniform_real_distribution<float> distribution(0.0, 1.0);
|
||||||
std::vector<float> vertices;
|
std::vector<float> vertices;
|
||||||
|
@ -109,8 +102,7 @@ namespace
|
||||||
return Mesh(std::move(indices), std::move(vertices), std::move(areaTypes));
|
return Mesh(std::move(indices), std::move(vertices), std::move(areaTypes));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Random>
|
Heightfield generateHeightfield(auto& random)
|
||||||
Heightfield generateHeightfield(Random& random)
|
|
||||||
{
|
{
|
||||||
std::uniform_real_distribution<float> distribution(0.0, 1.0);
|
std::uniform_real_distribution<float> distribution(0.0, 1.0);
|
||||||
Heightfield result;
|
Heightfield result;
|
||||||
|
@ -127,8 +119,7 @@ namespace
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Random>
|
FlatHeightfield generateFlatHeightfield(auto& random)
|
||||||
FlatHeightfield generateFlatHeightfield(Random& random)
|
|
||||||
{
|
{
|
||||||
std::uniform_real_distribution<float> distribution(0.0, 1.0);
|
std::uniform_real_distribution<float> distribution(0.0, 1.0);
|
||||||
FlatHeightfield result;
|
FlatHeightfield result;
|
||||||
|
@ -138,8 +129,7 @@ namespace
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Random>
|
Key generateKey(std::size_t triangles, auto& random)
|
||||||
Key generateKey(std::size_t triangles, Random& random)
|
|
||||||
{
|
{
|
||||||
const CollisionShapeType agentShapeType = CollisionShapeType::Aabb;
|
const CollisionShapeType agentShapeType = CollisionShapeType::Aabb;
|
||||||
const osg::Vec3f agentHalfExtents = generateAgentHalfExtents(0.5, 1.5, random);
|
const osg::Vec3f agentHalfExtents = generateAgentHalfExtents(0.5, 1.5, random);
|
||||||
|
@ -158,14 +148,12 @@ namespace
|
||||||
|
|
||||||
constexpr std::size_t trianglesPerTile = 239;
|
constexpr std::size_t trianglesPerTile = 239;
|
||||||
|
|
||||||
template <typename OutputIterator, typename Random>
|
void generateKeys(std::output_iterator<Key> auto out, std::size_t count, auto& random)
|
||||||
void generateKeys(OutputIterator out, std::size_t count, Random& random)
|
|
||||||
{
|
{
|
||||||
std::generate_n(out, count, [&] { return generateKey(trianglesPerTile, random); });
|
std::generate_n(out, count, [&] { return generateKey(trianglesPerTile, random); });
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename OutputIterator, typename Random>
|
void fillCache(std::output_iterator<Key> auto out, auto& random, NavMeshTilesCache& cache)
|
||||||
void fillCache(OutputIterator out, Random& random, NavMeshTilesCache& cache)
|
|
||||||
{
|
{
|
||||||
std::size_t size = cache.getStats().mNavMeshCacheSize;
|
std::size_t size = cache.getStats().mNavMeshCacheSize;
|
||||||
|
|
||||||
|
|
|
@ -194,7 +194,8 @@ int extract(std::unique_ptr<File>& bsa, Arguments& info)
|
||||||
// Get a stream for the file to extract
|
// Get a stream for the file to extract
|
||||||
for (auto it = bsa->getList().rbegin(); it != bsa->getList().rend(); ++it)
|
for (auto it = bsa->getList().rbegin(); it != bsa->getList().rend(); ++it)
|
||||||
{
|
{
|
||||||
if (Misc::StringUtils::ciEqual(Misc::StringUtils::stringToU8String(it->name()), archivePath))
|
auto streamPath = Misc::StringUtils::stringToU8String(it->name());
|
||||||
|
if (Misc::StringUtils::ciEqual(streamPath, archivePath) || Misc::StringUtils::ciEqual(streamPath, extractPath))
|
||||||
{
|
{
|
||||||
stream = bsa->getFile(&*it);
|
stream = bsa->getFile(&*it);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -145,12 +145,12 @@ namespace
|
||||||
|
|
||||||
config.filterOutNonExistingPaths(dataDirs);
|
config.filterOutNonExistingPaths(dataDirs);
|
||||||
|
|
||||||
const auto resDir = variables["resources"].as<Files::MaybeQuotedPath>();
|
const auto& resDir = variables["resources"].as<Files::MaybeQuotedPath>();
|
||||||
Log(Debug::Info) << Version::getOpenmwVersionDescription();
|
Log(Debug::Info) << Version::getOpenmwVersionDescription();
|
||||||
dataDirs.insert(dataDirs.begin(), resDir / "vfs");
|
dataDirs.insert(dataDirs.begin(), resDir / "vfs");
|
||||||
const auto fileCollections = Files::Collections(dataDirs);
|
const Files::Collections fileCollections(dataDirs);
|
||||||
const auto archives = variables["fallback-archive"].as<StringsVector>();
|
const auto& archives = variables["fallback-archive"].as<StringsVector>();
|
||||||
const auto contentFiles = variables["content"].as<StringsVector>();
|
const auto& contentFiles = variables["content"].as<StringsVector>();
|
||||||
|
|
||||||
Fallback::Map::init(variables["fallback"].as<Fallback::FallbackMap>().mMap);
|
Fallback::Map::init(variables["fallback"].as<Fallback::FallbackMap>().mMap);
|
||||||
|
|
||||||
|
|
|
@ -156,7 +156,7 @@ Allowed options)");
|
||||||
return false;
|
return false;
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
const auto inputFiles = variables["input-file"].as<Files::MaybeQuotedPathContainer>();
|
const auto& inputFiles = variables["input-file"].as<Files::MaybeQuotedPathContainer>();
|
||||||
info.filename = inputFiles[0].u8string(); // This call to u8string is redundant, but required to build on
|
info.filename = inputFiles[0].u8string(); // This call to u8string is redundant, but required to build on
|
||||||
// MSVC 14.26 due to implementation bugs.
|
// MSVC 14.26 due to implementation bugs.
|
||||||
if (inputFiles.size() > 1)
|
if (inputFiles.size() > 1)
|
||||||
|
@ -265,7 +265,7 @@ namespace
|
||||||
std::cout << " Faction rank: " << ref.mFactionRank << '\n';
|
std::cout << " Faction rank: " << ref.mFactionRank << '\n';
|
||||||
std::cout << " Enchantment charge: " << ref.mEnchantmentCharge << '\n';
|
std::cout << " Enchantment charge: " << ref.mEnchantmentCharge << '\n';
|
||||||
std::cout << " Uses/health: " << ref.mChargeInt << '\n';
|
std::cout << " Uses/health: " << ref.mChargeInt << '\n';
|
||||||
std::cout << " Gold value: " << ref.mGoldValue << '\n';
|
std::cout << " Count: " << ref.mCount << '\n';
|
||||||
std::cout << " Blocked: " << static_cast<int>(ref.mReferenceBlocked) << '\n';
|
std::cout << " Blocked: " << static_cast<int>(ref.mReferenceBlocked) << '\n';
|
||||||
std::cout << " Deleted: " << deleted << '\n';
|
std::cout << " Deleted: " << deleted << '\n';
|
||||||
if (!ref.mKey.empty())
|
if (!ref.mKey.empty())
|
||||||
|
@ -341,7 +341,7 @@ namespace
|
||||||
{
|
{
|
||||||
std::cout << "Author: " << esm.getAuthor() << '\n'
|
std::cout << "Author: " << esm.getAuthor() << '\n'
|
||||||
<< "Description: " << esm.getDesc() << '\n'
|
<< "Description: " << esm.getDesc() << '\n'
|
||||||
<< "File format version: " << esm.getFVer() << '\n';
|
<< "File format version: " << esm.esmVersionF() << '\n';
|
||||||
std::vector<ESM::Header::MasterData> masterData = esm.getGameFiles();
|
std::vector<ESM::Header::MasterData> masterData = esm.getGameFiles();
|
||||||
if (!masterData.empty())
|
if (!masterData.empty())
|
||||||
{
|
{
|
||||||
|
@ -508,7 +508,7 @@ namespace
|
||||||
ToUTF8::Utf8Encoder encoder(ToUTF8::calculateEncoding(info.encoding));
|
ToUTF8::Utf8Encoder encoder(ToUTF8::calculateEncoding(info.encoding));
|
||||||
esm.setEncoder(&encoder);
|
esm.setEncoder(&encoder);
|
||||||
esm.setHeader(data.mHeader);
|
esm.setHeader(data.mHeader);
|
||||||
esm.setVersion(ESM::VER_13);
|
esm.setVersion(ESM::VER_130);
|
||||||
esm.setRecordCount(recordCount);
|
esm.setRecordCount(recordCount);
|
||||||
|
|
||||||
std::fstream save(info.outname, std::fstream::out | std::fstream::binary);
|
std::fstream save(info.outname, std::fstream::out | std::fstream::binary);
|
||||||
|
|
|
@ -1084,14 +1084,8 @@ namespace EsmTool
|
||||||
std::cout << " Rank: " << (int)mData.mNpdt.mRank << std::endl;
|
std::cout << " Rank: " << (int)mData.mNpdt.mRank << std::endl;
|
||||||
|
|
||||||
std::cout << " Attributes:" << std::endl;
|
std::cout << " Attributes:" << std::endl;
|
||||||
std::cout << " Strength: " << (int)mData.mNpdt.mStrength << std::endl;
|
for (size_t i = 0; i != mData.mNpdt.mAttributes.size(); i++)
|
||||||
std::cout << " Intelligence: " << (int)mData.mNpdt.mIntelligence << std::endl;
|
std::cout << " " << attributeLabel(i) << ": " << int(mData.mNpdt.mAttributes[i]) << std::endl;
|
||||||
std::cout << " Willpower: " << (int)mData.mNpdt.mWillpower << std::endl;
|
|
||||||
std::cout << " Agility: " << (int)mData.mNpdt.mAgility << std::endl;
|
|
||||||
std::cout << " Speed: " << (int)mData.mNpdt.mSpeed << std::endl;
|
|
||||||
std::cout << " Endurance: " << (int)mData.mNpdt.mEndurance << std::endl;
|
|
||||||
std::cout << " Personality: " << (int)mData.mNpdt.mPersonality << std::endl;
|
|
||||||
std::cout << " Luck: " << (int)mData.mNpdt.mLuck << std::endl;
|
|
||||||
|
|
||||||
std::cout << " Skills:" << std::endl;
|
std::cout << " Skills:" << std::endl;
|
||||||
for (size_t i = 0; i != mData.mNpdt.mSkills.size(); i++)
|
for (size_t i = 0; i != mData.mNpdt.mSkills.size(); i++)
|
||||||
|
@ -1169,19 +1163,23 @@ namespace EsmTool
|
||||||
std::cout << " Description: " << mData.mDescription << std::endl;
|
std::cout << " Description: " << mData.mDescription << std::endl;
|
||||||
std::cout << " Flags: " << raceFlags(mData.mData.mFlags) << std::endl;
|
std::cout << " Flags: " << raceFlags(mData.mData.mFlags) << std::endl;
|
||||||
|
|
||||||
for (int i = 0; i < 2; ++i)
|
std::cout << " Male:" << std::endl;
|
||||||
|
for (int j = 0; j < ESM::Attribute::Length; ++j)
|
||||||
{
|
{
|
||||||
bool male = i == 0;
|
ESM::RefId id = ESM::Attribute::indexToRefId(j);
|
||||||
|
std::cout << " " << id << ": " << mData.mData.getAttribute(id, true) << std::endl;
|
||||||
std::cout << (male ? " Male:" : " Female:") << std::endl;
|
|
||||||
|
|
||||||
for (int j = 0; j < ESM::Attribute::Length; ++j)
|
|
||||||
std::cout << " " << ESM::Attribute::indexToRefId(j) << ": "
|
|
||||||
<< mData.mData.mAttributeValues[j].getValue(male) << std::endl;
|
|
||||||
|
|
||||||
std::cout << " Height: " << mData.mData.mHeight.getValue(male) << std::endl;
|
|
||||||
std::cout << " Weight: " << mData.mData.mWeight.getValue(male) << std::endl;
|
|
||||||
}
|
}
|
||||||
|
std::cout << " Height: " << mData.mData.mMaleHeight << std::endl;
|
||||||
|
std::cout << " Weight: " << mData.mData.mMaleWeight << std::endl;
|
||||||
|
|
||||||
|
std::cout << " Female:" << std::endl;
|
||||||
|
for (int j = 0; j < ESM::Attribute::Length; ++j)
|
||||||
|
{
|
||||||
|
ESM::RefId id = ESM::Attribute::indexToRefId(j);
|
||||||
|
std::cout << " " << id << ": " << mData.mData.getAttribute(id, false) << std::endl;
|
||||||
|
}
|
||||||
|
std::cout << " Height: " << mData.mData.mFemaleHeight << std::endl;
|
||||||
|
std::cout << " Weight: " << mData.mData.mFemaleWeight << std::endl;
|
||||||
|
|
||||||
for (const auto& bonus : mData.mData.mBonus)
|
for (const auto& bonus : mData.mData.mBonus)
|
||||||
// Not all races have 7 skills.
|
// Not all races have 7 skills.
|
||||||
|
@ -1204,7 +1202,8 @@ namespace EsmTool
|
||||||
std::array<std::string_view, 10> weathers
|
std::array<std::string_view, 10> weathers
|
||||||
= { "Clear", "Cloudy", "Fog", "Overcast", "Rain", "Thunder", "Ash", "Blight", "Snow", "Blizzard" };
|
= { "Clear", "Cloudy", "Fog", "Overcast", "Rain", "Thunder", "Ash", "Blight", "Snow", "Blizzard" };
|
||||||
for (size_t i = 0; i < weathers.size(); ++i)
|
for (size_t i = 0; i < weathers.size(); ++i)
|
||||||
std::cout << " " << weathers[i] << ": " << mData.mData.mProbabilities[i] << std::endl;
|
std::cout << " " << weathers[i] << ": " << static_cast<unsigned>(mData.mData.mProbabilities[i])
|
||||||
|
<< std::endl;
|
||||||
std::cout << " Map Color: " << mData.mMapColor << std::endl;
|
std::cout << " Map Color: " << mData.mMapColor << std::endl;
|
||||||
if (!mData.mSleepList.empty())
|
if (!mData.mSleepList.empty())
|
||||||
std::cout << " Sleep List: " << mData.mSleepList << std::endl;
|
std::cout << " Sleep List: " << mData.mSleepList << std::endl;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "converter.hpp"
|
#include "converter.hpp"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <cstdint>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
#include <osgDB/WriteFile>
|
#include <osgDB/WriteFile>
|
||||||
|
@ -33,7 +34,7 @@ namespace
|
||||||
objstate.mPosition = cellref.mPos;
|
objstate.mPosition = cellref.mPos;
|
||||||
objstate.mRef.mRefNum = cellref.mRefNum;
|
objstate.mRef.mRefNum = cellref.mRefNum;
|
||||||
if (cellref.mDeleted)
|
if (cellref.mDeleted)
|
||||||
objstate.mCount = 0;
|
objstate.mRef.mCount = 0;
|
||||||
convertSCRI(cellref.mActorData.mSCRI, objstate.mLocals);
|
convertSCRI(cellref.mActorData.mSCRI, objstate.mLocals);
|
||||||
objstate.mHasLocals = !objstate.mLocals.mVariables.empty();
|
objstate.mHasLocals = !objstate.mLocals.mVariables.empty();
|
||||||
|
|
||||||
|
@ -90,14 +91,14 @@ namespace ESSImport
|
||||||
|
|
||||||
struct MAPH
|
struct MAPH
|
||||||
{
|
{
|
||||||
unsigned int size;
|
uint32_t size;
|
||||||
unsigned int value;
|
uint32_t value;
|
||||||
};
|
};
|
||||||
|
|
||||||
void ConvertFMAP::read(ESM::ESMReader& esm)
|
void ConvertFMAP::read(ESM::ESMReader& esm)
|
||||||
{
|
{
|
||||||
MAPH maph;
|
MAPH maph;
|
||||||
esm.getHNTSized<8>(maph, "MAPH");
|
esm.getHNT("MAPH", maph.size, maph.value);
|
||||||
std::vector<char> data;
|
std::vector<char> data;
|
||||||
esm.getSubNameIs("MAPD");
|
esm.getSubNameIs("MAPD");
|
||||||
esm.getSubHeader();
|
esm.getSubHeader();
|
||||||
|
@ -278,7 +279,7 @@ namespace ESSImport
|
||||||
while (esm.isNextSub("MPCD"))
|
while (esm.isNextSub("MPCD"))
|
||||||
{
|
{
|
||||||
float notepos[3];
|
float notepos[3];
|
||||||
esm.getHTSized<3 * sizeof(float)>(notepos);
|
esm.getHT(notepos);
|
||||||
|
|
||||||
// Markers seem to be arranged in a 32*32 grid, notepos has grid-indices.
|
// Markers seem to be arranged in a 32*32 grid, notepos has grid-indices.
|
||||||
// This seems to be the reason markers can't be placed everywhere in interior cells,
|
// This seems to be the reason markers can't be placed everywhere in interior cells,
|
||||||
|
|
|
@ -9,15 +9,14 @@ namespace ESSImport
|
||||||
|
|
||||||
void convertInventory(const Inventory& inventory, ESM::InventoryState& state)
|
void convertInventory(const Inventory& inventory, ESM::InventoryState& state)
|
||||||
{
|
{
|
||||||
int index = 0;
|
uint32_t index = 0;
|
||||||
for (const auto& item : inventory.mItems)
|
for (const auto& item : inventory.mItems)
|
||||||
{
|
{
|
||||||
ESM::ObjectState objstate;
|
ESM::ObjectState objstate;
|
||||||
objstate.blank();
|
objstate.blank();
|
||||||
objstate.mRef = item;
|
objstate.mRef = item;
|
||||||
objstate.mRef.mRefID = ESM::RefId::stringRefId(item.mId);
|
objstate.mRef.mRefID = ESM::RefId::stringRefId(item.mId);
|
||||||
objstate.mCount = std::abs(item.mCount); // restocking items have negative count in the savefile
|
objstate.mRef.mCount = item.mCount;
|
||||||
// openmw handles them differently, so no need to set any flags
|
|
||||||
state.mItems.push_back(objstate);
|
state.mItems.push_back(objstate);
|
||||||
if (item.mRelativeEquipmentSlot != -1)
|
if (item.mRelativeEquipmentSlot != -1)
|
||||||
// Note we should really write the absolute slot here, which we do not know about
|
// Note we should really write the absolute slot here, which we do not know about
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef OPENMW_ESSIMPORT_ACDT_H
|
#ifndef OPENMW_ESSIMPORT_ACDT_H
|
||||||
#define OPENMW_ESSIMPORT_ACDT_H
|
#define OPENMW_ESSIMPORT_ACDT_H
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "importscri.hpp"
|
#include "importscri.hpp"
|
||||||
|
@ -25,14 +26,12 @@ namespace ESSImport
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Actor data, shared by (at least) REFR and CellRef
|
/// Actor data, shared by (at least) REFR and CellRef
|
||||||
#pragma pack(push)
|
|
||||||
#pragma pack(1)
|
|
||||||
struct ACDT
|
struct ACDT
|
||||||
{
|
{
|
||||||
// Note, not stored at *all*:
|
// Note, not stored at *all*:
|
||||||
// - Level changes are lost on reload, except for the player (there it's in the NPC record).
|
// - Level changes are lost on reload, except for the player (there it's in the NPC record).
|
||||||
unsigned char mUnknown[12];
|
unsigned char mUnknown[12];
|
||||||
unsigned int mFlags;
|
uint32_t mFlags;
|
||||||
float mBreathMeter; // Seconds left before drowning
|
float mBreathMeter; // Seconds left before drowning
|
||||||
unsigned char mUnknown2[20];
|
unsigned char mUnknown2[20];
|
||||||
float mDynamic[3][2];
|
float mDynamic[3][2];
|
||||||
|
@ -41,7 +40,7 @@ namespace ESSImport
|
||||||
float mMagicEffects[27]; // Effect attributes:
|
float mMagicEffects[27]; // Effect attributes:
|
||||||
// https://wiki.openmw.org/index.php?title=Research:Magic#Effect_attributes
|
// https://wiki.openmw.org/index.php?title=Research:Magic#Effect_attributes
|
||||||
unsigned char mUnknown4[4];
|
unsigned char mUnknown4[4];
|
||||||
unsigned int mGoldPool;
|
uint32_t mGoldPool;
|
||||||
unsigned char mCountDown; // seen the same value as in ACSC.mCorpseClearCountdown, maybe
|
unsigned char mCountDown; // seen the same value as in ACSC.mCorpseClearCountdown, maybe
|
||||||
// this one is for respawning?
|
// this one is for respawning?
|
||||||
unsigned char mUnknown5[3];
|
unsigned char mUnknown5[3];
|
||||||
|
@ -60,7 +59,6 @@ namespace ESSImport
|
||||||
unsigned char mUnknown[3];
|
unsigned char mUnknown[3];
|
||||||
float mTime;
|
float mTime;
|
||||||
};
|
};
|
||||||
#pragma pack(pop)
|
|
||||||
|
|
||||||
struct ActorData
|
struct ActorData
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "importcellref.hpp"
|
#include "importcellref.hpp"
|
||||||
|
|
||||||
#include <components/esm3/esmreader.hpp>
|
#include <components/esm3/esmreader.hpp>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
namespace ESSImport
|
namespace ESSImport
|
||||||
{
|
{
|
||||||
|
@ -44,19 +45,14 @@ namespace ESSImport
|
||||||
bool isDeleted = false;
|
bool isDeleted = false;
|
||||||
ESM::CellRef::loadData(esm, isDeleted);
|
ESM::CellRef::loadData(esm, isDeleted);
|
||||||
|
|
||||||
mActorData.mHasACDT = false;
|
mActorData.mHasACDT
|
||||||
if (esm.isNextSub("ACDT"))
|
= esm.getHNOT("ACDT", mActorData.mACDT.mUnknown, mActorData.mACDT.mFlags, mActorData.mACDT.mBreathMeter,
|
||||||
{
|
mActorData.mACDT.mUnknown2, mActorData.mACDT.mDynamic, mActorData.mACDT.mUnknown3,
|
||||||
mActorData.mHasACDT = true;
|
mActorData.mACDT.mAttributes, mActorData.mACDT.mMagicEffects, mActorData.mACDT.mUnknown4,
|
||||||
esm.getHTSized<264>(mActorData.mACDT);
|
mActorData.mACDT.mGoldPool, mActorData.mACDT.mCountDown, mActorData.mACDT.mUnknown5);
|
||||||
}
|
|
||||||
|
|
||||||
mActorData.mHasACSC = false;
|
mActorData.mHasACSC = esm.getHNOT("ACSC", mActorData.mACSC.mUnknown1, mActorData.mACSC.mFlags,
|
||||||
if (esm.isNextSub("ACSC"))
|
mActorData.mACSC.mUnknown2, mActorData.mACSC.mCorpseClearCountdown, mActorData.mACSC.mUnknown3);
|
||||||
{
|
|
||||||
mActorData.mHasACSC = true;
|
|
||||||
esm.getHTSized<112>(mActorData.mACSC);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (esm.isNextSub("ACSL"))
|
if (esm.isNextSub("ACSL"))
|
||||||
esm.skipHSubSize(112);
|
esm.skipHSubSize(112);
|
||||||
|
@ -122,23 +118,17 @@ namespace ESSImport
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: not all actors have this, add flag
|
// FIXME: not all actors have this, add flag
|
||||||
if (esm.isNextSub("CHRD")) // npc only
|
esm.getHNOT("CHRD", mActorData.mSkills); // npc only
|
||||||
esm.getHExact(mActorData.mSkills, 27 * 2 * sizeof(int));
|
|
||||||
|
|
||||||
if (esm.isNextSub("CRED")) // creature only
|
esm.getHNOT("CRED", mActorData.mCombatStats); // creature only
|
||||||
esm.getHExact(mActorData.mCombatStats, 3 * 2 * sizeof(int));
|
|
||||||
|
|
||||||
mActorData.mSCRI.load(esm);
|
mActorData.mSCRI.load(esm);
|
||||||
|
|
||||||
if (esm.isNextSub("ND3D"))
|
if (esm.isNextSub("ND3D"))
|
||||||
esm.skipHSub();
|
esm.skipHSub();
|
||||||
|
|
||||||
mActorData.mHasANIS = false;
|
mActorData.mHasANIS
|
||||||
if (esm.isNextSub("ANIS"))
|
= esm.getHNOT("ANIS", mActorData.mANIS.mGroupIndex, mActorData.mANIS.mUnknown, mActorData.mANIS.mTime);
|
||||||
{
|
|
||||||
mActorData.mHasANIS = true;
|
|
||||||
esm.getHTSized<8>(mActorData.mANIS);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (esm.isNextSub("LVCR"))
|
if (esm.isNextSub("LVCR"))
|
||||||
{
|
{
|
||||||
|
@ -155,13 +145,13 @@ namespace ESSImport
|
||||||
// DATA should occur for all references, except levelled creature spawners
|
// DATA should occur for all references, except levelled creature spawners
|
||||||
// I've seen DATA *twice* on a creature record, and with the exact same content too! weird
|
// I've seen DATA *twice* on a creature record, and with the exact same content too! weird
|
||||||
// alarmvoi0000.ess
|
// alarmvoi0000.ess
|
||||||
esm.getHNOTSized<24>(mPos, "DATA");
|
for (int i = 0; i < 2; ++i)
|
||||||
esm.getHNOTSized<24>(mPos, "DATA");
|
esm.getHNOT("DATA", mPos.pos, mPos.rot);
|
||||||
|
|
||||||
mDeleted = 0;
|
mDeleted = 0;
|
||||||
if (esm.isNextSub("DELE"))
|
if (esm.isNextSub("DELE"))
|
||||||
{
|
{
|
||||||
unsigned int deleted;
|
uint32_t deleted;
|
||||||
esm.getHT(deleted);
|
esm.getHT(deleted);
|
||||||
mDeleted = ((deleted >> 24) & 0x2) != 0; // the other 3 bytes seem to be uninitialized garbage
|
mDeleted = ((deleted >> 24) & 0x2) != 0; // the other 3 bytes seem to be uninitialized garbage
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "importcntc.hpp"
|
#include "importcntc.hpp"
|
||||||
|
|
||||||
#include <components/esm3/esmreader.hpp>
|
#include <components/esm3/esmreader.hpp>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
namespace ESSImport
|
namespace ESSImport
|
||||||
{
|
{
|
||||||
|
|
|
@ -14,7 +14,7 @@ namespace ESSImport
|
||||||
/// Changed container contents
|
/// Changed container contents
|
||||||
struct CNTC
|
struct CNTC
|
||||||
{
|
{
|
||||||
int mIndex;
|
int32_t mIndex;
|
||||||
|
|
||||||
Inventory mInventory;
|
Inventory mInventory;
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include "importinventory.hpp"
|
#include "importinventory.hpp"
|
||||||
#include <components/esm3/aipackage.hpp>
|
#include <components/esm3/aipackage.hpp>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
namespace ESM
|
namespace ESM
|
||||||
{
|
{
|
||||||
|
@ -15,7 +16,7 @@ namespace ESSImport
|
||||||
/// Creature changes
|
/// Creature changes
|
||||||
struct CREC
|
struct CREC
|
||||||
{
|
{
|
||||||
int mIndex;
|
int32_t mIndex;
|
||||||
|
|
||||||
Inventory mInventory;
|
Inventory mInventory;
|
||||||
ESM::AIPackageList mAiPackages;
|
ESM::AIPackageList mAiPackages;
|
||||||
|
|
|
@ -8,11 +8,11 @@ namespace ESSImport
|
||||||
void DIAL::load(ESM::ESMReader& esm)
|
void DIAL::load(ESM::ESMReader& esm)
|
||||||
{
|
{
|
||||||
// See ESM::Dialogue::Type enum, not sure why we would need this here though
|
// See ESM::Dialogue::Type enum, not sure why we would need this here though
|
||||||
int type = 0;
|
int32_t type = 0;
|
||||||
esm.getHNOT(type, "DATA");
|
esm.getHNOT(type, "DATA");
|
||||||
|
|
||||||
// Deleted dialogue in a savefile. No clue what this means...
|
// Deleted dialogue in a savefile. No clue what this means...
|
||||||
int deleted = 0;
|
int32_t deleted = 0;
|
||||||
esm.getHNOT(deleted, "DELE");
|
esm.getHNOT(deleted, "DELE");
|
||||||
|
|
||||||
mIndex = 0;
|
mIndex = 0;
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
#ifndef OPENMW_ESSIMPORT_IMPORTDIAL_H
|
#ifndef OPENMW_ESSIMPORT_IMPORTDIAL_H
|
||||||
#define OPENMW_ESSIMPORT_IMPORTDIAL_H
|
#define OPENMW_ESSIMPORT_IMPORTDIAL_H
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
namespace ESM
|
namespace ESM
|
||||||
{
|
{
|
||||||
class ESMReader;
|
class ESMReader;
|
||||||
|
@ -10,7 +13,7 @@ namespace ESSImport
|
||||||
|
|
||||||
struct DIAL
|
struct DIAL
|
||||||
{
|
{
|
||||||
int mIndex; // Journal index
|
int32_t mIndex; // Journal index
|
||||||
|
|
||||||
void load(ESM::ESMReader& esm);
|
void load(ESM::ESMReader& esm);
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,17 +9,17 @@ namespace ESSImport
|
||||||
{
|
{
|
||||||
esm.getSubNameIs("GMDT");
|
esm.getSubNameIs("GMDT");
|
||||||
esm.getSubHeader();
|
esm.getSubHeader();
|
||||||
if (esm.getSubSize() == 92)
|
bool hasSecundaPhase = esm.getSubSize() == 96;
|
||||||
{
|
esm.getT(mGMDT.mCellName);
|
||||||
esm.getExact(&mGMDT, 92);
|
esm.getT(mGMDT.mFogColour);
|
||||||
mGMDT.mSecundaPhase = 0;
|
esm.getT(mGMDT.mFogDensity);
|
||||||
}
|
esm.getT(mGMDT.mCurrentWeather);
|
||||||
else if (esm.getSubSize() == 96)
|
esm.getT(mGMDT.mNextWeather);
|
||||||
{
|
esm.getT(mGMDT.mWeatherTransition);
|
||||||
esm.getTSized<96>(mGMDT);
|
esm.getT(mGMDT.mTimeOfNextTransition);
|
||||||
}
|
esm.getT(mGMDT.mMasserPhase);
|
||||||
else
|
if (hasSecundaPhase)
|
||||||
esm.fail("unexpected subrecord size for GAME.GMDT");
|
esm.getT(mGMDT.mSecundaPhase);
|
||||||
|
|
||||||
mGMDT.mWeatherTransition &= (0x000000ff);
|
mGMDT.mWeatherTransition &= (0x000000ff);
|
||||||
mGMDT.mSecundaPhase &= (0x000000ff);
|
mGMDT.mSecundaPhase &= (0x000000ff);
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#ifndef OPENMW_ESSIMPORT_GAME_H
|
#ifndef OPENMW_ESSIMPORT_GAME_H
|
||||||
#define OPENMW_ESSIMPORT_GAME_H
|
#define OPENMW_ESSIMPORT_GAME_H
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
namespace ESM
|
namespace ESM
|
||||||
{
|
{
|
||||||
class ESMReader;
|
class ESMReader;
|
||||||
|
@ -15,12 +17,12 @@ namespace ESSImport
|
||||||
struct GMDT
|
struct GMDT
|
||||||
{
|
{
|
||||||
char mCellName[64]{};
|
char mCellName[64]{};
|
||||||
int mFogColour{ 0 };
|
int32_t mFogColour{ 0 };
|
||||||
float mFogDensity{ 0.f };
|
float mFogDensity{ 0.f };
|
||||||
int mCurrentWeather{ 0 }, mNextWeather{ 0 };
|
int32_t mCurrentWeather{ 0 }, mNextWeather{ 0 };
|
||||||
int mWeatherTransition{ 0 }; // 0-100 transition between weathers, top 3 bytes may be garbage
|
int32_t mWeatherTransition{ 0 }; // 0-100 transition between weathers, top 3 bytes may be garbage
|
||||||
float mTimeOfNextTransition{ 0.f }; // weather changes when gamehour == timeOfNextTransition
|
float mTimeOfNextTransition{ 0.f }; // weather changes when gamehour == timeOfNextTransition
|
||||||
int mMasserPhase{ 0 }, mSecundaPhase{ 0 }; // top 3 bytes may be garbage
|
int32_t mMasserPhase{ 0 }, mSecundaPhase{ 0 }; // top 3 bytes may be garbage
|
||||||
};
|
};
|
||||||
|
|
||||||
GMDT mGMDT;
|
GMDT mGMDT;
|
||||||
|
|
|
@ -12,7 +12,7 @@ namespace ESSImport
|
||||||
while (esm.isNextSub("NPCO"))
|
while (esm.isNextSub("NPCO"))
|
||||||
{
|
{
|
||||||
ContItem contItem;
|
ContItem contItem;
|
||||||
esm.getHTSized<36>(contItem);
|
esm.getHT(contItem.mCount, contItem.mItem.mData);
|
||||||
|
|
||||||
InventoryItem item;
|
InventoryItem item;
|
||||||
item.mId = contItem.mItem.toString();
|
item.mId = contItem.mItem.toString();
|
||||||
|
@ -28,7 +28,7 @@ namespace ESSImport
|
||||||
bool newStack = esm.isNextSub("XIDX");
|
bool newStack = esm.isNextSub("XIDX");
|
||||||
if (newStack)
|
if (newStack)
|
||||||
{
|
{
|
||||||
unsigned int idx;
|
uint32_t idx;
|
||||||
esm.getHT(idx);
|
esm.getHT(idx);
|
||||||
separateStacks = true;
|
separateStacks = true;
|
||||||
item.mCount = 1;
|
item.mCount = 1;
|
||||||
|
@ -40,7 +40,7 @@ namespace ESSImport
|
||||||
bool isDeleted = false;
|
bool isDeleted = false;
|
||||||
item.ESM::CellRef::loadData(esm, isDeleted);
|
item.ESM::CellRef::loadData(esm, isDeleted);
|
||||||
|
|
||||||
int charge = -1;
|
int32_t charge = -1;
|
||||||
esm.getHNOT(charge, "XHLT");
|
esm.getHNOT(charge, "XHLT");
|
||||||
item.mChargeInt = charge;
|
item.mChargeInt = charge;
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ namespace ESSImport
|
||||||
// this is currently not handled properly.
|
// this is currently not handled properly.
|
||||||
|
|
||||||
esm.getSubHeader();
|
esm.getSubHeader();
|
||||||
int itemIndex; // index of the item in the NPCO list
|
int32_t itemIndex; // index of the item in the NPCO list
|
||||||
esm.getT(itemIndex);
|
esm.getT(itemIndex);
|
||||||
|
|
||||||
if (itemIndex < 0 || itemIndex >= int(mItems.size()))
|
if (itemIndex < 0 || itemIndex >= int(mItems.size()))
|
||||||
|
@ -68,7 +68,7 @@ namespace ESSImport
|
||||||
|
|
||||||
// appears to be a relative index for only the *possible* slots this item can be equipped in,
|
// appears to be a relative index for only the *possible* slots this item can be equipped in,
|
||||||
// i.e. 0 most of the time
|
// i.e. 0 most of the time
|
||||||
int slotIndex;
|
int32_t slotIndex;
|
||||||
esm.getT(slotIndex);
|
esm.getT(slotIndex);
|
||||||
|
|
||||||
mItems[itemIndex].mRelativeEquipmentSlot = slotIndex;
|
mItems[itemIndex].mRelativeEquipmentSlot = slotIndex;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef OPENMW_ESSIMPORT_IMPORTINVENTORY_H
|
#ifndef OPENMW_ESSIMPORT_IMPORTINVENTORY_H
|
||||||
#define OPENMW_ESSIMPORT_IMPORTINVENTORY_H
|
#define OPENMW_ESSIMPORT_IMPORTINVENTORY_H
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
@ -19,7 +20,7 @@ namespace ESSImport
|
||||||
|
|
||||||
struct ContItem
|
struct ContItem
|
||||||
{
|
{
|
||||||
int mCount;
|
int32_t mCount;
|
||||||
ESM::NAME32 mItem;
|
ESM::NAME32 mItem;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -28,8 +29,8 @@ namespace ESSImport
|
||||||
struct InventoryItem : public ESM::CellRef
|
struct InventoryItem : public ESM::CellRef
|
||||||
{
|
{
|
||||||
std::string mId;
|
std::string mId;
|
||||||
int mCount;
|
int32_t mCount;
|
||||||
int mRelativeEquipmentSlot;
|
int32_t mRelativeEquipmentSlot;
|
||||||
SCRI mSCRI;
|
SCRI mSCRI;
|
||||||
};
|
};
|
||||||
std::vector<InventoryItem> mItems;
|
std::vector<InventoryItem> mItems;
|
||||||
|
|
|
@ -10,7 +10,7 @@ namespace ESSImport
|
||||||
while (esm.isNextSub("KNAM"))
|
while (esm.isNextSub("KNAM"))
|
||||||
{
|
{
|
||||||
std::string refId = esm.getHString();
|
std::string refId = esm.getHString();
|
||||||
int count;
|
int32_t count;
|
||||||
esm.getHNT(count, "CNAM");
|
esm.getHNT(count, "CNAM");
|
||||||
mKillCounter[refId] = count;
|
mKillCounter[refId] = count;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef OPENMW_ESSIMPORT_KLST_H
|
#ifndef OPENMW_ESSIMPORT_KLST_H
|
||||||
#define OPENMW_ESSIMPORT_KLST_H
|
#define OPENMW_ESSIMPORT_KLST_H
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
@ -18,9 +19,9 @@ namespace ESSImport
|
||||||
void load(ESM::ESMReader& esm);
|
void load(ESM::ESMReader& esm);
|
||||||
|
|
||||||
/// RefId, kill count
|
/// RefId, kill count
|
||||||
std::map<std::string, int> mKillCounter;
|
std::map<std::string, int32_t> mKillCounter;
|
||||||
|
|
||||||
int mWerewolfKills;
|
int32_t mWerewolfKills;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ namespace ESSImport
|
||||||
|
|
||||||
void NPCC::load(ESM::ESMReader& esm)
|
void NPCC::load(ESM::ESMReader& esm)
|
||||||
{
|
{
|
||||||
esm.getHNTSized<8>(mNPDT, "NPDT");
|
esm.getHNT("NPDT", mNPDT.mDisposition, mNPDT.unknown, mNPDT.mReputation, mNPDT.unknown2, mNPDT.mIndex);
|
||||||
|
|
||||||
while (esm.isNextSub("AI_W") || esm.isNextSub("AI_E") || esm.isNextSub("AI_T") || esm.isNextSub("AI_F")
|
while (esm.isNextSub("AI_W") || esm.isNextSub("AI_E") || esm.isNextSub("AI_T") || esm.isNextSub("AI_F")
|
||||||
|| esm.isNextSub("AI_A"))
|
|| esm.isNextSub("AI_A"))
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define OPENMW_ESSIMPORT_NPCC_H
|
#define OPENMW_ESSIMPORT_NPCC_H
|
||||||
|
|
||||||
#include <components/esm3/aipackage.hpp>
|
#include <components/esm3/aipackage.hpp>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
#include "importinventory.hpp"
|
#include "importinventory.hpp"
|
||||||
|
|
||||||
|
@ -21,7 +22,7 @@ namespace ESSImport
|
||||||
unsigned char unknown;
|
unsigned char unknown;
|
||||||
unsigned char mReputation;
|
unsigned char mReputation;
|
||||||
unsigned char unknown2;
|
unsigned char unknown2;
|
||||||
int mIndex;
|
int32_t mIndex;
|
||||||
} mNPDT;
|
} mNPDT;
|
||||||
|
|
||||||
Inventory mInventory;
|
Inventory mInventory;
|
||||||
|
|
|
@ -19,7 +19,12 @@ namespace ESSImport
|
||||||
mMNAM = esm.getHString();
|
mMNAM = esm.getHString();
|
||||||
}
|
}
|
||||||
|
|
||||||
esm.getHNTSized<212>(mPNAM, "PNAM");
|
esm.getHNT("PNAM", mPNAM.mPlayerFlags, mPNAM.mLevelProgress, mPNAM.mSkillProgress, mPNAM.mSkillIncreases,
|
||||||
|
mPNAM.mTelekinesisRangeBonus, mPNAM.mVisionBonus, mPNAM.mDetectKeyMagnitude,
|
||||||
|
mPNAM.mDetectEnchantmentMagnitude, mPNAM.mDetectAnimalMagnitude, mPNAM.mMarkLocation.mX,
|
||||||
|
mPNAM.mMarkLocation.mY, mPNAM.mMarkLocation.mZ, mPNAM.mMarkLocation.mRotZ, mPNAM.mMarkLocation.mCellX,
|
||||||
|
mPNAM.mMarkLocation.mCellY, mPNAM.mUnknown3, mPNAM.mVerticalRotation.mData, mPNAM.mSpecIncreases,
|
||||||
|
mPNAM.mUnknown4);
|
||||||
|
|
||||||
if (esm.isNextSub("SNAM"))
|
if (esm.isNextSub("SNAM"))
|
||||||
esm.skipHSub();
|
esm.skipHSub();
|
||||||
|
@ -50,12 +55,7 @@ namespace ESSImport
|
||||||
if (esm.isNextSub("NAM3"))
|
if (esm.isNextSub("NAM3"))
|
||||||
esm.skipHSub();
|
esm.skipHSub();
|
||||||
|
|
||||||
mHasENAM = false;
|
mHasENAM = esm.getHNOT("ENAM", mENAM.mCellX, mENAM.mCellY);
|
||||||
if (esm.isNextSub("ENAM"))
|
|
||||||
{
|
|
||||||
mHasENAM = true;
|
|
||||||
esm.getHTSized<8>(mENAM);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (esm.isNextSub("LNAM"))
|
if (esm.isNextSub("LNAM"))
|
||||||
esm.skipHSub();
|
esm.skipHSub();
|
||||||
|
@ -63,16 +63,12 @@ namespace ESSImport
|
||||||
while (esm.isNextSub("FNAM"))
|
while (esm.isNextSub("FNAM"))
|
||||||
{
|
{
|
||||||
FNAM fnam;
|
FNAM fnam;
|
||||||
esm.getHTSized<44>(fnam);
|
esm.getHT(
|
||||||
|
fnam.mRank, fnam.mUnknown1, fnam.mReputation, fnam.mFlags, fnam.mUnknown2, fnam.mFactionName.mData);
|
||||||
mFactions.push_back(fnam);
|
mFactions.push_back(fnam);
|
||||||
}
|
}
|
||||||
|
|
||||||
mHasAADT = false;
|
mHasAADT = esm.getHNOT("AADT", mAADT.animGroupIndex, mAADT.mUnknown5); // Attack animation data?
|
||||||
if (esm.isNextSub("AADT")) // Attack animation data?
|
|
||||||
{
|
|
||||||
mHasAADT = true;
|
|
||||||
esm.getHTSized<44>(mAADT);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (esm.isNextSub("KNAM"))
|
if (esm.isNextSub("KNAM"))
|
||||||
esm.skipHSub(); // assigned Quick Keys, I think
|
esm.skipHSub(); // assigned Quick Keys, I think
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef OPENMW_ESSIMPORT_PLAYER_H
|
#ifndef OPENMW_ESSIMPORT_PLAYER_H
|
||||||
#define OPENMW_ESSIMPORT_PLAYER_H
|
#define OPENMW_ESSIMPORT_PLAYER_H
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
@ -17,7 +18,7 @@ namespace ESSImport
|
||||||
/// Other player data
|
/// Other player data
|
||||||
struct PCDT
|
struct PCDT
|
||||||
{
|
{
|
||||||
int mBounty;
|
int32_t mBounty;
|
||||||
std::string mBirthsign;
|
std::string mBirthsign;
|
||||||
|
|
||||||
std::vector<std::string> mKnownDialogueTopics;
|
std::vector<std::string> mKnownDialogueTopics;
|
||||||
|
@ -41,13 +42,11 @@ namespace ESSImport
|
||||||
PlayerFlags_LevitationDisabled = 0x80000
|
PlayerFlags_LevitationDisabled = 0x80000
|
||||||
};
|
};
|
||||||
|
|
||||||
#pragma pack(push)
|
|
||||||
#pragma pack(1)
|
|
||||||
struct FNAM
|
struct FNAM
|
||||||
{
|
{
|
||||||
unsigned char mRank;
|
unsigned char mRank;
|
||||||
unsigned char mUnknown1[3];
|
unsigned char mUnknown1[3];
|
||||||
int mReputation;
|
int32_t mReputation;
|
||||||
unsigned char mFlags; // 0x1: unknown, 0x2: expelled
|
unsigned char mFlags; // 0x1: unknown, 0x2: expelled
|
||||||
unsigned char mUnknown2[3];
|
unsigned char mUnknown2[3];
|
||||||
ESM::NAME32 mFactionName;
|
ESM::NAME32 mFactionName;
|
||||||
|
@ -59,7 +58,7 @@ namespace ESSImport
|
||||||
{
|
{
|
||||||
float mX, mY, mZ; // worldspace position
|
float mX, mY, mZ; // worldspace position
|
||||||
float mRotZ; // Z angle in radians
|
float mRotZ; // Z angle in radians
|
||||||
int mCellX, mCellY; // grid coordinates; for interior cells this is always (0, 0)
|
int32_t mCellX, mCellY; // grid coordinates; for interior cells this is always (0, 0)
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Rotation
|
struct Rotation
|
||||||
|
@ -67,15 +66,15 @@ namespace ESSImport
|
||||||
float mData[3][3];
|
float mData[3][3];
|
||||||
};
|
};
|
||||||
|
|
||||||
int mPlayerFlags; // controls, camera and draw state
|
int32_t mPlayerFlags; // controls, camera and draw state
|
||||||
unsigned int mLevelProgress;
|
uint32_t mLevelProgress;
|
||||||
float mSkillProgress[27]; // skill progress, non-uniform scaled
|
float mSkillProgress[27]; // skill progress, non-uniform scaled
|
||||||
unsigned char mSkillIncreases[8]; // number of skill increases for each attribute
|
unsigned char mSkillIncreases[8]; // number of skill increases for each attribute
|
||||||
int mTelekinesisRangeBonus; // in units; seems redundant
|
int32_t mTelekinesisRangeBonus; // in units; seems redundant
|
||||||
float mVisionBonus; // range: <0.0, 1.0>; affected by light spells and Get/Mod/SetPCVisionBonus
|
float mVisionBonus; // range: <0.0, 1.0>; affected by light spells and Get/Mod/SetPCVisionBonus
|
||||||
int mDetectKeyMagnitude; // seems redundant
|
int32_t mDetectKeyMagnitude; // seems redundant
|
||||||
int mDetectEnchantmentMagnitude; // seems redundant
|
int32_t mDetectEnchantmentMagnitude; // seems redundant
|
||||||
int mDetectAnimalMagnitude; // seems redundant
|
int32_t mDetectAnimalMagnitude; // seems redundant
|
||||||
MarkLocation mMarkLocation;
|
MarkLocation mMarkLocation;
|
||||||
unsigned char mUnknown3[4];
|
unsigned char mUnknown3[4];
|
||||||
Rotation mVerticalRotation;
|
Rotation mVerticalRotation;
|
||||||
|
@ -85,16 +84,15 @@ namespace ESSImport
|
||||||
|
|
||||||
struct ENAM
|
struct ENAM
|
||||||
{
|
{
|
||||||
int mCellX;
|
int32_t mCellX;
|
||||||
int mCellY;
|
int32_t mCellY;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AADT // 44 bytes
|
struct AADT // 44 bytes
|
||||||
{
|
{
|
||||||
int animGroupIndex; // See convertANIS() for the mapping.
|
int32_t animGroupIndex; // See convertANIS() for the mapping.
|
||||||
unsigned char mUnknown5[40];
|
unsigned char mUnknown5[40];
|
||||||
};
|
};
|
||||||
#pragma pack(pop)
|
|
||||||
|
|
||||||
std::vector<FNAM> mFactions;
|
std::vector<FNAM> mFactions;
|
||||||
PNAM mPNAM;
|
PNAM mPNAM;
|
||||||
|
|
|
@ -10,7 +10,9 @@ namespace ESSImport
|
||||||
while (esm.isNextSub("PNAM"))
|
while (esm.isNextSub("PNAM"))
|
||||||
{
|
{
|
||||||
PNAM pnam;
|
PNAM pnam;
|
||||||
esm.getHTSized<184>(pnam);
|
esm.getHT(pnam.mAttackStrength, pnam.mSpeed, pnam.mUnknown, pnam.mFlightTime, pnam.mSplmIndex,
|
||||||
|
pnam.mUnknown2, pnam.mVelocity.mValues, pnam.mPosition.mValues, pnam.mUnknown3, pnam.mActorId.mData,
|
||||||
|
pnam.mArrowId.mData, pnam.mBowId.mData);
|
||||||
mProjectiles.push_back(pnam);
|
mProjectiles.push_back(pnam);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include <components/esm/esmcommon.hpp>
|
#include <components/esm/esmcommon.hpp>
|
||||||
#include <components/esm/util.hpp>
|
#include <components/esm/util.hpp>
|
||||||
|
#include <cstdint>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace ESM
|
namespace ESM
|
||||||
|
@ -16,15 +17,13 @@ namespace ESSImport
|
||||||
struct PROJ
|
struct PROJ
|
||||||
{
|
{
|
||||||
|
|
||||||
#pragma pack(push)
|
|
||||||
#pragma pack(1)
|
|
||||||
struct PNAM // 184 bytes
|
struct PNAM // 184 bytes
|
||||||
{
|
{
|
||||||
float mAttackStrength;
|
float mAttackStrength;
|
||||||
float mSpeed;
|
float mSpeed;
|
||||||
unsigned char mUnknown[4 * 2];
|
unsigned char mUnknown[4 * 2];
|
||||||
float mFlightTime;
|
float mFlightTime;
|
||||||
int mSplmIndex; // reference to a SPLM record (0 for ballistic projectiles)
|
int32_t mSplmIndex; // reference to a SPLM record (0 for ballistic projectiles)
|
||||||
unsigned char mUnknown2[4];
|
unsigned char mUnknown2[4];
|
||||||
ESM::Vector3 mVelocity;
|
ESM::Vector3 mVelocity;
|
||||||
ESM::Vector3 mPosition;
|
ESM::Vector3 mPosition;
|
||||||
|
@ -35,7 +34,6 @@ namespace ESSImport
|
||||||
|
|
||||||
bool isMagic() const { return mSplmIndex != 0; }
|
bool isMagic() const { return mSplmIndex != 0; }
|
||||||
};
|
};
|
||||||
#pragma pack(pop)
|
|
||||||
|
|
||||||
std::vector<PNAM> mProjectiles;
|
std::vector<PNAM> mProjectiles;
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,8 @@ namespace ESSImport
|
||||||
|
|
||||||
void SCPT::load(ESM::ESMReader& esm)
|
void SCPT::load(ESM::ESMReader& esm)
|
||||||
{
|
{
|
||||||
esm.getHNTSized<52>(mSCHD, "SCHD");
|
esm.getHNT("SCHD", mSCHD.mName.mData, mSCHD.mData.mNumShorts, mSCHD.mData.mNumLongs, mSCHD.mData.mNumFloats,
|
||||||
|
mSCHD.mData.mScriptDataSize, mSCHD.mData.mStringTableSize);
|
||||||
|
|
||||||
mSCRI.load(esm);
|
mSCRI.load(esm);
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#include "importscri.hpp"
|
#include "importscri.hpp"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
#include <components/esm/esmcommon.hpp>
|
#include <components/esm/esmcommon.hpp>
|
||||||
#include <components/esm3/loadscpt.hpp>
|
#include <components/esm3/loadscpt.hpp>
|
||||||
|
|
||||||
|
@ -29,7 +31,7 @@ namespace ESSImport
|
||||||
SCRI mSCRI;
|
SCRI mSCRI;
|
||||||
|
|
||||||
bool mRunning;
|
bool mRunning;
|
||||||
int mRefNum; // Targeted reference, -1: no reference
|
int32_t mRefNum; // Targeted reference, -1: no reference
|
||||||
|
|
||||||
void load(ESM::ESMReader& esm);
|
void load(ESM::ESMReader& esm);
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,7 +9,7 @@ namespace ESSImport
|
||||||
{
|
{
|
||||||
mScript = esm.getHNOString("SCRI");
|
mScript = esm.getHNOString("SCRI");
|
||||||
|
|
||||||
int numShorts = 0, numLongs = 0, numFloats = 0;
|
int32_t numShorts = 0, numLongs = 0, numFloats = 0;
|
||||||
if (esm.isNextSub("SLCS"))
|
if (esm.isNextSub("SLCS"))
|
||||||
{
|
{
|
||||||
esm.getSubHeader();
|
esm.getSubHeader();
|
||||||
|
@ -23,7 +23,7 @@ namespace ESSImport
|
||||||
esm.getSubHeader();
|
esm.getSubHeader();
|
||||||
for (int i = 0; i < numShorts; ++i)
|
for (int i = 0; i < numShorts; ++i)
|
||||||
{
|
{
|
||||||
short val;
|
int16_t val;
|
||||||
esm.getT(val);
|
esm.getT(val);
|
||||||
mShorts.push_back(val);
|
mShorts.push_back(val);
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ namespace ESSImport
|
||||||
esm.getSubHeader();
|
esm.getSubHeader();
|
||||||
for (int i = 0; i < numLongs; ++i)
|
for (int i = 0; i < numLongs; ++i)
|
||||||
{
|
{
|
||||||
int val;
|
int32_t val;
|
||||||
esm.getT(val);
|
esm.getT(val);
|
||||||
mLongs.push_back(val);
|
mLongs.push_back(val);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include <components/esm3/variant.hpp>
|
#include <components/esm3/variant.hpp>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace ESM
|
namespace ESM
|
||||||
|
|
|
@ -11,13 +11,15 @@ namespace ESSImport
|
||||||
{
|
{
|
||||||
ActiveSpell spell;
|
ActiveSpell spell;
|
||||||
esm.getHT(spell.mIndex);
|
esm.getHT(spell.mIndex);
|
||||||
esm.getHNTSized<160>(spell.mSPDT, "SPDT");
|
esm.getHNT("SPDT", spell.mSPDT.mType, spell.mSPDT.mId.mData, spell.mSPDT.mUnknown,
|
||||||
|
spell.mSPDT.mCasterId.mData, spell.mSPDT.mSourceId.mData, spell.mSPDT.mUnknown2);
|
||||||
spell.mTarget = esm.getHNOString("TNAM");
|
spell.mTarget = esm.getHNOString("TNAM");
|
||||||
|
|
||||||
while (esm.isNextSub("NPDT"))
|
while (esm.isNextSub("NPDT"))
|
||||||
{
|
{
|
||||||
ActiveEffect effect;
|
ActiveEffect effect;
|
||||||
esm.getHTSized<56>(effect.mNPDT);
|
esm.getHT(effect.mNPDT.mAffectedActorId.mData, effect.mNPDT.mUnknown, effect.mNPDT.mMagnitude,
|
||||||
|
effect.mNPDT.mSecondsActive, effect.mNPDT.mUnknown2);
|
||||||
|
|
||||||
// Effect-specific subrecords can follow:
|
// Effect-specific subrecords can follow:
|
||||||
// - INAM for disintegration and bound effects
|
// - INAM for disintegration and bound effects
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define OPENMW_ESSIMPORT_IMPORTSPLM_H
|
#define OPENMW_ESSIMPORT_IMPORTSPLM_H
|
||||||
|
|
||||||
#include <components/esm/esmcommon.hpp>
|
#include <components/esm/esmcommon.hpp>
|
||||||
|
#include <cstdint>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace ESM
|
namespace ESM
|
||||||
|
@ -15,11 +16,9 @@ namespace ESSImport
|
||||||
struct SPLM
|
struct SPLM
|
||||||
{
|
{
|
||||||
|
|
||||||
#pragma pack(push)
|
|
||||||
#pragma pack(1)
|
|
||||||
struct SPDT // 160 bytes
|
struct SPDT // 160 bytes
|
||||||
{
|
{
|
||||||
int mType; // 1 = spell, 2 = enchantment, 3 = potion
|
int32_t mType; // 1 = spell, 2 = enchantment, 3 = potion
|
||||||
ESM::NAME32 mId; // base ID of a spell/enchantment/potion
|
ESM::NAME32 mId; // base ID of a spell/enchantment/potion
|
||||||
unsigned char mUnknown[4 * 4];
|
unsigned char mUnknown[4 * 4];
|
||||||
ESM::NAME32 mCasterId;
|
ESM::NAME32 mCasterId;
|
||||||
|
@ -31,31 +30,29 @@ namespace ESSImport
|
||||||
{
|
{
|
||||||
ESM::NAME32 mAffectedActorId;
|
ESM::NAME32 mAffectedActorId;
|
||||||
unsigned char mUnknown[4 * 2];
|
unsigned char mUnknown[4 * 2];
|
||||||
int mMagnitude;
|
int32_t mMagnitude;
|
||||||
float mSecondsActive;
|
float mSecondsActive;
|
||||||
unsigned char mUnknown2[4 * 2];
|
unsigned char mUnknown2[4 * 2];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct INAM // 40 bytes
|
struct INAM // 40 bytes
|
||||||
{
|
{
|
||||||
int mUnknown;
|
int32_t mUnknown;
|
||||||
unsigned char mUnknown2;
|
unsigned char mUnknown2;
|
||||||
ESM::FixedString<35> mItemId; // disintegrated item / bound item / item to re-equip after expiration
|
ESM::FixedString<35> mItemId; // disintegrated item / bound item / item to re-equip after expiration
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CNAM // 36 bytes
|
struct CNAM // 36 bytes
|
||||||
{
|
{
|
||||||
int mUnknown; // seems to always be 0
|
int32_t mUnknown; // seems to always be 0
|
||||||
ESM::NAME32 mSummonedOrCommandedActor[32];
|
ESM::NAME32 mSummonedOrCommandedActor[32];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VNAM // 4 bytes
|
struct VNAM // 4 bytes
|
||||||
{
|
{
|
||||||
int mUnknown;
|
int32_t mUnknown;
|
||||||
};
|
};
|
||||||
|
|
||||||
#pragma pack(pop)
|
|
||||||
|
|
||||||
struct ActiveEffect
|
struct ActiveEffect
|
||||||
{
|
{
|
||||||
NPDT mNPDT;
|
NPDT mNPDT;
|
||||||
|
@ -63,7 +60,7 @@ namespace ESSImport
|
||||||
|
|
||||||
struct ActiveSpell
|
struct ActiveSpell
|
||||||
{
|
{
|
||||||
int mIndex;
|
int32_t mIndex;
|
||||||
SPDT mSPDT;
|
SPDT mSPDT;
|
||||||
std::string mTarget;
|
std::string mTarget;
|
||||||
std::vector<ActiveEffect> mActiveEffects;
|
std::vector<ActiveEffect> mActiveEffects;
|
||||||
|
|
|
@ -42,8 +42,8 @@ Allowed options)");
|
||||||
Files::ConfigurationManager cfgManager(true);
|
Files::ConfigurationManager cfgManager(true);
|
||||||
cfgManager.readConfiguration(variables, desc);
|
cfgManager.readConfiguration(variables, desc);
|
||||||
|
|
||||||
const auto essFile = variables["mwsave"].as<Files::MaybeQuotedPath>();
|
const auto& essFile = variables["mwsave"].as<Files::MaybeQuotedPath>();
|
||||||
const auto outputFile = variables["output"].as<Files::MaybeQuotedPath>();
|
const auto& outputFile = variables["output"].as<Files::MaybeQuotedPath>();
|
||||||
std::string encoding = variables["encoding"].as<std::string>();
|
std::string encoding = variables["encoding"].as<std::string>();
|
||||||
|
|
||||||
ESSImport::Importer importer(essFile, outputFile, encoding);
|
ESSImport::Importer importer(essFile, outputFile, encoding);
|
||||||
|
|
|
@ -35,13 +35,12 @@ set(LAUNCHER_HEADER
|
||||||
|
|
||||||
# Headers that must be pre-processed
|
# Headers that must be pre-processed
|
||||||
set(LAUNCHER_UI
|
set(LAUNCHER_UI
|
||||||
${CMAKE_SOURCE_DIR}/files/ui/datafilespage.ui
|
${CMAKE_CURRENT_SOURCE_DIR}/ui/datafilespage.ui
|
||||||
${CMAKE_SOURCE_DIR}/files/ui/graphicspage.ui
|
${CMAKE_CURRENT_SOURCE_DIR}/ui/graphicspage.ui
|
||||||
${CMAKE_SOURCE_DIR}/files/ui/mainwindow.ui
|
${CMAKE_CURRENT_SOURCE_DIR}/ui/mainwindow.ui
|
||||||
${CMAKE_SOURCE_DIR}/files/ui/contentselector.ui
|
${CMAKE_CURRENT_SOURCE_DIR}/ui/importpage.ui
|
||||||
${CMAKE_SOURCE_DIR}/files/ui/importpage.ui
|
${CMAKE_CURRENT_SOURCE_DIR}/ui/settingspage.ui
|
||||||
${CMAKE_SOURCE_DIR}/files/ui/settingspage.ui
|
${CMAKE_CURRENT_SOURCE_DIR}/ui/directorypicker.ui
|
||||||
${CMAKE_SOURCE_DIR}/files/ui/directorypicker.ui
|
|
||||||
)
|
)
|
||||||
|
|
||||||
source_group(launcher FILES ${LAUNCHER} ${LAUNCHER_HEADER})
|
source_group(launcher FILES ${LAUNCHER} ${LAUNCHER_HEADER})
|
||||||
|
@ -77,7 +76,7 @@ if (WIN32)
|
||||||
endif (WIN32)
|
endif (WIN32)
|
||||||
|
|
||||||
target_link_libraries(openmw-launcher
|
target_link_libraries(openmw-launcher
|
||||||
${SDL2_LIBRARY_ONLY}
|
SDL2::SDL2
|
||||||
${OPENAL_LIBRARY}
|
${OPENAL_LIBRARY}
|
||||||
components_qt
|
components_qt
|
||||||
)
|
)
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
#include <components/files/qtconversion.hpp>
|
#include <components/files/qtconversion.hpp>
|
||||||
#include <components/misc/strings/conversion.hpp>
|
#include <components/misc/strings/conversion.hpp>
|
||||||
#include <components/navmeshtool/protocol.hpp>
|
#include <components/navmeshtool/protocol.hpp>
|
||||||
#include <components/settings/settings.hpp>
|
#include <components/settings/values.hpp>
|
||||||
#include <components/vfs/bsaarchive.hpp>
|
#include <components/vfs/bsaarchive.hpp>
|
||||||
|
|
||||||
#include "utils/profilescombobox.hpp"
|
#include "utils/profilescombobox.hpp"
|
||||||
|
@ -123,7 +123,7 @@ namespace Launcher
|
||||||
|
|
||||||
int getMaxNavMeshDbFileSizeMiB()
|
int getMaxNavMeshDbFileSizeMiB()
|
||||||
{
|
{
|
||||||
return Settings::Manager::getUInt64("max navmeshdb file size", "Navigator") / (1024 * 1024);
|
return Settings::navigator().mMaxNavmeshdbFileSize / (1024 * 1024);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<QString> findFirstPath(const QStringList& directories, const QString& fileName)
|
std::optional<QString> findFirstPath(const QStringList& directories, const QString& fileName)
|
||||||
|
@ -164,11 +164,14 @@ Launcher::DataFilesPage::DataFilesPage(const Files::ConfigurationManager& cfg, C
|
||||||
const QString encoding = mGameSettings.value("encoding", "win1252");
|
const QString encoding = mGameSettings.value("encoding", "win1252");
|
||||||
mSelector->setEncoding(encoding);
|
mSelector->setEncoding(encoding);
|
||||||
|
|
||||||
QStringList languages;
|
QVector<std::pair<QString, QString>> languages = { { "English", tr("English") }, { "French", tr("French") },
|
||||||
languages << tr("English") << tr("French") << tr("German") << tr("Italian") << tr("Polish") << tr("Russian")
|
{ "German", tr("German") }, { "Italian", tr("Italian") }, { "Polish", tr("Polish") },
|
||||||
<< tr("Spanish");
|
{ "Russian", tr("Russian") }, { "Spanish", tr("Spanish") } };
|
||||||
|
|
||||||
mSelector->languageBox()->addItems(languages);
|
for (auto lang : languages)
|
||||||
|
{
|
||||||
|
mSelector->languageBox()->addItem(lang.second, lang.first);
|
||||||
|
}
|
||||||
|
|
||||||
mNewProfileDialog = new TextInputDialog(tr("New Content List"), tr("Content List name:"), this);
|
mNewProfileDialog = new TextInputDialog(tr("New Content List"), tr("Content List name:"), this);
|
||||||
mCloneProfileDialog = new TextInputDialog(tr("Clone Content List"), tr("Content List name:"), this);
|
mCloneProfileDialog = new TextInputDialog(tr("Clone Content List"), tr("Content List name:"), this);
|
||||||
|
@ -254,9 +257,17 @@ bool Launcher::DataFilesPage::loadSettings()
|
||||||
if (!currentProfile.isEmpty())
|
if (!currentProfile.isEmpty())
|
||||||
addProfile(currentProfile, true);
|
addProfile(currentProfile, true);
|
||||||
|
|
||||||
const int index = mSelector->languageBox()->findText(mLauncherSettings.getLanguage());
|
auto language = mLauncherSettings.getLanguage();
|
||||||
if (index != -1)
|
|
||||||
mSelector->languageBox()->setCurrentIndex(index);
|
for (int i = 0; i < mSelector->languageBox()->count(); ++i)
|
||||||
|
{
|
||||||
|
QString languageItem = mSelector->languageBox()->itemData(i).toString();
|
||||||
|
if (language == languageItem)
|
||||||
|
{
|
||||||
|
mSelector->languageBox()->setCurrentIndex(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -301,12 +312,14 @@ void Launcher::DataFilesPage::populateFileViews(const QString& contentModelName)
|
||||||
auto row = ui.directoryListWidget->count() - 1;
|
auto row = ui.directoryListWidget->count() - 1;
|
||||||
auto* item = ui.directoryListWidget->item(row);
|
auto* item = ui.directoryListWidget->item(row);
|
||||||
|
|
||||||
// Display new content with green background
|
// Display new content with custom formatting
|
||||||
if (mNewDataDirs.contains(canonicalDirPath))
|
if (mNewDataDirs.contains(canonicalDirPath))
|
||||||
{
|
{
|
||||||
tooltip += "Will be added to the current profile\n";
|
tooltip += "Will be added to the current profile\n";
|
||||||
item->setBackground(Qt::green);
|
QFont font = item->font();
|
||||||
item->setForeground(Qt::black);
|
font.setBold(true);
|
||||||
|
font.setItalic(true);
|
||||||
|
item->setFont(font);
|
||||||
}
|
}
|
||||||
|
|
||||||
// deactivate data-local and global data directory: they are always included
|
// deactivate data-local and global data directory: they are always included
|
||||||
|
@ -359,9 +372,8 @@ void Launcher::DataFilesPage::populateFileViews(const QString& contentModelName)
|
||||||
|
|
||||||
void Launcher::DataFilesPage::saveSettings(const QString& profile)
|
void Launcher::DataFilesPage::saveSettings(const QString& profile)
|
||||||
{
|
{
|
||||||
if (const int value = ui.navMeshMaxSizeSpinBox->value(); value != getMaxNavMeshDbFileSizeMiB())
|
Settings::navigator().mMaxNavmeshdbFileSize.set(
|
||||||
Settings::Manager::setUInt64(
|
static_cast<std::uint64_t>(std::max(0, ui.navMeshMaxSizeSpinBox->value())) * 1024 * 1024);
|
||||||
"max navmeshdb file size", "Navigator", static_cast<std::uint64_t>(std::max(0, value)) * 1024 * 1024);
|
|
||||||
|
|
||||||
QString profileName = profile;
|
QString profileName = profile;
|
||||||
|
|
||||||
|
@ -385,7 +397,7 @@ void Launcher::DataFilesPage::saveSettings(const QString& profile)
|
||||||
mLauncherSettings.setContentList(profileName, dirList, selectedArchivePaths(), fileNames);
|
mLauncherSettings.setContentList(profileName, dirList, selectedArchivePaths(), fileNames);
|
||||||
mGameSettings.setContentList(dirList, selectedArchivePaths(), fileNames);
|
mGameSettings.setContentList(dirList, selectedArchivePaths(), fileNames);
|
||||||
|
|
||||||
QString language(mSelector->languageBox()->currentText());
|
QString language(mSelector->languageBox()->currentData().toString());
|
||||||
|
|
||||||
mLauncherSettings.setLanguage(language);
|
mLauncherSettings.setLanguage(language);
|
||||||
|
|
||||||
|
@ -738,8 +750,11 @@ void Launcher::DataFilesPage::addArchive(const QString& name, Qt::CheckState sel
|
||||||
ui.archiveListWidget->item(row)->setCheckState(selected);
|
ui.archiveListWidget->item(row)->setCheckState(selected);
|
||||||
if (mKnownArchives.filter(name).isEmpty()) // XXX why contains doesn't work here ???
|
if (mKnownArchives.filter(name).isEmpty()) // XXX why contains doesn't work here ???
|
||||||
{
|
{
|
||||||
ui.archiveListWidget->item(row)->setBackground(Qt::green);
|
auto item = ui.archiveListWidget->item(row);
|
||||||
ui.archiveListWidget->item(row)->setForeground(Qt::black);
|
QFont font = item->font();
|
||||||
|
font.setBold(true);
|
||||||
|
font.setItalic(true);
|
||||||
|
item->setFont(font);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include "sdlinit.hpp"
|
#include "sdlinit.hpp"
|
||||||
|
|
||||||
|
#include <components/misc/display.hpp>
|
||||||
#include <components/settings/values.hpp>
|
#include <components/settings/values.hpp>
|
||||||
|
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
@ -16,22 +17,6 @@
|
||||||
#include <SDL_video.h>
|
#include <SDL_video.h>
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <numeric>
|
|
||||||
|
|
||||||
QString getAspect(int x, int y)
|
|
||||||
{
|
|
||||||
int gcd = std::gcd(x, y);
|
|
||||||
if (gcd == 0)
|
|
||||||
return QString();
|
|
||||||
|
|
||||||
int xaspect = x / gcd;
|
|
||||||
int yaspect = y / gcd;
|
|
||||||
// special case: 8 : 5 is usually referred to as 16:10
|
|
||||||
if (xaspect == 8 && yaspect == 5)
|
|
||||||
return QString("16:10");
|
|
||||||
|
|
||||||
return QString(QString::number(xaspect) + ":" + QString::number(yaspect));
|
|
||||||
}
|
|
||||||
|
|
||||||
Launcher::GraphicsPage::GraphicsPage(QWidget* parent)
|
Launcher::GraphicsPage::GraphicsPage(QWidget* parent)
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
|
@ -96,32 +81,29 @@ bool Launcher::GraphicsPage::loadSettings()
|
||||||
|
|
||||||
// Visuals
|
// Visuals
|
||||||
|
|
||||||
int vsync = Settings::Manager::getInt("vsync mode", "Video");
|
const int vsync = Settings::video().mVsyncMode;
|
||||||
if (vsync < 0 || vsync > 2)
|
|
||||||
vsync = 0;
|
|
||||||
|
|
||||||
vSyncComboBox->setCurrentIndex(vsync);
|
vSyncComboBox->setCurrentIndex(vsync);
|
||||||
|
|
||||||
size_t windowMode = static_cast<size_t>(Settings::Manager::getInt("window mode", "Video"));
|
const Settings::WindowMode windowMode = Settings::video().mWindowMode;
|
||||||
if (windowMode > static_cast<size_t>(Settings::WindowMode::Windowed))
|
|
||||||
windowMode = 0;
|
|
||||||
windowModeComboBox->setCurrentIndex(windowMode);
|
|
||||||
slotFullScreenChanged(windowMode);
|
|
||||||
|
|
||||||
if (Settings::Manager::getBool("window border", "Video"))
|
windowModeComboBox->setCurrentIndex(static_cast<int>(windowMode));
|
||||||
|
handleWindowModeChange(windowMode);
|
||||||
|
|
||||||
|
if (Settings::video().mWindowBorder)
|
||||||
windowBorderCheckBox->setCheckState(Qt::Checked);
|
windowBorderCheckBox->setCheckState(Qt::Checked);
|
||||||
|
|
||||||
// aaValue is the actual value (0, 1, 2, 4, 8, 16)
|
// aaValue is the actual value (0, 1, 2, 4, 8, 16)
|
||||||
int aaValue = Settings::Manager::getInt("antialiasing", "Video");
|
const int aaValue = Settings::video().mAntialiasing;
|
||||||
// aaIndex is the index into the allowed values in the pull down.
|
// aaIndex is the index into the allowed values in the pull down.
|
||||||
int aaIndex = antiAliasingComboBox->findText(QString::number(aaValue));
|
const int aaIndex = antiAliasingComboBox->findText(QString::number(aaValue));
|
||||||
if (aaIndex != -1)
|
if (aaIndex != -1)
|
||||||
antiAliasingComboBox->setCurrentIndex(aaIndex);
|
antiAliasingComboBox->setCurrentIndex(aaIndex);
|
||||||
|
|
||||||
int width = Settings::Manager::getInt("resolution x", "Video");
|
const int width = Settings::video().mResolutionX;
|
||||||
int height = Settings::Manager::getInt("resolution y", "Video");
|
const int height = Settings::video().mResolutionY;
|
||||||
QString resolution = QString::number(width) + QString(" x ") + QString::number(height);
|
QString resolution = QString::number(width) + QString(" × ") + QString::number(height);
|
||||||
screenComboBox->setCurrentIndex(Settings::Manager::getInt("screen", "Video"));
|
screenComboBox->setCurrentIndex(Settings::video().mScreen);
|
||||||
|
|
||||||
int resIndex = resolutionComboBox->findText(resolution, Qt::MatchStartsWith);
|
int resIndex = resolutionComboBox->findText(resolution, Qt::MatchStartsWith);
|
||||||
|
|
||||||
|
@ -137,7 +119,7 @@ bool Launcher::GraphicsPage::loadSettings()
|
||||||
customHeightSpinBox->setValue(height);
|
customHeightSpinBox->setValue(height);
|
||||||
}
|
}
|
||||||
|
|
||||||
float fpsLimit = Settings::Manager::getFloat("framerate limit", "Video");
|
const float fpsLimit = Settings::video().mFramerateLimit;
|
||||||
if (fpsLimit != 0)
|
if (fpsLimit != 0)
|
||||||
{
|
{
|
||||||
framerateLimitCheckBox->setCheckState(Qt::Checked);
|
framerateLimitCheckBox->setCheckState(Qt::Checked);
|
||||||
|
@ -161,32 +143,37 @@ bool Launcher::GraphicsPage::loadSettings()
|
||||||
lightingMethodComboBox->setCurrentIndex(lightingMethod);
|
lightingMethodComboBox->setCurrentIndex(lightingMethod);
|
||||||
|
|
||||||
// Shadows
|
// Shadows
|
||||||
if (Settings::Manager::getBool("actor shadows", "Shadows"))
|
if (Settings::shadows().mActorShadows)
|
||||||
actorShadowsCheckBox->setCheckState(Qt::Checked);
|
actorShadowsCheckBox->setCheckState(Qt::Checked);
|
||||||
if (Settings::Manager::getBool("player shadows", "Shadows"))
|
if (Settings::shadows().mPlayerShadows)
|
||||||
playerShadowsCheckBox->setCheckState(Qt::Checked);
|
playerShadowsCheckBox->setCheckState(Qt::Checked);
|
||||||
if (Settings::Manager::getBool("terrain shadows", "Shadows"))
|
if (Settings::shadows().mTerrainShadows)
|
||||||
terrainShadowsCheckBox->setCheckState(Qt::Checked);
|
terrainShadowsCheckBox->setCheckState(Qt::Checked);
|
||||||
if (Settings::Manager::getBool("object shadows", "Shadows"))
|
if (Settings::shadows().mObjectShadows)
|
||||||
objectShadowsCheckBox->setCheckState(Qt::Checked);
|
objectShadowsCheckBox->setCheckState(Qt::Checked);
|
||||||
if (Settings::Manager::getBool("enable indoor shadows", "Shadows"))
|
if (Settings::shadows().mEnableIndoorShadows)
|
||||||
indoorShadowsCheckBox->setCheckState(Qt::Checked);
|
indoorShadowsCheckBox->setCheckState(Qt::Checked);
|
||||||
|
|
||||||
shadowComputeSceneBoundsComboBox->setCurrentIndex(shadowComputeSceneBoundsComboBox->findText(
|
auto boundMethod = Settings::shadows().mComputeSceneBounds.get();
|
||||||
QString(tr(Settings::Manager::getString("compute scene bounds", "Shadows").c_str()))));
|
if (boundMethod == "bounds")
|
||||||
|
shadowComputeSceneBoundsComboBox->setCurrentIndex(0);
|
||||||
|
else if (boundMethod == "primitives")
|
||||||
|
shadowComputeSceneBoundsComboBox->setCurrentIndex(1);
|
||||||
|
else
|
||||||
|
shadowComputeSceneBoundsComboBox->setCurrentIndex(2);
|
||||||
|
|
||||||
int shadowDistLimit = Settings::Manager::getInt("maximum shadow map distance", "Shadows");
|
const int shadowDistLimit = Settings::shadows().mMaximumShadowMapDistance;
|
||||||
if (shadowDistLimit > 0)
|
if (shadowDistLimit > 0)
|
||||||
{
|
{
|
||||||
shadowDistanceCheckBox->setCheckState(Qt::Checked);
|
shadowDistanceCheckBox->setCheckState(Qt::Checked);
|
||||||
shadowDistanceSpinBox->setValue(shadowDistLimit);
|
shadowDistanceSpinBox->setValue(shadowDistLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
float shadowFadeStart = Settings::Manager::getFloat("shadow fade start", "Shadows");
|
const float shadowFadeStart = Settings::shadows().mShadowFadeStart;
|
||||||
if (shadowFadeStart != 0)
|
if (shadowFadeStart != 0)
|
||||||
fadeStartSpinBox->setValue(shadowFadeStart);
|
fadeStartSpinBox->setValue(shadowFadeStart);
|
||||||
|
|
||||||
int shadowRes = Settings::Manager::getInt("shadow map resolution", "Shadows");
|
const int shadowRes = Settings::shadows().mShadowMapResolution;
|
||||||
int shadowResIndex = shadowResolutionComboBox->findText(QString::number(shadowRes));
|
int shadowResIndex = shadowResolutionComboBox->findText(QString::number(shadowRes));
|
||||||
if (shadowResIndex != -1)
|
if (shadowResIndex != -1)
|
||||||
shadowResolutionComboBox->setCurrentIndex(shadowResIndex);
|
shadowResolutionComboBox->setCurrentIndex(shadowResIndex);
|
||||||
|
@ -198,29 +185,16 @@ void Launcher::GraphicsPage::saveSettings()
|
||||||
{
|
{
|
||||||
// Visuals
|
// Visuals
|
||||||
|
|
||||||
// Ensure we only set the new settings if they changed. This is to avoid cluttering the
|
Settings::video().mVsyncMode.set(static_cast<SDLUtil::VSyncMode>(vSyncComboBox->currentIndex()));
|
||||||
// user settings file (which by definition should only contain settings the user has touched)
|
Settings::video().mWindowMode.set(static_cast<Settings::WindowMode>(windowModeComboBox->currentIndex()));
|
||||||
int cVSync = vSyncComboBox->currentIndex();
|
Settings::video().mWindowBorder.set(windowBorderCheckBox->checkState() == Qt::Checked);
|
||||||
if (cVSync != Settings::Manager::getInt("vsync mode", "Video"))
|
Settings::video().mAntialiasing.set(antiAliasingComboBox->currentText().toInt());
|
||||||
Settings::Manager::setInt("vsync mode", "Video", cVSync);
|
|
||||||
|
|
||||||
int cWindowMode = windowModeComboBox->currentIndex();
|
|
||||||
if (cWindowMode != Settings::Manager::getInt("window mode", "Video"))
|
|
||||||
Settings::Manager::setInt("window mode", "Video", cWindowMode);
|
|
||||||
|
|
||||||
bool cWindowBorder = windowBorderCheckBox->checkState();
|
|
||||||
if (cWindowBorder != Settings::Manager::getBool("window border", "Video"))
|
|
||||||
Settings::Manager::setBool("window border", "Video", cWindowBorder);
|
|
||||||
|
|
||||||
int cAAValue = antiAliasingComboBox->currentText().toInt();
|
|
||||||
if (cAAValue != Settings::Manager::getInt("antialiasing", "Video"))
|
|
||||||
Settings::Manager::setInt("antialiasing", "Video", cAAValue);
|
|
||||||
|
|
||||||
int cWidth = 0;
|
int cWidth = 0;
|
||||||
int cHeight = 0;
|
int cHeight = 0;
|
||||||
if (standardRadioButton->isChecked())
|
if (standardRadioButton->isChecked())
|
||||||
{
|
{
|
||||||
QRegularExpression resolutionRe("^(\\d+) x (\\d+)");
|
QRegularExpression resolutionRe("^(\\d+) × (\\d+)");
|
||||||
QRegularExpressionMatch match = resolutionRe.match(resolutionComboBox->currentText().simplified());
|
QRegularExpressionMatch match = resolutionRe.match(resolutionComboBox->currentText().simplified());
|
||||||
if (match.hasMatch())
|
if (match.hasMatch())
|
||||||
{
|
{
|
||||||
|
@ -234,25 +208,17 @@ void Launcher::GraphicsPage::saveSettings()
|
||||||
cHeight = customHeightSpinBox->value();
|
cHeight = customHeightSpinBox->value();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cWidth != Settings::Manager::getInt("resolution x", "Video"))
|
Settings::video().mResolutionX.set(cWidth);
|
||||||
Settings::Manager::setInt("resolution x", "Video", cWidth);
|
Settings::video().mResolutionY.set(cHeight);
|
||||||
|
Settings::video().mScreen.set(screenComboBox->currentIndex());
|
||||||
if (cHeight != Settings::Manager::getInt("resolution y", "Video"))
|
|
||||||
Settings::Manager::setInt("resolution y", "Video", cHeight);
|
|
||||||
|
|
||||||
int cScreen = screenComboBox->currentIndex();
|
|
||||||
if (cScreen != Settings::Manager::getInt("screen", "Video"))
|
|
||||||
Settings::Manager::setInt("screen", "Video", cScreen);
|
|
||||||
|
|
||||||
if (framerateLimitCheckBox->checkState() != Qt::Unchecked)
|
if (framerateLimitCheckBox->checkState() != Qt::Unchecked)
|
||||||
{
|
{
|
||||||
float cFpsLimit = framerateLimitSpinBox->value();
|
Settings::video().mFramerateLimit.set(framerateLimitSpinBox->value());
|
||||||
if (cFpsLimit != Settings::Manager::getFloat("framerate limit", "Video"))
|
|
||||||
Settings::Manager::setFloat("framerate limit", "Video", cFpsLimit);
|
|
||||||
}
|
}
|
||||||
else if (Settings::Manager::getFloat("framerate limit", "Video") != 0)
|
else if (Settings::video().mFramerateLimit != 0)
|
||||||
{
|
{
|
||||||
Settings::Manager::setFloat("framerate limit", "Video", 0);
|
Settings::video().mFramerateLimit.set(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lighting
|
// Lighting
|
||||||
|
@ -264,55 +230,43 @@ void Launcher::GraphicsPage::saveSettings()
|
||||||
Settings::shaders().mLightingMethod.set(lightingMethodMap[lightingMethodComboBox->currentIndex()]);
|
Settings::shaders().mLightingMethod.set(lightingMethodMap[lightingMethodComboBox->currentIndex()]);
|
||||||
|
|
||||||
// Shadows
|
// Shadows
|
||||||
int cShadowDist = shadowDistanceCheckBox->checkState() != Qt::Unchecked ? shadowDistanceSpinBox->value() : 0;
|
const int cShadowDist = shadowDistanceCheckBox->checkState() != Qt::Unchecked ? shadowDistanceSpinBox->value() : 0;
|
||||||
if (Settings::Manager::getInt("maximum shadow map distance", "Shadows") != cShadowDist)
|
Settings::shadows().mMaximumShadowMapDistance.set(cShadowDist);
|
||||||
Settings::Manager::setInt("maximum shadow map distance", "Shadows", cShadowDist);
|
const float cFadeStart = fadeStartSpinBox->value();
|
||||||
float cFadeStart = fadeStartSpinBox->value();
|
if (cShadowDist > 0)
|
||||||
if (cShadowDist > 0 && Settings::Manager::getFloat("shadow fade start", "Shadows") != cFadeStart)
|
Settings::shadows().mShadowFadeStart.set(cFadeStart);
|
||||||
Settings::Manager::setFloat("shadow fade start", "Shadows", cFadeStart);
|
|
||||||
|
|
||||||
bool cActorShadows = actorShadowsCheckBox->checkState();
|
const bool cActorShadows = actorShadowsCheckBox->checkState() != Qt::Unchecked;
|
||||||
bool cObjectShadows = objectShadowsCheckBox->checkState();
|
const bool cObjectShadows = objectShadowsCheckBox->checkState() != Qt::Unchecked;
|
||||||
bool cTerrainShadows = terrainShadowsCheckBox->checkState();
|
const bool cTerrainShadows = terrainShadowsCheckBox->checkState() != Qt::Unchecked;
|
||||||
bool cPlayerShadows = playerShadowsCheckBox->checkState();
|
const bool cPlayerShadows = playerShadowsCheckBox->checkState() != Qt::Unchecked;
|
||||||
if (cActorShadows || cObjectShadows || cTerrainShadows || cPlayerShadows)
|
if (cActorShadows || cObjectShadows || cTerrainShadows || cPlayerShadows)
|
||||||
{
|
{
|
||||||
if (!Settings::Manager::getBool("enable shadows", "Shadows"))
|
Settings::shadows().mEnableShadows.set(true);
|
||||||
Settings::Manager::setBool("enable shadows", "Shadows", true);
|
Settings::shadows().mActorShadows.set(cActorShadows);
|
||||||
if (Settings::Manager::getBool("actor shadows", "Shadows") != cActorShadows)
|
Settings::shadows().mPlayerShadows.set(cPlayerShadows);
|
||||||
Settings::Manager::setBool("actor shadows", "Shadows", cActorShadows);
|
Settings::shadows().mObjectShadows.set(cObjectShadows);
|
||||||
if (Settings::Manager::getBool("player shadows", "Shadows") != cPlayerShadows)
|
Settings::shadows().mTerrainShadows.set(cTerrainShadows);
|
||||||
Settings::Manager::setBool("player shadows", "Shadows", cPlayerShadows);
|
|
||||||
if (Settings::Manager::getBool("object shadows", "Shadows") != cObjectShadows)
|
|
||||||
Settings::Manager::setBool("object shadows", "Shadows", cObjectShadows);
|
|
||||||
if (Settings::Manager::getBool("terrain shadows", "Shadows") != cTerrainShadows)
|
|
||||||
Settings::Manager::setBool("terrain shadows", "Shadows", cTerrainShadows);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (Settings::Manager::getBool("enable shadows", "Shadows"))
|
Settings::shadows().mEnableShadows.set(false);
|
||||||
Settings::Manager::setBool("enable shadows", "Shadows", false);
|
Settings::shadows().mActorShadows.set(false);
|
||||||
if (Settings::Manager::getBool("actor shadows", "Shadows"))
|
Settings::shadows().mPlayerShadows.set(false);
|
||||||
Settings::Manager::setBool("actor shadows", "Shadows", false);
|
Settings::shadows().mObjectShadows.set(false);
|
||||||
if (Settings::Manager::getBool("player shadows", "Shadows"))
|
Settings::shadows().mTerrainShadows.set(false);
|
||||||
Settings::Manager::setBool("player shadows", "Shadows", false);
|
|
||||||
if (Settings::Manager::getBool("object shadows", "Shadows"))
|
|
||||||
Settings::Manager::setBool("object shadows", "Shadows", false);
|
|
||||||
if (Settings::Manager::getBool("terrain shadows", "Shadows"))
|
|
||||||
Settings::Manager::setBool("terrain shadows", "Shadows", false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cIndoorShadows = indoorShadowsCheckBox->checkState();
|
Settings::shadows().mEnableIndoorShadows.set(indoorShadowsCheckBox->checkState() != Qt::Unchecked);
|
||||||
if (Settings::Manager::getBool("enable indoor shadows", "Shadows") != cIndoorShadows)
|
Settings::shadows().mShadowMapResolution.set(shadowResolutionComboBox->currentText().toInt());
|
||||||
Settings::Manager::setBool("enable indoor shadows", "Shadows", cIndoorShadows);
|
|
||||||
|
|
||||||
int cShadowRes = shadowResolutionComboBox->currentText().toInt();
|
auto index = shadowComputeSceneBoundsComboBox->currentIndex();
|
||||||
if (cShadowRes != Settings::Manager::getInt("shadow map resolution", "Shadows"))
|
if (index == 0)
|
||||||
Settings::Manager::setInt("shadow map resolution", "Shadows", cShadowRes);
|
Settings::shadows().mComputeSceneBounds.set("bounds");
|
||||||
|
else if (index == 1)
|
||||||
auto cComputeSceneBounds = shadowComputeSceneBoundsComboBox->currentText().toStdString();
|
Settings::shadows().mComputeSceneBounds.set("primitives");
|
||||||
if (cComputeSceneBounds != Settings::Manager::getString("compute scene bounds", "Shadows"))
|
else
|
||||||
Settings::Manager::setString("compute scene bounds", "Shadows", cComputeSceneBounds);
|
Settings::shadows().mComputeSceneBounds.set("none");
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList Launcher::GraphicsPage::getAvailableResolutions(int screen)
|
QStringList Launcher::GraphicsPage::getAvailableResolutions(int screen)
|
||||||
|
@ -347,19 +301,8 @@ QStringList Launcher::GraphicsPage::getAvailableResolutions(int screen)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString resolution = QString::number(mode.w) + QString(" x ") + QString::number(mode.h);
|
auto str = Misc::getResolutionText(mode.w, mode.h, "%i × %i (%i:%i)");
|
||||||
|
result.append(QString(str.c_str()));
|
||||||
QString aspect = getAspect(mode.w, mode.h);
|
|
||||||
if (aspect == QLatin1String("16:9") || aspect == QLatin1String("16:10"))
|
|
||||||
{
|
|
||||||
resolution.append(tr("\t(Wide ") + aspect + ")");
|
|
||||||
}
|
|
||||||
else if (aspect == QLatin1String("4:3"))
|
|
||||||
{
|
|
||||||
resolution.append(tr("\t(Standard 4:3)"));
|
|
||||||
}
|
|
||||||
|
|
||||||
result.append(resolution);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result.removeDuplicates();
|
result.removeDuplicates();
|
||||||
|
@ -392,8 +335,12 @@ void Launcher::GraphicsPage::screenChanged(int screen)
|
||||||
|
|
||||||
void Launcher::GraphicsPage::slotFullScreenChanged(int mode)
|
void Launcher::GraphicsPage::slotFullScreenChanged(int mode)
|
||||||
{
|
{
|
||||||
if (mode == static_cast<int>(Settings::WindowMode::Fullscreen)
|
handleWindowModeChange(static_cast<Settings::WindowMode>(mode));
|
||||||
|| mode == static_cast<int>(Settings::WindowMode::WindowedFullscreen))
|
}
|
||||||
|
|
||||||
|
void Launcher::GraphicsPage::handleWindowModeChange(Settings::WindowMode mode)
|
||||||
|
{
|
||||||
|
if (mode == Settings::WindowMode::Fullscreen || mode == Settings::WindowMode::WindowedFullscreen)
|
||||||
{
|
{
|
||||||
standardRadioButton->toggle();
|
standardRadioButton->toggle();
|
||||||
customRadioButton->setEnabled(false);
|
customRadioButton->setEnabled(false);
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
#include "ui_graphicspage.h"
|
#include "ui_graphicspage.h"
|
||||||
|
|
||||||
#include <components/settings/settings.hpp>
|
#include <components/settings/windowmode.hpp>
|
||||||
|
|
||||||
namespace Files
|
namespace Files
|
||||||
{
|
{
|
||||||
|
@ -40,6 +40,7 @@ namespace Launcher
|
||||||
static QRect getMaximumResolution();
|
static QRect getMaximumResolution();
|
||||||
|
|
||||||
bool setupSDL();
|
bool setupSDL();
|
||||||
|
void handleWindowModeChange(Settings::WindowMode state);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -104,9 +104,9 @@ void Launcher::ImportPage::on_importerButton_clicked()
|
||||||
msgBox.setIcon(QMessageBox::Critical);
|
msgBox.setIcon(QMessageBox::Critical);
|
||||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||||
msgBox.setText(
|
msgBox.setText(
|
||||||
tr("<html><head/><body><p><b>Could not open or create %1 for writing </b></p> \
|
tr("<html><head/><body><p><b>Could not open or create %1 for writing </b></p>"
|
||||||
<p>Please make sure you have the right permissions \
|
"<p>Please make sure you have the right permissions "
|
||||||
and try again.</p></body></html>")
|
"and try again.</p></body></html>")
|
||||||
.arg(file.fileName()));
|
.arg(file.fileName()));
|
||||||
msgBox.exec();
|
msgBox.exec();
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -1,13 +1,5 @@
|
||||||
#include "maindialog.hpp"
|
#include "maindialog.hpp"
|
||||||
|
|
||||||
#include <components/debug/debuglog.hpp>
|
|
||||||
#include <components/files/configurationmanager.hpp>
|
|
||||||
#include <components/files/conversion.hpp>
|
|
||||||
#include <components/files/qtconversion.hpp>
|
|
||||||
#include <components/misc/helpviewer.hpp>
|
|
||||||
#include <components/misc/utf8qtextstream.hpp>
|
|
||||||
#include <components/version/version.hpp>
|
|
||||||
|
|
||||||
#include <QCloseEvent>
|
#include <QCloseEvent>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
@ -15,10 +7,15 @@
|
||||||
#include <QTime>
|
#include <QTime>
|
||||||
|
|
||||||
#include <components/debug/debugging.hpp>
|
#include <components/debug/debugging.hpp>
|
||||||
|
#include <components/debug/debuglog.hpp>
|
||||||
|
#include <components/files/configurationmanager.hpp>
|
||||||
#include <components/files/conversion.hpp>
|
#include <components/files/conversion.hpp>
|
||||||
#include <components/files/qtconfigpath.hpp>
|
#include <components/files/qtconfigpath.hpp>
|
||||||
#include <components/files/qtconversion.hpp>
|
#include <components/files/qtconversion.hpp>
|
||||||
|
#include <components/misc/helpviewer.hpp>
|
||||||
#include <components/misc/utf8qtextstream.hpp>
|
#include <components/misc/utf8qtextstream.hpp>
|
||||||
|
#include <components/settings/settings.hpp>
|
||||||
|
#include <components/version/version.hpp>
|
||||||
|
|
||||||
#include "datafilespage.hpp"
|
#include "datafilespage.hpp"
|
||||||
#include "graphicspage.hpp"
|
#include "graphicspage.hpp"
|
||||||
|
@ -121,13 +118,14 @@ Launcher::FirstRunDialogResult Launcher::MainDialog::showFirstRunDialog()
|
||||||
const auto& userConfigDir = mCfgMgr.getUserConfigPath();
|
const auto& userConfigDir = mCfgMgr.getUserConfigPath();
|
||||||
if (!exists(userConfigDir))
|
if (!exists(userConfigDir))
|
||||||
{
|
{
|
||||||
if (!create_directories(userConfigDir))
|
std::error_code ec;
|
||||||
|
if (!create_directories(userConfigDir, ec))
|
||||||
{
|
{
|
||||||
cfgError(tr("Error opening OpenMW configuration file"),
|
cfgError(tr("Error creating OpenMW configuration directory: code %0").arg(ec.value()),
|
||||||
tr("<br><b>Could not create directory %0</b><br><br> \
|
tr("<br><b>Could not create directory %0</b><br><br>"
|
||||||
Please make sure you have the right permissions \
|
"%1<br>")
|
||||||
and try again.<br>")
|
.arg(Files::pathToQString(userConfigDir))
|
||||||
.arg(Files::pathToQString(canonical(userConfigDir))));
|
.arg(QString(ec.message().c_str())));
|
||||||
return FirstRunDialogResultFailure;
|
return FirstRunDialogResultFailure;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -139,10 +137,10 @@ Launcher::FirstRunDialogResult Launcher::MainDialog::showFirstRunDialog()
|
||||||
msgBox.setIcon(QMessageBox::Question);
|
msgBox.setIcon(QMessageBox::Question);
|
||||||
msgBox.setStandardButtons(QMessageBox::NoButton);
|
msgBox.setStandardButtons(QMessageBox::NoButton);
|
||||||
msgBox.setText(
|
msgBox.setText(
|
||||||
tr("<html><head/><body><p><b>Welcome to OpenMW!</b></p> \
|
tr("<html><head/><body><p><b>Welcome to OpenMW!</b></p>"
|
||||||
<p>It is recommended to run the Installation Wizard.</p> \
|
"<p>It is recommended to run the Installation Wizard.</p>"
|
||||||
<p>The Wizard will let you select an existing Morrowind installation, \
|
"<p>The Wizard will let you select an existing Morrowind installation, "
|
||||||
or install Morrowind for OpenMW to use.</p></body></html>"));
|
"or install Morrowind for OpenMW to use.</p></body></html>"));
|
||||||
|
|
||||||
QAbstractButton* wizardButton
|
QAbstractButton* wizardButton
|
||||||
= msgBox.addButton(tr("Run &Installation Wizard"), QMessageBox::AcceptRole); // ActionRole doesn't work?!
|
= msgBox.addButton(tr("Run &Installation Wizard"), QMessageBox::AcceptRole); // ActionRole doesn't work?!
|
||||||
|
@ -300,9 +298,9 @@ bool Launcher::MainDialog::setupLauncherSettings()
|
||||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
|
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||||
{
|
{
|
||||||
cfgError(tr("Error opening OpenMW configuration file"),
|
cfgError(tr("Error opening OpenMW configuration file"),
|
||||||
tr("<br><b>Could not open %0 for reading:</b><br><br>%1<br><br> \
|
tr("<br><b>Could not open %0 for reading:</b><br><br>%1<br><br>"
|
||||||
Please make sure you have the right permissions \
|
"Please make sure you have the right permissions "
|
||||||
and try again.<br>")
|
"and try again.<br>")
|
||||||
.arg(file.fileName())
|
.arg(file.fileName())
|
||||||
.arg(file.errorString()));
|
.arg(file.errorString()));
|
||||||
return false;
|
return false;
|
||||||
|
@ -330,9 +328,9 @@ bool Launcher::MainDialog::setupGameSettings()
|
||||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
|
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||||
{
|
{
|
||||||
cfgError(tr("Error opening OpenMW configuration file"),
|
cfgError(tr("Error opening OpenMW configuration file"),
|
||||||
tr("<br><b>Could not open %0 for reading</b><br><br> \
|
tr("<br><b>Could not open %0 for reading</b><br><br>"
|
||||||
Please make sure you have the right permissions \
|
"Please make sure you have the right permissions "
|
||||||
and try again.<br>")
|
"and try again.<br>")
|
||||||
.arg(file.fileName()));
|
.arg(file.fileName()));
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -391,8 +389,8 @@ bool Launcher::MainDialog::setupGameData()
|
||||||
msgBox.setIcon(QMessageBox::Warning);
|
msgBox.setIcon(QMessageBox::Warning);
|
||||||
msgBox.setStandardButtons(QMessageBox::NoButton);
|
msgBox.setStandardButtons(QMessageBox::NoButton);
|
||||||
msgBox.setText(
|
msgBox.setText(
|
||||||
tr("<br><b>Could not find the Data Files location</b><br><br> \
|
tr("<br><b>Could not find the Data Files location</b><br><br>"
|
||||||
The directory containing the data files was not found."));
|
"The directory containing the data files was not found."));
|
||||||
|
|
||||||
QAbstractButton* wizardButton = msgBox.addButton(tr("Run &Installation Wizard..."), QMessageBox::ActionRole);
|
QAbstractButton* wizardButton = msgBox.addButton(tr("Run &Installation Wizard..."), QMessageBox::ActionRole);
|
||||||
QAbstractButton* skipButton = msgBox.addButton(tr("Skip"), QMessageBox::RejectRole);
|
QAbstractButton* skipButton = msgBox.addButton(tr("Skip"), QMessageBox::RejectRole);
|
||||||
|
@ -422,8 +420,8 @@ bool Launcher::MainDialog::setupGraphicsSettings()
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
{
|
{
|
||||||
cfgError(tr("Error reading OpenMW configuration files"),
|
cfgError(tr("Error reading OpenMW configuration files"),
|
||||||
tr("<br>The problem may be due to an incomplete installation of OpenMW.<br> \
|
tr("<br>The problem may be due to an incomplete installation of OpenMW.<br>"
|
||||||
Reinstalling OpenMW may resolve the problem.<br>")
|
"Reinstalling OpenMW may resolve the problem.<br>")
|
||||||
+ e.what());
|
+ e.what());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -460,13 +458,14 @@ bool Launcher::MainDialog::writeSettings()
|
||||||
|
|
||||||
if (!exists(userPath))
|
if (!exists(userPath))
|
||||||
{
|
{
|
||||||
if (!create_directories(userPath))
|
std::error_code ec;
|
||||||
|
if (!create_directories(userPath, ec))
|
||||||
{
|
{
|
||||||
cfgError(tr("Error creating OpenMW configuration directory"),
|
cfgError(tr("Error creating OpenMW configuration directory: code %0").arg(ec.value()),
|
||||||
tr("<br><b>Could not create %0</b><br><br> \
|
tr("<br><b>Could not create directory %0</b><br><br>"
|
||||||
Please make sure you have the right permissions \
|
"%1<br>")
|
||||||
and try again.<br>")
|
.arg(Files::pathToQString(userPath))
|
||||||
.arg(Files::pathToQString(userPath)));
|
.arg(QString(ec.message().c_str())));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -482,9 +481,9 @@ bool Launcher::MainDialog::writeSettings()
|
||||||
{
|
{
|
||||||
// File cannot be opened or created
|
// File cannot be opened or created
|
||||||
cfgError(tr("Error writing OpenMW configuration file"),
|
cfgError(tr("Error writing OpenMW configuration file"),
|
||||||
tr("<br><b>Could not open or create %0 for writing</b><br><br> \
|
tr("<br><b>Could not open or create %0 for writing</b><br><br>"
|
||||||
Please make sure you have the right permissions \
|
"Please make sure you have the right permissions "
|
||||||
and try again.<br>")
|
"and try again.<br>")
|
||||||
.arg(file.fileName()));
|
.arg(file.fileName()));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -513,9 +512,9 @@ bool Launcher::MainDialog::writeSettings()
|
||||||
{
|
{
|
||||||
// File cannot be opened or created
|
// File cannot be opened or created
|
||||||
cfgError(tr("Error writing Launcher configuration file"),
|
cfgError(tr("Error writing Launcher configuration file"),
|
||||||
tr("<br><b>Could not open or create %0 for writing</b><br><br> \
|
tr("<br><b>Could not open or create %0 for writing</b><br><br>"
|
||||||
Please make sure you have the right permissions \
|
"Please make sure you have the right permissions "
|
||||||
and try again.<br>")
|
"and try again.<br>")
|
||||||
.arg(file.fileName()));
|
.arg(file.fileName()));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -565,8 +564,8 @@ void Launcher::MainDialog::play()
|
||||||
msgBox.setIcon(QMessageBox::Warning);
|
msgBox.setIcon(QMessageBox::Warning);
|
||||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||||
msgBox.setText(
|
msgBox.setText(
|
||||||
tr("<br><b>You do not have a game file selected.</b><br><br> \
|
tr("<br><b>You do not have a game file selected.</b><br><br>"
|
||||||
OpenMW will not start without a game file selected.<br>"));
|
"OpenMW will not start without a game file selected.<br>"));
|
||||||
msgBox.exec();
|
msgBox.exec();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -191,6 +191,7 @@ bool Launcher::SettingsPage::loadSettings()
|
||||||
}
|
}
|
||||||
loadSettingBool(Settings::game().mTurnToMovementDirection, *turnToMovementDirectionCheckBox);
|
loadSettingBool(Settings::game().mTurnToMovementDirection, *turnToMovementDirectionCheckBox);
|
||||||
loadSettingBool(Settings::game().mSmoothMovement, *smoothMovementCheckBox);
|
loadSettingBool(Settings::game().mSmoothMovement, *smoothMovementCheckBox);
|
||||||
|
loadSettingBool(Settings::game().mPlayerMovementIgnoresAnimation, *playerMovementIgnoresAnimationCheckBox);
|
||||||
|
|
||||||
distantLandCheckBox->setCheckState(
|
distantLandCheckBox->setCheckState(
|
||||||
Settings::terrain().mDistantTerrain && Settings::terrain().mObjectPaging ? Qt::Checked : Qt::Unchecked);
|
Settings::terrain().mDistantTerrain && Settings::terrain().mObjectPaging ? Qt::Checked : Qt::Unchecked);
|
||||||
|
@ -338,6 +339,7 @@ void Launcher::SettingsPage::saveSettings()
|
||||||
saveSettingBool(*shieldSheathingCheckBox, Settings::game().mShieldSheathing);
|
saveSettingBool(*shieldSheathingCheckBox, Settings::game().mShieldSheathing);
|
||||||
saveSettingBool(*turnToMovementDirectionCheckBox, Settings::game().mTurnToMovementDirection);
|
saveSettingBool(*turnToMovementDirectionCheckBox, Settings::game().mTurnToMovementDirection);
|
||||||
saveSettingBool(*smoothMovementCheckBox, Settings::game().mSmoothMovement);
|
saveSettingBool(*smoothMovementCheckBox, Settings::game().mSmoothMovement);
|
||||||
|
saveSettingBool(*playerMovementIgnoresAnimationCheckBox, Settings::game().mPlayerMovementIgnoresAnimation);
|
||||||
|
|
||||||
const bool wantDistantLand = distantLandCheckBox->checkState() == Qt::Checked;
|
const bool wantDistantLand = distantLandCheckBox->checkState() == Qt::Checked;
|
||||||
if (wantDistantLand != (Settings::terrain().mDistantTerrain && Settings::terrain().mObjectPaging))
|
if (wantDistantLand != (Settings::terrain().mDistantTerrain && Settings::terrain().mObjectPaging))
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>571</width>
|
<width>573</width>
|
||||||
<height>384</height>
|
<height>384</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
|
@ -30,7 +30,7 @@
|
||||||
<item row="1" column="0">
|
<item row="1" column="0">
|
||||||
<widget class="QLabel" name="dataNoteLabel">
|
<widget class="QLabel" name="dataNoteLabel">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string><html><head/><body><p><span style=" font-style:italic;">note: content files that are not part of current Content List are </span><span style=" font-style:italic; background-color:#00ff00;">highlighted</span></p></body></html></string>
|
<string><html><head/><body><p>note: content files that are not part of current Content List are <span style=" font-style:italic;font-weight: bold">highlighted</span></p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -57,7 +57,7 @@
|
||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string><html><head/><body><p><span style=" font-style:italic;">note: directories that are not part of current Content List are </span><span style=" font-style:italic; background-color:#00ff00;">highlighted</span></p></body></html></string>
|
<string><html><head/><body><p>note: directories that are not part of current Content List are <span style=" font-style:italic;font-weight: bold">highlighted</span></p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -210,7 +210,7 @@
|
||||||
<item row="27" column="0" colspan="2">
|
<item row="27" column="0" colspan="2">
|
||||||
<widget class="QLabel" name="archiveNoteLabel">
|
<widget class="QLabel" name="archiveNoteLabel">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string><html><head/><body><p><span style=" font-style:italic;">note: archives that are not part of current Content List are </span><span style=" font-style:italic; background-color:#00ff00;">highlighted</span></p></body></html></string>
|
<string><html><head/><body><p>note: archives that are not part of current Content List are <span style=" font-style:italic;font-weight: bold">highlighted</span></p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
|
@ -22,7 +22,7 @@
|
||||||
</attribute>
|
</attribute>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
<item>
|
<item>
|
||||||
<layout class="QGridLayout" name="gridLayout_4" columnstretch="1,0">
|
<layout class="QGridLayout" name="gridLayout_4" columnstretch="1,1">
|
||||||
<item row="5" column="0">
|
<item row="5" column="0">
|
||||||
<widget class="QLabel" name="screenLabel">
|
<widget class="QLabel" name="screenLabel">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
@ -107,7 +107,7 @@
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="multiplyLabel">
|
<widget class="QLabel" name="multiplyLabel">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string> x </string>
|
<string> × </string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
|
@ -14,7 +14,7 @@
|
||||||
<item>
|
<item>
|
||||||
<widget class="QTabWidget" name="AdvancedTabWidget">
|
<widget class="QTabWidget" name="AdvancedTabWidget">
|
||||||
<property name="currentIndex">
|
<property name="currentIndex">
|
||||||
<number>0</number>
|
<number>1</number>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QWidget" name="GameMechanics">
|
<widget class="QWidget" name="GameMechanics">
|
||||||
<attribute name="title">
|
<attribute name="title">
|
||||||
|
@ -116,10 +116,10 @@
|
||||||
<item row="4" column="0">
|
<item row="4" column="0">
|
||||||
<widget class="QCheckBox" name="enableNavigatorCheckBox">
|
<widget class="QCheckBox" name="enableNavigatorCheckBox">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><html><head/><body><p>Enable navigator. When enabled background threads are started to build nav mesh for world geometry. Pathfinding system uses nav mesh to build paths. When disabled only pathgrid is used to build paths. Single-core CPU systems may have big performance impact on exiting interior location and moving across exterior world. May slightly affect performance on multi-core CPU systems. Multi-core CPU systems may have different latency for nav mesh update depending on other settings and system performance. Moving across external world, entering/exiting location produce nav mesh update. NPC and creatures may not be able to find path before nav mesh is built around them. Try to disable this if you want to have old fashioned AI which doesn’t know where to go when you stand behind that stone and casting a firebolt.</p></body></html></string>
|
<string><html><head/><body><p><a name="docs-internal-guid-f375b85a-7fff-02ff-a5af-c5cff63923c0"/>When enabled, a navigation mesh is built in the background for world geometry to be used for pathfinding. When disabled only the path grid is used to build paths. Single-core CPU systems may have a big performance impact on existing interior location and moving across the exterior world. May slightly affect performance on multi-core CPU systems. Multi-core CPU systems may have different latency for nav mesh update depending on other settings and system performance. Moving across external world, entering/exiting location produce nav mesh update. NPC and creatures may not be able to find path before nav mesh is built around them. Try to disable this if you want to have old fashioned AI which doesn't know where to go when you stand behind that stone and cast a firebolt.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Build nav mesh for world geometry</string>
|
<string>Use navigation mesh for pathfinding</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -293,8 +293,8 @@
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>680</width>
|
<width>671</width>
|
||||||
<height>882</height>
|
<height>774</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
@ -377,6 +377,16 @@
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QCheckBox" name="playerMovementIgnoresAnimationCheckBox">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><head/><body><p>In third person, the camera will sway along with the movement animations of the player. Enabling this option disables this swaying by having the player character move independently of its animation. This was the default behavior of OpenMW 0.48 and earlier.</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Player movement ignores animation</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
|
@ -164,12 +164,12 @@ namespace NavMeshTool
|
||||||
|
|
||||||
config.filterOutNonExistingPaths(dataDirs);
|
config.filterOutNonExistingPaths(dataDirs);
|
||||||
|
|
||||||
const auto resDir = variables["resources"].as<Files::MaybeQuotedPath>();
|
const auto& resDir = variables["resources"].as<Files::MaybeQuotedPath>();
|
||||||
Log(Debug::Info) << Version::getOpenmwVersionDescription();
|
Log(Debug::Info) << Version::getOpenmwVersionDescription();
|
||||||
dataDirs.insert(dataDirs.begin(), resDir / "vfs");
|
dataDirs.insert(dataDirs.begin(), resDir / "vfs");
|
||||||
const auto fileCollections = Files::Collections(dataDirs);
|
const Files::Collections fileCollections(dataDirs);
|
||||||
const auto archives = variables["fallback-archive"].as<StringsVector>();
|
const auto& archives = variables["fallback-archive"].as<StringsVector>();
|
||||||
const auto contentFiles = variables["content"].as<StringsVector>();
|
const auto& contentFiles = variables["content"].as<StringsVector>();
|
||||||
const std::size_t threadsNumber = variables["threads"].as<std::size_t>();
|
const std::size_t threadsNumber = variables["threads"].as<std::size_t>();
|
||||||
|
|
||||||
if (threadsNumber < 1)
|
if (threadsNumber < 1)
|
||||||
|
|
|
@ -131,7 +131,7 @@ namespace NavMeshTool
|
||||||
osg::ref_ptr<const Resource::BulletShape> shape = [&] {
|
osg::ref_ptr<const Resource::BulletShape> shape = [&] {
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return bulletShapeManager.getShape(Misc::ResourceHelpers::correctMeshPath(model, &vfs));
|
return bulletShapeManager.getShape(Misc::ResourceHelpers::correctMeshPath(model));
|
||||||
}
|
}
|
||||||
catch (const std::exception& e)
|
catch (const std::exception& e)
|
||||||
{
|
{
|
||||||
|
|
|
@ -45,9 +45,6 @@ std::unique_ptr<VFS::Archive> makeBsaArchive(const std::filesystem::path& path)
|
||||||
{
|
{
|
||||||
switch (Bsa::BSAFile::detectVersion(path))
|
switch (Bsa::BSAFile::detectVersion(path))
|
||||||
{
|
{
|
||||||
case Bsa::BSAVER_UNKNOWN:
|
|
||||||
std::cerr << '"' << path << "\" is unknown BSA archive" << std::endl;
|
|
||||||
return nullptr;
|
|
||||||
case Bsa::BSAVER_COMPRESSED:
|
case Bsa::BSAVER_COMPRESSED:
|
||||||
return std::make_unique<VFS::ArchiveSelector<Bsa::BSAVER_COMPRESSED>::type>(path);
|
return std::make_unique<VFS::ArchiveSelector<Bsa::BSAVER_COMPRESSED>::type>(path);
|
||||||
case Bsa::BSAVER_BA2_GNRL:
|
case Bsa::BSAVER_BA2_GNRL:
|
||||||
|
@ -56,11 +53,11 @@ std::unique_ptr<VFS::Archive> makeBsaArchive(const std::filesystem::path& path)
|
||||||
return std::make_unique<VFS::ArchiveSelector<Bsa::BSAVER_BA2_DX10>::type>(path);
|
return std::make_unique<VFS::ArchiveSelector<Bsa::BSAVER_BA2_DX10>::type>(path);
|
||||||
case Bsa::BSAVER_UNCOMPRESSED:
|
case Bsa::BSAVER_UNCOMPRESSED:
|
||||||
return std::make_unique<VFS::ArchiveSelector<Bsa::BSAVER_UNCOMPRESSED>::type>(path);
|
return std::make_unique<VFS::ArchiveSelector<Bsa::BSAVER_UNCOMPRESSED>::type>(path);
|
||||||
|
case Bsa::BSAVER_UNKNOWN:
|
||||||
|
default:
|
||||||
|
std::cerr << "'" << Files::pathToUnicodeString(path) << "' is not a recognized BSA archive" << std::endl;
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cerr << '"' << path << "\" is unsupported BSA archive" << std::endl;
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<VFS::Archive> makeArchive(const std::filesystem::path& path)
|
std::unique_ptr<VFS::Archive> makeArchive(const std::filesystem::path& path)
|
||||||
|
@ -72,58 +69,86 @@ std::unique_ptr<VFS::Archive> makeArchive(const std::filesystem::path& path)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void readNIF(
|
||||||
|
const std::filesystem::path& source, const std::filesystem::path& path, const VFS::Manager* vfs, bool quiet)
|
||||||
|
{
|
||||||
|
const std::string pathStr = Files::pathToUnicodeString(path);
|
||||||
|
if (!quiet)
|
||||||
|
{
|
||||||
|
std::cout << "Reading NIF file '" << pathStr << "'";
|
||||||
|
if (!source.empty())
|
||||||
|
std::cout << " from '" << Files::pathToUnicodeString(isBSA(source) ? source.filename() : source) << "'";
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
std::filesystem::path fullPath = !source.empty() ? source / path : path;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Nif::NIFFile file(fullPath);
|
||||||
|
Nif::Reader reader(file);
|
||||||
|
if (vfs != nullptr)
|
||||||
|
reader.parse(vfs->get(pathStr));
|
||||||
|
else
|
||||||
|
reader.parse(Files::openConstrainedFileStream(fullPath));
|
||||||
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
std::cerr << "Failed to read '" << pathStr << "':" << std::endl << e.what() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Check all the nif files in a given VFS::Archive
|
/// Check all the nif files in a given VFS::Archive
|
||||||
/// \note Can not read a bsa file inside of a bsa file.
|
/// \note Can not read a bsa file inside of a bsa file.
|
||||||
void readVFS(std::unique_ptr<VFS::Archive>&& anArchive, const std::filesystem::path& archivePath = {})
|
void readVFS(std::unique_ptr<VFS::Archive>&& archive, const std::filesystem::path& archivePath, bool quiet)
|
||||||
{
|
{
|
||||||
if (anArchive == nullptr)
|
if (archive == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
VFS::Manager myManager;
|
if (!quiet)
|
||||||
myManager.addArchive(std::move(anArchive));
|
std::cout << "Reading data source '" << Files::pathToUnicodeString(archivePath) << "'" << std::endl;
|
||||||
myManager.buildIndex();
|
|
||||||
|
|
||||||
for (const auto& name : myManager.getRecursiveDirectoryIterator(""))
|
VFS::Manager vfs;
|
||||||
|
vfs.addArchive(std::move(archive));
|
||||||
|
vfs.buildIndex();
|
||||||
|
|
||||||
|
for (const auto& name : vfs.getRecursiveDirectoryIterator(""))
|
||||||
{
|
{
|
||||||
try
|
if (isNIF(name))
|
||||||
{
|
{
|
||||||
if (isNIF(name))
|
readNIF(archivePath, name, &vfs, quiet);
|
||||||
{
|
|
||||||
// std::cout << "Decoding: " << name << std::endl;
|
|
||||||
Nif::NIFFile file(archivePath / name);
|
|
||||||
Nif::Reader reader(file);
|
|
||||||
reader.parse(myManager.get(name));
|
|
||||||
}
|
|
||||||
else if (isBSA(name))
|
|
||||||
{
|
|
||||||
if (!archivePath.empty() && !isBSA(archivePath))
|
|
||||||
{
|
|
||||||
// std::cout << "Reading BSA File: " << name << std::endl;
|
|
||||||
readVFS(makeBsaArchive(archivePath / name), archivePath / name);
|
|
||||||
// std::cout << "Done with BSA File: " << name << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
}
|
||||||
|
|
||||||
|
if (!archivePath.empty() && !isBSA(archivePath))
|
||||||
|
{
|
||||||
|
Files::PathContainer dataDirs = { archivePath };
|
||||||
|
const Files::Collections fileCollections = Files::Collections(dataDirs);
|
||||||
|
const Files::MultiDirCollection& bsaCol = fileCollections.getCollection(".bsa");
|
||||||
|
const Files::MultiDirCollection& ba2Col = fileCollections.getCollection(".ba2");
|
||||||
|
for (auto& file : bsaCol)
|
||||||
{
|
{
|
||||||
std::cerr << "ERROR, an exception has occurred: " << e.what() << std::endl;
|
readVFS(makeBsaArchive(file.second), file.second, quiet);
|
||||||
|
}
|
||||||
|
for (auto& file : ba2Col)
|
||||||
|
{
|
||||||
|
readVFS(makeBsaArchive(file.second), file.second, quiet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parseOptions(int argc, char** argv, std::vector<Files::MaybeQuotedPath>& files, bool& writeDebugLog,
|
bool parseOptions(int argc, char** argv, Files::PathContainer& files, Files::PathContainer& archives,
|
||||||
std::vector<Files::MaybeQuotedPath>& archives)
|
bool& writeDebugLog, bool& quiet)
|
||||||
{
|
{
|
||||||
bpo::options_description desc(R"(Ensure that OpenMW can use the provided NIF and BSA files
|
bpo::options_description desc(R"(Ensure that OpenMW can use the provided NIF and BSA files
|
||||||
|
|
||||||
Usages:
|
Usages:
|
||||||
niftool <nif files, BSA files, or directories>
|
niftest <nif files, BSA files, or directories>
|
||||||
Scan the file or directories for nif errors.
|
Scan the file or directories for NIF errors.
|
||||||
|
|
||||||
Allowed options)");
|
Allowed options)");
|
||||||
auto addOption = desc.add_options();
|
auto addOption = desc.add_options();
|
||||||
addOption("help,h", "print help message.");
|
addOption("help,h", "print help message.");
|
||||||
addOption("write-debug-log,v", "write debug log for unsupported nif files");
|
addOption("write-debug-log,v", "write debug log for unsupported nif files");
|
||||||
|
addOption("quiet,q", "do not log read archives/files");
|
||||||
addOption("archives", bpo::value<Files::MaybeQuotedPathContainer>(), "path to archive files to provide files");
|
addOption("archives", bpo::value<Files::MaybeQuotedPathContainer>(), "path to archive files to provide files");
|
||||||
addOption("input-file", bpo::value<Files::MaybeQuotedPathContainer>(), "input file");
|
addOption("input-file", bpo::value<Files::MaybeQuotedPathContainer>(), "input file");
|
||||||
|
|
||||||
|
@ -143,17 +168,18 @@ Allowed options)");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
writeDebugLog = variables.count("write-debug-log") > 0;
|
writeDebugLog = variables.count("write-debug-log") > 0;
|
||||||
|
quiet = variables.count("quiet") > 0;
|
||||||
if (variables.count("input-file"))
|
if (variables.count("input-file"))
|
||||||
{
|
{
|
||||||
files = variables["input-file"].as<Files::MaybeQuotedPathContainer>();
|
files = asPathContainer(variables["input-file"].as<Files::MaybeQuotedPathContainer>());
|
||||||
if (const auto it = variables.find("archives"); it != variables.end())
|
if (const auto it = variables.find("archives"); it != variables.end())
|
||||||
archives = it->second.as<Files::MaybeQuotedPathContainer>();
|
archives = asPathContainer(it->second.as<Files::MaybeQuotedPathContainer>());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
{
|
{
|
||||||
std::cout << "ERROR parsing arguments: " << e.what() << "\n\n" << desc << std::endl;
|
std::cout << "Error parsing arguments: " << e.what() << "\n\n" << desc << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,64 +190,62 @@ Allowed options)");
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
std::vector<Files::MaybeQuotedPath> files;
|
Files::PathContainer files, sources;
|
||||||
bool writeDebugLog = false;
|
bool writeDebugLog = false;
|
||||||
std::vector<Files::MaybeQuotedPath> archives;
|
bool quiet = false;
|
||||||
if (!parseOptions(argc, argv, files, writeDebugLog, archives))
|
if (!parseOptions(argc, argv, files, sources, writeDebugLog, quiet))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
Nif::Reader::setLoadUnsupportedFiles(true);
|
Nif::Reader::setLoadUnsupportedFiles(true);
|
||||||
Nif::Reader::setWriteNifDebugLog(writeDebugLog);
|
Nif::Reader::setWriteNifDebugLog(writeDebugLog);
|
||||||
|
|
||||||
std::unique_ptr<VFS::Manager> vfs;
|
std::unique_ptr<VFS::Manager> vfs;
|
||||||
if (!archives.empty())
|
if (!sources.empty())
|
||||||
{
|
{
|
||||||
vfs = std::make_unique<VFS::Manager>();
|
vfs = std::make_unique<VFS::Manager>();
|
||||||
for (const std::filesystem::path& path : archives)
|
for (const std::filesystem::path& path : sources)
|
||||||
{
|
{
|
||||||
|
const std::string pathStr = Files::pathToUnicodeString(path);
|
||||||
|
if (!quiet)
|
||||||
|
std::cout << "Adding data source '" << pathStr << "'" << std::endl;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (auto archive = makeArchive(path))
|
if (auto archive = makeArchive(path))
|
||||||
vfs->addArchive(std::move(archive));
|
vfs->addArchive(std::move(archive));
|
||||||
else
|
else
|
||||||
std::cerr << '"' << path << "\" is unsupported archive" << std::endl;
|
std::cerr << "Error: '" << pathStr << "' is not an archive or directory" << std::endl;
|
||||||
vfs->buildIndex();
|
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
{
|
{
|
||||||
std::cerr << "ERROR, an exception has occurred: " << e.what() << std::endl;
|
std::cerr << "Failed to add data source '" << pathStr << "': " << e.what() << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vfs->buildIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
// std::cout << "Reading Files" << std::endl;
|
|
||||||
for (const auto& path : files)
|
for (const auto& path : files)
|
||||||
{
|
{
|
||||||
|
const std::string pathStr = Files::pathToUnicodeString(path);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (isNIF(path))
|
if (isNIF(path))
|
||||||
{
|
{
|
||||||
// std::cout << "Decoding: " << name << std::endl;
|
readNIF({}, path, vfs.get(), quiet);
|
||||||
Nif::NIFFile file(path);
|
|
||||||
Nif::Reader reader(file);
|
|
||||||
if (vfs != nullptr)
|
|
||||||
reader.parse(vfs->get(Files::pathToUnicodeString(path)));
|
|
||||||
else
|
|
||||||
reader.parse(Files::openConstrainedFileStream(path));
|
|
||||||
}
|
}
|
||||||
else if (auto archive = makeArchive(path))
|
else if (auto archive = makeArchive(path))
|
||||||
{
|
{
|
||||||
readVFS(std::move(archive), path);
|
readVFS(std::move(archive), path, quiet);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::cerr << "ERROR: \"" << Files::pathToUnicodeString(path)
|
std::cerr << "Error: '" << pathStr << "' is not a NIF file, BSA/BA2 archive, or directory" << std::endl;
|
||||||
<< "\" is not a nif file, bsa/ba2 file, or directory!" << std::endl;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
{
|
{
|
||||||
std::cerr << "ERROR, an exception has occurred: " << e.what() << std::endl;
|
std::cerr << "Failed to read '" << pathStr << "': " << e.what() << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -116,7 +116,7 @@ opencs_units (view/prefs
|
||||||
|
|
||||||
opencs_units (model/prefs
|
opencs_units (model/prefs
|
||||||
state setting intsetting doublesetting boolsetting enumsetting coloursetting shortcut
|
state setting intsetting doublesetting boolsetting enumsetting coloursetting shortcut
|
||||||
shortcuteventhandler shortcutmanager shortcutsetting modifiersetting stringsetting
|
shortcuteventhandler shortcutmanager shortcutsetting modifiersetting stringsetting subcategory
|
||||||
)
|
)
|
||||||
|
|
||||||
opencs_units (model/prefs
|
opencs_units (model/prefs
|
||||||
|
@ -139,8 +139,7 @@ set (OPENCS_RES ${CMAKE_SOURCE_DIR}/files/opencs/resources.qrc
|
||||||
)
|
)
|
||||||
|
|
||||||
set (OPENCS_UI
|
set (OPENCS_UI
|
||||||
${CMAKE_SOURCE_DIR}/files/ui/contentselector.ui
|
${CMAKE_CURRENT_SOURCE_DIR}/ui/filedialog.ui
|
||||||
${CMAKE_SOURCE_DIR}/files/ui/filedialog.ui
|
|
||||||
)
|
)
|
||||||
|
|
||||||
source_group (openmw-cs FILES main.cpp ${OPENCS_SRC} ${OPENCS_HDR})
|
source_group (openmw-cs FILES main.cpp ${OPENCS_SRC} ${OPENCS_HDR})
|
||||||
|
|
|
@ -200,6 +200,8 @@ std::pair<Files::PathContainer, std::vector<std::string>> CS::Editor::readConfig
|
||||||
|
|
||||||
dataDirs.insert(dataDirs.end(), dataLocal.begin(), dataLocal.end());
|
dataDirs.insert(dataDirs.end(), dataLocal.begin(), dataLocal.end());
|
||||||
|
|
||||||
|
dataDirs.insert(dataDirs.begin(), mResources / "vfs");
|
||||||
|
|
||||||
// iterate the data directories and add them to the file dialog for loading
|
// iterate the data directories and add them to the file dialog for loading
|
||||||
mFileDialog.addFiles(dataDirs);
|
mFileDialog.addFiles(dataDirs);
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include <components/esm3/loadsoun.hpp>
|
#include <components/esm3/loadsoun.hpp>
|
||||||
#include <components/esm3/loadspel.hpp>
|
#include <components/esm3/loadspel.hpp>
|
||||||
#include <components/esm3/loadsscr.hpp>
|
#include <components/esm3/loadsscr.hpp>
|
||||||
|
#include <components/esm3/selectiongroup.hpp>
|
||||||
|
|
||||||
#include "../world/data.hpp"
|
#include "../world/data.hpp"
|
||||||
#include "../world/idcollection.hpp"
|
#include "../world/idcollection.hpp"
|
||||||
|
@ -52,6 +53,9 @@ CSMDoc::Saving::Saving(Document& document, const std::filesystem::path& projectP
|
||||||
appendStage(new WriteCollectionStage<CSMWorld::IdCollection<ESM::Script>>(
|
appendStage(new WriteCollectionStage<CSMWorld::IdCollection<ESM::Script>>(
|
||||||
mDocument.getData().getScripts(), mState, CSMWorld::Scope_Project));
|
mDocument.getData().getScripts(), mState, CSMWorld::Scope_Project));
|
||||||
|
|
||||||
|
appendStage(new WriteCollectionStage<CSMWorld::IdCollection<ESM::SelectionGroup>>(
|
||||||
|
mDocument.getData().getSelectionGroups(), mState, CSMWorld::Scope_Project));
|
||||||
|
|
||||||
appendStage(new CloseSaveStage(mState));
|
appendStage(new CloseSaveStage(mState));
|
||||||
|
|
||||||
// save content file
|
// save content file
|
||||||
|
|
|
@ -11,9 +11,8 @@
|
||||||
#include "state.hpp"
|
#include "state.hpp"
|
||||||
|
|
||||||
CSMPrefs::BoolSetting::BoolSetting(
|
CSMPrefs::BoolSetting::BoolSetting(
|
||||||
Category* parent, QMutex* mutex, const std::string& key, const std::string& label, bool default_)
|
Category* parent, QMutex* mutex, std::string_view key, const QString& label, Settings::Index& index)
|
||||||
: Setting(parent, mutex, key, label)
|
: TypedSetting(parent, mutex, key, label, index)
|
||||||
, mDefault(default_)
|
|
||||||
, mWidget(nullptr)
|
, mWidget(nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -24,10 +23,10 @@ CSMPrefs::BoolSetting& CSMPrefs::BoolSetting::setTooltip(const std::string& tool
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<QWidget*, QWidget*> CSMPrefs::BoolSetting::makeWidgets(QWidget* parent)
|
CSMPrefs::SettingWidgets CSMPrefs::BoolSetting::makeWidgets(QWidget* parent)
|
||||||
{
|
{
|
||||||
mWidget = new QCheckBox(QString::fromUtf8(getLabel().c_str()), parent);
|
mWidget = new QCheckBox(getLabel(), parent);
|
||||||
mWidget->setCheckState(mDefault ? Qt::Checked : Qt::Unchecked);
|
mWidget->setCheckState(getValue() ? Qt::Checked : Qt::Unchecked);
|
||||||
|
|
||||||
if (!mTooltip.empty())
|
if (!mTooltip.empty())
|
||||||
{
|
{
|
||||||
|
@ -37,24 +36,19 @@ std::pair<QWidget*, QWidget*> CSMPrefs::BoolSetting::makeWidgets(QWidget* parent
|
||||||
|
|
||||||
connect(mWidget, &QCheckBox::stateChanged, this, &BoolSetting::valueChanged);
|
connect(mWidget, &QCheckBox::stateChanged, this, &BoolSetting::valueChanged);
|
||||||
|
|
||||||
return std::make_pair(static_cast<QWidget*>(nullptr), mWidget);
|
return SettingWidgets{ .mLabel = nullptr, .mInput = mWidget };
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMPrefs::BoolSetting::updateWidget()
|
void CSMPrefs::BoolSetting::updateWidget()
|
||||||
{
|
{
|
||||||
if (mWidget)
|
if (mWidget)
|
||||||
{
|
{
|
||||||
mWidget->setCheckState(
|
mWidget->setCheckState(getValue() ? Qt::Checked : Qt::Unchecked);
|
||||||
Settings::Manager::getBool(getKey(), getParent()->getKey()) ? Qt::Checked : Qt::Unchecked);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMPrefs::BoolSetting::valueChanged(int value)
|
void CSMPrefs::BoolSetting::valueChanged(int value)
|
||||||
{
|
{
|
||||||
{
|
setValue(value != Qt::Unchecked);
|
||||||
QMutexLocker lock(getMutex());
|
|
||||||
Settings::Manager::setBool(getKey(), getParent()->getKey(), value);
|
|
||||||
}
|
|
||||||
|
|
||||||
getParent()->getState()->update(*this);
|
getParent()->getState()->update(*this);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,21 +12,21 @@ namespace CSMPrefs
|
||||||
{
|
{
|
||||||
class Category;
|
class Category;
|
||||||
|
|
||||||
class BoolSetting : public Setting
|
class BoolSetting final : public TypedSetting<bool>
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
std::string mTooltip;
|
std::string mTooltip;
|
||||||
bool mDefault;
|
|
||||||
QCheckBox* mWidget;
|
QCheckBox* mWidget;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BoolSetting(Category* parent, QMutex* mutex, const std::string& key, const std::string& label, bool default_);
|
explicit BoolSetting(
|
||||||
|
Category* parent, QMutex* mutex, std::string_view key, const QString& label, Settings::Index& index);
|
||||||
|
|
||||||
BoolSetting& setTooltip(const std::string& tooltip);
|
BoolSetting& setTooltip(const std::string& tooltip);
|
||||||
|
|
||||||
/// Return label, input widget.
|
/// Return label, input widget.
|
||||||
std::pair<QWidget*, QWidget*> makeWidgets(QWidget* parent) override;
|
SettingWidgets makeWidgets(QWidget* parent) override;
|
||||||
|
|
||||||
void updateWidget() override;
|
void updateWidget() override;
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include "setting.hpp"
|
#include "setting.hpp"
|
||||||
#include "state.hpp"
|
#include "state.hpp"
|
||||||
|
#include "subcategory.hpp"
|
||||||
|
|
||||||
CSMPrefs::Category::Category(State* parent, const std::string& key)
|
CSMPrefs::Category::Category(State* parent, const std::string& key)
|
||||||
: mParent(parent)
|
: mParent(parent)
|
||||||
|
@ -23,6 +24,14 @@ CSMPrefs::State* CSMPrefs::Category::getState() const
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMPrefs::Category::addSetting(Setting* setting)
|
void CSMPrefs::Category::addSetting(Setting* setting)
|
||||||
|
{
|
||||||
|
if (!mIndex.emplace(setting->getKey(), setting).second)
|
||||||
|
throw std::logic_error("Category " + mKey + " already has setting: " + setting->getKey());
|
||||||
|
|
||||||
|
mSettings.push_back(setting);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSMPrefs::Category::addSubcategory(Subcategory* setting)
|
||||||
{
|
{
|
||||||
mSettings.push_back(setting);
|
mSettings.push_back(setting);
|
||||||
}
|
}
|
||||||
|
@ -39,11 +48,12 @@ CSMPrefs::Category::Iterator CSMPrefs::Category::end()
|
||||||
|
|
||||||
CSMPrefs::Setting& CSMPrefs::Category::operator[](const std::string& key)
|
CSMPrefs::Setting& CSMPrefs::Category::operator[](const std::string& key)
|
||||||
{
|
{
|
||||||
for (Iterator iter = mSettings.begin(); iter != mSettings.end(); ++iter)
|
const auto it = mIndex.find(key);
|
||||||
if ((*iter)->getKey() == key)
|
|
||||||
return **iter;
|
|
||||||
|
|
||||||
throw std::logic_error("Invalid user setting: " + key);
|
if (it != mIndex.end())
|
||||||
|
return *it->second;
|
||||||
|
|
||||||
|
throw std::logic_error("Invalid user setting in " + mKey + " category: " + key);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMPrefs::Category::update()
|
void CSMPrefs::Category::update()
|
||||||
|
|
|
@ -3,12 +3,14 @@
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace CSMPrefs
|
namespace CSMPrefs
|
||||||
{
|
{
|
||||||
class State;
|
class State;
|
||||||
class Setting;
|
class Setting;
|
||||||
|
class Subcategory;
|
||||||
|
|
||||||
class Category
|
class Category
|
||||||
{
|
{
|
||||||
|
@ -20,6 +22,7 @@ namespace CSMPrefs
|
||||||
State* mParent;
|
State* mParent;
|
||||||
std::string mKey;
|
std::string mKey;
|
||||||
Container mSettings;
|
Container mSettings;
|
||||||
|
std::unordered_map<std::string, Setting*> mIndex;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Category(State* parent, const std::string& key);
|
Category(State* parent, const std::string& key);
|
||||||
|
@ -30,6 +33,8 @@ namespace CSMPrefs
|
||||||
|
|
||||||
void addSetting(Setting* setting);
|
void addSetting(Setting* setting);
|
||||||
|
|
||||||
|
void addSubcategory(Subcategory* setting);
|
||||||
|
|
||||||
Iterator begin();
|
Iterator begin();
|
||||||
|
|
||||||
Iterator end();
|
Iterator end();
|
||||||
|
|
|
@ -14,9 +14,8 @@
|
||||||
#include "state.hpp"
|
#include "state.hpp"
|
||||||
|
|
||||||
CSMPrefs::ColourSetting::ColourSetting(
|
CSMPrefs::ColourSetting::ColourSetting(
|
||||||
Category* parent, QMutex* mutex, const std::string& key, const std::string& label, QColor default_)
|
Category* parent, QMutex* mutex, const std::string& key, const QString& label, Settings::Index& index)
|
||||||
: Setting(parent, mutex, key, label)
|
: TypedSetting(parent, mutex, key, label, index)
|
||||||
, mDefault(std::move(default_))
|
|
||||||
, mWidget(nullptr)
|
, mWidget(nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -27,11 +26,11 @@ CSMPrefs::ColourSetting& CSMPrefs::ColourSetting::setTooltip(const std::string&
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<QWidget*, QWidget*> CSMPrefs::ColourSetting::makeWidgets(QWidget* parent)
|
CSMPrefs::SettingWidgets CSMPrefs::ColourSetting::makeWidgets(QWidget* parent)
|
||||||
{
|
{
|
||||||
QLabel* label = new QLabel(QString::fromUtf8(getLabel().c_str()), parent);
|
QLabel* label = new QLabel(getLabel(), parent);
|
||||||
|
|
||||||
mWidget = new CSVWidget::ColorEditor(mDefault, parent);
|
mWidget = new CSVWidget::ColorEditor(toColor(), parent);
|
||||||
|
|
||||||
if (!mTooltip.empty())
|
if (!mTooltip.empty())
|
||||||
{
|
{
|
||||||
|
@ -42,24 +41,18 @@ std::pair<QWidget*, QWidget*> CSMPrefs::ColourSetting::makeWidgets(QWidget* pare
|
||||||
|
|
||||||
connect(mWidget, &CSVWidget::ColorEditor::pickingFinished, this, &ColourSetting::valueChanged);
|
connect(mWidget, &CSVWidget::ColorEditor::pickingFinished, this, &ColourSetting::valueChanged);
|
||||||
|
|
||||||
return std::make_pair(label, mWidget);
|
return SettingWidgets{ .mLabel = label, .mInput = mWidget };
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMPrefs::ColourSetting::updateWidget()
|
void CSMPrefs::ColourSetting::updateWidget()
|
||||||
{
|
{
|
||||||
if (mWidget)
|
if (mWidget)
|
||||||
{
|
mWidget->setColor(toColor());
|
||||||
mWidget->setColor(QString::fromStdString(Settings::Manager::getString(getKey(), getParent()->getKey())));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMPrefs::ColourSetting::valueChanged()
|
void CSMPrefs::ColourSetting::valueChanged()
|
||||||
{
|
{
|
||||||
CSVWidget::ColorEditor& widget = dynamic_cast<CSVWidget::ColorEditor&>(*sender());
|
CSVWidget::ColorEditor& widget = dynamic_cast<CSVWidget::ColorEditor&>(*sender());
|
||||||
{
|
setValue(widget.color().name().toStdString());
|
||||||
QMutexLocker lock(getMutex());
|
|
||||||
Settings::Manager::setString(getKey(), getParent()->getKey(), widget.color().name().toUtf8().data());
|
|
||||||
}
|
|
||||||
|
|
||||||
getParent()->getState()->update(*this);
|
getParent()->getState()->update(*this);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,22 +20,22 @@ namespace CSVWidget
|
||||||
namespace CSMPrefs
|
namespace CSMPrefs
|
||||||
{
|
{
|
||||||
class Category;
|
class Category;
|
||||||
class ColourSetting : public Setting
|
|
||||||
|
class ColourSetting final : public TypedSetting<std::string>
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
std::string mTooltip;
|
std::string mTooltip;
|
||||||
QColor mDefault;
|
|
||||||
CSVWidget::ColorEditor* mWidget;
|
CSVWidget::ColorEditor* mWidget;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ColourSetting(
|
explicit ColourSetting(
|
||||||
Category* parent, QMutex* mutex, const std::string& key, const std::string& label, QColor default_);
|
Category* parent, QMutex* mutex, const std::string& key, const QString& label, Settings::Index& index);
|
||||||
|
|
||||||
ColourSetting& setTooltip(const std::string& tooltip);
|
ColourSetting& setTooltip(const std::string& tooltip);
|
||||||
|
|
||||||
/// Return label, input widget.
|
/// Return label, input widget.
|
||||||
std::pair<QWidget*, QWidget*> makeWidgets(QWidget* parent) override;
|
SettingWidgets makeWidgets(QWidget* parent) override;
|
||||||
|
|
||||||
void updateWidget() override;
|
void updateWidget() override;
|
||||||
|
|
||||||
|
|
|
@ -15,12 +15,11 @@
|
||||||
#include "state.hpp"
|
#include "state.hpp"
|
||||||
|
|
||||||
CSMPrefs::DoubleSetting::DoubleSetting(
|
CSMPrefs::DoubleSetting::DoubleSetting(
|
||||||
Category* parent, QMutex* mutex, const std::string& key, const std::string& label, double default_)
|
Category* parent, QMutex* mutex, std::string_view key, const QString& label, Settings::Index& index)
|
||||||
: Setting(parent, mutex, key, label)
|
: TypedSetting(parent, mutex, key, label, index)
|
||||||
, mPrecision(2)
|
, mPrecision(2)
|
||||||
, mMin(0)
|
, mMin(0)
|
||||||
, mMax(std::numeric_limits<double>::max())
|
, mMax(std::numeric_limits<double>::max())
|
||||||
, mDefault(default_)
|
|
||||||
, mWidget(nullptr)
|
, mWidget(nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -56,14 +55,14 @@ CSMPrefs::DoubleSetting& CSMPrefs::DoubleSetting::setTooltip(const std::string&
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<QWidget*, QWidget*> CSMPrefs::DoubleSetting::makeWidgets(QWidget* parent)
|
CSMPrefs::SettingWidgets CSMPrefs::DoubleSetting::makeWidgets(QWidget* parent)
|
||||||
{
|
{
|
||||||
QLabel* label = new QLabel(QString::fromUtf8(getLabel().c_str()), parent);
|
QLabel* label = new QLabel(getLabel(), parent);
|
||||||
|
|
||||||
mWidget = new QDoubleSpinBox(parent);
|
mWidget = new QDoubleSpinBox(parent);
|
||||||
mWidget->setDecimals(mPrecision);
|
mWidget->setDecimals(mPrecision);
|
||||||
mWidget->setRange(mMin, mMax);
|
mWidget->setRange(mMin, mMax);
|
||||||
mWidget->setValue(mDefault);
|
mWidget->setValue(getValue());
|
||||||
|
|
||||||
if (!mTooltip.empty())
|
if (!mTooltip.empty())
|
||||||
{
|
{
|
||||||
|
@ -74,23 +73,17 @@ std::pair<QWidget*, QWidget*> CSMPrefs::DoubleSetting::makeWidgets(QWidget* pare
|
||||||
|
|
||||||
connect(mWidget, qOverload<double>(&QDoubleSpinBox::valueChanged), this, &DoubleSetting::valueChanged);
|
connect(mWidget, qOverload<double>(&QDoubleSpinBox::valueChanged), this, &DoubleSetting::valueChanged);
|
||||||
|
|
||||||
return std::make_pair(label, mWidget);
|
return SettingWidgets{ .mLabel = label, .mInput = mWidget };
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMPrefs::DoubleSetting::updateWidget()
|
void CSMPrefs::DoubleSetting::updateWidget()
|
||||||
{
|
{
|
||||||
if (mWidget)
|
if (mWidget)
|
||||||
{
|
mWidget->setValue(getValue());
|
||||||
mWidget->setValue(Settings::Manager::getFloat(getKey(), getParent()->getKey()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMPrefs::DoubleSetting::valueChanged(double value)
|
void CSMPrefs::DoubleSetting::valueChanged(double value)
|
||||||
{
|
{
|
||||||
{
|
setValue(value);
|
||||||
QMutexLocker lock(getMutex());
|
|
||||||
Settings::Manager::setFloat(getKey(), getParent()->getKey(), value);
|
|
||||||
}
|
|
||||||
|
|
||||||
getParent()->getState()->update(*this);
|
getParent()->getState()->update(*this);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ namespace CSMPrefs
|
||||||
{
|
{
|
||||||
class Category;
|
class Category;
|
||||||
|
|
||||||
class DoubleSetting : public Setting
|
class DoubleSetting final : public TypedSetting<double>
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
@ -17,12 +17,11 @@ namespace CSMPrefs
|
||||||
double mMin;
|
double mMin;
|
||||||
double mMax;
|
double mMax;
|
||||||
std::string mTooltip;
|
std::string mTooltip;
|
||||||
double mDefault;
|
|
||||||
QDoubleSpinBox* mWidget;
|
QDoubleSpinBox* mWidget;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DoubleSetting(
|
explicit DoubleSetting(
|
||||||
Category* parent, QMutex* mutex, const std::string& key, const std::string& label, double default_);
|
Category* parent, QMutex* mutex, std::string_view key, const QString& label, Settings::Index& index);
|
||||||
|
|
||||||
DoubleSetting& setPrecision(int precision);
|
DoubleSetting& setPrecision(int precision);
|
||||||
|
|
||||||
|
@ -36,7 +35,7 @@ namespace CSMPrefs
|
||||||
DoubleSetting& setTooltip(const std::string& tooltip);
|
DoubleSetting& setTooltip(const std::string& tooltip);
|
||||||
|
|
||||||
/// Return label, input widget.
|
/// Return label, input widget.
|
||||||
std::pair<QWidget*, QWidget*> makeWidgets(QWidget* parent) override;
|
SettingWidgets makeWidgets(QWidget* parent) override;
|
||||||
|
|
||||||
void updateWidget() override;
|
void updateWidget() override;
|
||||||
|
|
||||||
|
|
|
@ -15,39 +15,10 @@
|
||||||
#include "category.hpp"
|
#include "category.hpp"
|
||||||
#include "state.hpp"
|
#include "state.hpp"
|
||||||
|
|
||||||
CSMPrefs::EnumValue::EnumValue(const std::string& value, const std::string& tooltip)
|
CSMPrefs::EnumSetting::EnumSetting(Category* parent, QMutex* mutex, std::string_view key, const QString& label,
|
||||||
: mValue(value)
|
std::span<const EnumValueView> values, Settings::Index& index)
|
||||||
, mTooltip(tooltip)
|
: TypedSetting(parent, mutex, key, label, index)
|
||||||
{
|
, mValues(values)
|
||||||
}
|
|
||||||
|
|
||||||
CSMPrefs::EnumValue::EnumValue(const char* value)
|
|
||||||
: mValue(value)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
CSMPrefs::EnumValues& CSMPrefs::EnumValues::add(const EnumValues& values)
|
|
||||||
{
|
|
||||||
mValues.insert(mValues.end(), values.mValues.begin(), values.mValues.end());
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
CSMPrefs::EnumValues& CSMPrefs::EnumValues::add(const EnumValue& value)
|
|
||||||
{
|
|
||||||
mValues.push_back(value);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
CSMPrefs::EnumValues& CSMPrefs::EnumValues::add(const std::string& value, const std::string& tooltip)
|
|
||||||
{
|
|
||||||
mValues.emplace_back(value, tooltip);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
CSMPrefs::EnumSetting::EnumSetting(
|
|
||||||
Category* parent, QMutex* mutex, const std::string& key, const std::string& label, const EnumValue& default_)
|
|
||||||
: Setting(parent, mutex, key, label)
|
|
||||||
, mDefault(default_)
|
|
||||||
, mWidget(nullptr)
|
, mWidget(nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -58,43 +29,28 @@ CSMPrefs::EnumSetting& CSMPrefs::EnumSetting::setTooltip(const std::string& tool
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMPrefs::EnumSetting& CSMPrefs::EnumSetting::addValues(const EnumValues& values)
|
CSMPrefs::SettingWidgets CSMPrefs::EnumSetting::makeWidgets(QWidget* parent)
|
||||||
{
|
{
|
||||||
mValues.add(values);
|
QLabel* label = new QLabel(getLabel(), parent);
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
CSMPrefs::EnumSetting& CSMPrefs::EnumSetting::addValue(const EnumValue& value)
|
|
||||||
{
|
|
||||||
mValues.add(value);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
CSMPrefs::EnumSetting& CSMPrefs::EnumSetting::addValue(const std::string& value, const std::string& tooltip)
|
|
||||||
{
|
|
||||||
mValues.add(value, tooltip);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<QWidget*, QWidget*> CSMPrefs::EnumSetting::makeWidgets(QWidget* parent)
|
|
||||||
{
|
|
||||||
QLabel* label = new QLabel(QString::fromUtf8(getLabel().c_str()), parent);
|
|
||||||
|
|
||||||
mWidget = new QComboBox(parent);
|
mWidget = new QComboBox(parent);
|
||||||
|
|
||||||
size_t index = 0;
|
for (std::size_t i = 0; i < mValues.size(); ++i)
|
||||||
|
|
||||||
for (size_t i = 0; i < mValues.mValues.size(); ++i)
|
|
||||||
{
|
{
|
||||||
if (mDefault.mValue == mValues.mValues[i].mValue)
|
const EnumValueView& v = mValues[i];
|
||||||
index = i;
|
|
||||||
|
|
||||||
mWidget->addItem(QString::fromUtf8(mValues.mValues[i].mValue.c_str()));
|
mWidget->addItem(QString::fromUtf8(v.mValue.data(), static_cast<int>(v.mValue.size())));
|
||||||
|
|
||||||
if (!mValues.mValues[i].mTooltip.empty())
|
if (!v.mTooltip.empty())
|
||||||
mWidget->setItemData(i, QString::fromUtf8(mValues.mValues[i].mTooltip.c_str()), Qt::ToolTipRole);
|
mWidget->setItemData(static_cast<int>(i),
|
||||||
|
QString::fromUtf8(v.mTooltip.data(), static_cast<int>(v.mTooltip.size())), Qt::ToolTipRole);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::string value = getValue();
|
||||||
|
const std::size_t index = std::find_if(mValues.begin(), mValues.end(), [&](const EnumValueView& v) {
|
||||||
|
return v.mValue == value;
|
||||||
|
}) - mValues.begin();
|
||||||
|
|
||||||
mWidget->setCurrentIndex(static_cast<int>(index));
|
mWidget->setCurrentIndex(static_cast<int>(index));
|
||||||
|
|
||||||
if (!mTooltip.empty())
|
if (!mTooltip.empty())
|
||||||
|
@ -105,26 +61,20 @@ std::pair<QWidget*, QWidget*> CSMPrefs::EnumSetting::makeWidgets(QWidget* parent
|
||||||
|
|
||||||
connect(mWidget, qOverload<int>(&QComboBox::currentIndexChanged), this, &EnumSetting::valueChanged);
|
connect(mWidget, qOverload<int>(&QComboBox::currentIndexChanged), this, &EnumSetting::valueChanged);
|
||||||
|
|
||||||
return std::make_pair(label, mWidget);
|
return SettingWidgets{ .mLabel = label, .mInput = mWidget };
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMPrefs::EnumSetting::updateWidget()
|
void CSMPrefs::EnumSetting::updateWidget()
|
||||||
{
|
{
|
||||||
if (mWidget)
|
if (mWidget)
|
||||||
{
|
mWidget->setCurrentIndex(mWidget->findText(QString::fromStdString(getValue())));
|
||||||
int index
|
|
||||||
= mWidget->findText(QString::fromStdString(Settings::Manager::getString(getKey(), getParent()->getKey())));
|
|
||||||
|
|
||||||
mWidget->setCurrentIndex(index);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMPrefs::EnumSetting::valueChanged(int value)
|
void CSMPrefs::EnumSetting::valueChanged(int value)
|
||||||
{
|
{
|
||||||
{
|
if (value < 0 || static_cast<std::size_t>(value) >= mValues.size())
|
||||||
QMutexLocker lock(getMutex());
|
throw std::logic_error("Invalid enum setting \"" + getKey() + "\" value index: " + std::to_string(value));
|
||||||
Settings::Manager::setString(getKey(), getParent()->getKey(), mValues.mValues.at(value).mValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
setValue(std::string(mValues[value].mValue));
|
||||||
getParent()->getState()->update(*this);
|
getParent()->getState()->update(*this);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
#ifndef CSM_PREFS_ENUMSETTING_H
|
#ifndef CSM_PREFS_ENUMSETTING_H
|
||||||
#define CSM_PREFS_ENUMSETTING_H
|
#define CSM_PREFS_ENUMSETTING_H
|
||||||
|
|
||||||
|
#include <span>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "enumvalueview.hpp"
|
||||||
#include "setting.hpp"
|
#include "setting.hpp"
|
||||||
|
|
||||||
class QComboBox;
|
class QComboBox;
|
||||||
|
@ -13,50 +16,22 @@ namespace CSMPrefs
|
||||||
{
|
{
|
||||||
class Category;
|
class Category;
|
||||||
|
|
||||||
struct EnumValue
|
class EnumSetting final : public TypedSetting<std::string>
|
||||||
{
|
|
||||||
std::string mValue;
|
|
||||||
std::string mTooltip;
|
|
||||||
|
|
||||||
EnumValue(const std::string& value, const std::string& tooltip = "");
|
|
||||||
|
|
||||||
EnumValue(const char* value);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct EnumValues
|
|
||||||
{
|
|
||||||
std::vector<EnumValue> mValues;
|
|
||||||
|
|
||||||
EnumValues& add(const EnumValues& values);
|
|
||||||
|
|
||||||
EnumValues& add(const EnumValue& value);
|
|
||||||
|
|
||||||
EnumValues& add(const std::string& value, const std::string& tooltip);
|
|
||||||
};
|
|
||||||
|
|
||||||
class EnumSetting : public Setting
|
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
std::string mTooltip;
|
std::string mTooltip;
|
||||||
EnumValue mDefault;
|
std::span<const EnumValueView> mValues;
|
||||||
EnumValues mValues;
|
|
||||||
QComboBox* mWidget;
|
QComboBox* mWidget;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
EnumSetting(Category* parent, QMutex* mutex, const std::string& key, const std::string& label,
|
explicit EnumSetting(Category* parent, QMutex* mutex, std::string_view key, const QString& label,
|
||||||
const EnumValue& default_);
|
std::span<const EnumValueView> values, Settings::Index& index);
|
||||||
|
|
||||||
EnumSetting& setTooltip(const std::string& tooltip);
|
EnumSetting& setTooltip(const std::string& tooltip);
|
||||||
|
|
||||||
EnumSetting& addValues(const EnumValues& values);
|
|
||||||
|
|
||||||
EnumSetting& addValue(const EnumValue& value);
|
|
||||||
|
|
||||||
EnumSetting& addValue(const std::string& value, const std::string& tooltip);
|
|
||||||
|
|
||||||
/// Return label, input widget.
|
/// Return label, input widget.
|
||||||
std::pair<QWidget*, QWidget*> makeWidgets(QWidget* parent) override;
|
SettingWidgets makeWidgets(QWidget* parent) override;
|
||||||
|
|
||||||
void updateWidget() override;
|
void updateWidget() override;
|
||||||
|
|
||||||
|
|
15
apps/opencs/model/prefs/enumvalueview.hpp
Normal file
15
apps/opencs/model/prefs/enumvalueview.hpp
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#ifndef OPENMW_APPS_OPENCS_MODEL_PREFS_ENUMVALUEVIEW_H
|
||||||
|
#define OPENMW_APPS_OPENCS_MODEL_PREFS_ENUMVALUEVIEW_H
|
||||||
|
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
namespace CSMPrefs
|
||||||
|
{
|
||||||
|
struct EnumValueView
|
||||||
|
{
|
||||||
|
std::string_view mValue;
|
||||||
|
std::string_view mTooltip;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -15,11 +15,10 @@
|
||||||
#include "state.hpp"
|
#include "state.hpp"
|
||||||
|
|
||||||
CSMPrefs::IntSetting::IntSetting(
|
CSMPrefs::IntSetting::IntSetting(
|
||||||
Category* parent, QMutex* mutex, const std::string& key, const std::string& label, int default_)
|
Category* parent, QMutex* mutex, std::string_view key, const QString& label, Settings::Index& index)
|
||||||
: Setting(parent, mutex, key, label)
|
: TypedSetting(parent, mutex, key, label, index)
|
||||||
, mMin(0)
|
, mMin(0)
|
||||||
, mMax(std::numeric_limits<int>::max())
|
, mMax(std::numeric_limits<int>::max())
|
||||||
, mDefault(default_)
|
|
||||||
, mWidget(nullptr)
|
, mWidget(nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -49,13 +48,13 @@ CSMPrefs::IntSetting& CSMPrefs::IntSetting::setTooltip(const std::string& toolti
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<QWidget*, QWidget*> CSMPrefs::IntSetting::makeWidgets(QWidget* parent)
|
CSMPrefs::SettingWidgets CSMPrefs::IntSetting::makeWidgets(QWidget* parent)
|
||||||
{
|
{
|
||||||
QLabel* label = new QLabel(QString::fromUtf8(getLabel().c_str()), parent);
|
QLabel* label = new QLabel(getLabel(), parent);
|
||||||
|
|
||||||
mWidget = new QSpinBox(parent);
|
mWidget = new QSpinBox(parent);
|
||||||
mWidget->setRange(mMin, mMax);
|
mWidget->setRange(mMin, mMax);
|
||||||
mWidget->setValue(mDefault);
|
mWidget->setValue(getValue());
|
||||||
|
|
||||||
if (!mTooltip.empty())
|
if (!mTooltip.empty())
|
||||||
{
|
{
|
||||||
|
@ -66,23 +65,17 @@ std::pair<QWidget*, QWidget*> CSMPrefs::IntSetting::makeWidgets(QWidget* parent)
|
||||||
|
|
||||||
connect(mWidget, qOverload<int>(&QSpinBox::valueChanged), this, &IntSetting::valueChanged);
|
connect(mWidget, qOverload<int>(&QSpinBox::valueChanged), this, &IntSetting::valueChanged);
|
||||||
|
|
||||||
return std::make_pair(label, mWidget);
|
return SettingWidgets{ .mLabel = label, .mInput = mWidget };
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMPrefs::IntSetting::updateWidget()
|
void CSMPrefs::IntSetting::updateWidget()
|
||||||
{
|
{
|
||||||
if (mWidget)
|
if (mWidget)
|
||||||
{
|
mWidget->setValue(getValue());
|
||||||
mWidget->setValue(Settings::Manager::getInt(getKey(), getParent()->getKey()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMPrefs::IntSetting::valueChanged(int value)
|
void CSMPrefs::IntSetting::valueChanged(int value)
|
||||||
{
|
{
|
||||||
{
|
setValue(value);
|
||||||
QMutexLocker lock(getMutex());
|
|
||||||
Settings::Manager::setInt(getKey(), getParent()->getKey(), value);
|
|
||||||
}
|
|
||||||
|
|
||||||
getParent()->getState()->update(*this);
|
getParent()->getState()->update(*this);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,18 +12,18 @@ namespace CSMPrefs
|
||||||
{
|
{
|
||||||
class Category;
|
class Category;
|
||||||
|
|
||||||
class IntSetting : public Setting
|
class IntSetting final : public TypedSetting<int>
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
int mMin;
|
int mMin;
|
||||||
int mMax;
|
int mMax;
|
||||||
std::string mTooltip;
|
std::string mTooltip;
|
||||||
int mDefault;
|
|
||||||
QSpinBox* mWidget;
|
QSpinBox* mWidget;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
IntSetting(Category* parent, QMutex* mutex, const std::string& key, const std::string& label, int default_);
|
explicit IntSetting(
|
||||||
|
Category* parent, QMutex* mutex, std::string_view key, const QString& label, Settings::Index& index);
|
||||||
|
|
||||||
// defaults to [0, std::numeric_limits<int>::max()]
|
// defaults to [0, std::numeric_limits<int>::max()]
|
||||||
IntSetting& setRange(int min, int max);
|
IntSetting& setRange(int min, int max);
|
||||||
|
@ -35,7 +35,7 @@ namespace CSMPrefs
|
||||||
IntSetting& setTooltip(const std::string& tooltip);
|
IntSetting& setTooltip(const std::string& tooltip);
|
||||||
|
|
||||||
/// Return label, input widget.
|
/// Return label, input widget.
|
||||||
std::pair<QWidget*, QWidget*> makeWidgets(QWidget* parent) override;
|
SettingWidgets makeWidgets(QWidget* parent) override;
|
||||||
|
|
||||||
void updateWidget() override;
|
void updateWidget() override;
|
||||||
|
|
||||||
|
|
|
@ -19,21 +19,22 @@ class QWidget;
|
||||||
|
|
||||||
namespace CSMPrefs
|
namespace CSMPrefs
|
||||||
{
|
{
|
||||||
ModifierSetting::ModifierSetting(Category* parent, QMutex* mutex, const std::string& key, const std::string& label)
|
ModifierSetting::ModifierSetting(
|
||||||
: Setting(parent, mutex, key, label)
|
Category* parent, QMutex* mutex, std::string_view key, const QString& label, Settings::Index& index)
|
||||||
|
: TypedSetting(parent, mutex, key, label, index)
|
||||||
, mButton(nullptr)
|
, mButton(nullptr)
|
||||||
, mEditorActive(false)
|
, mEditorActive(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<QWidget*, QWidget*> ModifierSetting::makeWidgets(QWidget* parent)
|
SettingWidgets ModifierSetting::makeWidgets(QWidget* parent)
|
||||||
{
|
{
|
||||||
int modifier = 0;
|
int modifier = 0;
|
||||||
State::get().getShortcutManager().getModifier(getKey(), modifier);
|
State::get().getShortcutManager().getModifier(getKey(), modifier);
|
||||||
|
|
||||||
QString text = QString::fromUtf8(State::get().getShortcutManager().convertToString(modifier).c_str());
|
QString text = QString::fromUtf8(State::get().getShortcutManager().convertToString(modifier).c_str());
|
||||||
|
|
||||||
QLabel* label = new QLabel(QString::fromUtf8(getLabel().c_str()), parent);
|
QLabel* label = new QLabel(getLabel(), parent);
|
||||||
QPushButton* widget = new QPushButton(text, parent);
|
QPushButton* widget = new QPushButton(text, parent);
|
||||||
|
|
||||||
widget->setCheckable(true);
|
widget->setCheckable(true);
|
||||||
|
@ -46,14 +47,14 @@ namespace CSMPrefs
|
||||||
|
|
||||||
connect(widget, &QPushButton::toggled, this, &ModifierSetting::buttonToggled);
|
connect(widget, &QPushButton::toggled, this, &ModifierSetting::buttonToggled);
|
||||||
|
|
||||||
return std::make_pair(label, widget);
|
return SettingWidgets{ .mLabel = label, .mInput = widget };
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModifierSetting::updateWidget()
|
void ModifierSetting::updateWidget()
|
||||||
{
|
{
|
||||||
if (mButton)
|
if (mButton)
|
||||||
{
|
{
|
||||||
const std::string& shortcut = Settings::Manager::getString(getKey(), getParent()->getKey());
|
const std::string& shortcut = getValue();
|
||||||
|
|
||||||
int modifier;
|
int modifier;
|
||||||
State::get().getShortcutManager().convertFromString(shortcut, modifier);
|
State::get().getShortcutManager().convertFromString(shortcut, modifier);
|
||||||
|
@ -131,15 +132,7 @@ namespace CSMPrefs
|
||||||
void ModifierSetting::storeValue(int modifier)
|
void ModifierSetting::storeValue(int modifier)
|
||||||
{
|
{
|
||||||
State::get().getShortcutManager().setModifier(getKey(), modifier);
|
State::get().getShortcutManager().setModifier(getKey(), modifier);
|
||||||
|
setValue(State::get().getShortcutManager().convertToString(modifier));
|
||||||
// Convert to string and assign
|
|
||||||
std::string value = State::get().getShortcutManager().convertToString(modifier);
|
|
||||||
|
|
||||||
{
|
|
||||||
QMutexLocker lock(getMutex());
|
|
||||||
Settings::Manager::setString(getKey(), getParent()->getKey(), value);
|
|
||||||
}
|
|
||||||
|
|
||||||
getParent()->getState()->update(*this);
|
getParent()->getState()->update(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,14 +15,16 @@ class QPushButton;
|
||||||
namespace CSMPrefs
|
namespace CSMPrefs
|
||||||
{
|
{
|
||||||
class Category;
|
class Category;
|
||||||
class ModifierSetting : public Setting
|
|
||||||
|
class ModifierSetting final : public TypedSetting<std::string>
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ModifierSetting(Category* parent, QMutex* mutex, const std::string& key, const std::string& label);
|
explicit ModifierSetting(
|
||||||
|
Category* parent, QMutex* mutex, std::string_view key, const QString& label, Settings::Index& index);
|
||||||
|
|
||||||
std::pair<QWidget*, QWidget*> makeWidgets(QWidget* parent) override;
|
SettingWidgets makeWidgets(QWidget* parent) override;
|
||||||
|
|
||||||
void updateWidget() override;
|
void updateWidget() override;
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <QMutexLocker>
|
#include <QMutexLocker>
|
||||||
|
|
||||||
#include <components/settings/settings.hpp>
|
#include <components/settings/settings.hpp>
|
||||||
|
#include <components/settings/settingvalue.hpp>
|
||||||
|
|
||||||
#include "category.hpp"
|
#include "category.hpp"
|
||||||
#include "state.hpp"
|
#include "state.hpp"
|
||||||
|
@ -14,22 +15,17 @@ QMutex* CSMPrefs::Setting::getMutex()
|
||||||
return mMutex;
|
return mMutex;
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMPrefs::Setting::Setting(Category* parent, QMutex* mutex, const std::string& key, const std::string& label)
|
CSMPrefs::Setting::Setting(
|
||||||
|
Category* parent, QMutex* mutex, std::string_view key, const QString& label, Settings::Index& index)
|
||||||
: QObject(parent->getState())
|
: QObject(parent->getState())
|
||||||
, mParent(parent)
|
, mParent(parent)
|
||||||
, mMutex(mutex)
|
, mMutex(mutex)
|
||||||
, mKey(key)
|
, mKey(key)
|
||||||
, mLabel(label)
|
, mLabel(label)
|
||||||
|
, mIndex(index)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<QWidget*, QWidget*> CSMPrefs::Setting::makeWidgets(QWidget* parent)
|
|
||||||
{
|
|
||||||
return std::pair<QWidget*, QWidget*>(0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CSMPrefs::Setting::updateWidget() {}
|
|
||||||
|
|
||||||
const CSMPrefs::Category* CSMPrefs::Setting::getParent() const
|
const CSMPrefs::Category* CSMPrefs::Setting::getParent() const
|
||||||
{
|
{
|
||||||
return mParent;
|
return mParent;
|
||||||
|
@ -40,35 +36,6 @@ const std::string& CSMPrefs::Setting::getKey() const
|
||||||
return mKey;
|
return mKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string& CSMPrefs::Setting::getLabel() const
|
|
||||||
{
|
|
||||||
return mLabel;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CSMPrefs::Setting::toInt() const
|
|
||||||
{
|
|
||||||
QMutexLocker lock(mMutex);
|
|
||||||
return Settings::Manager::getInt(mKey, mParent->getKey());
|
|
||||||
}
|
|
||||||
|
|
||||||
double CSMPrefs::Setting::toDouble() const
|
|
||||||
{
|
|
||||||
QMutexLocker lock(mMutex);
|
|
||||||
return Settings::Manager::getFloat(mKey, mParent->getKey());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string CSMPrefs::Setting::toString() const
|
|
||||||
{
|
|
||||||
QMutexLocker lock(mMutex);
|
|
||||||
return Settings::Manager::getString(mKey, mParent->getKey());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CSMPrefs::Setting::isTrue() const
|
|
||||||
{
|
|
||||||
QMutexLocker lock(mMutex);
|
|
||||||
return Settings::Manager::getBool(mKey, mParent->getKey());
|
|
||||||
}
|
|
||||||
|
|
||||||
QColor CSMPrefs::Setting::toColor() const
|
QColor CSMPrefs::Setting::toColor() const
|
||||||
{
|
{
|
||||||
// toString() handles lock
|
// toString() handles lock
|
||||||
|
|
|
@ -4,15 +4,26 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
#include <QMutexLocker>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
||||||
|
#include <components/settings/settingvalue.hpp>
|
||||||
|
|
||||||
|
#include "category.hpp"
|
||||||
|
|
||||||
class QWidget;
|
class QWidget;
|
||||||
class QColor;
|
class QColor;
|
||||||
class QMutex;
|
class QMutex;
|
||||||
|
class QGridLayout;
|
||||||
|
class QLabel;
|
||||||
|
|
||||||
namespace CSMPrefs
|
namespace CSMPrefs
|
||||||
{
|
{
|
||||||
class Category;
|
struct SettingWidgets
|
||||||
|
{
|
||||||
|
QLabel* mLabel;
|
||||||
|
QWidget* mInput;
|
||||||
|
};
|
||||||
|
|
||||||
class Setting : public QObject
|
class Setting : public QObject
|
||||||
{
|
{
|
||||||
|
@ -21,44 +32,82 @@ namespace CSMPrefs
|
||||||
Category* mParent;
|
Category* mParent;
|
||||||
QMutex* mMutex;
|
QMutex* mMutex;
|
||||||
std::string mKey;
|
std::string mKey;
|
||||||
std::string mLabel;
|
QString mLabel;
|
||||||
|
Settings::Index& mIndex;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QMutex* getMutex();
|
QMutex* getMutex();
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void resetValueImpl()
|
||||||
|
{
|
||||||
|
QMutexLocker lock(mMutex);
|
||||||
|
return mIndex.get<T>(mParent->getKey(), mKey).reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
T getValueImpl() const
|
||||||
|
{
|
||||||
|
QMutexLocker lock(mMutex);
|
||||||
|
return mIndex.get<T>(mParent->getKey(), mKey).get();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void setValueImpl(const T& value)
|
||||||
|
{
|
||||||
|
QMutexLocker lock(mMutex);
|
||||||
|
return mIndex.get<T>(mParent->getKey(), mKey).set(value);
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Setting(Category* parent, QMutex* mutex, const std::string& key, const std::string& label);
|
explicit Setting(
|
||||||
|
Category* parent, QMutex* mutex, std::string_view key, const QString& label, Settings::Index& index);
|
||||||
|
|
||||||
~Setting() override = default;
|
~Setting() override = default;
|
||||||
|
|
||||||
/// Return label, input widget.
|
virtual SettingWidgets makeWidgets(QWidget* parent) = 0;
|
||||||
///
|
|
||||||
/// \note first can be a 0-pointer, which means that the label is part of the input
|
|
||||||
/// widget.
|
|
||||||
virtual std::pair<QWidget*, QWidget*> makeWidgets(QWidget* parent);
|
|
||||||
|
|
||||||
/// Updates the widget returned by makeWidgets() to the current setting.
|
/// Updates the widget returned by makeWidgets() to the current setting.
|
||||||
///
|
///
|
||||||
/// \note If make_widgets() has not been called yet then nothing happens.
|
/// \note If make_widgets() has not been called yet then nothing happens.
|
||||||
virtual void updateWidget();
|
virtual void updateWidget() = 0;
|
||||||
|
|
||||||
|
virtual void reset() = 0;
|
||||||
|
|
||||||
const Category* getParent() const;
|
const Category* getParent() const;
|
||||||
|
|
||||||
const std::string& getKey() const;
|
const std::string& getKey() const;
|
||||||
|
|
||||||
const std::string& getLabel() const;
|
const QString& getLabel() const { return mLabel; }
|
||||||
|
|
||||||
int toInt() const;
|
int toInt() const { return getValueImpl<int>(); }
|
||||||
|
|
||||||
double toDouble() const;
|
double toDouble() const { return getValueImpl<double>(); }
|
||||||
|
|
||||||
std::string toString() const;
|
std::string toString() const { return getValueImpl<std::string>(); }
|
||||||
|
|
||||||
bool isTrue() const;
|
bool isTrue() const { return getValueImpl<bool>(); }
|
||||||
|
|
||||||
QColor toColor() const;
|
QColor toColor() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class TypedSetting : public Setting
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using Setting::Setting;
|
||||||
|
|
||||||
|
void reset() final
|
||||||
|
{
|
||||||
|
resetValueImpl<T>();
|
||||||
|
updateWidget();
|
||||||
|
}
|
||||||
|
|
||||||
|
T getValue() const { return getValueImpl<T>(); }
|
||||||
|
|
||||||
|
void setValue(const T& value) { return setValueImpl(value); }
|
||||||
|
};
|
||||||
|
|
||||||
// note: fullKeys have the format categoryKey/settingKey
|
// note: fullKeys have the format categoryKey/settingKey
|
||||||
bool operator==(const Setting& setting, const std::string& fullKey);
|
bool operator==(const Setting& setting, const std::string& fullKey);
|
||||||
bool operator==(const std::string& fullKey, const Setting& setting);
|
bool operator==(const std::string& fullKey, const Setting& setting);
|
||||||
|
|
|
@ -91,7 +91,7 @@ namespace CSMPrefs
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShortcutManager::setModifier(const std::string& name, int modifier)
|
void ShortcutManager::setModifier(std::string_view name, int modifier)
|
||||||
{
|
{
|
||||||
// Add to map/modify
|
// Add to map/modify
|
||||||
ModifierMap::iterator item = mModifiers.find(name);
|
ModifierMap::iterator item = mModifiers.find(name);
|
||||||
|
|
|
@ -32,7 +32,7 @@ namespace CSMPrefs
|
||||||
void setSequence(const std::string& name, const QKeySequence& sequence);
|
void setSequence(const std::string& name, const QKeySequence& sequence);
|
||||||
|
|
||||||
bool getModifier(const std::string& name, int& modifier) const;
|
bool getModifier(const std::string& name, int& modifier) const;
|
||||||
void setModifier(const std::string& name, int modifier);
|
void setModifier(std::string_view name, int modifier);
|
||||||
|
|
||||||
std::string convertToString(const QKeySequence& sequence) const;
|
std::string convertToString(const QKeySequence& sequence) const;
|
||||||
std::string convertToString(int modifier) const;
|
std::string convertToString(int modifier) const;
|
||||||
|
@ -49,9 +49,9 @@ namespace CSMPrefs
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Need a multimap in case multiple shortcuts share the same name
|
// Need a multimap in case multiple shortcuts share the same name
|
||||||
typedef std::multimap<std::string, Shortcut*> ShortcutMap;
|
typedef std::multimap<std::string, Shortcut*, std::less<>> ShortcutMap;
|
||||||
typedef std::map<std::string, QKeySequence> SequenceMap;
|
typedef std::map<std::string, QKeySequence> SequenceMap;
|
||||||
typedef std::map<std::string, int> ModifierMap;
|
typedef std::map<std::string, int, std::less<>> ModifierMap;
|
||||||
typedef std::map<int, std::string> NameMap;
|
typedef std::map<int, std::string> NameMap;
|
||||||
typedef std::map<std::string, int> KeyMap;
|
typedef std::map<std::string, int> KeyMap;
|
||||||
|
|
||||||
|
|
|
@ -18,8 +18,9 @@
|
||||||
|
|
||||||
namespace CSMPrefs
|
namespace CSMPrefs
|
||||||
{
|
{
|
||||||
ShortcutSetting::ShortcutSetting(Category* parent, QMutex* mutex, const std::string& key, const std::string& label)
|
ShortcutSetting::ShortcutSetting(
|
||||||
: Setting(parent, mutex, key, label)
|
Category* parent, QMutex* mutex, const std::string& key, const QString& label, Settings::Index& index)
|
||||||
|
: TypedSetting(parent, mutex, key, label, index)
|
||||||
, mButton(nullptr)
|
, mButton(nullptr)
|
||||||
, mEditorActive(false)
|
, mEditorActive(false)
|
||||||
, mEditorPos(0)
|
, mEditorPos(0)
|
||||||
|
@ -30,14 +31,14 @@ namespace CSMPrefs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<QWidget*, QWidget*> ShortcutSetting::makeWidgets(QWidget* parent)
|
SettingWidgets ShortcutSetting::makeWidgets(QWidget* parent)
|
||||||
{
|
{
|
||||||
QKeySequence sequence;
|
QKeySequence sequence;
|
||||||
State::get().getShortcutManager().getSequence(getKey(), sequence);
|
State::get().getShortcutManager().getSequence(getKey(), sequence);
|
||||||
|
|
||||||
QString text = QString::fromUtf8(State::get().getShortcutManager().convertToString(sequence).c_str());
|
QString text = QString::fromUtf8(State::get().getShortcutManager().convertToString(sequence).c_str());
|
||||||
|
|
||||||
QLabel* label = new QLabel(QString::fromUtf8(getLabel().c_str()), parent);
|
QLabel* label = new QLabel(getLabel(), parent);
|
||||||
QPushButton* widget = new QPushButton(text, parent);
|
QPushButton* widget = new QPushButton(text, parent);
|
||||||
|
|
||||||
widget->setCheckable(true);
|
widget->setCheckable(true);
|
||||||
|
@ -50,14 +51,14 @@ namespace CSMPrefs
|
||||||
|
|
||||||
connect(widget, &QPushButton::toggled, this, &ShortcutSetting::buttonToggled);
|
connect(widget, &QPushButton::toggled, this, &ShortcutSetting::buttonToggled);
|
||||||
|
|
||||||
return std::make_pair(label, widget);
|
return SettingWidgets{ .mLabel = label, .mInput = widget };
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShortcutSetting::updateWidget()
|
void ShortcutSetting::updateWidget()
|
||||||
{
|
{
|
||||||
if (mButton)
|
if (mButton)
|
||||||
{
|
{
|
||||||
const std::string& shortcut = Settings::Manager::getString(getKey(), getParent()->getKey());
|
const std::string shortcut = getValue();
|
||||||
|
|
||||||
QKeySequence sequence;
|
QKeySequence sequence;
|
||||||
State::get().getShortcutManager().convertFromString(shortcut, sequence);
|
State::get().getShortcutManager().convertFromString(shortcut, sequence);
|
||||||
|
@ -170,15 +171,7 @@ namespace CSMPrefs
|
||||||
void ShortcutSetting::storeValue(const QKeySequence& sequence)
|
void ShortcutSetting::storeValue(const QKeySequence& sequence)
|
||||||
{
|
{
|
||||||
State::get().getShortcutManager().setSequence(getKey(), sequence);
|
State::get().getShortcutManager().setSequence(getKey(), sequence);
|
||||||
|
setValue(State::get().getShortcutManager().convertToString(sequence));
|
||||||
// Convert to string and assign
|
|
||||||
std::string value = State::get().getShortcutManager().convertToString(sequence);
|
|
||||||
|
|
||||||
{
|
|
||||||
QMutexLocker lock(getMutex());
|
|
||||||
Settings::Manager::setString(getKey(), getParent()->getKey(), value);
|
|
||||||
}
|
|
||||||
|
|
||||||
getParent()->getState()->update(*this);
|
getParent()->getState()->update(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,14 +17,16 @@ class QWidget;
|
||||||
namespace CSMPrefs
|
namespace CSMPrefs
|
||||||
{
|
{
|
||||||
class Category;
|
class Category;
|
||||||
class ShortcutSetting : public Setting
|
|
||||||
|
class ShortcutSetting final : public TypedSetting<std::string>
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ShortcutSetting(Category* parent, QMutex* mutex, const std::string& key, const std::string& label);
|
explicit ShortcutSetting(
|
||||||
|
Category* parent, QMutex* mutex, const std::string& key, const QString& label, Settings::Index& index);
|
||||||
|
|
||||||
std::pair<QWidget*, QWidget*> makeWidgets(QWidget* parent) override;
|
SettingWidgets makeWidgets(QWidget* parent) override;
|
||||||
|
|
||||||
void updateWidget() override;
|
void updateWidget() override;
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <apps/opencs/model/prefs/enumsetting.hpp>
|
#include <apps/opencs/model/prefs/enumsetting.hpp>
|
||||||
#include <apps/opencs/model/prefs/setting.hpp>
|
#include <apps/opencs/model/prefs/setting.hpp>
|
||||||
#include <apps/opencs/model/prefs/shortcutmanager.hpp>
|
#include <apps/opencs/model/prefs/shortcutmanager.hpp>
|
||||||
|
#include <apps/opencs/model/prefs/subcategory.hpp>
|
||||||
|
|
||||||
#include <components/settings/categories.hpp>
|
#include <components/settings/categories.hpp>
|
||||||
#include <components/settings/settings.hpp>
|
#include <components/settings/settings.hpp>
|
||||||
|
@ -24,50 +25,43 @@
|
||||||
#include "modifiersetting.hpp"
|
#include "modifiersetting.hpp"
|
||||||
#include "shortcutsetting.hpp"
|
#include "shortcutsetting.hpp"
|
||||||
#include "stringsetting.hpp"
|
#include "stringsetting.hpp"
|
||||||
|
#include "values.hpp"
|
||||||
|
|
||||||
CSMPrefs::State* CSMPrefs::State::sThis = nullptr;
|
CSMPrefs::State* CSMPrefs::State::sThis = nullptr;
|
||||||
|
|
||||||
void CSMPrefs::State::declare()
|
void CSMPrefs::State::declare()
|
||||||
{
|
{
|
||||||
declareCategory("Windows");
|
declareCategory("Windows");
|
||||||
declareInt("default-width", "Default window width", 800)
|
declareInt(mValues->mWindows.mDefaultWidth, "Default window width")
|
||||||
.setTooltip("Newly opened top-level windows will open with this width.")
|
.setTooltip("Newly opened top-level windows will open with this width.")
|
||||||
.setMin(80);
|
.setMin(80);
|
||||||
declareInt("default-height", "Default window height", 600)
|
declareInt(mValues->mWindows.mDefaultHeight, "Default window height")
|
||||||
.setTooltip("Newly opened top-level windows will open with this height.")
|
.setTooltip("Newly opened top-level windows will open with this height.")
|
||||||
.setMin(80);
|
.setMin(80);
|
||||||
declareBool("show-statusbar", "Show Status Bar", true)
|
declareBool(mValues->mWindows.mShowStatusbar, "Show Status Bar")
|
||||||
.setTooltip(
|
.setTooltip(
|
||||||
"If a newly open top level window is showing status bars or not. "
|
"If a newly open top level window is showing status bars or not. "
|
||||||
" Note that this does not affect existing windows.");
|
" Note that this does not affect existing windows.");
|
||||||
declareSeparator();
|
declareBool(mValues->mWindows.mReuse, "Reuse Subviews")
|
||||||
declareBool("reuse", "Reuse Subviews", true)
|
|
||||||
.setTooltip(
|
.setTooltip(
|
||||||
"When a new subview is requested and a matching subview already "
|
"When a new subview is requested and a matching subview already "
|
||||||
" exist, do not open a new subview and use the existing one instead.");
|
" exist, do not open a new subview and use the existing one instead.");
|
||||||
declareInt("max-subviews", "Maximum number of subviews per top-level window", 256)
|
declareInt(mValues->mWindows.mMaxSubviews, "Maximum number of subviews per top-level window")
|
||||||
.setTooltip(
|
.setTooltip(
|
||||||
"If the maximum number is reached and a new subview is opened "
|
"If the maximum number is reached and a new subview is opened "
|
||||||
"it will be placed into a new top-level window.")
|
"it will be placed into a new top-level window.")
|
||||||
.setRange(1, 256);
|
.setRange(1, 256);
|
||||||
declareBool("hide-subview", "Hide single subview", false)
|
declareBool(mValues->mWindows.mHideSubview, "Hide single subview")
|
||||||
.setTooltip(
|
.setTooltip(
|
||||||
"When a view contains only a single subview, hide the subview title "
|
"When a view contains only a single subview, hide the subview title "
|
||||||
"bar and if this subview is closed also close the view (unless it is the last "
|
"bar and if this subview is closed also close the view (unless it is the last "
|
||||||
"view for this document)");
|
"view for this document)");
|
||||||
declareInt("minimum-width", "Minimum subview width", 325)
|
declareInt(mValues->mWindows.mMinimumWidth, "Minimum subview width")
|
||||||
.setTooltip("Minimum width of subviews.")
|
.setTooltip("Minimum width of subviews.")
|
||||||
.setRange(50, 10000);
|
.setRange(50, 10000);
|
||||||
declareSeparator();
|
declareEnum(mValues->mWindows.mMainwindowScrollbar, "Horizontal scrollbar mode for main window.");
|
||||||
EnumValue scrollbarOnly("Scrollbar Only",
|
|
||||||
"Simple addition of scrollbars, the view window "
|
|
||||||
"does not grow automatically.");
|
|
||||||
declareEnum("mainwindow-scrollbar", "Horizontal scrollbar mode for main window.", scrollbarOnly)
|
|
||||||
.addValue(scrollbarOnly)
|
|
||||||
.addValue("Grow Only", "The view window grows as subviews are added. No scrollbars.")
|
|
||||||
.addValue("Grow then Scroll", "The view window grows. The scrollbar appears once it cannot grow any further.");
|
|
||||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||||
declareBool("grow-limit", "Grow Limit Screen", false)
|
declareBool(mValues->mWindows.mGrowLimit, "Grow Limit Screen")
|
||||||
.setTooltip(
|
.setTooltip(
|
||||||
"When \"Grow then Scroll\" option is selected, the window size grows to"
|
"When \"Grow then Scroll\" option is selected, the window size grows to"
|
||||||
" the width of the virtual desktop. \nIf this option is selected the the window growth"
|
" the width of the virtual desktop. \nIf this option is selected the the window growth"
|
||||||
|
@ -75,93 +69,64 @@ void CSMPrefs::State::declare()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
declareCategory("Records");
|
declareCategory("Records");
|
||||||
EnumValue iconAndText("Icon and Text");
|
declareEnum(mValues->mRecords.mStatusFormat, "Modification status display format");
|
||||||
EnumValues recordValues;
|
declareEnum(mValues->mRecords.mTypeFormat, "ID type display format");
|
||||||
recordValues.add(iconAndText).add("Icon Only").add("Text Only");
|
|
||||||
declareEnum("status-format", "Modification status display format", iconAndText).addValues(recordValues);
|
|
||||||
declareEnum("type-format", "ID type display format", iconAndText).addValues(recordValues);
|
|
||||||
|
|
||||||
declareCategory("ID Tables");
|
declareCategory("ID Tables");
|
||||||
EnumValue inPlaceEdit("Edit in Place", "Edit the clicked cell");
|
declareEnum(mValues->mIdTables.mDouble, "Double Click");
|
||||||
EnumValue editRecord("Edit Record", "Open a dialogue subview for the clicked record");
|
declareEnum(mValues->mIdTables.mDoubleS, "Shift Double Click");
|
||||||
EnumValue view("View", "Open a scene subview for the clicked record (not available everywhere)");
|
declareEnum(mValues->mIdTables.mDoubleC, "Control Double Click");
|
||||||
EnumValue editRecordAndClose("Edit Record and Close");
|
declareEnum(mValues->mIdTables.mDoubleSc, "Shift Control Double Click");
|
||||||
EnumValues doubleClickValues;
|
declareEnum(mValues->mIdTables.mJumpToAdded, "Action on adding or cloning a record");
|
||||||
doubleClickValues.add(inPlaceEdit)
|
declareBool(
|
||||||
.add(editRecord)
|
mValues->mIdTables.mExtendedConfig, "Manually specify affected record types for an extended delete/revert")
|
||||||
.add(view)
|
|
||||||
.add("Revert")
|
|
||||||
.add("Delete")
|
|
||||||
.add(editRecordAndClose)
|
|
||||||
.add("View and Close", "Open a scene subview for the clicked record and close the table subview");
|
|
||||||
declareEnum("double", "Double Click", inPlaceEdit).addValues(doubleClickValues);
|
|
||||||
declareEnum("double-s", "Shift Double Click", editRecord).addValues(doubleClickValues);
|
|
||||||
declareEnum("double-c", "Control Double Click", view).addValues(doubleClickValues);
|
|
||||||
declareEnum("double-sc", "Shift Control Double Click", editRecordAndClose).addValues(doubleClickValues);
|
|
||||||
declareSeparator();
|
|
||||||
EnumValue jumpAndSelect("Jump and Select", "Scroll new record into view and make it the selection");
|
|
||||||
declareEnum("jump-to-added", "Action on adding or cloning a record", jumpAndSelect)
|
|
||||||
.addValue(jumpAndSelect)
|
|
||||||
.addValue("Jump Only", "Scroll new record into view")
|
|
||||||
.addValue("No Jump", "No special action");
|
|
||||||
declareBool("extended-config", "Manually specify affected record types for an extended delete/revert", false)
|
|
||||||
.setTooltip(
|
.setTooltip(
|
||||||
"Delete and revert commands have an extended form that also affects "
|
"Delete and revert commands have an extended form that also affects "
|
||||||
"associated records.\n\n"
|
"associated records.\n\n"
|
||||||
"If this option is enabled, types of affected records are selected "
|
"If this option is enabled, types of affected records are selected "
|
||||||
"manually before a command execution.\nOtherwise, all associated "
|
"manually before a command execution.\nOtherwise, all associated "
|
||||||
"records are deleted/reverted immediately.");
|
"records are deleted/reverted immediately.");
|
||||||
declareBool("subview-new-window", "Open Record in new window", false)
|
declareBool(mValues->mIdTables.mSubviewNewWindow, "Open Record in new window")
|
||||||
.setTooltip(
|
.setTooltip(
|
||||||
"When editing a record, open the view in a new window,"
|
"When editing a record, open the view in a new window,"
|
||||||
" rather than docked in the main view.");
|
" rather than docked in the main view.");
|
||||||
|
|
||||||
declareCategory("ID Dialogues");
|
declareCategory("ID Dialogues");
|
||||||
declareBool("toolbar", "Show toolbar", true);
|
declareBool(mValues->mIdDialogues.mToolbar, "Show toolbar");
|
||||||
|
|
||||||
declareCategory("Reports");
|
declareCategory("Reports");
|
||||||
EnumValue actionNone("None");
|
declareEnum(mValues->mReports.mDouble, "Double Click");
|
||||||
EnumValue actionEdit("Edit", "Open a table or dialogue suitable for addressing the listed report");
|
declareEnum(mValues->mReports.mDoubleS, "Shift Double Click");
|
||||||
EnumValue actionRemove("Remove", "Remove the report from the report table");
|
declareEnum(mValues->mReports.mDoubleC, "Control Double Click");
|
||||||
EnumValue actionEditAndRemove("Edit And Remove",
|
declareEnum(mValues->mReports.mDoubleSc, "Shift Control Double Click");
|
||||||
"Open a table or dialogue suitable for addressing the listed report, then remove the report from the report "
|
declareBool(mValues->mReports.mIgnoreBaseRecords, "Ignore base records in verifier");
|
||||||
"table");
|
|
||||||
EnumValues reportValues;
|
|
||||||
reportValues.add(actionNone).add(actionEdit).add(actionRemove).add(actionEditAndRemove);
|
|
||||||
declareEnum("double", "Double Click", actionEdit).addValues(reportValues);
|
|
||||||
declareEnum("double-s", "Shift Double Click", actionRemove).addValues(reportValues);
|
|
||||||
declareEnum("double-c", "Control Double Click", actionEditAndRemove).addValues(reportValues);
|
|
||||||
declareEnum("double-sc", "Shift Control Double Click", actionNone).addValues(reportValues);
|
|
||||||
declareBool("ignore-base-records", "Ignore base records in verifier", false);
|
|
||||||
|
|
||||||
declareCategory("Search & Replace");
|
declareCategory("Search & Replace");
|
||||||
declareInt("char-before", "Characters before search string", 10)
|
declareInt(mValues->mSearchAndReplace.mCharBefore, "Characters before search string")
|
||||||
.setTooltip("Maximum number of character to display in search result before the searched text");
|
.setTooltip("Maximum number of character to display in search result before the searched text");
|
||||||
declareInt("char-after", "Characters after search string", 10)
|
declareInt(mValues->mSearchAndReplace.mCharAfter, "Characters after search string")
|
||||||
.setTooltip("Maximum number of character to display in search result after the searched text");
|
.setTooltip("Maximum number of character to display in search result after the searched text");
|
||||||
declareBool("auto-delete", "Delete row from result table after a successful replace", true);
|
declareBool(mValues->mSearchAndReplace.mAutoDelete, "Delete row from result table after a successful replace");
|
||||||
|
|
||||||
declareCategory("Scripts");
|
declareCategory("Scripts");
|
||||||
declareBool("show-linenum", "Show Line Numbers", true)
|
declareBool(mValues->mScripts.mShowLinenum, "Show Line Numbers")
|
||||||
.setTooltip(
|
.setTooltip(
|
||||||
"Show line numbers to the left of the script editor window."
|
"Show line numbers to the left of the script editor window."
|
||||||
"The current row and column numbers of the text cursor are shown at the bottom.");
|
"The current row and column numbers of the text cursor are shown at the bottom.");
|
||||||
declareBool("wrap-lines", "Wrap Lines", false).setTooltip("Wrap lines longer than width of script editor.");
|
declareBool(mValues->mScripts.mWrapLines, "Wrap Lines")
|
||||||
declareBool("mono-font", "Use monospace font", true);
|
.setTooltip("Wrap lines longer than width of script editor.");
|
||||||
declareInt("tab-width", "Tab Width", 4).setTooltip("Number of characters for tab width").setRange(1, 10);
|
declareBool(mValues->mScripts.mMonoFont, "Use monospace font");
|
||||||
EnumValue warningsNormal("Normal", "Report warnings as warning");
|
declareInt(mValues->mScripts.mTabWidth, "Tab Width")
|
||||||
declareEnum("warnings", "Warning Mode", warningsNormal)
|
.setTooltip("Number of characters for tab width")
|
||||||
.addValue("Ignore", "Do not report warning")
|
.setRange(1, 10);
|
||||||
.addValue(warningsNormal)
|
declareEnum(mValues->mScripts.mWarnings, "Warning Mode");
|
||||||
.addValue("Strict", "Promote warning to an error");
|
declareBool(mValues->mScripts.mToolbar, "Show toolbar");
|
||||||
declareBool("toolbar", "Show toolbar", true);
|
declareInt(mValues->mScripts.mCompileDelay, "Delay between updating of source errors")
|
||||||
declareInt("compile-delay", "Delay between updating of source errors", 100)
|
|
||||||
.setTooltip("Delay in milliseconds")
|
.setTooltip("Delay in milliseconds")
|
||||||
.setRange(0, 10000);
|
.setRange(0, 10000);
|
||||||
declareInt("error-height", "Initial height of the error panel", 100).setRange(100, 10000);
|
declareInt(mValues->mScripts.mErrorHeight, "Initial height of the error panel").setRange(100, 10000);
|
||||||
declareBool("highlight-occurrences", "Highlight other occurrences of selected names", true);
|
declareBool(mValues->mScripts.mHighlightOccurrences, "Highlight other occurrences of selected names");
|
||||||
declareColour("colour-highlight", "Colour of highlighted occurrences", QColor("lightcyan"));
|
declareColour("colour-highlight", "Colour of highlighted occurrences", QColor("lightcyan"));
|
||||||
declareSeparator();
|
|
||||||
declareColour("colour-int", "Highlight Colour: Integer Literals", QColor("darkmagenta"));
|
declareColour("colour-int", "Highlight Colour: Integer Literals", QColor("darkmagenta"));
|
||||||
declareColour("colour-float", "Highlight Colour: Float Literals", QColor("magenta"));
|
declareColour("colour-float", "Highlight Colour: Float Literals", QColor("magenta"));
|
||||||
declareColour("colour-name", "Highlight Colour: Names", QColor("grey"));
|
declareColour("colour-name", "Highlight Colour: Names", QColor("grey"));
|
||||||
|
@ -171,51 +136,55 @@ void CSMPrefs::State::declare()
|
||||||
declareColour("colour-id", "Highlight Colour: IDs", QColor("blue"));
|
declareColour("colour-id", "Highlight Colour: IDs", QColor("blue"));
|
||||||
|
|
||||||
declareCategory("General Input");
|
declareCategory("General Input");
|
||||||
declareBool("cycle", "Cyclic next/previous", false)
|
declareBool(mValues->mGeneralInput.mCycle, "Cyclic next/previous")
|
||||||
.setTooltip(
|
.setTooltip(
|
||||||
"When using next/previous functions at the last/first item of a "
|
"When using next/previous functions at the last/first item of a "
|
||||||
"list go to the first/last item");
|
"list go to the first/last item");
|
||||||
|
|
||||||
declareCategory("3D Scene Input");
|
declareCategory("3D Scene Input");
|
||||||
|
|
||||||
declareDouble("navi-wheel-factor", "Camera Zoom Sensitivity", 8).setRange(-100.0, 100.0);
|
declareDouble(mValues->mSceneInput.mNaviWheelFactor, "Camera Zoom Sensitivity").setRange(-100.0, 100.0);
|
||||||
declareDouble("s-navi-sensitivity", "Secondary Camera Movement Sensitivity", 50.0).setRange(-1000.0, 1000.0);
|
declareDouble(mValues->mSceneInput.mSNaviSensitivity, "Secondary Camera Movement Sensitivity")
|
||||||
declareSeparator();
|
.setRange(-1000.0, 1000.0);
|
||||||
|
|
||||||
declareDouble("p-navi-free-sensitivity", "Free Camera Sensitivity", 1 / 650.).setPrecision(5).setRange(0.0, 1.0);
|
declareDouble(mValues->mSceneInput.mPNaviFreeSensitivity, "Free Camera Sensitivity")
|
||||||
declareBool("p-navi-free-invert", "Invert Free Camera Mouse Input", false);
|
.setPrecision(5)
|
||||||
declareDouble("navi-free-lin-speed", "Free Camera Linear Speed", 1000.0).setRange(1.0, 10000.0);
|
.setRange(0.0, 1.0);
|
||||||
declareDouble("navi-free-rot-speed", "Free Camera Rotational Speed", 3.14 / 2).setRange(0.001, 6.28);
|
declareBool(mValues->mSceneInput.mPNaviFreeInvert, "Invert Free Camera Mouse Input");
|
||||||
declareDouble("navi-free-speed-mult", "Free Camera Speed Multiplier (from Modifier)", 8).setRange(0.001, 1000.0);
|
declareDouble(mValues->mSceneInput.mNaviFreeLinSpeed, "Free Camera Linear Speed").setRange(1.0, 10000.0);
|
||||||
declareSeparator();
|
declareDouble(mValues->mSceneInput.mNaviFreeRotSpeed, "Free Camera Rotational Speed").setRange(0.001, 6.28);
|
||||||
|
declareDouble(mValues->mSceneInput.mNaviFreeSpeedMult, "Free Camera Speed Multiplier (from Modifier)")
|
||||||
declareDouble("p-navi-orbit-sensitivity", "Orbit Camera Sensitivity", 1 / 650.).setPrecision(5).setRange(0.0, 1.0);
|
|
||||||
declareBool("p-navi-orbit-invert", "Invert Orbit Camera Mouse Input", false);
|
|
||||||
declareDouble("navi-orbit-rot-speed", "Orbital Camera Rotational Speed", 3.14 / 4).setRange(0.001, 6.28);
|
|
||||||
declareDouble("navi-orbit-speed-mult", "Orbital Camera Speed Multiplier (from Modifier)", 4)
|
|
||||||
.setRange(0.001, 1000.0);
|
.setRange(0.001, 1000.0);
|
||||||
declareBool("navi-orbit-const-roll", "Keep camera roll constant for orbital camera", true);
|
|
||||||
declareSeparator();
|
|
||||||
|
|
||||||
declareBool("context-select", "Context Sensitive Selection", false);
|
declareDouble(mValues->mSceneInput.mPNaviOrbitSensitivity, "Orbit Camera Sensitivity")
|
||||||
declareDouble("drag-factor", "Mouse sensitivity during drag operations", 1.0).setRange(0.001, 100.0);
|
.setPrecision(5)
|
||||||
declareDouble("drag-wheel-factor", "Mouse wheel sensitivity during drag operations", 1.0).setRange(0.001, 100.0);
|
.setRange(0.0, 1.0);
|
||||||
declareDouble("drag-shift-factor", "Shift-acceleration factor during drag operations", 4.0)
|
declareBool(mValues->mSceneInput.mPNaviOrbitInvert, "Invert Orbit Camera Mouse Input");
|
||||||
|
declareDouble(mValues->mSceneInput.mNaviOrbitRotSpeed, "Orbital Camera Rotational Speed").setRange(0.001, 6.28);
|
||||||
|
declareDouble(mValues->mSceneInput.mNaviOrbitSpeedMult, "Orbital Camera Speed Multiplier (from Modifier)")
|
||||||
|
.setRange(0.001, 1000.0);
|
||||||
|
declareBool(mValues->mSceneInput.mNaviOrbitConstRoll, "Keep camera roll constant for orbital camera");
|
||||||
|
|
||||||
|
declareBool(mValues->mSceneInput.mContextSelect, "Context Sensitive Selection");
|
||||||
|
declareDouble(mValues->mSceneInput.mDragFactor, "Mouse sensitivity during drag operations").setRange(0.001, 100.0);
|
||||||
|
declareDouble(mValues->mSceneInput.mDragWheelFactor, "Mouse wheel sensitivity during drag operations")
|
||||||
|
.setRange(0.001, 100.0);
|
||||||
|
declareDouble(mValues->mSceneInput.mDragShiftFactor, "Shift-acceleration factor during drag operations")
|
||||||
.setTooltip("Acceleration factor during drag operations while holding down shift")
|
.setTooltip("Acceleration factor during drag operations while holding down shift")
|
||||||
.setRange(0.001, 100.0);
|
.setRange(0.001, 100.0);
|
||||||
declareDouble("rotate-factor", "Free rotation factor", 0.007).setPrecision(4).setRange(0.0001, 0.1);
|
declareDouble(mValues->mSceneInput.mRotateFactor, "Free rotation factor").setPrecision(4).setRange(0.0001, 0.1);
|
||||||
|
|
||||||
declareCategory("Rendering");
|
declareCategory("Rendering");
|
||||||
declareInt("framerate-limit", "FPS limit", 60)
|
declareInt(mValues->mRendering.mFramerateLimit, "FPS limit")
|
||||||
.setTooltip("Framerate limit in 3D preview windows. Zero value means \"unlimited\".")
|
.setTooltip("Framerate limit in 3D preview windows. Zero value means \"unlimited\".")
|
||||||
.setRange(0, 10000);
|
.setRange(0, 10000);
|
||||||
declareInt("camera-fov", "Camera FOV", 90).setRange(10, 170);
|
declareInt(mValues->mRendering.mCameraFov, "Camera FOV").setRange(10, 170);
|
||||||
declareBool("camera-ortho", "Orthographic projection for camera", false);
|
declareBool(mValues->mRendering.mCameraOrtho, "Orthographic projection for camera");
|
||||||
declareInt("camera-ortho-size", "Orthographic projection size parameter", 100)
|
declareInt(mValues->mRendering.mCameraOrthoSize, "Orthographic projection size parameter")
|
||||||
.setTooltip("Size of the orthographic frustum, greater value will allow the camera to see more of the world.")
|
.setTooltip("Size of the orthographic frustum, greater value will allow the camera to see more of the world.")
|
||||||
.setRange(10, 10000);
|
.setRange(10, 10000);
|
||||||
declareDouble("object-marker-alpha", "Object Marker Transparency", 0.5).setPrecision(2).setRange(0, 1);
|
declareDouble(mValues->mRendering.mObjectMarkerAlpha, "Object Marker Transparency").setPrecision(2).setRange(0, 1);
|
||||||
declareBool("scene-use-gradient", "Use Gradient Background", true);
|
declareBool(mValues->mRendering.mSceneUseGradient, "Use Gradient Background");
|
||||||
declareColour("scene-day-background-colour", "Day Background Colour", QColor(110, 120, 128, 255));
|
declareColour("scene-day-background-colour", "Day Background Colour", QColor(110, 120, 128, 255));
|
||||||
declareColour("scene-day-gradient-colour", "Day Gradient Colour", QColor(47, 51, 51, 255))
|
declareColour("scene-day-gradient-colour", "Day Gradient Colour", QColor(47, 51, 51, 255))
|
||||||
.setTooltip(
|
.setTooltip(
|
||||||
|
@ -231,82 +200,52 @@ void CSMPrefs::State::declare()
|
||||||
.setTooltip(
|
.setTooltip(
|
||||||
"Sets the gradient color to use in conjunction with the night background color. Ignored if "
|
"Sets the gradient color to use in conjunction with the night background color. Ignored if "
|
||||||
"the gradient option is disabled.");
|
"the gradient option is disabled.");
|
||||||
declareBool("scene-day-night-switch-nodes", "Use Day/Night Switch Nodes", true);
|
declareBool(mValues->mRendering.mSceneDayNightSwitchNodes, "Use Day/Night Switch Nodes");
|
||||||
|
|
||||||
declareCategory("Tooltips");
|
declareCategory("Tooltips");
|
||||||
declareBool("scene", "Show Tooltips in 3D scenes", true);
|
declareBool(mValues->mTooltips.mScene, "Show Tooltips in 3D scenes");
|
||||||
declareBool("scene-hide-basic", "Hide basic 3D scenes tooltips", false);
|
declareBool(mValues->mTooltips.mSceneHideBasic, "Hide basic 3D scenes tooltips");
|
||||||
declareInt("scene-delay", "Tooltip delay in milliseconds", 500).setMin(1);
|
declareInt(mValues->mTooltips.mSceneDelay, "Tooltip delay in milliseconds").setMin(1);
|
||||||
|
|
||||||
EnumValue createAndInsert("Create cell and insert");
|
|
||||||
EnumValue showAndInsert("Show cell and insert");
|
|
||||||
EnumValue dontInsert("Discard");
|
|
||||||
EnumValue insertAnyway("Insert anyway");
|
|
||||||
EnumValues insertOutsideCell;
|
|
||||||
insertOutsideCell.add(createAndInsert).add(dontInsert).add(insertAnyway);
|
|
||||||
EnumValues insertOutsideVisibleCell;
|
|
||||||
insertOutsideVisibleCell.add(showAndInsert).add(dontInsert).add(insertAnyway);
|
|
||||||
|
|
||||||
EnumValue createAndLandEdit("Create cell and land, then edit");
|
|
||||||
EnumValue showAndLandEdit("Show cell and edit");
|
|
||||||
EnumValue dontLandEdit("Discard");
|
|
||||||
EnumValues landeditOutsideCell;
|
|
||||||
landeditOutsideCell.add(createAndLandEdit).add(dontLandEdit);
|
|
||||||
EnumValues landeditOutsideVisibleCell;
|
|
||||||
landeditOutsideVisibleCell.add(showAndLandEdit).add(dontLandEdit);
|
|
||||||
|
|
||||||
EnumValue SelectOnly("Select only");
|
|
||||||
EnumValue SelectAdd("Add to selection");
|
|
||||||
EnumValue SelectRemove("Remove from selection");
|
|
||||||
EnumValue selectInvert("Invert selection");
|
|
||||||
EnumValues primarySelectAction;
|
|
||||||
primarySelectAction.add(SelectOnly).add(SelectAdd).add(SelectRemove).add(selectInvert);
|
|
||||||
EnumValues secondarySelectAction;
|
|
||||||
secondarySelectAction.add(SelectOnly).add(SelectAdd).add(SelectRemove).add(selectInvert);
|
|
||||||
|
|
||||||
declareCategory("3D Scene Editing");
|
declareCategory("3D Scene Editing");
|
||||||
declareDouble("gridsnap-movement", "Grid snap size", 16);
|
declareDouble(mValues->mSceneEditing.mGridsnapMovement, "Grid snap size");
|
||||||
declareDouble("gridsnap-rotation", "Angle snap size", 15);
|
declareDouble(mValues->mSceneEditing.mGridsnapRotation, "Angle snap size");
|
||||||
declareDouble("gridsnap-scale", "Scale snap size", 0.25);
|
declareDouble(mValues->mSceneEditing.mGridsnapScale, "Scale snap size");
|
||||||
declareInt("distance", "Drop Distance", 50)
|
declareInt(mValues->mSceneEditing.mDistance, "Drop Distance")
|
||||||
.setTooltip(
|
.setTooltip(
|
||||||
"If an instance drop can not be placed against another object at the "
|
"If an instance drop can not be placed against another object at the "
|
||||||
"insert point, it will be placed by this distance from the insert point instead");
|
"insert point, it will be placed by this distance from the insert point instead");
|
||||||
declareEnum("outside-drop", "Handling drops outside of cells", createAndInsert).addValues(insertOutsideCell);
|
declareEnum(mValues->mSceneEditing.mOutsideDrop, "Handling drops outside of cells");
|
||||||
declareEnum("outside-visible-drop", "Handling drops outside of visible cells", showAndInsert)
|
declareEnum(mValues->mSceneEditing.mOutsideVisibleDrop, "Handling drops outside of visible cells");
|
||||||
.addValues(insertOutsideVisibleCell);
|
declareEnum(mValues->mSceneEditing.mOutsideLandedit, "Handling terrain edit outside of cells")
|
||||||
declareEnum("outside-landedit", "Handling terrain edit outside of cells", createAndLandEdit)
|
.setTooltip("Behavior of terrain editing, if land editing brush reaches an area without cell record.");
|
||||||
.setTooltip("Behavior of terrain editing, if land editing brush reaches an area without cell record.")
|
declareEnum(mValues->mSceneEditing.mOutsideVisibleLandedit, "Handling terrain edit outside of visible cells")
|
||||||
.addValues(landeditOutsideCell);
|
.setTooltip(
|
||||||
declareEnum("outside-visible-landedit", "Handling terrain edit outside of visible cells", showAndLandEdit)
|
"Behavior of terrain editing, if land editing brush reaches an area that is not currently visible.");
|
||||||
.setTooltip("Behavior of terrain editing, if land editing brush reaches an area that is not currently visible.")
|
declareInt(mValues->mSceneEditing.mTexturebrushMaximumsize, "Maximum texture brush size").setMin(1);
|
||||||
.addValues(landeditOutsideVisibleCell);
|
declareInt(mValues->mSceneEditing.mShapebrushMaximumsize, "Maximum height edit brush size")
|
||||||
declareInt("texturebrush-maximumsize", "Maximum texture brush size", 50).setMin(1);
|
|
||||||
declareInt("shapebrush-maximumsize", "Maximum height edit brush size", 100)
|
|
||||||
.setTooltip("Setting for the slider range of brush size in terrain height editing.")
|
.setTooltip("Setting for the slider range of brush size in terrain height editing.")
|
||||||
.setMin(1);
|
.setMin(1);
|
||||||
declareBool("landedit-post-smoothpainting", "Smooth land after painting height", false)
|
declareBool(mValues->mSceneEditing.mLandeditPostSmoothpainting, "Smooth land after painting height")
|
||||||
.setTooltip("Raise and lower tools will leave bumpy finish without this option");
|
.setTooltip("Raise and lower tools will leave bumpy finish without this option");
|
||||||
declareDouble("landedit-post-smoothstrength", "Smoothing strength (post-edit)", 0.25)
|
declareDouble(mValues->mSceneEditing.mLandeditPostSmoothstrength, "Smoothing strength (post-edit)")
|
||||||
.setTooltip(
|
.setTooltip(
|
||||||
"If smoothing land after painting height is used, this is the percentage of smooth applied afterwards. "
|
"If smoothing land after painting height is used, this is the percentage of smooth applied afterwards. "
|
||||||
"Negative values may be used to roughen instead of smooth.")
|
"Negative values may be used to roughen instead of smooth.")
|
||||||
.setMin(-1)
|
.setMin(-1)
|
||||||
.setMax(1);
|
.setMax(1);
|
||||||
declareBool("open-list-view", "Open displays list view", false)
|
declareBool(mValues->mSceneEditing.mOpenListView, "Open displays list view")
|
||||||
.setTooltip(
|
.setTooltip(
|
||||||
"When opening a reference from the scene view, it will open the"
|
"When opening a reference from the scene view, it will open the"
|
||||||
" instance list view instead of the individual instance record view.");
|
" instance list view instead of the individual instance record view.");
|
||||||
declareEnum("primary-select-action", "Action for primary select", SelectOnly)
|
declareEnum(mValues->mSceneEditing.mPrimarySelectAction, "Action for primary select")
|
||||||
.setTooltip(
|
.setTooltip(
|
||||||
"Selection can be chosen between select only, add to selection, remove from selection and invert "
|
"Selection can be chosen between select only, add to selection, remove from selection and invert "
|
||||||
"selection.")
|
"selection.");
|
||||||
.addValues(primarySelectAction);
|
declareEnum(mValues->mSceneEditing.mSecondarySelectAction, "Action for secondary select")
|
||||||
declareEnum("secondary-select-action", "Action for secondary select", SelectAdd)
|
|
||||||
.setTooltip(
|
.setTooltip(
|
||||||
"Selection can be chosen between select only, add to selection, remove from selection and invert "
|
"Selection can be chosen between select only, add to selection, remove from selection and invert "
|
||||||
"selection.")
|
"selection.");
|
||||||
.addValues(secondarySelectAction);
|
|
||||||
|
|
||||||
declareCategory("Key Bindings");
|
declareCategory("Key Bindings");
|
||||||
|
|
||||||
|
@ -401,7 +340,7 @@ void CSMPrefs::State::declare()
|
||||||
"scene-select-secondary", "Secondary Select", QKeySequence(Qt::ControlModifier | (int)Qt::MiddleButton));
|
"scene-select-secondary", "Secondary Select", QKeySequence(Qt::ControlModifier | (int)Qt::MiddleButton));
|
||||||
declareShortcut(
|
declareShortcut(
|
||||||
"scene-select-tertiary", "Tertiary Select", QKeySequence(Qt::ShiftModifier | (int)Qt::MiddleButton));
|
"scene-select-tertiary", "Tertiary Select", QKeySequence(Qt::ShiftModifier | (int)Qt::MiddleButton));
|
||||||
declareModifier("scene-speed-modifier", "Speed Modifier", Qt::Key_Shift);
|
declareModifier(mValues->mKeyBindings.mSceneSpeedModifier, "Speed Modifier");
|
||||||
declareShortcut("scene-delete", "Delete Instance", QKeySequence(Qt::Key_Delete));
|
declareShortcut("scene-delete", "Delete Instance", QKeySequence(Qt::Key_Delete));
|
||||||
declareShortcut("scene-instance-drop-terrain", "Drop to terrain level", QKeySequence(Qt::Key_G));
|
declareShortcut("scene-instance-drop-terrain", "Drop to terrain level", QKeySequence(Qt::Key_G));
|
||||||
declareShortcut("scene-instance-drop-collision", "Drop to collision", QKeySequence(Qt::Key_H));
|
declareShortcut("scene-instance-drop-collision", "Drop to collision", QKeySequence(Qt::Key_H));
|
||||||
|
@ -415,6 +354,30 @@ void CSMPrefs::State::declare()
|
||||||
declareShortcut("scene-edit-abort", "Abort", QKeySequence(Qt::Key_Escape));
|
declareShortcut("scene-edit-abort", "Abort", QKeySequence(Qt::Key_Escape));
|
||||||
declareShortcut("scene-focus-toolbar", "Toggle Toolbar Focus", QKeySequence(Qt::Key_T));
|
declareShortcut("scene-focus-toolbar", "Toggle Toolbar Focus", QKeySequence(Qt::Key_T));
|
||||||
declareShortcut("scene-render-stats", "Debug Rendering Stats", QKeySequence(Qt::Key_F3));
|
declareShortcut("scene-render-stats", "Debug Rendering Stats", QKeySequence(Qt::Key_F3));
|
||||||
|
declareShortcut("scene-duplicate", "Duplicate Instance", QKeySequence(Qt::ShiftModifier | Qt::Key_C));
|
||||||
|
declareShortcut("scene-clear-selection", "Clear Selection", QKeySequence(Qt::Key_Space));
|
||||||
|
declareShortcut("scene-unhide-all", "Unhide All Objects", QKeySequence(Qt::AltModifier | Qt::Key_H));
|
||||||
|
declareShortcut("scene-toggle-visibility", "Toggle Selection Visibility", QKeySequence(Qt::Key_H));
|
||||||
|
declareShortcut("scene-group-1", "Select Group 1", QKeySequence(Qt::Key_1));
|
||||||
|
declareShortcut("scene-save-1", "Save Group 1", QKeySequence(Qt::ControlModifier | Qt::Key_1));
|
||||||
|
declareShortcut("scene-group-2", "Select Group 2", QKeySequence(Qt::Key_2));
|
||||||
|
declareShortcut("scene-save-2", "Save Group 2", QKeySequence(Qt::ControlModifier | Qt::Key_2));
|
||||||
|
declareShortcut("scene-group-3", "Select Group 3", QKeySequence(Qt::Key_3));
|
||||||
|
declareShortcut("scene-save-3", "Save Group 3", QKeySequence(Qt::ControlModifier | Qt::Key_3));
|
||||||
|
declareShortcut("scene-group-4", "Select Group 4", QKeySequence(Qt::Key_4));
|
||||||
|
declareShortcut("scene-save-4", "Save Group 4", QKeySequence(Qt::ControlModifier | Qt::Key_4));
|
||||||
|
declareShortcut("scene-group-5", "Selection Group 5", QKeySequence(Qt::Key_5));
|
||||||
|
declareShortcut("scene-save-5", "Save Group 5", QKeySequence(Qt::ControlModifier | Qt::Key_5));
|
||||||
|
declareShortcut("scene-group-6", "Selection Group 6", QKeySequence(Qt::Key_6));
|
||||||
|
declareShortcut("scene-save-6", "Save Group 6", QKeySequence(Qt::ControlModifier | Qt::Key_6));
|
||||||
|
declareShortcut("scene-group-7", "Selection Group 7", QKeySequence(Qt::Key_7));
|
||||||
|
declareShortcut("scene-save-7", "Save Group 7", QKeySequence(Qt::ControlModifier | Qt::Key_7));
|
||||||
|
declareShortcut("scene-group-8", "Selection Group 8", QKeySequence(Qt::Key_8));
|
||||||
|
declareShortcut("scene-save-8", "Save Group 8", QKeySequence(Qt::ControlModifier | Qt::Key_8));
|
||||||
|
declareShortcut("scene-group-9", "Selection Group 9", QKeySequence(Qt::Key_9));
|
||||||
|
declareShortcut("scene-save-9", "Save Group 9", QKeySequence(Qt::ControlModifier | Qt::Key_9));
|
||||||
|
declareShortcut("scene-group-0", "Selection Group 10", QKeySequence(Qt::Key_0));
|
||||||
|
declareShortcut("scene-save-0", "Save Group 10", QKeySequence(Qt::ControlModifier | Qt::Key_0));
|
||||||
|
|
||||||
declareSubcategory("1st/Free Camera");
|
declareSubcategory("1st/Free Camera");
|
||||||
declareShortcut("free-forward", "Forward", QKeySequence(Qt::Key_W));
|
declareShortcut("free-forward", "Forward", QKeySequence(Qt::Key_W));
|
||||||
|
@ -440,13 +403,12 @@ void CSMPrefs::State::declare()
|
||||||
declareShortcut("script-editor-uncomment", "Uncomment Selection", QKeySequence());
|
declareShortcut("script-editor-uncomment", "Uncomment Selection", QKeySequence());
|
||||||
|
|
||||||
declareCategory("Models");
|
declareCategory("Models");
|
||||||
declareString("baseanim", "base animations", "meshes/base_anim.nif")
|
declareString(mValues->mModels.mBaseanim, "base animations").setTooltip("3rd person base model with textkeys-data");
|
||||||
.setTooltip("3rd person base model with textkeys-data");
|
declareString(mValues->mModels.mBaseanimkna, "base animations, kna")
|
||||||
declareString("baseanimkna", "base animations, kna", "meshes/base_animkna.nif")
|
|
||||||
.setTooltip("3rd person beast race base model with textkeys-data");
|
.setTooltip("3rd person beast race base model with textkeys-data");
|
||||||
declareString("baseanimfemale", "base animations, female", "meshes/base_anim_female.nif")
|
declareString(mValues->mModels.mBaseanimfemale, "base animations, female")
|
||||||
.setTooltip("3rd person female base model with textkeys-data");
|
.setTooltip("3rd person female base model with textkeys-data");
|
||||||
declareString("wolfskin", "base animations, wolf", "meshes/wolf/skin.nif").setTooltip("3rd person werewolf skin");
|
declareString(mValues->mModels.mWolfskin, "base animations, wolf").setTooltip("3rd person werewolf skin");
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMPrefs::State::declareCategory(const std::string& key)
|
void CSMPrefs::State::declareCategory(const std::string& key)
|
||||||
|
@ -463,90 +425,65 @@ void CSMPrefs::State::declareCategory(const std::string& key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMPrefs::IntSetting& CSMPrefs::State::declareInt(const std::string& key, const std::string& label, int default_)
|
CSMPrefs::IntSetting& CSMPrefs::State::declareInt(Settings::SettingValue<int>& value, const QString& label)
|
||||||
{
|
{
|
||||||
if (mCurrentCategory == mCategories.end())
|
if (mCurrentCategory == mCategories.end())
|
||||||
throw std::logic_error("no category for setting");
|
throw std::logic_error("no category for setting");
|
||||||
|
|
||||||
setDefault(key, std::to_string(default_));
|
CSMPrefs::IntSetting* setting
|
||||||
|
= new CSMPrefs::IntSetting(&mCurrentCategory->second, &mMutex, value.mName, label, *mIndex);
|
||||||
default_ = Settings::Manager::getInt(key, mCurrentCategory->second.getKey());
|
|
||||||
|
|
||||||
CSMPrefs::IntSetting* setting = new CSMPrefs::IntSetting(&mCurrentCategory->second, &mMutex, key, label, default_);
|
|
||||||
|
|
||||||
mCurrentCategory->second.addSetting(setting);
|
mCurrentCategory->second.addSetting(setting);
|
||||||
|
|
||||||
return *setting;
|
return *setting;
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMPrefs::DoubleSetting& CSMPrefs::State::declareDouble(
|
CSMPrefs::DoubleSetting& CSMPrefs::State::declareDouble(Settings::SettingValue<double>& value, const QString& label)
|
||||||
const std::string& key, const std::string& label, double default_)
|
|
||||||
{
|
{
|
||||||
if (mCurrentCategory == mCategories.end())
|
if (mCurrentCategory == mCategories.end())
|
||||||
throw std::logic_error("no category for setting");
|
throw std::logic_error("no category for setting");
|
||||||
|
|
||||||
std::ostringstream stream;
|
|
||||||
stream << default_;
|
|
||||||
setDefault(key, stream.str());
|
|
||||||
|
|
||||||
default_ = Settings::Manager::getFloat(key, mCurrentCategory->second.getKey());
|
|
||||||
|
|
||||||
CSMPrefs::DoubleSetting* setting
|
CSMPrefs::DoubleSetting* setting
|
||||||
= new CSMPrefs::DoubleSetting(&mCurrentCategory->second, &mMutex, key, label, default_);
|
= new CSMPrefs::DoubleSetting(&mCurrentCategory->second, &mMutex, value.mName, label, *mIndex);
|
||||||
|
|
||||||
mCurrentCategory->second.addSetting(setting);
|
mCurrentCategory->second.addSetting(setting);
|
||||||
|
|
||||||
return *setting;
|
return *setting;
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMPrefs::BoolSetting& CSMPrefs::State::declareBool(const std::string& key, const std::string& label, bool default_)
|
CSMPrefs::BoolSetting& CSMPrefs::State::declareBool(Settings::SettingValue<bool>& value, const QString& label)
|
||||||
{
|
{
|
||||||
if (mCurrentCategory == mCategories.end())
|
if (mCurrentCategory == mCategories.end())
|
||||||
throw std::logic_error("no category for setting");
|
throw std::logic_error("no category for setting");
|
||||||
|
|
||||||
setDefault(key, default_ ? "true" : "false");
|
|
||||||
|
|
||||||
default_ = Settings::Manager::getBool(key, mCurrentCategory->second.getKey());
|
|
||||||
|
|
||||||
CSMPrefs::BoolSetting* setting
|
CSMPrefs::BoolSetting* setting
|
||||||
= new CSMPrefs::BoolSetting(&mCurrentCategory->second, &mMutex, key, label, default_);
|
= new CSMPrefs::BoolSetting(&mCurrentCategory->second, &mMutex, value.mName, label, *mIndex);
|
||||||
|
|
||||||
mCurrentCategory->second.addSetting(setting);
|
mCurrentCategory->second.addSetting(setting);
|
||||||
|
|
||||||
return *setting;
|
return *setting;
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMPrefs::EnumSetting& CSMPrefs::State::declareEnum(
|
CSMPrefs::EnumSetting& CSMPrefs::State::declareEnum(EnumSettingValue& value, const QString& label)
|
||||||
const std::string& key, const std::string& label, EnumValue default_)
|
|
||||||
{
|
{
|
||||||
if (mCurrentCategory == mCategories.end())
|
if (mCurrentCategory == mCategories.end())
|
||||||
throw std::logic_error("no category for setting");
|
throw std::logic_error("no category for setting");
|
||||||
|
|
||||||
setDefault(key, default_.mValue);
|
CSMPrefs::EnumSetting* setting = new CSMPrefs::EnumSetting(
|
||||||
|
&mCurrentCategory->second, &mMutex, value.getValue().mName, label, value.getEnumValues(), *mIndex);
|
||||||
default_.mValue = Settings::Manager::getString(key, mCurrentCategory->second.getKey());
|
|
||||||
|
|
||||||
CSMPrefs::EnumSetting* setting
|
|
||||||
= new CSMPrefs::EnumSetting(&mCurrentCategory->second, &mMutex, key, label, default_);
|
|
||||||
|
|
||||||
mCurrentCategory->second.addSetting(setting);
|
mCurrentCategory->second.addSetting(setting);
|
||||||
|
|
||||||
return *setting;
|
return *setting;
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMPrefs::ColourSetting& CSMPrefs::State::declareColour(
|
CSMPrefs::ColourSetting& CSMPrefs::State::declareColour(const std::string& key, const QString& label, QColor default_)
|
||||||
const std::string& key, const std::string& label, QColor default_)
|
|
||||||
{
|
{
|
||||||
if (mCurrentCategory == mCategories.end())
|
if (mCurrentCategory == mCategories.end())
|
||||||
throw std::logic_error("no category for setting");
|
throw std::logic_error("no category for setting");
|
||||||
|
|
||||||
setDefault(key, default_.name().toUtf8().data());
|
|
||||||
|
|
||||||
default_.setNamedColor(
|
|
||||||
QString::fromUtf8(Settings::Manager::getString(key, mCurrentCategory->second.getKey()).c_str()));
|
|
||||||
|
|
||||||
CSMPrefs::ColourSetting* setting
|
CSMPrefs::ColourSetting* setting
|
||||||
= new CSMPrefs::ColourSetting(&mCurrentCategory->second, &mMutex, key, label, default_);
|
= new CSMPrefs::ColourSetting(&mCurrentCategory->second, &mMutex, key, label, *mIndex);
|
||||||
|
|
||||||
mCurrentCategory->second.addSetting(setting);
|
mCurrentCategory->second.addSetting(setting);
|
||||||
|
|
||||||
|
@ -554,39 +491,32 @@ CSMPrefs::ColourSetting& CSMPrefs::State::declareColour(
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMPrefs::ShortcutSetting& CSMPrefs::State::declareShortcut(
|
CSMPrefs::ShortcutSetting& CSMPrefs::State::declareShortcut(
|
||||||
const std::string& key, const std::string& label, const QKeySequence& default_)
|
const std::string& key, const QString& label, const QKeySequence& default_)
|
||||||
{
|
{
|
||||||
if (mCurrentCategory == mCategories.end())
|
if (mCurrentCategory == mCategories.end())
|
||||||
throw std::logic_error("no category for setting");
|
throw std::logic_error("no category for setting");
|
||||||
|
|
||||||
std::string seqStr = getShortcutManager().convertToString(default_);
|
|
||||||
setDefault(key, seqStr);
|
|
||||||
|
|
||||||
// Setup with actual data
|
// Setup with actual data
|
||||||
QKeySequence sequence;
|
QKeySequence sequence;
|
||||||
|
|
||||||
getShortcutManager().convertFromString(
|
getShortcutManager().convertFromString(mIndex->get<std::string>(mCurrentCategory->second.getKey(), key), sequence);
|
||||||
Settings::Manager::getString(key, mCurrentCategory->second.getKey()), sequence);
|
|
||||||
getShortcutManager().setSequence(key, sequence);
|
getShortcutManager().setSequence(key, sequence);
|
||||||
|
|
||||||
CSMPrefs::ShortcutSetting* setting = new CSMPrefs::ShortcutSetting(&mCurrentCategory->second, &mMutex, key, label);
|
CSMPrefs::ShortcutSetting* setting
|
||||||
|
= new CSMPrefs::ShortcutSetting(&mCurrentCategory->second, &mMutex, key, label, *mIndex);
|
||||||
mCurrentCategory->second.addSetting(setting);
|
mCurrentCategory->second.addSetting(setting);
|
||||||
|
|
||||||
return *setting;
|
return *setting;
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMPrefs::StringSetting& CSMPrefs::State::declareString(
|
CSMPrefs::StringSetting& CSMPrefs::State::declareString(
|
||||||
const std::string& key, const std::string& label, std::string default_)
|
Settings::SettingValue<std::string>& value, const QString& label)
|
||||||
{
|
{
|
||||||
if (mCurrentCategory == mCategories.end())
|
if (mCurrentCategory == mCategories.end())
|
||||||
throw std::logic_error("no category for setting");
|
throw std::logic_error("no category for setting");
|
||||||
|
|
||||||
setDefault(key, default_);
|
|
||||||
|
|
||||||
default_ = Settings::Manager::getString(key, mCurrentCategory->second.getKey());
|
|
||||||
|
|
||||||
CSMPrefs::StringSetting* setting
|
CSMPrefs::StringSetting* setting
|
||||||
= new CSMPrefs::StringSetting(&mCurrentCategory->second, &mMutex, key, label, default_);
|
= new CSMPrefs::StringSetting(&mCurrentCategory->second, &mMutex, value.mName, label, *mIndex);
|
||||||
|
|
||||||
mCurrentCategory->second.addSetting(setting);
|
mCurrentCategory->second.addSetting(setting);
|
||||||
|
|
||||||
|
@ -594,55 +524,31 @@ CSMPrefs::StringSetting& CSMPrefs::State::declareString(
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMPrefs::ModifierSetting& CSMPrefs::State::declareModifier(
|
CSMPrefs::ModifierSetting& CSMPrefs::State::declareModifier(
|
||||||
const std::string& key, const std::string& label, int default_)
|
Settings::SettingValue<std::string>& value, const QString& label)
|
||||||
{
|
{
|
||||||
if (mCurrentCategory == mCategories.end())
|
if (mCurrentCategory == mCategories.end())
|
||||||
throw std::logic_error("no category for setting");
|
throw std::logic_error("no category for setting");
|
||||||
|
|
||||||
std::string modStr = getShortcutManager().convertToString(default_);
|
|
||||||
setDefault(key, modStr);
|
|
||||||
|
|
||||||
// Setup with actual data
|
// Setup with actual data
|
||||||
int modifier;
|
int modifier;
|
||||||
|
|
||||||
getShortcutManager().convertFromString(
|
getShortcutManager().convertFromString(value.get(), modifier);
|
||||||
Settings::Manager::getString(key, mCurrentCategory->second.getKey()), modifier);
|
getShortcutManager().setModifier(value.mName, modifier);
|
||||||
getShortcutManager().setModifier(key, modifier);
|
|
||||||
|
|
||||||
CSMPrefs::ModifierSetting* setting = new CSMPrefs::ModifierSetting(&mCurrentCategory->second, &mMutex, key, label);
|
CSMPrefs::ModifierSetting* setting
|
||||||
|
= new CSMPrefs::ModifierSetting(&mCurrentCategory->second, &mMutex, value.mName, label, *mIndex);
|
||||||
mCurrentCategory->second.addSetting(setting);
|
mCurrentCategory->second.addSetting(setting);
|
||||||
|
|
||||||
return *setting;
|
return *setting;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMPrefs::State::declareSeparator()
|
void CSMPrefs::State::declareSubcategory(const QString& label)
|
||||||
{
|
{
|
||||||
if (mCurrentCategory == mCategories.end())
|
if (mCurrentCategory == mCategories.end())
|
||||||
throw std::logic_error("no category for setting");
|
throw std::logic_error("no category for setting");
|
||||||
|
|
||||||
CSMPrefs::Setting* setting = new CSMPrefs::Setting(&mCurrentCategory->second, &mMutex, "", "");
|
mCurrentCategory->second.addSubcategory(
|
||||||
|
new CSMPrefs::Subcategory(&mCurrentCategory->second, &mMutex, label, *mIndex));
|
||||||
mCurrentCategory->second.addSetting(setting);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CSMPrefs::State::declareSubcategory(const std::string& label)
|
|
||||||
{
|
|
||||||
if (mCurrentCategory == mCategories.end())
|
|
||||||
throw std::logic_error("no category for setting");
|
|
||||||
|
|
||||||
CSMPrefs::Setting* setting = new CSMPrefs::Setting(&mCurrentCategory->second, &mMutex, "", label);
|
|
||||||
|
|
||||||
mCurrentCategory->second.addSetting(setting);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CSMPrefs::State::setDefault(const std::string& key, const std::string& default_)
|
|
||||||
{
|
|
||||||
Settings::CategorySetting fullKey(mCurrentCategory->second.getKey(), key);
|
|
||||||
|
|
||||||
Settings::CategorySettingValueMap::iterator iter = Settings::Manager::mDefaultSettings.find(fullKey);
|
|
||||||
|
|
||||||
if (iter == Settings::Manager::mDefaultSettings.end())
|
|
||||||
Settings::Manager::mDefaultSettings.insert(std::make_pair(fullKey, default_));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CSMPrefs::State::State(const Files::ConfigurationManager& configurationManager)
|
CSMPrefs::State::State(const Files::ConfigurationManager& configurationManager)
|
||||||
|
@ -650,6 +556,8 @@ CSMPrefs::State::State(const Files::ConfigurationManager& configurationManager)
|
||||||
, mDefaultConfigFile("defaults-cs.bin")
|
, mDefaultConfigFile("defaults-cs.bin")
|
||||||
, mConfigurationManager(configurationManager)
|
, mConfigurationManager(configurationManager)
|
||||||
, mCurrentCategory(mCategories.end())
|
, mCurrentCategory(mCategories.end())
|
||||||
|
, mIndex(std::make_unique<Settings::Index>())
|
||||||
|
, mValues(std::make_unique<Values>(*mIndex))
|
||||||
{
|
{
|
||||||
if (sThis)
|
if (sThis)
|
||||||
throw std::logic_error("An instance of CSMPRefs::State already exists");
|
throw std::logic_error("An instance of CSMPRefs::State already exists");
|
||||||
|
@ -709,27 +617,13 @@ CSMPrefs::State& CSMPrefs::State::get()
|
||||||
|
|
||||||
void CSMPrefs::State::resetCategory(const std::string& category)
|
void CSMPrefs::State::resetCategory(const std::string& category)
|
||||||
{
|
{
|
||||||
for (Settings::CategorySettingValueMap::iterator i = Settings::Manager::mUserSettings.begin();
|
|
||||||
i != Settings::Manager::mUserSettings.end(); ++i)
|
|
||||||
{
|
|
||||||
// if the category matches
|
|
||||||
if (i->first.first == category)
|
|
||||||
{
|
|
||||||
// mark the setting as changed
|
|
||||||
Settings::Manager::mChangedSettings.insert(std::make_pair(i->first.first, i->first.second));
|
|
||||||
// reset the value to the default
|
|
||||||
i->second = Settings::Manager::mDefaultSettings[i->first];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Collection::iterator container = mCategories.find(category);
|
Collection::iterator container = mCategories.find(category);
|
||||||
if (container != mCategories.end())
|
if (container != mCategories.end())
|
||||||
{
|
{
|
||||||
Category settings = container->second;
|
for (Setting* setting : container->second)
|
||||||
for (Category::Iterator i = settings.begin(); i != settings.end(); ++i)
|
|
||||||
{
|
{
|
||||||
(*i)->updateWidget();
|
setting->reset();
|
||||||
update(**i);
|
update(*setting);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,11 @@
|
||||||
|
|
||||||
class QColor;
|
class QColor;
|
||||||
|
|
||||||
|
namespace Settings
|
||||||
|
{
|
||||||
|
class Index;
|
||||||
|
}
|
||||||
|
|
||||||
namespace CSMPrefs
|
namespace CSMPrefs
|
||||||
{
|
{
|
||||||
class IntSetting;
|
class IntSetting;
|
||||||
|
@ -27,6 +32,8 @@ namespace CSMPrefs
|
||||||
class ModifierSetting;
|
class ModifierSetting;
|
||||||
class Setting;
|
class Setting;
|
||||||
class StringSetting;
|
class StringSetting;
|
||||||
|
class EnumSettingValue;
|
||||||
|
struct Values;
|
||||||
|
|
||||||
/// \brief User settings state
|
/// \brief User settings state
|
||||||
///
|
///
|
||||||
|
@ -50,43 +57,40 @@ namespace CSMPrefs
|
||||||
Collection mCategories;
|
Collection mCategories;
|
||||||
Iterator mCurrentCategory;
|
Iterator mCurrentCategory;
|
||||||
QMutex mMutex;
|
QMutex mMutex;
|
||||||
|
std::unique_ptr<Settings::Index> mIndex;
|
||||||
|
std::unique_ptr<Values> mValues;
|
||||||
|
|
||||||
// not implemented
|
|
||||||
State(const State&);
|
|
||||||
State& operator=(const State&);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void declare();
|
void declare();
|
||||||
|
|
||||||
void declareCategory(const std::string& key);
|
void declareCategory(const std::string& key);
|
||||||
|
|
||||||
IntSetting& declareInt(const std::string& key, const std::string& label, int default_);
|
IntSetting& declareInt(Settings::SettingValue<int>& value, const QString& label);
|
||||||
DoubleSetting& declareDouble(const std::string& key, const std::string& label, double default_);
|
|
||||||
|
|
||||||
BoolSetting& declareBool(const std::string& key, const std::string& label, bool default_);
|
DoubleSetting& declareDouble(Settings::SettingValue<double>& value, const QString& label);
|
||||||
|
|
||||||
EnumSetting& declareEnum(const std::string& key, const std::string& label, EnumValue default_);
|
BoolSetting& declareBool(Settings::SettingValue<bool>& value, const QString& label);
|
||||||
|
|
||||||
ColourSetting& declareColour(const std::string& key, const std::string& label, QColor default_);
|
EnumSetting& declareEnum(EnumSettingValue& value, const QString& label);
|
||||||
|
|
||||||
ShortcutSetting& declareShortcut(
|
ColourSetting& declareColour(const std::string& key, const QString& label, QColor default_);
|
||||||
const std::string& key, const std::string& label, const QKeySequence& default_);
|
|
||||||
|
|
||||||
StringSetting& declareString(const std::string& key, const std::string& label, std::string default_);
|
ShortcutSetting& declareShortcut(const std::string& key, const QString& label, const QKeySequence& default_);
|
||||||
|
|
||||||
ModifierSetting& declareModifier(const std::string& key, const std::string& label, int modifier_);
|
StringSetting& declareString(Settings::SettingValue<std::string>& value, const QString& label);
|
||||||
|
|
||||||
void declareSeparator();
|
ModifierSetting& declareModifier(Settings::SettingValue<std::string>& value, const QString& label);
|
||||||
|
|
||||||
void declareSubcategory(const std::string& label);
|
void declareSubcategory(const QString& label);
|
||||||
|
|
||||||
void setDefault(const std::string& key, const std::string& default_);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
State(const Files::ConfigurationManager& configurationManager);
|
State(const Files::ConfigurationManager& configurationManager);
|
||||||
|
|
||||||
|
State(const State&) = delete;
|
||||||
|
|
||||||
~State();
|
~State();
|
||||||
|
|
||||||
|
State& operator=(const State&) = delete;
|
||||||
|
|
||||||
void save();
|
void save();
|
||||||
|
|
||||||
Iterator begin();
|
Iterator begin();
|
||||||
|
|
|
@ -12,9 +12,8 @@
|
||||||
#include "state.hpp"
|
#include "state.hpp"
|
||||||
|
|
||||||
CSMPrefs::StringSetting::StringSetting(
|
CSMPrefs::StringSetting::StringSetting(
|
||||||
Category* parent, QMutex* mutex, const std::string& key, const std::string& label, std::string_view default_)
|
Category* parent, QMutex* mutex, std::string_view key, const QString& label, Settings::Index& index)
|
||||||
: Setting(parent, mutex, key, label)
|
: TypedSetting(parent, mutex, key, label, index)
|
||||||
, mDefault(default_)
|
|
||||||
, mWidget(nullptr)
|
, mWidget(nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -25,9 +24,9 @@ CSMPrefs::StringSetting& CSMPrefs::StringSetting::setTooltip(const std::string&
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<QWidget*, QWidget*> CSMPrefs::StringSetting::makeWidgets(QWidget* parent)
|
CSMPrefs::SettingWidgets CSMPrefs::StringSetting::makeWidgets(QWidget* parent)
|
||||||
{
|
{
|
||||||
mWidget = new QLineEdit(QString::fromUtf8(mDefault.c_str()), parent);
|
mWidget = new QLineEdit(QString::fromStdString(getValue()), parent);
|
||||||
|
|
||||||
if (!mTooltip.empty())
|
if (!mTooltip.empty())
|
||||||
{
|
{
|
||||||
|
@ -37,23 +36,17 @@ std::pair<QWidget*, QWidget*> CSMPrefs::StringSetting::makeWidgets(QWidget* pare
|
||||||
|
|
||||||
connect(mWidget, &QLineEdit::textChanged, this, &StringSetting::textChanged);
|
connect(mWidget, &QLineEdit::textChanged, this, &StringSetting::textChanged);
|
||||||
|
|
||||||
return std::make_pair(static_cast<QWidget*>(nullptr), mWidget);
|
return SettingWidgets{ .mLabel = nullptr, .mInput = mWidget };
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMPrefs::StringSetting::updateWidget()
|
void CSMPrefs::StringSetting::updateWidget()
|
||||||
{
|
{
|
||||||
if (mWidget)
|
if (mWidget)
|
||||||
{
|
mWidget->setText(QString::fromStdString(getValue()));
|
||||||
mWidget->setText(QString::fromStdString(Settings::Manager::getString(getKey(), getParent()->getKey())));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSMPrefs::StringSetting::textChanged(const QString& text)
|
void CSMPrefs::StringSetting::textChanged(const QString& text)
|
||||||
{
|
{
|
||||||
{
|
setValue(text.toStdString());
|
||||||
QMutexLocker lock(getMutex());
|
|
||||||
Settings::Manager::setString(getKey(), getParent()->getKey(), text.toStdString());
|
|
||||||
}
|
|
||||||
|
|
||||||
getParent()->getState()->update(*this);
|
getParent()->getState()->update(*this);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,22 +14,22 @@ class QWidget;
|
||||||
namespace CSMPrefs
|
namespace CSMPrefs
|
||||||
{
|
{
|
||||||
class Category;
|
class Category;
|
||||||
class StringSetting : public Setting
|
|
||||||
|
class StringSetting final : public TypedSetting<std::string>
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
std::string mTooltip;
|
std::string mTooltip;
|
||||||
std::string mDefault;
|
|
||||||
QLineEdit* mWidget;
|
QLineEdit* mWidget;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
StringSetting(Category* parent, QMutex* mutex, const std::string& key, const std::string& label,
|
explicit StringSetting(
|
||||||
std::string_view default_);
|
Category* parent, QMutex* mutex, std::string_view key, const QString& label, Settings::Index& index);
|
||||||
|
|
||||||
StringSetting& setTooltip(const std::string& tooltip);
|
StringSetting& setTooltip(const std::string& tooltip);
|
||||||
|
|
||||||
/// Return label, input widget.
|
/// Return label, input widget.
|
||||||
std::pair<QWidget*, QWidget*> makeWidgets(QWidget* parent) override;
|
SettingWidgets makeWidgets(QWidget* parent) override;
|
||||||
|
|
||||||
void updateWidget() override;
|
void updateWidget() override;
|
||||||
|
|
||||||
|
|
18
apps/opencs/model/prefs/subcategory.cpp
Normal file
18
apps/opencs/model/prefs/subcategory.cpp
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#include "subcategory.hpp"
|
||||||
|
|
||||||
|
#include <QGridLayout>
|
||||||
|
|
||||||
|
namespace CSMPrefs
|
||||||
|
{
|
||||||
|
class Category;
|
||||||
|
|
||||||
|
Subcategory::Subcategory(Category* parent, QMutex* mutex, const QString& label, Settings::Index& index)
|
||||||
|
: Setting(parent, mutex, "", label, index)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingWidgets Subcategory::makeWidgets(QWidget* /*parent*/)
|
||||||
|
{
|
||||||
|
return SettingWidgets{ .mLabel = nullptr, .mInput = nullptr };
|
||||||
|
}
|
||||||
|
}
|
28
apps/opencs/model/prefs/subcategory.hpp
Normal file
28
apps/opencs/model/prefs/subcategory.hpp
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
#ifndef OPENMW_APPS_OPENCS_MODEL_PREFS_SUBCATEGORY_H
|
||||||
|
#define OPENMW_APPS_OPENCS_MODEL_PREFS_SUBCATEGORY_H
|
||||||
|
|
||||||
|
#include "setting.hpp"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace CSMPrefs
|
||||||
|
{
|
||||||
|
class Category;
|
||||||
|
|
||||||
|
class Subcategory final : public Setting
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit Subcategory(Category* parent, QMutex* mutex, const QString& label, Settings::Index& index);
|
||||||
|
|
||||||
|
SettingWidgets makeWidgets(QWidget* parent) override;
|
||||||
|
|
||||||
|
void updateWidget() override {}
|
||||||
|
|
||||||
|
void reset() override {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
546
apps/opencs/model/prefs/values.hpp
Normal file
546
apps/opencs/model/prefs/values.hpp
Normal file
|
@ -0,0 +1,546 @@
|
||||||
|
#ifndef OPENMW_APPS_OPENCS_MODEL_PREFS_VALUES_H
|
||||||
|
#define OPENMW_APPS_OPENCS_MODEL_PREFS_VALUES_H
|
||||||
|
|
||||||
|
#include "enumvalueview.hpp"
|
||||||
|
|
||||||
|
#include <components/settings/sanitizer.hpp>
|
||||||
|
#include <components/settings/settingvalue.hpp>
|
||||||
|
|
||||||
|
#include <Qt>
|
||||||
|
#include <QtGlobal>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <memory>
|
||||||
|
#include <span>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
namespace CSMPrefs
|
||||||
|
{
|
||||||
|
class EnumSanitizer final : public Settings::Sanitizer<std::string>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit EnumSanitizer(std::span<const EnumValueView> values)
|
||||||
|
: mValues(values)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string apply(const std::string& value) const override
|
||||||
|
{
|
||||||
|
const auto hasValue = [&](const EnumValueView& v) { return v.mValue == value; };
|
||||||
|
if (std::find_if(mValues.begin(), mValues.end(), hasValue) == mValues.end())
|
||||||
|
{
|
||||||
|
std::ostringstream message;
|
||||||
|
message << "Invalid enum value: " << value;
|
||||||
|
throw std::runtime_error(message.str());
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::span<const EnumValueView> mValues;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline std::unique_ptr<Settings::Sanitizer<std::string>> makeEnumSanitizerString(
|
||||||
|
std::span<const EnumValueView> values)
|
||||||
|
{
|
||||||
|
return std::make_unique<EnumSanitizer>(values);
|
||||||
|
}
|
||||||
|
|
||||||
|
class EnumSettingValue
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit EnumSettingValue(Settings::Index& index, std::string_view category, std::string_view name,
|
||||||
|
std::span<const EnumValueView> values, std::size_t defaultValueIndex)
|
||||||
|
: mValue(
|
||||||
|
index, category, name, std::string(values[defaultValueIndex].mValue), makeEnumSanitizerString(values))
|
||||||
|
, mEnumValues(values)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Settings::SettingValue<std::string>& getValue() { return mValue; }
|
||||||
|
|
||||||
|
std::span<const EnumValueView> getEnumValues() const { return mEnumValues; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Settings::SettingValue<std::string> mValue;
|
||||||
|
std::span<const EnumValueView> mEnumValues;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WindowsCategory : Settings::WithIndex
|
||||||
|
{
|
||||||
|
using Settings::WithIndex::WithIndex;
|
||||||
|
|
||||||
|
static constexpr std::string_view sName = "Windows";
|
||||||
|
|
||||||
|
static constexpr std::array<EnumValueView, 3> sMainwindowScrollbarValues{
|
||||||
|
EnumValueView{
|
||||||
|
"Scrollbar Only", "Simple addition of scrollbars, the view window does not grow automatically." },
|
||||||
|
EnumValueView{ "Grow Only", "The view window grows as subviews are added. No scrollbars." },
|
||||||
|
EnumValueView{
|
||||||
|
"Grow then Scroll", "The view window grows. The scrollbar appears once it cannot grow any further." },
|
||||||
|
};
|
||||||
|
|
||||||
|
Settings::SettingValue<int> mDefaultWidth{ mIndex, sName, "default-width", 800 };
|
||||||
|
Settings::SettingValue<int> mDefaultHeight{ mIndex, sName, "default-height", 600 };
|
||||||
|
Settings::SettingValue<bool> mShowStatusbar{ mIndex, sName, "show-statusbar", true };
|
||||||
|
Settings::SettingValue<bool> mReuse{ mIndex, sName, "reuse", true };
|
||||||
|
Settings::SettingValue<int> mMaxSubviews{ mIndex, sName, "max-subviews", 256 };
|
||||||
|
Settings::SettingValue<bool> mHideSubview{ mIndex, sName, "hide-subview", false };
|
||||||
|
Settings::SettingValue<int> mMinimumWidth{ mIndex, sName, "minimum-width", 325 };
|
||||||
|
EnumSettingValue mMainwindowScrollbar{ mIndex, sName, "mainwindow-scrollbar", sMainwindowScrollbarValues, 0 };
|
||||||
|
Settings::SettingValue<bool> mGrowLimit{ mIndex, sName, "grow-limit", false };
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RecordsCategory : Settings::WithIndex
|
||||||
|
{
|
||||||
|
using Settings::WithIndex::WithIndex;
|
||||||
|
|
||||||
|
static constexpr std::string_view sName = "Records";
|
||||||
|
|
||||||
|
static constexpr std::array<EnumValueView, 3> sRecordValues{
|
||||||
|
EnumValueView{ "Icon and Text", "" },
|
||||||
|
EnumValueView{ "Icon Only", "" },
|
||||||
|
EnumValueView{ "Text Only", "" },
|
||||||
|
};
|
||||||
|
|
||||||
|
EnumSettingValue mStatusFormat{ mIndex, sName, "status-format", sRecordValues, 0 };
|
||||||
|
EnumSettingValue mTypeFormat{ mIndex, sName, "type-format", sRecordValues, 0 };
|
||||||
|
};
|
||||||
|
|
||||||
|
struct IdTablesCategory : Settings::WithIndex
|
||||||
|
{
|
||||||
|
using Settings::WithIndex::WithIndex;
|
||||||
|
|
||||||
|
static constexpr std::string_view sName = "ID Tables";
|
||||||
|
|
||||||
|
static constexpr std::array<EnumValueView, 7> sDoubleClickValues{
|
||||||
|
EnumValueView{ "Edit in Place", "Edit the clicked cell" },
|
||||||
|
EnumValueView{ "Edit Record", "Open a dialogue subview for the clicked record" },
|
||||||
|
EnumValueView{ "View", "Open a scene subview for the clicked record (not available everywhere)" },
|
||||||
|
EnumValueView{ "Revert", "" },
|
||||||
|
EnumValueView{ "Delete", "" },
|
||||||
|
EnumValueView{ "Edit Record and Close", "" },
|
||||||
|
EnumValueView{
|
||||||
|
"View and Close", "Open a scene subview for the clicked record and close the table subview" },
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr std::array<EnumValueView, 3> sJumpAndSelectValues{
|
||||||
|
EnumValueView{ "Jump and Select", "Scroll new record into view and make it the selection" },
|
||||||
|
EnumValueView{ "Jump Only", "Scroll new record into view" },
|
||||||
|
EnumValueView{ "No Jump", "No special action" },
|
||||||
|
};
|
||||||
|
|
||||||
|
EnumSettingValue mDouble{ mIndex, sName, "double", sDoubleClickValues, 0 };
|
||||||
|
EnumSettingValue mDoubleS{ mIndex, sName, "double-s", sDoubleClickValues, 1 };
|
||||||
|
EnumSettingValue mDoubleC{ mIndex, sName, "double-c", sDoubleClickValues, 2 };
|
||||||
|
EnumSettingValue mDoubleSc{ mIndex, sName, "double-sc", sDoubleClickValues, 5 };
|
||||||
|
EnumSettingValue mJumpToAdded{ mIndex, sName, "jump-to-added", sJumpAndSelectValues, 0 };
|
||||||
|
Settings::SettingValue<bool> mExtendedConfig{ mIndex, sName, "extended-config", false };
|
||||||
|
Settings::SettingValue<bool> mSubviewNewWindow{ mIndex, sName, "subview-new-window", false };
|
||||||
|
};
|
||||||
|
|
||||||
|
struct IdDialoguesCategory : Settings::WithIndex
|
||||||
|
{
|
||||||
|
using Settings::WithIndex::WithIndex;
|
||||||
|
|
||||||
|
static constexpr std::string_view sName = "ID Dialogues";
|
||||||
|
|
||||||
|
Settings::SettingValue<bool> mToolbar{ mIndex, sName, "toolbar", true };
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ReportsCategory : Settings::WithIndex
|
||||||
|
{
|
||||||
|
using Settings::WithIndex::WithIndex;
|
||||||
|
|
||||||
|
static constexpr std::string_view sName = "Reports";
|
||||||
|
|
||||||
|
static constexpr std::array<EnumValueView, 4> sReportValues{
|
||||||
|
EnumValueView{ "None", "" },
|
||||||
|
EnumValueView{ "Edit", "Open a table or dialogue suitable for addressing the listed report" },
|
||||||
|
EnumValueView{ "Remove", "Remove the report from the report table" },
|
||||||
|
EnumValueView{ "Edit And Remove",
|
||||||
|
"Open a table or dialogue suitable for addressing the listed report, then remove the report from the "
|
||||||
|
"report table" },
|
||||||
|
};
|
||||||
|
|
||||||
|
EnumSettingValue mDouble{ mIndex, sName, "double", sReportValues, 1 };
|
||||||
|
EnumSettingValue mDoubleS{ mIndex, sName, "double-s", sReportValues, 2 };
|
||||||
|
EnumSettingValue mDoubleC{ mIndex, sName, "double-c", sReportValues, 3 };
|
||||||
|
EnumSettingValue mDoubleSc{ mIndex, sName, "double-sc", sReportValues, 0 };
|
||||||
|
Settings::SettingValue<bool> mIgnoreBaseRecords{ mIndex, sName, "ignore-base-records", false };
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SearchAndReplaceCategory : Settings::WithIndex
|
||||||
|
{
|
||||||
|
using Settings::WithIndex::WithIndex;
|
||||||
|
|
||||||
|
static constexpr std::string_view sName = "Search & Replace";
|
||||||
|
|
||||||
|
Settings::SettingValue<int> mCharBefore{ mIndex, sName, "char-before", 10 };
|
||||||
|
Settings::SettingValue<int> mCharAfter{ mIndex, sName, "char-after", 10 };
|
||||||
|
Settings::SettingValue<bool> mAutoDelete{ mIndex, sName, "auto-delete", true };
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ScriptsCategory : Settings::WithIndex
|
||||||
|
{
|
||||||
|
using Settings::WithIndex::WithIndex;
|
||||||
|
|
||||||
|
static constexpr std::string_view sName = "Scripts";
|
||||||
|
|
||||||
|
static constexpr std::array<EnumValueView, 3> sWarningValues{
|
||||||
|
EnumValueView{ "Ignore", "Do not report warning" },
|
||||||
|
EnumValueView{ "Normal", "Report warnings as warning" },
|
||||||
|
EnumValueView{ "Strict", "Promote warning to an error" },
|
||||||
|
};
|
||||||
|
|
||||||
|
Settings::SettingValue<bool> mShowLinenum{ mIndex, sName, "show-linenum", true };
|
||||||
|
Settings::SettingValue<bool> mWrapLines{ mIndex, sName, "wrap-lines", false };
|
||||||
|
Settings::SettingValue<bool> mMonoFont{ mIndex, sName, "mono-font", true };
|
||||||
|
Settings::SettingValue<int> mTabWidth{ mIndex, sName, "tab-width", 4 };
|
||||||
|
EnumSettingValue mWarnings{ mIndex, sName, "warnings", sWarningValues, 1 };
|
||||||
|
Settings::SettingValue<bool> mToolbar{ mIndex, sName, "toolbar", true };
|
||||||
|
Settings::SettingValue<int> mCompileDelay{ mIndex, sName, "compile-delay", 100 };
|
||||||
|
Settings::SettingValue<int> mErrorHeight{ mIndex, sName, "error-height", 100 };
|
||||||
|
Settings::SettingValue<bool> mHighlightOccurrences{ mIndex, sName, "highlight-occurrences", true };
|
||||||
|
Settings::SettingValue<std::string> mColourHighlight{ mIndex, sName, "colour-highlight", "lightcyan" };
|
||||||
|
Settings::SettingValue<std::string> mColourInt{ mIndex, sName, "colour-int", "darkmagenta" };
|
||||||
|
Settings::SettingValue<std::string> mColourFloat{ mIndex, sName, "colour-float", "magenta" };
|
||||||
|
Settings::SettingValue<std::string> mColourName{ mIndex, sName, "colour-name", "grey" };
|
||||||
|
Settings::SettingValue<std::string> mColourKeyword{ mIndex, sName, "colour-keyword", "red" };
|
||||||
|
Settings::SettingValue<std::string> mColourSpecial{ mIndex, sName, "colour-special", "darkorange" };
|
||||||
|
Settings::SettingValue<std::string> mColourComment{ mIndex, sName, "colour-comment", "green" };
|
||||||
|
Settings::SettingValue<std::string> mColourId{ mIndex, sName, "colour-id", "blue" };
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GeneralInputCategory : Settings::WithIndex
|
||||||
|
{
|
||||||
|
using Settings::WithIndex::WithIndex;
|
||||||
|
|
||||||
|
static constexpr std::string_view sName = "General Input";
|
||||||
|
|
||||||
|
Settings::SettingValue<bool> mCycle{ mIndex, sName, "cycle", false };
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SceneInputCategory : Settings::WithIndex
|
||||||
|
{
|
||||||
|
using Settings::WithIndex::WithIndex;
|
||||||
|
|
||||||
|
static constexpr std::string_view sName = "3D Scene Input";
|
||||||
|
|
||||||
|
Settings::SettingValue<double> mNaviWheelFactor{ mIndex, sName, "navi-wheel-factor", 8 };
|
||||||
|
Settings::SettingValue<double> mSNaviSensitivity{ mIndex, sName, "s-navi-sensitivity", 50 };
|
||||||
|
Settings::SettingValue<double> mPNaviFreeSensitivity{ mIndex, sName, "p-navi-free-sensitivity", 1 / 650.0 };
|
||||||
|
Settings::SettingValue<bool> mPNaviFreeInvert{ mIndex, sName, "p-navi-free-invert", false };
|
||||||
|
Settings::SettingValue<double> mNaviFreeLinSpeed{ mIndex, sName, "navi-free-lin-speed", 1000 };
|
||||||
|
Settings::SettingValue<double> mNaviFreeRotSpeed{ mIndex, sName, "navi-free-rot-speed", 3.14 / 2 };
|
||||||
|
Settings::SettingValue<double> mNaviFreeSpeedMult{ mIndex, sName, "navi-free-speed-mult", 8 };
|
||||||
|
Settings::SettingValue<double> mPNaviOrbitSensitivity{ mIndex, sName, "p-navi-orbit-sensitivity", 1 / 650.0 };
|
||||||
|
Settings::SettingValue<bool> mPNaviOrbitInvert{ mIndex, sName, "p-navi-orbit-invert", false };
|
||||||
|
Settings::SettingValue<double> mNaviOrbitRotSpeed{ mIndex, sName, "navi-orbit-rot-speed", 3.14 / 4 };
|
||||||
|
Settings::SettingValue<double> mNaviOrbitSpeedMult{ mIndex, sName, "navi-orbit-speed-mult", 4 };
|
||||||
|
Settings::SettingValue<bool> mNaviOrbitConstRoll{ mIndex, sName, "navi-orbit-const-roll", true };
|
||||||
|
Settings::SettingValue<bool> mContextSelect{ mIndex, sName, "context-select", false };
|
||||||
|
Settings::SettingValue<double> mDragFactor{ mIndex, sName, "drag-factor", 1 };
|
||||||
|
Settings::SettingValue<double> mDragWheelFactor{ mIndex, sName, "drag-wheel-factor", 1 };
|
||||||
|
Settings::SettingValue<double> mDragShiftFactor{ mIndex, sName, "drag-shift-factor", 4 };
|
||||||
|
Settings::SettingValue<double> mRotateFactor{ mIndex, sName, "rotate-factor", 0.007 };
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RenderingCategory : Settings::WithIndex
|
||||||
|
{
|
||||||
|
using Settings::WithIndex::WithIndex;
|
||||||
|
|
||||||
|
static constexpr std::string_view sName = "Rendering";
|
||||||
|
|
||||||
|
Settings::SettingValue<int> mFramerateLimit{ mIndex, sName, "framerate-limit", 60 };
|
||||||
|
Settings::SettingValue<int> mCameraFov{ mIndex, sName, "camera-fov", 90 };
|
||||||
|
Settings::SettingValue<bool> mCameraOrtho{ mIndex, sName, "camera-ortho", false };
|
||||||
|
Settings::SettingValue<int> mCameraOrthoSize{ mIndex, sName, "camera-ortho-size", 100 };
|
||||||
|
Settings::SettingValue<double> mObjectMarkerAlpha{ mIndex, sName, "object-marker-alpha", 0.5 };
|
||||||
|
Settings::SettingValue<bool> mSceneUseGradient{ mIndex, sName, "scene-use-gradient", true };
|
||||||
|
Settings::SettingValue<std::string> mSceneDayBackgroundColour{ mIndex, sName, "scene-day-background-colour",
|
||||||
|
"#6e7880" };
|
||||||
|
Settings::SettingValue<std::string> mSceneDayGradientColour{ mIndex, sName, "scene-day-gradient-colour",
|
||||||
|
"#2f3333" };
|
||||||
|
Settings::SettingValue<std::string> mSceneBrightBackgroundColour{ mIndex, sName,
|
||||||
|
"scene-bright-background-colour", "#4f575c" };
|
||||||
|
Settings::SettingValue<std::string> mSceneBrightGradientColour{ mIndex, sName, "scene-bright-gradient-colour",
|
||||||
|
"#2f3333" };
|
||||||
|
Settings::SettingValue<std::string> mSceneNightBackgroundColour{ mIndex, sName, "scene-night-background-colour",
|
||||||
|
"#404d4f" };
|
||||||
|
Settings::SettingValue<std::string> mSceneNightGradientColour{ mIndex, sName, "scene-night-gradient-colour",
|
||||||
|
"#2f3333" };
|
||||||
|
Settings::SettingValue<bool> mSceneDayNightSwitchNodes{ mIndex, sName, "scene-day-night-switch-nodes", true };
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TooltipsCategory : Settings::WithIndex
|
||||||
|
{
|
||||||
|
using Settings::WithIndex::WithIndex;
|
||||||
|
|
||||||
|
static constexpr std::string_view sName = "Tooltips";
|
||||||
|
|
||||||
|
Settings::SettingValue<bool> mScene{ mIndex, sName, "scene", true };
|
||||||
|
Settings::SettingValue<bool> mSceneHideBasic{ mIndex, sName, "scene-hide-basic", false };
|
||||||
|
Settings::SettingValue<int> mSceneDelay{ mIndex, sName, "scene-delay", 500 };
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SceneEditingCategory : Settings::WithIndex
|
||||||
|
{
|
||||||
|
using Settings::WithIndex::WithIndex;
|
||||||
|
|
||||||
|
static constexpr std::string_view sName = "3D Scene Editing";
|
||||||
|
|
||||||
|
static constexpr std::array<EnumValueView, 3> sInsertOutsideCellValues{
|
||||||
|
EnumValueView{ "Create cell and insert", "" },
|
||||||
|
EnumValueView{ "Discard", "" },
|
||||||
|
EnumValueView{ "Insert anyway", "" },
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr std::array<EnumValueView, 3> sInsertOutsideVisibleCellValues{
|
||||||
|
EnumValueView{ "Show cell and insert", "" },
|
||||||
|
EnumValueView{ "Discard", "" },
|
||||||
|
EnumValueView{ "Insert anyway", "" },
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr std::array<EnumValueView, 2> sLandEditOutsideCellValues{
|
||||||
|
EnumValueView{ "Create cell and land, then edit", "" },
|
||||||
|
EnumValueView{ "Discard", "" },
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr std::array<EnumValueView, 2> sLandEditOutsideVisibleCellValues{
|
||||||
|
EnumValueView{ "Show cell and edit", "" },
|
||||||
|
EnumValueView{ "Discard", "" },
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr std::array<EnumValueView, 4> sSelectAction{
|
||||||
|
EnumValueView{ "Select only", "" },
|
||||||
|
EnumValueView{ "Add to selection", "" },
|
||||||
|
EnumValueView{ "Remove from selection", "" },
|
||||||
|
EnumValueView{ "Invert selection", "" },
|
||||||
|
};
|
||||||
|
|
||||||
|
Settings::SettingValue<double> mGridsnapMovement{ mIndex, sName, "gridsnap-movement", 16 };
|
||||||
|
Settings::SettingValue<double> mGridsnapRotation{ mIndex, sName, "gridsnap-rotation", 15 };
|
||||||
|
Settings::SettingValue<double> mGridsnapScale{ mIndex, sName, "gridsnap-scale", 0.25 };
|
||||||
|
Settings::SettingValue<int> mDistance{ mIndex, sName, "distance", 50 };
|
||||||
|
EnumSettingValue mOutsideDrop{ mIndex, sName, "outside-drop", sInsertOutsideCellValues, 0 };
|
||||||
|
EnumSettingValue mOutsideVisibleDrop{ mIndex, sName, "outside-visible-drop", sInsertOutsideVisibleCellValues,
|
||||||
|
0 };
|
||||||
|
EnumSettingValue mOutsideLandedit{ mIndex, sName, "outside-landedit", sLandEditOutsideCellValues, 0 };
|
||||||
|
EnumSettingValue mOutsideVisibleLandedit{ mIndex, sName, "outside-visible-landedit",
|
||||||
|
sLandEditOutsideVisibleCellValues, 0 };
|
||||||
|
Settings::SettingValue<int> mTexturebrushMaximumsize{ mIndex, sName, "texturebrush-maximumsize", 50 };
|
||||||
|
Settings::SettingValue<int> mShapebrushMaximumsize{ mIndex, sName, "shapebrush-maximumsize", 100 };
|
||||||
|
Settings::SettingValue<bool> mLandeditPostSmoothpainting{ mIndex, sName, "landedit-post-smoothpainting",
|
||||||
|
false };
|
||||||
|
Settings::SettingValue<double> mLandeditPostSmoothstrength{ mIndex, sName, "landedit-post-smoothstrength",
|
||||||
|
0.25 };
|
||||||
|
Settings::SettingValue<bool> mOpenListView{ mIndex, sName, "open-list-view", false };
|
||||||
|
EnumSettingValue mPrimarySelectAction{ mIndex, sName, "primary-select-action", sSelectAction, 0 };
|
||||||
|
EnumSettingValue mSecondarySelectAction{ mIndex, sName, "secondary-select-action", sSelectAction, 1 };
|
||||||
|
};
|
||||||
|
|
||||||
|
struct KeyBindingsCategory : Settings::WithIndex
|
||||||
|
{
|
||||||
|
using Settings::WithIndex::WithIndex;
|
||||||
|
|
||||||
|
static constexpr std::string_view sName = "Key Bindings";
|
||||||
|
|
||||||
|
Settings::SettingValue<std::string> mDocumentFileNewgame{ mIndex, sName, "document-file-newgame", "Ctrl+N" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentFileNewaddon{ mIndex, sName, "document-file-newaddon", "" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentFileOpen{ mIndex, sName, "document-file-open", "Ctrl+O" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentFileSave{ mIndex, sName, "document-file-save", "Ctrl+S" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentHelpHelp{ mIndex, sName, "document-help-help", "F1" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentHelpTutorial{ mIndex, sName, "document-help-tutorial", "" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentFileVerify{ mIndex, sName, "document-file-verify", "" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentFileMerge{ mIndex, sName, "document-file-merge", "" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentFileErrorlog{ mIndex, sName, "document-file-errorlog", "" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentFileMetadata{ mIndex, sName, "document-file-metadata", "" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentFileClose{ mIndex, sName, "document-file-close", "Ctrl+W" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentFileExit{ mIndex, sName, "document-file-exit", "Ctrl+Q" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentEditUndo{ mIndex, sName, "document-edit-undo", "Ctrl+Z" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentEditRedo{ mIndex, sName, "document-edit-redo", "Ctrl+Shift+Z" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentEditPreferences{ mIndex, sName, "document-edit-preferences", "" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentEditSearch{ mIndex, sName, "document-edit-search", "Ctrl+F" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentViewNewview{ mIndex, sName, "document-view-newview", "" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentViewStatusbar{ mIndex, sName, "document-view-statusbar", "" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentViewFilters{ mIndex, sName, "document-view-filters", "" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentWorldRegions{ mIndex, sName, "document-world-regions", "" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentWorldCells{ mIndex, sName, "document-world-cells", "" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentWorldReferencables{ mIndex, sName, "document-world-referencables",
|
||||||
|
"" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentWorldReferences{ mIndex, sName, "document-world-references", "" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentWorldLands{ mIndex, sName, "document-world-lands", "" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentWorldLandtextures{ mIndex, sName, "document-world-landtextures",
|
||||||
|
"" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentWorldPathgrid{ mIndex, sName, "document-world-pathgrid", "" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentWorldRegionmap{ mIndex, sName, "document-world-regionmap", "" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentMechanicsGlobals{ mIndex, sName, "document-mechanics-globals",
|
||||||
|
"" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentMechanicsGamesettings{ mIndex, sName,
|
||||||
|
"document-mechanics-gamesettings", "" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentMechanicsScripts{ mIndex, sName, "document-mechanics-scripts",
|
||||||
|
"" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentMechanicsSpells{ mIndex, sName, "document-mechanics-spells", "" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentMechanicsEnchantments{ mIndex, sName,
|
||||||
|
"document-mechanics-enchantments", "" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentMechanicsMagiceffects{ mIndex, sName,
|
||||||
|
"document-mechanics-magiceffects", "" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentMechanicsStartscripts{ mIndex, sName,
|
||||||
|
"document-mechanics-startscripts", "" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentCharacterSkills{ mIndex, sName, "document-character-skills", "" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentCharacterClasses{ mIndex, sName, "document-character-classes",
|
||||||
|
"" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentCharacterFactions{ mIndex, sName, "document-character-factions",
|
||||||
|
"" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentCharacterRaces{ mIndex, sName, "document-character-races", "" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentCharacterBirthsigns{ mIndex, sName,
|
||||||
|
"document-character-birthsigns", "" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentCharacterTopics{ mIndex, sName, "document-character-topics", "" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentCharacterJournals{ mIndex, sName, "document-character-journals",
|
||||||
|
"" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentCharacterTopicinfos{ mIndex, sName,
|
||||||
|
"document-character-topicinfos", "" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentCharacterJournalinfos{ mIndex, sName,
|
||||||
|
"document-character-journalinfos", "" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentCharacterBodyparts{ mIndex, sName, "document-character-bodyparts",
|
||||||
|
"" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentAssetsReload{ mIndex, sName, "document-assets-reload", "F5" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentAssetsSounds{ mIndex, sName, "document-assets-sounds", "" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentAssetsSoundgens{ mIndex, sName, "document-assets-soundgens", "" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentAssetsMeshes{ mIndex, sName, "document-assets-meshes", "" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentAssetsIcons{ mIndex, sName, "document-assets-icons", "" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentAssetsMusic{ mIndex, sName, "document-assets-music", "" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentAssetsSoundres{ mIndex, sName, "document-assets-soundres", "" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentAssetsTextures{ mIndex, sName, "document-assets-textures", "" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentAssetsVideos{ mIndex, sName, "document-assets-videos", "" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentDebugRun{ mIndex, sName, "document-debug-run", "" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentDebugShutdown{ mIndex, sName, "document-debug-shutdown", "" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentDebugProfiles{ mIndex, sName, "document-debug-profiles", "" };
|
||||||
|
Settings::SettingValue<std::string> mDocumentDebugRunlog{ mIndex, sName, "document-debug-runlog", "" };
|
||||||
|
Settings::SettingValue<std::string> mTableEdit{ mIndex, sName, "table-edit", "" };
|
||||||
|
Settings::SettingValue<std::string> mTableAdd{ mIndex, sName, "table-add", "Shift+A" };
|
||||||
|
Settings::SettingValue<std::string> mTableClone{ mIndex, sName, "table-clone", "Shift+D" };
|
||||||
|
Settings::SettingValue<std::string> mTouchRecord{ mIndex, sName, "touch-record", "" };
|
||||||
|
Settings::SettingValue<std::string> mTableRevert{ mIndex, sName, "table-revert", "" };
|
||||||
|
Settings::SettingValue<std::string> mTableRemove{ mIndex, sName, "table-remove", "Delete" };
|
||||||
|
Settings::SettingValue<std::string> mTableMoveup{ mIndex, sName, "table-moveup", "" };
|
||||||
|
Settings::SettingValue<std::string> mTableMovedown{ mIndex, sName, "table-movedown", "" };
|
||||||
|
Settings::SettingValue<std::string> mTableView{ mIndex, sName, "table-view", "Shift+C" };
|
||||||
|
Settings::SettingValue<std::string> mTablePreview{ mIndex, sName, "table-preview", "Shift+V" };
|
||||||
|
Settings::SettingValue<std::string> mTableExtendeddelete{ mIndex, sName, "table-extendeddelete", "" };
|
||||||
|
Settings::SettingValue<std::string> mTableExtendedrevert{ mIndex, sName, "table-extendedrevert", "" };
|
||||||
|
Settings::SettingValue<std::string> mReporttableShow{ mIndex, sName, "reporttable-show", "" };
|
||||||
|
Settings::SettingValue<std::string> mReporttableRemove{ mIndex, sName, "reporttable-remove", "Delete" };
|
||||||
|
Settings::SettingValue<std::string> mReporttableReplace{ mIndex, sName, "reporttable-replace", "" };
|
||||||
|
Settings::SettingValue<std::string> mReporttableRefresh{ mIndex, sName, "reporttable-refresh", "" };
|
||||||
|
Settings::SettingValue<std::string> mSceneNaviPrimary{ mIndex, sName, "scene-navi-primary", "LMB" };
|
||||||
|
Settings::SettingValue<std::string> mSceneNaviSecondary{ mIndex, sName, "scene-navi-secondary", "Ctrl+LMB" };
|
||||||
|
Settings::SettingValue<std::string> mSceneOpenPrimary{ mIndex, sName, "scene-open-primary", "Shift+LMB" };
|
||||||
|
Settings::SettingValue<std::string> mSceneEditPrimary{ mIndex, sName, "scene-edit-primary", "RMB" };
|
||||||
|
Settings::SettingValue<std::string> mSceneEditSecondary{ mIndex, sName, "scene-edit-secondary", "Ctrl+RMB" };
|
||||||
|
Settings::SettingValue<std::string> mSceneSelectPrimary{ mIndex, sName, "scene-select-primary", "MMB" };
|
||||||
|
Settings::SettingValue<std::string> mSceneSelectSecondary{ mIndex, sName, "scene-select-secondary",
|
||||||
|
"Ctrl+MMB" };
|
||||||
|
Settings::SettingValue<std::string> mSceneSelectTertiary{ mIndex, sName, "scene-select-tertiary", "Shift+MMB" };
|
||||||
|
Settings::SettingValue<std::string> mSceneSpeedModifier{ mIndex, sName, "scene-speed-modifier", "Shift" };
|
||||||
|
Settings::SettingValue<std::string> mSceneDelete{ mIndex, sName, "scene-delete", "Delete" };
|
||||||
|
Settings::SettingValue<std::string> mSceneInstanceDropTerrain{ mIndex, sName, "scene-instance-drop-terrain",
|
||||||
|
"G" };
|
||||||
|
Settings::SettingValue<std::string> mSceneInstanceDropCollision{ mIndex, sName, "scene-instance-drop-collision",
|
||||||
|
"H" };
|
||||||
|
Settings::SettingValue<std::string> mSceneInstanceDropTerrainSeparately{ mIndex, sName,
|
||||||
|
"scene-instance-drop-terrain-separately", "" };
|
||||||
|
Settings::SettingValue<std::string> mSceneInstanceDropCollisionSeparately{ mIndex, sName,
|
||||||
|
"scene-instance-drop-collision-separately", "" };
|
||||||
|
Settings::SettingValue<std::string> mSceneDuplicate{ mIndex, sName, "scene-duplicate", "Shift+C" };
|
||||||
|
Settings::SettingValue<std::string> mSceneLoadCamCell{ mIndex, sName, "scene-load-cam-cell", "Keypad+5" };
|
||||||
|
Settings::SettingValue<std::string> mSceneLoadCamEastcell{ mIndex, sName, "scene-load-cam-eastcell",
|
||||||
|
"Keypad+6" };
|
||||||
|
Settings::SettingValue<std::string> mSceneLoadCamNorthcell{ mIndex, sName, "scene-load-cam-northcell",
|
||||||
|
"Keypad+8" };
|
||||||
|
Settings::SettingValue<std::string> mSceneLoadCamWestcell{ mIndex, sName, "scene-load-cam-westcell",
|
||||||
|
"Keypad+4" };
|
||||||
|
Settings::SettingValue<std::string> mSceneLoadCamSouthcell{ mIndex, sName, "scene-load-cam-southcell",
|
||||||
|
"Keypad+2" };
|
||||||
|
Settings::SettingValue<std::string> mSceneEditAbort{ mIndex, sName, "scene-edit-abort", "Escape" };
|
||||||
|
Settings::SettingValue<std::string> mSceneFocusToolbar{ mIndex, sName, "scene-focus-toolbar", "T" };
|
||||||
|
Settings::SettingValue<std::string> mSceneRenderStats{ mIndex, sName, "scene-render-stats", "F3" };
|
||||||
|
Settings::SettingValue<std::string> mSceneClearSelection{ mIndex, sName, "scene-clear-selection", "Space" };
|
||||||
|
Settings::SettingValue<std::string> mSceneUnhideAll{ mIndex, sName, "scene-unhide-all", "Alt+H" };
|
||||||
|
Settings::SettingValue<std::string> mSceneToggleVisibility{ mIndex, sName, "scene-toggle-visibility", "H" };
|
||||||
|
Settings::SettingValue<std::string> mSceneGroup0{ mIndex, sName, "scene-group-0", "0" };
|
||||||
|
Settings::SettingValue<std::string> mSceneSave0{ mIndex, sName, "scene-save-0", "Ctrl+0" };
|
||||||
|
Settings::SettingValue<std::string> mSceneGroup1{ mIndex, sName, "scene-group-1", "1" };
|
||||||
|
Settings::SettingValue<std::string> mSceneSave1{ mIndex, sName, "scene-save-1", "Ctrl+1" };
|
||||||
|
Settings::SettingValue<std::string> mSceneGroup2{ mIndex, sName, "scene-group-2", "2" };
|
||||||
|
Settings::SettingValue<std::string> mSceneSave2{ mIndex, sName, "scene-save-2", "Ctrl+2" };
|
||||||
|
Settings::SettingValue<std::string> mSceneGroup3{ mIndex, sName, "scene-group-3", "3" };
|
||||||
|
Settings::SettingValue<std::string> mSceneSave3{ mIndex, sName, "scene-save-3", "Ctrl+3" };
|
||||||
|
Settings::SettingValue<std::string> mSceneGroup4{ mIndex, sName, "scene-group-4", "4" };
|
||||||
|
Settings::SettingValue<std::string> mSceneSave4{ mIndex, sName, "scene-save-4", "Ctrl+4" };
|
||||||
|
Settings::SettingValue<std::string> mSceneGroup5{ mIndex, sName, "scene-group-5", "5" };
|
||||||
|
Settings::SettingValue<std::string> mSceneSave5{ mIndex, sName, "scene-save-5", "Ctrl+5" };
|
||||||
|
Settings::SettingValue<std::string> mSceneGroup6{ mIndex, sName, "scene-group-6", "6" };
|
||||||
|
Settings::SettingValue<std::string> mSceneSave6{ mIndex, sName, "scene-save-6", "Ctrl+6" };
|
||||||
|
Settings::SettingValue<std::string> mSceneGroup7{ mIndex, sName, "scene-group-7", "7" };
|
||||||
|
Settings::SettingValue<std::string> mSceneSave7{ mIndex, sName, "scene-save-7", "Ctrl+7" };
|
||||||
|
Settings::SettingValue<std::string> mSceneGroup8{ mIndex, sName, "scene-group-8", "8" };
|
||||||
|
Settings::SettingValue<std::string> mSceneSave8{ mIndex, sName, "scene-save-8", "Ctrl+8" };
|
||||||
|
Settings::SettingValue<std::string> mSceneGroup9{ mIndex, sName, "scene-group-9", "9" };
|
||||||
|
Settings::SettingValue<std::string> mSceneSave9{ mIndex, sName, "scene-save-9", "Ctrl+9" };
|
||||||
|
Settings::SettingValue<std::string> mFreeForward{ mIndex, sName, "free-forward", "W" };
|
||||||
|
Settings::SettingValue<std::string> mFreeBackward{ mIndex, sName, "free-backward", "S" };
|
||||||
|
Settings::SettingValue<std::string> mFreeLeft{ mIndex, sName, "free-left", "A" };
|
||||||
|
Settings::SettingValue<std::string> mFreeRight{ mIndex, sName, "free-right", "D" };
|
||||||
|
Settings::SettingValue<std::string> mFreeRollLeft{ mIndex, sName, "free-roll-left", "Q" };
|
||||||
|
Settings::SettingValue<std::string> mFreeRollRight{ mIndex, sName, "free-roll-right", "E" };
|
||||||
|
Settings::SettingValue<std::string> mFreeSpeedMode{ mIndex, sName, "free-speed-mode", "F" };
|
||||||
|
Settings::SettingValue<std::string> mOrbitUp{ mIndex, sName, "orbit-up", "W" };
|
||||||
|
Settings::SettingValue<std::string> mOrbitDown{ mIndex, sName, "orbit-down", "S" };
|
||||||
|
Settings::SettingValue<std::string> mOrbitLeft{ mIndex, sName, "orbit-left", "A" };
|
||||||
|
Settings::SettingValue<std::string> mOrbitRight{ mIndex, sName, "orbit-right", "D" };
|
||||||
|
Settings::SettingValue<std::string> mOrbitRollLeft{ mIndex, sName, "orbit-roll-left", "Q" };
|
||||||
|
Settings::SettingValue<std::string> mOrbitRollRight{ mIndex, sName, "orbit-roll-right", "E" };
|
||||||
|
Settings::SettingValue<std::string> mOrbitSpeedMode{ mIndex, sName, "orbit-speed-mode", "F" };
|
||||||
|
Settings::SettingValue<std::string> mOrbitCenterSelection{ mIndex, sName, "orbit-center-selection", "C" };
|
||||||
|
Settings::SettingValue<std::string> mScriptEditorComment{ mIndex, sName, "script-editor-comment", "" };
|
||||||
|
Settings::SettingValue<std::string> mScriptEditorUncomment{ mIndex, sName, "script-editor-uncomment", "" };
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ModelsCategory : Settings::WithIndex
|
||||||
|
{
|
||||||
|
using Settings::WithIndex::WithIndex;
|
||||||
|
|
||||||
|
static constexpr std::string_view sName = "Models";
|
||||||
|
|
||||||
|
Settings::SettingValue<std::string> mBaseanim{ mIndex, sName, "baseanim", "meshes/base_anim.nif" };
|
||||||
|
Settings::SettingValue<std::string> mBaseanimkna{ mIndex, sName, "baseanimkna", "meshes/base_animkna.nif" };
|
||||||
|
Settings::SettingValue<std::string> mBaseanimfemale{ mIndex, sName, "baseanimfemale",
|
||||||
|
"meshes/base_anim_female.nif" };
|
||||||
|
Settings::SettingValue<std::string> mWolfskin{ mIndex, sName, "wolfskin", "meshes/wolf/skin.nif" };
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Values : Settings::WithIndex
|
||||||
|
{
|
||||||
|
using Settings::WithIndex::WithIndex;
|
||||||
|
|
||||||
|
WindowsCategory mWindows{ mIndex };
|
||||||
|
RecordsCategory mRecords{ mIndex };
|
||||||
|
IdTablesCategory mIdTables{ mIndex };
|
||||||
|
IdDialoguesCategory mIdDialogues{ mIndex };
|
||||||
|
ReportsCategory mReports{ mIndex };
|
||||||
|
SearchAndReplaceCategory mSearchAndReplace{ mIndex };
|
||||||
|
ScriptsCategory mScripts{ mIndex };
|
||||||
|
GeneralInputCategory mGeneralInput{ mIndex };
|
||||||
|
SceneInputCategory mSceneInput{ mIndex };
|
||||||
|
RenderingCategory mRendering{ mIndex };
|
||||||
|
TooltipsCategory mTooltips{ mIndex };
|
||||||
|
SceneEditingCategory mSceneEditing{ mIndex };
|
||||||
|
KeyBindingsCategory mKeyBindings{ mIndex };
|
||||||
|
ModelsCategory mModels{ mIndex };
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -189,9 +189,9 @@ void CSMTools::FixLandsAndLandTexturesMergeStage::perform(int stage, CSMDoc::Mes
|
||||||
CSMWorld::IdTable& ltexTable = dynamic_cast<CSMWorld::IdTable&>(
|
CSMWorld::IdTable& ltexTable = dynamic_cast<CSMWorld::IdTable&>(
|
||||||
*mState.mTarget->getData().getTableModel(CSMWorld::UniversalId::Type_LandTextures));
|
*mState.mTarget->getData().getTableModel(CSMWorld::UniversalId::Type_LandTextures));
|
||||||
|
|
||||||
const std::string& id = mState.mTarget->getData().getLand().getId(stage).getRefIdString();
|
const auto& id = mState.mTarget->getData().getLand().getId(stage);
|
||||||
|
|
||||||
CSMWorld::TouchLandCommand cmd(landTable, ltexTable, id);
|
CSMWorld::TouchLandCommand cmd(landTable, ltexTable, id.getRefIdString());
|
||||||
cmd.redo();
|
cmd.redo();
|
||||||
|
|
||||||
// Get rid of base data
|
// Get rid of base data
|
||||||
|
|
|
@ -41,17 +41,17 @@ void CSMTools::RaceCheckStage::performPerRecord(int stage, CSMDoc::Messages& mes
|
||||||
messages.add(id, "Description is missing", "", CSMDoc::Message::Severity_Warning);
|
messages.add(id, "Description is missing", "", CSMDoc::Message::Severity_Warning);
|
||||||
|
|
||||||
// test for positive height
|
// test for positive height
|
||||||
if (race.mData.mHeight.mMale <= 0)
|
if (race.mData.mMaleHeight <= 0)
|
||||||
messages.add(id, "Male height is non-positive", "", CSMDoc::Message::Severity_Error);
|
messages.add(id, "Male height is non-positive", "", CSMDoc::Message::Severity_Error);
|
||||||
|
|
||||||
if (race.mData.mHeight.mFemale <= 0)
|
if (race.mData.mFemaleHeight <= 0)
|
||||||
messages.add(id, "Female height is non-positive", "", CSMDoc::Message::Severity_Error);
|
messages.add(id, "Female height is non-positive", "", CSMDoc::Message::Severity_Error);
|
||||||
|
|
||||||
// test for non-negative weight
|
// test for non-negative weight
|
||||||
if (race.mData.mWeight.mMale < 0)
|
if (race.mData.mMaleWeight < 0)
|
||||||
messages.add(id, "Male weight is negative", "", CSMDoc::Message::Severity_Error);
|
messages.add(id, "Male weight is negative", "", CSMDoc::Message::Severity_Error);
|
||||||
|
|
||||||
if (race.mData.mWeight.mFemale < 0)
|
if (race.mData.mFemaleWeight < 0)
|
||||||
messages.add(id, "Female weight is negative", "", CSMDoc::Message::Severity_Error);
|
messages.add(id, "Female weight is negative", "", CSMDoc::Message::Severity_Error);
|
||||||
|
|
||||||
/// \todo check data members that can't be edited in the table view
|
/// \todo check data members that can't be edited in the table view
|
||||||
|
|
|
@ -693,22 +693,12 @@ void CSMTools::ReferenceableCheckStage::npcCheck(
|
||||||
}
|
}
|
||||||
else if (npc.mNpdt.mHealth != 0)
|
else if (npc.mNpdt.mHealth != 0)
|
||||||
{
|
{
|
||||||
if (npc.mNpdt.mStrength == 0)
|
for (size_t i = 0; i < npc.mNpdt.mAttributes.size(); ++i)
|
||||||
messages.add(id, "Strength is equal to zero", "", CSMDoc::Message::Severity_Warning);
|
{
|
||||||
if (npc.mNpdt.mIntelligence == 0)
|
if (npc.mNpdt.mAttributes[i] == 0)
|
||||||
messages.add(id, "Intelligence is equal to zero", "", CSMDoc::Message::Severity_Warning);
|
messages.add(id, ESM::Attribute::indexToRefId(i).getRefIdString() + " is equal to zero", {},
|
||||||
if (npc.mNpdt.mWillpower == 0)
|
CSMDoc::Message::Severity_Warning);
|
||||||
messages.add(id, "Willpower is equal to zero", "", CSMDoc::Message::Severity_Warning);
|
}
|
||||||
if (npc.mNpdt.mAgility == 0)
|
|
||||||
messages.add(id, "Agility is equal to zero", "", CSMDoc::Message::Severity_Warning);
|
|
||||||
if (npc.mNpdt.mSpeed == 0)
|
|
||||||
messages.add(id, "Speed is equal to zero", "", CSMDoc::Message::Severity_Warning);
|
|
||||||
if (npc.mNpdt.mEndurance == 0)
|
|
||||||
messages.add(id, "Endurance is equal to zero", "", CSMDoc::Message::Severity_Warning);
|
|
||||||
if (npc.mNpdt.mPersonality == 0)
|
|
||||||
messages.add(id, "Personality is equal to zero", "", CSMDoc::Message::Severity_Warning);
|
|
||||||
if (npc.mNpdt.mLuck == 0)
|
|
||||||
messages.add(id, "Luck is equal to zero", "", CSMDoc::Message::Severity_Warning);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (level <= 0)
|
if (level <= 0)
|
||||||
|
|
|
@ -98,9 +98,8 @@ void CSMTools::ReferenceCheckStage::perform(int stage, CSMDoc::Messages& message
|
||||||
if (cellRef.mEnchantmentCharge < -1)
|
if (cellRef.mEnchantmentCharge < -1)
|
||||||
messages.add(id, "Negative number of enchantment points", "", CSMDoc::Message::Severity_Error);
|
messages.add(id, "Negative number of enchantment points", "", CSMDoc::Message::Severity_Error);
|
||||||
|
|
||||||
// Check if gold value isn't negative
|
if (cellRef.mCount < 1)
|
||||||
if (cellRef.mGoldValue < 0)
|
messages.add(id, "Reference without count", {}, CSMDoc::Message::Severity_Error);
|
||||||
messages.add(id, "Negative gold value", "", CSMDoc::Message::Severity_Error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int CSMTools::ReferenceCheckStage::setup()
|
int CSMTools::ReferenceCheckStage::setup()
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <apps/opencs/model/prefs/state.hpp>
|
||||||
#include <apps/opencs/model/world/columns.hpp>
|
#include <apps/opencs/model/world/columns.hpp>
|
||||||
#include <apps/opencs/model/world/idcollection.hpp>
|
#include <apps/opencs/model/world/idcollection.hpp>
|
||||||
#include <apps/opencs/model/world/record.hpp>
|
#include <apps/opencs/model/world/record.hpp>
|
||||||
|
@ -132,11 +133,11 @@ namespace CSMWorld
|
||||||
bool beast = mRaceData ? mRaceData->isBeast() : false;
|
bool beast = mRaceData ? mRaceData->isBeast() : false;
|
||||||
|
|
||||||
if (beast)
|
if (beast)
|
||||||
return Settings::Manager::getString("baseanimkna", "Models");
|
return CSMPrefs::get()["Models"]["baseanimkna"].toString();
|
||||||
else if (mFemale)
|
else if (mFemale)
|
||||||
return Settings::Manager::getString("baseanimfemale", "Models");
|
return CSMPrefs::get()["Models"]["baseanimfemale"].toString();
|
||||||
else
|
else
|
||||||
return Settings::Manager::getString("baseanim", "Models");
|
return CSMPrefs::get()["Models"]["baseanim"].toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
ESM::RefId ActorAdapter::ActorData::getPart(ESM::PartReferenceType index) const
|
ESM::RefId ActorAdapter::ActorData::getPart(ESM::PartReferenceType index) const
|
||||||
|
|
|
@ -333,6 +333,37 @@ namespace CSMWorld
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SelectionGroupColumn::SelectionGroupColumn()
|
||||||
|
: Column<ESM::SelectionGroup>(Columns::ColumnId_SelectionGroupObjects, ColumnBase::Display_None)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant SelectionGroupColumn::get(const Record<ESM::SelectionGroup>& record) const
|
||||||
|
{
|
||||||
|
QVariant data;
|
||||||
|
QStringList selectionInfo;
|
||||||
|
const std::vector<std::string>& instances = record.get().selectedInstances;
|
||||||
|
|
||||||
|
for (const std::string& instance : instances)
|
||||||
|
selectionInfo << QString::fromStdString(instance);
|
||||||
|
data.setValue(selectionInfo);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SelectionGroupColumn::set(Record<ESM::SelectionGroup>& record, const QVariant& data)
|
||||||
|
{
|
||||||
|
ESM::SelectionGroup record2 = record.get();
|
||||||
|
for (const auto& item : data.toStringList())
|
||||||
|
record2.selectedInstances.push_back(item.toStdString());
|
||||||
|
record.setModified(record2);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SelectionGroupColumn::isEditable() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<std::uint32_t> getSkillIndex(std::string_view value)
|
std::optional<std::uint32_t> getSkillIndex(std::string_view value)
|
||||||
{
|
{
|
||||||
int index = ESM::Skill::refIdToIndex(ESM::RefId::stringRefId(value));
|
int index = ESM::Skill::refIdToIndex(ESM::RefId::stringRefId(value));
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include <components/esm3/loadinfo.hpp>
|
#include <components/esm3/loadinfo.hpp>
|
||||||
#include <components/esm3/loadrace.hpp>
|
#include <components/esm3/loadrace.hpp>
|
||||||
#include <components/esm3/loadskil.hpp>
|
#include <components/esm3/loadskil.hpp>
|
||||||
|
#include <components/esm3/selectiongroup.hpp>
|
||||||
#include <components/esm3/variant.hpp>
|
#include <components/esm3/variant.hpp>
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
@ -570,19 +571,34 @@ namespace CSMWorld
|
||||||
|
|
||||||
QVariant get(const Record<ESXRecordT>& record) const override
|
QVariant get(const Record<ESXRecordT>& record) const override
|
||||||
{
|
{
|
||||||
const ESM::Race::MaleFemaleF& value = mWeight ? record.get().mData.mWeight : record.get().mData.mHeight;
|
if (mWeight)
|
||||||
|
{
|
||||||
return mMale ? value.mMale : value.mFemale;
|
if (mMale)
|
||||||
|
return record.get().mData.mMaleWeight;
|
||||||
|
return record.get().mData.mFemaleWeight;
|
||||||
|
}
|
||||||
|
if (mMale)
|
||||||
|
return record.get().mData.mMaleHeight;
|
||||||
|
return record.get().mData.mFemaleHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set(Record<ESXRecordT>& record, const QVariant& data) override
|
void set(Record<ESXRecordT>& record, const QVariant& data) override
|
||||||
{
|
{
|
||||||
ESXRecordT record2 = record.get();
|
ESXRecordT record2 = record.get();
|
||||||
|
if (mWeight)
|
||||||
ESM::Race::MaleFemaleF& value = mWeight ? record2.mData.mWeight : record2.mData.mHeight;
|
{
|
||||||
|
if (mMale)
|
||||||
(mMale ? value.mMale : value.mFemale) = data.toFloat();
|
record2.mData.mMaleWeight = data.toFloat();
|
||||||
|
else
|
||||||
|
record2.mData.mFemaleWeight = data.toFloat();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (mMale)
|
||||||
|
record2.mData.mMaleHeight = data.toFloat();
|
||||||
|
else
|
||||||
|
record2.mData.mFemaleHeight = data.toFloat();
|
||||||
|
}
|
||||||
record.setModified(record2);
|
record.setModified(record2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1095,19 +1111,19 @@ namespace CSMWorld
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename ESXRecordT>
|
template <typename ESXRecordT>
|
||||||
struct GoldValueColumn : public Column<ESXRecordT>
|
struct StackSizeColumn : public Column<ESXRecordT>
|
||||||
{
|
{
|
||||||
GoldValueColumn()
|
StackSizeColumn()
|
||||||
: Column<ESXRecordT>(Columns::ColumnId_CoinValue, ColumnBase::Display_Integer)
|
: Column<ESXRecordT>(Columns::ColumnId_StackCount, ColumnBase::Display_Integer)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant get(const Record<ESXRecordT>& record) const override { return record.get().mGoldValue; }
|
QVariant get(const Record<ESXRecordT>& record) const override { return record.get().mCount; }
|
||||||
|
|
||||||
void set(Record<ESXRecordT>& record, const QVariant& data) override
|
void set(Record<ESXRecordT>& record, const QVariant& data) override
|
||||||
{
|
{
|
||||||
ESXRecordT record2 = record.get();
|
ESXRecordT record2 = record.get();
|
||||||
record2.mGoldValue = data.toInt();
|
record2.mCount = data.toInt();
|
||||||
record.setModified(record2);
|
record.setModified(record2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2376,6 +2392,17 @@ namespace CSMWorld
|
||||||
void set(Record<ESM::BodyPart>& record, const QVariant& data) override;
|
void set(Record<ESM::BodyPart>& record, const QVariant& data) override;
|
||||||
bool isEditable() const override;
|
bool isEditable() const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SelectionGroupColumn : public Column<ESM::SelectionGroup>
|
||||||
|
{
|
||||||
|
SelectionGroupColumn();
|
||||||
|
|
||||||
|
QVariant get(const Record<ESM::SelectionGroup>& record) const override;
|
||||||
|
|
||||||
|
void set(Record<ESM::SelectionGroup>& record, const QVariant& data) override;
|
||||||
|
|
||||||
|
bool isEditable() const override;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is required to access the type as a QVariant.
|
// This is required to access the type as a QVariant.
|
||||||
|
|
|
@ -56,7 +56,7 @@ namespace CSMWorld
|
||||||
{ ColumnId_FactionIndex, "Faction Index" },
|
{ ColumnId_FactionIndex, "Faction Index" },
|
||||||
{ ColumnId_Charges, "Charges" },
|
{ ColumnId_Charges, "Charges" },
|
||||||
{ ColumnId_Enchantment, "Enchantment" },
|
{ ColumnId_Enchantment, "Enchantment" },
|
||||||
{ ColumnId_CoinValue, "Coin Value" },
|
{ ColumnId_StackCount, "Count" },
|
||||||
{ ColumnId_Teleport, "Teleport" },
|
{ ColumnId_Teleport, "Teleport" },
|
||||||
{ ColumnId_TeleportCell, "Teleport Cell" },
|
{ ColumnId_TeleportCell, "Teleport Cell" },
|
||||||
{ ColumnId_LockLevel, "Lock Level" },
|
{ ColumnId_LockLevel, "Lock Level" },
|
||||||
|
|
|
@ -45,7 +45,7 @@ namespace CSMWorld
|
||||||
ColumnId_FactionIndex = 31,
|
ColumnId_FactionIndex = 31,
|
||||||
ColumnId_Charges = 32,
|
ColumnId_Charges = 32,
|
||||||
ColumnId_Enchantment = 33,
|
ColumnId_Enchantment = 33,
|
||||||
ColumnId_CoinValue = 34,
|
ColumnId_StackCount = 34,
|
||||||
ColumnId_Teleport = 35,
|
ColumnId_Teleport = 35,
|
||||||
ColumnId_TeleportCell = 36,
|
ColumnId_TeleportCell = 36,
|
||||||
ColumnId_LockLevel = 37,
|
ColumnId_LockLevel = 37,
|
||||||
|
@ -347,6 +347,8 @@ namespace CSMWorld
|
||||||
|
|
||||||
ColumnId_LevelledCreatureId = 315,
|
ColumnId_LevelledCreatureId = 315,
|
||||||
|
|
||||||
|
ColumnId_SelectionGroupObjects = 316,
|
||||||
|
|
||||||
// Allocated to a separate value range, so we don't get a collision should we ever need
|
// Allocated to a separate value range, so we don't get a collision should we ever need
|
||||||
// to extend the number of use values.
|
// to extend the number of use values.
|
||||||
ColumnId_UseValue1 = 0x10000,
|
ColumnId_UseValue1 = 0x10000,
|
||||||
|
|
|
@ -587,7 +587,7 @@ CSMWorld::Data::Data(ToUTF8::FromType encoding, const Files::PathContainer& data
|
||||||
mRefs.addColumn(new FactionIndexColumn<CellRef>);
|
mRefs.addColumn(new FactionIndexColumn<CellRef>);
|
||||||
mRefs.addColumn(new ChargesColumn<CellRef>);
|
mRefs.addColumn(new ChargesColumn<CellRef>);
|
||||||
mRefs.addColumn(new EnchantmentChargesColumn<CellRef>);
|
mRefs.addColumn(new EnchantmentChargesColumn<CellRef>);
|
||||||
mRefs.addColumn(new GoldValueColumn<CellRef>);
|
mRefs.addColumn(new StackSizeColumn<CellRef>);
|
||||||
mRefs.addColumn(new TeleportColumn<CellRef>);
|
mRefs.addColumn(new TeleportColumn<CellRef>);
|
||||||
mRefs.addColumn(new TeleportCellColumn<CellRef>);
|
mRefs.addColumn(new TeleportCellColumn<CellRef>);
|
||||||
mRefs.addColumn(new PosColumn<CellRef>(&CellRef::mDoorDest, 0, true));
|
mRefs.addColumn(new PosColumn<CellRef>(&CellRef::mDoorDest, 0, true));
|
||||||
|
@ -620,6 +620,11 @@ CSMWorld::Data::Data(ToUTF8::FromType encoding, const Files::PathContainer& data
|
||||||
mDebugProfiles.addColumn(new DescriptionColumn<ESM::DebugProfile>);
|
mDebugProfiles.addColumn(new DescriptionColumn<ESM::DebugProfile>);
|
||||||
mDebugProfiles.addColumn(new ScriptColumn<ESM::DebugProfile>(ScriptColumn<ESM::DebugProfile>::Type_Lines));
|
mDebugProfiles.addColumn(new ScriptColumn<ESM::DebugProfile>(ScriptColumn<ESM::DebugProfile>::Type_Lines));
|
||||||
|
|
||||||
|
mSelectionGroups.addColumn(new StringIdColumn<ESM::SelectionGroup>);
|
||||||
|
mSelectionGroups.addColumn(new RecordStateColumn<ESM::SelectionGroup>);
|
||||||
|
mSelectionGroups.addColumn(new FixedRecordTypeColumn<ESM::SelectionGroup>(UniversalId::Type_SelectionGroup));
|
||||||
|
mSelectionGroups.addColumn(new SelectionGroupColumn);
|
||||||
|
|
||||||
mMetaData.appendBlankRecord(ESM::RefId::stringRefId("sys::meta"));
|
mMetaData.appendBlankRecord(ESM::RefId::stringRefId("sys::meta"));
|
||||||
|
|
||||||
mMetaData.addColumn(new StringIdColumn<MetaData>(true));
|
mMetaData.addColumn(new StringIdColumn<MetaData>(true));
|
||||||
|
@ -664,6 +669,7 @@ CSMWorld::Data::Data(ToUTF8::FromType encoding, const Files::PathContainer& data
|
||||||
addModel(new ResourceTable(&mResourcesManager.get(UniversalId::Type_Textures)), UniversalId::Type_Texture);
|
addModel(new ResourceTable(&mResourcesManager.get(UniversalId::Type_Textures)), UniversalId::Type_Texture);
|
||||||
addModel(new ResourceTable(&mResourcesManager.get(UniversalId::Type_Videos)), UniversalId::Type_Video);
|
addModel(new ResourceTable(&mResourcesManager.get(UniversalId::Type_Videos)), UniversalId::Type_Video);
|
||||||
addModel(new IdTable(&mMetaData), UniversalId::Type_MetaData);
|
addModel(new IdTable(&mMetaData), UniversalId::Type_MetaData);
|
||||||
|
addModel(new IdTable(&mSelectionGroups), UniversalId::Type_SelectionGroup);
|
||||||
|
|
||||||
mActorAdapter = std::make_unique<ActorAdapter>(*this);
|
mActorAdapter = std::make_unique<ActorAdapter>(*this);
|
||||||
|
|
||||||
|
@ -908,6 +914,16 @@ CSMWorld::IdCollection<ESM::DebugProfile>& CSMWorld::Data::getDebugProfiles()
|
||||||
return mDebugProfiles;
|
return mDebugProfiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CSMWorld::IdCollection<ESM::SelectionGroup>& CSMWorld::Data::getSelectionGroups()
|
||||||
|
{
|
||||||
|
return mSelectionGroups;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CSMWorld::IdCollection<ESM::SelectionGroup>& CSMWorld::Data::getSelectionGroups() const
|
||||||
|
{
|
||||||
|
return mSelectionGroups;
|
||||||
|
}
|
||||||
|
|
||||||
const CSMWorld::IdCollection<CSMWorld::Land>& CSMWorld::Data::getLand() const
|
const CSMWorld::IdCollection<CSMWorld::Land>& CSMWorld::Data::getLand() const
|
||||||
{
|
{
|
||||||
return mLand;
|
return mLand;
|
||||||
|
@ -1369,6 +1385,17 @@ bool CSMWorld::Data::continueLoading(CSMDoc::Messages& messages)
|
||||||
mDebugProfiles.load(*mReader, mBase);
|
mDebugProfiles.load(*mReader, mBase);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ESM::REC_SELG:
|
||||||
|
|
||||||
|
if (!mProject)
|
||||||
|
{
|
||||||
|
unhandledRecord = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
mSelectionGroups.load(*mReader, mBase);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
||||||
unhandledRecord = true;
|
unhandledRecord = true;
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
#include <components/esm3/loadsoun.hpp>
|
#include <components/esm3/loadsoun.hpp>
|
||||||
#include <components/esm3/loadspel.hpp>
|
#include <components/esm3/loadspel.hpp>
|
||||||
#include <components/esm3/loadsscr.hpp>
|
#include <components/esm3/loadsscr.hpp>
|
||||||
|
#include <components/esm3/selectiongroup.hpp>
|
||||||
#include <components/files/multidircollection.hpp>
|
#include <components/files/multidircollection.hpp>
|
||||||
#include <components/misc/algorithm.hpp>
|
#include <components/misc/algorithm.hpp>
|
||||||
#include <components/to_utf8/to_utf8.hpp>
|
#include <components/to_utf8/to_utf8.hpp>
|
||||||
|
@ -105,6 +106,7 @@ namespace CSMWorld
|
||||||
IdCollection<ESM::BodyPart> mBodyParts;
|
IdCollection<ESM::BodyPart> mBodyParts;
|
||||||
IdCollection<ESM::MagicEffect> mMagicEffects;
|
IdCollection<ESM::MagicEffect> mMagicEffects;
|
||||||
IdCollection<ESM::DebugProfile> mDebugProfiles;
|
IdCollection<ESM::DebugProfile> mDebugProfiles;
|
||||||
|
IdCollection<ESM::SelectionGroup> mSelectionGroups;
|
||||||
IdCollection<ESM::SoundGenerator> mSoundGens;
|
IdCollection<ESM::SoundGenerator> mSoundGens;
|
||||||
IdCollection<ESM::StartScript> mStartScripts;
|
IdCollection<ESM::StartScript> mStartScripts;
|
||||||
NestedInfoCollection mTopicInfos;
|
NestedInfoCollection mTopicInfos;
|
||||||
|
@ -251,6 +253,10 @@ namespace CSMWorld
|
||||||
|
|
||||||
IdCollection<ESM::DebugProfile>& getDebugProfiles();
|
IdCollection<ESM::DebugProfile>& getDebugProfiles();
|
||||||
|
|
||||||
|
const IdCollection<ESM::SelectionGroup>& getSelectionGroups() const;
|
||||||
|
|
||||||
|
IdCollection<ESM::SelectionGroup>& getSelectionGroups();
|
||||||
|
|
||||||
const IdCollection<CSMWorld::Land>& getLand() const;
|
const IdCollection<CSMWorld::Land>& getLand() const;
|
||||||
|
|
||||||
IdCollection<CSMWorld::Land>& getLand();
|
IdCollection<CSMWorld::Land>& getLand();
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue