mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-04-19 15:52:53 +00:00
Merge pull request #7 from Laupetin/feature/iw5-menus
IW5 Menu writing & dumping improvements
This commit is contained in:
commit
6802b1c23b
@ -2084,8 +2084,8 @@ namespace IW4
|
|||||||
float y;
|
float y;
|
||||||
float w;
|
float w;
|
||||||
float h;
|
float h;
|
||||||
char horzAlign;
|
unsigned char horzAlign;
|
||||||
char vertAlign;
|
unsigned char vertAlign;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum WindowDefStaticFlag : unsigned int
|
enum WindowDefStaticFlag : unsigned int
|
||||||
|
@ -2316,7 +2316,21 @@ namespace IW5
|
|||||||
EXP_FUNC_STATIC_DVAR_FLOAT,
|
EXP_FUNC_STATIC_DVAR_FLOAT,
|
||||||
EXP_FUNC_STATIC_DVAR_STRING,
|
EXP_FUNC_STATIC_DVAR_STRING,
|
||||||
|
|
||||||
EXP_FUNC_DYN_START
|
EXP_FUNC_DYN_START,
|
||||||
|
|
||||||
|
EXP_FUNC_INT = EXP_FUNC_DYN_START,
|
||||||
|
EXP_FUNC_STRING,
|
||||||
|
EXP_FUNC_FLOAT,
|
||||||
|
EXP_FUNC_SIN,
|
||||||
|
EXP_FUNC_COS,
|
||||||
|
EXP_FUNC_MIN,
|
||||||
|
EXP_FUNC_MAX,
|
||||||
|
EXP_FUNC_MILLISECONDS,
|
||||||
|
EXP_FUNC_LOCAL_CLIENT_UI_MILLISECONDS,
|
||||||
|
EXP_FUNC_DVAR_INT,
|
||||||
|
EXP_FUNC_DVAR_BOOL,
|
||||||
|
EXP_FUNC_DVAR_FLOAT,
|
||||||
|
EXP_FUNC_DVAR_STRING
|
||||||
};
|
};
|
||||||
|
|
||||||
enum expressionEntryType : int
|
enum expressionEntryType : int
|
||||||
@ -2554,12 +2568,25 @@ namespace IW5
|
|||||||
WINDOW_FLAG_AUTO_WRAPPED = 0x800000,
|
WINDOW_FLAG_AUTO_WRAPPED = 0x800000,
|
||||||
WINDOW_FLAG_POPUP = 0x1000000,
|
WINDOW_FLAG_POPUP = 0x1000000,
|
||||||
WINDOW_FLAG_LEGACY_SPLIT_SCREEN_SCALE = 0x4000000,
|
WINDOW_FLAG_LEGACY_SPLIT_SCREEN_SCALE = 0x4000000,
|
||||||
WINDOW_FLAG_HIDDEN_DURING_FLASH_BANG = 0x10000000,
|
WINDOW_FLAG_HIDDEN_DURING_FLASH_BANG = 0x10000000, // confirmed
|
||||||
WINDOW_FLAG_HIDDEN_DURING_SCOPE = 0x20000000,
|
WINDOW_FLAG_HIDDEN_DURING_SCOPE = 0x20000000, // confirmed
|
||||||
WINDOW_FLAG_HIDDEN_DURING_UI = 0x40000000,
|
WINDOW_FLAG_HIDDEN_DURING_UI = 0x40000000, // confirmed
|
||||||
WINDOW_FLAG_TEXT_ONLY_FOCUS = 0x80000000,
|
WINDOW_FLAG_TEXT_ONLY_FOCUS = 0x80000000,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// This is data from IW4, could be different for IW5, to be investigated
|
||||||
|
enum WindowDefDynamicFlag : unsigned int
|
||||||
|
{
|
||||||
|
WINDOW_FLAG_HOVERED = 0x1, // guessed
|
||||||
|
WINDOW_FLAG_FOCUSED = 0x2,
|
||||||
|
WINDOW_FLAG_VISIBLE = 0x4, // confirmed
|
||||||
|
WINDOW_FLAG_FADING_OUT = 0x10,
|
||||||
|
WINDOW_FLAG_FADING_IN = 0x20,
|
||||||
|
WINDOW_FLAG_80 = 0x80,
|
||||||
|
WINDOW_FLAG_NON_DEFAULT_BACKCOLOR = 0x8000,
|
||||||
|
WINDOW_FLAG_NON_DEFAULT_FORECOLOR = 0x10000
|
||||||
|
};
|
||||||
|
|
||||||
struct windowDef_t
|
struct windowDef_t
|
||||||
{
|
{
|
||||||
const char* name;
|
const char* name;
|
||||||
|
@ -34,8 +34,8 @@ namespace IW4
|
|||||||
static_cast<float>(rect.y),
|
static_cast<float>(rect.y),
|
||||||
static_cast<float>(rect.w),
|
static_cast<float>(rect.w),
|
||||||
static_cast<float>(rect.h),
|
static_cast<float>(rect.h),
|
||||||
static_cast<char>(rect.horizontalAlign),
|
static_cast<unsigned char>(rect.horizontalAlign),
|
||||||
static_cast<char>(rect.verticalAlign)
|
static_cast<unsigned char>(rect.verticalAlign)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,8 +46,8 @@ namespace IW4
|
|||||||
static_cast<float>(rectRelativeTo.y + rect.y),
|
static_cast<float>(rectRelativeTo.y + rect.y),
|
||||||
static_cast<float>(rect.w),
|
static_cast<float>(rect.w),
|
||||||
static_cast<float>(rect.h),
|
static_cast<float>(rect.h),
|
||||||
static_cast<char>(rect.horizontalAlign),
|
static_cast<unsigned char>(rect.horizontalAlign),
|
||||||
static_cast<char>(rect.verticalAlign)
|
static_cast<unsigned char>(rect.verticalAlign)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -502,7 +502,7 @@ namespace IW4
|
|||||||
{
|
{
|
||||||
const auto* staticValue = dynamic_cast<const SimpleExpressionValue*>(expression);
|
const auto* staticValue = dynamic_cast<const SimpleExpressionValue*>(expression);
|
||||||
isStatic = staticValue != nullptr;
|
isStatic = staticValue != nullptr;
|
||||||
isTruthy = isStatic && staticValue->IsTruthy();
|
isTruthy = isStatic && (staticValue->m_type == SimpleExpressionValue::Type::INT || staticValue->m_type == SimpleExpressionValue::Type::DOUBLE) && staticValue->IsTruthy();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -661,7 +661,7 @@ namespace IW4
|
|||||||
return outputSet;
|
return outputSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
_NODISCARD ItemKeyHandler* ConvertKeyHandler(const std::map<int, std::unique_ptr<CommonEventHandlerSet>>& keyHandlers, const CommonMenuDef* menu, const CommonItemDef* item = nullptr) const
|
_NODISCARD ItemKeyHandler* ConvertKeyHandler(const std::multimap<int, std::unique_ptr<CommonEventHandlerSet>>& keyHandlers, const CommonMenuDef* menu, const CommonItemDef* item = nullptr) const
|
||||||
{
|
{
|
||||||
if (keyHandlers.empty())
|
if (keyHandlers.empty())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -751,7 +751,8 @@ namespace IW4
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(false);
|
// Do not consider this a mistake since the games menus do this by mistake and it should be able to compile them anyway
|
||||||
|
// But the game should also not know what to do with this i guess
|
||||||
expressionIsStatic = false;
|
expressionIsStatic = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -943,6 +944,7 @@ namespace IW4
|
|||||||
ApplyFlag(item->window.staticFlags, commonItem.m_auto_wrapped, WINDOW_FLAG_AUTO_WRAPPED);
|
ApplyFlag(item->window.staticFlags, commonItem.m_auto_wrapped, WINDOW_FLAG_AUTO_WRAPPED);
|
||||||
ApplyFlag(item->window.staticFlags, commonItem.m_horizontal_scroll, WINDOW_FLAG_HORIZONTAL_SCROLL);
|
ApplyFlag(item->window.staticFlags, commonItem.m_horizontal_scroll, WINDOW_FLAG_HORIZONTAL_SCROLL);
|
||||||
item->type = ConvertItemType(commonItem.m_type);
|
item->type = ConvertItemType(commonItem.m_type);
|
||||||
|
item->dataType = item->type;
|
||||||
item->window.border = commonItem.m_border;
|
item->window.border = commonItem.m_border;
|
||||||
item->window.borderSize = static_cast<float>(commonItem.m_border_size);
|
item->window.borderSize = static_cast<float>(commonItem.m_border_size);
|
||||||
item->visibleExp = ConvertVisibleExpression(&item->window, commonItem.m_visible_expression.get(), &parentMenu, &commonItem);
|
item->visibleExp = ConvertVisibleExpression(&item->window, commonItem.m_visible_expression.get(), &parentMenu, &commonItem);
|
||||||
|
17
src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderMenuDef.cpp
Normal file
17
src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderMenuDef.cpp
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#include "AssetLoaderMenuDef.h"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include "ObjLoading.h"
|
||||||
|
#include "Game/IW5/IW5.h"
|
||||||
|
#include "Pool/GlobalAssetPool.h"
|
||||||
|
|
||||||
|
using namespace IW5;
|
||||||
|
|
||||||
|
void* AssetLoaderMenuDef::CreateEmptyAsset(const std::string& assetName, MemoryManager* memory)
|
||||||
|
{
|
||||||
|
auto* menu = memory->Create<menuDef_t>();
|
||||||
|
memset(menu, 0, sizeof(menuDef_t));
|
||||||
|
menu->window.name = memory->Dup(assetName.c_str());
|
||||||
|
return menu;
|
||||||
|
}
|
14
src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderMenuDef.h
Normal file
14
src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderMenuDef.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Game/IW5/IW5.h"
|
||||||
|
#include "AssetLoading/BasicAssetLoader.h"
|
||||||
|
#include "SearchPath/ISearchPath.h"
|
||||||
|
|
||||||
|
namespace IW5
|
||||||
|
{
|
||||||
|
class AssetLoaderMenuDef final : public BasicAssetLoader<ASSET_TYPE_MENU, menuDef_t>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
_NODISCARD void* CreateEmptyAsset(const std::string& assetName, MemoryManager* memory) override;
|
||||||
|
};
|
||||||
|
}
|
207
src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderMenuList.cpp
Normal file
207
src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderMenuList.cpp
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
#include "AssetLoaderMenuList.h"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "ObjLoading.h"
|
||||||
|
#include "Game/IW5/IW5.h"
|
||||||
|
#include "Game/IW5/Menu/MenuConversionZoneStateIW5.h"
|
||||||
|
#include "Game/IW5/Menu/MenuConverterIW5.h"
|
||||||
|
#include "Parsing/Menu/MenuFileReader.h"
|
||||||
|
#include "Pool/GlobalAssetPool.h"
|
||||||
|
|
||||||
|
using namespace IW5;
|
||||||
|
|
||||||
|
namespace IW5
|
||||||
|
{
|
||||||
|
class MenuLoader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static bool ProcessParsedResults(const std::string& fileName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, menu::ParsingResult* parsingResult,
|
||||||
|
menu::MenuAssetZoneState* zoneState, MenuConversionZoneState* conversionState, std::vector<menuDef_t*>& menus,
|
||||||
|
std::vector<XAssetInfoGeneric*>& menuListDependencies)
|
||||||
|
{
|
||||||
|
const auto menuCount = parsingResult->m_menus.size();
|
||||||
|
const auto functionCount = parsingResult->m_functions.size();
|
||||||
|
const auto menuLoadCount = parsingResult->m_menus_to_load.size();
|
||||||
|
auto totalItemCount = 0u;
|
||||||
|
for (const auto& menu : parsingResult->m_menus)
|
||||||
|
totalItemCount += menu->m_items.size();
|
||||||
|
|
||||||
|
std::cout << "Successfully read menu file \"" << fileName << "\" (" << menuLoadCount << " loads, " << menuCount << " menus, " << functionCount << " functions, " << totalItemCount <<
|
||||||
|
" items)\n";
|
||||||
|
|
||||||
|
// Add all functions to the zone state to make them available for all menus to be converted
|
||||||
|
for (auto& function : parsingResult->m_functions)
|
||||||
|
zoneState->AddFunction(std::move(function));
|
||||||
|
|
||||||
|
// Prepare a list of all menus of this file
|
||||||
|
std::vector<XAssetInfo<menuDef_t>*> allMenusOfFile;
|
||||||
|
allMenusOfFile.reserve(parsingResult->m_menus.size());
|
||||||
|
|
||||||
|
// Convert all menus and add them as assets
|
||||||
|
for (auto& menu : parsingResult->m_menus)
|
||||||
|
{
|
||||||
|
MenuConverter converter(ObjLoading::Configuration.MenuNoOptimization, searchPath, memory, manager);
|
||||||
|
auto* menuAsset = converter.ConvertMenu(*menu);
|
||||||
|
if (menuAsset == nullptr)
|
||||||
|
{
|
||||||
|
std::cout << "Failed to convert menu file \"" << menu->m_name << "\"\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
menus.push_back(menuAsset);
|
||||||
|
auto* menuAssetInfo = manager->AddAsset(ASSET_TYPE_MENU, menu->m_name, menuAsset, std::move(converter.GetDependencies()), std::vector<scr_string_t>());
|
||||||
|
|
||||||
|
if (menuAssetInfo)
|
||||||
|
{
|
||||||
|
allMenusOfFile.push_back(reinterpret_cast<XAssetInfo<menuDef_t>*>(menuAssetInfo));
|
||||||
|
menuListDependencies.push_back(menuAssetInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
zoneState->AddMenu(std::move(menu));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register this file with all loaded menus
|
||||||
|
conversionState->AddLoadedFile(fileName, std::move(allMenusOfFile));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static MenuList* CreateMenuListAsset(const std::string& assetName, MemoryManager* memory, const std::vector<menuDef_t*>& menus)
|
||||||
|
{
|
||||||
|
auto* menuListAsset = memory->Create<MenuList>();
|
||||||
|
menuListAsset->name = memory->Dup(assetName.c_str());
|
||||||
|
menuListAsset->menuCount = static_cast<int>(menus.size());
|
||||||
|
|
||||||
|
if (menuListAsset->menuCount > 0)
|
||||||
|
{
|
||||||
|
menuListAsset->menus = static_cast<menuDef_t**>(memory->Alloc(sizeof(uintptr_t) * menuListAsset->menuCount));
|
||||||
|
for (auto i = 0; i < menuListAsset->menuCount; i++)
|
||||||
|
menuListAsset->menus[i] = menus[i];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
menuListAsset->menus = nullptr;
|
||||||
|
|
||||||
|
return menuListAsset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::unique_ptr<menu::ParsingResult> ParseMenuFile(const std::string& menuFileName, ISearchPath* searchPath, const menu::MenuAssetZoneState* zoneState)
|
||||||
|
{
|
||||||
|
const auto file = searchPath->Open(menuFileName);
|
||||||
|
if (!file.IsOpen())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
menu::MenuFileReader reader(*file.m_stream, menuFileName, menu::FeatureLevel::IW5, [searchPath](const std::string& filename, const std::string& sourceFile) -> std::unique_ptr<std::istream>
|
||||||
|
{
|
||||||
|
auto foundFileToInclude = searchPath->Open(filename);
|
||||||
|
if (!foundFileToInclude.IsOpen() || !foundFileToInclude.m_stream)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return std::move(foundFileToInclude.m_stream);
|
||||||
|
});
|
||||||
|
|
||||||
|
reader.IncludeZoneState(zoneState);
|
||||||
|
reader.SetPermissiveMode(ObjLoading::Configuration.MenuPermissiveParsing);
|
||||||
|
|
||||||
|
return reader.ReadMenuFile();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void* AssetLoaderMenuList::CreateEmptyAsset(const std::string& assetName, MemoryManager* memory)
|
||||||
|
{
|
||||||
|
auto* menuList = memory->Create<MenuList>();
|
||||||
|
memset(menuList, 0, sizeof(MenuList));
|
||||||
|
menuList->name = memory->Dup(assetName.c_str());
|
||||||
|
return menuList;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AssetLoaderMenuList::CanLoadFromRaw() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BuildMenuFileQueue(std::deque<std::string>& menuLoadQueue, const std::string& menuListAssetName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, menu::MenuAssetZoneState* zoneState,
|
||||||
|
MenuConversionZoneState* conversionState, std::vector<menuDef_t*>& menus, std::vector<XAssetInfoGeneric*>& menuListDependencies)
|
||||||
|
{
|
||||||
|
const auto alreadyLoadedMenuListFileMenus = conversionState->m_menus_by_filename.find(menuListAssetName);
|
||||||
|
|
||||||
|
if (alreadyLoadedMenuListFileMenus == conversionState->m_menus_by_filename.end())
|
||||||
|
{
|
||||||
|
const auto menuListResult = MenuLoader::ParseMenuFile(menuListAssetName, searchPath, zoneState);
|
||||||
|
if (menuListResult)
|
||||||
|
{
|
||||||
|
MenuLoader::ProcessParsedResults(menuListAssetName, searchPath, memory, manager, menuListResult.get(), zoneState, conversionState, menus, menuListDependencies);
|
||||||
|
|
||||||
|
for (const auto& menuToLoad : menuListResult->m_menus_to_load)
|
||||||
|
menuLoadQueue.push_back(menuToLoad);
|
||||||
|
|
||||||
|
zoneState->AddMenusToLoad(menuListAssetName, std::move(menuListResult->m_menus_to_load));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadMenuFileFromQueue(const std::string& menuFilePath, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, menu::MenuAssetZoneState* zoneState,
|
||||||
|
MenuConversionZoneState* conversionState, std::vector<menuDef_t*>& menus, std::vector<XAssetInfoGeneric*>& menuListDependencies)
|
||||||
|
{
|
||||||
|
const auto alreadyLoadedMenuFile = conversionState->m_menus_by_filename.find(menuFilePath);
|
||||||
|
if (alreadyLoadedMenuFile != conversionState->m_menus_by_filename.end())
|
||||||
|
{
|
||||||
|
std::cout << "Already loaded \"" << menuFilePath << "\", skipping\n";
|
||||||
|
for (auto* menu : alreadyLoadedMenuFile->second)
|
||||||
|
{
|
||||||
|
menus.push_back(menu->Asset());
|
||||||
|
menuListDependencies.push_back(menu);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto menuFileResult = MenuLoader::ParseMenuFile(menuFilePath, searchPath, zoneState);
|
||||||
|
if (menuFileResult)
|
||||||
|
{
|
||||||
|
MenuLoader::ProcessParsedResults(menuFilePath, searchPath, memory, manager, menuFileResult.get(), zoneState, conversionState, menus, menuListDependencies);
|
||||||
|
if (!menuFileResult->m_menus_to_load.empty())
|
||||||
|
std::cout << "WARNING: Menu file has menus to load even though it is not a menu list, ignoring: \"" << menuFilePath << "\"\n";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
std::cerr << "Could not read menu file \"" << menuFilePath << "\"\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AssetLoaderMenuList::LoadFromRaw(const std::string& assetName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const
|
||||||
|
{
|
||||||
|
std::vector<menuDef_t*> menus;
|
||||||
|
std::vector<XAssetInfoGeneric*> menuListDependencies;
|
||||||
|
|
||||||
|
auto* zoneState = manager->GetAssetLoadingContext()->GetZoneAssetLoaderState<menu::MenuAssetZoneState>();
|
||||||
|
auto* conversionState = manager->GetAssetLoadingContext()->GetZoneAssetLoaderState<MenuConversionZoneState>();
|
||||||
|
|
||||||
|
std::deque<std::string> menuLoadQueue;
|
||||||
|
if (!BuildMenuFileQueue(menuLoadQueue, assetName, searchPath, memory, manager, zoneState, conversionState, menus, menuListDependencies))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
while(!menuLoadQueue.empty())
|
||||||
|
{
|
||||||
|
const auto& menuFileToLoad = menuLoadQueue.front();
|
||||||
|
|
||||||
|
LoadMenuFileFromQueue(menuFileToLoad, searchPath, memory, manager, zoneState, conversionState, menus, menuListDependencies);
|
||||||
|
|
||||||
|
menuLoadQueue.pop_front();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* menuListAsset = MenuLoader::CreateMenuListAsset(assetName, memory, menus);
|
||||||
|
|
||||||
|
if (menuListAsset)
|
||||||
|
manager->AddAsset(ASSET_TYPE_MENULIST, assetName, menuListAsset, menuListDependencies, std::vector<scr_string_t>());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssetLoaderMenuList::FinalizeAssetsForZone(AssetLoadingContext* context) const
|
||||||
|
{
|
||||||
|
context->GetZoneAssetLoaderState<MenuConversionZoneState>()->FinalizeSupportingData();
|
||||||
|
}
|
18
src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderMenuList.h
Normal file
18
src/ObjLoading/Game/IW5/AssetLoaders/AssetLoaderMenuList.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Game/IW5/IW5.h"
|
||||||
|
#include "AssetLoading/BasicAssetLoader.h"
|
||||||
|
#include "AssetLoading/IAssetLoadingManager.h"
|
||||||
|
#include "SearchPath/ISearchPath.h"
|
||||||
|
|
||||||
|
namespace IW5
|
||||||
|
{
|
||||||
|
class AssetLoaderMenuList final : public BasicAssetLoader<ASSET_TYPE_MENULIST, MenuList>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
_NODISCARD void* CreateEmptyAsset(const std::string& assetName, MemoryManager* memory) override;
|
||||||
|
_NODISCARD bool CanLoadFromRaw() const override;
|
||||||
|
bool LoadFromRaw(const std::string& assetName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const override;
|
||||||
|
void FinalizeAssetsForZone(AssetLoadingContext* context) const override;
|
||||||
|
};
|
||||||
|
}
|
121
src/ObjLoading/Game/IW5/Menu/MenuConversionZoneStateIW5.cpp
Normal file
121
src/ObjLoading/Game/IW5/Menu/MenuConversionZoneStateIW5.cpp
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
#include "MenuConversionZoneStateIW5.h"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
using namespace IW5;
|
||||||
|
|
||||||
|
MenuConversionZoneState::MenuConversionZoneState()
|
||||||
|
: m_zone(nullptr),
|
||||||
|
m_supporting_data(nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void MenuConversionZoneState::SetZone(Zone* zone)
|
||||||
|
{
|
||||||
|
auto* memory = zone->GetMemory();
|
||||||
|
|
||||||
|
m_zone = zone;
|
||||||
|
m_supporting_data = memory->Create<ExpressionSupportingData>();
|
||||||
|
memset(m_supporting_data, 0, sizeof(ExpressionSupportingData));
|
||||||
|
}
|
||||||
|
|
||||||
|
Statement_s* MenuConversionZoneState::FindFunction(const std::string& functionName)
|
||||||
|
{
|
||||||
|
const auto foundFunction = m_function_by_name.find(functionName);
|
||||||
|
|
||||||
|
if (foundFunction != m_function_by_name.end())
|
||||||
|
return foundFunction->second;
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Statement_s* MenuConversionZoneState::AddFunction(const std::string& functionName, Statement_s* function)
|
||||||
|
{
|
||||||
|
m_functions.push_back(function);
|
||||||
|
m_function_by_name.emplace(std::make_pair(functionName, function));
|
||||||
|
|
||||||
|
return function;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t MenuConversionZoneState::AddStaticDvar(const std::string& dvarName)
|
||||||
|
{
|
||||||
|
const auto foundDvar = m_dvars_by_name.find(dvarName);
|
||||||
|
|
||||||
|
if (foundDvar != m_dvars_by_name.end())
|
||||||
|
return foundDvar->second;
|
||||||
|
|
||||||
|
auto* memory = m_zone->GetMemory();
|
||||||
|
auto* staticDvar = static_cast<StaticDvar*>(memory->Alloc(sizeof(StaticDvar)));
|
||||||
|
|
||||||
|
staticDvar->dvarName = memory->Dup(dvarName.c_str());
|
||||||
|
staticDvar->dvar = nullptr;
|
||||||
|
|
||||||
|
const auto staticDvarIndex = m_static_dvars.size();
|
||||||
|
m_static_dvars.push_back(staticDvar);
|
||||||
|
m_dvars_by_name.emplace(std::make_pair(dvarName, staticDvarIndex));
|
||||||
|
|
||||||
|
return staticDvarIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* MenuConversionZoneState::AddString(const std::string& str)
|
||||||
|
{
|
||||||
|
const auto foundString = m_strings_by_value.find(str);
|
||||||
|
|
||||||
|
if (foundString != m_strings_by_value.end())
|
||||||
|
return foundString->second;
|
||||||
|
|
||||||
|
auto* memory = m_zone->GetMemory();
|
||||||
|
const auto* strDuped = memory->Dup(str.c_str());
|
||||||
|
|
||||||
|
m_strings.push_back(strDuped);
|
||||||
|
m_strings_by_value.emplace(std::make_pair(str, strDuped));
|
||||||
|
|
||||||
|
return strDuped;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MenuConversionZoneState::AddLoadedFile(std::string loadedFileName, std::vector<XAssetInfo<menuDef_t>*> menusOfFile)
|
||||||
|
{
|
||||||
|
m_menus_by_filename.emplace(std::make_pair(std::move(loadedFileName), std::move(menusOfFile)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MenuConversionZoneState::FinalizeSupportingData() const
|
||||||
|
{
|
||||||
|
auto* memory = m_zone->GetMemory();
|
||||||
|
|
||||||
|
m_supporting_data->uifunctions.totalFunctions = static_cast<int>(m_functions.size());
|
||||||
|
m_supporting_data->staticDvarList.numStaticDvars = static_cast<int>(m_static_dvars.size());
|
||||||
|
m_supporting_data->uiStrings.totalStrings = static_cast<int>(m_strings.size());
|
||||||
|
|
||||||
|
if (m_supporting_data->uifunctions.functions)
|
||||||
|
memory->Free(m_supporting_data->uifunctions.functions);
|
||||||
|
|
||||||
|
if (m_supporting_data->staticDvarList.staticDvars)
|
||||||
|
memory->Free(m_supporting_data->staticDvarList.staticDvars);
|
||||||
|
|
||||||
|
if (m_supporting_data->uiStrings.strings)
|
||||||
|
memory->Free(m_supporting_data->uiStrings.strings);
|
||||||
|
|
||||||
|
if (!m_functions.empty())
|
||||||
|
{
|
||||||
|
m_supporting_data->uifunctions.functions = static_cast<Statement_s**>(memory->Alloc(sizeof(void*) * m_functions.size()));
|
||||||
|
memcpy(m_supporting_data->uifunctions.functions, &m_functions[0], sizeof(void*) * m_functions.size());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_supporting_data->uifunctions.functions = nullptr;
|
||||||
|
|
||||||
|
if (!m_static_dvars.empty())
|
||||||
|
{
|
||||||
|
m_supporting_data->staticDvarList.staticDvars = static_cast<StaticDvar**>(memory->Alloc(sizeof(void*) * m_static_dvars.size()));
|
||||||
|
memcpy(m_supporting_data->staticDvarList.staticDvars, &m_static_dvars[0], sizeof(void*) * m_static_dvars.size());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_supporting_data->staticDvarList.staticDvars = nullptr;
|
||||||
|
|
||||||
|
if (!m_strings.empty())
|
||||||
|
{
|
||||||
|
m_supporting_data->uiStrings.strings = static_cast<const char**>(memory->Alloc(sizeof(void*) * m_strings.size()));
|
||||||
|
memcpy(m_supporting_data->uiStrings.strings, &m_strings[0], sizeof(void*) * m_strings.size());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_supporting_data->uiStrings.strings = nullptr;
|
||||||
|
}
|
39
src/ObjLoading/Game/IW5/Menu/MenuConversionZoneStateIW5.h
Normal file
39
src/ObjLoading/Game/IW5/Menu/MenuConversionZoneStateIW5.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include "AssetLoading/IZoneAssetLoaderState.h"
|
||||||
|
#include "Game/IW5/IW5.h"
|
||||||
|
|
||||||
|
namespace IW5
|
||||||
|
{
|
||||||
|
class MenuConversionZoneState final : public IZoneAssetLoaderState
|
||||||
|
{
|
||||||
|
Zone* m_zone;
|
||||||
|
std::vector<Statement_s*> m_functions;
|
||||||
|
std::map<std::string, Statement_s*> m_function_by_name;
|
||||||
|
|
||||||
|
std::vector<StaticDvar*> m_static_dvars;
|
||||||
|
std::map<std::string, size_t> m_dvars_by_name;
|
||||||
|
|
||||||
|
std::vector<const char*> m_strings;
|
||||||
|
std::map<std::string, const char*> m_strings_by_value;
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::map<std::string, std::vector<XAssetInfo<menuDef_t>*>> m_menus_by_filename;
|
||||||
|
ExpressionSupportingData* m_supporting_data;
|
||||||
|
|
||||||
|
MenuConversionZoneState();
|
||||||
|
void SetZone(Zone* zone) override;
|
||||||
|
|
||||||
|
Statement_s* FindFunction(const std::string& functionName);
|
||||||
|
|
||||||
|
Statement_s* AddFunction(const std::string& functionName, Statement_s* function);
|
||||||
|
size_t AddStaticDvar(const std::string& dvarName);
|
||||||
|
const char* AddString(const std::string& str);
|
||||||
|
|
||||||
|
void AddLoadedFile(std::string loadedFileName, std::vector<XAssetInfo<menuDef_t>*> menusOfFile);
|
||||||
|
|
||||||
|
void FinalizeSupportingData() const;
|
||||||
|
};
|
||||||
|
}
|
1154
src/ObjLoading/Game/IW5/Menu/MenuConverterIW5.cpp
Normal file
1154
src/ObjLoading/Game/IW5/Menu/MenuConverterIW5.cpp
Normal file
File diff suppressed because it is too large
Load Diff
26
src/ObjLoading/Game/IW5/Menu/MenuConverterIW5.h
Normal file
26
src/ObjLoading/Game/IW5/Menu/MenuConverterIW5.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Utils/ClassUtils.h"
|
||||||
|
#include "AssetLoading/IAssetLoadingManager.h"
|
||||||
|
#include "Game/IW5/IW5.h"
|
||||||
|
#include "Parsing/Menu/Domain/CommonMenuDef.h"
|
||||||
|
#include "Utils/MemoryManager.h"
|
||||||
|
#include "SearchPath/ISearchPath.h"
|
||||||
|
|
||||||
|
namespace IW5
|
||||||
|
{
|
||||||
|
class MenuConverter
|
||||||
|
{
|
||||||
|
bool m_disable_optimizations;
|
||||||
|
ISearchPath* m_search_path;
|
||||||
|
MemoryManager* m_memory;
|
||||||
|
IAssetLoadingManager* m_manager;
|
||||||
|
std::vector<XAssetInfoGeneric*> m_dependencies;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MenuConverter(bool disableOptimizations, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager);
|
||||||
|
|
||||||
|
std::vector<XAssetInfoGeneric*>& GetDependencies();
|
||||||
|
_NODISCARD menuDef_t* ConvertMenu(const menu::CommonMenuDef& commonMenu);
|
||||||
|
};
|
||||||
|
}
|
@ -5,6 +5,8 @@
|
|||||||
#include "ObjContainer/IPak/IPak.h"
|
#include "ObjContainer/IPak/IPak.h"
|
||||||
#include "ObjLoading.h"
|
#include "ObjLoading.h"
|
||||||
#include "AssetLoaders/AssetLoaderLocalizeEntry.h"
|
#include "AssetLoaders/AssetLoaderLocalizeEntry.h"
|
||||||
|
#include "AssetLoaders/AssetLoaderMenuDef.h"
|
||||||
|
#include "AssetLoaders/AssetLoaderMenuList.h"
|
||||||
#include "AssetLoaders/AssetLoaderRawFile.h"
|
#include "AssetLoaders/AssetLoaderRawFile.h"
|
||||||
#include "AssetLoaders/AssetLoaderStringTable.h"
|
#include "AssetLoaders/AssetLoaderStringTable.h"
|
||||||
#include "AssetLoading/AssetLoadingManager.h"
|
#include "AssetLoading/AssetLoadingManager.h"
|
||||||
@ -44,8 +46,8 @@ ObjLoader::ObjLoader()
|
|||||||
REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_GFXWORLD, GfxWorld))
|
REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_GFXWORLD, GfxWorld))
|
||||||
REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_LIGHT_DEF, GfxLightDef))
|
REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_LIGHT_DEF, GfxLightDef))
|
||||||
REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_FONT, Font_s))
|
REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_FONT, Font_s))
|
||||||
REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_MENULIST, MenuList))
|
REGISTER_ASSET_LOADER(AssetLoaderMenuList)
|
||||||
REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_MENU, menuDef_t))
|
REGISTER_ASSET_LOADER(AssetLoaderMenuDef)
|
||||||
REGISTER_ASSET_LOADER(AssetLoaderLocalizeEntry)
|
REGISTER_ASSET_LOADER(AssetLoaderLocalizeEntry)
|
||||||
REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_ATTACHMENT, WeaponAttachment))
|
REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_ATTACHMENT, WeaponAttachment))
|
||||||
REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_WEAPON, WeaponCompleteDef))
|
REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_WEAPON, WeaponCompleteDef))
|
||||||
|
@ -32,6 +32,7 @@ std::vector<LocalizeFileEntry> LocalizeFileReader::ReadLocalizeFile()
|
|||||||
SimpleLexer::Config lexerConfig;
|
SimpleLexer::Config lexerConfig;
|
||||||
lexerConfig.m_emit_new_line_tokens = true;
|
lexerConfig.m_emit_new_line_tokens = true;
|
||||||
lexerConfig.m_read_strings = true;
|
lexerConfig.m_read_strings = true;
|
||||||
|
lexerConfig.m_string_escape_sequences = true;
|
||||||
lexerConfig.m_read_integer_numbers = false;
|
lexerConfig.m_read_integer_numbers = false;
|
||||||
lexerConfig.m_read_floating_point_numbers = false;
|
lexerConfig.m_read_floating_point_numbers = false;
|
||||||
const auto lexer = std::make_unique<SimpleLexer>(m_stream, std::move(lexerConfig));
|
const auto lexer = std::make_unique<SimpleLexer>(m_stream, std::move(lexerConfig));
|
||||||
|
@ -15,44 +15,6 @@ SequenceLocalizeFileLanguageValue::SequenceLocalizeFileLanguageValue()
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string SequenceLocalizeFileLanguageValue::UnescapeValue(const std::string& value)
|
|
||||||
{
|
|
||||||
std::ostringstream str;
|
|
||||||
|
|
||||||
auto isEscaped = false;
|
|
||||||
for(const auto c : value)
|
|
||||||
{
|
|
||||||
if(isEscaped)
|
|
||||||
{
|
|
||||||
switch(c)
|
|
||||||
{
|
|
||||||
case 'n':
|
|
||||||
str << '\n';
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'r':
|
|
||||||
str << '\r';
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
str << c;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
isEscaped = false;
|
|
||||||
}
|
|
||||||
else if(c == '\\')
|
|
||||||
{
|
|
||||||
isEscaped = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
str << c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return str.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SequenceLocalizeFileLanguageValue::ProcessMatch(LocalizeFileParserState* state, SequenceResult<SimpleParserValue>& result) const
|
void SequenceLocalizeFileLanguageValue::ProcessMatch(LocalizeFileParserState* state, SequenceResult<SimpleParserValue>& result) const
|
||||||
{
|
{
|
||||||
const auto& langToken = result.NextCapture(CAPTURE_LANGUAGE_NAME);
|
const auto& langToken = result.NextCapture(CAPTURE_LANGUAGE_NAME);
|
||||||
@ -69,5 +31,5 @@ void SequenceLocalizeFileLanguageValue::ProcessMatch(LocalizeFileParserState* st
|
|||||||
state->m_current_reference_languages.emplace(langName);
|
state->m_current_reference_languages.emplace(langName);
|
||||||
|
|
||||||
if(langName == state->m_language_name_caps)
|
if(langName == state->m_language_name_caps)
|
||||||
state->m_entries.emplace_back(state->m_current_reference, UnescapeValue(valueToken.StringValue()));
|
state->m_entries.emplace_back(state->m_current_reference, valueToken.StringValue());
|
||||||
}
|
}
|
||||||
|
@ -7,8 +7,6 @@ class SequenceLocalizeFileLanguageValue final : public LocalizeFileParser::seque
|
|||||||
static constexpr auto CAPTURE_LANGUAGE_NAME = 1;
|
static constexpr auto CAPTURE_LANGUAGE_NAME = 1;
|
||||||
static constexpr auto CAPTURE_ENTRY_VALUE = 2;
|
static constexpr auto CAPTURE_ENTRY_VALUE = 2;
|
||||||
|
|
||||||
static std::string UnescapeValue(const std::string& value);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void ProcessMatch(LocalizeFileParserState* state, SequenceResult<SimpleParserValue>& result) const override;
|
void ProcessMatch(LocalizeFileParserState* state, SequenceResult<SimpleParserValue>& result) const override;
|
||||||
|
|
||||||
|
@ -8,7 +8,10 @@ SequenceLocalizeFileReference::SequenceLocalizeFileReference()
|
|||||||
|
|
||||||
AddMatchers({
|
AddMatchers({
|
||||||
create.Keyword("REFERENCE"),
|
create.Keyword("REFERENCE"),
|
||||||
create.Identifier().Capture(CAPTURE_REFERENCE_NAME),
|
create.Or({
|
||||||
|
create.Identifier(),
|
||||||
|
create.String()
|
||||||
|
}).Capture(CAPTURE_REFERENCE_NAME),
|
||||||
create.Type(SimpleParserValueType::NEW_LINE)
|
create.Type(SimpleParserValueType::NEW_LINE)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -44,6 +44,7 @@ namespace menu
|
|||||||
std::string m_select_icon;
|
std::string m_select_icon;
|
||||||
|
|
||||||
std::unique_ptr<CommonEventHandlerSet> m_on_double_click;
|
std::unique_ptr<CommonEventHandlerSet> m_on_double_click;
|
||||||
|
std::unique_ptr<ISimpleExpression> m_element_height_expression;
|
||||||
std::vector<Column> m_columns;
|
std::vector<Column> m_columns;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -136,6 +137,7 @@ namespace menu
|
|||||||
std::unique_ptr<ISimpleExpression> m_visible_expression;
|
std::unique_ptr<ISimpleExpression> m_visible_expression;
|
||||||
std::unique_ptr<ISimpleExpression> m_disabled_expression;
|
std::unique_ptr<ISimpleExpression> m_disabled_expression;
|
||||||
std::unique_ptr<ISimpleExpression> m_text_expression;
|
std::unique_ptr<ISimpleExpression> m_text_expression;
|
||||||
|
std::unique_ptr<ISimpleExpression> m_text_align_y_expression;
|
||||||
std::unique_ptr<ISimpleExpression> m_material_expression;
|
std::unique_ptr<ISimpleExpression> m_material_expression;
|
||||||
std::unique_ptr<ISimpleExpression> m_rect_x_exp;
|
std::unique_ptr<ISimpleExpression> m_rect_x_exp;
|
||||||
std::unique_ptr<ISimpleExpression> m_rect_y_exp;
|
std::unique_ptr<ISimpleExpression> m_rect_y_exp;
|
||||||
@ -145,6 +147,7 @@ namespace menu
|
|||||||
ColorExpressions m_glowcolor_expressions;
|
ColorExpressions m_glowcolor_expressions;
|
||||||
ColorExpressions m_backcolor_expressions;
|
ColorExpressions m_backcolor_expressions;
|
||||||
std::unique_ptr<CommonEventHandlerSet> m_on_focus;
|
std::unique_ptr<CommonEventHandlerSet> m_on_focus;
|
||||||
|
std::unique_ptr<CommonEventHandlerSet> m_has_focus;
|
||||||
std::unique_ptr<CommonEventHandlerSet> m_on_leave_focus;
|
std::unique_ptr<CommonEventHandlerSet> m_on_leave_focus;
|
||||||
std::unique_ptr<CommonEventHandlerSet> m_on_mouse_enter;
|
std::unique_ptr<CommonEventHandlerSet> m_on_mouse_enter;
|
||||||
std::unique_ptr<CommonEventHandlerSet> m_on_mouse_exit;
|
std::unique_ptr<CommonEventHandlerSet> m_on_mouse_exit;
|
||||||
@ -152,7 +155,7 @@ namespace menu
|
|||||||
std::unique_ptr<CommonEventHandlerSet> m_on_mouse_exit_text;
|
std::unique_ptr<CommonEventHandlerSet> m_on_mouse_exit_text;
|
||||||
std::unique_ptr<CommonEventHandlerSet> m_on_action;
|
std::unique_ptr<CommonEventHandlerSet> m_on_action;
|
||||||
std::unique_ptr<CommonEventHandlerSet> m_on_accept;
|
std::unique_ptr<CommonEventHandlerSet> m_on_accept;
|
||||||
std::map<int, std::unique_ptr<CommonEventHandlerSet>> m_key_handlers;
|
std::multimap<int, std::unique_ptr<CommonEventHandlerSet>> m_key_handlers;
|
||||||
|
|
||||||
std::unique_ptr<CommonItemFeaturesListBox> m_list_box_features;
|
std::unique_ptr<CommonItemFeaturesListBox> m_list_box_features;
|
||||||
std::unique_ptr<CommonItemFeaturesEditField> m_edit_field_features;
|
std::unique_ptr<CommonItemFeaturesEditField> m_edit_field_features;
|
||||||
|
@ -29,6 +29,7 @@ namespace menu
|
|||||||
int m_owner_draw = 0;
|
int m_owner_draw = 0;
|
||||||
int m_owner_draw_flags = 0;
|
int m_owner_draw_flags = 0;
|
||||||
std::string m_sound_loop;
|
std::string m_sound_loop;
|
||||||
|
std::unique_ptr<ISimpleExpression> m_sound_loop_exp;
|
||||||
double m_fade_clamp = 0;
|
double m_fade_clamp = 0;
|
||||||
int m_fade_cycle = 0;
|
int m_fade_cycle = 0;
|
||||||
double m_fade_amount = 0;
|
double m_fade_amount = 0;
|
||||||
@ -46,7 +47,8 @@ namespace menu
|
|||||||
std::unique_ptr<CommonEventHandlerSet> m_on_close;
|
std::unique_ptr<CommonEventHandlerSet> m_on_close;
|
||||||
std::unique_ptr<CommonEventHandlerSet> m_on_request_close;
|
std::unique_ptr<CommonEventHandlerSet> m_on_request_close;
|
||||||
std::unique_ptr<CommonEventHandlerSet> m_on_esc;
|
std::unique_ptr<CommonEventHandlerSet> m_on_esc;
|
||||||
std::map<int, std::unique_ptr<CommonEventHandlerSet>> m_key_handlers;
|
std::unique_ptr<CommonEventHandlerSet> m_on_focus_due_to_close;
|
||||||
|
std::multimap<int, std::unique_ptr<CommonEventHandlerSet>> m_key_handlers;
|
||||||
|
|
||||||
bool m_full_screen = false;
|
bool m_full_screen = false;
|
||||||
bool m_screen_space = false;
|
bool m_screen_space = false;
|
||||||
|
27
src/ObjLoading/Parsing/Menu/MenuFileCommonOperations.cpp
Normal file
27
src/ObjLoading/Parsing/Menu/MenuFileCommonOperations.cpp
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#include "MenuFileCommonOperations.h"
|
||||||
|
|
||||||
|
#include "Parsing/ParsingException.h"
|
||||||
|
|
||||||
|
using namespace menu;
|
||||||
|
|
||||||
|
void MenuFileCommonOperations::EnsureIsNumericExpression(const MenuFileParserState* state, const TokenPos& pos, const ISimpleExpression& expression)
|
||||||
|
{
|
||||||
|
if (!state->m_permissive_mode && expression.IsStatic())
|
||||||
|
{
|
||||||
|
const auto staticValue = expression.EvaluateStatic();
|
||||||
|
|
||||||
|
if (staticValue.m_type != SimpleExpressionValue::Type::INT && staticValue.m_type != SimpleExpressionValue::Type::DOUBLE)
|
||||||
|
throw ParsingException(pos, "Expression is expected to be numeric. Use permissive mode to compile anyway.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MenuFileCommonOperations::EnsureIsStringExpression(const MenuFileParserState* state, const TokenPos& pos, const ISimpleExpression& expression)
|
||||||
|
{
|
||||||
|
if (!state->m_permissive_mode && expression.IsStatic())
|
||||||
|
{
|
||||||
|
const auto staticValue = expression.EvaluateStatic();
|
||||||
|
|
||||||
|
if (staticValue.m_type != SimpleExpressionValue::Type::STRING)
|
||||||
|
throw ParsingException(pos, "Expression is expected to be string. Use permissive mode to compile anyway.");
|
||||||
|
}
|
||||||
|
}
|
14
src/ObjLoading/Parsing/Menu/MenuFileCommonOperations.h
Normal file
14
src/ObjLoading/Parsing/Menu/MenuFileCommonOperations.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "MenuFileParserState.h"
|
||||||
|
#include "Parsing/TokenPos.h"
|
||||||
|
#include "Parsing/Simple/Expression/ISimpleExpression.h"
|
||||||
|
|
||||||
|
namespace menu
|
||||||
|
{
|
||||||
|
class MenuFileCommonOperations
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void EnsureIsNumericExpression(const MenuFileParserState* state, const TokenPos& pos, const ISimpleExpression& expression);
|
||||||
|
static void EnsureIsStringExpression(const MenuFileParserState* state, const TokenPos& pos, const ISimpleExpression& expression);
|
||||||
|
};
|
||||||
|
}
|
@ -129,6 +129,7 @@ std::unique_ptr<ParsingResult> MenuFileReader::ReadMenuFile()
|
|||||||
SimpleLexer::Config lexerConfig;
|
SimpleLexer::Config lexerConfig;
|
||||||
lexerConfig.m_emit_new_line_tokens = false;
|
lexerConfig.m_emit_new_line_tokens = false;
|
||||||
lexerConfig.m_read_strings = true;
|
lexerConfig.m_read_strings = true;
|
||||||
|
lexerConfig.m_string_escape_sequences = true;
|
||||||
lexerConfig.m_read_integer_numbers = true;
|
lexerConfig.m_read_integer_numbers = true;
|
||||||
lexerConfig.m_read_floating_point_numbers = true;
|
lexerConfig.m_read_floating_point_numbers = true;
|
||||||
MenuExpressionMatchers().ApplyTokensToLexerConfig(lexerConfig);
|
MenuExpressionMatchers().ApplyTokensToLexerConfig(lexerConfig);
|
||||||
|
@ -235,7 +235,8 @@ namespace menu::event_handler_set_scope_sequences
|
|||||||
AddMatchers({
|
AddMatchers({
|
||||||
create.Or({
|
create.Or({
|
||||||
create.Numeric(),
|
create.Numeric(),
|
||||||
create.Text(),
|
create.String(),
|
||||||
|
create.Identifier(),
|
||||||
create.Type(SimpleParserValueType::CHARACTER),
|
create.Type(SimpleParserValueType::CHARACTER),
|
||||||
}).Capture(CAPTURE_SCRIPT_TOKEN)
|
}).Capture(CAPTURE_SCRIPT_TOKEN)
|
||||||
});
|
});
|
||||||
@ -579,8 +580,13 @@ namespace menu::event_handler_set_scope_sequences
|
|||||||
state->m_current_script << "\" ; ";
|
state->m_current_script << "\" ; ";
|
||||||
}
|
}
|
||||||
|
|
||||||
static void EmitDynamicSetLocalVar(const MenuFileParserState* state, const SetLocalVarType type, const std::string& varName, std::unique_ptr<ISimpleExpression> expression)
|
static void EmitDynamicSetLocalVar(MenuFileParserState* state, const SetLocalVarType type, const std::string& varName, std::unique_ptr<ISimpleExpression> expression)
|
||||||
{
|
{
|
||||||
|
auto remainingScript = state->m_current_script.str();
|
||||||
|
if (!remainingScript.empty())
|
||||||
|
state->m_current_nested_event_handler_set->m_elements.emplace_back(std::make_unique<CommonEventHandlerScript>(std::move(remainingScript)));
|
||||||
|
state->m_current_script.str(std::string());
|
||||||
|
|
||||||
state->m_current_nested_event_handler_set->m_elements.emplace_back(std::make_unique<CommonEventHandlerSetLocalVar>(type, varName, std::move(expression)));
|
state->m_current_nested_event_handler_set->m_elements.emplace_back(std::make_unique<CommonEventHandlerSetLocalVar>(type, varName, std::move(expression)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include "Generic/GenericKeywordPropertySequence.h"
|
#include "Generic/GenericKeywordPropertySequence.h"
|
||||||
#include "Generic/GenericMenuEventHandlerSetPropertySequence.h"
|
#include "Generic/GenericMenuEventHandlerSetPropertySequence.h"
|
||||||
#include "Generic/GenericStringPropertySequence.h"
|
#include "Generic/GenericStringPropertySequence.h"
|
||||||
|
#include "Parsing/Menu/MenuFileCommonOperations.h"
|
||||||
#include "Parsing/Menu/Matcher/MenuExpressionMatchers.h"
|
#include "Parsing/Menu/Matcher/MenuExpressionMatchers.h"
|
||||||
#include "Parsing/Menu/Matcher/MenuMatcherFactory.h"
|
#include "Parsing/Menu/Matcher/MenuMatcherFactory.h"
|
||||||
|
|
||||||
@ -45,6 +46,34 @@ class ItemScopeOperations
|
|||||||
CommonItemFeatureType::EDIT_FIELD // ITEM_TYPE_PASSWORDFIELD
|
CommonItemFeatureType::EDIT_FIELD // ITEM_TYPE_PASSWORDFIELD
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline static const CommonItemFeatureType IW5_FEATURE_TYPE_BY_TYPE[0x18]
|
||||||
|
{
|
||||||
|
CommonItemFeatureType::EDIT_FIELD, // ITEM_TYPE_TEXT
|
||||||
|
CommonItemFeatureType::NONE, // ITEM_TYPE_BUTTON
|
||||||
|
CommonItemFeatureType::NONE, // ITEM_TYPE_RADIOBUTTON
|
||||||
|
CommonItemFeatureType::NONE, // ITEM_TYPE_CHECKBOX
|
||||||
|
CommonItemFeatureType::EDIT_FIELD, // ITEM_TYPE_EDITFIELD
|
||||||
|
CommonItemFeatureType::NONE, // ITEM_TYPE_COMBO
|
||||||
|
CommonItemFeatureType::LISTBOX, // ITEM_TYPE_LISTBOX
|
||||||
|
CommonItemFeatureType::NONE, // ITEM_TYPE_MODEL
|
||||||
|
CommonItemFeatureType::NONE, // ITEM_TYPE_OWNERDRAW
|
||||||
|
CommonItemFeatureType::EDIT_FIELD, // ITEM_TYPE_NUMERICFIELD
|
||||||
|
CommonItemFeatureType::EDIT_FIELD, // ITEM_TYPE_SLIDER
|
||||||
|
CommonItemFeatureType::EDIT_FIELD, // ITEM_TYPE_YESNO
|
||||||
|
CommonItemFeatureType::MULTI_VALUE, // ITEM_TYPE_MULTI
|
||||||
|
CommonItemFeatureType::ENUM_DVAR, // ITEM_TYPE_DVARENUM
|
||||||
|
CommonItemFeatureType::EDIT_FIELD, // ITEM_TYPE_BIND
|
||||||
|
CommonItemFeatureType::NONE, // ITEM_TYPE_MENUMODEL
|
||||||
|
CommonItemFeatureType::EDIT_FIELD, // ITEM_TYPE_VALIDFILEFIELD
|
||||||
|
CommonItemFeatureType::EDIT_FIELD, // ITEM_TYPE_DECIMALFIELD
|
||||||
|
CommonItemFeatureType::EDIT_FIELD, // ITEM_TYPE_UPREDITFIELD
|
||||||
|
CommonItemFeatureType::NONE, // ITEM_TYPE_GAME_MESSAGE_WINDOW
|
||||||
|
CommonItemFeatureType::NEWS_TICKER, // ITEM_TYPE_NEWS_TICKER
|
||||||
|
CommonItemFeatureType::NONE, // ITEM_TYPE_TEXT_SCROLL
|
||||||
|
CommonItemFeatureType::EDIT_FIELD, // ITEM_TYPE_EMAILFIELD
|
||||||
|
CommonItemFeatureType::EDIT_FIELD // ITEM_TYPE_PASSWORDFIELD
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static void SetItemType(CommonItemDef& item, const FeatureLevel featureLevel, const TokenPos& pos, const int type)
|
static void SetItemType(CommonItemDef& item, const FeatureLevel featureLevel, const TokenPos& pos, const int type)
|
||||||
{
|
{
|
||||||
@ -66,8 +95,10 @@ public:
|
|||||||
|
|
||||||
case FeatureLevel::IW5:
|
case FeatureLevel::IW5:
|
||||||
default:
|
default:
|
||||||
assert(false);
|
if (static_cast<unsigned>(type) >= std::extent_v<decltype(IW5_FEATURE_TYPE_BY_TYPE)>)
|
||||||
throw ParsingException(pos, "Unimplemented item types for feature level");
|
throw ParsingException(pos, "Invalid item type");
|
||||||
|
item.m_feature_type = IW5_FEATURE_TYPE_BY_TYPE[static_cast<unsigned>(type)];
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (item.m_feature_type)
|
switch (item.m_feature_type)
|
||||||
@ -431,26 +462,46 @@ namespace menu::item_scope_sequences
|
|||||||
{
|
{
|
||||||
static constexpr auto CAPTURE_FIRST_TOKEN = 1;
|
static constexpr auto CAPTURE_FIRST_TOKEN = 1;
|
||||||
static constexpr auto CAPTURE_COLUMN_COUNT = 2;
|
static constexpr auto CAPTURE_COLUMN_COUNT = 2;
|
||||||
static constexpr auto CAPTURE_POS = 3;
|
static constexpr auto CAPTURE_X_POS = 3;
|
||||||
static constexpr auto CAPTURE_WIDTH = 4;
|
static constexpr auto CAPTURE_Y_POS = 4;
|
||||||
static constexpr auto CAPTURE_MAX_CHARS = 5;
|
static constexpr auto CAPTURE_WIDTH = 5;
|
||||||
static constexpr auto CAPTURE_ALIGNMENT = 6;
|
static constexpr auto CAPTURE_HEIGHT = 6;
|
||||||
|
static constexpr auto CAPTURE_MAX_CHARS = 7;
|
||||||
|
static constexpr auto CAPTURE_ALIGNMENT = 8;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SequenceColumns()
|
explicit SequenceColumns(const FeatureLevel featureLevel)
|
||||||
{
|
{
|
||||||
const MenuMatcherFactory create(this);
|
const MenuMatcherFactory create(this);
|
||||||
|
|
||||||
AddMatchers({
|
if (featureLevel == FeatureLevel::IW5)
|
||||||
create.KeywordIgnoreCase("columns").Capture(CAPTURE_FIRST_TOKEN),
|
{
|
||||||
create.Integer().Capture(CAPTURE_COLUMN_COUNT),
|
AddMatchers({
|
||||||
create.Loop(create.And({
|
create.KeywordIgnoreCase("columns").Capture(CAPTURE_FIRST_TOKEN),
|
||||||
create.Integer().Capture(CAPTURE_POS),
|
create.Integer().Capture(CAPTURE_COLUMN_COUNT),
|
||||||
create.Integer().Capture(CAPTURE_WIDTH),
|
create.Loop(create.And({
|
||||||
create.Integer().Capture(CAPTURE_MAX_CHARS),
|
create.Integer().Capture(CAPTURE_X_POS),
|
||||||
create.Integer().Capture(CAPTURE_ALIGNMENT),
|
create.Integer().Capture(CAPTURE_Y_POS),
|
||||||
})),
|
create.Integer().Capture(CAPTURE_WIDTH),
|
||||||
});
|
create.Integer().Capture(CAPTURE_HEIGHT),
|
||||||
|
create.Integer().Capture(CAPTURE_MAX_CHARS),
|
||||||
|
create.Integer().Capture(CAPTURE_ALIGNMENT),
|
||||||
|
})),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddMatchers({
|
||||||
|
create.KeywordIgnoreCase("columns").Capture(CAPTURE_FIRST_TOKEN),
|
||||||
|
create.Integer().Capture(CAPTURE_COLUMN_COUNT),
|
||||||
|
create.Loop(create.And({
|
||||||
|
create.Integer().Capture(CAPTURE_X_POS),
|
||||||
|
create.Integer().Capture(CAPTURE_WIDTH),
|
||||||
|
create.Integer().Capture(CAPTURE_MAX_CHARS),
|
||||||
|
create.Integer().Capture(CAPTURE_ALIGNMENT),
|
||||||
|
})),
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -461,14 +512,14 @@ namespace menu::item_scope_sequences
|
|||||||
ItemScopeOperations::EnsureHasListboxFeatures(*state->m_current_item, result.NextCapture(CAPTURE_FIRST_TOKEN).GetPos());
|
ItemScopeOperations::EnsureHasListboxFeatures(*state->m_current_item, result.NextCapture(CAPTURE_FIRST_TOKEN).GetPos());
|
||||||
|
|
||||||
const auto& listBoxFeatures = state->m_current_item->m_list_box_features;
|
const auto& listBoxFeatures = state->m_current_item->m_list_box_features;
|
||||||
while (result.HasNextCapture(CAPTURE_POS))
|
while (result.HasNextCapture(CAPTURE_X_POS))
|
||||||
{
|
{
|
||||||
CommonItemFeaturesListBox::Column column
|
CommonItemFeaturesListBox::Column column
|
||||||
{
|
{
|
||||||
result.NextCapture(CAPTURE_POS).IntegerValue(),
|
result.NextCapture(CAPTURE_X_POS).IntegerValue(),
|
||||||
0,
|
state->m_feature_level == FeatureLevel::IW5 ? result.NextCapture(CAPTURE_Y_POS).IntegerValue() : 0,
|
||||||
result.NextCapture(CAPTURE_WIDTH).IntegerValue(),
|
result.NextCapture(CAPTURE_WIDTH).IntegerValue(),
|
||||||
0,
|
state->m_feature_level == FeatureLevel::IW5 ? result.NextCapture(CAPTURE_HEIGHT).IntegerValue() : 0,
|
||||||
result.NextCapture(CAPTURE_MAX_CHARS).IntegerValue(),
|
result.NextCapture(CAPTURE_MAX_CHARS).IntegerValue(),
|
||||||
result.NextCapture(CAPTURE_ALIGNMENT).IntegerValue()
|
result.NextCapture(CAPTURE_ALIGNMENT).IntegerValue()
|
||||||
};
|
};
|
||||||
@ -613,12 +664,14 @@ void ItemScopeSequences::AddSequences(FeatureLevel featureLevel, bool permissive
|
|||||||
{
|
{
|
||||||
state->m_current_item->m_border_size = value;
|
state->m_current_item->m_border_size = value;
|
||||||
}));
|
}));
|
||||||
AddSequence(GenericExpressionPropertySequence::WithKeywordAndBool("visible", [](const MenuFileParserState* state, const TokenPos&, std::unique_ptr<ISimpleExpression> value)
|
AddSequence(GenericExpressionPropertySequence::WithKeywordAndBool("visible", [](const MenuFileParserState* state, const TokenPos& pos, std::unique_ptr<ISimpleExpression> value)
|
||||||
{
|
{
|
||||||
|
MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *value);
|
||||||
state->m_current_item->m_visible_expression = std::move(value);
|
state->m_current_item->m_visible_expression = std::move(value);
|
||||||
}));
|
}));
|
||||||
AddSequence(GenericExpressionPropertySequence::WithKeywordAndBool("disabled", [](const MenuFileParserState* state, const TokenPos&, std::unique_ptr<ISimpleExpression> value)
|
AddSequence(GenericExpressionPropertySequence::WithKeywordAndBool("disabled", [](const MenuFileParserState* state, const TokenPos& pos, std::unique_ptr<ISimpleExpression> value)
|
||||||
{
|
{
|
||||||
|
MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *value);
|
||||||
state->m_current_item->m_disabled_expression = std::move(value);
|
state->m_current_item->m_disabled_expression = std::move(value);
|
||||||
}));
|
}));
|
||||||
AddSequence(std::make_unique<GenericIntPropertySequence>("ownerdraw", [](const MenuFileParserState* state, const TokenPos&, const int value)
|
AddSequence(std::make_unique<GenericIntPropertySequence>("ownerdraw", [](const MenuFileParserState* state, const TokenPos&, const int value)
|
||||||
@ -681,36 +734,28 @@ void ItemScopeSequences::AddSequences(FeatureLevel featureLevel, bool permissive
|
|||||||
{
|
{
|
||||||
state->m_current_item->m_background = value;
|
state->m_current_item->m_background = value;
|
||||||
}));
|
}));
|
||||||
AddSequence(std::make_unique<GenericMenuEventHandlerSetPropertySequence>("onFocus", [](const MenuFileParserState* state, const TokenPos&) -> std::unique_ptr<CommonEventHandlerSet>&
|
AddSequence(std::make_unique<GenericMenuEventHandlerSetPropertySequence>("onFocus", [](const MenuFileParserState* state, const TokenPos&) -> std::unique_ptr<CommonEventHandlerSet>& {
|
||||||
{
|
|
||||||
return state->m_current_item->m_on_focus;
|
return state->m_current_item->m_on_focus;
|
||||||
}));
|
}));
|
||||||
AddSequence(std::make_unique<GenericMenuEventHandlerSetPropertySequence>("leaveFocus", [](const MenuFileParserState* state, const TokenPos&) -> std::unique_ptr<CommonEventHandlerSet>&
|
AddSequence(std::make_unique<GenericMenuEventHandlerSetPropertySequence>("leaveFocus", [](const MenuFileParserState* state, const TokenPos&) -> std::unique_ptr<CommonEventHandlerSet>& {
|
||||||
{
|
|
||||||
return state->m_current_item->m_on_leave_focus;
|
return state->m_current_item->m_on_leave_focus;
|
||||||
}));
|
}));
|
||||||
AddSequence(std::make_unique<GenericMenuEventHandlerSetPropertySequence>("mouseEnter", [](const MenuFileParserState* state, const TokenPos&) -> std::unique_ptr<CommonEventHandlerSet>&
|
AddSequence(std::make_unique<GenericMenuEventHandlerSetPropertySequence>("mouseEnter", [](const MenuFileParserState* state, const TokenPos&) -> std::unique_ptr<CommonEventHandlerSet>& {
|
||||||
{
|
|
||||||
return state->m_current_item->m_on_mouse_enter;
|
return state->m_current_item->m_on_mouse_enter;
|
||||||
}));
|
}));
|
||||||
AddSequence(std::make_unique<GenericMenuEventHandlerSetPropertySequence>("mouseExit", [](const MenuFileParserState* state, const TokenPos&) -> std::unique_ptr<CommonEventHandlerSet>&
|
AddSequence(std::make_unique<GenericMenuEventHandlerSetPropertySequence>("mouseExit", [](const MenuFileParserState* state, const TokenPos&) -> std::unique_ptr<CommonEventHandlerSet>& {
|
||||||
{
|
|
||||||
return state->m_current_item->m_on_mouse_exit;
|
return state->m_current_item->m_on_mouse_exit;
|
||||||
}));
|
}));
|
||||||
AddSequence(std::make_unique<GenericMenuEventHandlerSetPropertySequence>("mouseEnterText", [](const MenuFileParserState* state, const TokenPos&) -> std::unique_ptr<CommonEventHandlerSet>&
|
AddSequence(std::make_unique<GenericMenuEventHandlerSetPropertySequence>("mouseEnterText", [](const MenuFileParserState* state, const TokenPos&) -> std::unique_ptr<CommonEventHandlerSet>& {
|
||||||
{
|
|
||||||
return state->m_current_item->m_on_mouse_enter_text;
|
return state->m_current_item->m_on_mouse_enter_text;
|
||||||
}));
|
}));
|
||||||
AddSequence(std::make_unique<GenericMenuEventHandlerSetPropertySequence>("mouseExitText", [](const MenuFileParserState* state, const TokenPos&) -> std::unique_ptr<CommonEventHandlerSet>&
|
AddSequence(std::make_unique<GenericMenuEventHandlerSetPropertySequence>("mouseExitText", [](const MenuFileParserState* state, const TokenPos&) -> std::unique_ptr<CommonEventHandlerSet>& {
|
||||||
{
|
|
||||||
return state->m_current_item->m_on_mouse_exit_text;
|
return state->m_current_item->m_on_mouse_exit_text;
|
||||||
}));
|
}));
|
||||||
AddSequence(std::make_unique<GenericMenuEventHandlerSetPropertySequence>("action", [](const MenuFileParserState* state, const TokenPos&) -> std::unique_ptr<CommonEventHandlerSet>&
|
AddSequence(std::make_unique<GenericMenuEventHandlerSetPropertySequence>("action", [](const MenuFileParserState* state, const TokenPos&) -> std::unique_ptr<CommonEventHandlerSet>& {
|
||||||
{
|
|
||||||
return state->m_current_item->m_on_action;
|
return state->m_current_item->m_on_action;
|
||||||
}));
|
}));
|
||||||
AddSequence(std::make_unique<GenericMenuEventHandlerSetPropertySequence>("accept", [](const MenuFileParserState* state, const TokenPos&) -> std::unique_ptr<CommonEventHandlerSet>&
|
AddSequence(std::make_unique<GenericMenuEventHandlerSetPropertySequence>("accept", [](const MenuFileParserState* state, const TokenPos&) -> std::unique_ptr<CommonEventHandlerSet>& {
|
||||||
{
|
|
||||||
return state->m_current_item->m_on_accept;
|
return state->m_current_item->m_on_accept;
|
||||||
}));
|
}));
|
||||||
// special
|
// special
|
||||||
@ -761,101 +806,131 @@ void ItemScopeSequences::AddSequences(FeatureLevel featureLevel, bool permissive
|
|||||||
state->m_current_item->m_game_message_window_mode = value;
|
state->m_current_item->m_game_message_window_mode = value;
|
||||||
}));
|
}));
|
||||||
AddSequence(std::make_unique<SequenceDecodeEffect>());
|
AddSequence(std::make_unique<SequenceDecodeEffect>());
|
||||||
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "disabled"}, [](const MenuFileParserState* state, const TokenPos&, std::unique_ptr<ISimpleExpression> value)
|
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "disabled"}, [](const MenuFileParserState* state, const TokenPos& pos, std::unique_ptr<ISimpleExpression> value)
|
||||||
{
|
{
|
||||||
|
MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *value);
|
||||||
state->m_current_item->m_disabled_expression = std::move(value);
|
state->m_current_item->m_disabled_expression = std::move(value);
|
||||||
}));
|
}));
|
||||||
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "text"}, [](const MenuFileParserState* state, const TokenPos&, std::unique_ptr<ISimpleExpression> value)
|
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "text"}, [](const MenuFileParserState* state, const TokenPos& pos, std::unique_ptr<ISimpleExpression> value)
|
||||||
{
|
{
|
||||||
|
MenuFileCommonOperations::EnsureIsStringExpression(state, pos, *value);
|
||||||
state->m_current_item->m_text_expression = std::move(value);
|
state->m_current_item->m_text_expression = std::move(value);
|
||||||
}));
|
}));
|
||||||
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "material"}, [](const MenuFileParserState* state, const TokenPos&, std::unique_ptr<ISimpleExpression> value)
|
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "material"}, [](const MenuFileParserState* state, const TokenPos& pos, std::unique_ptr<ISimpleExpression> value)
|
||||||
{
|
{
|
||||||
|
MenuFileCommonOperations::EnsureIsStringExpression(state, pos, *value);
|
||||||
state->m_current_item->m_material_expression = std::move(value);
|
state->m_current_item->m_material_expression = std::move(value);
|
||||||
}));
|
}));
|
||||||
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "material"}, [](const MenuFileParserState* state, const TokenPos&, std::unique_ptr<ISimpleExpression> value)
|
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "rect", "X"}, [](const MenuFileParserState* state, const TokenPos& pos, std::unique_ptr<ISimpleExpression> value)
|
||||||
{
|
|
||||||
state->m_current_item->m_material_expression = std::move(value);
|
|
||||||
}));
|
|
||||||
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "rect", "X"}, [](const MenuFileParserState* state, const TokenPos&, std::unique_ptr<ISimpleExpression> value)
|
|
||||||
{
|
{
|
||||||
|
MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *value);
|
||||||
state->m_current_item->m_rect_x_exp = std::move(value);
|
state->m_current_item->m_rect_x_exp = std::move(value);
|
||||||
}));
|
}));
|
||||||
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "rect", "Y"}, [](const MenuFileParserState* state, const TokenPos&, std::unique_ptr<ISimpleExpression> value)
|
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "rect", "Y"}, [](const MenuFileParserState* state, const TokenPos& pos, std::unique_ptr<ISimpleExpression> value)
|
||||||
{
|
{
|
||||||
|
MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *value);
|
||||||
state->m_current_item->m_rect_y_exp = std::move(value);
|
state->m_current_item->m_rect_y_exp = std::move(value);
|
||||||
}));
|
}));
|
||||||
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "rect", "W"}, [](const MenuFileParserState* state, const TokenPos&, std::unique_ptr<ISimpleExpression> value)
|
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "rect", "W"}, [](const MenuFileParserState* state, const TokenPos& pos, std::unique_ptr<ISimpleExpression> value)
|
||||||
{
|
{
|
||||||
|
MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *value);
|
||||||
state->m_current_item->m_rect_w_exp = std::move(value);
|
state->m_current_item->m_rect_w_exp = std::move(value);
|
||||||
}));
|
}));
|
||||||
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "rect", "H"}, [](const MenuFileParserState* state, const TokenPos&, std::unique_ptr<ISimpleExpression> value)
|
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "rect", "H"}, [](const MenuFileParserState* state, const TokenPos& pos, std::unique_ptr<ISimpleExpression> value)
|
||||||
{
|
{
|
||||||
|
MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *value);
|
||||||
state->m_current_item->m_rect_h_exp = std::move(value);
|
state->m_current_item->m_rect_h_exp = std::move(value);
|
||||||
}));
|
}));
|
||||||
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "forecolor", "R"}, [](const MenuFileParserState* state, const TokenPos&, std::unique_ptr<ISimpleExpression> value)
|
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "forecolor", "R"}, [](const MenuFileParserState* state, const TokenPos& pos, std::unique_ptr<ISimpleExpression> value)
|
||||||
{
|
{
|
||||||
|
MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *value);
|
||||||
state->m_current_item->m_forecolor_expressions.m_r_exp = std::move(value);
|
state->m_current_item->m_forecolor_expressions.m_r_exp = std::move(value);
|
||||||
}));
|
}));
|
||||||
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "forecolor", "G"}, [](const MenuFileParserState* state, const TokenPos&, std::unique_ptr<ISimpleExpression> value)
|
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "forecolor", "G"}, [](const MenuFileParserState* state, const TokenPos& pos, std::unique_ptr<ISimpleExpression> value)
|
||||||
{
|
{
|
||||||
|
MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *value);
|
||||||
state->m_current_item->m_forecolor_expressions.m_g_exp = std::move(value);
|
state->m_current_item->m_forecolor_expressions.m_g_exp = std::move(value);
|
||||||
}));
|
}));
|
||||||
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "forecolor", "B"}, [](const MenuFileParserState* state, const TokenPos&, std::unique_ptr<ISimpleExpression> value)
|
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "forecolor", "B"}, [](const MenuFileParserState* state, const TokenPos& pos, std::unique_ptr<ISimpleExpression> value)
|
||||||
{
|
{
|
||||||
|
MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *value);
|
||||||
state->m_current_item->m_forecolor_expressions.m_b_exp = std::move(value);
|
state->m_current_item->m_forecolor_expressions.m_b_exp = std::move(value);
|
||||||
}));
|
}));
|
||||||
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "forecolor", "A"}, [](const MenuFileParserState* state, const TokenPos&, std::unique_ptr<ISimpleExpression> value)
|
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "forecolor", "A"}, [](const MenuFileParserState* state, const TokenPos& pos, std::unique_ptr<ISimpleExpression> value)
|
||||||
{
|
{
|
||||||
|
MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *value);
|
||||||
state->m_current_item->m_forecolor_expressions.m_a_exp = std::move(value);
|
state->m_current_item->m_forecolor_expressions.m_a_exp = std::move(value);
|
||||||
}));
|
}));
|
||||||
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "forecolor", "RGB"}, [](const MenuFileParserState* state, const TokenPos&, std::unique_ptr<ISimpleExpression> value)
|
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "forecolor", "RGB"}, [](const MenuFileParserState* state, const TokenPos& pos, std::unique_ptr<ISimpleExpression> value)
|
||||||
{
|
{
|
||||||
|
MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *value);
|
||||||
state->m_current_item->m_forecolor_expressions.m_rgb_exp = std::move(value);
|
state->m_current_item->m_forecolor_expressions.m_rgb_exp = std::move(value);
|
||||||
}));
|
}));
|
||||||
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "glowcolor", "R"}, [](const MenuFileParserState* state, const TokenPos&, std::unique_ptr<ISimpleExpression> value)
|
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "glowcolor", "R"}, [](const MenuFileParserState* state, const TokenPos& pos, std::unique_ptr<ISimpleExpression> value)
|
||||||
{
|
{
|
||||||
|
MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *value);
|
||||||
state->m_current_item->m_glowcolor_expressions.m_r_exp = std::move(value);
|
state->m_current_item->m_glowcolor_expressions.m_r_exp = std::move(value);
|
||||||
}));
|
}));
|
||||||
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "glowcolor", "G"}, [](const MenuFileParserState* state, const TokenPos&, std::unique_ptr<ISimpleExpression> value)
|
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "glowcolor", "G"}, [](const MenuFileParserState* state, const TokenPos& pos, std::unique_ptr<ISimpleExpression> value)
|
||||||
{
|
{
|
||||||
|
MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *value);
|
||||||
state->m_current_item->m_glowcolor_expressions.m_g_exp = std::move(value);
|
state->m_current_item->m_glowcolor_expressions.m_g_exp = std::move(value);
|
||||||
}));
|
}));
|
||||||
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "glowcolor", "B"}, [](const MenuFileParserState* state, const TokenPos&, std::unique_ptr<ISimpleExpression> value)
|
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "glowcolor", "B"}, [](const MenuFileParserState* state, const TokenPos& pos, std::unique_ptr<ISimpleExpression> value)
|
||||||
{
|
{
|
||||||
|
MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *value);
|
||||||
state->m_current_item->m_glowcolor_expressions.m_b_exp = std::move(value);
|
state->m_current_item->m_glowcolor_expressions.m_b_exp = std::move(value);
|
||||||
}));
|
}));
|
||||||
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "glowcolor", "A"}, [](const MenuFileParserState* state, const TokenPos&, std::unique_ptr<ISimpleExpression> value)
|
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "glowcolor", "A"}, [](const MenuFileParserState* state, const TokenPos& pos, std::unique_ptr<ISimpleExpression> value)
|
||||||
{
|
{
|
||||||
|
MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *value);
|
||||||
state->m_current_item->m_glowcolor_expressions.m_a_exp = std::move(value);
|
state->m_current_item->m_glowcolor_expressions.m_a_exp = std::move(value);
|
||||||
}));
|
}));
|
||||||
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "glowcolor", "RGB"}, [](const MenuFileParserState* state, const TokenPos&, std::unique_ptr<ISimpleExpression> value)
|
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "glowcolor", "RGB"}, [](const MenuFileParserState* state, const TokenPos& pos, std::unique_ptr<ISimpleExpression> value)
|
||||||
{
|
{
|
||||||
|
MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *value);
|
||||||
state->m_current_item->m_glowcolor_expressions.m_rgb_exp = std::move(value);
|
state->m_current_item->m_glowcolor_expressions.m_rgb_exp = std::move(value);
|
||||||
}));
|
}));
|
||||||
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "backcolor", "R"}, [](const MenuFileParserState* state, const TokenPos&, std::unique_ptr<ISimpleExpression> value)
|
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "backcolor", "R"}, [](const MenuFileParserState* state, const TokenPos& pos, std::unique_ptr<ISimpleExpression> value)
|
||||||
{
|
{
|
||||||
|
MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *value);
|
||||||
state->m_current_item->m_backcolor_expressions.m_r_exp = std::move(value);
|
state->m_current_item->m_backcolor_expressions.m_r_exp = std::move(value);
|
||||||
}));
|
}));
|
||||||
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "backcolor", "G"}, [](const MenuFileParserState* state, const TokenPos&, std::unique_ptr<ISimpleExpression> value)
|
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "backcolor", "G"}, [](const MenuFileParserState* state, const TokenPos& pos, std::unique_ptr<ISimpleExpression> value)
|
||||||
{
|
{
|
||||||
|
MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *value);
|
||||||
state->m_current_item->m_backcolor_expressions.m_g_exp = std::move(value);
|
state->m_current_item->m_backcolor_expressions.m_g_exp = std::move(value);
|
||||||
}));
|
}));
|
||||||
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "backcolor", "B"}, [](const MenuFileParserState* state, const TokenPos&, std::unique_ptr<ISimpleExpression> value)
|
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "backcolor", "B"}, [](const MenuFileParserState* state, const TokenPos& pos, std::unique_ptr<ISimpleExpression> value)
|
||||||
{
|
{
|
||||||
|
MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *value);
|
||||||
state->m_current_item->m_backcolor_expressions.m_b_exp = std::move(value);
|
state->m_current_item->m_backcolor_expressions.m_b_exp = std::move(value);
|
||||||
}));
|
}));
|
||||||
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "backcolor", "A"}, [](const MenuFileParserState* state, const TokenPos&, std::unique_ptr<ISimpleExpression> value)
|
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "backcolor", "A"}, [](const MenuFileParserState* state, const TokenPos& pos, std::unique_ptr<ISimpleExpression> value)
|
||||||
{
|
{
|
||||||
|
MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *value);
|
||||||
state->m_current_item->m_backcolor_expressions.m_a_exp = std::move(value);
|
state->m_current_item->m_backcolor_expressions.m_a_exp = std::move(value);
|
||||||
}));
|
}));
|
||||||
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "backcolor", "RGB"}, [](const MenuFileParserState* state, const TokenPos&, std::unique_ptr<ISimpleExpression> value)
|
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "backcolor", "RGB"}, [](const MenuFileParserState* state, const TokenPos& pos, std::unique_ptr<ISimpleExpression> value)
|
||||||
{
|
{
|
||||||
|
MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *value);
|
||||||
state->m_current_item->m_backcolor_expressions.m_rgb_exp = std::move(value);
|
state->m_current_item->m_backcolor_expressions.m_rgb_exp = std::move(value);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
if (featureLevel == FeatureLevel::IW5)
|
||||||
|
{
|
||||||
|
AddSequence(std::make_unique<GenericMenuEventHandlerSetPropertySequence>("hasFocus", [](const MenuFileParserState* state, const TokenPos&) -> std::unique_ptr<CommonEventHandlerSet>& {
|
||||||
|
return state->m_current_item->m_has_focus;
|
||||||
|
}));
|
||||||
|
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "textaligny"}, [](const MenuFileParserState* state, const TokenPos& pos, std::unique_ptr<ISimpleExpression> value)
|
||||||
|
{
|
||||||
|
MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *value);
|
||||||
|
state->m_current_item->m_text_align_y_expression = std::move(value);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
// ============== ListBox ==============
|
// ============== ListBox ==============
|
||||||
AddSequence(std::make_unique<SequenceColumns>());
|
AddSequence(std::make_unique<SequenceColumns>(featureLevel));
|
||||||
AddSequence(std::make_unique<GenericKeywordPropertySequence>("notselectable", [](const MenuFileParserState* state, const TokenPos& pos)
|
AddSequence(std::make_unique<GenericKeywordPropertySequence>("notselectable", [](const MenuFileParserState* state, const TokenPos& pos)
|
||||||
{
|
{
|
||||||
ItemScopeOperations::EnsureHasListboxFeatures(*state->m_current_item, pos);
|
ItemScopeOperations::EnsureHasListboxFeatures(*state->m_current_item, pos);
|
||||||
@ -891,8 +966,7 @@ void ItemScopeSequences::AddSequences(FeatureLevel featureLevel, bool permissive
|
|||||||
ItemScopeOperations::EnsureHasListboxFeatures(*state->m_current_item, pos);
|
ItemScopeOperations::EnsureHasListboxFeatures(*state->m_current_item, pos);
|
||||||
state->m_current_item->m_list_box_features->m_element_style = value;
|
state->m_current_item->m_list_box_features->m_element_style = value;
|
||||||
}));
|
}));
|
||||||
AddSequence(std::make_unique<GenericMenuEventHandlerSetPropertySequence>("doubleclick", [](const MenuFileParserState* state, const TokenPos& pos) -> std::unique_ptr<CommonEventHandlerSet>&
|
AddSequence(std::make_unique<GenericMenuEventHandlerSetPropertySequence>("doubleclick", [](const MenuFileParserState* state, const TokenPos& pos) -> std::unique_ptr<CommonEventHandlerSet>& {
|
||||||
{
|
|
||||||
ItemScopeOperations::EnsureHasListboxFeatures(*state->m_current_item, pos);
|
ItemScopeOperations::EnsureHasListboxFeatures(*state->m_current_item, pos);
|
||||||
return state->m_current_item->m_list_box_features->m_on_double_click;
|
return state->m_current_item->m_list_box_features->m_on_double_click;
|
||||||
}));
|
}));
|
||||||
@ -907,6 +981,16 @@ void ItemScopeSequences::AddSequences(FeatureLevel featureLevel, bool permissive
|
|||||||
state->m_current_item->m_list_box_features->m_select_icon = value;
|
state->m_current_item->m_list_box_features->m_select_icon = value;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
if (featureLevel == FeatureLevel::IW5)
|
||||||
|
{
|
||||||
|
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "elementheight"}, [](const MenuFileParserState* state, const TokenPos& pos, std::unique_ptr<ISimpleExpression> value)
|
||||||
|
{
|
||||||
|
ItemScopeOperations::EnsureHasListboxFeatures(*state->m_current_item, pos);
|
||||||
|
MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *value);
|
||||||
|
state->m_current_item->m_list_box_features->m_element_height_expression = std::move(value);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
// ============== Edit Field ==============
|
// ============== Edit Field ==============
|
||||||
AddSequence(std::make_unique<SequenceDvarFloat>());
|
AddSequence(std::make_unique<SequenceDvarFloat>());
|
||||||
AddSequence(std::make_unique<GenericStringPropertySequence>("localvar", [](const MenuFileParserState* state, const TokenPos& pos, const std::string& value)
|
AddSequence(std::make_unique<GenericStringPropertySequence>("localvar", [](const MenuFileParserState* state, const TokenPos& pos, const std::string& value)
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include "Generic/GenericKeywordPropertySequence.h"
|
#include "Generic/GenericKeywordPropertySequence.h"
|
||||||
#include "Generic/GenericMenuEventHandlerSetPropertySequence.h"
|
#include "Generic/GenericMenuEventHandlerSetPropertySequence.h"
|
||||||
#include "Generic/GenericStringPropertySequence.h"
|
#include "Generic/GenericStringPropertySequence.h"
|
||||||
|
#include "Parsing/Menu/MenuFileCommonOperations.h"
|
||||||
#include "Parsing/Menu/Matcher/MenuMatcherFactory.h"
|
#include "Parsing/Menu/Matcher/MenuMatcherFactory.h"
|
||||||
#include "Parsing/Menu/Domain/CommonMenuTypes.h"
|
#include "Parsing/Menu/Domain/CommonMenuTypes.h"
|
||||||
#include "Parsing/Menu/Matcher/MenuExpressionMatchers.h"
|
#include "Parsing/Menu/Matcher/MenuExpressionMatchers.h"
|
||||||
@ -254,24 +255,21 @@ void MenuScopeSequences::AddSequences(FeatureLevel featureLevel, bool permissive
|
|||||||
{
|
{
|
||||||
state->m_current_menu->m_style = value;
|
state->m_current_menu->m_style = value;
|
||||||
}));
|
}));
|
||||||
AddSequence(GenericExpressionPropertySequence::WithKeywordAndBool("visible", [](const MenuFileParserState* state, const TokenPos&, std::unique_ptr<ISimpleExpression> value)
|
AddSequence(GenericExpressionPropertySequence::WithKeywordAndBool("visible", [](const MenuFileParserState* state, const TokenPos& pos, std::unique_ptr<ISimpleExpression> value)
|
||||||
{
|
{
|
||||||
|
MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *value);
|
||||||
state->m_current_menu->m_visible_expression = std::move(value);
|
state->m_current_menu->m_visible_expression = std::move(value);
|
||||||
}));
|
}));
|
||||||
AddSequence(std::make_unique<GenericMenuEventHandlerSetPropertySequence>("onOpen", [](const MenuFileParserState* state, const TokenPos&) -> std::unique_ptr<CommonEventHandlerSet>&
|
AddSequence(std::make_unique<GenericMenuEventHandlerSetPropertySequence>("onOpen", [](const MenuFileParserState* state, const TokenPos&) -> std::unique_ptr<CommonEventHandlerSet>& {
|
||||||
{
|
|
||||||
return state->m_current_menu->m_on_open;
|
return state->m_current_menu->m_on_open;
|
||||||
}));
|
}));
|
||||||
AddSequence(std::make_unique<GenericMenuEventHandlerSetPropertySequence>("onClose", [](const MenuFileParserState* state, const TokenPos&) -> std::unique_ptr<CommonEventHandlerSet>&
|
AddSequence(std::make_unique<GenericMenuEventHandlerSetPropertySequence>("onClose", [](const MenuFileParserState* state, const TokenPos&) -> std::unique_ptr<CommonEventHandlerSet>& {
|
||||||
{
|
|
||||||
return state->m_current_menu->m_on_close;
|
return state->m_current_menu->m_on_close;
|
||||||
}));
|
}));
|
||||||
AddSequence(std::make_unique<GenericMenuEventHandlerSetPropertySequence>("onRequestClose", [](const MenuFileParserState* state, const TokenPos&) -> std::unique_ptr<CommonEventHandlerSet>&
|
AddSequence(std::make_unique<GenericMenuEventHandlerSetPropertySequence>("onRequestClose", [](const MenuFileParserState* state, const TokenPos&) -> std::unique_ptr<CommonEventHandlerSet>& {
|
||||||
{
|
|
||||||
return state->m_current_menu->m_on_request_close;
|
return state->m_current_menu->m_on_request_close;
|
||||||
}));
|
}));
|
||||||
AddSequence(std::make_unique<GenericMenuEventHandlerSetPropertySequence>("onESC", [](const MenuFileParserState* state, const TokenPos&) -> std::unique_ptr<CommonEventHandlerSet>&
|
AddSequence(std::make_unique<GenericMenuEventHandlerSetPropertySequence>("onESC", [](const MenuFileParserState* state, const TokenPos&) -> std::unique_ptr<CommonEventHandlerSet>& {
|
||||||
{
|
|
||||||
return state->m_current_menu->m_on_esc;
|
return state->m_current_menu->m_on_esc;
|
||||||
}));
|
}));
|
||||||
AddSequence(std::make_unique<GenericIntPropertySequence>("border", [](const MenuFileParserState* state, const TokenPos&, const int value)
|
AddSequence(std::make_unique<GenericIntPropertySequence>("border", [](const MenuFileParserState* state, const TokenPos&, const int value)
|
||||||
@ -322,28 +320,34 @@ void MenuScopeSequences::AddSequences(FeatureLevel featureLevel, bool permissive
|
|||||||
{
|
{
|
||||||
state->m_current_menu->m_sound_loop = value;
|
state->m_current_menu->m_sound_loop = value;
|
||||||
}));
|
}));
|
||||||
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "rect", "X"}, [](const MenuFileParserState* state, const TokenPos&, std::unique_ptr<ISimpleExpression> value)
|
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "rect", "X"}, [](const MenuFileParserState* state, const TokenPos& pos, std::unique_ptr<ISimpleExpression> value)
|
||||||
{
|
{
|
||||||
|
MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *value);
|
||||||
state->m_current_menu->m_rect_x_exp = std::move(value);
|
state->m_current_menu->m_rect_x_exp = std::move(value);
|
||||||
}));
|
}));
|
||||||
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "rect", "Y"}, [](const MenuFileParserState* state, const TokenPos&, std::unique_ptr<ISimpleExpression> value)
|
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "rect", "Y"}, [](const MenuFileParserState* state, const TokenPos& pos, std::unique_ptr<ISimpleExpression> value)
|
||||||
{
|
{
|
||||||
|
MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *value);
|
||||||
state->m_current_menu->m_rect_y_exp = std::move(value);
|
state->m_current_menu->m_rect_y_exp = std::move(value);
|
||||||
}));
|
}));
|
||||||
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "rect", "W"}, [](const MenuFileParserState* state, const TokenPos&, std::unique_ptr<ISimpleExpression> value)
|
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "rect", "W"}, [](const MenuFileParserState* state, const TokenPos& pos, std::unique_ptr<ISimpleExpression> value)
|
||||||
{
|
{
|
||||||
|
MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *value);
|
||||||
state->m_current_menu->m_rect_w_exp = std::move(value);
|
state->m_current_menu->m_rect_w_exp = std::move(value);
|
||||||
}));
|
}));
|
||||||
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "rect", "H"}, [](const MenuFileParserState* state, const TokenPos&, std::unique_ptr<ISimpleExpression> value)
|
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "rect", "H"}, [](const MenuFileParserState* state, const TokenPos& pos, std::unique_ptr<ISimpleExpression> value)
|
||||||
{
|
{
|
||||||
|
MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *value);
|
||||||
state->m_current_menu->m_rect_h_exp = std::move(value);
|
state->m_current_menu->m_rect_h_exp = std::move(value);
|
||||||
}));
|
}));
|
||||||
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "openSound"}, [](const MenuFileParserState* state, const TokenPos&, std::unique_ptr<ISimpleExpression> value)
|
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "openSound"}, [](const MenuFileParserState* state, const TokenPos& pos, std::unique_ptr<ISimpleExpression> value)
|
||||||
{
|
{
|
||||||
|
MenuFileCommonOperations::EnsureIsStringExpression(state, pos, *value);
|
||||||
state->m_current_menu->m_open_sound_exp = std::move(value);
|
state->m_current_menu->m_open_sound_exp = std::move(value);
|
||||||
}));
|
}));
|
||||||
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "closeSound"}, [](const MenuFileParserState* state, const TokenPos&, std::unique_ptr<ISimpleExpression> value)
|
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "closeSound"}, [](const MenuFileParserState* state, const TokenPos& pos, std::unique_ptr<ISimpleExpression> value)
|
||||||
{
|
{
|
||||||
|
MenuFileCommonOperations::EnsureIsStringExpression(state, pos, *value);
|
||||||
state->m_current_menu->m_close_sound_exp = std::move(value);
|
state->m_current_menu->m_close_sound_exp = std::move(value);
|
||||||
}));
|
}));
|
||||||
AddSequence(std::make_unique<GenericKeywordPropertySequence>("popup", [](const MenuFileParserState* state, const TokenPos&)
|
AddSequence(std::make_unique<GenericKeywordPropertySequence>("popup", [](const MenuFileParserState* state, const TokenPos&)
|
||||||
@ -396,5 +400,20 @@ void MenuScopeSequences::AddSequences(FeatureLevel featureLevel, bool permissive
|
|||||||
{
|
{
|
||||||
state->m_current_menu->m_text_only_focus = true;
|
state->m_current_menu->m_text_only_focus = true;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
if (featureLevel == FeatureLevel::IW5)
|
||||||
|
{
|
||||||
|
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "soundLoop"}, [](const MenuFileParserState* state, const TokenPos& pos, std::unique_ptr<ISimpleExpression> value)
|
||||||
|
{
|
||||||
|
MenuFileCommonOperations::EnsureIsStringExpression(state, pos, *value);
|
||||||
|
state->m_current_menu->m_sound_loop_exp = std::move(value);
|
||||||
|
}));
|
||||||
|
AddSequence(std::make_unique<GenericMenuEventHandlerSetPropertySequence>("onFocusDueToClose", [](const MenuFileParserState* state, const TokenPos&) -> std::unique_ptr<CommonEventHandlerSet>& {
|
||||||
|
return state->m_current_menu->m_on_focus_due_to_close;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
AddSequence(std::make_unique<SequenceConsumeSemicolons>());
|
AddSequence(std::make_unique<SequenceConsumeSemicolons>());
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,7 @@ std::vector<std::unique_ptr<CommonStructuredDataDef>> StructuredDataDefReader::R
|
|||||||
SimpleLexer::Config lexerConfig;
|
SimpleLexer::Config lexerConfig;
|
||||||
lexerConfig.m_emit_new_line_tokens = false;
|
lexerConfig.m_emit_new_line_tokens = false;
|
||||||
lexerConfig.m_read_strings = true;
|
lexerConfig.m_read_strings = true;
|
||||||
|
lexerConfig.m_string_escape_sequences = true;
|
||||||
lexerConfig.m_read_integer_numbers = true;
|
lexerConfig.m_read_integer_numbers = true;
|
||||||
lexerConfig.m_read_floating_point_numbers = true;
|
lexerConfig.m_read_floating_point_numbers = true;
|
||||||
const auto lexer = std::make_unique<SimpleLexer>(m_stream, std::move(lexerConfig));
|
const auto lexer = std::make_unique<SimpleLexer>(m_stream, std::move(lexerConfig));
|
||||||
|
@ -22,6 +22,7 @@ bool TechniqueFileReader::ReadTechniqueDefinition() const
|
|||||||
SimpleLexer::Config lexerConfig;
|
SimpleLexer::Config lexerConfig;
|
||||||
lexerConfig.m_emit_new_line_tokens = false;
|
lexerConfig.m_emit_new_line_tokens = false;
|
||||||
lexerConfig.m_read_strings = true;
|
lexerConfig.m_read_strings = true;
|
||||||
|
lexerConfig.m_string_escape_sequences = false;
|
||||||
lexerConfig.m_read_integer_numbers = true;
|
lexerConfig.m_read_integer_numbers = true;
|
||||||
lexerConfig.m_read_floating_point_numbers = true;
|
lexerConfig.m_read_floating_point_numbers = true;
|
||||||
const auto lexer = std::make_unique<SimpleLexer>(m_comment_proxy.get(), std::move(lexerConfig));
|
const auto lexer = std::make_unique<SimpleLexer>(m_comment_proxy.get(), std::move(lexerConfig));
|
||||||
|
@ -22,6 +22,7 @@ std::unique_ptr<techset::TechsetDefinition> TechsetFileReader::ReadTechsetDefini
|
|||||||
SimpleLexer::Config lexerConfig;
|
SimpleLexer::Config lexerConfig;
|
||||||
lexerConfig.m_emit_new_line_tokens = false;
|
lexerConfig.m_emit_new_line_tokens = false;
|
||||||
lexerConfig.m_read_strings = true;
|
lexerConfig.m_read_strings = true;
|
||||||
|
lexerConfig.m_string_escape_sequences = false;
|
||||||
lexerConfig.m_read_integer_numbers = false;
|
lexerConfig.m_read_integer_numbers = false;
|
||||||
lexerConfig.m_read_floating_point_numbers = false;
|
lexerConfig.m_read_floating_point_numbers = false;
|
||||||
const auto lexer = std::make_unique<SimpleLexer>(m_comment_proxy.get(), std::move(lexerConfig));
|
const auto lexer = std::make_unique<SimpleLexer>(m_comment_proxy.get(), std::move(lexerConfig));
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#include "StringFileDumper.h"
|
#include "StringFileDumper.h"
|
||||||
#include <regex>
|
#include <regex>
|
||||||
|
|
||||||
|
#include "Utils/StringUtils.h"
|
||||||
|
|
||||||
StringFileDumper::StringFileDumper(Zone* zone, std::ostream& stream)
|
StringFileDumper::StringFileDumper(Zone* zone, std::ostream& stream)
|
||||||
: AbstractTextDumper(stream),
|
: AbstractTextDumper(stream),
|
||||||
m_zone(zone),
|
m_zone(zone),
|
||||||
@ -36,19 +38,32 @@ void StringFileDumper::WriteHeader()
|
|||||||
m_wrote_header = true;
|
m_wrote_header = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void StringFileDumper::WriteReference(const std::string& reference) const
|
||||||
|
{
|
||||||
|
if (reference.find_first_not_of(utils::LETTERS_AL_NUM_UNDERSCORE) != std::string::npos)
|
||||||
|
{
|
||||||
|
m_stream << "REFERENCE \"";
|
||||||
|
|
||||||
|
utils::EscapeStringForQuotationMarks(m_stream, reference);
|
||||||
|
|
||||||
|
m_stream << "\"\n";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_stream << "REFERENCE " << reference << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
void StringFileDumper::WriteLocalizeEntry(const std::string& reference, const std::string& value)
|
void StringFileDumper::WriteLocalizeEntry(const std::string& reference, const std::string& value)
|
||||||
{
|
{
|
||||||
if (!m_wrote_header)
|
if (!m_wrote_header)
|
||||||
WriteHeader();
|
WriteHeader();
|
||||||
|
|
||||||
m_stream << "\n";
|
m_stream << "\n";
|
||||||
m_stream << "REFERENCE " << reference << "\n";
|
WriteReference(reference);
|
||||||
|
|
||||||
auto escapedValue = std::regex_replace(value, std::regex("\n"), "\\n");
|
|
||||||
escapedValue = std::regex_replace(escapedValue, std::regex("\r"), "\\r");
|
|
||||||
|
|
||||||
const auto valueSpacing = std::string(15 - m_language_caps.length(), ' ');
|
const auto valueSpacing = std::string(15 - m_language_caps.length(), ' ');
|
||||||
m_stream << "LANG_" << m_language_caps << valueSpacing << "\"" << escapedValue << "\"\n";
|
m_stream << "LANG_" << m_language_caps << valueSpacing << "\"";
|
||||||
|
utils::EscapeStringForQuotationMarks(m_stream, value);
|
||||||
|
m_stream << "\"\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void StringFileDumper::Finalize()
|
void StringFileDumper::Finalize()
|
||||||
|
@ -14,6 +14,7 @@ class StringFileDumper : AbstractTextDumper
|
|||||||
bool m_wrote_header;
|
bool m_wrote_header;
|
||||||
|
|
||||||
void WriteHeader();
|
void WriteHeader();
|
||||||
|
void WriteReference(const std::string& reference) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
StringFileDumper(Zone* zone, std::ostream& stream);
|
StringFileDumper(Zone* zone, std::ostream& stream);
|
||||||
|
@ -25,7 +25,7 @@ void AssetDumperLocalizeEntry::DumpPool(AssetDumpingContext& context, AssetPool<
|
|||||||
stringFileDumper.SetLanguageName(language);
|
stringFileDumper.SetLanguageName(language);
|
||||||
|
|
||||||
// Magic string. Original string files do have this config file. The purpose of the config file is unknown though.
|
// Magic string. Original string files do have this config file. The purpose of the config file is unknown though.
|
||||||
stringFileDumper.SetConfigFile(R"(C:\trees\cod3\cod3\bin\StringEd.cfg)");
|
stringFileDumper.SetConfigFile(R"(C:/trees/cod3/cod3/bin/StringEd.cfg)");
|
||||||
|
|
||||||
stringFileDumper.SetNotes("");
|
stringFileDumper.SetNotes("");
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ void AssetDumperLocalizeEntry::DumpPool(AssetDumpingContext& context, AssetPool<
|
|||||||
stringFileDumper.SetLanguageName(language);
|
stringFileDumper.SetLanguageName(language);
|
||||||
|
|
||||||
// Magic string. Original string files do have this config file. The purpose of the config file is unknown though.
|
// Magic string. Original string files do have this config file. The purpose of the config file is unknown though.
|
||||||
stringFileDumper.SetConfigFile(R"(C:\trees\cod3\cod3\bin\StringEd.cfg)");
|
stringFileDumper.SetConfigFile(R"(C:/trees/cod3/cod3/bin/StringEd.cfg)");
|
||||||
|
|
||||||
stringFileDumper.SetNotes("");
|
stringFileDumper.SetNotes("");
|
||||||
|
|
||||||
|
@ -137,7 +137,7 @@ void MenuDumper::WriteStatementOperator(const Statement_s* statement, size_t& cu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MenuDumper::WriteStatementOperandFunction(const Statement_s* statement, size_t currentPos) const
|
void MenuDumper::WriteStatementOperandFunction(const Statement_s* statement, const size_t currentPos) const
|
||||||
{
|
{
|
||||||
const auto& operand = statement->entries[currentPos].data.operand;
|
const auto& operand = statement->entries[currentPos].data.operand;
|
||||||
|
|
||||||
@ -160,7 +160,7 @@ void MenuDumper::WriteStatementOperandFunction(const Statement_s* statement, siz
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (functionIndex >= 0)
|
if (functionIndex >= 0)
|
||||||
m_stream << "FUNC_" << functionIndex;
|
m_stream << "FUNC_" << functionIndex << "()";
|
||||||
else
|
else
|
||||||
m_stream << "INVALID_FUNC";
|
m_stream << "INVALID_FUNC";
|
||||||
m_stream << "()";
|
m_stream << "()";
|
||||||
@ -193,7 +193,7 @@ void MenuDumper::WriteStatementOperand(const Statement_s* statement, size_t& cur
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case VAL_STRING:
|
case VAL_STRING:
|
||||||
m_stream << "\"" << operand.internals.stringVal.string << "\"";
|
WriteEscapedString(operand.internals.stringVal.string);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VAL_FUNCTION:
|
case VAL_FUNCTION:
|
||||||
@ -645,6 +645,7 @@ void MenuDumper::WriteMultiProperties(const itemDef_s* item) const
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
WriteStringProperty("dvar", item->dvar);
|
WriteStringProperty("dvar", item->dvar);
|
||||||
|
WriteStringProperty("localvar", item->localVar);
|
||||||
WriteMultiValueProperty(multiDef);
|
WriteMultiValueProperty(multiDef);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -653,6 +654,8 @@ void MenuDumper::WriteEnumDvarProperties(const itemDef_s* item) const
|
|||||||
if (item->type != ITEM_TYPE_DVARENUM)
|
if (item->type != ITEM_TYPE_DVARENUM)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
WriteStringProperty("dvar", item->dvar);
|
||||||
|
WriteStringProperty("localvar", item->localVar);
|
||||||
WriteStringProperty("dvarEnumList", item->typeData.enumDvarName);
|
WriteStringProperty("dvarEnumList", item->typeData.enumDvarName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -770,6 +773,7 @@ void MenuDumper::WriteMenuData(const menuDef_t* menu)
|
|||||||
WriteColorProperty("forecolor", menu->window.foreColor, COLOR_1111);
|
WriteColorProperty("forecolor", menu->window.foreColor, COLOR_1111);
|
||||||
WriteColorProperty("bordercolor", menu->window.borderColor, COLOR_0000);
|
WriteColorProperty("bordercolor", menu->window.borderColor, COLOR_0000);
|
||||||
WriteColorProperty("focuscolor", menu->focusColor, COLOR_0000);
|
WriteColorProperty("focuscolor", menu->focusColor, COLOR_0000);
|
||||||
|
WriteColorProperty("outlinecolor", menu->window.outlineColor, COLOR_0000);
|
||||||
WriteMaterialProperty("background", menu->window.background);
|
WriteMaterialProperty("background", menu->window.background);
|
||||||
WriteIntProperty("ownerdraw", menu->window.ownerDraw, 0);
|
WriteIntProperty("ownerdraw", menu->window.ownerDraw, 0);
|
||||||
WriteFlagsProperty("ownerdrawFlag", menu->window.ownerDrawFlags);
|
WriteFlagsProperty("ownerdrawFlag", menu->window.ownerDrawFlags);
|
||||||
|
@ -25,7 +25,7 @@ void AssetDumperLocalizeEntry::DumpPool(AssetDumpingContext& context, AssetPool<
|
|||||||
stringFileDumper.SetLanguageName(language);
|
stringFileDumper.SetLanguageName(language);
|
||||||
|
|
||||||
// Magic string. Original string files do have this config file. The purpose of the config file is unknown though.
|
// Magic string. Original string files do have this config file. The purpose of the config file is unknown though.
|
||||||
stringFileDumper.SetConfigFile(R"(C:\trees\cod3\cod3\bin\StringEd.cfg)");
|
stringFileDumper.SetConfigFile(R"(C:/trees/cod3/cod3/bin/StringEd.cfg)");
|
||||||
|
|
||||||
stringFileDumper.SetNotes("");
|
stringFileDumper.SetNotes("");
|
||||||
|
|
||||||
|
@ -137,7 +137,7 @@ void MenuDumper::WriteStatementOperator(const Statement_s* statement, size_t& cu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MenuDumper::WriteStatementOperandFunction(const Statement_s* statement, size_t currentPos) const
|
void MenuDumper::WriteStatementOperandFunction(const Statement_s* statement, const size_t currentPos) const
|
||||||
{
|
{
|
||||||
const auto& operand = statement->entries[currentPos].data.operand;
|
const auto& operand = statement->entries[currentPos].data.operand;
|
||||||
|
|
||||||
@ -160,7 +160,7 @@ void MenuDumper::WriteStatementOperandFunction(const Statement_s* statement, siz
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (functionIndex >= 0)
|
if (functionIndex >= 0)
|
||||||
m_stream << "FUNC_" << functionIndex;
|
m_stream << "FUNC_" << functionIndex << "()";
|
||||||
else
|
else
|
||||||
m_stream << "INVALID_FUNC";
|
m_stream << "INVALID_FUNC";
|
||||||
}
|
}
|
||||||
@ -192,7 +192,7 @@ void MenuDumper::WriteStatementOperand(const Statement_s* statement, size_t& cur
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case VAL_STRING:
|
case VAL_STRING:
|
||||||
m_stream << "\"" << operand.internals.stringVal.string << "\"";
|
WriteEscapedString(operand.internals.stringVal.string);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VAL_FUNCTION:
|
case VAL_FUNCTION:
|
||||||
@ -492,6 +492,31 @@ void MenuDumper::WriteFloatExpressionsProperty(const ItemFloatExpression* floatE
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MenuDumper::WriteMultiTokenStringProperty(const std::string& propertyKey, const char* value) const
|
||||||
|
{
|
||||||
|
if (!value)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Indent();
|
||||||
|
WriteKey(propertyKey);
|
||||||
|
|
||||||
|
const auto tokenList = CreateScriptTokenList(value);
|
||||||
|
|
||||||
|
auto firstToken = true;
|
||||||
|
m_stream << "{ ";
|
||||||
|
for (const auto& token : tokenList)
|
||||||
|
{
|
||||||
|
if (firstToken)
|
||||||
|
firstToken = false;
|
||||||
|
else
|
||||||
|
m_stream << ";";
|
||||||
|
m_stream << "\"" << token << "\"";
|
||||||
|
}
|
||||||
|
if (!firstToken)
|
||||||
|
m_stream << " ";
|
||||||
|
m_stream << "}\n";
|
||||||
|
}
|
||||||
|
|
||||||
void MenuDumper::WriteColumnProperty(const std::string& propertyKey, const listBoxDef_s* listBox) const
|
void MenuDumper::WriteColumnProperty(const std::string& propertyKey, const listBoxDef_s* listBox) const
|
||||||
{
|
{
|
||||||
if (listBox->numColumns <= 0)
|
if (listBox->numColumns <= 0)
|
||||||
@ -533,7 +558,7 @@ void MenuDumper::WriteListBoxProperties(const itemDef_s* item)
|
|||||||
WriteMenuEventHandlerSetProperty("doubleclick", listBox->onDoubleClick);
|
WriteMenuEventHandlerSetProperty("doubleclick", listBox->onDoubleClick);
|
||||||
WriteColorProperty("selectBorder", listBox->selectBorder, COLOR_0000);
|
WriteColorProperty("selectBorder", listBox->selectBorder, COLOR_0000);
|
||||||
WriteMaterialProperty("selectIcon", listBox->selectIcon);
|
WriteMaterialProperty("selectIcon", listBox->selectIcon);
|
||||||
WriteStatementProperty("exp elementHeight", listBox->elementHeightExp, false);
|
WriteStatementProperty("exp elementheight", listBox->elementHeightExp, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MenuDumper::WriteDvarFloatProperty(const std::string& propertyKey, const itemDef_s* item, const editFieldDef_s* editField) const
|
void MenuDumper::WriteDvarFloatProperty(const std::string& propertyKey, const itemDef_s* item, const editFieldDef_s* editField) const
|
||||||
@ -622,6 +647,7 @@ void MenuDumper::WriteMultiProperties(const itemDef_s* item) const
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
WriteStringProperty("dvar", item->dvar);
|
WriteStringProperty("dvar", item->dvar);
|
||||||
|
WriteStringProperty("localvar", item->localVar);
|
||||||
WriteMultiValueProperty(multiDef);
|
WriteMultiValueProperty(multiDef);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -630,6 +656,8 @@ void MenuDumper::WriteEnumDvarProperties(const itemDef_s* item) const
|
|||||||
if (item->type != ITEM_TYPE_DVARENUM)
|
if (item->type != ITEM_TYPE_DVARENUM)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
WriteStringProperty("dvar", item->dvar);
|
||||||
|
WriteStringProperty("localvar", item->localVar);
|
||||||
WriteStringProperty("dvarEnumList", item->typeData.enumDvarName);
|
WriteStringProperty("dvarEnumList", item->typeData.enumDvarName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -651,7 +679,7 @@ void MenuDumper::WriteItemData(const itemDef_s* item)
|
|||||||
WriteKeywordProperty("textsavegame", item->itemFlags & ITEM_FLAG_SAVE_GAME_INFO);
|
WriteKeywordProperty("textsavegame", item->itemFlags & ITEM_FLAG_SAVE_GAME_INFO);
|
||||||
WriteKeywordProperty("textcinematicsubtitle", item->itemFlags & ITEM_FLAG_CINEMATIC_SUBTITLE);
|
WriteKeywordProperty("textcinematicsubtitle", item->itemFlags & ITEM_FLAG_CINEMATIC_SUBTITLE);
|
||||||
WriteStringProperty("group", item->window.group);
|
WriteStringProperty("group", item->window.group);
|
||||||
WriteRectProperty("rect", item->window.rect);
|
WriteRectProperty("rect", item->window.rectClient);
|
||||||
WriteIntProperty("style", item->window.style, 0);
|
WriteIntProperty("style", item->window.style, 0);
|
||||||
WriteKeywordProperty("decoration", item->window.staticFlags & WINDOW_FLAG_DECORATION);
|
WriteKeywordProperty("decoration", item->window.staticFlags & WINDOW_FLAG_DECORATION);
|
||||||
WriteKeywordProperty("autowrapped", item->window.staticFlags & WINDOW_FLAG_AUTO_WRAPPED);
|
WriteKeywordProperty("autowrapped", item->window.staticFlags & WINDOW_FLAG_AUTO_WRAPPED);
|
||||||
@ -659,9 +687,15 @@ void MenuDumper::WriteItemData(const itemDef_s* item)
|
|||||||
WriteIntProperty("type", item->type, ITEM_TYPE_TEXT);
|
WriteIntProperty("type", item->type, ITEM_TYPE_TEXT);
|
||||||
WriteIntProperty("border", item->window.border, 0);
|
WriteIntProperty("border", item->window.border, 0);
|
||||||
WriteFloatProperty("borderSize", item->window.borderSize, 0.0f);
|
WriteFloatProperty("borderSize", item->window.borderSize, 0.0f);
|
||||||
WriteStatementProperty("visible", item->visibleExp, true);
|
|
||||||
|
if (item->visibleExp)
|
||||||
|
WriteStatementProperty("visible", item->visibleExp, true);
|
||||||
|
else if (item->window.dynamicFlags[0] & WINDOW_FLAG_VISIBLE)
|
||||||
|
WriteIntProperty("visible", 1, 0);
|
||||||
|
|
||||||
WriteStatementProperty("disabled", item->disabledExp, true);
|
WriteStatementProperty("disabled", item->disabledExp, true);
|
||||||
WriteIntProperty("ownerDraw", item->window.ownerDraw, 0);
|
WriteIntProperty("ownerdraw", item->window.ownerDraw, 0);
|
||||||
|
WriteFlagsProperty("ownerdrawFlag", item->window.ownerDrawFlags);
|
||||||
WriteIntProperty("align", item->alignment, 0);
|
WriteIntProperty("align", item->alignment, 0);
|
||||||
WriteIntProperty("textalign", item->textAlignMode, 0);
|
WriteIntProperty("textalign", item->textAlignMode, 0);
|
||||||
WriteFloatProperty("textalignx", item->textalignx, 0.0f);
|
WriteFloatProperty("textalignx", item->textalignx, 0.0f);
|
||||||
@ -687,19 +721,18 @@ void MenuDumper::WriteItemData(const itemDef_s* item)
|
|||||||
WriteMenuEventHandlerSetProperty("accept", item->accept);
|
WriteMenuEventHandlerSetProperty("accept", item->accept);
|
||||||
// WriteFloatProperty("special", item->special, 0.0f);
|
// WriteFloatProperty("special", item->special, 0.0f);
|
||||||
WriteSoundAliasProperty("focusSound", item->focusSound);
|
WriteSoundAliasProperty("focusSound", item->focusSound);
|
||||||
WriteFlagsProperty("ownerdrawFlag", item->window.ownerDrawFlags);
|
|
||||||
WriteStringProperty("dvarTest", item->dvarTest);
|
WriteStringProperty("dvarTest", item->dvarTest);
|
||||||
|
|
||||||
if (item->dvarFlags & ITEM_DVAR_FLAG_ENABLE)
|
if (item->dvarFlags & ITEM_DVAR_FLAG_ENABLE)
|
||||||
WriteStringProperty("enableDvar", item->enableDvar);
|
WriteMultiTokenStringProperty("enableDvar", item->enableDvar);
|
||||||
else if (item->dvarFlags & ITEM_DVAR_FLAG_DISABLE)
|
else if (item->dvarFlags & ITEM_DVAR_FLAG_DISABLE)
|
||||||
WriteStringProperty("disableDvar", item->enableDvar);
|
WriteMultiTokenStringProperty("disableDvar", item->enableDvar);
|
||||||
else if (item->dvarFlags & ITEM_DVAR_FLAG_SHOW)
|
else if (item->dvarFlags & ITEM_DVAR_FLAG_SHOW)
|
||||||
WriteStringProperty("showDvar", item->enableDvar);
|
WriteMultiTokenStringProperty("showDvar", item->enableDvar);
|
||||||
else if (item->dvarFlags & ITEM_DVAR_FLAG_HIDE)
|
else if (item->dvarFlags & ITEM_DVAR_FLAG_HIDE)
|
||||||
WriteStringProperty("hideDvar", item->enableDvar);
|
WriteMultiTokenStringProperty("hideDvar", item->enableDvar);
|
||||||
else if (item->dvarFlags & ITEM_DVAR_FLAG_FOCUS)
|
else if (item->dvarFlags & ITEM_DVAR_FLAG_FOCUS)
|
||||||
WriteStringProperty("focusDvar", item->enableDvar);
|
WriteMultiTokenStringProperty("focusDvar", item->enableDvar);
|
||||||
|
|
||||||
WriteItemKeyHandlerProperty(item->onKey);
|
WriteItemKeyHandlerProperty(item->onKey);
|
||||||
WriteStatementProperty("exp text", item->textExp, false);
|
WriteStatementProperty("exp text", item->textExp, false);
|
||||||
@ -744,6 +777,7 @@ void MenuDumper::WriteMenuData(const menuDef_t* menu)
|
|||||||
WriteColorProperty("forecolor", menu->window.foreColor, COLOR_1111);
|
WriteColorProperty("forecolor", menu->window.foreColor, COLOR_1111);
|
||||||
WriteColorProperty("bordercolor", menu->window.borderColor, COLOR_0000);
|
WriteColorProperty("bordercolor", menu->window.borderColor, COLOR_0000);
|
||||||
WriteColorProperty("focuscolor", menu->data->focusColor, COLOR_0000);
|
WriteColorProperty("focuscolor", menu->data->focusColor, COLOR_0000);
|
||||||
|
WriteColorProperty("outlinecolor", menu->window.outlineColor, COLOR_0000);
|
||||||
WriteMaterialProperty("background", menu->window.background);
|
WriteMaterialProperty("background", menu->window.background);
|
||||||
WriteIntProperty("ownerdraw", menu->window.ownerDraw, 0);
|
WriteIntProperty("ownerdraw", menu->window.ownerDraw, 0);
|
||||||
WriteFlagsProperty("ownerdrawFlag", menu->window.ownerDrawFlags);
|
WriteFlagsProperty("ownerdrawFlag", menu->window.ownerDrawFlags);
|
||||||
@ -761,7 +795,12 @@ void MenuDumper::WriteMenuData(const menuDef_t* menu)
|
|||||||
WriteKeywordProperty("hiddenDuringUI", menu->window.staticFlags & WINDOW_FLAG_HIDDEN_DURING_UI);
|
WriteKeywordProperty("hiddenDuringUI", menu->window.staticFlags & WINDOW_FLAG_HIDDEN_DURING_UI);
|
||||||
WriteStringProperty("allowedBinding", menu->data->allowedBinding);
|
WriteStringProperty("allowedBinding", menu->data->allowedBinding);
|
||||||
WriteKeywordProperty("textOnlyFocus", menu->window.staticFlags & WINDOW_FLAG_TEXT_ONLY_FOCUS);
|
WriteKeywordProperty("textOnlyFocus", menu->window.staticFlags & WINDOW_FLAG_TEXT_ONLY_FOCUS);
|
||||||
WriteStatementProperty("visible", menu->data->visibleExp, true);
|
|
||||||
|
if (menu->data->visibleExp)
|
||||||
|
WriteStatementProperty("visible", menu->data->visibleExp, true);
|
||||||
|
else if (menu->window.dynamicFlags[0] & WINDOW_FLAG_VISIBLE)
|
||||||
|
WriteIntProperty("visible", 1, 0);
|
||||||
|
|
||||||
WriteStatementProperty("exp rect X", menu->data->rectXExp, false);
|
WriteStatementProperty("exp rect X", menu->data->rectXExp, false);
|
||||||
WriteStatementProperty("exp rect Y", menu->data->rectYExp, false);
|
WriteStatementProperty("exp rect Y", menu->data->rectYExp, false);
|
||||||
WriteStatementProperty("exp rect W", menu->data->rectWExp, false);
|
WriteStatementProperty("exp rect W", menu->data->rectWExp, false);
|
||||||
|
@ -29,6 +29,7 @@ namespace IW5
|
|||||||
void WriteSoundAliasProperty(const std::string& propertyKey, const snd_alias_list_t* soundAliasValue) const;
|
void WriteSoundAliasProperty(const std::string& propertyKey, const snd_alias_list_t* soundAliasValue) const;
|
||||||
void WriteDecodeEffectProperty(const std::string& propertyKey, const itemDef_s* item) const;
|
void WriteDecodeEffectProperty(const std::string& propertyKey, const itemDef_s* item) const;
|
||||||
void WriteItemKeyHandlerProperty(const ItemKeyHandler* itemKeyHandlerValue);
|
void WriteItemKeyHandlerProperty(const ItemKeyHandler* itemKeyHandlerValue);
|
||||||
|
void WriteMultiTokenStringProperty(const std::string& propertyKey, const char* value) const;
|
||||||
void WriteFloatExpressionsProperty(const ItemFloatExpression* floatExpressions, int floatExpressionCount) const;
|
void WriteFloatExpressionsProperty(const ItemFloatExpression* floatExpressions, int floatExpressionCount) const;
|
||||||
void WriteColumnProperty(const std::string& propertyKey, const listBoxDef_s* listBox) const;
|
void WriteColumnProperty(const std::string& propertyKey, const listBoxDef_s* listBox) const;
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ void AssetDumperLocalizeEntry::DumpPool(AssetDumpingContext& context, AssetPool<
|
|||||||
stringFileDumper.SetLanguageName(language);
|
stringFileDumper.SetLanguageName(language);
|
||||||
|
|
||||||
// Magic string. Original string files do have this config file. The purpose of the config file is unknown though.
|
// Magic string. Original string files do have this config file. The purpose of the config file is unknown though.
|
||||||
stringFileDumper.SetConfigFile(R"(C:\projects\cod\t5\bin\StringEd.cfg)");
|
stringFileDumper.SetConfigFile(R"(C:/projects/cod/t5/bin/StringEd.cfg)");
|
||||||
|
|
||||||
stringFileDumper.SetNotes("");
|
stringFileDumper.SetNotes("");
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ void AssetDumperLocalizeEntry::DumpPool(AssetDumpingContext& context, AssetPool<
|
|||||||
stringFileDumper.SetLanguageName(language);
|
stringFileDumper.SetLanguageName(language);
|
||||||
|
|
||||||
// Magic string. Original string files do have this config file. The purpose of the config file is unknown though.
|
// Magic string. Original string files do have this config file. The purpose of the config file is unknown though.
|
||||||
stringFileDumper.SetConfigFile(R"(C:\projects\cod\t6\bin\StringEd.cfg)");
|
stringFileDumper.SetConfigFile(R"(C:/projects/cod/t6/bin/StringEd.cfg)");
|
||||||
|
|
||||||
stringFileDumper.SetNotes("");
|
stringFileDumper.SetNotes("");
|
||||||
|
|
||||||
|
@ -70,6 +70,7 @@ std::vector<std::string> AbstractMenuDumper::CreateScriptTokenList(const char* s
|
|||||||
SimpleLexer::Config lexerConfig;
|
SimpleLexer::Config lexerConfig;
|
||||||
lexerConfig.m_emit_new_line_tokens = false;
|
lexerConfig.m_emit_new_line_tokens = false;
|
||||||
lexerConfig.m_read_strings = true;
|
lexerConfig.m_read_strings = true;
|
||||||
|
lexerConfig.m_string_escape_sequences = true;
|
||||||
lexerConfig.m_read_integer_numbers = false;
|
lexerConfig.m_read_integer_numbers = false;
|
||||||
lexerConfig.m_read_floating_point_numbers = false;
|
lexerConfig.m_read_floating_point_numbers = false;
|
||||||
SimpleLexer lexer(&inputStream, std::move(lexerConfig));
|
SimpleLexer lexer(&inputStream, std::move(lexerConfig));
|
||||||
@ -130,6 +131,38 @@ bool AbstractMenuDumper::DoesTokenNeedQuotationMarks(const std::string& token)
|
|||||||
return hasNonIdentifierCharacter;
|
return hasNonIdentifierCharacter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AbstractMenuDumper::WriteEscapedString(const std::string_view& str) const
|
||||||
|
{
|
||||||
|
m_stream << "\"";
|
||||||
|
|
||||||
|
for (const auto& c : str)
|
||||||
|
{
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case '\r':
|
||||||
|
m_stream << "\\r";
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
m_stream << "\\n";
|
||||||
|
break;
|
||||||
|
case '\t':
|
||||||
|
m_stream << "\\t";
|
||||||
|
break;
|
||||||
|
case '\f':
|
||||||
|
m_stream << "\\f";
|
||||||
|
break;
|
||||||
|
case '"':
|
||||||
|
m_stream << "\\\"";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
m_stream << c;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_stream << "\"";
|
||||||
|
}
|
||||||
|
|
||||||
const std::string& AbstractMenuDumper::BoolValue(const bool value)
|
const std::string& AbstractMenuDumper::BoolValue(const bool value)
|
||||||
{
|
{
|
||||||
return value ? BOOL_VALUE_TRUE : BOOL_VALUE_FALSE;
|
return value ? BOOL_VALUE_TRUE : BOOL_VALUE_FALSE;
|
||||||
@ -154,7 +187,9 @@ void AbstractMenuDumper::WriteStringProperty(const std::string& propertyKey, con
|
|||||||
|
|
||||||
Indent();
|
Indent();
|
||||||
WriteKey(propertyKey);
|
WriteKey(propertyKey);
|
||||||
m_stream << "\"" << propertyValue << "\"\n";
|
|
||||||
|
WriteEscapedString(propertyValue);
|
||||||
|
m_stream << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void AbstractMenuDumper::WriteStringProperty(const std::string& propertyKey, const char* propertyValue) const
|
void AbstractMenuDumper::WriteStringProperty(const std::string& propertyKey, const char* propertyValue) const
|
||||||
@ -164,7 +199,9 @@ void AbstractMenuDumper::WriteStringProperty(const std::string& propertyKey, con
|
|||||||
|
|
||||||
Indent();
|
Indent();
|
||||||
WriteKey(propertyKey);
|
WriteKey(propertyKey);
|
||||||
m_stream << "\"" << propertyValue << "\"\n";
|
|
||||||
|
WriteEscapedString(propertyValue);
|
||||||
|
m_stream << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void AbstractMenuDumper::WriteBoolProperty(const std::string& propertyKey, const bool propertyValue, const bool defaultValue) const
|
void AbstractMenuDumper::WriteBoolProperty(const std::string& propertyKey, const bool propertyValue, const bool defaultValue) const
|
||||||
|
@ -30,6 +30,8 @@ protected:
|
|||||||
static std::vector<std::string> CreateScriptTokenList(const char* script);
|
static std::vector<std::string> CreateScriptTokenList(const char* script);
|
||||||
static bool DoesTokenNeedQuotationMarks(const std::string& token);
|
static bool DoesTokenNeedQuotationMarks(const std::string& token);
|
||||||
|
|
||||||
|
void WriteEscapedString(const std::string_view& str) const;
|
||||||
|
|
||||||
static const std::string& BoolValue(bool value);
|
static const std::string& BoolValue(bool value);
|
||||||
void WriteKey(const std::string& keyName) const;
|
void WriteKey(const std::string& keyName) const;
|
||||||
void WriteStringProperty(const std::string& propertyKey, const std::string& propertyValue) const;
|
void WriteStringProperty(const std::string& propertyKey, const std::string& propertyValue) const;
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
#include "Utils/Alignment.h"
|
#include "Utils/Alignment.h"
|
||||||
|
#include "Utils/StringUtils.h"
|
||||||
|
|
||||||
StructuredDataDefDumper::StructuredDataDefDumper(std::ostream& stream)
|
StructuredDataDefDumper::StructuredDataDefDumper(std::ostream& stream)
|
||||||
: AbstractTextDumper(stream),
|
: AbstractTextDumper(stream),
|
||||||
@ -37,7 +38,9 @@ void StructuredDataDefDumper::DumpEnum(const CommonStructuredDataEnum& _enum)
|
|||||||
for (auto i = 0u; i < entryCount; i++)
|
for (auto i = 0u; i < entryCount; i++)
|
||||||
{
|
{
|
||||||
Indent();
|
Indent();
|
||||||
m_stream << "\"" << _enum.m_entries[i].m_name << "\"";
|
m_stream << "\"";
|
||||||
|
utils::EscapeStringForQuotationMarks(m_stream, _enum.m_entries[i].m_name);
|
||||||
|
m_stream << "\"";
|
||||||
|
|
||||||
if (i + 1 < entryCount)
|
if (i + 1 < entryCount)
|
||||||
m_stream << ",";
|
m_stream << ",";
|
||||||
|
@ -2,11 +2,13 @@
|
|||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
#include "Utils/ClassUtils.h"
|
#include "Utils/ClassUtils.h"
|
||||||
#include "Parsing/ILexer.h"
|
#include "Parsing/ILexer.h"
|
||||||
#include "Parsing/IParserLineStream.h"
|
#include "Parsing/IParserLineStream.h"
|
||||||
#include "Parsing/ParsingException.h"
|
#include "Parsing/ParsingException.h"
|
||||||
|
#include "Utils/StringUtils.h"
|
||||||
|
|
||||||
template <typename TokenType>
|
template <typename TokenType>
|
||||||
class AbstractLexer : public ILexer<TokenType>
|
class AbstractLexer : public ILexer<TokenType>
|
||||||
@ -140,6 +142,52 @@ protected:
|
|||||||
return std::string(currentLine.m_line, startPos, m_current_line_offset - startPos);
|
return std::string(currentLine.m_line, startPos, m_current_line_offset - startPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Reads an identifier from the current position
|
||||||
|
* \return The value of the read identifier
|
||||||
|
*/
|
||||||
|
std::string ReadStringWithEscapeSequences()
|
||||||
|
{
|
||||||
|
const auto& currentLine = CurrentLine();
|
||||||
|
assert(m_current_line_offset >= 1);
|
||||||
|
assert(currentLine.m_line[m_current_line_offset - 1] == '"');
|
||||||
|
|
||||||
|
const auto startPos = m_current_line_offset;
|
||||||
|
const auto lineSize = currentLine.m_line.size();
|
||||||
|
auto isEscaped = false;
|
||||||
|
auto inEscape = false;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (m_current_line_offset >= lineSize)
|
||||||
|
throw ParsingException(TokenPos(*currentLine.m_filename, currentLine.m_line_number, m_current_line_offset), "Unclosed string");
|
||||||
|
|
||||||
|
const auto c = currentLine.m_line[m_current_line_offset];
|
||||||
|
|
||||||
|
if (c == '\"' && !inEscape)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (c == '\\' && !inEscape)
|
||||||
|
{
|
||||||
|
isEscaped = true;
|
||||||
|
inEscape = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
inEscape = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_current_line_offset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string str(currentLine.m_line, startPos, m_current_line_offset++ - startPos);
|
||||||
|
if (!isEscaped)
|
||||||
|
return str;
|
||||||
|
|
||||||
|
std::ostringstream ss;
|
||||||
|
utils::UnescapeStringFromQuotationMarks(ss, std::move(str));
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Reads an identifier from the current position
|
* \brief Reads an identifier from the current position
|
||||||
* \return The value of the read identifier
|
* \return The value of the read identifier
|
||||||
|
@ -67,6 +67,7 @@ std::unique_ptr<ISimpleExpression> SimpleExpressionInterpreter::Evaluate() const
|
|||||||
lexerConfig.m_read_integer_numbers = true;
|
lexerConfig.m_read_integer_numbers = true;
|
||||||
lexerConfig.m_read_floating_point_numbers = true;
|
lexerConfig.m_read_floating_point_numbers = true;
|
||||||
lexerConfig.m_read_strings = true;
|
lexerConfig.m_read_strings = true;
|
||||||
|
lexerConfig.m_string_escape_sequences = true;
|
||||||
SimpleExpressionMatchers().ApplyTokensToLexerConfig(lexerConfig);
|
SimpleExpressionMatchers().ApplyTokensToLexerConfig(lexerConfig);
|
||||||
|
|
||||||
SimpleLexer lexer(m_input, std::move(lexerConfig));
|
SimpleLexer lexer(m_input, std::move(lexerConfig));
|
||||||
|
@ -14,7 +14,7 @@ SimpleLexer::MultiCharacterTokenLookupEntry::MultiCharacterTokenLookupEntry(cons
|
|||||||
|
|
||||||
SimpleLexer::SimpleLexer(IParserLineStream* stream)
|
SimpleLexer::SimpleLexer(IParserLineStream* stream)
|
||||||
: AbstractLexer(stream),
|
: AbstractLexer(stream),
|
||||||
m_config{false, true, true, true, {}},
|
m_config{false, true, false, true, true, {}},
|
||||||
m_check_for_multi_character_tokens(false),
|
m_check_for_multi_character_tokens(false),
|
||||||
m_last_line(1)
|
m_last_line(1)
|
||||||
{
|
{
|
||||||
@ -31,7 +31,7 @@ SimpleLexer::SimpleLexer(IParserLineStream* stream, Config config)
|
|||||||
m_config.m_multi_character_tokens.clear();
|
m_config.m_multi_character_tokens.clear();
|
||||||
|
|
||||||
// If reading floating point numbers then must be reading integers
|
// If reading floating point numbers then must be reading integers
|
||||||
assert(config.m_read_floating_point_numbers == false || config.m_read_floating_point_numbers == config.m_read_integer_numbers);
|
assert(m_config.m_read_floating_point_numbers == false || m_config.m_read_floating_point_numbers == m_config.m_read_integer_numbers);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimpleLexer::AddMultiCharacterTokenConfigToLookup(Config::MultiCharacterToken tokenConfig)
|
void SimpleLexer::AddMultiCharacterTokenConfigToLookup(Config::MultiCharacterToken tokenConfig)
|
||||||
@ -121,7 +121,7 @@ SimpleParserValue SimpleLexer::GetNextToken()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (m_config.m_read_strings && c == '\"')
|
if (m_config.m_read_strings && c == '\"')
|
||||||
return SimpleParserValue::String(pos, new std::string(ReadString()));
|
return SimpleParserValue::String(pos, new std::string(m_config.m_string_escape_sequences ? ReadStringWithEscapeSequences() : ReadString()));
|
||||||
|
|
||||||
if (m_config.m_read_integer_numbers && (isdigit(c) || (c == '+' || c == '-' || (m_config.m_read_floating_point_numbers && c == '.')) && isdigit(PeekChar())))
|
if (m_config.m_read_integer_numbers && (isdigit(c) || (c == '+' || c == '-' || (m_config.m_read_floating_point_numbers && c == '.')) && isdigit(PeekChar())))
|
||||||
{
|
{
|
||||||
|
@ -22,10 +22,11 @@ public:
|
|||||||
MultiCharacterToken(int id, std::string value);
|
MultiCharacterToken(int id, std::string value);
|
||||||
};
|
};
|
||||||
|
|
||||||
bool m_emit_new_line_tokens;
|
bool m_emit_new_line_tokens = false;
|
||||||
bool m_read_strings;
|
bool m_read_strings = true;
|
||||||
bool m_read_integer_numbers;
|
bool m_string_escape_sequences = false;
|
||||||
bool m_read_floating_point_numbers;
|
bool m_read_integer_numbers = true;
|
||||||
|
bool m_read_floating_point_numbers = true;
|
||||||
std::vector<MultiCharacterToken> m_multi_character_tokens;
|
std::vector<MultiCharacterToken> m_multi_character_tokens;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
91
src/Utils/Utils/StringUtils.cpp
Normal file
91
src/Utils/Utils/StringUtils.cpp
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
#include "StringUtils.h"
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
namespace utils
|
||||||
|
{
|
||||||
|
std::string EscapeStringForQuotationMarks(const std::string_view& str)
|
||||||
|
{
|
||||||
|
std::ostringstream ss;
|
||||||
|
EscapeStringForQuotationMarks(ss, str);
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EscapeStringForQuotationMarks(std::ostream& stream, const std::string_view& str)
|
||||||
|
{
|
||||||
|
for (const auto& c : str)
|
||||||
|
{
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case '\r':
|
||||||
|
stream << "\\r";
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
stream << "\\n";
|
||||||
|
break;
|
||||||
|
case '\t':
|
||||||
|
stream << "\\t";
|
||||||
|
break;
|
||||||
|
case '\f':
|
||||||
|
stream << "\\f";
|
||||||
|
break;
|
||||||
|
case '"':
|
||||||
|
stream << "\\\"";
|
||||||
|
break;
|
||||||
|
case '\\':
|
||||||
|
stream << "\\\\";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
stream << c;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string UnescapeStringFromQuotationMarks(const std::string_view& str)
|
||||||
|
{
|
||||||
|
std::ostringstream ss;
|
||||||
|
UnescapeStringFromQuotationMarks(ss, str);
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnescapeStringFromQuotationMarks(std::ostream& stream, const std::string_view& str)
|
||||||
|
{
|
||||||
|
auto inEscape = false;
|
||||||
|
for (const auto& c : str)
|
||||||
|
{
|
||||||
|
if (inEscape)
|
||||||
|
{
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case 'r':
|
||||||
|
stream << "\r";
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
stream << "\n";
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
stream << "\t";
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
stream << "\f";
|
||||||
|
break;
|
||||||
|
case '"':
|
||||||
|
stream << "\"";
|
||||||
|
break;
|
||||||
|
case '\\':
|
||||||
|
stream << "\\";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
stream << c;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
inEscape = false;
|
||||||
|
}
|
||||||
|
else if (c != '\\')
|
||||||
|
stream << c;
|
||||||
|
else
|
||||||
|
inEscape = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
14
src/Utils/Utils/StringUtils.h
Normal file
14
src/Utils/Utils/StringUtils.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace utils
|
||||||
|
{
|
||||||
|
#define M_LETTERS_AL_NUM "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
|
||||||
|
static constexpr const char* LETTERS_AL_NUM = M_LETTERS_AL_NUM;
|
||||||
|
static constexpr const char* LETTERS_AL_NUM_UNDERSCORE = M_LETTERS_AL_NUM "_";
|
||||||
|
|
||||||
|
std::string EscapeStringForQuotationMarks(const std::string_view& str);
|
||||||
|
void EscapeStringForQuotationMarks(std::ostream& stream, const std::string_view& str);
|
||||||
|
std::string UnescapeStringFromQuotationMarks(const std::string_view& str);
|
||||||
|
void UnescapeStringFromQuotationMarks(std::ostream& stream, const std::string_view& str);
|
||||||
|
}
|
@ -112,6 +112,7 @@ namespace test::parsing::simple::expression
|
|||||||
|
|
||||||
SimpleLexer::Config lexerConfig;
|
SimpleLexer::Config lexerConfig;
|
||||||
lexerConfig.m_read_strings = true;
|
lexerConfig.m_read_strings = true;
|
||||||
|
lexerConfig.m_string_escape_sequences = true;
|
||||||
lexerConfig.m_read_integer_numbers = true;
|
lexerConfig.m_read_integer_numbers = true;
|
||||||
lexerConfig.m_read_floating_point_numbers = true;
|
lexerConfig.m_read_floating_point_numbers = true;
|
||||||
lexerConfig.m_emit_new_line_tokens = false;
|
lexerConfig.m_emit_new_line_tokens = false;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user