From 1015176ae1e7beaf3fa1377b38f94398f106a464 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Sun, 28 May 2023 12:43:41 +0200 Subject: [PATCH 1/7] Fix inconsistent width/height calculation for generic popups Sometimes the calculated popup width and height do not perfectly match the width and height when the text is rendered, so a small nudge value is added to prevent cases where this was noticeable. --- src/game/client/ui.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/game/client/ui.cpp b/src/game/client/ui.cpp index 2b2d0c4ca..b2820d8e6 100644 --- a/src/game/client/ui.cpp +++ b/src/game/client/ui.cpp @@ -1281,7 +1281,7 @@ CUI::EPopupMenuFunctionResult CUI::PopupMessage(void *pContext, CUIRect View, bo void CUI::ShowPopupMessage(float X, float Y, SMessagePopupContext *pContext) { - const float TextWidth = minimum(std::ceil(TextRender()->TextWidth(SMessagePopupContext::POPUP_FONT_SIZE, pContext->m_aMessage, -1, -1.0f)), SMessagePopupContext::POPUP_MAX_WIDTH); + const float TextWidth = minimum(std::ceil(TextRender()->TextWidth(SMessagePopupContext::POPUP_FONT_SIZE, pContext->m_aMessage, -1, -1.0f) + 0.5f), SMessagePopupContext::POPUP_MAX_WIDTH); float TextHeight = 0.0f; STextSizeProperties TextSizeProps{}; TextSizeProps.m_pHeight = &TextHeight; @@ -1308,7 +1308,7 @@ void CUI::SConfirmPopupContext::YesNoButtons() void CUI::ShowPopupConfirm(float X, float Y, SConfirmPopupContext *pContext) { - const float TextWidth = minimum(std::ceil(TextRender()->TextWidth(SConfirmPopupContext::POPUP_FONT_SIZE, pContext->m_aMessage, -1, -1.0f)), SConfirmPopupContext::POPUP_MAX_WIDTH); + const float TextWidth = minimum(std::ceil(TextRender()->TextWidth(SConfirmPopupContext::POPUP_FONT_SIZE, pContext->m_aMessage, -1, -1.0f) + 0.5f), SConfirmPopupContext::POPUP_MAX_WIDTH); float TextHeight = 0.0f; STextSizeProperties TextSizeProps{}; TextSizeProps.m_pHeight = &TextHeight; From b01e8b7bc57bf93110c187c08634932e3d08430e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Sun, 28 May 2023 11:52:31 +0200 Subject: [PATCH 2/7] Extract `CMenus::RenderDemoPlayerSliceSavePopup` function --- src/game/client/components/menus.h | 1 + src/game/client/components/menus_demo.cpp | 181 +++++++++++----------- 2 files changed, 93 insertions(+), 89 deletions(-) diff --git a/src/game/client/components/menus.h b/src/game/client/components/menus.h index ff964a426..3abf8289d 100644 --- a/src/game/client/components/menus.h +++ b/src/game/client/components/menus.h @@ -443,6 +443,7 @@ protected: void FetchAllHeaders(); void HandleDemoSeeking(float PositionToSeek, float TimeToSeek); void RenderDemoPlayer(CUIRect MainView); + void RenderDemoPlayerSliceSavePopup(CUIRect MainView); void RenderDemoList(CUIRect MainView); void PopupConfirmDeleteDemo(); diff --git a/src/game/client/components/menus_demo.cpp b/src/game/client/components/menus_demo.cpp index c866f22a4..223e5aec2 100644 --- a/src/game/client/components/menus_demo.cpp +++ b/src/game/client/components/menus_demo.cpp @@ -122,95 +122,7 @@ void CMenus::RenderDemoPlayer(CUIRect MainView) // render popups if(m_DemoPlayerState == DEMOPLAYER_SLICE_SAVE) { - CUIRect Screen = *UI()->Screen(); - CUIRect Box, Part, Part2; - Box = Screen; - Box.Margin(150.0f, &Box); - - // render the box - Box.Draw(ColorRGBA(0, 0, 0, 0.5f), IGraphics::CORNER_ALL, 15.0f); - - Box.HSplitTop(20.f, 0, &Box); - Box.HSplitTop(24.f, &Part, &Box); - UI()->DoLabel(&Part, Localize("Select a name"), 24.f, TEXTALIGN_MC); - Box.HSplitTop(20.f, 0, &Box); - Box.HSplitTop(20.f, &Part, &Box); - Part.VMargin(20.f, &Part); - UI()->DoLabel(&Part, m_aDemoPlayerPopupHint, 20.f, TEXTALIGN_MC); - Box.HSplitTop(20.f, 0, &Box); - - CUIRect Label, TextBox, Ok, Abort; - - Box.HSplitBottom(20.f, &Box, 0); - Box.HSplitBottom(24.f, &Box, &Part); - Part.VMargin(80.0f, &Part); - - Part.VSplitMid(&Abort, &Ok); - - Ok.VMargin(20.0f, &Ok); - Abort.VMargin(20.0f, &Abort); - - static int s_RemoveChat = 0; - - static CButtonContainer s_ButtonAbort; - if(DoButton_Menu(&s_ButtonAbort, Localize("Abort"), 0, &Abort) || UI()->ConsumeHotkey(CUI::HOTKEY_ESCAPE)) - m_DemoPlayerState = DEMOPLAYER_NONE; - - static CButtonContainer s_ButtonOk; - if(DoButton_Menu(&s_ButtonOk, Localize("Ok"), 0, &Ok) || UI()->ConsumeHotkey(CUI::HOTKEY_ENTER)) - { - char aDemoName[IO_MAX_PATH_LENGTH]; - DemoPlayer()->GetDemoName(aDemoName, sizeof(aDemoName)); - str_append(aDemoName, ".demo", sizeof(aDemoName)); - - if(!str_endswith(m_DemoSliceInput.GetString(), ".demo")) - m_DemoSliceInput.Append(".demo"); - - if(str_comp(aDemoName, m_DemoSliceInput.GetString()) == 0) - str_copy(m_aDemoPlayerPopupHint, Localize("Please use a different name")); - else - { - char aPath[IO_MAX_PATH_LENGTH]; - str_format(aPath, sizeof(aPath), "%s/%s", m_aCurrentDemoFolder, m_DemoSliceInput.GetString()); - - IOHANDLE DemoFile = Storage()->OpenFile(aPath, IOFLAG_READ, IStorage::TYPE_SAVE); - const char *pStr = Localize("File already exists, do you want to overwrite it?"); - if(DemoFile && str_comp(m_aDemoPlayerPopupHint, pStr) != 0) - { - io_close(DemoFile); - str_copy(m_aDemoPlayerPopupHint, pStr); - } - else - { - if(DemoFile) - io_close(DemoFile); - m_DemoPlayerState = DEMOPLAYER_NONE; - Client()->DemoSlice(aPath, CMenus::DemoFilterChat, &s_RemoveChat); - DemolistPopulate(); - DemolistOnUpdate(false); - } - } - } - - Box.HSplitTop(24.f, &Part, &Box); - Box.HSplitTop(10.f, 0, &Box); - Box.HSplitTop(24.f, &Part2, &Box); - - Part2.VSplitLeft(60.0f, 0, &Label); - if(DoButton_CheckBox(&s_RemoveChat, Localize("Remove chat"), s_RemoveChat, &Label)) - { - s_RemoveChat ^= 1; - } - - Part.VSplitLeft(60.0f, 0, &Label); - Label.VSplitLeft(120.0f, 0, &TextBox); - TextBox.VSplitLeft(20.0f, 0, &TextBox); - TextBox.VSplitRight(60.0f, &TextBox, 0); - UI()->DoLabel(&Label, Localize("New name:"), 18.0f, TEXTALIGN_ML); - if(UI()->DoEditBox(&m_DemoSliceInput, &TextBox, 12.0f)) - { - m_aDemoPlayerPopupHint[0] = '\0'; - } + RenderDemoPlayerSliceSavePopup(MainView); } // handle keyboard shortcuts independent of active menu @@ -648,6 +560,97 @@ void CMenus::RenderDemoPlayer(CUIRect MainView) HandleDemoSeeking(PositionToSeek, TimeToSeek); } +void CMenus::RenderDemoPlayerSliceSavePopup(CUIRect MainView) +{ + CUIRect Box, Part, Part2; + MainView.Margin(150.0f, &Box); + + // render the box + Box.Draw(ColorRGBA(0, 0, 0, 0.5f), IGraphics::CORNER_ALL, 15.0f); + + Box.HSplitTop(20.f, 0, &Box); + Box.HSplitTop(24.f, &Part, &Box); + UI()->DoLabel(&Part, Localize("Select a name"), 24.f, TEXTALIGN_MC); + Box.HSplitTop(20.f, 0, &Box); + Box.HSplitTop(20.f, &Part, &Box); + Part.VMargin(20.f, &Part); + UI()->DoLabel(&Part, m_aDemoPlayerPopupHint, 20.f, TEXTALIGN_MC); + Box.HSplitTop(20.f, 0, &Box); + + CUIRect Label, TextBox, Ok, Abort; + + Box.HSplitBottom(20.f, &Box, 0); + Box.HSplitBottom(24.f, &Box, &Part); + Part.VMargin(80.0f, &Part); + + Part.VSplitMid(&Abort, &Ok); + + Ok.VMargin(20.0f, &Ok); + Abort.VMargin(20.0f, &Abort); + + static int s_RemoveChat = 0; + + static CButtonContainer s_ButtonAbort; + if(DoButton_Menu(&s_ButtonAbort, Localize("Abort"), 0, &Abort) || UI()->ConsumeHotkey(CUI::HOTKEY_ESCAPE)) + m_DemoPlayerState = DEMOPLAYER_NONE; + + static CButtonContainer s_ButtonOk; + if(DoButton_Menu(&s_ButtonOk, Localize("Ok"), 0, &Ok) || UI()->ConsumeHotkey(CUI::HOTKEY_ENTER)) + { + char aDemoName[IO_MAX_PATH_LENGTH]; + DemoPlayer()->GetDemoName(aDemoName, sizeof(aDemoName)); + str_append(aDemoName, ".demo", sizeof(aDemoName)); + + if(!str_endswith(m_DemoSliceInput.GetString(), ".demo")) + m_DemoSliceInput.Append(".demo"); + + if(str_comp(aDemoName, m_DemoSliceInput.GetString()) == 0) + str_copy(m_aDemoPlayerPopupHint, Localize("Please use a different name")); + else + { + char aPath[IO_MAX_PATH_LENGTH]; + str_format(aPath, sizeof(aPath), "%s/%s", m_aCurrentDemoFolder, m_DemoSliceInput.GetString()); + + IOHANDLE DemoFile = Storage()->OpenFile(aPath, IOFLAG_READ, IStorage::TYPE_SAVE); + const char *pStr = Localize("File already exists, do you want to overwrite it?"); + if(DemoFile && str_comp(m_aDemoPlayerPopupHint, pStr) != 0) + { + io_close(DemoFile); + str_copy(m_aDemoPlayerPopupHint, pStr); + } + else + { + if(DemoFile) + io_close(DemoFile); + m_DemoPlayerState = DEMOPLAYER_NONE; + Client()->DemoSlice(aPath, CMenus::DemoFilterChat, &s_RemoveChat); + DemolistPopulate(); + DemolistOnUpdate(false); + } + } + } + + Box.HSplitTop(24.f, &Part, &Box); + Box.HSplitTop(10.f, 0, &Box); + Box.HSplitTop(24.f, &Part2, &Box); + + Part2.VSplitLeft(60.0f, 0, &Label); + if(DoButton_CheckBox(&s_RemoveChat, Localize("Remove chat"), s_RemoveChat, &Label)) + { + s_RemoveChat ^= 1; + } + + Part.VSplitLeft(60.0f, 0, &Label); + Label.VSplitLeft(120.0f, 0, &TextBox); + TextBox.VSplitLeft(20.0f, 0, &TextBox); + TextBox.VSplitRight(60.0f, &TextBox, 0); + UI()->DoLabel(&Label, Localize("New name:"), 18.0f, TEXTALIGN_ML); + if(UI()->DoEditBox(&m_DemoSliceInput, &TextBox, 12.0f)) + { + m_aDemoPlayerPopupHint[0] = '\0'; + } +} + int CMenus::DemolistFetchCallback(const CFsFileInfo *pInfo, int IsDir, int StorageType, void *pUser) { CMenus *pSelf = (CMenus *)pUser; From 20ce93076596d04340e364044bc82342ab93c143 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Sun, 28 May 2023 11:57:08 +0200 Subject: [PATCH 3/7] Move variable declarations closer to usages --- src/game/client/components/menus_demo.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/game/client/components/menus_demo.cpp b/src/game/client/components/menus_demo.cpp index 223e5aec2..2ddf80549 100644 --- a/src/game/client/components/menus_demo.cpp +++ b/src/game/client/components/menus_demo.cpp @@ -111,20 +111,15 @@ void CMenus::DemoSeekTick(IDemoPlayer::ETickOffset TickOffset) void CMenus::RenderDemoPlayer(CUIRect MainView) { - const IDemoPlayer::CInfo *pInfo = DemoPlayer()->BaseInfo(); - - const float SeekBarHeight = 15.0f; - const float ButtonbarHeight = 20.0f; - const float NameBarHeight = 20.0f; - const float Margins = 5.0f; - static int64_t s_LastSpeedChange = 0; - // render popups if(m_DemoPlayerState == DEMOPLAYER_SLICE_SAVE) { RenderDemoPlayerSliceSavePopup(MainView); } + const IDemoPlayer::CInfo *pInfo = DemoPlayer()->BaseInfo(); + static int64_t s_LastSpeedChange = 0; + // handle keyboard shortcuts independent of active menu float PositionToSeek = -1.0f; float TimeToSeek = 0.0f; @@ -206,7 +201,11 @@ void CMenus::RenderDemoPlayer(CUIRect MainView) } } - float TotalHeight = SeekBarHeight + ButtonbarHeight + NameBarHeight + Margins * 3; + const float SeekBarHeight = 15.0f; + const float ButtonbarHeight = 20.0f; + const float NameBarHeight = 20.0f; + const float Margins = 5.0f; + const float TotalHeight = SeekBarHeight + ButtonbarHeight + NameBarHeight + Margins * 3; // render speed info if(g_Config.m_ClDemoShowSpeed && time_get() - s_LastSpeedChange < time_freq() * 1) From be8a601e9e3cb0fbccb2fd51a80d90c740155eee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Sun, 28 May 2023 12:49:03 +0200 Subject: [PATCH 4/7] Render demo popups above/after other demo controls Prevent using other demo controls while a demo popup is open. --- src/game/client/components/menus_demo.cpp | 39 ++++++++++++----------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/src/game/client/components/menus_demo.cpp b/src/game/client/components/menus_demo.cpp index 2ddf80549..c33c20b1b 100644 --- a/src/game/client/components/menus_demo.cpp +++ b/src/game/client/components/menus_demo.cpp @@ -111,12 +111,6 @@ void CMenus::DemoSeekTick(IDemoPlayer::ETickOffset TickOffset) void CMenus::RenderDemoPlayer(CUIRect MainView) { - // render popups - if(m_DemoPlayerState == DEMOPLAYER_SLICE_SAVE) - { - RenderDemoPlayerSliceSavePopup(MainView); - } - const IDemoPlayer::CInfo *pInfo = DemoPlayer()->BaseInfo(); static int64_t s_LastSpeedChange = 0; @@ -232,20 +226,18 @@ void CMenus::RenderDemoPlayer(CUIRect MainView) return; } - MainView.HSplitBottom(TotalHeight, 0, &MainView); - MainView.VSplitLeft(50.0f, 0, &MainView); - MainView.VSplitLeft(600.0f, &MainView, 0); - - MainView.Draw(ms_ColorTabbarActive, IGraphics::CORNER_T, 10.0f); - - MainView.Margin(5.0f, &MainView); + CUIRect DemoControls; + MainView.HSplitBottom(TotalHeight, nullptr, &DemoControls); + DemoControls.VSplitLeft(50.0f, nullptr, &DemoControls); + DemoControls.VSplitLeft(600.0f, &DemoControls, nullptr); + DemoControls.Draw(ms_ColorTabbarActive, IGraphics::CORNER_T, 10.0f); CUIRect SeekBar, ButtonBar, NameBar, SpeedBar; - - MainView.HSplitTop(SeekBarHeight, &SeekBar, &ButtonBar); - ButtonBar.HSplitTop(Margins, 0, &ButtonBar); + DemoControls.Margin(5.0f, &DemoControls); + DemoControls.HSplitTop(SeekBarHeight, &SeekBar, &ButtonBar); + ButtonBar.HSplitTop(Margins, nullptr, &ButtonBar); ButtonBar.HSplitBottom(NameBarHeight, &ButtonBar, &NameBar); - NameBar.HSplitTop(4.0f, 0, &NameBar); + NameBar.HSplitTop(4.0f, nullptr, &NameBar); // do seekbar { @@ -542,7 +534,7 @@ void CMenus::RenderDemoPlayer(CUIRect MainView) str_format(aBuf, sizeof(aBuf), Localize("Demofile: %s"), aDemoName); CTextCursor Cursor; TextRender()->SetCursor(&Cursor, NameBar.x, NameBar.y + (NameBar.h - (Button.h * 0.5f)) / 2.f, Button.h * 0.5f, TEXTFLAG_RENDER | TEXTFLAG_STOP_AT_END); - Cursor.m_LineWidth = MainView.w; + Cursor.m_LineWidth = DemoControls.w; TextRender()->TextEx(&Cursor, aBuf, -1); if(IncreaseDemoSpeed) @@ -557,6 +549,17 @@ void CMenus::RenderDemoPlayer(CUIRect MainView) } HandleDemoSeeking(PositionToSeek, TimeToSeek); + + // render popups + if(m_DemoPlayerState != DEMOPLAYER_NONE) + { + // prevent element under the active popup from being activated + UI()->SetHotItem(nullptr); + } + if(m_DemoPlayerState == DEMOPLAYER_SLICE_SAVE) + { + RenderDemoPlayerSliceSavePopup(MainView); + } } void CMenus::RenderDemoPlayerSliceSavePopup(CUIRect MainView) From 6ff418322b5720e06605535a1ea25cb056139f85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Sun, 28 May 2023 12:50:21 +0200 Subject: [PATCH 5/7] Support rendering generic popup menus in demo player Due to different code paths for the demo player, the `RenderPopupMenus` funtion needs to be called separately. --- src/game/client/components/menus_demo.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/game/client/components/menus_demo.cpp b/src/game/client/components/menus_demo.cpp index c33c20b1b..5d9532f08 100644 --- a/src/game/client/components/menus_demo.cpp +++ b/src/game/client/components/menus_demo.cpp @@ -560,6 +560,8 @@ void CMenus::RenderDemoPlayer(CUIRect MainView) { RenderDemoPlayerSliceSavePopup(MainView); } + + UI()->RenderPopupMenus(); } void CMenus::RenderDemoPlayerSliceSavePopup(CUIRect MainView) From 16678618571584778bd88ff21b8a5254ba8a9ff7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Sun, 28 May 2023 12:51:56 +0200 Subject: [PATCH 6/7] Use `nullptr` instead of `0` --- src/game/client/components/menus_demo.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/game/client/components/menus_demo.cpp b/src/game/client/components/menus_demo.cpp index 5d9532f08..15038b7e2 100644 --- a/src/game/client/components/menus_demo.cpp +++ b/src/game/client/components/menus_demo.cpp @@ -386,7 +386,7 @@ void CMenus::RenderDemoPlayer(CUIRect MainView) GameClient()->m_Tooltips.DoToolTip(&s_PlayPauseButton, &Button, pInfo->m_Paused ? Localize("Play the current demo") : Localize("Pause the current demo")); // stop button - ButtonBar.VSplitLeft(Margins, 0, &ButtonBar); + ButtonBar.VSplitLeft(Margins, nullptr, &ButtonBar); ButtonBar.VSplitLeft(ButtonbarHeight, &Button, &ButtonBar); static CButtonContainer s_ResetButton; if(DoButton_FontIcon(&s_ResetButton, FONT_ICON_STOP, false, &Button, IGraphics::CORNER_ALL)) @@ -397,7 +397,7 @@ void CMenus::RenderDemoPlayer(CUIRect MainView) GameClient()->m_Tooltips.DoToolTip(&s_ResetButton, &Button, Localize("Stop the current demo")); // one tick back - ButtonBar.VSplitLeft(Margins + 10.0f, 0, &ButtonBar); + ButtonBar.VSplitLeft(Margins + 10.0f, nullptr, &ButtonBar); ButtonBar.VSplitLeft(ButtonbarHeight, &Button, &ButtonBar); static CButtonContainer s_OneTickBackButton; if(DoButton_FontIcon(&s_OneTickBackButton, FONT_ICON_CHEVRON_LEFT, 0, &Button, IGraphics::CORNER_ALL)) @@ -405,7 +405,7 @@ void CMenus::RenderDemoPlayer(CUIRect MainView) GameClient()->m_Tooltips.DoToolTip(&s_OneTickBackButton, &Button, Localize("Go back one tick")); // one tick forward - ButtonBar.VSplitLeft(Margins, 0, &ButtonBar); + ButtonBar.VSplitLeft(Margins, nullptr, &ButtonBar); ButtonBar.VSplitLeft(ButtonbarHeight, &Button, &ButtonBar); static CButtonContainer s_OneTickForwardButton; if(DoButton_FontIcon(&s_OneTickForwardButton, FONT_ICON_CHEVRON_RIGHT, 0, &Button, IGraphics::CORNER_ALL)) @@ -446,7 +446,7 @@ void CMenus::RenderDemoPlayer(CUIRect MainView) GameClient()->m_Tooltips.DoToolTip(&s_SliceBeginButton, &Button, Localize("Mark the beginning of a cut")); // slice end button - ButtonBar.VSplitLeft(Margins, 0, &ButtonBar); + ButtonBar.VSplitLeft(Margins, nullptr, &ButtonBar); ButtonBar.VSplitLeft(ButtonbarHeight, &Button, &ButtonBar); static CButtonContainer s_SliceEndButton; if(DoButton_FontIcon(&s_SliceEndButton, FONT_ICON_RIGHT_TO_BRACKET, 0, &Button, IGraphics::CORNER_ALL)) @@ -458,7 +458,7 @@ void CMenus::RenderDemoPlayer(CUIRect MainView) GameClient()->m_Tooltips.DoToolTip(&s_SliceEndButton, &Button, Localize("Mark the end of a cut")); // slice save button - ButtonBar.VSplitLeft(Margins, 0, &ButtonBar); + ButtonBar.VSplitLeft(Margins, nullptr, &ButtonBar); ButtonBar.VSplitLeft(ButtonbarHeight, &Button, &ButtonBar); static CButtonContainer s_SliceSaveButton; if(DoButton_FontIcon(&s_SliceSaveButton, FONT_ICON_ARROW_UP_RIGHT_FROM_SQUARE, 0, &Button, IGraphics::CORNER_ALL)) @@ -477,7 +477,7 @@ void CMenus::RenderDemoPlayer(CUIRect MainView) const int Threshold = 10; // one marker back - ButtonBar.VSplitLeft(Margins + 20.0f, 0, &ButtonBar); + ButtonBar.VSplitLeft(Margins + 20.0f, nullptr, &ButtonBar); ButtonBar.VSplitLeft(ButtonbarHeight, &Button, &ButtonBar); static CButtonContainer s_OneMarkerBackButton; if(DoButton_FontIcon(&s_OneMarkerBackButton, FONT_ICON_BACKWARD_STEP, 0, &Button, IGraphics::CORNER_ALL)) @@ -493,7 +493,7 @@ void CMenus::RenderDemoPlayer(CUIRect MainView) GameClient()->m_Tooltips.DoToolTip(&s_OneMarkerBackButton, &Button, Localize("Go back one marker")); // one marker forward - ButtonBar.VSplitLeft(Margins, 0, &ButtonBar); + ButtonBar.VSplitLeft(Margins, nullptr, &ButtonBar); ButtonBar.VSplitLeft(ButtonbarHeight, &Button, &ButtonBar); static CButtonContainer s_OneMarkerForwardButton; if(DoButton_FontIcon(&s_OneMarkerForwardButton, FONT_ICON_FORWARD_STEP, 0, &Button, IGraphics::CORNER_ALL)) @@ -518,7 +518,7 @@ void CMenus::RenderDemoPlayer(CUIRect MainView) } // toggle keyboard shortcuts button - ButtonBar.VSplitRight(Margins, &ButtonBar, 0); + ButtonBar.VSplitRight(Margins, &ButtonBar, nullptr); ButtonBar.VSplitRight(ButtonbarHeight, &ButtonBar, &Button); static CButtonContainer s_KeyboardShortcutsButton; if(DoButton_FontIcon(&s_KeyboardShortcutsButton, FONT_ICON_KEYBOARD, 0, &Button, IGraphics::CORNER_ALL, g_Config.m_ClDemoKeyboardShortcuts != 0)) From 6feb46183e196c9d18465f6059bad016b3d3fd55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Sun, 28 May 2023 12:53:00 +0200 Subject: [PATCH 7/7] Improve demo slice popup Show begin time, end time and length of demo cut in popup. Replace demo slice error/confirm messages with generic popups. Improve layout. Remove unnecessary empty space. --- src/game/client/components/menus.h | 1 - src/game/client/components/menus_demo.cpp | 127 +++++++++++++--------- 2 files changed, 74 insertions(+), 54 deletions(-) diff --git a/src/game/client/components/menus.h b/src/game/client/components/menus.h index 3abf8289d..f7d393243 100644 --- a/src/game/client/components/menus.h +++ b/src/game/client/components/menus.h @@ -647,7 +647,6 @@ public: std::chrono::nanoseconds m_PopupWarningDuration; int m_DemoPlayerState; - char m_aDemoPlayerPopupHint[256]; enum { diff --git a/src/game/client/components/menus_demo.cpp b/src/game/client/components/menus_demo.cpp index 15038b7e2..8054b1d42 100644 --- a/src/game/client/components/menus_demo.cpp +++ b/src/game/client/components/menus_demo.cpp @@ -468,7 +468,6 @@ void CMenus::RenderDemoPlayer(CUIRect MainView) m_DemoSliceInput.Set(aDemoName); m_DemoSliceInput.Append(".demo"); UI()->SetActiveItem(&m_DemoSliceInput); - m_aDemoPlayerPopupHint[0] = '\0'; m_DemoPlayerState = DEMOPLAYER_SLICE_SAVE; } GameClient()->m_Tooltips.DoToolTip(&s_SliceSaveButton, &Button, Localize("Export cut as a separate demo")); @@ -566,40 +565,71 @@ void CMenus::RenderDemoPlayer(CUIRect MainView) void CMenus::RenderDemoPlayerSliceSavePopup(CUIRect MainView) { - CUIRect Box, Part, Part2; + const IDemoPlayer::CInfo *pInfo = DemoPlayer()->BaseInfo(); + + CUIRect Box; MainView.Margin(150.0f, &Box); - // render the box - Box.Draw(ColorRGBA(0, 0, 0, 0.5f), IGraphics::CORNER_ALL, 15.0f); + // background + Box.Draw(ColorRGBA(0.0f, 0.0f, 0.0f, 0.5f), IGraphics::CORNER_ALL, 15.0f); + Box.Margin(24.0f, &Box); - Box.HSplitTop(20.f, 0, &Box); - Box.HSplitTop(24.f, &Part, &Box); - UI()->DoLabel(&Part, Localize("Select a name"), 24.f, TEXTALIGN_MC); - Box.HSplitTop(20.f, 0, &Box); - Box.HSplitTop(20.f, &Part, &Box); - Part.VMargin(20.f, &Part); - UI()->DoLabel(&Part, m_aDemoPlayerPopupHint, 20.f, TEXTALIGN_MC); - Box.HSplitTop(20.f, 0, &Box); + // title + CUIRect Title; + Box.HSplitTop(24.0f, &Title, &Box); + Box.HSplitTop(20.0f, nullptr, &Box); + UI()->DoLabel(&Title, Localize("Export demo cut"), 24.0f, TEXTALIGN_MC); - CUIRect Label, TextBox, Ok, Abort; + // slice times + CUIRect SliceTimesBar, SliceInterval, SliceLength; + Box.HSplitTop(24.0f, &SliceTimesBar, &Box); + SliceTimesBar.VSplitMid(&SliceInterval, &SliceLength, 40.0f); + Box.HSplitTop(20.0f, nullptr, &Box); + const int64_t RealSliceBegin = g_Config.m_ClDemoSliceBegin == -1 ? 0 : (g_Config.m_ClDemoSliceBegin - pInfo->m_FirstTick); + const int64_t RealSliceEnd = (g_Config.m_ClDemoSliceEnd == -1 ? pInfo->m_LastTick : g_Config.m_ClDemoSliceEnd) - pInfo->m_FirstTick; + char aSliceBegin[32]; + str_time(RealSliceBegin / SERVER_TICK_SPEED * 100, TIME_HOURS, aSliceBegin, sizeof(aSliceBegin)); + char aSliceEnd[32]; + str_time(RealSliceEnd / SERVER_TICK_SPEED * 100, TIME_HOURS, aSliceEnd, sizeof(aSliceEnd)); + char aSliceLength[32]; + str_time((RealSliceEnd - RealSliceBegin) / SERVER_TICK_SPEED * 100, TIME_HOURS, aSliceLength, sizeof(aSliceLength)); + char aBuf[256]; + str_format(aBuf, sizeof(aBuf), "%s: %s – %s", Localize("Cut interval"), aSliceBegin, aSliceEnd); + UI()->DoLabel(&SliceInterval, aBuf, 18.0f, TEXTALIGN_ML); + str_format(aBuf, sizeof(aBuf), "%s: %s", Localize("Cut length"), aSliceLength); + UI()->DoLabel(&SliceLength, aBuf, 18.0f, TEXTALIGN_ML); - Box.HSplitBottom(20.f, &Box, 0); - Box.HSplitBottom(24.f, &Box, &Part); - Part.VMargin(80.0f, &Part); - - Part.VSplitMid(&Abort, &Ok); - - Ok.VMargin(20.0f, &Ok); - Abort.VMargin(20.0f, &Abort); + // file name + CUIRect NameLabel, NameBox; + Box.HSplitTop(24.0f, &NameLabel, &Box); + Box.HSplitTop(20.0f, nullptr, &Box); + NameLabel.VSplitLeft(150.0f, &NameLabel, &NameBox); + NameBox.VSplitLeft(20.0f, nullptr, &NameBox); + UI()->DoLabel(&NameLabel, Localize("New name:"), 18.0f, TEXTALIGN_ML); + UI()->DoEditBox(&m_DemoSliceInput, &NameBox, 12.0f); + // remove chat checkbox static int s_RemoveChat = 0; + CUIRect RemoveChatCheckBox; + Box.HSplitTop(24.0f, &RemoveChatCheckBox, &Box); + Box.HSplitTop(20.0f, nullptr, &Box); + if(DoButton_CheckBox(&s_RemoveChat, Localize("Remove chat"), s_RemoveChat, &RemoveChatCheckBox)) + { + s_RemoveChat ^= 1; + } + + // buttons + CUIRect ButtonBar, AbortButton, OkButton; + Box.HSplitBottom(24.0f, &Box, &ButtonBar); + ButtonBar.VSplitMid(&AbortButton, &OkButton, 40.0f); static CButtonContainer s_ButtonAbort; - if(DoButton_Menu(&s_ButtonAbort, Localize("Abort"), 0, &Abort) || UI()->ConsumeHotkey(CUI::HOTKEY_ESCAPE)) + if(DoButton_Menu(&s_ButtonAbort, Localize("Abort"), 0, &AbortButton) || (!UI()->IsPopupOpen() && UI()->ConsumeHotkey(CUI::HOTKEY_ESCAPE))) m_DemoPlayerState = DEMOPLAYER_NONE; + static CUI::SConfirmPopupContext s_ConfirmPopupContext; static CButtonContainer s_ButtonOk; - if(DoButton_Menu(&s_ButtonOk, Localize("Ok"), 0, &Ok) || UI()->ConsumeHotkey(CUI::HOTKEY_ENTER)) + if(DoButton_Menu(&s_ButtonOk, Localize("Ok"), 0, &OkButton) || (!UI()->IsPopupOpen() && UI()->ConsumeHotkey(CUI::HOTKEY_ENTER))) { char aDemoName[IO_MAX_PATH_LENGTH]; DemoPlayer()->GetDemoName(aDemoName, sizeof(aDemoName)); @@ -609,49 +639,40 @@ void CMenus::RenderDemoPlayerSliceSavePopup(CUIRect MainView) m_DemoSliceInput.Append(".demo"); if(str_comp(aDemoName, m_DemoSliceInput.GetString()) == 0) - str_copy(m_aDemoPlayerPopupHint, Localize("Please use a different name")); + { + static CUI::SMessagePopupContext s_MessagePopupContext; + s_MessagePopupContext.ErrorColor(); + str_copy(s_MessagePopupContext.m_aMessage, Localize("Please use a different name")); + UI()->ShowPopupMessage(UI()->MouseX(), OkButton.y + OkButton.h + 5.0f, &s_MessagePopupContext); + } else { char aPath[IO_MAX_PATH_LENGTH]; str_format(aPath, sizeof(aPath), "%s/%s", m_aCurrentDemoFolder, m_DemoSliceInput.GetString()); - - IOHANDLE DemoFile = Storage()->OpenFile(aPath, IOFLAG_READ, IStorage::TYPE_SAVE); - const char *pStr = Localize("File already exists, do you want to overwrite it?"); - if(DemoFile && str_comp(m_aDemoPlayerPopupHint, pStr) != 0) + if(Storage()->FileExists(aPath, IStorage::TYPE_SAVE)) { - io_close(DemoFile); - str_copy(m_aDemoPlayerPopupHint, pStr); + s_ConfirmPopupContext.Reset(); + s_ConfirmPopupContext.YesNoButtons(); + str_copy(s_ConfirmPopupContext.m_aMessage, Localize("File already exists, do you want to overwrite it?")); + UI()->ShowPopupConfirm(UI()->MouseX(), OkButton.y + OkButton.h + 5.0f, &s_ConfirmPopupContext); } else - { - if(DemoFile) - io_close(DemoFile); - m_DemoPlayerState = DEMOPLAYER_NONE; - Client()->DemoSlice(aPath, CMenus::DemoFilterChat, &s_RemoveChat); - DemolistPopulate(); - DemolistOnUpdate(false); - } + s_ConfirmPopupContext.m_Result = CUI::SConfirmPopupContext::CONFIRMED; } } - Box.HSplitTop(24.f, &Part, &Box); - Box.HSplitTop(10.f, 0, &Box); - Box.HSplitTop(24.f, &Part2, &Box); - - Part2.VSplitLeft(60.0f, 0, &Label); - if(DoButton_CheckBox(&s_RemoveChat, Localize("Remove chat"), s_RemoveChat, &Label)) + if(s_ConfirmPopupContext.m_Result == CUI::SConfirmPopupContext::CONFIRMED) { - s_RemoveChat ^= 1; + char aPath[IO_MAX_PATH_LENGTH]; + str_format(aPath, sizeof(aPath), "%s/%s", m_aCurrentDemoFolder, m_DemoSliceInput.GetString()); + m_DemoPlayerState = DEMOPLAYER_NONE; + Client()->DemoSlice(aPath, CMenus::DemoFilterChat, &s_RemoveChat); + DemolistPopulate(); + DemolistOnUpdate(false); } - - Part.VSplitLeft(60.0f, 0, &Label); - Label.VSplitLeft(120.0f, 0, &TextBox); - TextBox.VSplitLeft(20.0f, 0, &TextBox); - TextBox.VSplitRight(60.0f, &TextBox, 0); - UI()->DoLabel(&Label, Localize("New name:"), 18.0f, TEXTALIGN_ML); - if(UI()->DoEditBox(&m_DemoSliceInput, &TextBox, 12.0f)) + if(s_ConfirmPopupContext.m_Result != CUI::SConfirmPopupContext::UNSET) { - m_aDemoPlayerPopupHint[0] = '\0'; + s_ConfirmPopupContext.Reset(); } }