mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-03-29 13:20:35 +00:00
Merge branch 'master' into menuscripts
This commit is contained in:
commit
d1268acf95
1
.gitignore
vendored
1
.gitignore
vendored
@ -28,6 +28,7 @@ Doxygen
|
||||
.idea
|
||||
cmake-build-*
|
||||
files/windows/*.aps
|
||||
.cache/clangd
|
||||
## qt-creator
|
||||
CMakeLists.txt.user*
|
||||
.vs
|
||||
|
@ -142,7 +142,7 @@ Ubuntu_GCC:
|
||||
variables:
|
||||
CC: gcc
|
||||
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.
|
||||
timeout: 2h
|
||||
|
||||
@ -193,7 +193,7 @@ Ubuntu_GCC_Debug:
|
||||
variables:
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
CCACHE_SIZE: 4G
|
||||
CCACHE_SIZE: 3G
|
||||
CMAKE_BUILD_TYPE: Debug
|
||||
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.
|
||||
|
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 #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 #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 #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 #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 #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 #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
|
||||
@ -22,6 +29,7 @@
|
||||
Bug #5977: Fatigueless NPCs' corpse underwater changes animation on game load
|
||||
Bug #6025: Subrecords cannot overlap records
|
||||
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 #6313: Followers with high Fight can turn hostile
|
||||
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 #6661: Saved games that have no preview screenshot cause issues or crashes
|
||||
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 #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
|
||||
@ -63,32 +73,63 @@
|
||||
Bug #7229: Error marker loading failure is not handled
|
||||
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 #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 #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 #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 #7415: Unbreakable lock discrepancies
|
||||
Bug #7416: Modpccrimelevel is different from vanilla
|
||||
Bug #7428: AutoCalc flag is not used to calculate enchantment costs
|
||||
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 #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 #7505: Distant terrain does not support sample size greater than cell size
|
||||
Bug #7553: Faction reaction loading is incorrect
|
||||
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 #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 #7604: Goblins Grunt becomes idle once injured
|
||||
Bug #7609: ForceGreeting should not open dialogue for werewolves
|
||||
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 #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 #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 #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 #5173: Support for NiFogProperty
|
||||
Feature #5492: Let rain and snow collide with statics
|
||||
Feature #6149: Dehardcode Lua API_REVISION
|
||||
Feature #6152: Playing music via lua scripts
|
||||
Feature #6188: Specular lighting from point light sources
|
||||
Feature #6447: Add LOD support to Object Paging
|
||||
Feature #6491: Add support for Qt6
|
||||
Feature #6556: Lua API for sounds
|
||||
@ -113,12 +154,17 @@
|
||||
Feature #7477: NegativeLight Magic Effect flag
|
||||
Feature #7499: OpenMW-CS: Generate record filters by drag & dropping cell content to the filters field
|
||||
Feature #7546: Start the game on Fredas
|
||||
Feature #7554: Controller binding for tab for menu navigation
|
||||
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 #7625: Add some missing console error outputs
|
||||
Feature #7634: Support NiParticleBomb
|
||||
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 #6624: Drop support for saves made prior to 0.45
|
||||
Task #7113: Move from std::atoi to std::from_char
|
||||
Task #7117: Replace boost::scoped_array with std::vector
|
||||
Task #7151: Do not use std::strerror to get errno error message
|
||||
|
@ -1,22 +1,18 @@
|
||||
#!/bin/sh -ex
|
||||
|
||||
export HOMEBREW_NO_EMOJI=1
|
||||
export HOMEBREW_NO_INSTALL_CLEANUP=1
|
||||
export HOMEBREW_AUTOREMOVE=1
|
||||
|
||||
brew uninstall --ignore-dependencies python@3.8 || true
|
||||
brew uninstall --ignore-dependencies python@3.9 || true
|
||||
brew uninstall --ignore-dependencies qt@6 || true
|
||||
brew uninstall --ignore-dependencies jpeg || true
|
||||
# workaround for gitlab's pre-installed brew
|
||||
# purge large and unnecessary packages that get in our way and have caused issues
|
||||
brew uninstall ruby php openjdk node postgresql maven curl || true
|
||||
|
||||
brew tap --repair
|
||||
brew update --quiet
|
||||
|
||||
# Some of these tools can come from places other than brew, so check before installing
|
||||
brew reinstall xquartz 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
|
||||
brew install curl xquartz gd fontconfig freetype harfbuzz brotli
|
||||
|
||||
command -v ccache >/dev/null 2>&1 || brew install ccache
|
||||
command -v cmake >/dev/null 2>&1 || brew install cmake
|
||||
|
@ -902,8 +902,6 @@ printf "Qt ${QT_VER}... "
|
||||
fi
|
||||
|
||||
cd $QT_SDK
|
||||
add_cmake_opts -DQT_QMAKE_EXECUTABLE="${QT_SDK}/bin/qmake.exe" \
|
||||
-DCMAKE_PREFIX_PATH="$QT_SDK"
|
||||
for CONFIGURATION in ${CONFIGURATIONS[@]}; do
|
||||
if [ $CONFIGURATION == "Debug" ]; then
|
||||
DLLSUFFIX="d"
|
||||
@ -930,7 +928,7 @@ printf "SDL 2.24.0... "
|
||||
rm -rf SDL2-2.24.0
|
||||
eval 7z x -y SDL2-devel-2.24.0-VC.zip $STRIP
|
||||
fi
|
||||
export SDL2DIR="$(real_pwd)/SDL2-2.24.0"
|
||||
SDL2DIR="$(real_pwd)/SDL2-2.24.0"
|
||||
for config in ${CONFIGURATIONS[@]}; do
|
||||
add_runtime_dlls $config "$(pwd)/SDL2-2.24.0/lib/x${ARCHSUFFIX}/SDL2.dll"
|
||||
done
|
||||
@ -1025,6 +1023,8 @@ printf "zlib 1.2.11... "
|
||||
echo Done.
|
||||
}
|
||||
|
||||
add_cmake_opts -DCMAKE_PREFIX_PATH="\"${QT_SDK};${SDL2DIR}\""
|
||||
|
||||
echo
|
||||
cd $DEPS_INSTALL/..
|
||||
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_ui_content.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_resourcehelpers.cpp
|
||||
apps/openmw_test_suite/misc/test_stringops.cpp
|
||||
|
@ -86,7 +86,7 @@ declare -rA GROUPED_DEPS=(
|
||||
libswresample3
|
||||
libswscale5
|
||||
libtinyxml2.6.2v5
|
||||
libyaml-cpp0.7
|
||||
libyaml-cpp0.8
|
||||
python3-pip
|
||||
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/staging
|
||||
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
|
||||
PATH=$PATH:~/luarocks/bin
|
||||
|
@ -71,7 +71,8 @@ message(STATUS "Configuring OpenMW...")
|
||||
set(OPENMW_VERSION_MAJOR 0)
|
||||
set(OPENMW_VERSION_MINOR 49)
|
||||
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_TAGHASH "")
|
||||
@ -113,7 +114,6 @@ include(WholeArchive)
|
||||
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(SDL2_STATIC "Link static build of SDL 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)
|
||||
@ -179,6 +179,8 @@ if (MSVC)
|
||||
# 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
|
||||
add_compile_options(/bigobj)
|
||||
|
||||
add_compile_options(/Zc:__cplusplus)
|
||||
endif()
|
||||
|
||||
# Set up common paths
|
||||
@ -480,7 +482,6 @@ set(SOL_CONFIG_DIR ${OpenMW_SOURCE_DIR}/extern/sol_config)
|
||||
include_directories(
|
||||
BEFORE SYSTEM
|
||||
"."
|
||||
${SDL2_INCLUDE_DIR}
|
||||
${Boost_INCLUDE_DIR}
|
||||
${MyGUI_INCLUDE_DIRS}
|
||||
${OPENAL_INCLUDE_DIR}
|
||||
@ -492,7 +493,7 @@ include_directories(
|
||||
${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)
|
||||
add_definitions(-DMYGUI_STATIC)
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <components/esm3/loadland.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <random>
|
||||
|
||||
namespace
|
||||
@ -24,29 +25,25 @@ namespace
|
||||
PreparedNavMeshData mValue;
|
||||
};
|
||||
|
||||
template <typename Random>
|
||||
osg::Vec2i generateVec2i(int max, Random& random)
|
||||
osg::Vec2i generateVec2i(int max, auto& random)
|
||||
{
|
||||
std::uniform_int_distribution<int> distribution(0, max);
|
||||
return osg::Vec2i(distribution(random), distribution(random));
|
||||
}
|
||||
|
||||
template <typename Random>
|
||||
osg::Vec3f generateAgentHalfExtents(float min, float max, Random& random)
|
||||
osg::Vec3f generateAgentHalfExtents(float min, float max, auto& random)
|
||||
{
|
||||
std::uniform_int_distribution<int> distribution(min, max);
|
||||
return osg::Vec3f(distribution(random), distribution(random), distribution(random));
|
||||
}
|
||||
|
||||
template <typename OutputIterator, typename Random>
|
||||
void generateVertices(OutputIterator out, std::size_t number, Random& random)
|
||||
void generateVertices(std::output_iterator<int> auto out, std::size_t number, auto& random)
|
||||
{
|
||||
std::uniform_real_distribution<float> distribution(0.0, 1.0);
|
||||
std::generate_n(out, 3 * (number - number % 3), [&] { return distribution(random); });
|
||||
}
|
||||
|
||||
template <typename OutputIterator, typename Random>
|
||||
void generateIndices(OutputIterator out, int max, std::size_t number, Random& random)
|
||||
void generateIndices(std::output_iterator<int> auto out, int max, std::size_t number, auto& random)
|
||||
{
|
||||
std::uniform_int_distribution<int> distribution(0, max);
|
||||
std::generate_n(out, number - number % 3, [&] { return distribution(random); });
|
||||
@ -70,21 +67,18 @@ namespace
|
||||
return AreaType_null;
|
||||
}
|
||||
|
||||
template <typename Random>
|
||||
AreaType generateAreaType(Random& random)
|
||||
AreaType generateAreaType(auto& random)
|
||||
{
|
||||
std::uniform_int_distribution<int> distribution(0, 4);
|
||||
return toAreaType(distribution(random));
|
||||
}
|
||||
|
||||
template <typename OutputIterator, typename Random>
|
||||
void generateAreaTypes(OutputIterator out, std::size_t triangles, Random& random)
|
||||
void generateAreaTypes(std::output_iterator<AreaType> auto out, std::size_t triangles, auto& random)
|
||||
{
|
||||
std::generate_n(out, triangles, [&] { return generateAreaType(random); });
|
||||
}
|
||||
|
||||
template <typename OutputIterator, typename Random>
|
||||
void generateWater(OutputIterator out, std::size_t count, Random& random)
|
||||
void generateWater(std::output_iterator<CellWater> auto out, std::size_t count, auto& random)
|
||||
{
|
||||
std::uniform_real_distribution<float> distribution(0.0, 1.0);
|
||||
std::generate_n(out, count, [&] {
|
||||
@ -92,8 +86,7 @@ namespace
|
||||
});
|
||||
}
|
||||
|
||||
template <class Random>
|
||||
Mesh generateMesh(std::size_t triangles, Random& random)
|
||||
Mesh generateMesh(std::size_t triangles, auto& random)
|
||||
{
|
||||
std::uniform_real_distribution<float> distribution(0.0, 1.0);
|
||||
std::vector<float> vertices;
|
||||
@ -109,8 +102,7 @@ namespace
|
||||
return Mesh(std::move(indices), std::move(vertices), std::move(areaTypes));
|
||||
}
|
||||
|
||||
template <class Random>
|
||||
Heightfield generateHeightfield(Random& random)
|
||||
Heightfield generateHeightfield(auto& random)
|
||||
{
|
||||
std::uniform_real_distribution<float> distribution(0.0, 1.0);
|
||||
Heightfield result;
|
||||
@ -127,8 +119,7 @@ namespace
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class Random>
|
||||
FlatHeightfield generateFlatHeightfield(Random& random)
|
||||
FlatHeightfield generateFlatHeightfield(auto& random)
|
||||
{
|
||||
std::uniform_real_distribution<float> distribution(0.0, 1.0);
|
||||
FlatHeightfield result;
|
||||
@ -138,8 +129,7 @@ namespace
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class Random>
|
||||
Key generateKey(std::size_t triangles, Random& random)
|
||||
Key generateKey(std::size_t triangles, auto& random)
|
||||
{
|
||||
const CollisionShapeType agentShapeType = CollisionShapeType::Aabb;
|
||||
const osg::Vec3f agentHalfExtents = generateAgentHalfExtents(0.5, 1.5, random);
|
||||
@ -158,14 +148,12 @@ namespace
|
||||
|
||||
constexpr std::size_t trianglesPerTile = 239;
|
||||
|
||||
template <typename OutputIterator, typename Random>
|
||||
void generateKeys(OutputIterator out, std::size_t count, Random& random)
|
||||
void generateKeys(std::output_iterator<Key> auto out, std::size_t count, auto& random)
|
||||
{
|
||||
std::generate_n(out, count, [&] { return generateKey(trianglesPerTile, random); });
|
||||
}
|
||||
|
||||
template <typename OutputIterator, typename Random>
|
||||
void fillCache(OutputIterator out, Random& random, NavMeshTilesCache& cache)
|
||||
void fillCache(std::output_iterator<Key> auto out, auto& random, NavMeshTilesCache& cache)
|
||||
{
|
||||
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
|
||||
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);
|
||||
break;
|
||||
|
@ -145,12 +145,12 @@ namespace
|
||||
|
||||
config.filterOutNonExistingPaths(dataDirs);
|
||||
|
||||
const auto resDir = variables["resources"].as<Files::MaybeQuotedPath>();
|
||||
const auto& resDir = variables["resources"].as<Files::MaybeQuotedPath>();
|
||||
Log(Debug::Info) << Version::getOpenmwVersionDescription();
|
||||
dataDirs.insert(dataDirs.begin(), resDir / "vfs");
|
||||
const auto fileCollections = Files::Collections(dataDirs);
|
||||
const auto archives = variables["fallback-archive"].as<StringsVector>();
|
||||
const auto contentFiles = variables["content"].as<StringsVector>();
|
||||
const Files::Collections fileCollections(dataDirs);
|
||||
const auto& archives = variables["fallback-archive"].as<StringsVector>();
|
||||
const auto& contentFiles = variables["content"].as<StringsVector>();
|
||||
|
||||
Fallback::Map::init(variables["fallback"].as<Fallback::FallbackMap>().mMap);
|
||||
|
||||
|
@ -156,7 +156,7 @@ Allowed options)");
|
||||
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
|
||||
// MSVC 14.26 due to implementation bugs.
|
||||
if (inputFiles.size() > 1)
|
||||
@ -265,7 +265,7 @@ namespace
|
||||
std::cout << " Faction rank: " << ref.mFactionRank << '\n';
|
||||
std::cout << " Enchantment charge: " << ref.mEnchantmentCharge << '\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 << " Deleted: " << deleted << '\n';
|
||||
if (!ref.mKey.empty())
|
||||
@ -341,7 +341,7 @@ namespace
|
||||
{
|
||||
std::cout << "Author: " << esm.getAuthor() << '\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();
|
||||
if (!masterData.empty())
|
||||
{
|
||||
@ -508,7 +508,7 @@ namespace
|
||||
ToUTF8::Utf8Encoder encoder(ToUTF8::calculateEncoding(info.encoding));
|
||||
esm.setEncoder(&encoder);
|
||||
esm.setHeader(data.mHeader);
|
||||
esm.setVersion(ESM::VER_13);
|
||||
esm.setVersion(ESM::VER_130);
|
||||
esm.setRecordCount(recordCount);
|
||||
|
||||
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 << " Attributes:" << std::endl;
|
||||
std::cout << " Strength: " << (int)mData.mNpdt.mStrength << std::endl;
|
||||
std::cout << " Intelligence: " << (int)mData.mNpdt.mIntelligence << 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;
|
||||
for (size_t i = 0; i != mData.mNpdt.mAttributes.size(); i++)
|
||||
std::cout << " " << attributeLabel(i) << ": " << int(mData.mNpdt.mAttributes[i]) << std::endl;
|
||||
|
||||
std::cout << " Skills:" << std::endl;
|
||||
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 << " 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;
|
||||
|
||||
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;
|
||||
ESM::RefId id = ESM::Attribute::indexToRefId(j);
|
||||
std::cout << " " << id << ": " << mData.mData.getAttribute(id, true) << 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)
|
||||
// Not all races have 7 skills.
|
||||
@ -1204,7 +1202,8 @@ namespace EsmTool
|
||||
std::array<std::string_view, 10> weathers
|
||||
= { "Clear", "Cloudy", "Fog", "Overcast", "Rain", "Thunder", "Ash", "Blight", "Snow", "Blizzard" };
|
||||
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;
|
||||
if (!mData.mSleepList.empty())
|
||||
std::cout << " Sleep List: " << mData.mSleepList << std::endl;
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "converter.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <osgDB/WriteFile>
|
||||
@ -33,7 +34,7 @@ namespace
|
||||
objstate.mPosition = cellref.mPos;
|
||||
objstate.mRef.mRefNum = cellref.mRefNum;
|
||||
if (cellref.mDeleted)
|
||||
objstate.mCount = 0;
|
||||
objstate.mRef.mCount = 0;
|
||||
convertSCRI(cellref.mActorData.mSCRI, objstate.mLocals);
|
||||
objstate.mHasLocals = !objstate.mLocals.mVariables.empty();
|
||||
|
||||
@ -90,14 +91,14 @@ namespace ESSImport
|
||||
|
||||
struct MAPH
|
||||
{
|
||||
unsigned int size;
|
||||
unsigned int value;
|
||||
uint32_t size;
|
||||
uint32_t value;
|
||||
};
|
||||
|
||||
void ConvertFMAP::read(ESM::ESMReader& esm)
|
||||
{
|
||||
MAPH maph;
|
||||
esm.getHNTSized<8>(maph, "MAPH");
|
||||
esm.getHNT("MAPH", maph.size, maph.value);
|
||||
std::vector<char> data;
|
||||
esm.getSubNameIs("MAPD");
|
||||
esm.getSubHeader();
|
||||
@ -278,7 +279,7 @@ namespace ESSImport
|
||||
while (esm.isNextSub("MPCD"))
|
||||
{
|
||||
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.
|
||||
// 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)
|
||||
{
|
||||
int index = 0;
|
||||
uint32_t index = 0;
|
||||
for (const auto& item : inventory.mItems)
|
||||
{
|
||||
ESM::ObjectState objstate;
|
||||
objstate.blank();
|
||||
objstate.mRef = item;
|
||||
objstate.mRef.mRefID = ESM::RefId::stringRefId(item.mId);
|
||||
objstate.mCount = std::abs(item.mCount); // restocking items have negative count in the savefile
|
||||
// openmw handles them differently, so no need to set any flags
|
||||
objstate.mRef.mCount = item.mCount;
|
||||
state.mItems.push_back(objstate);
|
||||
if (item.mRelativeEquipmentSlot != -1)
|
||||
// Note we should really write the absolute slot here, which we do not know about
|
||||
|
@ -1,6 +1,7 @@
|
||||
#ifndef OPENMW_ESSIMPORT_ACDT_H
|
||||
#define OPENMW_ESSIMPORT_ACDT_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#include "importscri.hpp"
|
||||
@ -25,14 +26,12 @@ namespace ESSImport
|
||||
};
|
||||
|
||||
/// Actor data, shared by (at least) REFR and CellRef
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
struct ACDT
|
||||
{
|
||||
// Note, not stored at *all*:
|
||||
// - Level changes are lost on reload, except for the player (there it's in the NPC record).
|
||||
unsigned char mUnknown[12];
|
||||
unsigned int mFlags;
|
||||
uint32_t mFlags;
|
||||
float mBreathMeter; // Seconds left before drowning
|
||||
unsigned char mUnknown2[20];
|
||||
float mDynamic[3][2];
|
||||
@ -41,7 +40,7 @@ namespace ESSImport
|
||||
float mMagicEffects[27]; // Effect attributes:
|
||||
// https://wiki.openmw.org/index.php?title=Research:Magic#Effect_attributes
|
||||
unsigned char mUnknown4[4];
|
||||
unsigned int mGoldPool;
|
||||
uint32_t mGoldPool;
|
||||
unsigned char mCountDown; // seen the same value as in ACSC.mCorpseClearCountdown, maybe
|
||||
// this one is for respawning?
|
||||
unsigned char mUnknown5[3];
|
||||
@ -60,7 +59,6 @@ namespace ESSImport
|
||||
unsigned char mUnknown[3];
|
||||
float mTime;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
struct ActorData
|
||||
{
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "importcellref.hpp"
|
||||
|
||||
#include <components/esm3/esmreader.hpp>
|
||||
#include <cstdint>
|
||||
|
||||
namespace ESSImport
|
||||
{
|
||||
@ -44,19 +45,14 @@ namespace ESSImport
|
||||
bool isDeleted = false;
|
||||
ESM::CellRef::loadData(esm, isDeleted);
|
||||
|
||||
mActorData.mHasACDT = false;
|
||||
if (esm.isNextSub("ACDT"))
|
||||
{
|
||||
mActorData.mHasACDT = true;
|
||||
esm.getHTSized<264>(mActorData.mACDT);
|
||||
}
|
||||
mActorData.mHasACDT
|
||||
= esm.getHNOT("ACDT", mActorData.mACDT.mUnknown, mActorData.mACDT.mFlags, mActorData.mACDT.mBreathMeter,
|
||||
mActorData.mACDT.mUnknown2, mActorData.mACDT.mDynamic, mActorData.mACDT.mUnknown3,
|
||||
mActorData.mACDT.mAttributes, mActorData.mACDT.mMagicEffects, mActorData.mACDT.mUnknown4,
|
||||
mActorData.mACDT.mGoldPool, mActorData.mACDT.mCountDown, mActorData.mACDT.mUnknown5);
|
||||
|
||||
mActorData.mHasACSC = false;
|
||||
if (esm.isNextSub("ACSC"))
|
||||
{
|
||||
mActorData.mHasACSC = true;
|
||||
esm.getHTSized<112>(mActorData.mACSC);
|
||||
}
|
||||
mActorData.mHasACSC = esm.getHNOT("ACSC", mActorData.mACSC.mUnknown1, mActorData.mACSC.mFlags,
|
||||
mActorData.mACSC.mUnknown2, mActorData.mACSC.mCorpseClearCountdown, mActorData.mACSC.mUnknown3);
|
||||
|
||||
if (esm.isNextSub("ACSL"))
|
||||
esm.skipHSubSize(112);
|
||||
@ -122,23 +118,17 @@ namespace ESSImport
|
||||
}
|
||||
|
||||
// FIXME: not all actors have this, add flag
|
||||
if (esm.isNextSub("CHRD")) // npc only
|
||||
esm.getHExact(mActorData.mSkills, 27 * 2 * sizeof(int));
|
||||
esm.getHNOT("CHRD", mActorData.mSkills); // npc only
|
||||
|
||||
if (esm.isNextSub("CRED")) // creature only
|
||||
esm.getHExact(mActorData.mCombatStats, 3 * 2 * sizeof(int));
|
||||
esm.getHNOT("CRED", mActorData.mCombatStats); // creature only
|
||||
|
||||
mActorData.mSCRI.load(esm);
|
||||
|
||||
if (esm.isNextSub("ND3D"))
|
||||
esm.skipHSub();
|
||||
|
||||
mActorData.mHasANIS = false;
|
||||
if (esm.isNextSub("ANIS"))
|
||||
{
|
||||
mActorData.mHasANIS = true;
|
||||
esm.getHTSized<8>(mActorData.mANIS);
|
||||
}
|
||||
mActorData.mHasANIS
|
||||
= esm.getHNOT("ANIS", mActorData.mANIS.mGroupIndex, mActorData.mANIS.mUnknown, mActorData.mANIS.mTime);
|
||||
|
||||
if (esm.isNextSub("LVCR"))
|
||||
{
|
||||
@ -155,13 +145,13 @@ namespace ESSImport
|
||||
// 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
|
||||
// alarmvoi0000.ess
|
||||
esm.getHNOTSized<24>(mPos, "DATA");
|
||||
esm.getHNOTSized<24>(mPos, "DATA");
|
||||
for (int i = 0; i < 2; ++i)
|
||||
esm.getHNOT("DATA", mPos.pos, mPos.rot);
|
||||
|
||||
mDeleted = 0;
|
||||
if (esm.isNextSub("DELE"))
|
||||
{
|
||||
unsigned int deleted;
|
||||
uint32_t deleted;
|
||||
esm.getHT(deleted);
|
||||
mDeleted = ((deleted >> 24) & 0x2) != 0; // the other 3 bytes seem to be uninitialized garbage
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "importcntc.hpp"
|
||||
|
||||
#include <components/esm3/esmreader.hpp>
|
||||
#include <cstdint>
|
||||
|
||||
namespace ESSImport
|
||||
{
|
||||
|
@ -14,7 +14,7 @@ namespace ESSImport
|
||||
/// Changed container contents
|
||||
struct CNTC
|
||||
{
|
||||
int mIndex;
|
||||
int32_t mIndex;
|
||||
|
||||
Inventory mInventory;
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include "importinventory.hpp"
|
||||
#include <components/esm3/aipackage.hpp>
|
||||
#include <cstdint>
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
@ -15,7 +16,7 @@ namespace ESSImport
|
||||
/// Creature changes
|
||||
struct CREC
|
||||
{
|
||||
int mIndex;
|
||||
int32_t mIndex;
|
||||
|
||||
Inventory mInventory;
|
||||
ESM::AIPackageList mAiPackages;
|
||||
|
@ -8,11 +8,11 @@ namespace ESSImport
|
||||
void DIAL::load(ESM::ESMReader& esm)
|
||||
{
|
||||
// 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");
|
||||
|
||||
// Deleted dialogue in a savefile. No clue what this means...
|
||||
int deleted = 0;
|
||||
int32_t deleted = 0;
|
||||
esm.getHNOT(deleted, "DELE");
|
||||
|
||||
mIndex = 0;
|
||||
|
@ -1,5 +1,8 @@
|
||||
#ifndef OPENMW_ESSIMPORT_IMPORTDIAL_H
|
||||
#define OPENMW_ESSIMPORT_IMPORTDIAL_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
class ESMReader;
|
||||
@ -10,7 +13,7 @@ namespace ESSImport
|
||||
|
||||
struct DIAL
|
||||
{
|
||||
int mIndex; // Journal index
|
||||
int32_t mIndex; // Journal index
|
||||
|
||||
void load(ESM::ESMReader& esm);
|
||||
};
|
||||
|
@ -9,17 +9,17 @@ namespace ESSImport
|
||||
{
|
||||
esm.getSubNameIs("GMDT");
|
||||
esm.getSubHeader();
|
||||
if (esm.getSubSize() == 92)
|
||||
{
|
||||
esm.getExact(&mGMDT, 92);
|
||||
mGMDT.mSecundaPhase = 0;
|
||||
}
|
||||
else if (esm.getSubSize() == 96)
|
||||
{
|
||||
esm.getTSized<96>(mGMDT);
|
||||
}
|
||||
else
|
||||
esm.fail("unexpected subrecord size for GAME.GMDT");
|
||||
bool hasSecundaPhase = esm.getSubSize() == 96;
|
||||
esm.getT(mGMDT.mCellName);
|
||||
esm.getT(mGMDT.mFogColour);
|
||||
esm.getT(mGMDT.mFogDensity);
|
||||
esm.getT(mGMDT.mCurrentWeather);
|
||||
esm.getT(mGMDT.mNextWeather);
|
||||
esm.getT(mGMDT.mWeatherTransition);
|
||||
esm.getT(mGMDT.mTimeOfNextTransition);
|
||||
esm.getT(mGMDT.mMasserPhase);
|
||||
if (hasSecundaPhase)
|
||||
esm.getT(mGMDT.mSecundaPhase);
|
||||
|
||||
mGMDT.mWeatherTransition &= (0x000000ff);
|
||||
mGMDT.mSecundaPhase &= (0x000000ff);
|
||||
|
@ -1,6 +1,8 @@
|
||||
#ifndef OPENMW_ESSIMPORT_GAME_H
|
||||
#define OPENMW_ESSIMPORT_GAME_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
class ESMReader;
|
||||
@ -15,12 +17,12 @@ namespace ESSImport
|
||||
struct GMDT
|
||||
{
|
||||
char mCellName[64]{};
|
||||
int mFogColour{ 0 };
|
||||
int32_t mFogColour{ 0 };
|
||||
float mFogDensity{ 0.f };
|
||||
int mCurrentWeather{ 0 }, mNextWeather{ 0 };
|
||||
int mWeatherTransition{ 0 }; // 0-100 transition between weathers, top 3 bytes may be garbage
|
||||
int32_t mCurrentWeather{ 0 }, mNextWeather{ 0 };
|
||||
int32_t mWeatherTransition{ 0 }; // 0-100 transition between weathers, top 3 bytes may be garbage
|
||||
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;
|
||||
|
@ -12,7 +12,7 @@ namespace ESSImport
|
||||
while (esm.isNextSub("NPCO"))
|
||||
{
|
||||
ContItem contItem;
|
||||
esm.getHTSized<36>(contItem);
|
||||
esm.getHT(contItem.mCount, contItem.mItem.mData);
|
||||
|
||||
InventoryItem item;
|
||||
item.mId = contItem.mItem.toString();
|
||||
@ -28,7 +28,7 @@ namespace ESSImport
|
||||
bool newStack = esm.isNextSub("XIDX");
|
||||
if (newStack)
|
||||
{
|
||||
unsigned int idx;
|
||||
uint32_t idx;
|
||||
esm.getHT(idx);
|
||||
separateStacks = true;
|
||||
item.mCount = 1;
|
||||
@ -40,7 +40,7 @@ namespace ESSImport
|
||||
bool isDeleted = false;
|
||||
item.ESM::CellRef::loadData(esm, isDeleted);
|
||||
|
||||
int charge = -1;
|
||||
int32_t charge = -1;
|
||||
esm.getHNOT(charge, "XHLT");
|
||||
item.mChargeInt = charge;
|
||||
|
||||
@ -60,7 +60,7 @@ namespace ESSImport
|
||||
// this is currently not handled properly.
|
||||
|
||||
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);
|
||||
|
||||
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,
|
||||
// i.e. 0 most of the time
|
||||
int slotIndex;
|
||||
int32_t slotIndex;
|
||||
esm.getT(slotIndex);
|
||||
|
||||
mItems[itemIndex].mRelativeEquipmentSlot = slotIndex;
|
||||
|
@ -1,6 +1,7 @@
|
||||
#ifndef OPENMW_ESSIMPORT_IMPORTINVENTORY_H
|
||||
#define OPENMW_ESSIMPORT_IMPORTINVENTORY_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@ -19,7 +20,7 @@ namespace ESSImport
|
||||
|
||||
struct ContItem
|
||||
{
|
||||
int mCount;
|
||||
int32_t mCount;
|
||||
ESM::NAME32 mItem;
|
||||
};
|
||||
|
||||
@ -28,8 +29,8 @@ namespace ESSImport
|
||||
struct InventoryItem : public ESM::CellRef
|
||||
{
|
||||
std::string mId;
|
||||
int mCount;
|
||||
int mRelativeEquipmentSlot;
|
||||
int32_t mCount;
|
||||
int32_t mRelativeEquipmentSlot;
|
||||
SCRI mSCRI;
|
||||
};
|
||||
std::vector<InventoryItem> mItems;
|
||||
|
@ -10,7 +10,7 @@ namespace ESSImport
|
||||
while (esm.isNextSub("KNAM"))
|
||||
{
|
||||
std::string refId = esm.getHString();
|
||||
int count;
|
||||
int32_t count;
|
||||
esm.getHNT(count, "CNAM");
|
||||
mKillCounter[refId] = count;
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#ifndef OPENMW_ESSIMPORT_KLST_H
|
||||
#define OPENMW_ESSIMPORT_KLST_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
@ -18,9 +19,9 @@ namespace ESSImport
|
||||
void load(ESM::ESMReader& esm);
|
||||
|
||||
/// 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)
|
||||
{
|
||||
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")
|
||||
|| esm.isNextSub("AI_A"))
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define OPENMW_ESSIMPORT_NPCC_H
|
||||
|
||||
#include <components/esm3/aipackage.hpp>
|
||||
#include <cstdint>
|
||||
|
||||
#include "importinventory.hpp"
|
||||
|
||||
@ -21,7 +22,7 @@ namespace ESSImport
|
||||
unsigned char unknown;
|
||||
unsigned char mReputation;
|
||||
unsigned char unknown2;
|
||||
int mIndex;
|
||||
int32_t mIndex;
|
||||
} mNPDT;
|
||||
|
||||
Inventory mInventory;
|
||||
|
@ -19,7 +19,12 @@ namespace ESSImport
|
||||
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"))
|
||||
esm.skipHSub();
|
||||
@ -50,12 +55,7 @@ namespace ESSImport
|
||||
if (esm.isNextSub("NAM3"))
|
||||
esm.skipHSub();
|
||||
|
||||
mHasENAM = false;
|
||||
if (esm.isNextSub("ENAM"))
|
||||
{
|
||||
mHasENAM = true;
|
||||
esm.getHTSized<8>(mENAM);
|
||||
}
|
||||
mHasENAM = esm.getHNOT("ENAM", mENAM.mCellX, mENAM.mCellY);
|
||||
|
||||
if (esm.isNextSub("LNAM"))
|
||||
esm.skipHSub();
|
||||
@ -63,16 +63,12 @@ namespace ESSImport
|
||||
while (esm.isNextSub("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);
|
||||
}
|
||||
|
||||
mHasAADT = false;
|
||||
if (esm.isNextSub("AADT")) // Attack animation data?
|
||||
{
|
||||
mHasAADT = true;
|
||||
esm.getHTSized<44>(mAADT);
|
||||
}
|
||||
mHasAADT = esm.getHNOT("AADT", mAADT.animGroupIndex, mAADT.mUnknown5); // Attack animation data?
|
||||
|
||||
if (esm.isNextSub("KNAM"))
|
||||
esm.skipHSub(); // assigned Quick Keys, I think
|
||||
|
@ -1,6 +1,7 @@
|
||||
#ifndef OPENMW_ESSIMPORT_PLAYER_H
|
||||
#define OPENMW_ESSIMPORT_PLAYER_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@ -17,7 +18,7 @@ namespace ESSImport
|
||||
/// Other player data
|
||||
struct PCDT
|
||||
{
|
||||
int mBounty;
|
||||
int32_t mBounty;
|
||||
std::string mBirthsign;
|
||||
|
||||
std::vector<std::string> mKnownDialogueTopics;
|
||||
@ -41,13 +42,11 @@ namespace ESSImport
|
||||
PlayerFlags_LevitationDisabled = 0x80000
|
||||
};
|
||||
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
struct FNAM
|
||||
{
|
||||
unsigned char mRank;
|
||||
unsigned char mUnknown1[3];
|
||||
int mReputation;
|
||||
int32_t mReputation;
|
||||
unsigned char mFlags; // 0x1: unknown, 0x2: expelled
|
||||
unsigned char mUnknown2[3];
|
||||
ESM::NAME32 mFactionName;
|
||||
@ -59,7 +58,7 @@ namespace ESSImport
|
||||
{
|
||||
float mX, mY, mZ; // worldspace position
|
||||
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
|
||||
@ -67,15 +66,15 @@ namespace ESSImport
|
||||
float mData[3][3];
|
||||
};
|
||||
|
||||
int mPlayerFlags; // controls, camera and draw state
|
||||
unsigned int mLevelProgress;
|
||||
int32_t mPlayerFlags; // controls, camera and draw state
|
||||
uint32_t mLevelProgress;
|
||||
float mSkillProgress[27]; // skill progress, non-uniform scaled
|
||||
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
|
||||
int mDetectKeyMagnitude; // seems redundant
|
||||
int mDetectEnchantmentMagnitude; // seems redundant
|
||||
int mDetectAnimalMagnitude; // seems redundant
|
||||
int32_t mDetectKeyMagnitude; // seems redundant
|
||||
int32_t mDetectEnchantmentMagnitude; // seems redundant
|
||||
int32_t mDetectAnimalMagnitude; // seems redundant
|
||||
MarkLocation mMarkLocation;
|
||||
unsigned char mUnknown3[4];
|
||||
Rotation mVerticalRotation;
|
||||
@ -85,16 +84,15 @@ namespace ESSImport
|
||||
|
||||
struct ENAM
|
||||
{
|
||||
int mCellX;
|
||||
int mCellY;
|
||||
int32_t mCellX;
|
||||
int32_t mCellY;
|
||||
};
|
||||
|
||||
struct AADT // 44 bytes
|
||||
{
|
||||
int animGroupIndex; // See convertANIS() for the mapping.
|
||||
int32_t animGroupIndex; // See convertANIS() for the mapping.
|
||||
unsigned char mUnknown5[40];
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
std::vector<FNAM> mFactions;
|
||||
PNAM mPNAM;
|
||||
|
@ -10,7 +10,9 @@ namespace ESSImport
|
||||
while (esm.isNextSub("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);
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include <components/esm/esmcommon.hpp>
|
||||
#include <components/esm/util.hpp>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace ESM
|
||||
@ -16,15 +17,13 @@ namespace ESSImport
|
||||
struct PROJ
|
||||
{
|
||||
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
struct PNAM // 184 bytes
|
||||
{
|
||||
float mAttackStrength;
|
||||
float mSpeed;
|
||||
unsigned char mUnknown[4 * 2];
|
||||
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];
|
||||
ESM::Vector3 mVelocity;
|
||||
ESM::Vector3 mPosition;
|
||||
@ -35,7 +34,6 @@ namespace ESSImport
|
||||
|
||||
bool isMagic() const { return mSplmIndex != 0; }
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
std::vector<PNAM> mProjectiles;
|
||||
|
||||
|
@ -7,7 +7,8 @@ namespace ESSImport
|
||||
|
||||
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);
|
||||
|
||||
|
@ -3,6 +3,8 @@
|
||||
|
||||
#include "importscri.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include <components/esm/esmcommon.hpp>
|
||||
#include <components/esm3/loadscpt.hpp>
|
||||
|
||||
@ -29,7 +31,7 @@ namespace ESSImport
|
||||
SCRI mSCRI;
|
||||
|
||||
bool mRunning;
|
||||
int mRefNum; // Targeted reference, -1: no reference
|
||||
int32_t mRefNum; // Targeted reference, -1: no reference
|
||||
|
||||
void load(ESM::ESMReader& esm);
|
||||
};
|
||||
|
@ -9,7 +9,7 @@ namespace ESSImport
|
||||
{
|
||||
mScript = esm.getHNOString("SCRI");
|
||||
|
||||
int numShorts = 0, numLongs = 0, numFloats = 0;
|
||||
int32_t numShorts = 0, numLongs = 0, numFloats = 0;
|
||||
if (esm.isNextSub("SLCS"))
|
||||
{
|
||||
esm.getSubHeader();
|
||||
@ -23,7 +23,7 @@ namespace ESSImport
|
||||
esm.getSubHeader();
|
||||
for (int i = 0; i < numShorts; ++i)
|
||||
{
|
||||
short val;
|
||||
int16_t val;
|
||||
esm.getT(val);
|
||||
mShorts.push_back(val);
|
||||
}
|
||||
@ -35,7 +35,7 @@ namespace ESSImport
|
||||
esm.getSubHeader();
|
||||
for (int i = 0; i < numLongs; ++i)
|
||||
{
|
||||
int val;
|
||||
int32_t val;
|
||||
esm.getT(val);
|
||||
mLongs.push_back(val);
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include <components/esm3/variant.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace ESM
|
||||
|
@ -11,13 +11,15 @@ namespace ESSImport
|
||||
{
|
||||
ActiveSpell spell;
|
||||
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");
|
||||
|
||||
while (esm.isNextSub("NPDT"))
|
||||
{
|
||||
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:
|
||||
// - INAM for disintegration and bound effects
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define OPENMW_ESSIMPORT_IMPORTSPLM_H
|
||||
|
||||
#include <components/esm/esmcommon.hpp>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace ESM
|
||||
@ -15,11 +16,9 @@ namespace ESSImport
|
||||
struct SPLM
|
||||
{
|
||||
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
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
|
||||
unsigned char mUnknown[4 * 4];
|
||||
ESM::NAME32 mCasterId;
|
||||
@ -31,31 +30,29 @@ namespace ESSImport
|
||||
{
|
||||
ESM::NAME32 mAffectedActorId;
|
||||
unsigned char mUnknown[4 * 2];
|
||||
int mMagnitude;
|
||||
int32_t mMagnitude;
|
||||
float mSecondsActive;
|
||||
unsigned char mUnknown2[4 * 2];
|
||||
};
|
||||
|
||||
struct INAM // 40 bytes
|
||||
{
|
||||
int mUnknown;
|
||||
int32_t mUnknown;
|
||||
unsigned char mUnknown2;
|
||||
ESM::FixedString<35> mItemId; // disintegrated item / bound item / item to re-equip after expiration
|
||||
};
|
||||
|
||||
struct CNAM // 36 bytes
|
||||
{
|
||||
int mUnknown; // seems to always be 0
|
||||
int32_t mUnknown; // seems to always be 0
|
||||
ESM::NAME32 mSummonedOrCommandedActor[32];
|
||||
};
|
||||
|
||||
struct VNAM // 4 bytes
|
||||
{
|
||||
int mUnknown;
|
||||
int32_t mUnknown;
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
struct ActiveEffect
|
||||
{
|
||||
NPDT mNPDT;
|
||||
@ -63,7 +60,7 @@ namespace ESSImport
|
||||
|
||||
struct ActiveSpell
|
||||
{
|
||||
int mIndex;
|
||||
int32_t mIndex;
|
||||
SPDT mSPDT;
|
||||
std::string mTarget;
|
||||
std::vector<ActiveEffect> mActiveEffects;
|
||||
|
@ -42,8 +42,8 @@ Allowed options)");
|
||||
Files::ConfigurationManager cfgManager(true);
|
||||
cfgManager.readConfiguration(variables, desc);
|
||||
|
||||
const auto essFile = variables["mwsave"].as<Files::MaybeQuotedPath>();
|
||||
const auto outputFile = variables["output"].as<Files::MaybeQuotedPath>();
|
||||
const auto& essFile = variables["mwsave"].as<Files::MaybeQuotedPath>();
|
||||
const auto& outputFile = variables["output"].as<Files::MaybeQuotedPath>();
|
||||
std::string encoding = variables["encoding"].as<std::string>();
|
||||
|
||||
ESSImport::Importer importer(essFile, outputFile, encoding);
|
||||
|
@ -35,13 +35,12 @@ set(LAUNCHER_HEADER
|
||||
|
||||
# Headers that must be pre-processed
|
||||
set(LAUNCHER_UI
|
||||
${CMAKE_SOURCE_DIR}/files/ui/datafilespage.ui
|
||||
${CMAKE_SOURCE_DIR}/files/ui/graphicspage.ui
|
||||
${CMAKE_SOURCE_DIR}/files/ui/mainwindow.ui
|
||||
${CMAKE_SOURCE_DIR}/files/ui/contentselector.ui
|
||||
${CMAKE_SOURCE_DIR}/files/ui/importpage.ui
|
||||
${CMAKE_SOURCE_DIR}/files/ui/settingspage.ui
|
||||
${CMAKE_SOURCE_DIR}/files/ui/directorypicker.ui
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ui/datafilespage.ui
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ui/graphicspage.ui
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ui/mainwindow.ui
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ui/importpage.ui
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ui/settingspage.ui
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ui/directorypicker.ui
|
||||
)
|
||||
|
||||
source_group(launcher FILES ${LAUNCHER} ${LAUNCHER_HEADER})
|
||||
@ -77,7 +76,7 @@ if (WIN32)
|
||||
endif (WIN32)
|
||||
|
||||
target_link_libraries(openmw-launcher
|
||||
${SDL2_LIBRARY_ONLY}
|
||||
SDL2::SDL2
|
||||
${OPENAL_LIBRARY}
|
||||
components_qt
|
||||
)
|
||||
|
@ -26,7 +26,7 @@
|
||||
#include <components/files/qtconversion.hpp>
|
||||
#include <components/misc/strings/conversion.hpp>
|
||||
#include <components/navmeshtool/protocol.hpp>
|
||||
#include <components/settings/settings.hpp>
|
||||
#include <components/settings/values.hpp>
|
||||
#include <components/vfs/bsaarchive.hpp>
|
||||
|
||||
#include "utils/profilescombobox.hpp"
|
||||
@ -123,7 +123,7 @@ namespace Launcher
|
||||
|
||||
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)
|
||||
@ -164,11 +164,14 @@ Launcher::DataFilesPage::DataFilesPage(const Files::ConfigurationManager& cfg, C
|
||||
const QString encoding = mGameSettings.value("encoding", "win1252");
|
||||
mSelector->setEncoding(encoding);
|
||||
|
||||
QStringList languages;
|
||||
languages << tr("English") << tr("French") << tr("German") << tr("Italian") << tr("Polish") << tr("Russian")
|
||||
<< tr("Spanish");
|
||||
QVector<std::pair<QString, QString>> languages = { { "English", tr("English") }, { "French", tr("French") },
|
||||
{ "German", tr("German") }, { "Italian", tr("Italian") }, { "Polish", tr("Polish") },
|
||||
{ "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);
|
||||
mCloneProfileDialog = new TextInputDialog(tr("Clone Content List"), tr("Content List name:"), this);
|
||||
@ -254,9 +257,17 @@ bool Launcher::DataFilesPage::loadSettings()
|
||||
if (!currentProfile.isEmpty())
|
||||
addProfile(currentProfile, true);
|
||||
|
||||
const int index = mSelector->languageBox()->findText(mLauncherSettings.getLanguage());
|
||||
if (index != -1)
|
||||
mSelector->languageBox()->setCurrentIndex(index);
|
||||
auto language = mLauncherSettings.getLanguage();
|
||||
|
||||
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;
|
||||
}
|
||||
@ -301,12 +312,14 @@ void Launcher::DataFilesPage::populateFileViews(const QString& contentModelName)
|
||||
auto row = ui.directoryListWidget->count() - 1;
|
||||
auto* item = ui.directoryListWidget->item(row);
|
||||
|
||||
// Display new content with green background
|
||||
// Display new content with custom formatting
|
||||
if (mNewDataDirs.contains(canonicalDirPath))
|
||||
{
|
||||
tooltip += "Will be added to the current profile\n";
|
||||
item->setBackground(Qt::green);
|
||||
item->setForeground(Qt::black);
|
||||
QFont font = item->font();
|
||||
font.setBold(true);
|
||||
font.setItalic(true);
|
||||
item->setFont(font);
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
if (const int value = ui.navMeshMaxSizeSpinBox->value(); value != getMaxNavMeshDbFileSizeMiB())
|
||||
Settings::Manager::setUInt64(
|
||||
"max navmeshdb file size", "Navigator", static_cast<std::uint64_t>(std::max(0, value)) * 1024 * 1024);
|
||||
Settings::navigator().mMaxNavmeshdbFileSize.set(
|
||||
static_cast<std::uint64_t>(std::max(0, ui.navMeshMaxSizeSpinBox->value())) * 1024 * 1024);
|
||||
|
||||
QString profileName = profile;
|
||||
|
||||
@ -385,7 +397,7 @@ void Launcher::DataFilesPage::saveSettings(const QString& profile)
|
||||
mLauncherSettings.setContentList(profileName, dirList, selectedArchivePaths(), fileNames);
|
||||
mGameSettings.setContentList(dirList, selectedArchivePaths(), fileNames);
|
||||
|
||||
QString language(mSelector->languageBox()->currentText());
|
||||
QString language(mSelector->languageBox()->currentData().toString());
|
||||
|
||||
mLauncherSettings.setLanguage(language);
|
||||
|
||||
@ -738,8 +750,11 @@ void Launcher::DataFilesPage::addArchive(const QString& name, Qt::CheckState sel
|
||||
ui.archiveListWidget->item(row)->setCheckState(selected);
|
||||
if (mKnownArchives.filter(name).isEmpty()) // XXX why contains doesn't work here ???
|
||||
{
|
||||
ui.archiveListWidget->item(row)->setBackground(Qt::green);
|
||||
ui.archiveListWidget->item(row)->setForeground(Qt::black);
|
||||
auto item = ui.archiveListWidget->item(row);
|
||||
QFont font = item->font();
|
||||
font.setBold(true);
|
||||
font.setItalic(true);
|
||||
item->setFont(font);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include "sdlinit.hpp"
|
||||
|
||||
#include <components/misc/display.hpp>
|
||||
#include <components/settings/values.hpp>
|
||||
|
||||
#include <QMessageBox>
|
||||
@ -16,22 +17,6 @@
|
||||
#include <SDL_video.h>
|
||||
|
||||
#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)
|
||||
: QWidget(parent)
|
||||
@ -96,32 +81,29 @@ bool Launcher::GraphicsPage::loadSettings()
|
||||
|
||||
// Visuals
|
||||
|
||||
int vsync = Settings::Manager::getInt("vsync mode", "Video");
|
||||
if (vsync < 0 || vsync > 2)
|
||||
vsync = 0;
|
||||
const int vsync = Settings::video().mVsyncMode;
|
||||
|
||||
vSyncComboBox->setCurrentIndex(vsync);
|
||||
|
||||
size_t windowMode = static_cast<size_t>(Settings::Manager::getInt("window mode", "Video"));
|
||||
if (windowMode > static_cast<size_t>(Settings::WindowMode::Windowed))
|
||||
windowMode = 0;
|
||||
windowModeComboBox->setCurrentIndex(windowMode);
|
||||
slotFullScreenChanged(windowMode);
|
||||
const Settings::WindowMode windowMode = Settings::video().mWindowMode;
|
||||
|
||||
if (Settings::Manager::getBool("window border", "Video"))
|
||||
windowModeComboBox->setCurrentIndex(static_cast<int>(windowMode));
|
||||
handleWindowModeChange(windowMode);
|
||||
|
||||
if (Settings::video().mWindowBorder)
|
||||
windowBorderCheckBox->setCheckState(Qt::Checked);
|
||||
|
||||
// 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.
|
||||
int aaIndex = antiAliasingComboBox->findText(QString::number(aaValue));
|
||||
const int aaIndex = antiAliasingComboBox->findText(QString::number(aaValue));
|
||||
if (aaIndex != -1)
|
||||
antiAliasingComboBox->setCurrentIndex(aaIndex);
|
||||
|
||||
int width = Settings::Manager::getInt("resolution x", "Video");
|
||||
int height = Settings::Manager::getInt("resolution y", "Video");
|
||||
QString resolution = QString::number(width) + QString(" x ") + QString::number(height);
|
||||
screenComboBox->setCurrentIndex(Settings::Manager::getInt("screen", "Video"));
|
||||
const int width = Settings::video().mResolutionX;
|
||||
const int height = Settings::video().mResolutionY;
|
||||
QString resolution = QString::number(width) + QString(" × ") + QString::number(height);
|
||||
screenComboBox->setCurrentIndex(Settings::video().mScreen);
|
||||
|
||||
int resIndex = resolutionComboBox->findText(resolution, Qt::MatchStartsWith);
|
||||
|
||||
@ -137,7 +119,7 @@ bool Launcher::GraphicsPage::loadSettings()
|
||||
customHeightSpinBox->setValue(height);
|
||||
}
|
||||
|
||||
float fpsLimit = Settings::Manager::getFloat("framerate limit", "Video");
|
||||
const float fpsLimit = Settings::video().mFramerateLimit;
|
||||
if (fpsLimit != 0)
|
||||
{
|
||||
framerateLimitCheckBox->setCheckState(Qt::Checked);
|
||||
@ -161,32 +143,37 @@ bool Launcher::GraphicsPage::loadSettings()
|
||||
lightingMethodComboBox->setCurrentIndex(lightingMethod);
|
||||
|
||||
// Shadows
|
||||
if (Settings::Manager::getBool("actor shadows", "Shadows"))
|
||||
if (Settings::shadows().mActorShadows)
|
||||
actorShadowsCheckBox->setCheckState(Qt::Checked);
|
||||
if (Settings::Manager::getBool("player shadows", "Shadows"))
|
||||
if (Settings::shadows().mPlayerShadows)
|
||||
playerShadowsCheckBox->setCheckState(Qt::Checked);
|
||||
if (Settings::Manager::getBool("terrain shadows", "Shadows"))
|
||||
if (Settings::shadows().mTerrainShadows)
|
||||
terrainShadowsCheckBox->setCheckState(Qt::Checked);
|
||||
if (Settings::Manager::getBool("object shadows", "Shadows"))
|
||||
if (Settings::shadows().mObjectShadows)
|
||||
objectShadowsCheckBox->setCheckState(Qt::Checked);
|
||||
if (Settings::Manager::getBool("enable indoor shadows", "Shadows"))
|
||||
if (Settings::shadows().mEnableIndoorShadows)
|
||||
indoorShadowsCheckBox->setCheckState(Qt::Checked);
|
||||
|
||||
shadowComputeSceneBoundsComboBox->setCurrentIndex(shadowComputeSceneBoundsComboBox->findText(
|
||||
QString(tr(Settings::Manager::getString("compute scene bounds", "Shadows").c_str()))));
|
||||
auto boundMethod = Settings::shadows().mComputeSceneBounds.get();
|
||||
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)
|
||||
{
|
||||
shadowDistanceCheckBox->setCheckState(Qt::Checked);
|
||||
shadowDistanceSpinBox->setValue(shadowDistLimit);
|
||||
}
|
||||
|
||||
float shadowFadeStart = Settings::Manager::getFloat("shadow fade start", "Shadows");
|
||||
const float shadowFadeStart = Settings::shadows().mShadowFadeStart;
|
||||
if (shadowFadeStart != 0)
|
||||
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));
|
||||
if (shadowResIndex != -1)
|
||||
shadowResolutionComboBox->setCurrentIndex(shadowResIndex);
|
||||
@ -198,29 +185,16 @@ void Launcher::GraphicsPage::saveSettings()
|
||||
{
|
||||
// Visuals
|
||||
|
||||
// Ensure we only set the new settings if they changed. This is to avoid cluttering the
|
||||
// user settings file (which by definition should only contain settings the user has touched)
|
||||
int cVSync = vSyncComboBox->currentIndex();
|
||||
if (cVSync != Settings::Manager::getInt("vsync mode", "Video"))
|
||||
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);
|
||||
Settings::video().mVsyncMode.set(static_cast<SDLUtil::VSyncMode>(vSyncComboBox->currentIndex()));
|
||||
Settings::video().mWindowMode.set(static_cast<Settings::WindowMode>(windowModeComboBox->currentIndex()));
|
||||
Settings::video().mWindowBorder.set(windowBorderCheckBox->checkState() == Qt::Checked);
|
||||
Settings::video().mAntialiasing.set(antiAliasingComboBox->currentText().toInt());
|
||||
|
||||
int cWidth = 0;
|
||||
int cHeight = 0;
|
||||
if (standardRadioButton->isChecked())
|
||||
{
|
||||
QRegularExpression resolutionRe("^(\\d+) x (\\d+)");
|
||||
QRegularExpression resolutionRe("^(\\d+) × (\\d+)");
|
||||
QRegularExpressionMatch match = resolutionRe.match(resolutionComboBox->currentText().simplified());
|
||||
if (match.hasMatch())
|
||||
{
|
||||
@ -234,25 +208,17 @@ void Launcher::GraphicsPage::saveSettings()
|
||||
cHeight = customHeightSpinBox->value();
|
||||
}
|
||||
|
||||
if (cWidth != Settings::Manager::getInt("resolution x", "Video"))
|
||||
Settings::Manager::setInt("resolution x", "Video", cWidth);
|
||||
|
||||
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);
|
||||
Settings::video().mResolutionX.set(cWidth);
|
||||
Settings::video().mResolutionY.set(cHeight);
|
||||
Settings::video().mScreen.set(screenComboBox->currentIndex());
|
||||
|
||||
if (framerateLimitCheckBox->checkState() != Qt::Unchecked)
|
||||
{
|
||||
float cFpsLimit = framerateLimitSpinBox->value();
|
||||
if (cFpsLimit != Settings::Manager::getFloat("framerate limit", "Video"))
|
||||
Settings::Manager::setFloat("framerate limit", "Video", cFpsLimit);
|
||||
Settings::video().mFramerateLimit.set(framerateLimitSpinBox->value());
|
||||
}
|
||||
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
|
||||
@ -264,55 +230,43 @@ void Launcher::GraphicsPage::saveSettings()
|
||||
Settings::shaders().mLightingMethod.set(lightingMethodMap[lightingMethodComboBox->currentIndex()]);
|
||||
|
||||
// Shadows
|
||||
int cShadowDist = shadowDistanceCheckBox->checkState() != Qt::Unchecked ? shadowDistanceSpinBox->value() : 0;
|
||||
if (Settings::Manager::getInt("maximum shadow map distance", "Shadows") != cShadowDist)
|
||||
Settings::Manager::setInt("maximum shadow map distance", "Shadows", cShadowDist);
|
||||
float cFadeStart = fadeStartSpinBox->value();
|
||||
if (cShadowDist > 0 && Settings::Manager::getFloat("shadow fade start", "Shadows") != cFadeStart)
|
||||
Settings::Manager::setFloat("shadow fade start", "Shadows", cFadeStart);
|
||||
const int cShadowDist = shadowDistanceCheckBox->checkState() != Qt::Unchecked ? shadowDistanceSpinBox->value() : 0;
|
||||
Settings::shadows().mMaximumShadowMapDistance.set(cShadowDist);
|
||||
const float cFadeStart = fadeStartSpinBox->value();
|
||||
if (cShadowDist > 0)
|
||||
Settings::shadows().mShadowFadeStart.set(cFadeStart);
|
||||
|
||||
bool cActorShadows = actorShadowsCheckBox->checkState();
|
||||
bool cObjectShadows = objectShadowsCheckBox->checkState();
|
||||
bool cTerrainShadows = terrainShadowsCheckBox->checkState();
|
||||
bool cPlayerShadows = playerShadowsCheckBox->checkState();
|
||||
const bool cActorShadows = actorShadowsCheckBox->checkState() != Qt::Unchecked;
|
||||
const bool cObjectShadows = objectShadowsCheckBox->checkState() != Qt::Unchecked;
|
||||
const bool cTerrainShadows = terrainShadowsCheckBox->checkState() != Qt::Unchecked;
|
||||
const bool cPlayerShadows = playerShadowsCheckBox->checkState() != Qt::Unchecked;
|
||||
if (cActorShadows || cObjectShadows || cTerrainShadows || cPlayerShadows)
|
||||
{
|
||||
if (!Settings::Manager::getBool("enable shadows", "Shadows"))
|
||||
Settings::Manager::setBool("enable shadows", "Shadows", true);
|
||||
if (Settings::Manager::getBool("actor shadows", "Shadows") != cActorShadows)
|
||||
Settings::Manager::setBool("actor shadows", "Shadows", cActorShadows);
|
||||
if (Settings::Manager::getBool("player shadows", "Shadows") != cPlayerShadows)
|
||||
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);
|
||||
Settings::shadows().mEnableShadows.set(true);
|
||||
Settings::shadows().mActorShadows.set(cActorShadows);
|
||||
Settings::shadows().mPlayerShadows.set(cPlayerShadows);
|
||||
Settings::shadows().mObjectShadows.set(cObjectShadows);
|
||||
Settings::shadows().mTerrainShadows.set(cTerrainShadows);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Settings::Manager::getBool("enable shadows", "Shadows"))
|
||||
Settings::Manager::setBool("enable shadows", "Shadows", false);
|
||||
if (Settings::Manager::getBool("actor shadows", "Shadows"))
|
||||
Settings::Manager::setBool("actor shadows", "Shadows", false);
|
||||
if (Settings::Manager::getBool("player shadows", "Shadows"))
|
||||
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);
|
||||
Settings::shadows().mEnableShadows.set(false);
|
||||
Settings::shadows().mActorShadows.set(false);
|
||||
Settings::shadows().mPlayerShadows.set(false);
|
||||
Settings::shadows().mObjectShadows.set(false);
|
||||
Settings::shadows().mTerrainShadows.set(false);
|
||||
}
|
||||
|
||||
bool cIndoorShadows = indoorShadowsCheckBox->checkState();
|
||||
if (Settings::Manager::getBool("enable indoor shadows", "Shadows") != cIndoorShadows)
|
||||
Settings::Manager::setBool("enable indoor shadows", "Shadows", cIndoorShadows);
|
||||
Settings::shadows().mEnableIndoorShadows.set(indoorShadowsCheckBox->checkState() != Qt::Unchecked);
|
||||
Settings::shadows().mShadowMapResolution.set(shadowResolutionComboBox->currentText().toInt());
|
||||
|
||||
int cShadowRes = shadowResolutionComboBox->currentText().toInt();
|
||||
if (cShadowRes != Settings::Manager::getInt("shadow map resolution", "Shadows"))
|
||||
Settings::Manager::setInt("shadow map resolution", "Shadows", cShadowRes);
|
||||
|
||||
auto cComputeSceneBounds = shadowComputeSceneBoundsComboBox->currentText().toStdString();
|
||||
if (cComputeSceneBounds != Settings::Manager::getString("compute scene bounds", "Shadows"))
|
||||
Settings::Manager::setString("compute scene bounds", "Shadows", cComputeSceneBounds);
|
||||
auto index = shadowComputeSceneBoundsComboBox->currentIndex();
|
||||
if (index == 0)
|
||||
Settings::shadows().mComputeSceneBounds.set("bounds");
|
||||
else if (index == 1)
|
||||
Settings::shadows().mComputeSceneBounds.set("primitives");
|
||||
else
|
||||
Settings::shadows().mComputeSceneBounds.set("none");
|
||||
}
|
||||
|
||||
QStringList Launcher::GraphicsPage::getAvailableResolutions(int screen)
|
||||
@ -347,19 +301,8 @@ QStringList Launcher::GraphicsPage::getAvailableResolutions(int screen)
|
||||
return result;
|
||||
}
|
||||
|
||||
QString resolution = QString::number(mode.w) + QString(" x ") + QString::number(mode.h);
|
||||
|
||||
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);
|
||||
auto str = Misc::getResolutionText(mode.w, mode.h, "%i × %i (%i:%i)");
|
||||
result.append(QString(str.c_str()));
|
||||
}
|
||||
|
||||
result.removeDuplicates();
|
||||
@ -392,8 +335,12 @@ void Launcher::GraphicsPage::screenChanged(int screen)
|
||||
|
||||
void Launcher::GraphicsPage::slotFullScreenChanged(int mode)
|
||||
{
|
||||
if (mode == static_cast<int>(Settings::WindowMode::Fullscreen)
|
||||
|| mode == static_cast<int>(Settings::WindowMode::WindowedFullscreen))
|
||||
handleWindowModeChange(static_cast<Settings::WindowMode>(mode));
|
||||
}
|
||||
|
||||
void Launcher::GraphicsPage::handleWindowModeChange(Settings::WindowMode mode)
|
||||
{
|
||||
if (mode == Settings::WindowMode::Fullscreen || mode == Settings::WindowMode::WindowedFullscreen)
|
||||
{
|
||||
standardRadioButton->toggle();
|
||||
customRadioButton->setEnabled(false);
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
#include "ui_graphicspage.h"
|
||||
|
||||
#include <components/settings/settings.hpp>
|
||||
#include <components/settings/windowmode.hpp>
|
||||
|
||||
namespace Files
|
||||
{
|
||||
@ -40,6 +40,7 @@ namespace Launcher
|
||||
static QRect getMaximumResolution();
|
||||
|
||||
bool setupSDL();
|
||||
void handleWindowModeChange(Settings::WindowMode state);
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
@ -104,9 +104,9 @@ void Launcher::ImportPage::on_importerButton_clicked()
|
||||
msgBox.setIcon(QMessageBox::Critical);
|
||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||
msgBox.setText(
|
||||
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 \
|
||||
and try again.</p></body></html>")
|
||||
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 "
|
||||
"and try again.</p></body></html>")
|
||||
.arg(file.fileName()));
|
||||
msgBox.exec();
|
||||
return;
|
||||
|
@ -1,13 +1,5 @@
|
||||
#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 <QDir>
|
||||
#include <QMessageBox>
|
||||
@ -15,10 +7,15 @@
|
||||
#include <QTime>
|
||||
|
||||
#include <components/debug/debugging.hpp>
|
||||
#include <components/debug/debuglog.hpp>
|
||||
#include <components/files/configurationmanager.hpp>
|
||||
#include <components/files/conversion.hpp>
|
||||
#include <components/files/qtconfigpath.hpp>
|
||||
#include <components/files/qtconversion.hpp>
|
||||
#include <components/misc/helpviewer.hpp>
|
||||
#include <components/misc/utf8qtextstream.hpp>
|
||||
#include <components/settings/settings.hpp>
|
||||
#include <components/version/version.hpp>
|
||||
|
||||
#include "datafilespage.hpp"
|
||||
#include "graphicspage.hpp"
|
||||
@ -121,13 +118,14 @@ Launcher::FirstRunDialogResult Launcher::MainDialog::showFirstRunDialog()
|
||||
const auto& userConfigDir = mCfgMgr.getUserConfigPath();
|
||||
if (!exists(userConfigDir))
|
||||
{
|
||||
if (!create_directories(userConfigDir))
|
||||
std::error_code ec;
|
||||
if (!create_directories(userConfigDir, ec))
|
||||
{
|
||||
cfgError(tr("Error opening OpenMW configuration file"),
|
||||
tr("<br><b>Could not create directory %0</b><br><br> \
|
||||
Please make sure you have the right permissions \
|
||||
and try again.<br>")
|
||||
.arg(Files::pathToQString(canonical(userConfigDir))));
|
||||
cfgError(tr("Error creating OpenMW configuration directory: code %0").arg(ec.value()),
|
||||
tr("<br><b>Could not create directory %0</b><br><br>"
|
||||
"%1<br>")
|
||||
.arg(Files::pathToQString(userConfigDir))
|
||||
.arg(QString(ec.message().c_str())));
|
||||
return FirstRunDialogResultFailure;
|
||||
}
|
||||
}
|
||||
@ -139,10 +137,10 @@ Launcher::FirstRunDialogResult Launcher::MainDialog::showFirstRunDialog()
|
||||
msgBox.setIcon(QMessageBox::Question);
|
||||
msgBox.setStandardButtons(QMessageBox::NoButton);
|
||||
msgBox.setText(
|
||||
tr("<html><head/><body><p><b>Welcome to OpenMW!</b></p> \
|
||||
<p>It is recommended to run the Installation Wizard.</p> \
|
||||
<p>The Wizard will let you select an existing Morrowind installation, \
|
||||
or install Morrowind for OpenMW to use.</p></body></html>"));
|
||||
tr("<html><head/><body><p><b>Welcome to OpenMW!</b></p>"
|
||||
"<p>It is recommended to run the Installation Wizard.</p>"
|
||||
"<p>The Wizard will let you select an existing Morrowind installation, "
|
||||
"or install Morrowind for OpenMW to use.</p></body></html>"));
|
||||
|
||||
QAbstractButton* wizardButton
|
||||
= 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))
|
||||
{
|
||||
cfgError(tr("Error opening OpenMW configuration file"),
|
||||
tr("<br><b>Could not open %0 for reading:</b><br><br>%1<br><br> \
|
||||
Please make sure you have the right permissions \
|
||||
and try again.<br>")
|
||||
tr("<br><b>Could not open %0 for reading:</b><br><br>%1<br><br>"
|
||||
"Please make sure you have the right permissions "
|
||||
"and try again.<br>")
|
||||
.arg(file.fileName())
|
||||
.arg(file.errorString()));
|
||||
return false;
|
||||
@ -330,9 +328,9 @@ bool Launcher::MainDialog::setupGameSettings()
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
{
|
||||
cfgError(tr("Error opening OpenMW configuration file"),
|
||||
tr("<br><b>Could not open %0 for reading</b><br><br> \
|
||||
Please make sure you have the right permissions \
|
||||
and try again.<br>")
|
||||
tr("<br><b>Could not open %0 for reading</b><br><br>"
|
||||
"Please make sure you have the right permissions "
|
||||
"and try again.<br>")
|
||||
.arg(file.fileName()));
|
||||
return {};
|
||||
}
|
||||
@ -391,8 +389,8 @@ bool Launcher::MainDialog::setupGameData()
|
||||
msgBox.setIcon(QMessageBox::Warning);
|
||||
msgBox.setStandardButtons(QMessageBox::NoButton);
|
||||
msgBox.setText(
|
||||
tr("<br><b>Could not find the Data Files location</b><br><br> \
|
||||
The directory containing the data files was not found."));
|
||||
tr("<br><b>Could not find the Data Files location</b><br><br>"
|
||||
"The directory containing the data files was not found."));
|
||||
|
||||
QAbstractButton* wizardButton = msgBox.addButton(tr("Run &Installation Wizard..."), QMessageBox::ActionRole);
|
||||
QAbstractButton* skipButton = msgBox.addButton(tr("Skip"), QMessageBox::RejectRole);
|
||||
@ -422,8 +420,8 @@ bool Launcher::MainDialog::setupGraphicsSettings()
|
||||
catch (std::exception& e)
|
||||
{
|
||||
cfgError(tr("Error reading OpenMW configuration files"),
|
||||
tr("<br>The problem may be due to an incomplete installation of OpenMW.<br> \
|
||||
Reinstalling OpenMW may resolve the problem.<br>")
|
||||
tr("<br>The problem may be due to an incomplete installation of OpenMW.<br>"
|
||||
"Reinstalling OpenMW may resolve the problem.<br>")
|
||||
+ e.what());
|
||||
return false;
|
||||
}
|
||||
@ -460,13 +458,14 @@ bool Launcher::MainDialog::writeSettings()
|
||||
|
||||
if (!exists(userPath))
|
||||
{
|
||||
if (!create_directories(userPath))
|
||||
std::error_code ec;
|
||||
if (!create_directories(userPath, ec))
|
||||
{
|
||||
cfgError(tr("Error creating OpenMW configuration directory"),
|
||||
tr("<br><b>Could not create %0</b><br><br> \
|
||||
Please make sure you have the right permissions \
|
||||
and try again.<br>")
|
||||
.arg(Files::pathToQString(userPath)));
|
||||
cfgError(tr("Error creating OpenMW configuration directory: code %0").arg(ec.value()),
|
||||
tr("<br><b>Could not create directory %0</b><br><br>"
|
||||
"%1<br>")
|
||||
.arg(Files::pathToQString(userPath))
|
||||
.arg(QString(ec.message().c_str())));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -482,9 +481,9 @@ bool Launcher::MainDialog::writeSettings()
|
||||
{
|
||||
// File cannot be opened or created
|
||||
cfgError(tr("Error writing OpenMW configuration file"),
|
||||
tr("<br><b>Could not open or create %0 for writing</b><br><br> \
|
||||
Please make sure you have the right permissions \
|
||||
and try again.<br>")
|
||||
tr("<br><b>Could not open or create %0 for writing</b><br><br>"
|
||||
"Please make sure you have the right permissions "
|
||||
"and try again.<br>")
|
||||
.arg(file.fileName()));
|
||||
return false;
|
||||
}
|
||||
@ -513,9 +512,9 @@ bool Launcher::MainDialog::writeSettings()
|
||||
{
|
||||
// File cannot be opened or created
|
||||
cfgError(tr("Error writing Launcher configuration file"),
|
||||
tr("<br><b>Could not open or create %0 for writing</b><br><br> \
|
||||
Please make sure you have the right permissions \
|
||||
and try again.<br>")
|
||||
tr("<br><b>Could not open or create %0 for writing</b><br><br>"
|
||||
"Please make sure you have the right permissions "
|
||||
"and try again.<br>")
|
||||
.arg(file.fileName()));
|
||||
return false;
|
||||
}
|
||||
@ -565,8 +564,8 @@ void Launcher::MainDialog::play()
|
||||
msgBox.setIcon(QMessageBox::Warning);
|
||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||
msgBox.setText(
|
||||
tr("<br><b>You do not have a game file selected.</b><br><br> \
|
||||
OpenMW will not start without a game file selected.<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>"));
|
||||
msgBox.exec();
|
||||
return;
|
||||
}
|
||||
|
@ -191,6 +191,7 @@ bool Launcher::SettingsPage::loadSettings()
|
||||
}
|
||||
loadSettingBool(Settings::game().mTurnToMovementDirection, *turnToMovementDirectionCheckBox);
|
||||
loadSettingBool(Settings::game().mSmoothMovement, *smoothMovementCheckBox);
|
||||
loadSettingBool(Settings::game().mPlayerMovementIgnoresAnimation, *playerMovementIgnoresAnimationCheckBox);
|
||||
|
||||
distantLandCheckBox->setCheckState(
|
||||
Settings::terrain().mDistantTerrain && Settings::terrain().mObjectPaging ? Qt::Checked : Qt::Unchecked);
|
||||
@ -338,6 +339,7 @@ void Launcher::SettingsPage::saveSettings()
|
||||
saveSettingBool(*shieldSheathingCheckBox, Settings::game().mShieldSheathing);
|
||||
saveSettingBool(*turnToMovementDirectionCheckBox, Settings::game().mTurnToMovementDirection);
|
||||
saveSettingBool(*smoothMovementCheckBox, Settings::game().mSmoothMovement);
|
||||
saveSettingBool(*playerMovementIgnoresAnimationCheckBox, Settings::game().mPlayerMovementIgnoresAnimation);
|
||||
|
||||
const bool wantDistantLand = distantLandCheckBox->checkState() == Qt::Checked;
|
||||
if (wantDistantLand != (Settings::terrain().mDistantTerrain && Settings::terrain().mObjectPaging))
|
||||
|
@ -6,7 +6,7 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>571</width>
|
||||
<width>573</width>
|
||||
<height>384</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -30,7 +30,7 @@
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="dataNoteLabel">
|
||||
<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>
|
||||
</widget>
|
||||
</item>
|
||||
@ -57,7 +57,7 @@
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<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>
|
||||
</widget>
|
||||
</item>
|
||||
@ -210,7 +210,7 @@
|
||||
<item row="27" column="0" colspan="2">
|
||||
<widget class="QLabel" name="archiveNoteLabel">
|
||||
<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>
|
||||
</widget>
|
||||
</item>
|
@ -22,7 +22,7 @@
|
||||
</attribute>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_4" columnstretch="1,0">
|
||||
<layout class="QGridLayout" name="gridLayout_4" columnstretch="1,1">
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="screenLabel">
|
||||
<property name="text">
|
||||
@ -107,7 +107,7 @@
|
||||
<item>
|
||||
<widget class="QLabel" name="multiplyLabel">
|
||||
<property name="text">
|
||||
<string> x </string>
|
||||
<string> × </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
@ -14,7 +14,7 @@
|
||||
<item>
|
||||
<widget class="QTabWidget" name="AdvancedTabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
<number>1</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="GameMechanics">
|
||||
<attribute name="title">
|
||||
@ -116,10 +116,10 @@
|
||||
<item row="4" column="0">
|
||||
<widget class="QCheckBox" name="enableNavigatorCheckBox">
|
||||
<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 name="text">
|
||||
<string>Build nav mesh for world geometry</string>
|
||||
<string>Use navigation mesh for pathfinding</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -293,8 +293,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>680</width>
|
||||
<height>882</height>
|
||||
<width>671</width>
|
||||
<height>774</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
@ -377,6 +377,16 @@
|
||||
</item>
|
||||
</layout>
|
||||
</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>
|
||||
</widget>
|
||||
</item>
|
@ -164,12 +164,12 @@ namespace NavMeshTool
|
||||
|
||||
config.filterOutNonExistingPaths(dataDirs);
|
||||
|
||||
const auto resDir = variables["resources"].as<Files::MaybeQuotedPath>();
|
||||
const auto& resDir = variables["resources"].as<Files::MaybeQuotedPath>();
|
||||
Log(Debug::Info) << Version::getOpenmwVersionDescription();
|
||||
dataDirs.insert(dataDirs.begin(), resDir / "vfs");
|
||||
const auto fileCollections = Files::Collections(dataDirs);
|
||||
const auto archives = variables["fallback-archive"].as<StringsVector>();
|
||||
const auto contentFiles = variables["content"].as<StringsVector>();
|
||||
const Files::Collections fileCollections(dataDirs);
|
||||
const auto& archives = variables["fallback-archive"].as<StringsVector>();
|
||||
const auto& contentFiles = variables["content"].as<StringsVector>();
|
||||
const std::size_t threadsNumber = variables["threads"].as<std::size_t>();
|
||||
|
||||
if (threadsNumber < 1)
|
||||
|
@ -131,7 +131,7 @@ namespace NavMeshTool
|
||||
osg::ref_ptr<const Resource::BulletShape> shape = [&] {
|
||||
try
|
||||
{
|
||||
return bulletShapeManager.getShape(Misc::ResourceHelpers::correctMeshPath(model, &vfs));
|
||||
return bulletShapeManager.getShape(Misc::ResourceHelpers::correctMeshPath(model));
|
||||
}
|
||||
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))
|
||||
{
|
||||
case Bsa::BSAVER_UNKNOWN:
|
||||
std::cerr << '"' << path << "\" is unknown BSA archive" << std::endl;
|
||||
return nullptr;
|
||||
case Bsa::BSAVER_COMPRESSED:
|
||||
return std::make_unique<VFS::ArchiveSelector<Bsa::BSAVER_COMPRESSED>::type>(path);
|
||||
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);
|
||||
case Bsa::BSAVER_UNCOMPRESSED:
|
||||
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)
|
||||
@ -72,58 +69,86 @@ std::unique_ptr<VFS::Archive> makeArchive(const std::filesystem::path& path)
|
||||
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
|
||||
/// \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;
|
||||
|
||||
VFS::Manager myManager;
|
||||
myManager.addArchive(std::move(anArchive));
|
||||
myManager.buildIndex();
|
||||
if (!quiet)
|
||||
std::cout << "Reading data source '" << Files::pathToUnicodeString(archivePath) << "'" << std::endl;
|
||||
|
||||
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))
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
readNIF(archivePath, name, &vfs, quiet);
|
||||
}
|
||||
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,
|
||||
std::vector<Files::MaybeQuotedPath>& archives)
|
||||
bool parseOptions(int argc, char** argv, Files::PathContainer& files, Files::PathContainer& archives,
|
||||
bool& writeDebugLog, bool& quiet)
|
||||
{
|
||||
bpo::options_description desc(R"(Ensure that OpenMW can use the provided NIF and BSA files
|
||||
|
||||
Usages:
|
||||
niftool <nif files, BSA files, or directories>
|
||||
Scan the file or directories for nif errors.
|
||||
niftest <nif files, BSA files, or directories>
|
||||
Scan the file or directories for NIF errors.
|
||||
|
||||
Allowed options)");
|
||||
auto addOption = desc.add_options();
|
||||
addOption("help,h", "print help message.");
|
||||
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("input-file", bpo::value<Files::MaybeQuotedPathContainer>(), "input file");
|
||||
|
||||
@ -143,17 +168,18 @@ Allowed options)");
|
||||
return false;
|
||||
}
|
||||
writeDebugLog = variables.count("write-debug-log") > 0;
|
||||
quiet = variables.count("quiet") > 0;
|
||||
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())
|
||||
archives = it->second.as<Files::MaybeQuotedPathContainer>();
|
||||
archives = asPathContainer(it->second.as<Files::MaybeQuotedPathContainer>());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@ -164,64 +190,62 @@ Allowed options)");
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
std::vector<Files::MaybeQuotedPath> files;
|
||||
Files::PathContainer files, sources;
|
||||
bool writeDebugLog = false;
|
||||
std::vector<Files::MaybeQuotedPath> archives;
|
||||
if (!parseOptions(argc, argv, files, writeDebugLog, archives))
|
||||
bool quiet = false;
|
||||
if (!parseOptions(argc, argv, files, sources, writeDebugLog, quiet))
|
||||
return 1;
|
||||
|
||||
Nif::Reader::setLoadUnsupportedFiles(true);
|
||||
Nif::Reader::setWriteNifDebugLog(writeDebugLog);
|
||||
|
||||
std::unique_ptr<VFS::Manager> vfs;
|
||||
if (!archives.empty())
|
||||
if (!sources.empty())
|
||||
{
|
||||
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
|
||||
{
|
||||
if (auto archive = makeArchive(path))
|
||||
vfs->addArchive(std::move(archive));
|
||||
else
|
||||
std::cerr << '"' << path << "\" is unsupported archive" << std::endl;
|
||||
vfs->buildIndex();
|
||||
std::cerr << "Error: '" << pathStr << "' is not an archive or directory" << std::endl;
|
||||
}
|
||||
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)
|
||||
{
|
||||
const std::string pathStr = Files::pathToUnicodeString(path);
|
||||
try
|
||||
{
|
||||
if (isNIF(path))
|
||||
{
|
||||
// std::cout << "Decoding: " << name << std::endl;
|
||||
Nif::NIFFile file(path);
|
||||
Nif::Reader reader(file);
|
||||
if (vfs != nullptr)
|
||||
reader.parse(vfs->get(Files::pathToUnicodeString(path)));
|
||||
else
|
||||
reader.parse(Files::openConstrainedFileStream(path));
|
||||
readNIF({}, path, vfs.get(), quiet);
|
||||
}
|
||||
else if (auto archive = makeArchive(path))
|
||||
{
|
||||
readVFS(std::move(archive), path);
|
||||
readVFS(std::move(archive), path, quiet);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "ERROR: \"" << Files::pathToUnicodeString(path)
|
||||
<< "\" is not a nif file, bsa/ba2 file, or directory!" << std::endl;
|
||||
std::cerr << "Error: '" << pathStr << "' is not a NIF file, BSA/BA2 archive, or directory" << std::endl;
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
@ -116,7 +116,7 @@ opencs_units (view/prefs
|
||||
|
||||
opencs_units (model/prefs
|
||||
state setting intsetting doublesetting boolsetting enumsetting coloursetting shortcut
|
||||
shortcuteventhandler shortcutmanager shortcutsetting modifiersetting stringsetting
|
||||
shortcuteventhandler shortcutmanager shortcutsetting modifiersetting stringsetting subcategory
|
||||
)
|
||||
|
||||
opencs_units (model/prefs
|
||||
@ -139,8 +139,7 @@ set (OPENCS_RES ${CMAKE_SOURCE_DIR}/files/opencs/resources.qrc
|
||||
)
|
||||
|
||||
set (OPENCS_UI
|
||||
${CMAKE_SOURCE_DIR}/files/ui/contentselector.ui
|
||||
${CMAKE_SOURCE_DIR}/files/ui/filedialog.ui
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ui/filedialog.ui
|
||||
)
|
||||
|
||||
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.begin(), mResources / "vfs");
|
||||
|
||||
// iterate the data directories and add them to the file dialog for loading
|
||||
mFileDialog.addFiles(dataDirs);
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <components/esm3/loadsoun.hpp>
|
||||
#include <components/esm3/loadspel.hpp>
|
||||
#include <components/esm3/loadsscr.hpp>
|
||||
#include <components/esm3/selectiongroup.hpp>
|
||||
|
||||
#include "../world/data.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>>(
|
||||
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));
|
||||
|
||||
// save content file
|
||||
|
@ -11,9 +11,8 @@
|
||||
#include "state.hpp"
|
||||
|
||||
CSMPrefs::BoolSetting::BoolSetting(
|
||||
Category* parent, QMutex* mutex, const std::string& key, const std::string& label, bool default_)
|
||||
: Setting(parent, mutex, key, label)
|
||||
, mDefault(default_)
|
||||
Category* parent, QMutex* mutex, std::string_view key, const QString& label, Settings::Index& index)
|
||||
: TypedSetting(parent, mutex, key, label, index)
|
||||
, mWidget(nullptr)
|
||||
{
|
||||
}
|
||||
@ -24,10 +23,10 @@ CSMPrefs::BoolSetting& CSMPrefs::BoolSetting::setTooltip(const std::string& tool
|
||||
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->setCheckState(mDefault ? Qt::Checked : Qt::Unchecked);
|
||||
mWidget = new QCheckBox(getLabel(), parent);
|
||||
mWidget->setCheckState(getValue() ? Qt::Checked : Qt::Unchecked);
|
||||
|
||||
if (!mTooltip.empty())
|
||||
{
|
||||
@ -37,24 +36,19 @@ std::pair<QWidget*, QWidget*> CSMPrefs::BoolSetting::makeWidgets(QWidget* parent
|
||||
|
||||
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()
|
||||
{
|
||||
if (mWidget)
|
||||
{
|
||||
mWidget->setCheckState(
|
||||
Settings::Manager::getBool(getKey(), getParent()->getKey()) ? Qt::Checked : Qt::Unchecked);
|
||||
mWidget->setCheckState(getValue() ? Qt::Checked : Qt::Unchecked);
|
||||
}
|
||||
}
|
||||
|
||||
void CSMPrefs::BoolSetting::valueChanged(int value)
|
||||
{
|
||||
{
|
||||
QMutexLocker lock(getMutex());
|
||||
Settings::Manager::setBool(getKey(), getParent()->getKey(), value);
|
||||
}
|
||||
|
||||
setValue(value != Qt::Unchecked);
|
||||
getParent()->getState()->update(*this);
|
||||
}
|
||||
|
@ -12,21 +12,21 @@ namespace CSMPrefs
|
||||
{
|
||||
class Category;
|
||||
|
||||
class BoolSetting : public Setting
|
||||
class BoolSetting final : public TypedSetting<bool>
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
std::string mTooltip;
|
||||
bool mDefault;
|
||||
QCheckBox* mWidget;
|
||||
|
||||
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);
|
||||
|
||||
/// Return label, input widget.
|
||||
std::pair<QWidget*, QWidget*> makeWidgets(QWidget* parent) override;
|
||||
SettingWidgets makeWidgets(QWidget* parent) override;
|
||||
|
||||
void updateWidget() override;
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
#include "setting.hpp"
|
||||
#include "state.hpp"
|
||||
#include "subcategory.hpp"
|
||||
|
||||
CSMPrefs::Category::Category(State* parent, const std::string& key)
|
||||
: mParent(parent)
|
||||
@ -23,6 +24,14 @@ CSMPrefs::State* CSMPrefs::Category::getState() const
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
@ -39,11 +48,12 @@ CSMPrefs::Category::Iterator CSMPrefs::Category::end()
|
||||
|
||||
CSMPrefs::Setting& CSMPrefs::Category::operator[](const std::string& key)
|
||||
{
|
||||
for (Iterator iter = mSettings.begin(); iter != mSettings.end(); ++iter)
|
||||
if ((*iter)->getKey() == key)
|
||||
return **iter;
|
||||
const auto it = mIndex.find(key);
|
||||
|
||||
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()
|
||||
|
@ -3,12 +3,14 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace CSMPrefs
|
||||
{
|
||||
class State;
|
||||
class Setting;
|
||||
class Subcategory;
|
||||
|
||||
class Category
|
||||
{
|
||||
@ -20,6 +22,7 @@ namespace CSMPrefs
|
||||
State* mParent;
|
||||
std::string mKey;
|
||||
Container mSettings;
|
||||
std::unordered_map<std::string, Setting*> mIndex;
|
||||
|
||||
public:
|
||||
Category(State* parent, const std::string& key);
|
||||
@ -30,6 +33,8 @@ namespace CSMPrefs
|
||||
|
||||
void addSetting(Setting* setting);
|
||||
|
||||
void addSubcategory(Subcategory* setting);
|
||||
|
||||
Iterator begin();
|
||||
|
||||
Iterator end();
|
||||
|
@ -14,9 +14,8 @@
|
||||
#include "state.hpp"
|
||||
|
||||
CSMPrefs::ColourSetting::ColourSetting(
|
||||
Category* parent, QMutex* mutex, const std::string& key, const std::string& label, QColor default_)
|
||||
: Setting(parent, mutex, key, label)
|
||||
, mDefault(std::move(default_))
|
||||
Category* parent, QMutex* mutex, const std::string& key, const QString& label, Settings::Index& index)
|
||||
: TypedSetting(parent, mutex, key, label, index)
|
||||
, mWidget(nullptr)
|
||||
{
|
||||
}
|
||||
@ -27,11 +26,11 @@ CSMPrefs::ColourSetting& CSMPrefs::ColourSetting::setTooltip(const std::string&
|
||||
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())
|
||||
{
|
||||
@ -42,24 +41,18 @@ std::pair<QWidget*, QWidget*> CSMPrefs::ColourSetting::makeWidgets(QWidget* pare
|
||||
|
||||
connect(mWidget, &CSVWidget::ColorEditor::pickingFinished, this, &ColourSetting::valueChanged);
|
||||
|
||||
return std::make_pair(label, mWidget);
|
||||
return SettingWidgets{ .mLabel = label, .mInput = mWidget };
|
||||
}
|
||||
|
||||
void CSMPrefs::ColourSetting::updateWidget()
|
||||
{
|
||||
if (mWidget)
|
||||
{
|
||||
mWidget->setColor(QString::fromStdString(Settings::Manager::getString(getKey(), getParent()->getKey())));
|
||||
}
|
||||
mWidget->setColor(toColor());
|
||||
}
|
||||
|
||||
void CSMPrefs::ColourSetting::valueChanged()
|
||||
{
|
||||
CSVWidget::ColorEditor& widget = dynamic_cast<CSVWidget::ColorEditor&>(*sender());
|
||||
{
|
||||
QMutexLocker lock(getMutex());
|
||||
Settings::Manager::setString(getKey(), getParent()->getKey(), widget.color().name().toUtf8().data());
|
||||
}
|
||||
|
||||
setValue(widget.color().name().toStdString());
|
||||
getParent()->getState()->update(*this);
|
||||
}
|
||||
|
@ -20,22 +20,22 @@ namespace CSVWidget
|
||||
namespace CSMPrefs
|
||||
{
|
||||
class Category;
|
||||
class ColourSetting : public Setting
|
||||
|
||||
class ColourSetting final : public TypedSetting<std::string>
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
std::string mTooltip;
|
||||
QColor mDefault;
|
||||
CSVWidget::ColorEditor* mWidget;
|
||||
|
||||
public:
|
||||
ColourSetting(
|
||||
Category* parent, QMutex* mutex, const std::string& key, const std::string& label, QColor default_);
|
||||
explicit ColourSetting(
|
||||
Category* parent, QMutex* mutex, const std::string& key, const QString& label, Settings::Index& index);
|
||||
|
||||
ColourSetting& setTooltip(const std::string& tooltip);
|
||||
|
||||
/// Return label, input widget.
|
||||
std::pair<QWidget*, QWidget*> makeWidgets(QWidget* parent) override;
|
||||
SettingWidgets makeWidgets(QWidget* parent) override;
|
||||
|
||||
void updateWidget() override;
|
||||
|
||||
|
@ -15,12 +15,11 @@
|
||||
#include "state.hpp"
|
||||
|
||||
CSMPrefs::DoubleSetting::DoubleSetting(
|
||||
Category* parent, QMutex* mutex, const std::string& key, const std::string& label, double default_)
|
||||
: 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)
|
||||
, mPrecision(2)
|
||||
, mMin(0)
|
||||
, mMax(std::numeric_limits<double>::max())
|
||||
, mDefault(default_)
|
||||
, mWidget(nullptr)
|
||||
{
|
||||
}
|
||||
@ -56,14 +55,14 @@ CSMPrefs::DoubleSetting& CSMPrefs::DoubleSetting::setTooltip(const std::string&
|
||||
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->setDecimals(mPrecision);
|
||||
mWidget->setRange(mMin, mMax);
|
||||
mWidget->setValue(mDefault);
|
||||
mWidget->setValue(getValue());
|
||||
|
||||
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);
|
||||
|
||||
return std::make_pair(label, mWidget);
|
||||
return SettingWidgets{ .mLabel = label, .mInput = mWidget };
|
||||
}
|
||||
|
||||
void CSMPrefs::DoubleSetting::updateWidget()
|
||||
{
|
||||
if (mWidget)
|
||||
{
|
||||
mWidget->setValue(Settings::Manager::getFloat(getKey(), getParent()->getKey()));
|
||||
}
|
||||
mWidget->setValue(getValue());
|
||||
}
|
||||
|
||||
void CSMPrefs::DoubleSetting::valueChanged(double value)
|
||||
{
|
||||
{
|
||||
QMutexLocker lock(getMutex());
|
||||
Settings::Manager::setFloat(getKey(), getParent()->getKey(), value);
|
||||
}
|
||||
|
||||
setValue(value);
|
||||
getParent()->getState()->update(*this);
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ namespace CSMPrefs
|
||||
{
|
||||
class Category;
|
||||
|
||||
class DoubleSetting : public Setting
|
||||
class DoubleSetting final : public TypedSetting<double>
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@ -17,12 +17,11 @@ namespace CSMPrefs
|
||||
double mMin;
|
||||
double mMax;
|
||||
std::string mTooltip;
|
||||
double mDefault;
|
||||
QDoubleSpinBox* mWidget;
|
||||
|
||||
public:
|
||||
DoubleSetting(
|
||||
Category* parent, QMutex* mutex, const std::string& key, const std::string& label, double default_);
|
||||
explicit DoubleSetting(
|
||||
Category* parent, QMutex* mutex, std::string_view key, const QString& label, Settings::Index& index);
|
||||
|
||||
DoubleSetting& setPrecision(int precision);
|
||||
|
||||
@ -36,7 +35,7 @@ namespace CSMPrefs
|
||||
DoubleSetting& setTooltip(const std::string& tooltip);
|
||||
|
||||
/// Return label, input widget.
|
||||
std::pair<QWidget*, QWidget*> makeWidgets(QWidget* parent) override;
|
||||
SettingWidgets makeWidgets(QWidget* parent) override;
|
||||
|
||||
void updateWidget() override;
|
||||
|
||||
|
@ -15,39 +15,10 @@
|
||||
#include "category.hpp"
|
||||
#include "state.hpp"
|
||||
|
||||
CSMPrefs::EnumValue::EnumValue(const std::string& value, const std::string& tooltip)
|
||||
: mValue(value)
|
||||
, mTooltip(tooltip)
|
||||
{
|
||||
}
|
||||
|
||||
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_)
|
||||
CSMPrefs::EnumSetting::EnumSetting(Category* parent, QMutex* mutex, std::string_view key, const QString& label,
|
||||
std::span<const EnumValueView> values, Settings::Index& index)
|
||||
: TypedSetting(parent, mutex, key, label, index)
|
||||
, mValues(values)
|
||||
, mWidget(nullptr)
|
||||
{
|
||||
}
|
||||
@ -58,43 +29,28 @@ CSMPrefs::EnumSetting& CSMPrefs::EnumSetting::setTooltip(const std::string& tool
|
||||
return *this;
|
||||
}
|
||||
|
||||
CSMPrefs::EnumSetting& CSMPrefs::EnumSetting::addValues(const EnumValues& values)
|
||||
CSMPrefs::SettingWidgets CSMPrefs::EnumSetting::makeWidgets(QWidget* parent)
|
||||
{
|
||||
mValues.add(values);
|
||||
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);
|
||||
QLabel* label = new QLabel(getLabel(), parent);
|
||||
|
||||
mWidget = new QComboBox(parent);
|
||||
|
||||
size_t index = 0;
|
||||
|
||||
for (size_t i = 0; i < mValues.mValues.size(); ++i)
|
||||
for (std::size_t i = 0; i < mValues.size(); ++i)
|
||||
{
|
||||
if (mDefault.mValue == mValues.mValues[i].mValue)
|
||||
index = i;
|
||||
const EnumValueView& v = mValues[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())
|
||||
mWidget->setItemData(i, QString::fromUtf8(mValues.mValues[i].mTooltip.c_str()), Qt::ToolTipRole);
|
||||
if (!v.mTooltip.empty())
|
||||
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));
|
||||
|
||||
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);
|
||||
|
||||
return std::make_pair(label, mWidget);
|
||||
return SettingWidgets{ .mLabel = label, .mInput = mWidget };
|
||||
}
|
||||
|
||||
void CSMPrefs::EnumSetting::updateWidget()
|
||||
{
|
||||
if (mWidget)
|
||||
{
|
||||
int index
|
||||
= mWidget->findText(QString::fromStdString(Settings::Manager::getString(getKey(), getParent()->getKey())));
|
||||
|
||||
mWidget->setCurrentIndex(index);
|
||||
}
|
||||
mWidget->setCurrentIndex(mWidget->findText(QString::fromStdString(getValue())));
|
||||
}
|
||||
|
||||
void CSMPrefs::EnumSetting::valueChanged(int value)
|
||||
{
|
||||
{
|
||||
QMutexLocker lock(getMutex());
|
||||
Settings::Manager::setString(getKey(), getParent()->getKey(), mValues.mValues.at(value).mValue);
|
||||
}
|
||||
if (value < 0 || static_cast<std::size_t>(value) >= mValues.size())
|
||||
throw std::logic_error("Invalid enum setting \"" + getKey() + "\" value index: " + std::to_string(value));
|
||||
|
||||
setValue(std::string(mValues[value].mValue));
|
||||
getParent()->getState()->update(*this);
|
||||
}
|
||||
|
@ -1,10 +1,13 @@
|
||||
#ifndef CSM_PREFS_ENUMSETTING_H
|
||||
#define CSM_PREFS_ENUMSETTING_H
|
||||
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "enumvalueview.hpp"
|
||||
#include "setting.hpp"
|
||||
|
||||
class QComboBox;
|
||||
@ -13,50 +16,22 @@ namespace CSMPrefs
|
||||
{
|
||||
class Category;
|
||||
|
||||
struct EnumValue
|
||||
{
|
||||
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
|
||||
class EnumSetting final : public TypedSetting<std::string>
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
std::string mTooltip;
|
||||
EnumValue mDefault;
|
||||
EnumValues mValues;
|
||||
std::span<const EnumValueView> mValues;
|
||||
QComboBox* mWidget;
|
||||
|
||||
public:
|
||||
EnumSetting(Category* parent, QMutex* mutex, const std::string& key, const std::string& label,
|
||||
const EnumValue& default_);
|
||||
explicit EnumSetting(Category* parent, QMutex* mutex, std::string_view key, const QString& label,
|
||||
std::span<const EnumValueView> values, Settings::Index& index);
|
||||
|
||||
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.
|
||||
std::pair<QWidget*, QWidget*> makeWidgets(QWidget* parent) override;
|
||||
SettingWidgets makeWidgets(QWidget* parent) 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"
|
||||
|
||||
CSMPrefs::IntSetting::IntSetting(
|
||||
Category* parent, QMutex* mutex, const std::string& key, const std::string& label, int default_)
|
||||
: 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)
|
||||
, mMin(0)
|
||||
, mMax(std::numeric_limits<int>::max())
|
||||
, mDefault(default_)
|
||||
, mWidget(nullptr)
|
||||
{
|
||||
}
|
||||
@ -49,13 +48,13 @@ CSMPrefs::IntSetting& CSMPrefs::IntSetting::setTooltip(const std::string& toolti
|
||||
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->setRange(mMin, mMax);
|
||||
mWidget->setValue(mDefault);
|
||||
mWidget->setValue(getValue());
|
||||
|
||||
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);
|
||||
|
||||
return std::make_pair(label, mWidget);
|
||||
return SettingWidgets{ .mLabel = label, .mInput = mWidget };
|
||||
}
|
||||
|
||||
void CSMPrefs::IntSetting::updateWidget()
|
||||
{
|
||||
if (mWidget)
|
||||
{
|
||||
mWidget->setValue(Settings::Manager::getInt(getKey(), getParent()->getKey()));
|
||||
}
|
||||
mWidget->setValue(getValue());
|
||||
}
|
||||
|
||||
void CSMPrefs::IntSetting::valueChanged(int value)
|
||||
{
|
||||
{
|
||||
QMutexLocker lock(getMutex());
|
||||
Settings::Manager::setInt(getKey(), getParent()->getKey(), value);
|
||||
}
|
||||
|
||||
setValue(value);
|
||||
getParent()->getState()->update(*this);
|
||||
}
|
||||
|
@ -12,18 +12,18 @@ namespace CSMPrefs
|
||||
{
|
||||
class Category;
|
||||
|
||||
class IntSetting : public Setting
|
||||
class IntSetting final : public TypedSetting<int>
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
int mMin;
|
||||
int mMax;
|
||||
std::string mTooltip;
|
||||
int mDefault;
|
||||
QSpinBox* mWidget;
|
||||
|
||||
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()]
|
||||
IntSetting& setRange(int min, int max);
|
||||
@ -35,7 +35,7 @@ namespace CSMPrefs
|
||||
IntSetting& setTooltip(const std::string& tooltip);
|
||||
|
||||
/// Return label, input widget.
|
||||
std::pair<QWidget*, QWidget*> makeWidgets(QWidget* parent) override;
|
||||
SettingWidgets makeWidgets(QWidget* parent) override;
|
||||
|
||||
void updateWidget() override;
|
||||
|
||||
|
@ -19,21 +19,22 @@ class QWidget;
|
||||
|
||||
namespace CSMPrefs
|
||||
{
|
||||
ModifierSetting::ModifierSetting(Category* parent, QMutex* mutex, const std::string& key, const std::string& label)
|
||||
: Setting(parent, mutex, key, label)
|
||||
ModifierSetting::ModifierSetting(
|
||||
Category* parent, QMutex* mutex, std::string_view key, const QString& label, Settings::Index& index)
|
||||
: TypedSetting(parent, mutex, key, label, index)
|
||||
, mButton(nullptr)
|
||||
, mEditorActive(false)
|
||||
{
|
||||
}
|
||||
|
||||
std::pair<QWidget*, QWidget*> ModifierSetting::makeWidgets(QWidget* parent)
|
||||
SettingWidgets ModifierSetting::makeWidgets(QWidget* parent)
|
||||
{
|
||||
int modifier = 0;
|
||||
State::get().getShortcutManager().getModifier(getKey(), modifier);
|
||||
|
||||
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);
|
||||
|
||||
widget->setCheckable(true);
|
||||
@ -46,14 +47,14 @@ namespace CSMPrefs
|
||||
|
||||
connect(widget, &QPushButton::toggled, this, &ModifierSetting::buttonToggled);
|
||||
|
||||
return std::make_pair(label, widget);
|
||||
return SettingWidgets{ .mLabel = label, .mInput = widget };
|
||||
}
|
||||
|
||||
void ModifierSetting::updateWidget()
|
||||
{
|
||||
if (mButton)
|
||||
{
|
||||
const std::string& shortcut = Settings::Manager::getString(getKey(), getParent()->getKey());
|
||||
const std::string& shortcut = getValue();
|
||||
|
||||
int modifier;
|
||||
State::get().getShortcutManager().convertFromString(shortcut, modifier);
|
||||
@ -131,15 +132,7 @@ namespace CSMPrefs
|
||||
void ModifierSetting::storeValue(int modifier)
|
||||
{
|
||||
State::get().getShortcutManager().setModifier(getKey(), modifier);
|
||||
|
||||
// Convert to string and assign
|
||||
std::string value = State::get().getShortcutManager().convertToString(modifier);
|
||||
|
||||
{
|
||||
QMutexLocker lock(getMutex());
|
||||
Settings::Manager::setString(getKey(), getParent()->getKey(), value);
|
||||
}
|
||||
|
||||
setValue(State::get().getShortcutManager().convertToString(modifier));
|
||||
getParent()->getState()->update(*this);
|
||||
}
|
||||
|
||||
|
@ -15,14 +15,16 @@ class QPushButton;
|
||||
namespace CSMPrefs
|
||||
{
|
||||
class Category;
|
||||
class ModifierSetting : public Setting
|
||||
|
||||
class ModifierSetting final : public TypedSetting<std::string>
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
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;
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <QMutexLocker>
|
||||
|
||||
#include <components/settings/settings.hpp>
|
||||
#include <components/settings/settingvalue.hpp>
|
||||
|
||||
#include "category.hpp"
|
||||
#include "state.hpp"
|
||||
@ -14,22 +15,17 @@ QMutex* CSMPrefs::Setting::getMutex()
|
||||
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())
|
||||
, mParent(parent)
|
||||
, mMutex(mutex)
|
||||
, mKey(key)
|
||||
, 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
|
||||
{
|
||||
return mParent;
|
||||
@ -40,35 +36,6 @@ const std::string& CSMPrefs::Setting::getKey() const
|
||||
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
|
||||
{
|
||||
// toString() handles lock
|
||||
|
@ -4,15 +4,26 @@
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include <QMutexLocker>
|
||||
#include <QObject>
|
||||
|
||||
#include <components/settings/settingvalue.hpp>
|
||||
|
||||
#include "category.hpp"
|
||||
|
||||
class QWidget;
|
||||
class QColor;
|
||||
class QMutex;
|
||||
class QGridLayout;
|
||||
class QLabel;
|
||||
|
||||
namespace CSMPrefs
|
||||
{
|
||||
class Category;
|
||||
struct SettingWidgets
|
||||
{
|
||||
QLabel* mLabel;
|
||||
QWidget* mInput;
|
||||
};
|
||||
|
||||
class Setting : public QObject
|
||||
{
|
||||
@ -21,44 +32,82 @@ namespace CSMPrefs
|
||||
Category* mParent;
|
||||
QMutex* mMutex;
|
||||
std::string mKey;
|
||||
std::string mLabel;
|
||||
QString mLabel;
|
||||
Settings::Index& mIndex;
|
||||
|
||||
protected:
|
||||
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:
|
||||
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;
|
||||
|
||||
/// Return label, input widget.
|
||||
///
|
||||
/// \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);
|
||||
virtual SettingWidgets makeWidgets(QWidget* parent) = 0;
|
||||
|
||||
/// Updates the widget returned by makeWidgets() to the current setting.
|
||||
///
|
||||
/// \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 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;
|
||||
};
|
||||
|
||||
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
|
||||
bool operator==(const Setting& setting, const std::string& fullKey);
|
||||
bool operator==(const std::string& fullKey, const Setting& setting);
|
||||
|
@ -91,7 +91,7 @@ namespace CSMPrefs
|
||||
return false;
|
||||
}
|
||||
|
||||
void ShortcutManager::setModifier(const std::string& name, int modifier)
|
||||
void ShortcutManager::setModifier(std::string_view name, int modifier)
|
||||
{
|
||||
// Add to map/modify
|
||||
ModifierMap::iterator item = mModifiers.find(name);
|
||||
|
@ -32,7 +32,7 @@ namespace CSMPrefs
|
||||
void setSequence(const std::string& name, const QKeySequence& sequence);
|
||||
|
||||
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(int modifier) const;
|
||||
@ -49,9 +49,9 @@ namespace CSMPrefs
|
||||
|
||||
private:
|
||||
// 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, int> ModifierMap;
|
||||
typedef std::map<std::string, int, std::less<>> ModifierMap;
|
||||
typedef std::map<int, std::string> NameMap;
|
||||
typedef std::map<std::string, int> KeyMap;
|
||||
|
||||
|
@ -18,8 +18,9 @@
|
||||
|
||||
namespace CSMPrefs
|
||||
{
|
||||
ShortcutSetting::ShortcutSetting(Category* parent, QMutex* mutex, const std::string& key, const std::string& label)
|
||||
: Setting(parent, mutex, key, label)
|
||||
ShortcutSetting::ShortcutSetting(
|
||||
Category* parent, QMutex* mutex, const std::string& key, const QString& label, Settings::Index& index)
|
||||
: TypedSetting(parent, mutex, key, label, index)
|
||||
, mButton(nullptr)
|
||||
, mEditorActive(false)
|
||||
, mEditorPos(0)
|
||||
@ -30,14 +31,14 @@ namespace CSMPrefs
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<QWidget*, QWidget*> ShortcutSetting::makeWidgets(QWidget* parent)
|
||||
SettingWidgets ShortcutSetting::makeWidgets(QWidget* parent)
|
||||
{
|
||||
QKeySequence sequence;
|
||||
State::get().getShortcutManager().getSequence(getKey(), sequence);
|
||||
|
||||
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);
|
||||
|
||||
widget->setCheckable(true);
|
||||
@ -50,14 +51,14 @@ namespace CSMPrefs
|
||||
|
||||
connect(widget, &QPushButton::toggled, this, &ShortcutSetting::buttonToggled);
|
||||
|
||||
return std::make_pair(label, widget);
|
||||
return SettingWidgets{ .mLabel = label, .mInput = widget };
|
||||
}
|
||||
|
||||
void ShortcutSetting::updateWidget()
|
||||
{
|
||||
if (mButton)
|
||||
{
|
||||
const std::string& shortcut = Settings::Manager::getString(getKey(), getParent()->getKey());
|
||||
const std::string shortcut = getValue();
|
||||
|
||||
QKeySequence sequence;
|
||||
State::get().getShortcutManager().convertFromString(shortcut, sequence);
|
||||
@ -170,15 +171,7 @@ namespace CSMPrefs
|
||||
void ShortcutSetting::storeValue(const QKeySequence& sequence)
|
||||
{
|
||||
State::get().getShortcutManager().setSequence(getKey(), sequence);
|
||||
|
||||
// Convert to string and assign
|
||||
std::string value = State::get().getShortcutManager().convertToString(sequence);
|
||||
|
||||
{
|
||||
QMutexLocker lock(getMutex());
|
||||
Settings::Manager::setString(getKey(), getParent()->getKey(), value);
|
||||
}
|
||||
|
||||
setValue(State::get().getShortcutManager().convertToString(sequence));
|
||||
getParent()->getState()->update(*this);
|
||||
}
|
||||
|
||||
|
@ -17,14 +17,16 @@ class QWidget;
|
||||
namespace CSMPrefs
|
||||
{
|
||||
class Category;
|
||||
class ShortcutSetting : public Setting
|
||||
|
||||
class ShortcutSetting final : public TypedSetting<std::string>
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
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;
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <apps/opencs/model/prefs/enumsetting.hpp>
|
||||
#include <apps/opencs/model/prefs/setting.hpp>
|
||||
#include <apps/opencs/model/prefs/shortcutmanager.hpp>
|
||||
#include <apps/opencs/model/prefs/subcategory.hpp>
|
||||
|
||||
#include <components/settings/categories.hpp>
|
||||
#include <components/settings/settings.hpp>
|
||||
@ -24,50 +25,43 @@
|
||||
#include "modifiersetting.hpp"
|
||||
#include "shortcutsetting.hpp"
|
||||
#include "stringsetting.hpp"
|
||||
#include "values.hpp"
|
||||
|
||||
CSMPrefs::State* CSMPrefs::State::sThis = nullptr;
|
||||
|
||||
void CSMPrefs::State::declare()
|
||||
{
|
||||
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.")
|
||||
.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.")
|
||||
.setMin(80);
|
||||
declareBool("show-statusbar", "Show Status Bar", true)
|
||||
declareBool(mValues->mWindows.mShowStatusbar, "Show Status Bar")
|
||||
.setTooltip(
|
||||
"If a newly open top level window is showing status bars or not. "
|
||||
" Note that this does not affect existing windows.");
|
||||
declareSeparator();
|
||||
declareBool("reuse", "Reuse Subviews", true)
|
||||
declareBool(mValues->mWindows.mReuse, "Reuse Subviews")
|
||||
.setTooltip(
|
||||
"When a new subview is requested and a matching subview already "
|
||||
" 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(
|
||||
"If the maximum number is reached and a new subview is opened "
|
||||
"it will be placed into a new top-level window.")
|
||||
.setRange(1, 256);
|
||||
declareBool("hide-subview", "Hide single subview", false)
|
||||
declareBool(mValues->mWindows.mHideSubview, "Hide single subview")
|
||||
.setTooltip(
|
||||
"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 "
|
||||
"view for this document)");
|
||||
declareInt("minimum-width", "Minimum subview width", 325)
|
||||
declareInt(mValues->mWindows.mMinimumWidth, "Minimum subview width")
|
||||
.setTooltip("Minimum width of subviews.")
|
||||
.setRange(50, 10000);
|
||||
declareSeparator();
|
||||
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.");
|
||||
declareEnum(mValues->mWindows.mMainwindowScrollbar, "Horizontal scrollbar mode for main window.");
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
declareBool("grow-limit", "Grow Limit Screen", false)
|
||||
declareBool(mValues->mWindows.mGrowLimit, "Grow Limit Screen")
|
||||
.setTooltip(
|
||||
"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"
|
||||
@ -75,93 +69,64 @@ void CSMPrefs::State::declare()
|
||||
#endif
|
||||
|
||||
declareCategory("Records");
|
||||
EnumValue iconAndText("Icon and Text");
|
||||
EnumValues recordValues;
|
||||
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);
|
||||
declareEnum(mValues->mRecords.mStatusFormat, "Modification status display format");
|
||||
declareEnum(mValues->mRecords.mTypeFormat, "ID type display format");
|
||||
|
||||
declareCategory("ID Tables");
|
||||
EnumValue inPlaceEdit("Edit in Place", "Edit the clicked cell");
|
||||
EnumValue editRecord("Edit Record", "Open a dialogue subview for the clicked record");
|
||||
EnumValue view("View", "Open a scene subview for the clicked record (not available everywhere)");
|
||||
EnumValue editRecordAndClose("Edit Record and Close");
|
||||
EnumValues doubleClickValues;
|
||||
doubleClickValues.add(inPlaceEdit)
|
||||
.add(editRecord)
|
||||
.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)
|
||||
declareEnum(mValues->mIdTables.mDouble, "Double Click");
|
||||
declareEnum(mValues->mIdTables.mDoubleS, "Shift Double Click");
|
||||
declareEnum(mValues->mIdTables.mDoubleC, "Control Double Click");
|
||||
declareEnum(mValues->mIdTables.mDoubleSc, "Shift Control Double Click");
|
||||
declareEnum(mValues->mIdTables.mJumpToAdded, "Action on adding or cloning a record");
|
||||
declareBool(
|
||||
mValues->mIdTables.mExtendedConfig, "Manually specify affected record types for an extended delete/revert")
|
||||
.setTooltip(
|
||||
"Delete and revert commands have an extended form that also affects "
|
||||
"associated records.\n\n"
|
||||
"If this option is enabled, types of affected records are selected "
|
||||
"manually before a command execution.\nOtherwise, all associated "
|
||||
"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(
|
||||
"When editing a record, open the view in a new window,"
|
||||
" rather than docked in the main view.");
|
||||
|
||||
declareCategory("ID Dialogues");
|
||||
declareBool("toolbar", "Show toolbar", true);
|
||||
declareBool(mValues->mIdDialogues.mToolbar, "Show toolbar");
|
||||
|
||||
declareCategory("Reports");
|
||||
EnumValue actionNone("None");
|
||||
EnumValue actionEdit("Edit", "Open a table or dialogue suitable for addressing the listed report");
|
||||
EnumValue actionRemove("Remove", "Remove the report from the report table");
|
||||
EnumValue actionEditAndRemove("Edit And Remove",
|
||||
"Open a table or dialogue suitable for addressing the listed report, then remove the report from the report "
|
||||
"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);
|
||||
declareEnum(mValues->mReports.mDouble, "Double Click");
|
||||
declareEnum(mValues->mReports.mDoubleS, "Shift Double Click");
|
||||
declareEnum(mValues->mReports.mDoubleC, "Control Double Click");
|
||||
declareEnum(mValues->mReports.mDoubleSc, "Shift Control Double Click");
|
||||
declareBool(mValues->mReports.mIgnoreBaseRecords, "Ignore base records in verifier");
|
||||
|
||||
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");
|
||||
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");
|
||||
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");
|
||||
declareBool("show-linenum", "Show Line Numbers", true)
|
||||
declareBool(mValues->mScripts.mShowLinenum, "Show Line Numbers")
|
||||
.setTooltip(
|
||||
"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.");
|
||||
declareBool("wrap-lines", "Wrap Lines", false).setTooltip("Wrap lines longer than width of script editor.");
|
||||
declareBool("mono-font", "Use monospace font", true);
|
||||
declareInt("tab-width", "Tab Width", 4).setTooltip("Number of characters for tab width").setRange(1, 10);
|
||||
EnumValue warningsNormal("Normal", "Report warnings as warning");
|
||||
declareEnum("warnings", "Warning Mode", warningsNormal)
|
||||
.addValue("Ignore", "Do not report warning")
|
||||
.addValue(warningsNormal)
|
||||
.addValue("Strict", "Promote warning to an error");
|
||||
declareBool("toolbar", "Show toolbar", true);
|
||||
declareInt("compile-delay", "Delay between updating of source errors", 100)
|
||||
declareBool(mValues->mScripts.mWrapLines, "Wrap Lines")
|
||||
.setTooltip("Wrap lines longer than width of script editor.");
|
||||
declareBool(mValues->mScripts.mMonoFont, "Use monospace font");
|
||||
declareInt(mValues->mScripts.mTabWidth, "Tab Width")
|
||||
.setTooltip("Number of characters for tab width")
|
||||
.setRange(1, 10);
|
||||
declareEnum(mValues->mScripts.mWarnings, "Warning Mode");
|
||||
declareBool(mValues->mScripts.mToolbar, "Show toolbar");
|
||||
declareInt(mValues->mScripts.mCompileDelay, "Delay between updating of source errors")
|
||||
.setTooltip("Delay in milliseconds")
|
||||
.setRange(0, 10000);
|
||||
declareInt("error-height", "Initial height of the error panel", 100).setRange(100, 10000);
|
||||
declareBool("highlight-occurrences", "Highlight other occurrences of selected names", true);
|
||||
declareInt(mValues->mScripts.mErrorHeight, "Initial height of the error panel").setRange(100, 10000);
|
||||
declareBool(mValues->mScripts.mHighlightOccurrences, "Highlight other occurrences of selected names");
|
||||
declareColour("colour-highlight", "Colour of highlighted occurrences", QColor("lightcyan"));
|
||||
declareSeparator();
|
||||
declareColour("colour-int", "Highlight Colour: Integer Literals", QColor("darkmagenta"));
|
||||
declareColour("colour-float", "Highlight Colour: Float Literals", QColor("magenta"));
|
||||
declareColour("colour-name", "Highlight Colour: Names", QColor("grey"));
|
||||
@ -171,51 +136,55 @@ void CSMPrefs::State::declare()
|
||||
declareColour("colour-id", "Highlight Colour: IDs", QColor("blue"));
|
||||
|
||||
declareCategory("General Input");
|
||||
declareBool("cycle", "Cyclic next/previous", false)
|
||||
declareBool(mValues->mGeneralInput.mCycle, "Cyclic next/previous")
|
||||
.setTooltip(
|
||||
"When using next/previous functions at the last/first item of a "
|
||||
"list go to the first/last item");
|
||||
|
||||
declareCategory("3D Scene Input");
|
||||
|
||||
declareDouble("navi-wheel-factor", "Camera Zoom Sensitivity", 8).setRange(-100.0, 100.0);
|
||||
declareDouble("s-navi-sensitivity", "Secondary Camera Movement Sensitivity", 50.0).setRange(-1000.0, 1000.0);
|
||||
declareSeparator();
|
||||
declareDouble(mValues->mSceneInput.mNaviWheelFactor, "Camera Zoom Sensitivity").setRange(-100.0, 100.0);
|
||||
declareDouble(mValues->mSceneInput.mSNaviSensitivity, "Secondary Camera Movement Sensitivity")
|
||||
.setRange(-1000.0, 1000.0);
|
||||
|
||||
declareDouble("p-navi-free-sensitivity", "Free Camera Sensitivity", 1 / 650.).setPrecision(5).setRange(0.0, 1.0);
|
||||
declareBool("p-navi-free-invert", "Invert Free Camera Mouse Input", false);
|
||||
declareDouble("navi-free-lin-speed", "Free Camera Linear Speed", 1000.0).setRange(1.0, 10000.0);
|
||||
declareDouble("navi-free-rot-speed", "Free Camera Rotational Speed", 3.14 / 2).setRange(0.001, 6.28);
|
||||
declareDouble("navi-free-speed-mult", "Free Camera Speed Multiplier (from Modifier)", 8).setRange(0.001, 1000.0);
|
||||
declareSeparator();
|
||||
|
||||
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)
|
||||
declareDouble(mValues->mSceneInput.mPNaviFreeSensitivity, "Free Camera Sensitivity")
|
||||
.setPrecision(5)
|
||||
.setRange(0.0, 1.0);
|
||||
declareBool(mValues->mSceneInput.mPNaviFreeInvert, "Invert Free Camera Mouse Input");
|
||||
declareDouble(mValues->mSceneInput.mNaviFreeLinSpeed, "Free Camera Linear Speed").setRange(1.0, 10000.0);
|
||||
declareDouble(mValues->mSceneInput.mNaviFreeRotSpeed, "Free Camera Rotational Speed").setRange(0.001, 6.28);
|
||||
declareDouble(mValues->mSceneInput.mNaviFreeSpeedMult, "Free Camera Speed Multiplier (from Modifier)")
|
||||
.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("drag-factor", "Mouse sensitivity during drag operations", 1.0).setRange(0.001, 100.0);
|
||||
declareDouble("drag-wheel-factor", "Mouse wheel sensitivity during drag operations", 1.0).setRange(0.001, 100.0);
|
||||
declareDouble("drag-shift-factor", "Shift-acceleration factor during drag operations", 4.0)
|
||||
declareDouble(mValues->mSceneInput.mPNaviOrbitSensitivity, "Orbit Camera Sensitivity")
|
||||
.setPrecision(5)
|
||||
.setRange(0.0, 1.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")
|
||||
.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");
|
||||
declareInt("framerate-limit", "FPS limit", 60)
|
||||
declareInt(mValues->mRendering.mFramerateLimit, "FPS limit")
|
||||
.setTooltip("Framerate limit in 3D preview windows. Zero value means \"unlimited\".")
|
||||
.setRange(0, 10000);
|
||||
declareInt("camera-fov", "Camera FOV", 90).setRange(10, 170);
|
||||
declareBool("camera-ortho", "Orthographic projection for camera", false);
|
||||
declareInt("camera-ortho-size", "Orthographic projection size parameter", 100)
|
||||
declareInt(mValues->mRendering.mCameraFov, "Camera FOV").setRange(10, 170);
|
||||
declareBool(mValues->mRendering.mCameraOrtho, "Orthographic projection for camera");
|
||||
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.")
|
||||
.setRange(10, 10000);
|
||||
declareDouble("object-marker-alpha", "Object Marker Transparency", 0.5).setPrecision(2).setRange(0, 1);
|
||||
declareBool("scene-use-gradient", "Use Gradient Background", true);
|
||||
declareDouble(mValues->mRendering.mObjectMarkerAlpha, "Object Marker Transparency").setPrecision(2).setRange(0, 1);
|
||||
declareBool(mValues->mRendering.mSceneUseGradient, "Use Gradient Background");
|
||||
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))
|
||||
.setTooltip(
|
||||
@ -231,82 +200,52 @@ void CSMPrefs::State::declare()
|
||||
.setTooltip(
|
||||
"Sets the gradient color to use in conjunction with the night background color. Ignored if "
|
||||
"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");
|
||||
declareBool("scene", "Show Tooltips in 3D scenes", true);
|
||||
declareBool("scene-hide-basic", "Hide basic 3D scenes tooltips", false);
|
||||
declareInt("scene-delay", "Tooltip delay in milliseconds", 500).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);
|
||||
declareBool(mValues->mTooltips.mScene, "Show Tooltips in 3D scenes");
|
||||
declareBool(mValues->mTooltips.mSceneHideBasic, "Hide basic 3D scenes tooltips");
|
||||
declareInt(mValues->mTooltips.mSceneDelay, "Tooltip delay in milliseconds").setMin(1);
|
||||
|
||||
declareCategory("3D Scene Editing");
|
||||
declareDouble("gridsnap-movement", "Grid snap size", 16);
|
||||
declareDouble("gridsnap-rotation", "Angle snap size", 15);
|
||||
declareDouble("gridsnap-scale", "Scale snap size", 0.25);
|
||||
declareInt("distance", "Drop Distance", 50)
|
||||
declareDouble(mValues->mSceneEditing.mGridsnapMovement, "Grid snap size");
|
||||
declareDouble(mValues->mSceneEditing.mGridsnapRotation, "Angle snap size");
|
||||
declareDouble(mValues->mSceneEditing.mGridsnapScale, "Scale snap size");
|
||||
declareInt(mValues->mSceneEditing.mDistance, "Drop Distance")
|
||||
.setTooltip(
|
||||
"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");
|
||||
declareEnum("outside-drop", "Handling drops outside of cells", createAndInsert).addValues(insertOutsideCell);
|
||||
declareEnum("outside-visible-drop", "Handling drops outside of visible cells", showAndInsert)
|
||||
.addValues(insertOutsideVisibleCell);
|
||||
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.")
|
||||
.addValues(landeditOutsideCell);
|
||||
declareEnum("outside-visible-landedit", "Handling terrain edit outside of visible cells", showAndLandEdit)
|
||||
.setTooltip("Behavior of terrain editing, if land editing brush reaches an area that is not currently visible.")
|
||||
.addValues(landeditOutsideVisibleCell);
|
||||
declareInt("texturebrush-maximumsize", "Maximum texture brush size", 50).setMin(1);
|
||||
declareInt("shapebrush-maximumsize", "Maximum height edit brush size", 100)
|
||||
declareEnum(mValues->mSceneEditing.mOutsideDrop, "Handling drops outside of cells");
|
||||
declareEnum(mValues->mSceneEditing.mOutsideVisibleDrop, "Handling drops outside of visible cells");
|
||||
declareEnum(mValues->mSceneEditing.mOutsideLandedit, "Handling terrain edit outside of cells")
|
||||
.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")
|
||||
.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);
|
||||
declareInt(mValues->mSceneEditing.mShapebrushMaximumsize, "Maximum height edit brush size")
|
||||
.setTooltip("Setting for the slider range of brush size in terrain height editing.")
|
||||
.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");
|
||||
declareDouble("landedit-post-smoothstrength", "Smoothing strength (post-edit)", 0.25)
|
||||
declareDouble(mValues->mSceneEditing.mLandeditPostSmoothstrength, "Smoothing strength (post-edit)")
|
||||
.setTooltip(
|
||||
"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.")
|
||||
.setMin(-1)
|
||||
.setMax(1);
|
||||
declareBool("open-list-view", "Open displays list view", false)
|
||||
declareBool(mValues->mSceneEditing.mOpenListView, "Open displays list view")
|
||||
.setTooltip(
|
||||
"When opening a reference from the scene view, it will open the"
|
||||
" 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(
|
||||
"Selection can be chosen between select only, add to selection, remove from selection and invert "
|
||||
"selection.")
|
||||
.addValues(primarySelectAction);
|
||||
declareEnum("secondary-select-action", "Action for secondary select", SelectAdd)
|
||||
"selection.");
|
||||
declareEnum(mValues->mSceneEditing.mSecondarySelectAction, "Action for secondary select")
|
||||
.setTooltip(
|
||||
"Selection can be chosen between select only, add to selection, remove from selection and invert "
|
||||
"selection.")
|
||||
.addValues(secondarySelectAction);
|
||||
"selection.");
|
||||
|
||||
declareCategory("Key Bindings");
|
||||
|
||||
@ -401,7 +340,7 @@ void CSMPrefs::State::declare()
|
||||
"scene-select-secondary", "Secondary Select", QKeySequence(Qt::ControlModifier | (int)Qt::MiddleButton));
|
||||
declareShortcut(
|
||||
"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-instance-drop-terrain", "Drop to terrain level", QKeySequence(Qt::Key_G));
|
||||
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-focus-toolbar", "Toggle Toolbar Focus", QKeySequence(Qt::Key_T));
|
||||
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");
|
||||
declareShortcut("free-forward", "Forward", QKeySequence(Qt::Key_W));
|
||||
@ -440,13 +403,12 @@ void CSMPrefs::State::declare()
|
||||
declareShortcut("script-editor-uncomment", "Uncomment Selection", QKeySequence());
|
||||
|
||||
declareCategory("Models");
|
||||
declareString("baseanim", "base animations", "meshes/base_anim.nif")
|
||||
.setTooltip("3rd person base model with textkeys-data");
|
||||
declareString("baseanimkna", "base animations, kna", "meshes/base_animkna.nif")
|
||||
declareString(mValues->mModels.mBaseanim, "base animations").setTooltip("3rd person base model with textkeys-data");
|
||||
declareString(mValues->mModels.mBaseanimkna, "base animations, kna")
|
||||
.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");
|
||||
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)
|
||||
@ -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())
|
||||
throw std::logic_error("no category for setting");
|
||||
|
||||
setDefault(key, std::to_string(default_));
|
||||
|
||||
default_ = Settings::Manager::getInt(key, mCurrentCategory->second.getKey());
|
||||
|
||||
CSMPrefs::IntSetting* setting = new CSMPrefs::IntSetting(&mCurrentCategory->second, &mMutex, key, label, default_);
|
||||
CSMPrefs::IntSetting* setting
|
||||
= new CSMPrefs::IntSetting(&mCurrentCategory->second, &mMutex, value.mName, label, *mIndex);
|
||||
|
||||
mCurrentCategory->second.addSetting(setting);
|
||||
|
||||
return *setting;
|
||||
}
|
||||
|
||||
CSMPrefs::DoubleSetting& CSMPrefs::State::declareDouble(
|
||||
const std::string& key, const std::string& label, double default_)
|
||||
CSMPrefs::DoubleSetting& CSMPrefs::State::declareDouble(Settings::SettingValue<double>& value, const QString& label)
|
||||
{
|
||||
if (mCurrentCategory == mCategories.end())
|
||||
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
|
||||
= new CSMPrefs::DoubleSetting(&mCurrentCategory->second, &mMutex, key, label, default_);
|
||||
= new CSMPrefs::DoubleSetting(&mCurrentCategory->second, &mMutex, value.mName, label, *mIndex);
|
||||
|
||||
mCurrentCategory->second.addSetting(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())
|
||||
throw std::logic_error("no category for setting");
|
||||
|
||||
setDefault(key, default_ ? "true" : "false");
|
||||
|
||||
default_ = Settings::Manager::getBool(key, mCurrentCategory->second.getKey());
|
||||
|
||||
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);
|
||||
|
||||
return *setting;
|
||||
}
|
||||
|
||||
CSMPrefs::EnumSetting& CSMPrefs::State::declareEnum(
|
||||
const std::string& key, const std::string& label, EnumValue default_)
|
||||
CSMPrefs::EnumSetting& CSMPrefs::State::declareEnum(EnumSettingValue& value, const QString& label)
|
||||
{
|
||||
if (mCurrentCategory == mCategories.end())
|
||||
throw std::logic_error("no category for setting");
|
||||
|
||||
setDefault(key, default_.mValue);
|
||||
|
||||
default_.mValue = Settings::Manager::getString(key, mCurrentCategory->second.getKey());
|
||||
|
||||
CSMPrefs::EnumSetting* setting
|
||||
= new CSMPrefs::EnumSetting(&mCurrentCategory->second, &mMutex, key, label, default_);
|
||||
CSMPrefs::EnumSetting* setting = new CSMPrefs::EnumSetting(
|
||||
&mCurrentCategory->second, &mMutex, value.getValue().mName, label, value.getEnumValues(), *mIndex);
|
||||
|
||||
mCurrentCategory->second.addSetting(setting);
|
||||
|
||||
return *setting;
|
||||
}
|
||||
|
||||
CSMPrefs::ColourSetting& CSMPrefs::State::declareColour(
|
||||
const std::string& key, const std::string& label, QColor default_)
|
||||
CSMPrefs::ColourSetting& CSMPrefs::State::declareColour(const std::string& key, const QString& label, QColor default_)
|
||||
{
|
||||
if (mCurrentCategory == mCategories.end())
|
||||
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
|
||||
= new CSMPrefs::ColourSetting(&mCurrentCategory->second, &mMutex, key, label, default_);
|
||||
= new CSMPrefs::ColourSetting(&mCurrentCategory->second, &mMutex, key, label, *mIndex);
|
||||
|
||||
mCurrentCategory->second.addSetting(setting);
|
||||
|
||||
@ -554,39 +491,32 @@ CSMPrefs::ColourSetting& CSMPrefs::State::declareColour(
|
||||
}
|
||||
|
||||
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())
|
||||
throw std::logic_error("no category for setting");
|
||||
|
||||
std::string seqStr = getShortcutManager().convertToString(default_);
|
||||
setDefault(key, seqStr);
|
||||
|
||||
// Setup with actual data
|
||||
QKeySequence sequence;
|
||||
|
||||
getShortcutManager().convertFromString(
|
||||
Settings::Manager::getString(key, mCurrentCategory->second.getKey()), sequence);
|
||||
getShortcutManager().convertFromString(mIndex->get<std::string>(mCurrentCategory->second.getKey(), 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);
|
||||
|
||||
return *setting;
|
||||
}
|
||||
|
||||
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())
|
||||
throw std::logic_error("no category for setting");
|
||||
|
||||
setDefault(key, default_);
|
||||
|
||||
default_ = Settings::Manager::getString(key, mCurrentCategory->second.getKey());
|
||||
|
||||
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);
|
||||
|
||||
@ -594,55 +524,31 @@ CSMPrefs::StringSetting& CSMPrefs::State::declareString(
|
||||
}
|
||||
|
||||
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())
|
||||
throw std::logic_error("no category for setting");
|
||||
|
||||
std::string modStr = getShortcutManager().convertToString(default_);
|
||||
setDefault(key, modStr);
|
||||
|
||||
// Setup with actual data
|
||||
int modifier;
|
||||
|
||||
getShortcutManager().convertFromString(
|
||||
Settings::Manager::getString(key, mCurrentCategory->second.getKey()), modifier);
|
||||
getShortcutManager().setModifier(key, modifier);
|
||||
getShortcutManager().convertFromString(value.get(), modifier);
|
||||
getShortcutManager().setModifier(value.mName, 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);
|
||||
|
||||
return *setting;
|
||||
}
|
||||
|
||||
void CSMPrefs::State::declareSeparator()
|
||||
void CSMPrefs::State::declareSubcategory(const QString& label)
|
||||
{
|
||||
if (mCurrentCategory == mCategories.end())
|
||||
throw std::logic_error("no category for setting");
|
||||
|
||||
CSMPrefs::Setting* setting = new CSMPrefs::Setting(&mCurrentCategory->second, &mMutex, "", "");
|
||||
|
||||
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_));
|
||||
mCurrentCategory->second.addSubcategory(
|
||||
new CSMPrefs::Subcategory(&mCurrentCategory->second, &mMutex, label, *mIndex));
|
||||
}
|
||||
|
||||
CSMPrefs::State::State(const Files::ConfigurationManager& configurationManager)
|
||||
@ -650,6 +556,8 @@ CSMPrefs::State::State(const Files::ConfigurationManager& configurationManager)
|
||||
, mDefaultConfigFile("defaults-cs.bin")
|
||||
, mConfigurationManager(configurationManager)
|
||||
, mCurrentCategory(mCategories.end())
|
||||
, mIndex(std::make_unique<Settings::Index>())
|
||||
, mValues(std::make_unique<Values>(*mIndex))
|
||||
{
|
||||
if (sThis)
|
||||
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)
|
||||
{
|
||||
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);
|
||||
if (container != mCategories.end())
|
||||
{
|
||||
Category settings = container->second;
|
||||
for (Category::Iterator i = settings.begin(); i != settings.end(); ++i)
|
||||
for (Setting* setting : container->second)
|
||||
{
|
||||
(*i)->updateWidget();
|
||||
update(**i);
|
||||
setting->reset();
|
||||
update(*setting);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,11 @@
|
||||
|
||||
class QColor;
|
||||
|
||||
namespace Settings
|
||||
{
|
||||
class Index;
|
||||
}
|
||||
|
||||
namespace CSMPrefs
|
||||
{
|
||||
class IntSetting;
|
||||
@ -27,6 +32,8 @@ namespace CSMPrefs
|
||||
class ModifierSetting;
|
||||
class Setting;
|
||||
class StringSetting;
|
||||
class EnumSettingValue;
|
||||
struct Values;
|
||||
|
||||
/// \brief User settings state
|
||||
///
|
||||
@ -50,43 +57,40 @@ namespace CSMPrefs
|
||||
Collection mCategories;
|
||||
Iterator mCurrentCategory;
|
||||
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 declareCategory(const std::string& key);
|
||||
|
||||
IntSetting& declareInt(const std::string& key, const std::string& label, int default_);
|
||||
DoubleSetting& declareDouble(const std::string& key, const std::string& label, double default_);
|
||||
IntSetting& declareInt(Settings::SettingValue<int>& value, const QString& label);
|
||||
|
||||
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(
|
||||
const std::string& key, const std::string& label, const QKeySequence& default_);
|
||||
ColourSetting& declareColour(const std::string& key, const QString& label, QColor 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 setDefault(const std::string& key, const std::string& default_);
|
||||
void declareSubcategory(const QString& label);
|
||||
|
||||
public:
|
||||
State(const Files::ConfigurationManager& configurationManager);
|
||||
|
||||
State(const State&) = delete;
|
||||
|
||||
~State();
|
||||
|
||||
State& operator=(const State&) = delete;
|
||||
|
||||
void save();
|
||||
|
||||
Iterator begin();
|
||||
|
@ -12,9 +12,8 @@
|
||||
#include "state.hpp"
|
||||
|
||||
CSMPrefs::StringSetting::StringSetting(
|
||||
Category* parent, QMutex* mutex, const std::string& key, const std::string& label, std::string_view default_)
|
||||
: Setting(parent, mutex, key, label)
|
||||
, mDefault(default_)
|
||||
Category* parent, QMutex* mutex, std::string_view key, const QString& label, Settings::Index& index)
|
||||
: TypedSetting(parent, mutex, key, label, index)
|
||||
, mWidget(nullptr)
|
||||
{
|
||||
}
|
||||
@ -25,9 +24,9 @@ CSMPrefs::StringSetting& CSMPrefs::StringSetting::setTooltip(const std::string&
|
||||
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())
|
||||
{
|
||||
@ -37,23 +36,17 @@ std::pair<QWidget*, QWidget*> CSMPrefs::StringSetting::makeWidgets(QWidget* pare
|
||||
|
||||
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()
|
||||
{
|
||||
if (mWidget)
|
||||
{
|
||||
mWidget->setText(QString::fromStdString(Settings::Manager::getString(getKey(), getParent()->getKey())));
|
||||
}
|
||||
mWidget->setText(QString::fromStdString(getValue()));
|
||||
}
|
||||
|
||||
void CSMPrefs::StringSetting::textChanged(const QString& text)
|
||||
{
|
||||
{
|
||||
QMutexLocker lock(getMutex());
|
||||
Settings::Manager::setString(getKey(), getParent()->getKey(), text.toStdString());
|
||||
}
|
||||
|
||||
setValue(text.toStdString());
|
||||
getParent()->getState()->update(*this);
|
||||
}
|
||||
|
@ -14,22 +14,22 @@ class QWidget;
|
||||
namespace CSMPrefs
|
||||
{
|
||||
class Category;
|
||||
class StringSetting : public Setting
|
||||
|
||||
class StringSetting final : public TypedSetting<std::string>
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
std::string mTooltip;
|
||||
std::string mDefault;
|
||||
QLineEdit* mWidget;
|
||||
|
||||
public:
|
||||
StringSetting(Category* parent, QMutex* mutex, const std::string& key, const std::string& label,
|
||||
std::string_view default_);
|
||||
explicit StringSetting(
|
||||
Category* parent, QMutex* mutex, std::string_view key, const QString& label, Settings::Index& index);
|
||||
|
||||
StringSetting& setTooltip(const std::string& tooltip);
|
||||
|
||||
/// Return label, input widget.
|
||||
std::pair<QWidget*, QWidget*> makeWidgets(QWidget* parent) override;
|
||||
SettingWidgets makeWidgets(QWidget* parent) 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&>(
|
||||
*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();
|
||||
|
||||
// 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);
|
||||
|
||||
// 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);
|
||||
|
||||
if (race.mData.mHeight.mFemale <= 0)
|
||||
if (race.mData.mFemaleHeight <= 0)
|
||||
messages.add(id, "Female height is non-positive", "", CSMDoc::Message::Severity_Error);
|
||||
|
||||
// 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);
|
||||
|
||||
if (race.mData.mWeight.mFemale < 0)
|
||||
if (race.mData.mFemaleWeight < 0)
|
||||
messages.add(id, "Female weight is negative", "", CSMDoc::Message::Severity_Error);
|
||||
|
||||
/// \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)
|
||||
{
|
||||
if (npc.mNpdt.mStrength == 0)
|
||||
messages.add(id, "Strength is equal to zero", "", CSMDoc::Message::Severity_Warning);
|
||||
if (npc.mNpdt.mIntelligence == 0)
|
||||
messages.add(id, "Intelligence is equal to zero", "", CSMDoc::Message::Severity_Warning);
|
||||
if (npc.mNpdt.mWillpower == 0)
|
||||
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);
|
||||
for (size_t i = 0; i < npc.mNpdt.mAttributes.size(); ++i)
|
||||
{
|
||||
if (npc.mNpdt.mAttributes[i] == 0)
|
||||
messages.add(id, ESM::Attribute::indexToRefId(i).getRefIdString() + " is equal to zero", {},
|
||||
CSMDoc::Message::Severity_Warning);
|
||||
}
|
||||
}
|
||||
|
||||
if (level <= 0)
|
||||
|
@ -98,9 +98,8 @@ void CSMTools::ReferenceCheckStage::perform(int stage, CSMDoc::Messages& message
|
||||
if (cellRef.mEnchantmentCharge < -1)
|
||||
messages.add(id, "Negative number of enchantment points", "", CSMDoc::Message::Severity_Error);
|
||||
|
||||
// Check if gold value isn't negative
|
||||
if (cellRef.mGoldValue < 0)
|
||||
messages.add(id, "Negative gold value", "", CSMDoc::Message::Severity_Error);
|
||||
if (cellRef.mCount < 1)
|
||||
messages.add(id, "Reference without count", {}, CSMDoc::Message::Severity_Error);
|
||||
}
|
||||
|
||||
int CSMTools::ReferenceCheckStage::setup()
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include <apps/opencs/model/prefs/state.hpp>
|
||||
#include <apps/opencs/model/world/columns.hpp>
|
||||
#include <apps/opencs/model/world/idcollection.hpp>
|
||||
#include <apps/opencs/model/world/record.hpp>
|
||||
@ -132,11 +133,11 @@ namespace CSMWorld
|
||||
bool beast = mRaceData ? mRaceData->isBeast() : false;
|
||||
|
||||
if (beast)
|
||||
return Settings::Manager::getString("baseanimkna", "Models");
|
||||
return CSMPrefs::get()["Models"]["baseanimkna"].toString();
|
||||
else if (mFemale)
|
||||
return Settings::Manager::getString("baseanimfemale", "Models");
|
||||
return CSMPrefs::get()["Models"]["baseanimfemale"].toString();
|
||||
else
|
||||
return Settings::Manager::getString("baseanim", "Models");
|
||||
return CSMPrefs::get()["Models"]["baseanim"].toString();
|
||||
}
|
||||
|
||||
ESM::RefId ActorAdapter::ActorData::getPart(ESM::PartReferenceType index) const
|
||||
|
@ -333,6 +333,37 @@ namespace CSMWorld
|
||||
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)
|
||||
{
|
||||
int index = ESM::Skill::refIdToIndex(ESM::RefId::stringRefId(value));
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <components/esm3/loadinfo.hpp>
|
||||
#include <components/esm3/loadrace.hpp>
|
||||
#include <components/esm3/loadskil.hpp>
|
||||
#include <components/esm3/selectiongroup.hpp>
|
||||
#include <components/esm3/variant.hpp>
|
||||
|
||||
#include <optional>
|
||||
@ -570,19 +571,34 @@ namespace CSMWorld
|
||||
|
||||
QVariant get(const Record<ESXRecordT>& record) const override
|
||||
{
|
||||
const ESM::Race::MaleFemaleF& value = mWeight ? record.get().mData.mWeight : record.get().mData.mHeight;
|
||||
|
||||
return mMale ? value.mMale : value.mFemale;
|
||||
if (mWeight)
|
||||
{
|
||||
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
|
||||
{
|
||||
ESXRecordT record2 = record.get();
|
||||
|
||||
ESM::Race::MaleFemaleF& value = mWeight ? record2.mData.mWeight : record2.mData.mHeight;
|
||||
|
||||
(mMale ? value.mMale : value.mFemale) = data.toFloat();
|
||||
|
||||
if (mWeight)
|
||||
{
|
||||
if (mMale)
|
||||
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);
|
||||
}
|
||||
|
||||
@ -1095,19 +1111,19 @@ namespace CSMWorld
|
||||
};
|
||||
|
||||
template <typename ESXRecordT>
|
||||
struct GoldValueColumn : public Column<ESXRecordT>
|
||||
struct StackSizeColumn : public Column<ESXRecordT>
|
||||
{
|
||||
GoldValueColumn()
|
||||
: Column<ESXRecordT>(Columns::ColumnId_CoinValue, ColumnBase::Display_Integer)
|
||||
StackSizeColumn()
|
||||
: 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
|
||||
{
|
||||
ESXRecordT record2 = record.get();
|
||||
record2.mGoldValue = data.toInt();
|
||||
record2.mCount = data.toInt();
|
||||
record.setModified(record2);
|
||||
}
|
||||
|
||||
@ -2376,6 +2392,17 @@ namespace CSMWorld
|
||||
void set(Record<ESM::BodyPart>& record, const QVariant& data) 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.
|
||||
|
@ -56,7 +56,7 @@ namespace CSMWorld
|
||||
{ ColumnId_FactionIndex, "Faction Index" },
|
||||
{ ColumnId_Charges, "Charges" },
|
||||
{ ColumnId_Enchantment, "Enchantment" },
|
||||
{ ColumnId_CoinValue, "Coin Value" },
|
||||
{ ColumnId_StackCount, "Count" },
|
||||
{ ColumnId_Teleport, "Teleport" },
|
||||
{ ColumnId_TeleportCell, "Teleport Cell" },
|
||||
{ ColumnId_LockLevel, "Lock Level" },
|
||||
|
@ -45,7 +45,7 @@ namespace CSMWorld
|
||||
ColumnId_FactionIndex = 31,
|
||||
ColumnId_Charges = 32,
|
||||
ColumnId_Enchantment = 33,
|
||||
ColumnId_CoinValue = 34,
|
||||
ColumnId_StackCount = 34,
|
||||
ColumnId_Teleport = 35,
|
||||
ColumnId_TeleportCell = 36,
|
||||
ColumnId_LockLevel = 37,
|
||||
@ -347,6 +347,8 @@ namespace CSMWorld
|
||||
|
||||
ColumnId_LevelledCreatureId = 315,
|
||||
|
||||
ColumnId_SelectionGroupObjects = 316,
|
||||
|
||||
// Allocated to a separate value range, so we don't get a collision should we ever need
|
||||
// to extend the number of use values.
|
||||
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 ChargesColumn<CellRef>);
|
||||
mRefs.addColumn(new EnchantmentChargesColumn<CellRef>);
|
||||
mRefs.addColumn(new GoldValueColumn<CellRef>);
|
||||
mRefs.addColumn(new StackSizeColumn<CellRef>);
|
||||
mRefs.addColumn(new TeleportColumn<CellRef>);
|
||||
mRefs.addColumn(new TeleportCellColumn<CellRef>);
|
||||
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 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.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_Videos)), UniversalId::Type_Video);
|
||||
addModel(new IdTable(&mMetaData), UniversalId::Type_MetaData);
|
||||
addModel(new IdTable(&mSelectionGroups), UniversalId::Type_SelectionGroup);
|
||||
|
||||
mActorAdapter = std::make_unique<ActorAdapter>(*this);
|
||||
|
||||
@ -908,6 +914,16 @@ CSMWorld::IdCollection<ESM::DebugProfile>& CSMWorld::Data::getDebugProfiles()
|
||||
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
|
||||
{
|
||||
return mLand;
|
||||
@ -1369,6 +1385,17 @@ bool CSMWorld::Data::continueLoading(CSMDoc::Messages& messages)
|
||||
mDebugProfiles.load(*mReader, mBase);
|
||||
break;
|
||||
|
||||
case ESM::REC_SELG:
|
||||
|
||||
if (!mProject)
|
||||
{
|
||||
unhandledRecord = true;
|
||||
break;
|
||||
}
|
||||
|
||||
mSelectionGroups.load(*mReader, mBase);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
unhandledRecord = true;
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include <components/esm3/loadsoun.hpp>
|
||||
#include <components/esm3/loadspel.hpp>
|
||||
#include <components/esm3/loadsscr.hpp>
|
||||
#include <components/esm3/selectiongroup.hpp>
|
||||
#include <components/files/multidircollection.hpp>
|
||||
#include <components/misc/algorithm.hpp>
|
||||
#include <components/to_utf8/to_utf8.hpp>
|
||||
@ -105,6 +106,7 @@ namespace CSMWorld
|
||||
IdCollection<ESM::BodyPart> mBodyParts;
|
||||
IdCollection<ESM::MagicEffect> mMagicEffects;
|
||||
IdCollection<ESM::DebugProfile> mDebugProfiles;
|
||||
IdCollection<ESM::SelectionGroup> mSelectionGroups;
|
||||
IdCollection<ESM::SoundGenerator> mSoundGens;
|
||||
IdCollection<ESM::StartScript> mStartScripts;
|
||||
NestedInfoCollection mTopicInfos;
|
||||
@ -251,6 +253,10 @@ namespace CSMWorld
|
||||
|
||||
IdCollection<ESM::DebugProfile>& getDebugProfiles();
|
||||
|
||||
const IdCollection<ESM::SelectionGroup>& getSelectionGroups() const;
|
||||
|
||||
IdCollection<ESM::SelectionGroup>& getSelectionGroups();
|
||||
|
||||
const IdCollection<CSMWorld::Land>& getLand() const;
|
||||
|
||||
IdCollection<CSMWorld::Land>& getLand();
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user