mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-03-20 19:21:13 +00:00
Merge branch 'master' of gitlab.com:openmw/openmw into lua_controller_cursor
This commit is contained in:
commit
f3229f8674
@ -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.
|
||||
|
@ -245,6 +245,7 @@ Programmers
|
||||
xyzz
|
||||
Yohaulticetl
|
||||
Yuri Krupenin
|
||||
Yury Stepovikov
|
||||
zelurker
|
||||
|
||||
Documentation
|
||||
|
36
CHANGELOG.md
36
CHANGELOG.md
@ -10,11 +10,15 @@
|
||||
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
|
||||
@ -28,12 +32,15 @@
|
||||
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 #6402: The sound of a thunderstorm does not stop playing after entering the premises
|
||||
Bug #6427: Enemy health bar disappears before damaging effect ends
|
||||
Bug #6550: Cloned body parts don't inherit texture effects
|
||||
Bug #6645: Enemy block sounds align with animation instead of blocked hits
|
||||
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
|
||||
@ -58,6 +65,7 @@
|
||||
Bug #7084: Resurrecting an actor doesn't take into account base record changes
|
||||
Bug #7088: Deleting last save game of last character doesn't clear character name/details
|
||||
Bug #7092: BSA archives from higher priority directories don't take priority
|
||||
Bug #7103: Multiple paths pointing to the same plugin but with different cases lead to automatically removed config entries
|
||||
Bug #7122: Teleportation to underwater should cancel active water walking effect
|
||||
Bug #7131: MyGUI log spam when post processing HUD is open
|
||||
Bug #7134: Saves with an invalid last generated RefNum can be loaded
|
||||
@ -67,38 +75,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 #7617: The death prompt asks the player if they wanted to load the character's last created save
|
||||
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 #7733: Launcher shows incorrect data paths when there's two plugins with the same name
|
||||
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
|
||||
Bug #7761: Rain and ambient loop sounds are mutually exclusive
|
||||
Bug #7770: Sword of the Perithia: Script execution failure
|
||||
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
|
||||
@ -127,14 +160,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,31 +1,26 @@
|
||||
#!/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
|
||||
command -v qmake >/dev/null 2>&1 || brew install qt@5
|
||||
export PATH="/opt/homebrew/opt/qt@5/bin:$PATH"
|
||||
|
||||
|
||||
# Install deps
|
||||
brew install icu4c yaml-cpp sqlite
|
||||
brew install openal-soft icu4c yaml-cpp sqlite
|
||||
|
||||
ccache --version
|
||||
cmake --version
|
||||
|
@ -902,7 +902,6 @@ printf "Qt ${QT_VER}... "
|
||||
fi
|
||||
|
||||
cd $QT_SDK
|
||||
add_cmake_opts -DQT_QMAKE_EXECUTABLE="${QT_SDK}/bin/qmake.exe"
|
||||
for CONFIGURATION in ${CONFIGURATIONS[@]}; do
|
||||
if [ $CONFIGURATION == "Debug" ]; then
|
||||
DLLSUFFIX="d"
|
||||
|
@ -10,12 +10,13 @@ DEPENDENCIES_ROOT="/tmp/openmw-deps"
|
||||
|
||||
QT_PATH=$(brew --prefix qt@5)
|
||||
ICU_PATH=$(brew --prefix icu4c)
|
||||
OPENAL_PATH=$(brew --prefix openal-soft)
|
||||
CCACHE_EXECUTABLE=$(brew --prefix ccache)/bin/ccache
|
||||
mkdir build
|
||||
cd build
|
||||
|
||||
cmake \
|
||||
-D CMAKE_PREFIX_PATH="$DEPENDENCIES_ROOT;$QT_PATH" \
|
||||
-D CMAKE_PREFIX_PATH="$DEPENDENCIES_ROOT;$QT_PATH;$OPENAL_PATH" \
|
||||
-D CMAKE_C_COMPILER_LAUNCHER="$CCACHE_EXECUTABLE" \
|
||||
-D CMAKE_CXX_COMPILER_LAUNCHER="$CCACHE_EXECUTABLE" \
|
||||
-D CMAKE_CXX_FLAGS="-stdlib=libc++" \
|
||||
|
@ -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
|
||||
|
@ -1,4 +1,4 @@
|
||||
set -e
|
||||
#!/bin/bash -e
|
||||
|
||||
docs/source/install_luadocumentor_in_docker.sh
|
||||
PATH=$PATH:~/luarocks/bin
|
||||
|
@ -54,6 +54,7 @@ IF(NOT CMAKE_BUILD_TYPE)
|
||||
ENDIF()
|
||||
|
||||
if (APPLE)
|
||||
set(CMAKE_FIND_FRAMEWORK LAST) # prefer dylibs over frameworks
|
||||
set(APP_BUNDLE_NAME "${CMAKE_PROJECT_NAME}.app")
|
||||
|
||||
set(APP_BUNDLE_DIR "${OpenMW_BINARY_DIR}/${APP_BUNDLE_NAME}")
|
||||
|
@ -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.
|
||||
|
@ -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,
|
||||
|
@ -16,7 +16,7 @@ namespace ESSImport
|
||||
objstate.blank();
|
||||
objstate.mRef = item;
|
||||
objstate.mRef.mRefID = ESM::RefId::stringRefId(item.mId);
|
||||
objstate.mCount = item.mCount;
|
||||
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})
|
||||
|
@ -125,27 +125,6 @@ namespace Launcher
|
||||
{
|
||||
return Settings::navigator().mMaxNavmeshdbFileSize / (1024 * 1024);
|
||||
}
|
||||
|
||||
std::optional<QString> findFirstPath(const QStringList& directories, const QString& fileName)
|
||||
{
|
||||
for (const QString& directoryPath : directories)
|
||||
{
|
||||
const QString filePath = QDir(directoryPath).absoluteFilePath(fileName);
|
||||
if (QFile::exists(filePath))
|
||||
return filePath;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
QStringList findAllFilePaths(const QStringList& directories, const QStringList& fileNames)
|
||||
{
|
||||
QStringList result;
|
||||
result.reserve(fileNames.size());
|
||||
for (const QString& fileName : fileNames)
|
||||
if (const auto filepath = findFirstPath(directories, fileName))
|
||||
result.append(*filepath);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -164,11 +143,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 +236,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 +291,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
|
||||
@ -353,8 +345,7 @@ void Launcher::DataFilesPage::populateFileViews(const QString& contentModelName)
|
||||
row++;
|
||||
}
|
||||
|
||||
mSelector->setProfileContent(
|
||||
findAllFilePaths(directories, mLauncherSettings.getContentListFiles(contentModelName)));
|
||||
mSelector->setProfileContent(mLauncherSettings.getContentListFiles(contentModelName));
|
||||
}
|
||||
|
||||
void Launcher::DataFilesPage::saveSettings(const QString& profile)
|
||||
@ -384,7 +375,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);
|
||||
|
||||
@ -737,8 +728,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -154,8 +154,13 @@ bool Launcher::GraphicsPage::loadSettings()
|
||||
if (Settings::shadows().mEnableIndoorShadows)
|
||||
indoorShadowsCheckBox->setCheckState(Qt::Checked);
|
||||
|
||||
shadowComputeSceneBoundsComboBox->setCurrentIndex(
|
||||
shadowComputeSceneBoundsComboBox->findText(QString(tr(Settings::shadows().mComputeSceneBounds.get().c_str()))));
|
||||
const auto& boundMethod = Settings::shadows().mComputeSceneBounds.get();
|
||||
if (boundMethod == "bounds")
|
||||
shadowComputeSceneBoundsComboBox->setCurrentIndex(0);
|
||||
else if (boundMethod == "primitives")
|
||||
shadowComputeSceneBoundsComboBox->setCurrentIndex(1);
|
||||
else
|
||||
shadowComputeSceneBoundsComboBox->setCurrentIndex(2);
|
||||
|
||||
const int shadowDistLimit = Settings::shadows().mMaximumShadowMapDistance;
|
||||
if (shadowDistLimit > 0)
|
||||
@ -254,7 +259,14 @@ void Launcher::GraphicsPage::saveSettings()
|
||||
|
||||
Settings::shadows().mEnableIndoorShadows.set(indoorShadowsCheckBox->checkState() != Qt::Unchecked);
|
||||
Settings::shadows().mShadowMapResolution.set(shadowResolutionComboBox->currentText().toInt());
|
||||
Settings::shadows().mComputeSceneBounds.set(shadowComputeSceneBoundsComboBox->currentText().toStdString());
|
||||
|
||||
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)
|
||||
|
@ -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;
|
||||
|
@ -41,11 +41,6 @@ int runLauncher(int argc, char* argv[])
|
||||
appTranslator.load(":/translations/" + locale + ".qm");
|
||||
app.installTranslator(&appTranslator);
|
||||
|
||||
// Now we make sure the current dir is set to application path
|
||||
QDir dir(QCoreApplication::applicationDirPath());
|
||||
|
||||
QDir::setCurrent(dir.absolutePath());
|
||||
|
||||
Launcher::MainDialog mainWin(configurationManager);
|
||||
|
||||
Launcher::FirstRunDialogResult result = mainWin.showFirstRunDialog();
|
||||
|
@ -118,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;
|
||||
}
|
||||
}
|
||||
@ -136,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?!
|
||||
@ -297,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;
|
||||
@ -327,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 {};
|
||||
}
|
||||
@ -388,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);
|
||||
@ -419,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;
|
||||
}
|
||||
@ -457,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;
|
||||
}
|
||||
}
|
||||
@ -479,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;
|
||||
}
|
||||
@ -510,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;
|
||||
}
|
||||
@ -562,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;
|
||||
}
|
||||
|
@ -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>
|
@ -107,7 +107,7 @@
|
||||
<item>
|
||||
<widget class="QLabel" name="multiplyLabel">
|
||||
<property name="text">
|
||||
<string> x </string>
|
||||
<string> × </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
@ -1,7 +1,7 @@
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
#include <apps/openmw/mwsound/alext.h>
|
||||
#include "apps/openmw/mwsound/alext.h"
|
||||
|
||||
#include "openalutil.hpp"
|
||||
|
||||
|
@ -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;
|
||||
|
@ -1,5 +1,4 @@
|
||||
set (OPENCS_SRC
|
||||
${CMAKE_SOURCE_DIR}/files/windows/opencs.rc
|
||||
)
|
||||
|
||||
opencs_units (. editor)
|
||||
@ -116,7 +115,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,14 +138,16 @@ 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})
|
||||
|
||||
if(WIN32)
|
||||
set(QT_USE_QTMAIN TRUE)
|
||||
set(OPENCS_RC_FILE ${CMAKE_SOURCE_DIR}/files/windows/opencs.rc)
|
||||
else(WIN32)
|
||||
set(OPENCS_RC_FILE "")
|
||||
endif(WIN32)
|
||||
|
||||
if (QT_VERSION_MAJOR VERSION_EQUAL 5)
|
||||
@ -187,6 +188,7 @@ if(BUILD_OPENCS)
|
||||
${OPENCS_CFG}
|
||||
${OPENCS_DEFAULT_FILTERS_FILE}
|
||||
${OPENCS_OPENMW_CFG}
|
||||
${OPENCS_RC_FILE}
|
||||
main.cpp
|
||||
)
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -81,11 +81,6 @@ int runApplication(int argc, char* argv[])
|
||||
|
||||
Application application(argc, argv);
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
QDir dir(QCoreApplication::applicationDirPath());
|
||||
QDir::setCurrent(dir.absolutePath());
|
||||
#endif
|
||||
|
||||
application.setWindowIcon(QIcon(":./openmw-cs.png"));
|
||||
|
||||
CS::Editor editor(argc, argv);
|
||||
|
@ -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, std::string_view 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);
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <QColor>
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
class QMutex;
|
||||
@ -20,22 +21,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, std::string_view 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);
|
||||
|
@ -43,7 +43,7 @@ namespace CSMPrefs
|
||||
mEventHandler->removeShortcut(shortcut);
|
||||
}
|
||||
|
||||
bool ShortcutManager::getSequence(const std::string& name, QKeySequence& sequence) const
|
||||
bool ShortcutManager::getSequence(std::string_view name, QKeySequence& sequence) const
|
||||
{
|
||||
SequenceMap::const_iterator item = mSequences.find(name);
|
||||
if (item != mSequences.end())
|
||||
@ -56,7 +56,7 @@ namespace CSMPrefs
|
||||
return false;
|
||||
}
|
||||
|
||||
void ShortcutManager::setSequence(const std::string& name, const QKeySequence& sequence)
|
||||
void ShortcutManager::setSequence(std::string_view name, const QKeySequence& sequence)
|
||||
{
|
||||
// Add to map/modify
|
||||
SequenceMap::iterator item = mSequences.find(name);
|
||||
@ -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);
|
||||
|
@ -28,11 +28,11 @@ namespace CSMPrefs
|
||||
/// The shortcut class will do this automatically
|
||||
void removeShortcut(Shortcut* shortcut);
|
||||
|
||||
bool getSequence(const std::string& name, QKeySequence& sequence) const;
|
||||
void setSequence(const std::string& name, const QKeySequence& sequence);
|
||||
bool getSequence(std::string_view name, QKeySequence& sequence) const;
|
||||
void setSequence(std::string_view 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::map<std::string, QKeySequence> SequenceMap;
|
||||
typedef std::map<std::string, int> ModifierMap;
|
||||
typedef std::multimap<std::string, Shortcut*, std::less<>> ShortcutMap;
|
||||
typedef std::map<std::string, QKeySequence, std::less<>> SequenceMap;
|
||||
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, std::string_view 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);
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define CSM_PREFS_SHORTCUTSETTING_H
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
#include <QKeySequence>
|
||||
@ -17,14 +18,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, 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;
|
||||
|
||||
|
@ -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,378 +69,343 @@ 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);
|
||||
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"));
|
||||
declareColour("colour-keyword", "Highlight Colour: Keywords", QColor("red"));
|
||||
declareColour("colour-special", "Highlight Colour: Special Characters", QColor("darkorange"));
|
||||
declareColour("colour-comment", "Highlight Colour: Comments", QColor("green"));
|
||||
declareColour("colour-id", "Highlight Colour: IDs", QColor("blue"));
|
||||
declareInt(mValues->mScripts.mErrorHeight, "Initial height of the error panel").setRange(100, 10000);
|
||||
declareBool(mValues->mScripts.mHighlightOccurrences, "Highlight other occurrences of selected names");
|
||||
declareColour(mValues->mScripts.mColourHighlight, "Colour of highlighted occurrences");
|
||||
declareColour(mValues->mScripts.mColourInt, "Highlight Colour: Integer Literals");
|
||||
declareColour(mValues->mScripts.mColourFloat, "Highlight Colour: Float Literals");
|
||||
declareColour(mValues->mScripts.mColourName, "Highlight Colour: Names");
|
||||
declareColour(mValues->mScripts.mColourKeyword, "Highlight Colour: Keywords");
|
||||
declareColour(mValues->mScripts.mColourSpecial, "Highlight Colour: Special Characters");
|
||||
declareColour(mValues->mScripts.mColourComment, "Highlight Colour: Comments");
|
||||
declareColour(mValues->mScripts.mColourId, "Highlight Colour: IDs");
|
||||
|
||||
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);
|
||||
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))
|
||||
declareDouble(mValues->mRendering.mObjectMarkerAlpha, "Object Marker Transparency").setPrecision(2).setRange(0, 1);
|
||||
declareBool(mValues->mRendering.mSceneUseGradient, "Use Gradient Background");
|
||||
declareColour(mValues->mRendering.mSceneDayBackgroundColour, "Day Background Colour");
|
||||
declareColour(mValues->mRendering.mSceneDayGradientColour, "Day Gradient Colour")
|
||||
.setTooltip(
|
||||
"Sets the gradient color to use in conjunction with the day background color. Ignored if "
|
||||
"the gradient option is disabled.");
|
||||
declareColour("scene-bright-background-colour", "Scene Bright Background Colour", QColor(79, 87, 92, 255));
|
||||
declareColour("scene-bright-gradient-colour", "Scene Bright Gradient Colour", QColor(47, 51, 51, 255))
|
||||
declareColour(mValues->mRendering.mSceneBrightBackgroundColour, "Scene Bright Background Colour");
|
||||
declareColour(mValues->mRendering.mSceneBrightGradientColour, "Scene Bright Gradient Colour")
|
||||
.setTooltip(
|
||||
"Sets the gradient color to use in conjunction with the bright background color. Ignored if "
|
||||
"the gradient option is disabled.");
|
||||
declareColour("scene-night-background-colour", "Scene Night Background Colour", QColor(64, 77, 79, 255));
|
||||
declareColour("scene-night-gradient-colour", "Scene Night Gradient Colour", QColor(47, 51, 51, 255))
|
||||
declareColour(mValues->mRendering.mSceneNightBackgroundColour, "Scene Night Background Colour");
|
||||
declareColour(mValues->mRendering.mSceneNightGradientColour, "Scene Night Gradient Colour")
|
||||
.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");
|
||||
|
||||
declareSubcategory("Document");
|
||||
declareShortcut("document-file-newgame", "New Game", QKeySequence(Qt::ControlModifier | Qt::Key_N));
|
||||
declareShortcut("document-file-newaddon", "New Addon", QKeySequence());
|
||||
declareShortcut("document-file-open", "Open", QKeySequence(Qt::ControlModifier | Qt::Key_O));
|
||||
declareShortcut("document-file-save", "Save", QKeySequence(Qt::ControlModifier | Qt::Key_S));
|
||||
declareShortcut("document-help-help", "Help", QKeySequence(Qt::Key_F1));
|
||||
declareShortcut("document-help-tutorial", "Tutorial", QKeySequence());
|
||||
declareShortcut("document-file-verify", "Verify", QKeySequence());
|
||||
declareShortcut("document-file-merge", "Merge", QKeySequence());
|
||||
declareShortcut("document-file-errorlog", "Open Load Error Log", QKeySequence());
|
||||
declareShortcut("document-file-metadata", "Meta Data", QKeySequence());
|
||||
declareShortcut("document-file-close", "Close Document", QKeySequence(Qt::ControlModifier | Qt::Key_W));
|
||||
declareShortcut("document-file-exit", "Exit Application", QKeySequence(Qt::ControlModifier | Qt::Key_Q));
|
||||
declareShortcut("document-edit-undo", "Undo", QKeySequence(Qt::ControlModifier | Qt::Key_Z));
|
||||
declareShortcut("document-edit-redo", "Redo", QKeySequence(Qt::ControlModifier | Qt::ShiftModifier | Qt::Key_Z));
|
||||
declareShortcut("document-edit-preferences", "Open Preferences", QKeySequence());
|
||||
declareShortcut("document-edit-search", "Search", QKeySequence(Qt::ControlModifier | Qt::Key_F));
|
||||
declareShortcut("document-view-newview", "New View", QKeySequence());
|
||||
declareShortcut("document-view-statusbar", "Toggle Status Bar", QKeySequence());
|
||||
declareShortcut("document-view-filters", "Open Filter List", QKeySequence());
|
||||
declareShortcut("document-world-regions", "Open Region List", QKeySequence());
|
||||
declareShortcut("document-world-cells", "Open Cell List", QKeySequence());
|
||||
declareShortcut("document-world-referencables", "Open Object List", QKeySequence());
|
||||
declareShortcut("document-world-references", "Open Instance List", QKeySequence());
|
||||
declareShortcut("document-world-lands", "Open Lands List", QKeySequence());
|
||||
declareShortcut("document-world-landtextures", "Open Land Textures List", QKeySequence());
|
||||
declareShortcut("document-world-pathgrid", "Open Pathgrid List", QKeySequence());
|
||||
declareShortcut("document-world-regionmap", "Open Region Map", QKeySequence());
|
||||
declareShortcut("document-mechanics-globals", "Open Global List", QKeySequence());
|
||||
declareShortcut("document-mechanics-gamesettings", "Open Game Settings", QKeySequence());
|
||||
declareShortcut("document-mechanics-scripts", "Open Script List", QKeySequence());
|
||||
declareShortcut("document-mechanics-spells", "Open Spell List", QKeySequence());
|
||||
declareShortcut("document-mechanics-enchantments", "Open Enchantment List", QKeySequence());
|
||||
declareShortcut("document-mechanics-magiceffects", "Open Magic Effect List", QKeySequence());
|
||||
declareShortcut("document-mechanics-startscripts", "Open Start Script List", QKeySequence());
|
||||
declareShortcut("document-character-skills", "Open Skill List", QKeySequence());
|
||||
declareShortcut("document-character-classes", "Open Class List", QKeySequence());
|
||||
declareShortcut("document-character-factions", "Open Faction List", QKeySequence());
|
||||
declareShortcut("document-character-races", "Open Race List", QKeySequence());
|
||||
declareShortcut("document-character-birthsigns", "Open Birthsign List", QKeySequence());
|
||||
declareShortcut("document-character-topics", "Open Topic List", QKeySequence());
|
||||
declareShortcut("document-character-journals", "Open Journal List", QKeySequence());
|
||||
declareShortcut("document-character-topicinfos", "Open Topic Info List", QKeySequence());
|
||||
declareShortcut("document-character-journalinfos", "Open Journal Info List", QKeySequence());
|
||||
declareShortcut("document-character-bodyparts", "Open Body Part List", QKeySequence());
|
||||
declareShortcut("document-assets-reload", "Reload Assets", QKeySequence(Qt::Key_F5));
|
||||
declareShortcut("document-assets-sounds", "Open Sound Asset List", QKeySequence());
|
||||
declareShortcut("document-assets-soundgens", "Open Sound Generator List", QKeySequence());
|
||||
declareShortcut("document-assets-meshes", "Open Mesh Asset List", QKeySequence());
|
||||
declareShortcut("document-assets-icons", "Open Icon Asset List", QKeySequence());
|
||||
declareShortcut("document-assets-music", "Open Music Asset List", QKeySequence());
|
||||
declareShortcut("document-assets-soundres", "Open Sound File List", QKeySequence());
|
||||
declareShortcut("document-assets-textures", "Open Texture Asset List", QKeySequence());
|
||||
declareShortcut("document-assets-videos", "Open Video Asset List", QKeySequence());
|
||||
declareShortcut("document-debug-run", "Run Debug", QKeySequence());
|
||||
declareShortcut("document-debug-shutdown", "Stop Debug", QKeySequence());
|
||||
declareShortcut("document-debug-profiles", "Debug Profiles", QKeySequence());
|
||||
declareShortcut("document-debug-runlog", "Open Run Log", QKeySequence());
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentFileNewgame, "New Game");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentFileNewaddon, "New Addon");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentFileOpen, "Open");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentFileSave, "Save");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentHelpHelp, "Help");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentHelpTutorial, "Tutorial");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentFileVerify, "Verify");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentFileMerge, "Merge");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentFileErrorlog, "Open Load Error Log");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentFileMetadata, "Meta Data");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentFileClose, "Close Document");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentFileExit, "Exit Application");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentEditUndo, "Undo");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentEditRedo, "Redo");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentEditPreferences, "Open Preferences");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentEditSearch, "Search");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentViewNewview, "New View");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentViewStatusbar, "Toggle Status Bar");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentViewFilters, "Open Filter List");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentWorldRegions, "Open Region List");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentWorldCells, "Open Cell List");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentWorldReferencables, "Open Object List");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentWorldReferences, "Open Instance List");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentWorldLands, "Open Lands List");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentWorldLandtextures, "Open Land Textures List");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentWorldPathgrid, "Open Pathgrid List");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentWorldRegionmap, "Open Region Map");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentMechanicsGlobals, "Open Global List");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentMechanicsGamesettings, "Open Game Settings");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentMechanicsScripts, "Open Script List");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentMechanicsSpells, "Open Spell List");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentMechanicsEnchantments, "Open Enchantment List");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentMechanicsMagiceffects, "Open Magic Effect List");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentMechanicsStartscripts, "Open Start Script List");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentCharacterSkills, "Open Skill List");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentCharacterClasses, "Open Class List");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentCharacterFactions, "Open Faction List");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentCharacterRaces, "Open Race List");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentCharacterBirthsigns, "Open Birthsign List");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentCharacterTopics, "Open Topic List");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentCharacterJournals, "Open Journal List");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentCharacterTopicinfos, "Open Topic Info List");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentCharacterJournalinfos, "Open Journal Info List");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentCharacterBodyparts, "Open Body Part List");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentAssetsReload, "Reload Assets");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentAssetsSounds, "Open Sound Asset List");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentAssetsSoundgens, "Open Sound Generator List");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentAssetsMeshes, "Open Mesh Asset List");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentAssetsIcons, "Open Icon Asset List");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentAssetsMusic, "Open Music Asset List");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentAssetsSoundres, "Open Sound File List");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentAssetsTextures, "Open Texture Asset List");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentAssetsVideos, "Open Video Asset List");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentDebugRun, "Run Debug");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentDebugShutdown, "Stop Debug");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentDebugProfiles, "Debug Profiles");
|
||||
declareShortcut(mValues->mKeyBindings.mDocumentDebugRunlog, "Open Run Log");
|
||||
|
||||
declareSubcategory("Table");
|
||||
declareShortcut("table-edit", "Edit Record", QKeySequence());
|
||||
declareShortcut("table-add", "Add Row/Record", QKeySequence(Qt::ShiftModifier | Qt::Key_A));
|
||||
declareShortcut("table-clone", "Clone Record", QKeySequence(Qt::ShiftModifier | Qt::Key_D));
|
||||
declareShortcut("touch-record", "Touch Record", QKeySequence());
|
||||
declareShortcut("table-revert", "Revert Record", QKeySequence());
|
||||
declareShortcut("table-remove", "Remove Row/Record", QKeySequence(Qt::Key_Delete));
|
||||
declareShortcut("table-moveup", "Move Record Up", QKeySequence());
|
||||
declareShortcut("table-movedown", "Move Record Down", QKeySequence());
|
||||
declareShortcut("table-view", "View Record", QKeySequence(Qt::ShiftModifier | Qt::Key_C));
|
||||
declareShortcut("table-preview", "Preview Record", QKeySequence(Qt::ShiftModifier | Qt::Key_V));
|
||||
declareShortcut("table-extendeddelete", "Extended Record Deletion", QKeySequence());
|
||||
declareShortcut("table-extendedrevert", "Extended Record Revertion", QKeySequence());
|
||||
declareShortcut(mValues->mKeyBindings.mTableEdit, "Edit Record");
|
||||
declareShortcut(mValues->mKeyBindings.mTableAdd, "Add Row/Record");
|
||||
declareShortcut(mValues->mKeyBindings.mTableClone, "Clone Record");
|
||||
declareShortcut(mValues->mKeyBindings.mTouchRecord, "Touch Record");
|
||||
declareShortcut(mValues->mKeyBindings.mTableRevert, "Revert Record");
|
||||
declareShortcut(mValues->mKeyBindings.mTableRemove, "Remove Row/Record");
|
||||
declareShortcut(mValues->mKeyBindings.mTableMoveup, "Move Record Up");
|
||||
declareShortcut(mValues->mKeyBindings.mTableMovedown, "Move Record Down");
|
||||
declareShortcut(mValues->mKeyBindings.mTableView, "View Record");
|
||||
declareShortcut(mValues->mKeyBindings.mTablePreview, "Preview Record");
|
||||
declareShortcut(mValues->mKeyBindings.mTableExtendeddelete, "Extended Record Deletion");
|
||||
declareShortcut(mValues->mKeyBindings.mTableExtendedrevert, "Extended Record Revertion");
|
||||
|
||||
declareSubcategory("Report Table");
|
||||
declareShortcut("reporttable-show", "Show Report", QKeySequence());
|
||||
declareShortcut("reporttable-remove", "Remove Report", QKeySequence(Qt::Key_Delete));
|
||||
declareShortcut("reporttable-replace", "Replace Report", QKeySequence());
|
||||
declareShortcut("reporttable-refresh", "Refresh Report", QKeySequence());
|
||||
declareShortcut(mValues->mKeyBindings.mReporttableShow, "Show Report");
|
||||
declareShortcut(mValues->mKeyBindings.mReporttableRemove, "Remove Report");
|
||||
declareShortcut(mValues->mKeyBindings.mReporttableReplace, "Replace Report");
|
||||
declareShortcut(mValues->mKeyBindings.mReporttableRefresh, "Refresh Report");
|
||||
|
||||
declareSubcategory("Scene");
|
||||
declareShortcut("scene-navi-primary", "Camera Rotation From Mouse Movement", QKeySequence(Qt::LeftButton));
|
||||
declareShortcut("scene-navi-secondary", "Camera Translation From Mouse Movement",
|
||||
QKeySequence(Qt::ControlModifier | (int)Qt::LeftButton));
|
||||
declareShortcut("scene-open-primary", "Primary Open", QKeySequence(Qt::ShiftModifier | (int)Qt::LeftButton));
|
||||
declareShortcut("scene-edit-primary", "Primary Edit", QKeySequence(Qt::RightButton));
|
||||
declareShortcut("scene-edit-secondary", "Secondary Edit", QKeySequence(Qt::ControlModifier | (int)Qt::RightButton));
|
||||
declareShortcut("scene-select-primary", "Primary Select", QKeySequence(Qt::MiddleButton));
|
||||
declareShortcut(
|
||||
"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);
|
||||
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));
|
||||
declareShortcut("scene-instance-drop-terrain-separately", "Drop to terrain level separately", QKeySequence());
|
||||
declareShortcut("scene-instance-drop-collision-separately", "Drop to collision separately", QKeySequence());
|
||||
declareShortcut("scene-load-cam-cell", "Load Camera Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_5));
|
||||
declareShortcut("scene-load-cam-eastcell", "Load East Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_6));
|
||||
declareShortcut("scene-load-cam-northcell", "Load North Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_8));
|
||||
declareShortcut("scene-load-cam-westcell", "Load West Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_4));
|
||||
declareShortcut("scene-load-cam-southcell", "Load South Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_2));
|
||||
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(mValues->mKeyBindings.mSceneNaviPrimary, "Camera Rotation From Mouse Movement");
|
||||
declareShortcut(mValues->mKeyBindings.mSceneNaviSecondary, "Camera Translation From Mouse Movement");
|
||||
declareShortcut(mValues->mKeyBindings.mSceneOpenPrimary, "Primary Open");
|
||||
declareShortcut(mValues->mKeyBindings.mSceneEditPrimary, "Primary Edit");
|
||||
declareShortcut(mValues->mKeyBindings.mSceneEditSecondary, "Secondary Edit");
|
||||
declareShortcut(mValues->mKeyBindings.mSceneSelectPrimary, "Primary Select");
|
||||
declareShortcut(mValues->mKeyBindings.mSceneSelectSecondary, "Secondary Select");
|
||||
declareShortcut(mValues->mKeyBindings.mSceneSelectTertiary, "Tertiary Select");
|
||||
declareModifier(mValues->mKeyBindings.mSceneSpeedModifier, "Speed Modifier");
|
||||
declareShortcut(mValues->mKeyBindings.mSceneDelete, "Delete Instance");
|
||||
declareShortcut(mValues->mKeyBindings.mSceneInstanceDropTerrain, "Drop to terrain level");
|
||||
declareShortcut(mValues->mKeyBindings.mSceneInstanceDropCollision, "Drop to collision");
|
||||
declareShortcut(mValues->mKeyBindings.mSceneInstanceDropTerrainSeparately, "Drop to terrain level separately");
|
||||
declareShortcut(mValues->mKeyBindings.mSceneInstanceDropCollisionSeparately, "Drop to collision separately");
|
||||
declareShortcut(mValues->mKeyBindings.mSceneLoadCamCell, "Load Camera Cell");
|
||||
declareShortcut(mValues->mKeyBindings.mSceneLoadCamEastcell, "Load East Cell");
|
||||
declareShortcut(mValues->mKeyBindings.mSceneLoadCamNorthcell, "Load North Cell");
|
||||
declareShortcut(mValues->mKeyBindings.mSceneLoadCamWestcell, "Load West Cell");
|
||||
declareShortcut(mValues->mKeyBindings.mSceneLoadCamSouthcell, "Load South Cell");
|
||||
declareShortcut(mValues->mKeyBindings.mSceneEditAbort, "Abort");
|
||||
declareShortcut(mValues->mKeyBindings.mSceneFocusToolbar, "Toggle Toolbar Focus");
|
||||
declareShortcut(mValues->mKeyBindings.mSceneRenderStats, "Debug Rendering Stats");
|
||||
declareShortcut(mValues->mKeyBindings.mSceneDuplicate, "Duplicate Instance");
|
||||
declareShortcut(mValues->mKeyBindings.mSceneClearSelection, "Clear Selection");
|
||||
declareShortcut(mValues->mKeyBindings.mSceneUnhideAll, "Unhide All Objects");
|
||||
declareShortcut(mValues->mKeyBindings.mSceneToggleVisibility, "Toggle Selection Visibility");
|
||||
declareShortcut(mValues->mKeyBindings.mSceneGroup0, "Selection Group 0");
|
||||
declareShortcut(mValues->mKeyBindings.mSceneSave0, "Save Group 0");
|
||||
declareShortcut(mValues->mKeyBindings.mSceneGroup1, "Select Group 1");
|
||||
declareShortcut(mValues->mKeyBindings.mSceneSave1, "Save Group 1");
|
||||
declareShortcut(mValues->mKeyBindings.mSceneGroup2, "Select Group 2");
|
||||
declareShortcut(mValues->mKeyBindings.mSceneSave2, "Save Group 2");
|
||||
declareShortcut(mValues->mKeyBindings.mSceneGroup3, "Select Group 3");
|
||||
declareShortcut(mValues->mKeyBindings.mSceneSave3, "Save Group 3");
|
||||
declareShortcut(mValues->mKeyBindings.mSceneGroup4, "Select Group 4");
|
||||
declareShortcut(mValues->mKeyBindings.mSceneSave4, "Save Group 4");
|
||||
declareShortcut(mValues->mKeyBindings.mSceneGroup5, "Selection Group 5");
|
||||
declareShortcut(mValues->mKeyBindings.mSceneSave5, "Save Group 5");
|
||||
declareShortcut(mValues->mKeyBindings.mSceneGroup6, "Selection Group 6");
|
||||
declareShortcut(mValues->mKeyBindings.mSceneSave6, "Save Group 6");
|
||||
declareShortcut(mValues->mKeyBindings.mSceneGroup7, "Selection Group 7");
|
||||
declareShortcut(mValues->mKeyBindings.mSceneSave7, "Save Group 7");
|
||||
declareShortcut(mValues->mKeyBindings.mSceneGroup8, "Selection Group 8");
|
||||
declareShortcut(mValues->mKeyBindings.mSceneSave8, "Save Group 8");
|
||||
declareShortcut(mValues->mKeyBindings.mSceneGroup9, "Selection Group 9");
|
||||
declareShortcut(mValues->mKeyBindings.mSceneSave9, "Save Group 9");
|
||||
|
||||
declareSubcategory("1st/Free Camera");
|
||||
declareShortcut("free-forward", "Forward", QKeySequence(Qt::Key_W));
|
||||
declareShortcut("free-backward", "Backward", QKeySequence(Qt::Key_S));
|
||||
declareShortcut("free-left", "Left", QKeySequence(Qt::Key_A));
|
||||
declareShortcut("free-right", "Right", QKeySequence(Qt::Key_D));
|
||||
declareShortcut("free-roll-left", "Roll Left", QKeySequence(Qt::Key_Q));
|
||||
declareShortcut("free-roll-right", "Roll Right", QKeySequence(Qt::Key_E));
|
||||
declareShortcut("free-speed-mode", "Toggle Speed Mode", QKeySequence(Qt::Key_F));
|
||||
declareShortcut(mValues->mKeyBindings.mFreeForward, "Forward");
|
||||
declareShortcut(mValues->mKeyBindings.mFreeBackward, "Backward");
|
||||
declareShortcut(mValues->mKeyBindings.mFreeLeft, "Left");
|
||||
declareShortcut(mValues->mKeyBindings.mFreeRight, "Right");
|
||||
declareShortcut(mValues->mKeyBindings.mFreeRollLeft, "Roll Left");
|
||||
declareShortcut(mValues->mKeyBindings.mFreeRollRight, "Roll Right");
|
||||
declareShortcut(mValues->mKeyBindings.mFreeSpeedMode, "Toggle Speed Mode");
|
||||
|
||||
declareSubcategory("Orbit Camera");
|
||||
declareShortcut("orbit-up", "Up", QKeySequence(Qt::Key_W));
|
||||
declareShortcut("orbit-down", "Down", QKeySequence(Qt::Key_S));
|
||||
declareShortcut("orbit-left", "Left", QKeySequence(Qt::Key_A));
|
||||
declareShortcut("orbit-right", "Right", QKeySequence(Qt::Key_D));
|
||||
declareShortcut("orbit-roll-left", "Roll Left", QKeySequence(Qt::Key_Q));
|
||||
declareShortcut("orbit-roll-right", "Roll Right", QKeySequence(Qt::Key_E));
|
||||
declareShortcut("orbit-speed-mode", "Toggle Speed Mode", QKeySequence(Qt::Key_F));
|
||||
declareShortcut("orbit-center-selection", "Center On Selected", QKeySequence(Qt::Key_C));
|
||||
declareShortcut(mValues->mKeyBindings.mOrbitUp, "Up");
|
||||
declareShortcut(mValues->mKeyBindings.mOrbitDown, "Down");
|
||||
declareShortcut(mValues->mKeyBindings.mOrbitLeft, "Left");
|
||||
declareShortcut(mValues->mKeyBindings.mOrbitRight, "Right");
|
||||
declareShortcut(mValues->mKeyBindings.mOrbitRollLeft, "Roll Left");
|
||||
declareShortcut(mValues->mKeyBindings.mOrbitRollRight, "Roll Right");
|
||||
declareShortcut(mValues->mKeyBindings.mOrbitSpeedMode, "Toggle Speed Mode");
|
||||
declareShortcut(mValues->mKeyBindings.mOrbitCenterSelection, "Center On Selected");
|
||||
|
||||
declareSubcategory("Script Editor");
|
||||
declareShortcut("script-editor-comment", "Comment Selection", QKeySequence());
|
||||
declareShortcut("script-editor-uncomment", "Uncomment Selection", QKeySequence());
|
||||
declareShortcut(mValues->mKeyBindings.mScriptEditorComment, "Comment Selection");
|
||||
declareShortcut(mValues->mKeyBindings.mScriptEditorUncomment, "Uncomment Selection");
|
||||
|
||||
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,71 +422,52 @@ 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);
|
||||
|
||||
@ -535,18 +475,13 @@ CSMPrefs::EnumSetting& CSMPrefs::State::declareEnum(
|
||||
}
|
||||
|
||||
CSMPrefs::ColourSetting& CSMPrefs::State::declareColour(
|
||||
const std::string& key, const std::string& label, QColor default_)
|
||||
Settings::SettingValue<std::string>& value, const QString& label)
|
||||
{
|
||||
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, value.mName, label, *mIndex);
|
||||
|
||||
mCurrentCategory->second.addSetting(setting);
|
||||
|
||||
@ -554,39 +489,32 @@ CSMPrefs::ColourSetting& CSMPrefs::State::declareColour(
|
||||
}
|
||||
|
||||
CSMPrefs::ShortcutSetting& CSMPrefs::State::declareShortcut(
|
||||
const std::string& key, const std::string& label, const QKeySequence& default_)
|
||||
Settings::SettingValue<std::string>& value, const QString& label)
|
||||
{
|
||||
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().setSequence(key, sequence);
|
||||
getShortcutManager().convertFromString(value, sequence);
|
||||
getShortcutManager().setSequence(value.mName, sequence);
|
||||
|
||||
CSMPrefs::ShortcutSetting* setting = new CSMPrefs::ShortcutSetting(&mCurrentCategory->second, &mMutex, key, label);
|
||||
CSMPrefs::ShortcutSetting* setting
|
||||
= new CSMPrefs::ShortcutSetting(&mCurrentCategory->second, &mMutex, value.mName, 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 +522,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 +554,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 +615,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(Settings::SettingValue<std::string>& value, const QString& label);
|
||||
|
||||
StringSetting& declareString(const std::string& key, const std::string& label, std::string default_);
|
||||
ShortcutSetting& declareShortcut(Settings::SettingValue<std::string>& value, const QString& label);
|
||||
|
||||
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
|
@ -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();
|
||||
|
@ -741,8 +741,8 @@ namespace CSMWorld
|
||||
QVariant RaceAttributeAdapter::getData(const Record<ESM::Race>& record, int subRowIndex, int subColIndex) const
|
||||
{
|
||||
ESM::Race race = record.get();
|
||||
|
||||
if (subRowIndex < 0 || subRowIndex >= ESM::Attribute::Length)
|
||||
ESM::RefId attribute = ESM::Attribute::indexToRefId(subRowIndex);
|
||||
if (attribute.empty())
|
||||
throw std::runtime_error("index out of range");
|
||||
|
||||
switch (subColIndex)
|
||||
@ -750,9 +750,9 @@ namespace CSMWorld
|
||||
case 0:
|
||||
return subRowIndex;
|
||||
case 1:
|
||||
return race.mData.mAttributeValues[subRowIndex].mMale;
|
||||
return race.mData.getAttribute(attribute, true);
|
||||
case 2:
|
||||
return race.mData.mAttributeValues[subRowIndex].mFemale;
|
||||
return race.mData.getAttribute(attribute, false);
|
||||
default:
|
||||
throw std::runtime_error("Race Attribute subcolumn index out of range");
|
||||
}
|
||||
@ -762,8 +762,8 @@ namespace CSMWorld
|
||||
Record<ESM::Race>& record, const QVariant& value, int subRowIndex, int subColIndex) const
|
||||
{
|
||||
ESM::Race race = record.get();
|
||||
|
||||
if (subRowIndex < 0 || subRowIndex >= ESM::Attribute::Length)
|
||||
ESM::RefId attribute = ESM::Attribute::indexToRefId(subRowIndex);
|
||||
if (attribute.empty())
|
||||
throw std::runtime_error("index out of range");
|
||||
|
||||
switch (subColIndex)
|
||||
@ -771,10 +771,10 @@ namespace CSMWorld
|
||||
case 0:
|
||||
return; // throw an exception here?
|
||||
case 1:
|
||||
race.mData.mAttributeValues[subRowIndex].mMale = value.toInt();
|
||||
race.mData.setAttribute(attribute, true, value.toInt());
|
||||
break;
|
||||
case 2:
|
||||
race.mData.mAttributeValues[subRowIndex].mFemale = value.toInt();
|
||||
race.mData.setAttribute(attribute, false, value.toInt());
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Race Attribute subcolumn index out of range");
|
||||
|
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