Add base for IW5 menu parsing

This commit is contained in:
Jan
2023-08-23 23:08:50 +02:00
parent 0d6e3e8298
commit 8a1fe03358
7 changed files with 175 additions and 58 deletions

View File

@ -848,6 +848,7 @@ namespace IW5
listBox->onDoubleClick = ConvertEventHandlerSet(commonListBox->m_on_double_click.get(), &parentMenu, &commonItem);
ConvertColor(listBox->selectBorder, commonListBox->m_select_border);
listBox->selectIcon = ConvertMaterial(commonListBox->m_select_icon, &parentMenu, &commonItem);
listBox->elementHeightExp = ConvertOrApplyStatement(listBox->elementHeight, commonListBox->m_element_height_expression.get(), &parentMenu, &commonItem);
listBox->numColumns = static_cast<int>(std::min(std::extent_v<decltype(listBoxDef_s::columnInfo)>, commonListBox->m_columns.size()));
for (auto i = 0; i < listBox->numColumns; i++)
@ -971,6 +972,7 @@ namespace IW5
ConvertColor(item->glowColor, commonItem.m_glow_color);
item->window.background = ConvertMaterial(commonItem.m_background, &parentMenu, &commonItem);
item->onFocus = ConvertEventHandlerSet(commonItem.m_on_focus.get(), &parentMenu, &commonItem);
item->hasFocus = ConvertEventHandlerSet(commonItem.m_has_focus.get(), &parentMenu, &commonItem);
item->leaveFocus = ConvertEventHandlerSet(commonItem.m_on_leave_focus.get(), &parentMenu, &commonItem);
item->mouseEnter = ConvertEventHandlerSet(commonItem.m_on_mouse_enter.get(), &parentMenu, &commonItem);
item->mouseExit = ConvertEventHandlerSet(commonItem.m_on_mouse_exit.get(), &parentMenu, &commonItem);
@ -983,6 +985,7 @@ namespace IW5
item->enableDvar = ConvertEnableDvar(commonItem, item->dvarFlags);
item->onKey = ConvertKeyHandler(commonItem.m_key_handlers, &parentMenu, &commonItem);
item->textExp = ConvertOrApplyStatement(item->text, commonItem.m_text_expression.get(), &parentMenu, &commonItem);
item->textAlignYExp = ConvertOrApplyStatement(item->textaligny, commonItem.m_text_align_y_expression.get(), &parentMenu, &commonItem);
item->materialExp = ConvertOrApplyStatement(item->window.background, commonItem.m_material_expression.get(), &parentMenu, &commonItem);
item->disabledExp = ConvertExpression(commonItem.m_disabled_expression.get(), &parentMenu, &commonItem);
item->floatExpressions = ConvertFloatExpressions(&commonItem, item, &parentMenu, item->floatExpressionCount);
@ -1103,6 +1106,7 @@ namespace IW5
menuData->onClose = ConvertEventHandlerSet(commonMenu.m_on_close.get(), &commonMenu);
menuData->onCloseRequest = ConvertEventHandlerSet(commonMenu.m_on_request_close.get(), &commonMenu);
menuData->onESC = ConvertEventHandlerSet(commonMenu.m_on_esc.get(), &commonMenu);
menuData->onFocusDueToClose = ConvertEventHandlerSet(commonMenu.m_on_focus_due_to_close.get(), &commonMenu);
menuData->onKey = ConvertKeyHandler(commonMenu.m_key_handlers, &commonMenu);
menu->items = ConvertMenuItems(commonMenu, menu->itemCount);
menuData->expressionData = m_conversion_zone_state->m_supporting_data;

View File

@ -44,6 +44,7 @@ namespace menu
std::string m_select_icon;
std::unique_ptr<CommonEventHandlerSet> m_on_double_click;
std::unique_ptr<ISimpleExpression> m_element_height_expression;
std::vector<Column> m_columns;
};
@ -136,6 +137,7 @@ namespace menu
std::unique_ptr<ISimpleExpression> m_visible_expression;
std::unique_ptr<ISimpleExpression> m_disabled_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_rect_x_exp;
std::unique_ptr<ISimpleExpression> m_rect_y_exp;
@ -145,6 +147,7 @@ namespace menu
ColorExpressions m_glowcolor_expressions;
ColorExpressions m_backcolor_expressions;
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_mouse_enter;
std::unique_ptr<CommonEventHandlerSet> m_on_mouse_exit;

View File

@ -29,6 +29,7 @@ namespace menu
int m_owner_draw = 0;
int m_owner_draw_flags = 0;
std::string m_sound_loop;
std::unique_ptr<ISimpleExpression> m_sound_loop_exp;
double m_fade_clamp = 0;
int m_fade_cycle = 0;
double m_fade_amount = 0;
@ -46,6 +47,7 @@ namespace menu
std::unique_ptr<CommonEventHandlerSet> m_on_close;
std::unique_ptr<CommonEventHandlerSet> m_on_request_close;
std::unique_ptr<CommonEventHandlerSet> m_on_esc;
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;

View File

@ -45,6 +45,34 @@ class ItemScopeOperations
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)
{
@ -66,8 +94,10 @@ public:
case FeatureLevel::IW5:
default:
assert(false);
throw ParsingException(pos, "Unimplemented item types for feature level");
if (static_cast<unsigned>(type) >= std::extent_v<decltype(IW5_FEATURE_TYPE_BY_TYPE)>)
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)
@ -431,26 +461,46 @@ namespace menu::item_scope_sequences
{
static constexpr auto CAPTURE_FIRST_TOKEN = 1;
static constexpr auto CAPTURE_COLUMN_COUNT = 2;
static constexpr auto CAPTURE_POS = 3;
static constexpr auto CAPTURE_WIDTH = 4;
static constexpr auto CAPTURE_MAX_CHARS = 5;
static constexpr auto CAPTURE_ALIGNMENT = 6;
static constexpr auto CAPTURE_X_POS = 3;
static constexpr auto CAPTURE_Y_POS = 4;
static constexpr auto CAPTURE_WIDTH = 5;
static constexpr auto CAPTURE_HEIGHT = 6;
static constexpr auto CAPTURE_MAX_CHARS = 7;
static constexpr auto CAPTURE_ALIGNMENT = 8;
public:
SequenceColumns()
explicit SequenceColumns(const FeatureLevel featureLevel)
{
const MenuMatcherFactory create(this);
AddMatchers({
create.KeywordIgnoreCase("columns").Capture(CAPTURE_FIRST_TOKEN),
create.Integer().Capture(CAPTURE_COLUMN_COUNT),
create.Loop(create.And({
create.Integer().Capture(CAPTURE_POS),
create.Integer().Capture(CAPTURE_WIDTH),
create.Integer().Capture(CAPTURE_MAX_CHARS),
create.Integer().Capture(CAPTURE_ALIGNMENT),
})),
});
if (featureLevel == FeatureLevel::IW5)
{
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_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:
@ -461,14 +511,14 @@ namespace menu::item_scope_sequences
ItemScopeOperations::EnsureHasListboxFeatures(*state->m_current_item, result.NextCapture(CAPTURE_FIRST_TOKEN).GetPos());
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
{
result.NextCapture(CAPTURE_POS).IntegerValue(),
0,
result.NextCapture(CAPTURE_X_POS).IntegerValue(),
state->m_feature_level == FeatureLevel::IW5 ? result.NextCapture(CAPTURE_Y_POS).IntegerValue() : 0,
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_ALIGNMENT).IntegerValue()
};
@ -681,36 +731,28 @@ void ItemScopeSequences::AddSequences(FeatureLevel featureLevel, bool permissive
{
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;
}));
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;
}));
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;
}));
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;
}));
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;
}));
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;
}));
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;
}));
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;
}));
// special
@ -854,8 +896,19 @@ void ItemScopeSequences::AddSequences(FeatureLevel featureLevel, bool permissive
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&, std::unique_ptr<ISimpleExpression> value)
{
state->m_current_item->m_text_align_y_expression = std::move(value);
}));
}
// ============== ListBox ==============
AddSequence(std::make_unique<SequenceColumns>());
AddSequence(std::make_unique<SequenceColumns>(featureLevel));
AddSequence(std::make_unique<GenericKeywordPropertySequence>("notselectable", [](const MenuFileParserState* state, const TokenPos& pos)
{
ItemScopeOperations::EnsureHasListboxFeatures(*state->m_current_item, pos);
@ -891,8 +944,7 @@ void ItemScopeSequences::AddSequences(FeatureLevel featureLevel, bool permissive
ItemScopeOperations::EnsureHasListboxFeatures(*state->m_current_item, pos);
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);
return state->m_current_item->m_list_box_features->m_on_double_click;
}));
@ -907,6 +959,15 @@ void ItemScopeSequences::AddSequences(FeatureLevel featureLevel, bool permissive
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);
state->m_current_item->m_list_box_features->m_element_height_expression = std::move(value);
}));
}
// ============== Edit Field ==============
AddSequence(std::make_unique<SequenceDvarFloat>());
AddSequence(std::make_unique<GenericStringPropertySequence>("localvar", [](const MenuFileParserState* state, const TokenPos& pos, const std::string& value)

View File

@ -258,20 +258,16 @@ void MenuScopeSequences::AddSequences(FeatureLevel featureLevel, bool permissive
{
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;
}));
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;
}));
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;
}));
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;
}));
AddSequence(std::make_unique<GenericIntPropertySequence>("border", [](const MenuFileParserState* state, const TokenPos&, const int value)
@ -396,5 +392,19 @@ void MenuScopeSequences::AddSequences(FeatureLevel featureLevel, bool permissive
{
state->m_current_menu->m_text_only_focus = true;
}));
if (featureLevel == FeatureLevel::IW5)
{
AddSequence(GenericExpressionPropertySequence::WithKeywords({"exp", "soundLoop"}, [](const MenuFileParserState* state, const TokenPos&, std::unique_ptr<ISimpleExpression> 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>());
}