#include "ItemScopeSequences.h" #include "Generic/GenericColorPropertySequence.h" #include "Generic/GenericExpressionPropertySequence.h" #include "Generic/GenericFloatingPointPropertySequence.h" #include "Generic/GenericIntPropertySequence.h" #include "Generic/GenericKeywordPropertySequence.h" #include "Generic/GenericMenuEventHandlerSetPropertySequence.h" #include "Generic/GenericStringPropertySequence.h" #include "Parsing/Menu/Matcher/MenuExpressionMatchers.h" #include "Parsing/Menu/Matcher/MenuMatcherFactory.h" #include "Parsing/Menu/MenuFileCommonOperations.h" #include #include #include using namespace menu; class ItemScopeOperations { inline static const CommonItemFeatureType IW4_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 }; 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: static void SetItemType(CommonItemDef& item, const FeatureLevel featureLevel, const TokenPos& pos, const int type) { if (type < 0) throw ParsingException(pos, "Invalid item type"); if (item.m_feature_type != CommonItemFeatureType::NONE) throw ParsingException(pos, "Item type has already been set"); item.m_type = type; switch (featureLevel) { case FeatureLevel::IW4: if (static_cast(type) >= std::extent_v) throw ParsingException(pos, "Invalid item type"); item.m_feature_type = IW4_FEATURE_TYPE_BY_TYPE[static_cast(type)]; break; case FeatureLevel::IW5: default: if (static_cast(type) >= std::extent_v) throw ParsingException(pos, "Invalid item type"); item.m_feature_type = IW5_FEATURE_TYPE_BY_TYPE[static_cast(type)]; break; } switch (item.m_feature_type) { case CommonItemFeatureType::LISTBOX: item.m_list_box_features = std::make_unique(); break; case CommonItemFeatureType::EDIT_FIELD: item.m_edit_field_features = std::make_unique(); break; case CommonItemFeatureType::MULTI_VALUE: item.m_multi_value_features = std::make_unique(); break; case CommonItemFeatureType::NEWS_TICKER: item.m_news_ticker_features = std::make_unique(); break; default: break; } } static void EnsureHasListboxFeatures(const CommonItemDef& item, const TokenPos& pos) { if (item.m_feature_type != CommonItemFeatureType::LISTBOX || !item.m_list_box_features) throw ParsingException(pos, "Item must have be listbox to use this declaration"); } static void EnsureHasEditFieldFeatures(const CommonItemDef& item, const TokenPos& pos) { if (item.m_feature_type != CommonItemFeatureType::EDIT_FIELD || !item.m_edit_field_features) throw ParsingException(pos, "Item must have be edit field to use this declaration"); } static void EnsureHasMultiValueFeatures(const CommonItemDef& item, const TokenPos& pos) { if (item.m_feature_type != CommonItemFeatureType::MULTI_VALUE || !item.m_multi_value_features) throw ParsingException(pos, "Item must have be multi value to use this declaration"); } static void EnsureHasEnumDvarFeatures(const CommonItemDef& item, const TokenPos& pos) { if (item.m_feature_type != CommonItemFeatureType::ENUM_DVAR) throw ParsingException(pos, "Item must have be enum dvar to use this declaration"); } static void EnsureHasNewsTickerFeatures(const CommonItemDef& item, const TokenPos& pos) { if (item.m_feature_type != CommonItemFeatureType::NEWS_TICKER || !item.m_news_ticker_features) throw ParsingException(pos, "Item must have be news ticker to use this declaration"); } }; namespace menu::item_scope_sequences { class SequenceCloseBlock final : public MenuFileParser::sequence_t { public: SequenceCloseBlock() { const MenuMatcherFactory create(this); AddMatchers({ create.Char('}'), }); } protected: void ProcessMatch(MenuFileParserState* state, SequenceResult& result) const override { state->m_current_item = nullptr; } }; class SequenceConsumeSemicolons final : public MenuFileParser::sequence_t { public: SequenceConsumeSemicolons() { const MenuMatcherFactory create(this); AddMatchers({ create.Char(';'), }); } protected: void ProcessMatch(MenuFileParserState* state, SequenceResult& result) const override {} }; class SequenceRect final : public MenuFileParser::sequence_t { static constexpr auto CAPTURE_ALIGN_HORIZONTAL = 1; static constexpr auto CAPTURE_ALIGN_VERTICAL = 2; public: SequenceRect() { const MenuMatcherFactory create(this); AddLabeledMatchers(MenuExpressionMatchers().Expression(this), MenuExpressionMatchers::LABEL_EXPRESSION); AddMatchers({ create.KeywordIgnoreCase("rect"), create.NumericExpression(), // x create.NumericExpression(), // y create.NumericExpression(), // w create.NumericExpression(), // h create.Optional(create.And({ create.Integer().Capture(CAPTURE_ALIGN_HORIZONTAL), create.Integer().Capture(CAPTURE_ALIGN_VERTICAL), })), }); } protected: void ProcessMatch(MenuFileParserState* state, SequenceResult& result) const override { assert(state->m_current_item); const auto x = MenuMatcherFactory::TokenNumericExpressionValue(state, result); const auto y = MenuMatcherFactory::TokenNumericExpressionValue(state, result); const auto w = MenuMatcherFactory::TokenNumericExpressionValue(state, result); const auto h = MenuMatcherFactory::TokenNumericExpressionValue(state, result); CommonRect rect{x, y, w, h, 0, 0}; if (result.HasNextCapture(CAPTURE_ALIGN_HORIZONTAL) && result.HasNextCapture(CAPTURE_ALIGN_VERTICAL)) { rect.horizontalAlign = result.NextCapture(CAPTURE_ALIGN_HORIZONTAL).IntegerValue(); rect.verticalAlign = result.NextCapture(CAPTURE_ALIGN_VERTICAL).IntegerValue(); } state->m_current_item->m_rect = rect; } }; class SequenceOrigin final : public MenuFileParser::sequence_t { public: SequenceOrigin() { const MenuMatcherFactory create(this); AddLabeledMatchers(MenuExpressionMatchers().Expression(this), MenuExpressionMatchers::LABEL_EXPRESSION); AddMatchers({ create.KeywordIgnoreCase("origin"), create.NumericExpression(), // x create.NumericExpression(), // y }); } protected: void ProcessMatch(MenuFileParserState* state, SequenceResult& result) const override { assert(state->m_current_item); state->m_current_item->m_rect.x = MenuMatcherFactory::TokenNumericExpressionValue(state, result); state->m_current_item->m_rect.y = MenuMatcherFactory::TokenNumericExpressionValue(state, result); } }; class SequenceDecodeEffect final : public MenuFileParser::sequence_t { static constexpr auto CAPTURE_LETTER_TIME = 1; static constexpr auto CAPTURE_DECAY_START_TIME = 2; static constexpr auto CAPTURE_DECAY_DURATION = 3; public: SequenceDecodeEffect() { const MenuMatcherFactory create(this); AddLabeledMatchers(MenuExpressionMatchers().Expression(this), MenuExpressionMatchers::LABEL_EXPRESSION); AddMatchers({ create.KeywordIgnoreCase("decodeEffect"), create.IntExpression(), // letter time create.IntExpression(), // decay start time create.IntExpression(), // decay duration }); } protected: void ProcessMatch(MenuFileParserState* state, SequenceResult& result) const override { assert(state->m_current_item); state->m_current_item->m_fx_letter_time = MenuMatcherFactory::TokenIntExpressionValue(state, result); state->m_current_item->m_fx_decay_start_time = MenuMatcherFactory::TokenIntExpressionValue(state, result); state->m_current_item->m_fx_decay_duration = MenuMatcherFactory::TokenIntExpressionValue(state, result); } }; class SequenceMultiTokenBlock final : public MenuFileParser::sequence_t { public: using callback_t = std::function value)>; private: static constexpr auto CAPTURE_FIRST_TOKEN = 1; static constexpr auto CAPTURE_VALUE = 2; callback_t m_set_callback; public: SequenceMultiTokenBlock(std::string keyName, callback_t setCallback) : m_set_callback(std::move(setCallback)) { const MenuMatcherFactory create(this); AddMatchers({ create.KeywordIgnoreCase(std::move(keyName)).Capture(CAPTURE_FIRST_TOKEN), create.Char('{'), create.Optional(create.And({ create.Text().Capture(CAPTURE_VALUE), create.OptionalLoop(create.And({ create.Char(';'), create.Text().Capture(CAPTURE_VALUE), })), })), create.Char('}'), }); } protected: void ProcessMatch(MenuFileParserState* state, SequenceResult& result) const override { if (!m_set_callback) return; std::vector values; while (result.HasNextCapture(CAPTURE_VALUE)) { values.emplace_back(MenuMatcherFactory::TokenTextValue(result.NextCapture(CAPTURE_VALUE))); } m_set_callback(state, result.NextCapture(CAPTURE_FIRST_TOKEN).GetPos(), std::move(values)); } }; class SequenceDvarFloat final : public MenuFileParser::sequence_t { static constexpr auto CAPTURE_FIRST_TOKEN = 1; static constexpr auto CAPTURE_DVAR_NAME = 2; public: SequenceDvarFloat() { const MenuMatcherFactory create(this); AddLabeledMatchers(MenuExpressionMatchers().Expression(this), MenuExpressionMatchers::LABEL_EXPRESSION); AddMatchers({ create.KeywordIgnoreCase("dvarFloat").Capture(CAPTURE_FIRST_TOKEN), create.Text().Capture(CAPTURE_DVAR_NAME), create.NumericExpression(), // def value create.NumericExpression(), // min value create.NumericExpression(), // max value }); } protected: void ProcessMatch(MenuFileParserState* state, SequenceResult& result) const override { assert(state->m_current_item); ItemScopeOperations::EnsureHasEditFieldFeatures(*state->m_current_item, result.NextCapture(CAPTURE_FIRST_TOKEN).GetPos()); state->m_current_item->m_dvar = MenuMatcherFactory::TokenTextValue(result.NextCapture(CAPTURE_DVAR_NAME)); state->m_current_item->m_edit_field_features->m_def_val = MenuMatcherFactory::TokenNumericExpressionValue(state, result); state->m_current_item->m_edit_field_features->m_min_val = MenuMatcherFactory::TokenNumericExpressionValue(state, result); state->m_current_item->m_edit_field_features->m_max_val = MenuMatcherFactory::TokenNumericExpressionValue(state, result); } }; class SequenceDvarStrList final : public MenuFileParser::sequence_t { static constexpr auto CAPTURE_FIRST_TOKEN = 1; static constexpr auto CAPTURE_STEP_NAME = 2; static constexpr auto CAPTURE_STEP_VALUE = 3; public: SequenceDvarStrList() { const MenuMatcherFactory create(this); AddMatchers({ create.KeywordIgnoreCase("dvarStrList").Capture(CAPTURE_FIRST_TOKEN), create.Char('{'), create.OptionalLoop(create.And({ create.TextNoChain().Capture(CAPTURE_STEP_NAME), create.Optional(create.Char(';')), create.TextNoChain().Capture(CAPTURE_STEP_VALUE), create.Optional(create.Char(';')), })), create.Char('}'), }); } protected: void ProcessMatch(MenuFileParserState* state, SequenceResult& result) const override { assert(state->m_current_item); ItemScopeOperations::EnsureHasMultiValueFeatures(*state->m_current_item, result.NextCapture(CAPTURE_FIRST_TOKEN).GetPos()); const auto& multiValueFeatures = state->m_current_item->m_multi_value_features; while (result.HasNextCapture(CAPTURE_STEP_NAME)) { multiValueFeatures->m_step_names.emplace_back(MenuMatcherFactory::TokenTextValue(result.NextCapture(CAPTURE_STEP_NAME))); multiValueFeatures->m_string_values.emplace_back(MenuMatcherFactory::TokenTextValue(result.NextCapture(CAPTURE_STEP_VALUE))); } } }; class SequenceDvarFloatList final : public MenuFileParser::sequence_t { static constexpr auto CAPTURE_FIRST_TOKEN = 1; static constexpr auto CAPTURE_STEP_NAME = 2; public: SequenceDvarFloatList() { const MenuMatcherFactory create(this); AddLabeledMatchers(MenuExpressionMatchers().Expression(this), MenuExpressionMatchers::LABEL_EXPRESSION); AddMatchers({ create.KeywordIgnoreCase("dvarFloatList").Capture(CAPTURE_FIRST_TOKEN), create.Char('{'), create.OptionalLoop(create.And({ create.Text().Capture(CAPTURE_STEP_NAME), create.Optional(create.Char(';')), create.NumericExpression(), create.Optional(create.Char(';')), })), create.Char('}'), }); } protected: void ProcessMatch(MenuFileParserState* state, SequenceResult& result) const override { assert(state->m_current_item); ItemScopeOperations::EnsureHasMultiValueFeatures(*state->m_current_item, result.NextCapture(CAPTURE_FIRST_TOKEN).GetPos()); const auto& multiValueFeatures = state->m_current_item->m_multi_value_features; while (result.HasNextCapture(CAPTURE_STEP_NAME)) { multiValueFeatures->m_step_names.emplace_back(MenuMatcherFactory::TokenTextValue(result.NextCapture(CAPTURE_STEP_NAME))); multiValueFeatures->m_double_values.emplace_back(MenuMatcherFactory::TokenNumericExpressionValue(state, result)); } } }; class SequenceColumns final : public MenuFileParser::sequence_t { static constexpr auto TAG_COLUMN = 1; static constexpr auto CAPTURE_FIRST_TOKEN = 1; static constexpr auto CAPTURE_COLUMN_COUNT = 2; public: explicit SequenceColumns(const FeatureLevel featureLevel) { const MenuMatcherFactory create(this); AddLabeledMatchers(MenuExpressionMatchers().Expression(this), MenuExpressionMatchers::LABEL_EXPRESSION); if (featureLevel == FeatureLevel::IW5) { AddMatchers({ create.KeywordIgnoreCase("columns").Capture(CAPTURE_FIRST_TOKEN), create.Integer().Capture(CAPTURE_COLUMN_COUNT), create.Loop(create.And({ create.True().Tag(TAG_COLUMN), create.IntExpression(), // xpos create.IntExpression(), // ypos create.IntExpression(), // width create.IntExpression(), // height create.IntExpression(), // maxChars create.IntExpression(), // alignment })), }); } else { AddMatchers({ create.KeywordIgnoreCase("columns").Capture(CAPTURE_FIRST_TOKEN), create.Integer().Capture(CAPTURE_COLUMN_COUNT), create.Loop(create.And({ create.True().Tag(TAG_COLUMN), create.IntExpression(), // xpos create.IntExpression(), // width create.IntExpression(), // maxChars create.IntExpression(), // alignment })), }); } } protected: void ProcessMatch(MenuFileParserState* state, SequenceResult& result) const override { assert(state->m_current_item); ItemScopeOperations::EnsureHasListboxFeatures(*state->m_current_item, result.NextCapture(CAPTURE_FIRST_TOKEN).GetPos()); assert(state->m_feature_level == FeatureLevel::IW4 || state->m_feature_level == FeatureLevel::IW5); const auto& listBoxFeatures = state->m_current_item->m_list_box_features; while (result.PeekAndRemoveIfTag(TAG_COLUMN) == TAG_COLUMN) { int xPos = 0; int yPos = 0; int width = 0; int height = 0; int maxChars = 0; int alignment = 0; if (state->m_feature_level == FeatureLevel::IW4) { xPos = MenuMatcherFactory::TokenIntExpressionValue(state, result); width = MenuMatcherFactory::TokenIntExpressionValue(state, result); maxChars = MenuMatcherFactory::TokenIntExpressionValue(state, result); alignment = MenuMatcherFactory::TokenIntExpressionValue(state, result); } else if (state->m_feature_level == FeatureLevel::IW5) { xPos = MenuMatcherFactory::TokenIntExpressionValue(state, result); yPos = MenuMatcherFactory::TokenIntExpressionValue(state, result); width = MenuMatcherFactory::TokenIntExpressionValue(state, result); height = MenuMatcherFactory::TokenIntExpressionValue(state, result); maxChars = MenuMatcherFactory::TokenIntExpressionValue(state, result); alignment = MenuMatcherFactory::TokenIntExpressionValue(state, result); } CommonItemFeaturesListBox::Column column{ xPos, yPos, width, height, maxChars, alignment, }; listBoxFeatures->m_columns.emplace_back(column); } } }; class SequenceExecKey final : public MenuFileParser::sequence_t { static constexpr auto CAPTURE_KEY = 1; public: SequenceExecKey() { const MenuMatcherFactory create(this); AddMatchers({ create.KeywordIgnoreCase("execKey"), create.StringChain().Capture(CAPTURE_KEY), create.Char('{'), }); } protected: void ProcessMatch(MenuFileParserState* state, SequenceResult& result) const override { assert(state->m_current_item); const auto& keyToken = result.NextCapture(CAPTURE_KEY); const auto& keyValue = keyToken.StringValue(); if (keyValue.empty() || keyValue.size() > 1) throw ParsingException(keyToken.GetPos(), "Key handler string must have exactly one character"); const auto key = static_cast(static_cast(keyValue[0])); auto newEventHandlerSet = std::make_unique(); state->m_current_event_handler_set = newEventHandlerSet.get(); state->m_current_nested_event_handler_set = newEventHandlerSet.get(); state->m_current_item->m_key_handlers.emplace(std::make_pair(key, std::move(newEventHandlerSet))); } }; class SequenceExecKeyInt final : public MenuFileParser::sequence_t { static constexpr auto CAPTURE_KEY = 1; public: SequenceExecKeyInt() { const MenuMatcherFactory create(this); AddMatchers({ create.KeywordIgnoreCase("execKeyInt"), create.Integer().Capture(CAPTURE_KEY), create.Char('{'), }); } protected: void ProcessMatch(MenuFileParserState* state, SequenceResult& result) const override { assert(state->m_current_item); const auto& keyToken = result.NextCapture(CAPTURE_KEY); const auto& keyValue = keyToken.IntegerValue(); if (keyValue < 0) throw ParsingException(keyToken.GetPos(), "Key handler value must be positive"); auto newEventHandlerSet = std::make_unique(); state->m_current_event_handler_set = newEventHandlerSet.get(); state->m_current_nested_event_handler_set = newEventHandlerSet.get(); state->m_current_item->m_key_handlers.emplace(std::make_pair(keyValue, std::move(newEventHandlerSet))); } }; } // namespace menu::item_scope_sequences using namespace item_scope_sequences; ItemScopeSequences::ItemScopeSequences(std::vector>& allSequences, std::vector& scopeSequences) : AbstractScopeSequenceHolder(allSequences, scopeSequences) { } void ItemScopeSequences::AddSequences(FeatureLevel featureLevel, bool permissive) const { AddSequence(std::make_unique()); AddSequence(std::make_unique("name", [](const MenuFileParserState* state, const TokenPos&, const std::string& value) { state->m_current_item->m_name = value; })); AddSequence(std::make_unique("text", [](const MenuFileParserState* state, const TokenPos&, const std::string& value) { state->m_current_item->m_text = value; })); // textfile AddSequence(std::make_unique("textsavegame", [](const MenuFileParserState* state, const TokenPos&) { state->m_current_item->m_text_save_game = true; })); AddSequence(std::make_unique("textcinematicsubtitle", [](const MenuFileParserState* state, const TokenPos&) { state->m_current_item->m_text_cinematic_subtitle = true; })); AddSequence(std::make_unique("group", [](const MenuFileParserState* state, const TokenPos&, const std::string& value) { state->m_current_item->m_group = value; })); AddSequence(std::make_unique()); AddSequence(std::make_unique()); // rect480 // rect720 // pos480 // pos720 AddSequence(std::make_unique("style", [](const MenuFileParserState* state, const TokenPos&, const int value) { state->m_current_item->m_style = value; })); AddSequence(std::make_unique("decoration", [](const MenuFileParserState* state, const TokenPos&) { state->m_current_item->m_decoration = true; })); AddSequence(std::make_unique("autowrapped", [](const MenuFileParserState* state, const TokenPos&) { state->m_current_item->m_auto_wrapped = true; })); AddSequence(std::make_unique("horizontalscroll", [](const MenuFileParserState* state, const TokenPos&) { state->m_current_item->m_horizontal_scroll = true; })); AddSequence(std::make_unique("type", [](const MenuFileParserState* state, const TokenPos& pos, const int value) { ItemScopeOperations::SetItemType(*state->m_current_item, state->m_feature_level, pos, value); })); AddSequence(std::make_unique("border", [](const MenuFileParserState* state, const TokenPos&, const int value) { state->m_current_item->m_border = value; })); AddSequence(std::make_unique("borderSize", [](const MenuFileParserState* state, const TokenPos&, const double value) { state->m_current_item->m_border_size = value; })); AddSequence(GenericExpressionPropertySequence::WithKeywordAndBool( "visible", [](const MenuFileParserState* state, const TokenPos& pos, std::unique_ptr value) { MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *value); state->m_current_item->m_visible_expression = std::move(value); })); AddSequence(GenericExpressionPropertySequence::WithKeywordAndBool( "disabled", [](const MenuFileParserState* state, const TokenPos& pos, std::unique_ptr value) { MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *value); state->m_current_item->m_disabled_expression = std::move(value); })); AddSequence(std::make_unique("ownerdraw", [](const MenuFileParserState* state, const TokenPos&, const int value) { state->m_current_item->m_owner_draw = value; })); AddSequence(std::make_unique("align", [](const MenuFileParserState* state, const TokenPos&, const int value) { state->m_current_item->m_align = value; })); AddSequence(std::make_unique("textalign", [](const MenuFileParserState* state, const TokenPos&, const int value) { state->m_current_item->m_text_align = value; })); AddSequence(std::make_unique("textalignx", [](const MenuFileParserState* state, const TokenPos&, const double value) { state->m_current_item->m_text_align_x = value; })); AddSequence(std::make_unique("textaligny", [](const MenuFileParserState* state, const TokenPos&, const double value) { state->m_current_item->m_text_align_y = value; })); AddSequence(std::make_unique("textscale", [](const MenuFileParserState* state, const TokenPos&, const double value) { state->m_current_item->m_text_scale = value; })); AddSequence(std::make_unique("textstyle", [](const MenuFileParserState* state, const TokenPos&, const int value) { state->m_current_item->m_text_style = value; })); AddSequence(std::make_unique("textfont", [](const MenuFileParserState* state, const TokenPos&, const int value) { state->m_current_item->m_text_font = value; })); AddSequence(std::make_unique("backcolor", [](const MenuFileParserState* state, const TokenPos&, const CommonColor value) { state->m_current_item->m_back_color = value; })); AddSequence(std::make_unique("forecolor", [](const MenuFileParserState* state, const TokenPos&, const CommonColor value) { state->m_current_item->m_fore_color = value; })); AddSequence(std::make_unique("bordercolor", [](const MenuFileParserState* state, const TokenPos&, const CommonColor value) { state->m_current_item->m_border_color = value; })); AddSequence(std::make_unique("outlinecolor", [](const MenuFileParserState* state, const TokenPos&, const CommonColor value) { state->m_current_item->m_outline_color = value; })); AddSequence(std::make_unique("disablecolor", [](const MenuFileParserState* state, const TokenPos&, const CommonColor value) { state->m_current_item->m_disable_color = value; })); AddSequence(std::make_unique("glowcolor", [](const MenuFileParserState* state, const TokenPos&, const CommonColor value) { state->m_current_item->m_glow_color = value; })); AddSequence(std::make_unique("background", [](const MenuFileParserState* state, const TokenPos&, const std::string& value) { state->m_current_item->m_background = value; })); AddSequence(std::make_unique( "onFocus", [](const MenuFileParserState* state, const TokenPos&) -> std::unique_ptr& { return state->m_current_item->m_on_focus; })); AddSequence(std::make_unique( "leaveFocus", [](const MenuFileParserState* state, const TokenPos&) -> std::unique_ptr& { return state->m_current_item->m_on_leave_focus; })); AddSequence(std::make_unique( "mouseEnter", [](const MenuFileParserState* state, const TokenPos&) -> std::unique_ptr& { return state->m_current_item->m_on_mouse_enter; })); AddSequence(std::make_unique( "mouseExit", [](const MenuFileParserState* state, const TokenPos&) -> std::unique_ptr& { return state->m_current_item->m_on_mouse_exit; })); AddSequence(std::make_unique( "mouseEnterText", [](const MenuFileParserState* state, const TokenPos&) -> std::unique_ptr& { return state->m_current_item->m_on_mouse_enter_text; })); AddSequence(std::make_unique( "mouseExitText", [](const MenuFileParserState* state, const TokenPos&) -> std::unique_ptr& { return state->m_current_item->m_on_mouse_exit_text; })); AddSequence(std::make_unique( "action", [](const MenuFileParserState* state, const TokenPos&) -> std::unique_ptr& { return state->m_current_item->m_on_action; })); AddSequence(std::make_unique( "accept", [](const MenuFileParserState* state, const TokenPos&) -> std::unique_ptr& { return state->m_current_item->m_on_accept; })); // special AddSequence(std::make_unique("dvar", [](const MenuFileParserState* state, const TokenPos&, const std::string& value) { state->m_current_item->m_dvar = value; })); AddSequence(std::make_unique("focusSound", [](const MenuFileParserState* state, const TokenPos&, const std::string& value) { state->m_current_item->m_focus_sound = value; })); AddSequence(std::make_unique("ownerdrawFlag", [](const MenuFileParserState* state, const TokenPos&, const int value) { state->m_current_item->m_owner_draw_flags |= value; })); AddSequence(std::make_unique("enableDvar", [](const MenuFileParserState* state, const TokenPos&, std::vector value) { state->m_current_item->m_enable_dvar = std::move(value); })); AddSequence(std::make_unique("dvarTest", [](const MenuFileParserState* state, const TokenPos&, const std::string& value) { state->m_current_item->m_dvar_test = value; })); AddSequence(std::make_unique("disableDvar", [](const MenuFileParserState* state, const TokenPos&, std::vector value) { state->m_current_item->m_disable_dvar = std::move(value); })); AddSequence(std::make_unique("showDvar", [](const MenuFileParserState* state, const TokenPos&, std::vector value) { state->m_current_item->m_show_dvar = std::move(value); })); AddSequence(std::make_unique("hideDvar", [](const MenuFileParserState* state, const TokenPos&, std::vector value) { state->m_current_item->m_hide_dvar = std::move(value); })); AddSequence(std::make_unique("focusDvar", [](const MenuFileParserState* state, const TokenPos&, std::vector value) { state->m_current_item->m_focus_dvar = std::move(value); })); AddSequence(std::make_unique()); AddSequence(std::make_unique()); AddSequence(std::make_unique("gamemsgwindowindex", [](const MenuFileParserState* state, const TokenPos&, const int value) { state->m_current_item->m_game_message_window_index = value; })); AddSequence(std::make_unique("gamemsgwindowmode", [](const MenuFileParserState* state, const TokenPos&, const int value) { state->m_current_item->m_game_message_window_mode = value; })); AddSequence(std::make_unique()); AddSequence( GenericExpressionPropertySequence::WithKeywords({"exp", "disabled"}, [](const MenuFileParserState* state, const TokenPos& pos, std::unique_ptr value) { MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *value); state->m_current_item->m_disabled_expression = std::move(value); })); AddSequence( GenericExpressionPropertySequence::WithKeywords({"exp", "text"}, [](const MenuFileParserState* state, const TokenPos& pos, std::unique_ptr value) { MenuFileCommonOperations::EnsureIsStringExpression(state, pos, *value); state->m_current_item->m_text_expression = std::move(value); })); AddSequence( GenericExpressionPropertySequence::WithKeywords({"exp", "material"}, [](const MenuFileParserState* state, const TokenPos& pos, std::unique_ptr value) { MenuFileCommonOperations::EnsureIsStringExpression(state, pos, *value); state->m_current_item->m_material_expression = std::move(value); })); AddSequence( GenericExpressionPropertySequence::WithKeywords({"exp", "rect", "X"}, [](const MenuFileParserState* state, const TokenPos& pos, std::unique_ptr value) { MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *value); state->m_current_item->m_rect_x_exp = std::move(value); })); AddSequence( GenericExpressionPropertySequence::WithKeywords({"exp", "rect", "Y"}, [](const MenuFileParserState* state, const TokenPos& pos, std::unique_ptr value) { MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *value); state->m_current_item->m_rect_y_exp = std::move(value); })); AddSequence( GenericExpressionPropertySequence::WithKeywords({"exp", "rect", "W"}, [](const MenuFileParserState* state, const TokenPos& pos, std::unique_ptr value) { MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *value); state->m_current_item->m_rect_w_exp = std::move(value); })); AddSequence( GenericExpressionPropertySequence::WithKeywords({"exp", "rect", "H"}, [](const MenuFileParserState* state, const TokenPos& pos, std::unique_ptr value) { MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *value); state->m_current_item->m_rect_h_exp = std::move(value); })); AddSequence( GenericExpressionPropertySequence::WithKeywords({"exp", "forecolor", "R"}, [](const MenuFileParserState* state, const TokenPos& pos, std::unique_ptr value) { MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *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& pos, std::unique_ptr value) { MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *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& pos, std::unique_ptr value) { MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *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& pos, std::unique_ptr value) { MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *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& pos, std::unique_ptr value) { MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *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& pos, std::unique_ptr value) { MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *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& pos, std::unique_ptr value) { MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *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& pos, std::unique_ptr value) { MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *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& pos, std::unique_ptr value) { MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *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& pos, std::unique_ptr value) { MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *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& pos, std::unique_ptr value) { MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *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& pos, std::unique_ptr value) { MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *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& pos, std::unique_ptr value) { MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *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& pos, std::unique_ptr value) { MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *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& pos, std::unique_ptr value) { MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *value); state->m_current_item->m_backcolor_expressions.m_rgb_exp = std::move(value); })); if (featureLevel == FeatureLevel::IW5) { AddSequence(std::make_unique( "hasFocus", [](const MenuFileParserState* state, const TokenPos&) -> std::unique_ptr& { return state->m_current_item->m_has_focus; })); AddSequence( GenericExpressionPropertySequence::WithKeywords({"exp", "textaligny"}, [](const MenuFileParserState* state, const TokenPos& pos, std::unique_ptr value) { MenuFileCommonOperations::EnsureIsNumericExpression(state, pos, *value); state->m_current_item->m_text_align_y_expression = std::move(value); })); } // ============== ListBox ============== AddSequence(std::make_unique(featureLevel)); AddSequence(std::make_unique("notselectable", [](const MenuFileParserState* state, const TokenPos& pos) { ItemScopeOperations::EnsureHasListboxFeatures(*state->m_current_item, pos); state->m_current_item->m_list_box_features->m_not_selectable = true; })); AddSequence(std::make_unique("noscrollbars", [](const MenuFileParserState* state, const TokenPos& pos) { ItemScopeOperations::EnsureHasListboxFeatures(*state->m_current_item, pos); state->m_current_item->m_list_box_features->m_no_scrollbars = true; })); AddSequence(std::make_unique("usepaging", [](const MenuFileParserState* state, const TokenPos& pos) { ItemScopeOperations::EnsureHasListboxFeatures(*state->m_current_item, pos); state->m_current_item->m_list_box_features->m_use_paging = true; })); AddSequence(std::make_unique("elementwidth", [](const MenuFileParserState* state, const TokenPos& pos, const double value) { ItemScopeOperations::EnsureHasListboxFeatures(*state->m_current_item, pos); state->m_current_item->m_list_box_features->m_element_width = value; })); AddSequence(std::make_unique("elementheight", [](const MenuFileParserState* state, const TokenPos& pos, const double value) { ItemScopeOperations::EnsureHasListboxFeatures(*state->m_current_item, pos); state->m_current_item->m_list_box_features->m_element_height = value; })); AddSequence(std::make_unique("feeder", [](const MenuFileParserState* state, const TokenPos& pos, const double value) { ItemScopeOperations::EnsureHasListboxFeatures(*state->m_current_item, pos); state->m_current_item->m_list_box_features->m_feeder = value; })); AddSequence(std::make_unique("elementtype", [](const MenuFileParserState* state, const TokenPos& pos, const int value) { ItemScopeOperations::EnsureHasListboxFeatures(*state->m_current_item, pos); state->m_current_item->m_list_box_features->m_element_style = value; })); AddSequence(std::make_unique( "doubleclick", [](const MenuFileParserState* state, const TokenPos& pos) -> std::unique_ptr& { ItemScopeOperations::EnsureHasListboxFeatures(*state->m_current_item, pos); return state->m_current_item->m_list_box_features->m_on_double_click; })); AddSequence(std::make_unique("selectBorder", [](const MenuFileParserState* state, const TokenPos& pos, const CommonColor value) { ItemScopeOperations::EnsureHasListboxFeatures(*state->m_current_item, pos); state->m_current_item->m_list_box_features->m_select_border = value; })); AddSequence(std::make_unique("selectIcon", [](const MenuFileParserState* state, const TokenPos& pos, const std::string& value) { ItemScopeOperations::EnsureHasListboxFeatures(*state->m_current_item, pos); 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 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 ============== AddSequence(std::make_unique()); AddSequence(std::make_unique("localvar", [](const MenuFileParserState* state, const TokenPos& pos, const std::string& value) { ItemScopeOperations::EnsureHasEditFieldFeatures(*state->m_current_item, pos); state->m_current_item->m_edit_field_features->m_local_var = value; })); AddSequence(std::make_unique("maxChars", [](const MenuFileParserState* state, const TokenPos& pos, const int value) { ItemScopeOperations::EnsureHasEditFieldFeatures(*state->m_current_item, pos); state->m_current_item->m_edit_field_features->m_max_chars = value; })); AddSequence(std::make_unique("maxPaintChars", [](const MenuFileParserState* state, const TokenPos& pos, const int value) { ItemScopeOperations::EnsureHasEditFieldFeatures(*state->m_current_item, pos); state->m_current_item->m_edit_field_features->m_max_paint_chars = value; })); AddSequence(std::make_unique("maxCharsGotoNext", [](const MenuFileParserState* state, const TokenPos& pos) { ItemScopeOperations::EnsureHasEditFieldFeatures(*state->m_current_item, pos); state->m_current_item->m_edit_field_features->m_max_chars_goto_next = true; })); // ============== Multi Value ============== AddSequence(std::make_unique()); AddSequence(std::make_unique()); // ============== Enum Dvar ============== AddSequence(std::make_unique("dvarEnumList", [](const MenuFileParserState* state, const TokenPos& pos, const std::string& value) { ItemScopeOperations::EnsureHasEnumDvarFeatures(*state->m_current_item, pos); state->m_current_item->m_enum_dvar_name = value; })); // ============== News Ticker ============== AddSequence(std::make_unique("spacing", [](const MenuFileParserState* state, const TokenPos& pos, const int value) { ItemScopeOperations::EnsureHasNewsTickerFeatures(*state->m_current_item, pos); state->m_current_item->m_news_ticker_features->m_spacing = value; })); AddSequence(std::make_unique("speed", [](const MenuFileParserState* state, const TokenPos& pos, const int value) { ItemScopeOperations::EnsureHasNewsTickerFeatures(*state->m_current_item, pos); state->m_current_item->m_news_ticker_features->m_speed = value; })); AddSequence(std::make_unique("newsfeed", [](const MenuFileParserState* state, const TokenPos& pos, const int value) { ItemScopeOperations::EnsureHasNewsTickerFeatures(*state->m_current_item, pos); state->m_current_item->m_news_ticker_features->m_news_feed_id = value; })); AddSequence(std::make_unique()); }