fix: menu rect optimization not setting global values (#920)

* fix: menu rect optimization not setting global values

* fix: relative item rects not considering optimized parent rect
This commit is contained in:
Jan Laupetin
2026-07-20 19:24:58 +02:00
committed by GitHub
parent 9c56a28ef4
commit fadcd74182
3 changed files with 500 additions and 136 deletions
+187 -67
View File
@@ -37,15 +37,15 @@ namespace
}; };
} }
[[nodiscard]] static rectDef_s ConvertRectDefRelativeTo(const CommonRect& rect, const CommonRect& rectRelativeTo) [[nodiscard]] static rectDef_s ConvertRectDefRelativeTo(const rectDef_s& rect, const rectDef_s& rectRelativeTo)
{ {
return rectDef_s{ return rectDef_s{
static_cast<float>(rectRelativeTo.x + rect.x), .x = rectRelativeTo.x + rect.x,
static_cast<float>(rectRelativeTo.y + rect.y), .y = rectRelativeTo.y + rect.y,
static_cast<float>(rect.w), .w = static_cast<float>(rect.w),
static_cast<float>(rect.h), .h = static_cast<float>(rect.h),
static_cast<unsigned char>(rect.horizontalAlign), .horzAlign = static_cast<unsigned char>(rect.horzAlign),
static_cast<unsigned char>(rect.verticalAlign), .vertAlign = static_cast<unsigned char>(rect.vertAlign),
}; };
} }
@@ -745,40 +745,158 @@ namespace
}; };
FloatExpressionLocation locations[]{ FloatExpressionLocation locations[]{
{commonItem->m_rect_x_exp.get(), false, ITEM_FLOATEXP_TGT_RECT_X, &item->window.rectClient.x, 1, 0 }, {
{commonItem->m_rect_y_exp.get(), false, ITEM_FLOATEXP_TGT_RECT_Y, &item->window.rectClient.y, 1, 0 }, .m_expression = commonItem->m_rect_x_exp.get(),
{commonItem->m_rect_w_exp.get(), false, ITEM_FLOATEXP_TGT_RECT_W, &item->window.rectClient.w, 1, 0 }, .m_expression_is_static = false,
{commonItem->m_rect_h_exp.get(), false, ITEM_FLOATEXP_TGT_RECT_H, &item->window.rectClient.h, 1, 0 }, .m_target = ITEM_FLOATEXP_TGT_RECT_X,
{commonItem->m_forecolor_expressions.m_r_exp.get(), .m_static_value = &item->window.rectClient.x,
false, ITEM_FLOATEXP_TGT_FORECOLOR_R, .m_static_value_array_size = 1,
&item->window.foreColor[0], .m_dynamic_flags_to_set = 0,
1, WINDOW_FLAG_NON_DEFAULT_FORECOLOR}, },
{commonItem->m_forecolor_expressions.m_g_exp.get(), {
false, ITEM_FLOATEXP_TGT_FORECOLOR_G, .m_expression = commonItem->m_rect_y_exp.get(),
&item->window.foreColor[1], .m_expression_is_static = false,
1, WINDOW_FLAG_NON_DEFAULT_FORECOLOR}, .m_target = ITEM_FLOATEXP_TGT_RECT_Y,
{commonItem->m_forecolor_expressions.m_b_exp.get(), .m_static_value = &item->window.rectClient.y,
false, ITEM_FLOATEXP_TGT_FORECOLOR_B, .m_static_value_array_size = 1,
&item->window.foreColor[2], .m_dynamic_flags_to_set = 0,
1, WINDOW_FLAG_NON_DEFAULT_FORECOLOR}, },
{commonItem->m_forecolor_expressions.m_a_exp.get(), {
false, ITEM_FLOATEXP_TGT_FORECOLOR_A, .m_expression = commonItem->m_rect_w_exp.get(),
&item->window.foreColor[3], .m_expression_is_static = false,
1, WINDOW_FLAG_NON_DEFAULT_FORECOLOR}, .m_target = ITEM_FLOATEXP_TGT_RECT_W,
{commonItem->m_forecolor_expressions.m_rgb_exp.get(), .m_static_value = &item->window.rectClient.w,
false, ITEM_FLOATEXP_TGT_FORECOLOR_RGB, .m_static_value_array_size = 1,
&item->window.foreColor[0], .m_dynamic_flags_to_set = 0,
3, WINDOW_FLAG_NON_DEFAULT_FORECOLOR}, },
{commonItem->m_glowcolor_expressions.m_r_exp.get(), false, ITEM_FLOATEXP_TGT_GLOWCOLOR_R, &item->glowColor[0], 1, 0 }, {
{commonItem->m_glowcolor_expressions.m_g_exp.get(), false, ITEM_FLOATEXP_TGT_GLOWCOLOR_G, &item->glowColor[1], 1, 0 }, .m_expression = commonItem->m_rect_h_exp.get(),
{commonItem->m_glowcolor_expressions.m_b_exp.get(), false, ITEM_FLOATEXP_TGT_GLOWCOLOR_B, &item->glowColor[2], 1, 0 }, .m_expression_is_static = false,
{commonItem->m_glowcolor_expressions.m_a_exp.get(), false, ITEM_FLOATEXP_TGT_GLOWCOLOR_A, &item->glowColor[3], 1, 0 }, .m_target = ITEM_FLOATEXP_TGT_RECT_H,
{commonItem->m_glowcolor_expressions.m_rgb_exp.get(), false, ITEM_FLOATEXP_TGT_GLOWCOLOR_RGB, &item->glowColor[0], 3, 0 }, .m_static_value = &item->window.rectClient.h,
{commonItem->m_backcolor_expressions.m_r_exp.get(), false, ITEM_FLOATEXP_TGT_BACKCOLOR_R, &item->window.backColor[0], 1, 0 }, .m_static_value_array_size = 1,
{commonItem->m_backcolor_expressions.m_g_exp.get(), false, ITEM_FLOATEXP_TGT_BACKCOLOR_G, &item->window.backColor[1], 1, 0 }, .m_dynamic_flags_to_set = 0,
{commonItem->m_backcolor_expressions.m_b_exp.get(), false, ITEM_FLOATEXP_TGT_BACKCOLOR_B, &item->window.backColor[2], 1, 0 }, },
{commonItem->m_backcolor_expressions.m_a_exp.get(), false, ITEM_FLOATEXP_TGT_BACKCOLOR_A, &item->window.backColor[3], 1, 0 }, {
{commonItem->m_backcolor_expressions.m_rgb_exp.get(), false, ITEM_FLOATEXP_TGT_BACKCOLOR_RGB, &item->window.backColor[0], 3, 0 }, .m_expression = commonItem->m_forecolor_expressions.m_r_exp.get(),
.m_expression_is_static = false,
.m_target = ITEM_FLOATEXP_TGT_FORECOLOR_R,
.m_static_value = &item->window.foreColor[0],
.m_static_value_array_size = 1,
.m_dynamic_flags_to_set = WINDOW_FLAG_NON_DEFAULT_FORECOLOR,
},
{
.m_expression = commonItem->m_forecolor_expressions.m_g_exp.get(),
.m_expression_is_static = false,
.m_target = ITEM_FLOATEXP_TGT_FORECOLOR_G,
.m_static_value = &item->window.foreColor[1],
.m_static_value_array_size = 1,
.m_dynamic_flags_to_set = WINDOW_FLAG_NON_DEFAULT_FORECOLOR,
},
{
.m_expression = commonItem->m_forecolor_expressions.m_b_exp.get(),
.m_expression_is_static = false,
.m_target = ITEM_FLOATEXP_TGT_FORECOLOR_B,
.m_static_value = &item->window.foreColor[2],
.m_static_value_array_size = 1,
.m_dynamic_flags_to_set = WINDOW_FLAG_NON_DEFAULT_FORECOLOR,
},
{
.m_expression = commonItem->m_forecolor_expressions.m_a_exp.get(),
.m_expression_is_static = false,
.m_target = ITEM_FLOATEXP_TGT_FORECOLOR_A,
.m_static_value = &item->window.foreColor[3],
.m_static_value_array_size = 1,
.m_dynamic_flags_to_set = WINDOW_FLAG_NON_DEFAULT_FORECOLOR,
},
{
.m_expression = commonItem->m_forecolor_expressions.m_rgb_exp.get(),
.m_expression_is_static = false,
.m_target = ITEM_FLOATEXP_TGT_FORECOLOR_RGB,
.m_static_value = &item->window.foreColor[0],
.m_static_value_array_size = 3,
.m_dynamic_flags_to_set = WINDOW_FLAG_NON_DEFAULT_FORECOLOR,
},
{
.m_expression = commonItem->m_glowcolor_expressions.m_r_exp.get(),
.m_expression_is_static = false,
.m_target = ITEM_FLOATEXP_TGT_GLOWCOLOR_R,
.m_static_value = &item->glowColor[0],
.m_static_value_array_size = 1,
.m_dynamic_flags_to_set = 0,
},
{
.m_expression = commonItem->m_glowcolor_expressions.m_g_exp.get(),
.m_expression_is_static = false,
.m_target = ITEM_FLOATEXP_TGT_GLOWCOLOR_G,
.m_static_value = &item->glowColor[1],
.m_static_value_array_size = 1,
.m_dynamic_flags_to_set = 0,
},
{
.m_expression = commonItem->m_glowcolor_expressions.m_b_exp.get(),
.m_expression_is_static = false,
.m_target = ITEM_FLOATEXP_TGT_GLOWCOLOR_B,
.m_static_value = &item->glowColor[2],
.m_static_value_array_size = 1,
.m_dynamic_flags_to_set = 0,
},
{
.m_expression = commonItem->m_glowcolor_expressions.m_a_exp.get(),
.m_expression_is_static = false,
.m_target = ITEM_FLOATEXP_TGT_GLOWCOLOR_A,
.m_static_value = &item->glowColor[3],
.m_static_value_array_size = 1,
.m_dynamic_flags_to_set = 0,
},
{
.m_expression = commonItem->m_glowcolor_expressions.m_rgb_exp.get(),
.m_expression_is_static = false,
.m_target = ITEM_FLOATEXP_TGT_GLOWCOLOR_RGB,
.m_static_value = &item->glowColor[0],
.m_static_value_array_size = 3,
.m_dynamic_flags_to_set = 0,
},
{
.m_expression = commonItem->m_backcolor_expressions.m_r_exp.get(),
.m_expression_is_static = false,
.m_target = ITEM_FLOATEXP_TGT_BACKCOLOR_R,
.m_static_value = &item->window.backColor[0],
.m_static_value_array_size = 1,
.m_dynamic_flags_to_set = 0,
},
{
.m_expression = commonItem->m_backcolor_expressions.m_g_exp.get(),
.m_expression_is_static = false,
.m_target = ITEM_FLOATEXP_TGT_BACKCOLOR_G,
.m_static_value = &item->window.backColor[1],
.m_static_value_array_size = 1,
.m_dynamic_flags_to_set = 0,
},
{
.m_expression = commonItem->m_backcolor_expressions.m_b_exp.get(),
.m_expression_is_static = false,
.m_target = ITEM_FLOATEXP_TGT_BACKCOLOR_B,
.m_static_value = &item->window.backColor[2],
.m_static_value_array_size = 1,
.m_dynamic_flags_to_set = 0,
},
{
.m_expression = commonItem->m_backcolor_expressions.m_a_exp.get(),
.m_expression_is_static = false,
.m_target = ITEM_FLOATEXP_TGT_BACKCOLOR_A,
.m_static_value = &item->window.backColor[3],
.m_static_value_array_size = 1,
.m_dynamic_flags_to_set = 0,
},
{
.m_expression = commonItem->m_backcolor_expressions.m_rgb_exp.get(),
.m_expression_is_static = false,
.m_target = ITEM_FLOATEXP_TGT_BACKCOLOR_RGB,
.m_static_value = &item->window.backColor[0],
.m_static_value_array_size = 3,
.m_dynamic_flags_to_set = 0,
},
}; };
floatExpressionCount = 0; floatExpressionCount = 0;
@@ -994,7 +1112,7 @@ namespace
return newsTicker; return newsTicker;
} }
[[nodiscard]] itemDef_s* ConvertItem(const CommonMenuDef& parentMenu, const CommonItemDef& commonItem) const [[nodiscard]] itemDef_s* ConvertItem(const CommonMenuDef& commonParentMenu, const menuDef_t& parentMenu, const CommonItemDef& commonItem) const
{ {
auto* item = m_memory.Alloc<itemDef_s>(); auto* item = m_memory.Alloc<itemDef_s>();
@@ -1004,7 +1122,6 @@ namespace
ApplyFlag(item->itemFlags, commonItem.m_text_cinematic_subtitle, ITEM_FLAG_CINEMATIC_SUBTITLE); ApplyFlag(item->itemFlags, commonItem.m_text_cinematic_subtitle, ITEM_FLAG_CINEMATIC_SUBTITLE);
item->window.group = ConvertString(commonItem.m_group); item->window.group = ConvertString(commonItem.m_group);
item->window.rectClient = ConvertRectDef(commonItem.m_rect); item->window.rectClient = ConvertRectDef(commonItem.m_rect);
item->window.rect = ConvertRectDefRelativeTo(commonItem.m_rect, parentMenu.m_rect);
item->window.style = commonItem.m_style; item->window.style = commonItem.m_style;
ApplyFlag(item->window.staticFlags, commonItem.m_decoration, WINDOW_FLAG_DECORATION); ApplyFlag(item->window.staticFlags, commonItem.m_decoration, WINDOW_FLAG_DECORATION);
ApplyFlag(item->window.staticFlags, commonItem.m_auto_wrapped, WINDOW_FLAG_AUTO_WRAPPED); ApplyFlag(item->window.staticFlags, commonItem.m_auto_wrapped, WINDOW_FLAG_AUTO_WRAPPED);
@@ -1013,8 +1130,8 @@ namespace
item->dataType = item->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(), &commonParentMenu, &commonItem);
item->disabledExp = ConvertExpression(commonItem.m_disabled_expression.get(), &parentMenu, &commonItem); item->disabledExp = ConvertExpression(commonItem.m_disabled_expression.get(), &commonParentMenu, &commonItem);
item->window.ownerDraw = commonItem.m_owner_draw; item->window.ownerDraw = commonItem.m_owner_draw;
item->window.ownerDrawFlags = commonItem.m_owner_draw_flags; item->window.ownerDrawFlags = commonItem.m_owner_draw_flags;
item->alignment = commonItem.m_align; item->alignment = commonItem.m_align;
@@ -1034,23 +1151,23 @@ namespace
ConvertColor(item->window.outlineColor, commonItem.m_outline_color); ConvertColor(item->window.outlineColor, commonItem.m_outline_color);
ConvertColor(item->window.disableColor, commonItem.m_disable_color); ConvertColor(item->window.disableColor, commonItem.m_disable_color);
ConvertColor(item->glowColor, commonItem.m_glow_color); ConvertColor(item->glowColor, commonItem.m_glow_color);
item->window.background = ConvertMaterial(commonItem.m_background, &parentMenu, &commonItem); item->window.background = ConvertMaterial(commonItem.m_background, &commonParentMenu, &commonItem);
item->onFocus = ConvertEventHandlerSet(commonItem.m_on_focus.get(), &parentMenu, &commonItem); item->onFocus = ConvertEventHandlerSet(commonItem.m_on_focus.get(), &commonParentMenu, &commonItem);
item->leaveFocus = ConvertEventHandlerSet(commonItem.m_on_leave_focus.get(), &parentMenu, &commonItem); item->leaveFocus = ConvertEventHandlerSet(commonItem.m_on_leave_focus.get(), &commonParentMenu, &commonItem);
item->mouseEnter = ConvertEventHandlerSet(commonItem.m_on_mouse_enter.get(), &parentMenu, &commonItem); item->mouseEnter = ConvertEventHandlerSet(commonItem.m_on_mouse_enter.get(), &commonParentMenu, &commonItem);
item->mouseExit = ConvertEventHandlerSet(commonItem.m_on_mouse_exit.get(), &parentMenu, &commonItem); item->mouseExit = ConvertEventHandlerSet(commonItem.m_on_mouse_exit.get(), &commonParentMenu, &commonItem);
item->mouseEnterText = ConvertEventHandlerSet(commonItem.m_on_mouse_enter_text.get(), &parentMenu, &commonItem); item->mouseEnterText = ConvertEventHandlerSet(commonItem.m_on_mouse_enter_text.get(), &commonParentMenu, &commonItem);
item->mouseExitText = ConvertEventHandlerSet(commonItem.m_on_mouse_exit_text.get(), &parentMenu, &commonItem); item->mouseExitText = ConvertEventHandlerSet(commonItem.m_on_mouse_exit_text.get(), &commonParentMenu, &commonItem);
item->action = ConvertEventHandlerSet(commonItem.m_on_action.get(), &parentMenu, &commonItem); item->action = ConvertEventHandlerSet(commonItem.m_on_action.get(), &commonParentMenu, &commonItem);
item->accept = ConvertEventHandlerSet(commonItem.m_on_accept.get(), &parentMenu, &commonItem); item->accept = ConvertEventHandlerSet(commonItem.m_on_accept.get(), &commonParentMenu, &commonItem);
item->focusSound = ConvertSound(commonItem.m_focus_sound, &parentMenu, &commonItem); item->focusSound = ConvertSound(commonItem.m_focus_sound, &commonParentMenu, &commonItem);
item->dvarTest = ConvertString(commonItem.m_dvar_test); item->dvarTest = ConvertString(commonItem.m_dvar_test);
item->enableDvar = ConvertEnableDvar(commonItem, item->dvarFlags); item->enableDvar = ConvertEnableDvar(commonItem, item->dvarFlags);
item->onKey = ConvertKeyHandler(commonItem.m_key_handlers, &parentMenu, &commonItem); item->onKey = ConvertKeyHandler(commonItem.m_key_handlers, &commonParentMenu, &commonItem);
item->textExp = ConvertOrApplyStatement(item->text, commonItem.m_text_expression.get(), &parentMenu, &commonItem); item->textExp = ConvertOrApplyStatement(item->text, commonItem.m_text_expression.get(), &commonParentMenu, &commonItem);
item->materialExp = ConvertOrApplyStatement(item->window.background, commonItem.m_material_expression.get(), &parentMenu, &commonItem); item->materialExp = ConvertOrApplyStatement(item->window.background, commonItem.m_material_expression.get(), &commonParentMenu, &commonItem);
item->disabledExp = ConvertExpression(commonItem.m_disabled_expression.get(), &parentMenu, &commonItem); item->disabledExp = ConvertExpression(commonItem.m_disabled_expression.get(), &commonParentMenu, &commonItem);
item->floatExpressions = ConvertFloatExpressions(&commonItem, item, &parentMenu, item->floatExpressionCount); item->floatExpressions = ConvertFloatExpressions(&commonItem, item, &commonParentMenu, item->floatExpressionCount);
item->gameMsgWindowIndex = commonItem.m_game_message_window_index; item->gameMsgWindowIndex = commonItem.m_game_message_window_index;
item->gameMsgWindowMode = commonItem.m_game_message_window_mode; item->gameMsgWindowMode = commonItem.m_game_message_window_mode;
item->fxLetterTime = commonItem.m_fx_letter_time; item->fxLetterTime = commonItem.m_fx_letter_time;
@@ -1061,15 +1178,15 @@ namespace
switch (commonItem.m_feature_type) switch (commonItem.m_feature_type)
{ {
case CommonItemFeatureType::LISTBOX: case CommonItemFeatureType::LISTBOX:
item->typeData.listBox = ConvertListBoxFeatures(item, commonItem.m_list_box_features.get(), parentMenu, commonItem); item->typeData.listBox = ConvertListBoxFeatures(item, commonItem.m_list_box_features.get(), commonParentMenu, commonItem);
break; break;
case CommonItemFeatureType::EDIT_FIELD: case CommonItemFeatureType::EDIT_FIELD:
item->typeData.editField = ConvertEditFieldFeatures(item, commonItem.m_edit_field_features.get(), parentMenu, commonItem); item->typeData.editField = ConvertEditFieldFeatures(item, commonItem.m_edit_field_features.get(), commonParentMenu, commonItem);
break; break;
case CommonItemFeatureType::MULTI_VALUE: case CommonItemFeatureType::MULTI_VALUE:
item->typeData.multi = ConvertMultiValueFeatures(item, commonItem.m_multi_value_features.get(), parentMenu, commonItem); item->typeData.multi = ConvertMultiValueFeatures(item, commonItem.m_multi_value_features.get(), commonParentMenu, commonItem);
break; break;
case CommonItemFeatureType::ENUM_DVAR: case CommonItemFeatureType::ENUM_DVAR:
@@ -1077,7 +1194,7 @@ namespace
break; break;
case CommonItemFeatureType::NEWS_TICKER: case CommonItemFeatureType::NEWS_TICKER:
item->typeData.ticker = ConvertNewsTickerFeatures(item, commonItem.m_news_ticker_features.get(), parentMenu, commonItem); item->typeData.ticker = ConvertNewsTickerFeatures(item, commonItem.m_news_ticker_features.get(), commonParentMenu, commonItem);
break; break;
case CommonItemFeatureType::NONE: case CommonItemFeatureType::NONE:
@@ -1088,10 +1205,13 @@ namespace
break; break;
} }
// Do this last so any optimizations are considered
item->window.rect = ConvertRectDefRelativeTo(item->window.rectClient, parentMenu.window.rect);
return item; return item;
} }
itemDef_s** ConvertMenuItems(const CommonMenuDef& commonMenu, int& itemCount) const itemDef_s** ConvertMenuItems(const CommonMenuDef& commonMenu, const menuDef_t& menu, int& itemCount) const
{ {
if (commonMenu.m_items.empty()) if (commonMenu.m_items.empty())
{ {
@@ -1101,7 +1221,7 @@ namespace
auto* items = m_memory.Alloc<itemDef_s*>(commonMenu.m_items.size()); auto* items = m_memory.Alloc<itemDef_s*>(commonMenu.m_items.size());
for (auto i = 0u; i < commonMenu.m_items.size(); i++) for (auto i = 0u; i < commonMenu.m_items.size(); i++)
items[i] = ConvertItem(commonMenu, *commonMenu.m_items[i]); items[i] = ConvertItem(commonMenu, menu, *commonMenu.m_items[i]);
itemCount = static_cast<int>(commonMenu.m_items.size()); itemCount = static_cast<int>(commonMenu.m_items.size());
@@ -1161,7 +1281,7 @@ namespace
menu.onCloseRequest = ConvertEventHandlerSet(commonMenu.m_on_request_close.get(), &commonMenu); menu.onCloseRequest = ConvertEventHandlerSet(commonMenu.m_on_request_close.get(), &commonMenu);
menu.onESC = ConvertEventHandlerSet(commonMenu.m_on_esc.get(), &commonMenu); menu.onESC = ConvertEventHandlerSet(commonMenu.m_on_esc.get(), &commonMenu);
menu.onKey = ConvertKeyHandler(commonMenu.m_key_handlers, &commonMenu); menu.onKey = ConvertKeyHandler(commonMenu.m_key_handlers, &commonMenu);
menu.items = ConvertMenuItems(commonMenu, menu.itemCount); menu.items = ConvertMenuItems(commonMenu, menu, menu.itemCount);
menu.expressionData = m_conversion_zone_state.m_supporting_data; menu.expressionData = m_conversion_zone_state.m_supporting_data;
} }
catch (const MenuConversionException& e) catch (const MenuConversionException& e)
+189 -69
View File
@@ -37,15 +37,15 @@ namespace
}; };
} }
[[nodiscard]] static rectDef_s ConvertRectDefRelativeTo(const CommonRect& rect, const CommonRect& rectRelativeTo) [[nodiscard]] static rectDef_s ConvertRectDefRelativeTo(const rectDef_s& rect, const rectDef_s& rectRelativeTo)
{ {
return rectDef_s{ return rectDef_s{
static_cast<float>(rectRelativeTo.x + rect.x), .x = rectRelativeTo.x + rect.x,
static_cast<float>(rectRelativeTo.y + rect.y), .y = rectRelativeTo.y + rect.y,
static_cast<float>(rect.w), .w = static_cast<float>(rect.w),
static_cast<float>(rect.h), .h = static_cast<float>(rect.h),
static_cast<unsigned char>(rect.horizontalAlign), .horzAlign = static_cast<unsigned char>(rect.horzAlign),
static_cast<unsigned char>(rect.verticalAlign), .vertAlign = static_cast<unsigned char>(rect.vertAlign),
}; };
} }
@@ -747,40 +747,158 @@ namespace
}; };
FloatExpressionLocation locations[]{ FloatExpressionLocation locations[]{
{commonItem->m_rect_x_exp.get(), false, ITEM_FLOATEXP_TGT_RECT_X, &item->window.rectClient.x, 1, 0 }, {
{commonItem->m_rect_y_exp.get(), false, ITEM_FLOATEXP_TGT_RECT_Y, &item->window.rectClient.y, 1, 0 }, .m_expression = commonItem->m_rect_x_exp.get(),
{commonItem->m_rect_w_exp.get(), false, ITEM_FLOATEXP_TGT_RECT_W, &item->window.rectClient.w, 1, 0 }, .m_expression_is_static = false,
{commonItem->m_rect_h_exp.get(), false, ITEM_FLOATEXP_TGT_RECT_H, &item->window.rectClient.h, 1, 0 }, .m_target = ITEM_FLOATEXP_TGT_RECT_X,
{commonItem->m_forecolor_expressions.m_r_exp.get(), .m_static_value = &item->window.rectClient.x,
false, ITEM_FLOATEXP_TGT_FORECOLOR_R, .m_static_value_array_size = 1,
&item->window.foreColor[0], .m_dynamic_flags_to_set = 0,
1, WINDOW_FLAG_NON_DEFAULT_FORECOLOR}, },
{commonItem->m_forecolor_expressions.m_g_exp.get(), {
false, ITEM_FLOATEXP_TGT_FORECOLOR_G, .m_expression = commonItem->m_rect_y_exp.get(),
&item->window.foreColor[1], .m_expression_is_static = false,
1, WINDOW_FLAG_NON_DEFAULT_FORECOLOR}, .m_target = ITEM_FLOATEXP_TGT_RECT_Y,
{commonItem->m_forecolor_expressions.m_b_exp.get(), .m_static_value = &item->window.rectClient.y,
false, ITEM_FLOATEXP_TGT_FORECOLOR_B, .m_static_value_array_size = 1,
&item->window.foreColor[2], .m_dynamic_flags_to_set = 0,
1, WINDOW_FLAG_NON_DEFAULT_FORECOLOR}, },
{commonItem->m_forecolor_expressions.m_a_exp.get(), {
false, ITEM_FLOATEXP_TGT_FORECOLOR_A, .m_expression = commonItem->m_rect_w_exp.get(),
&item->window.foreColor[3], .m_expression_is_static = false,
1, WINDOW_FLAG_NON_DEFAULT_FORECOLOR}, .m_target = ITEM_FLOATEXP_TGT_RECT_W,
{commonItem->m_forecolor_expressions.m_rgb_exp.get(), .m_static_value = &item->window.rectClient.w,
false, ITEM_FLOATEXP_TGT_FORECOLOR_RGB, .m_static_value_array_size = 1,
&item->window.foreColor[0], .m_dynamic_flags_to_set = 0,
3, WINDOW_FLAG_NON_DEFAULT_FORECOLOR}, },
{commonItem->m_glowcolor_expressions.m_r_exp.get(), false, ITEM_FLOATEXP_TGT_GLOWCOLOR_R, &item->glowColor[0], 1, 0 }, {
{commonItem->m_glowcolor_expressions.m_g_exp.get(), false, ITEM_FLOATEXP_TGT_GLOWCOLOR_G, &item->glowColor[1], 1, 0 }, .m_expression = commonItem->m_rect_h_exp.get(),
{commonItem->m_glowcolor_expressions.m_b_exp.get(), false, ITEM_FLOATEXP_TGT_GLOWCOLOR_B, &item->glowColor[2], 1, 0 }, .m_expression_is_static = false,
{commonItem->m_glowcolor_expressions.m_a_exp.get(), false, ITEM_FLOATEXP_TGT_GLOWCOLOR_A, &item->glowColor[3], 1, 0 }, .m_target = ITEM_FLOATEXP_TGT_RECT_H,
{commonItem->m_glowcolor_expressions.m_rgb_exp.get(), false, ITEM_FLOATEXP_TGT_GLOWCOLOR_RGB, &item->glowColor[0], 3, 0 }, .m_static_value = &item->window.rectClient.h,
{commonItem->m_backcolor_expressions.m_r_exp.get(), false, ITEM_FLOATEXP_TGT_BACKCOLOR_R, &item->window.backColor[0], 1, 0 }, .m_static_value_array_size = 1,
{commonItem->m_backcolor_expressions.m_g_exp.get(), false, ITEM_FLOATEXP_TGT_BACKCOLOR_G, &item->window.backColor[1], 1, 0 }, .m_dynamic_flags_to_set = 0,
{commonItem->m_backcolor_expressions.m_b_exp.get(), false, ITEM_FLOATEXP_TGT_BACKCOLOR_B, &item->window.backColor[2], 1, 0 }, },
{commonItem->m_backcolor_expressions.m_a_exp.get(), false, ITEM_FLOATEXP_TGT_BACKCOLOR_A, &item->window.backColor[3], 1, 0 }, {
{commonItem->m_backcolor_expressions.m_rgb_exp.get(), false, ITEM_FLOATEXP_TGT_BACKCOLOR_RGB, &item->window.backColor[0], 3, 0 }, .m_expression = commonItem->m_forecolor_expressions.m_r_exp.get(),
.m_expression_is_static = false,
.m_target = ITEM_FLOATEXP_TGT_FORECOLOR_R,
.m_static_value = &item->window.foreColor[0],
.m_static_value_array_size = 1,
.m_dynamic_flags_to_set = WINDOW_FLAG_NON_DEFAULT_FORECOLOR,
},
{
.m_expression = commonItem->m_forecolor_expressions.m_g_exp.get(),
.m_expression_is_static = false,
.m_target = ITEM_FLOATEXP_TGT_FORECOLOR_G,
.m_static_value = &item->window.foreColor[1],
.m_static_value_array_size = 1,
.m_dynamic_flags_to_set = WINDOW_FLAG_NON_DEFAULT_FORECOLOR,
},
{
.m_expression = commonItem->m_forecolor_expressions.m_b_exp.get(),
.m_expression_is_static = false,
.m_target = ITEM_FLOATEXP_TGT_FORECOLOR_B,
.m_static_value = &item->window.foreColor[2],
.m_static_value_array_size = 1,
.m_dynamic_flags_to_set = WINDOW_FLAG_NON_DEFAULT_FORECOLOR,
},
{
.m_expression = commonItem->m_forecolor_expressions.m_a_exp.get(),
.m_expression_is_static = false,
.m_target = ITEM_FLOATEXP_TGT_FORECOLOR_A,
.m_static_value = &item->window.foreColor[3],
.m_static_value_array_size = 1,
.m_dynamic_flags_to_set = WINDOW_FLAG_NON_DEFAULT_FORECOLOR,
},
{
.m_expression = commonItem->m_forecolor_expressions.m_rgb_exp.get(),
.m_expression_is_static = false,
.m_target = ITEM_FLOATEXP_TGT_FORECOLOR_RGB,
.m_static_value = &item->window.foreColor[0],
.m_static_value_array_size = 3,
.m_dynamic_flags_to_set = WINDOW_FLAG_NON_DEFAULT_FORECOLOR,
},
{
.m_expression = commonItem->m_glowcolor_expressions.m_r_exp.get(),
.m_expression_is_static = false,
.m_target = ITEM_FLOATEXP_TGT_GLOWCOLOR_R,
.m_static_value = &item->glowColor[0],
.m_static_value_array_size = 1,
.m_dynamic_flags_to_set = 0,
},
{
.m_expression = commonItem->m_glowcolor_expressions.m_g_exp.get(),
.m_expression_is_static = false,
.m_target = ITEM_FLOATEXP_TGT_GLOWCOLOR_G,
.m_static_value = &item->glowColor[1],
.m_static_value_array_size = 1,
.m_dynamic_flags_to_set = 0,
},
{
.m_expression = commonItem->m_glowcolor_expressions.m_b_exp.get(),
.m_expression_is_static = false,
.m_target = ITEM_FLOATEXP_TGT_GLOWCOLOR_B,
.m_static_value = &item->glowColor[2],
.m_static_value_array_size = 1,
.m_dynamic_flags_to_set = 0,
},
{
.m_expression = commonItem->m_glowcolor_expressions.m_a_exp.get(),
.m_expression_is_static = false,
.m_target = ITEM_FLOATEXP_TGT_GLOWCOLOR_A,
.m_static_value = &item->glowColor[3],
.m_static_value_array_size = 1,
.m_dynamic_flags_to_set = 0,
},
{
.m_expression = commonItem->m_glowcolor_expressions.m_rgb_exp.get(),
.m_expression_is_static = false,
.m_target = ITEM_FLOATEXP_TGT_GLOWCOLOR_RGB,
.m_static_value = &item->glowColor[0],
.m_static_value_array_size = 3,
.m_dynamic_flags_to_set = 0,
},
{
.m_expression = commonItem->m_backcolor_expressions.m_r_exp.get(),
.m_expression_is_static = false,
.m_target = ITEM_FLOATEXP_TGT_BACKCOLOR_R,
.m_static_value = &item->window.backColor[0],
.m_static_value_array_size = 1,
.m_dynamic_flags_to_set = 0,
},
{
.m_expression = commonItem->m_backcolor_expressions.m_g_exp.get(),
.m_expression_is_static = false,
.m_target = ITEM_FLOATEXP_TGT_BACKCOLOR_G,
.m_static_value = &item->window.backColor[1],
.m_static_value_array_size = 1,
.m_dynamic_flags_to_set = 0,
},
{
.m_expression = commonItem->m_backcolor_expressions.m_b_exp.get(),
.m_expression_is_static = false,
.m_target = ITEM_FLOATEXP_TGT_BACKCOLOR_B,
.m_static_value = &item->window.backColor[2],
.m_static_value_array_size = 1,
.m_dynamic_flags_to_set = 0,
},
{
.m_expression = commonItem->m_backcolor_expressions.m_a_exp.get(),
.m_expression_is_static = false,
.m_target = ITEM_FLOATEXP_TGT_BACKCOLOR_A,
.m_static_value = &item->window.backColor[3],
.m_static_value_array_size = 1,
.m_dynamic_flags_to_set = 0,
},
{
.m_expression = commonItem->m_backcolor_expressions.m_rgb_exp.get(),
.m_expression_is_static = false,
.m_target = ITEM_FLOATEXP_TGT_BACKCOLOR_RGB,
.m_static_value = &item->window.backColor[0],
.m_static_value_array_size = 3,
.m_dynamic_flags_to_set = 0,
},
}; };
floatExpressionCount = 0; floatExpressionCount = 0;
@@ -999,7 +1117,7 @@ namespace
return newsTicker; return newsTicker;
} }
[[nodiscard]] itemDef_s* ConvertItem(const CommonMenuDef& parentMenu, const CommonItemDef& commonItem) const [[nodiscard]] itemDef_s* ConvertItem(const CommonMenuDef& commonParentMenu, const menuDef_t& parentMenu, const CommonItemDef& commonItem) const
{ {
auto* item = m_memory.Alloc<itemDef_s>(); auto* item = m_memory.Alloc<itemDef_s>();
memset(item, 0, sizeof(itemDef_s)); memset(item, 0, sizeof(itemDef_s));
@@ -1010,7 +1128,6 @@ namespace
ApplyFlag(item->itemFlags, commonItem.m_text_cinematic_subtitle, ITEM_FLAG_CINEMATIC_SUBTITLE); ApplyFlag(item->itemFlags, commonItem.m_text_cinematic_subtitle, ITEM_FLAG_CINEMATIC_SUBTITLE);
item->window.group = ConvertString(commonItem.m_group); item->window.group = ConvertString(commonItem.m_group);
item->window.rectClient = ConvertRectDef(commonItem.m_rect); item->window.rectClient = ConvertRectDef(commonItem.m_rect);
item->window.rect = ConvertRectDefRelativeTo(commonItem.m_rect, parentMenu.m_rect);
item->window.style = commonItem.m_style; item->window.style = commonItem.m_style;
ApplyFlag(item->window.staticFlags, commonItem.m_decoration, WINDOW_FLAG_DECORATION); ApplyFlag(item->window.staticFlags, commonItem.m_decoration, WINDOW_FLAG_DECORATION);
ApplyFlag(item->window.staticFlags, commonItem.m_auto_wrapped, WINDOW_FLAG_AUTO_WRAPPED); ApplyFlag(item->window.staticFlags, commonItem.m_auto_wrapped, WINDOW_FLAG_AUTO_WRAPPED);
@@ -1019,8 +1136,8 @@ namespace
item->dataType = item->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(), &commonParentMenu, &commonItem);
item->disabledExp = ConvertExpression(commonItem.m_disabled_expression.get(), &parentMenu, &commonItem); item->disabledExp = ConvertExpression(commonItem.m_disabled_expression.get(), &commonParentMenu, &commonItem);
item->window.ownerDraw = commonItem.m_owner_draw; item->window.ownerDraw = commonItem.m_owner_draw;
item->window.ownerDrawFlags = commonItem.m_owner_draw_flags; item->window.ownerDrawFlags = commonItem.m_owner_draw_flags;
item->alignment = commonItem.m_align; item->alignment = commonItem.m_align;
@@ -1040,25 +1157,25 @@ namespace
ConvertColor(item->window.outlineColor, commonItem.m_outline_color); ConvertColor(item->window.outlineColor, commonItem.m_outline_color);
ConvertColor(item->window.disableColor, commonItem.m_disable_color); ConvertColor(item->window.disableColor, commonItem.m_disable_color);
ConvertColor(item->glowColor, commonItem.m_glow_color); ConvertColor(item->glowColor, commonItem.m_glow_color);
item->window.background = ConvertMaterial(commonItem.m_background, &parentMenu, &commonItem); item->window.background = ConvertMaterial(commonItem.m_background, &commonParentMenu, &commonItem);
item->onFocus = ConvertEventHandlerSet(commonItem.m_on_focus.get(), &parentMenu, &commonItem); item->onFocus = ConvertEventHandlerSet(commonItem.m_on_focus.get(), &commonParentMenu, &commonItem);
item->hasFocus = ConvertEventHandlerSet(commonItem.m_has_focus.get(), &parentMenu, &commonItem); item->hasFocus = ConvertEventHandlerSet(commonItem.m_has_focus.get(), &commonParentMenu, &commonItem);
item->leaveFocus = ConvertEventHandlerSet(commonItem.m_on_leave_focus.get(), &parentMenu, &commonItem); item->leaveFocus = ConvertEventHandlerSet(commonItem.m_on_leave_focus.get(), &commonParentMenu, &commonItem);
item->mouseEnter = ConvertEventHandlerSet(commonItem.m_on_mouse_enter.get(), &parentMenu, &commonItem); item->mouseEnter = ConvertEventHandlerSet(commonItem.m_on_mouse_enter.get(), &commonParentMenu, &commonItem);
item->mouseExit = ConvertEventHandlerSet(commonItem.m_on_mouse_exit.get(), &parentMenu, &commonItem); item->mouseExit = ConvertEventHandlerSet(commonItem.m_on_mouse_exit.get(), &commonParentMenu, &commonItem);
item->mouseEnterText = ConvertEventHandlerSet(commonItem.m_on_mouse_enter_text.get(), &parentMenu, &commonItem); item->mouseEnterText = ConvertEventHandlerSet(commonItem.m_on_mouse_enter_text.get(), &commonParentMenu, &commonItem);
item->mouseExitText = ConvertEventHandlerSet(commonItem.m_on_mouse_exit_text.get(), &parentMenu, &commonItem); item->mouseExitText = ConvertEventHandlerSet(commonItem.m_on_mouse_exit_text.get(), &commonParentMenu, &commonItem);
item->action = ConvertEventHandlerSet(commonItem.m_on_action.get(), &parentMenu, &commonItem); item->action = ConvertEventHandlerSet(commonItem.m_on_action.get(), &commonParentMenu, &commonItem);
item->accept = ConvertEventHandlerSet(commonItem.m_on_accept.get(), &parentMenu, &commonItem); item->accept = ConvertEventHandlerSet(commonItem.m_on_accept.get(), &commonParentMenu, &commonItem);
item->focusSound = ConvertSound(commonItem.m_focus_sound, &parentMenu, &commonItem); item->focusSound = ConvertSound(commonItem.m_focus_sound, &commonParentMenu, &commonItem);
item->dvarTest = ConvertString(commonItem.m_dvar_test); item->dvarTest = ConvertString(commonItem.m_dvar_test);
item->enableDvar = ConvertEnableDvar(commonItem, item->dvarFlags); item->enableDvar = ConvertEnableDvar(commonItem, item->dvarFlags);
item->onKey = ConvertKeyHandler(commonItem.m_key_handlers, &parentMenu, &commonItem); item->onKey = ConvertKeyHandler(commonItem.m_key_handlers, &commonParentMenu, &commonItem);
item->textExp = ConvertOrApplyStatement(item->text, commonItem.m_text_expression.get(), &parentMenu, &commonItem); item->textExp = ConvertOrApplyStatement(item->text, commonItem.m_text_expression.get(), &commonParentMenu, &commonItem);
item->textAlignYExp = ConvertOrApplyStatement(item->textaligny, commonItem.m_text_align_y_expression.get(), &parentMenu, &commonItem); item->textAlignYExp = ConvertOrApplyStatement(item->textaligny, commonItem.m_text_align_y_expression.get(), &commonParentMenu, &commonItem);
item->materialExp = ConvertOrApplyStatement(item->window.background, commonItem.m_material_expression.get(), &parentMenu, &commonItem); item->materialExp = ConvertOrApplyStatement(item->window.background, commonItem.m_material_expression.get(), &commonParentMenu, &commonItem);
item->disabledExp = ConvertExpression(commonItem.m_disabled_expression.get(), &parentMenu, &commonItem); item->disabledExp = ConvertExpression(commonItem.m_disabled_expression.get(), &commonParentMenu, &commonItem);
item->floatExpressions = ConvertFloatExpressions(&commonItem, item, &parentMenu, item->floatExpressionCount); item->floatExpressions = ConvertFloatExpressions(&commonItem, item, &commonParentMenu, item->floatExpressionCount);
item->gameMsgWindowIndex = commonItem.m_game_message_window_index; item->gameMsgWindowIndex = commonItem.m_game_message_window_index;
item->gameMsgWindowMode = commonItem.m_game_message_window_mode; item->gameMsgWindowMode = commonItem.m_game_message_window_mode;
item->fxLetterTime = commonItem.m_fx_letter_time; item->fxLetterTime = commonItem.m_fx_letter_time;
@@ -1069,15 +1186,15 @@ namespace
switch (commonItem.m_feature_type) switch (commonItem.m_feature_type)
{ {
case CommonItemFeatureType::LISTBOX: case CommonItemFeatureType::LISTBOX:
item->typeData.listBox = ConvertListBoxFeatures(item, commonItem.m_list_box_features.get(), parentMenu, commonItem); item->typeData.listBox = ConvertListBoxFeatures(item, commonItem.m_list_box_features.get(), commonParentMenu, commonItem);
break; break;
case CommonItemFeatureType::EDIT_FIELD: case CommonItemFeatureType::EDIT_FIELD:
item->typeData.editField = ConvertEditFieldFeatures(item, commonItem.m_edit_field_features.get(), parentMenu, commonItem); item->typeData.editField = ConvertEditFieldFeatures(item, commonItem.m_edit_field_features.get(), commonParentMenu, commonItem);
break; break;
case CommonItemFeatureType::MULTI_VALUE: case CommonItemFeatureType::MULTI_VALUE:
item->typeData.multi = ConvertMultiValueFeatures(item, commonItem.m_multi_value_features.get(), parentMenu, commonItem); item->typeData.multi = ConvertMultiValueFeatures(item, commonItem.m_multi_value_features.get(), commonParentMenu, commonItem);
break; break;
case CommonItemFeatureType::ENUM_DVAR: case CommonItemFeatureType::ENUM_DVAR:
@@ -1085,7 +1202,7 @@ namespace
break; break;
case CommonItemFeatureType::NEWS_TICKER: case CommonItemFeatureType::NEWS_TICKER:
item->typeData.ticker = ConvertNewsTickerFeatures(item, commonItem.m_news_ticker_features.get(), parentMenu, commonItem); item->typeData.ticker = ConvertNewsTickerFeatures(item, commonItem.m_news_ticker_features.get(), commonParentMenu, commonItem);
break; break;
case CommonItemFeatureType::NONE: case CommonItemFeatureType::NONE:
@@ -1096,10 +1213,13 @@ namespace
break; break;
} }
// Do this last so any optimizations are considered
item->window.rect = ConvertRectDefRelativeTo(item->window.rectClient, parentMenu.window.rect);
return item; return item;
} }
itemDef_s** ConvertMenuItems(const CommonMenuDef& commonMenu, int& itemCount) const itemDef_s** ConvertMenuItems(const CommonMenuDef& commonMenu, const menuDef_t& menu, int& itemCount) const
{ {
if (commonMenu.m_items.empty()) if (commonMenu.m_items.empty())
{ {
@@ -1109,7 +1229,7 @@ namespace
auto* items = m_memory.Alloc<itemDef_s*>(commonMenu.m_items.size()); auto* items = m_memory.Alloc<itemDef_s*>(commonMenu.m_items.size());
for (auto i = 0u; i < commonMenu.m_items.size(); i++) for (auto i = 0u; i < commonMenu.m_items.size(); i++)
items[i] = ConvertItem(commonMenu, *commonMenu.m_items[i]); items[i] = ConvertItem(commonMenu, menu, *commonMenu.m_items[i]);
itemCount = static_cast<int>(commonMenu.m_items.size()); itemCount = static_cast<int>(commonMenu.m_items.size());
@@ -1173,7 +1293,7 @@ namespace
menuData->onESC = ConvertEventHandlerSet(commonMenu.m_on_esc.get(), &commonMenu); menuData->onESC = ConvertEventHandlerSet(commonMenu.m_on_esc.get(), &commonMenu);
menuData->onFocusDueToClose = ConvertEventHandlerSet(commonMenu.m_on_focus_due_to_close.get(), &commonMenu); menuData->onFocusDueToClose = ConvertEventHandlerSet(commonMenu.m_on_focus_due_to_close.get(), &commonMenu);
menuData->onKey = ConvertKeyHandler(commonMenu.m_key_handlers, &commonMenu); menuData->onKey = ConvertKeyHandler(commonMenu.m_key_handlers, &commonMenu);
menu.items = ConvertMenuItems(commonMenu, menu.itemCount); menu.items = ConvertMenuItems(commonMenu, menu, menu.itemCount);
menuData->expressionData = m_conversion_zone_state.m_supporting_data; menuData->expressionData = m_conversion_zone_state.m_supporting_data;
} }
catch (const MenuConversionException& e) catch (const MenuConversionException& e)
@@ -378,4 +378,128 @@ namespace test::game::iw4::menu::parsing::it
REQUIRE(item->action->eventHandlers[1]->eventData.unconditionalScript != nullptr); REQUIRE(item->action->eventHandlers[1]->eventData.unconditionalScript != nullptr);
REQUIRE(item->action->eventHandlers[1]->eventData.unconditionalScript == R"("play" "lol" ; )"s); REQUIRE(item->action->eventHandlers[1]->eventData.unconditionalScript == R"("play" "lol" ; )"s);
} }
TEST_CASE("MenuParsingIW4IT: Optimized exp rect considers parent pos", "[parsing][converting][menu][it]")
{
MenuParsingItHelper helper;
helper.AddFile(R"testmenu(
{
menuDef
{
name "Blab"
rect 10 10 70 70;
itemDef
{
rect 20 20 40 40;
}
itemDef
{
rect 0 0 0 0;
exp rect x 20;
exp rect y 20;
exp rect w 40;
exp rect h 40;
}
}
})testmenu");
const auto result = helper.RunIntegrationTest();
REQUIRE(result.HasBeenSuccessful());
const auto* menuList = static_cast<MenuList*>(result.GetAssetInfo()->m_ptr);
const auto* menu = helper.GetMenuAsset("Blab");
REQUIRE(menuList->menuCount == 1);
REQUIRE(menuList->menus);
REQUIRE(menuList->menus[0] == menu);
REQUIRE(menu->window.name == "Blab"s);
CHECK_THAT(menu->window.rect.x, WithinRel(10.0f));
CHECK_THAT(menu->window.rect.y, WithinRel(10.0f));
CHECK_THAT(menu->window.rect.w, WithinRel(70.0f));
CHECK_THAT(menu->window.rect.h, WithinRel(70.0f));
REQUIRE(menu->itemCount == 2);
REQUIRE(menu->items != nullptr);
const auto* item0 = menu->items[0];
REQUIRE(item0 != nullptr);
CHECK_THAT(item0->window.rectClient.x, WithinRel(20.0f));
CHECK_THAT(item0->window.rectClient.y, WithinRel(20.0f));
CHECK_THAT(item0->window.rectClient.w, WithinRel(40.0f));
CHECK_THAT(item0->window.rectClient.h, WithinRel(40.0f));
CHECK_THAT(item0->window.rect.x, WithinRel(30.0f));
CHECK_THAT(item0->window.rect.y, WithinRel(30.0f));
CHECK_THAT(item0->window.rect.w, WithinRel(40.0f));
CHECK_THAT(item0->window.rect.h, WithinRel(40.0f));
const auto* item1 = menu->items[1];
REQUIRE(item1 != nullptr);
CHECK_THAT(item1->window.rectClient.x, WithinRel(20.0f));
CHECK_THAT(item1->window.rectClient.y, WithinRel(20.0f));
CHECK_THAT(item1->window.rectClient.w, WithinRel(40.0f));
CHECK_THAT(item1->window.rectClient.h, WithinRel(40.0f));
CHECK_THAT(item1->window.rect.x, WithinRel(30.0f));
CHECK_THAT(item1->window.rect.y, WithinRel(30.0f));
CHECK_THAT(item1->window.rect.w, WithinRel(40.0f));
CHECK_THAT(item1->window.rect.h, WithinRel(40.0f));
}
TEST_CASE("MenuParsingIW4IT: Optimized exp rect considers parent optimized pos", "[parsing][converting][menu][it]")
{
MenuParsingItHelper helper;
helper.AddFile(R"testmenu(
{
menuDef
{
name "Blab"
rect 0 0 1 1;
exp rect x 10;
exp rect y 10;
exp rect w 70;
exp rect h 70;
itemDef
{
rect 0 0 0 0;
exp rect x 20;
exp rect y 20;
exp rect w 40;
exp rect h 40;
}
}
})testmenu");
const auto result = helper.RunIntegrationTest();
REQUIRE(result.HasBeenSuccessful());
const auto* menuList = static_cast<MenuList*>(result.GetAssetInfo()->m_ptr);
const auto* menu = helper.GetMenuAsset("Blab");
REQUIRE(menuList->menuCount == 1);
REQUIRE(menuList->menus);
REQUIRE(menuList->menus[0] == menu);
REQUIRE(menu->window.name == "Blab"s);
CHECK_THAT(menu->window.rect.x, WithinRel(10.0f));
CHECK_THAT(menu->window.rect.y, WithinRel(10.0f));
CHECK_THAT(menu->window.rect.w, WithinRel(70.0f));
CHECK_THAT(menu->window.rect.h, WithinRel(70.0f));
REQUIRE(menu->itemCount == 1);
REQUIRE(menu->items != nullptr);
const auto* item0 = menu->items[0];
REQUIRE(item0 != nullptr);
CHECK_THAT(item0->window.rectClient.x, WithinRel(20.0f));
CHECK_THAT(item0->window.rectClient.y, WithinRel(20.0f));
CHECK_THAT(item0->window.rectClient.w, WithinRel(40.0f));
CHECK_THAT(item0->window.rectClient.h, WithinRel(40.0f));
CHECK_THAT(item0->window.rect.x, WithinRel(30.0f));
CHECK_THAT(item0->window.rect.y, WithinRel(30.0f));
CHECK_THAT(item0->window.rect.w, WithinRel(40.0f));
CHECK_THAT(item0->window.rect.h, WithinRel(40.0f));
}
} // namespace test::game::iw4::menu::parsing::it } // namespace test::game::iw4::menu::parsing::it