diff --git a/Minecraft.Client/Assets/UI/SettingsUIMenu.rcss b/Minecraft.Client/Assets/UI/SettingsUIMenu.rcss new file mode 100644 index 00000000..557d73a3 --- /dev/null +++ b/Minecraft.Client/Assets/UI/SettingsUIMenu.rcss @@ -0,0 +1,162 @@ +body +{ + width: 100%; + height: 100%; + font-family: Minecraft Default; + font-size: 26dp; + font-effect: shadow(1dp 1dp #000000); + color: #333333; + background: transparent; + display: flex; + align-items: center; + justify-content: center; +} + +div#settings_ui_menu +{ + width: 449dp; + height: auto; + margin: auto; + margin-top: 320dp; + padding: 20dp 34dp; + decorator: image(images/lce/frame_MessageBox_background.png); + display: flex; + flex-direction: column; + align-items: center; +} + +p#title +{ + color: #333333; + font-size: 29dp; + font-weight: bold; + margin-bottom: 10dp; + text-align: center; + width: 100%; +} + +div#controls +{ + width: 100%; + display: flex; + flex-direction: column; + align-items: center; +} + +.toggle_row +{ + display: flex; + align-items: center; + width: 100%; + min-height: 30dp; + padding: 1dp 0; + margin-bottom: 3dp; +} + +.toggle_row button +{ + display: inline-block; + width: 30dp; + height: 30dp; + padding: 0; + border: none; + background: transparent; + cursor: pointer; +} + +.toggle_row .toggle_switch +{ + display: block; + width: 30dp; + height: 30dp; + decorator: image(images/lce/Tickbox_Background.png); + position: relative; +} + +.toggle_row button:hover .toggle_switch +{ + decorator: image(images/lce/Tickbox_Over.png); +} + +.tick_mark +{ + display: block; + width: 100%; + height: 100%; + decorator: image(images/lce/Tick.png); +} + +.toggle_row:not(.checked) .tick_mark +{ + display: none; +} + +.toggle_label +{ + display: inline-block; + font-size: 20dp; + color: #333333; + margin-left: 9dp; + line-height: 30dp; +} + +.slider_row +{ + display: flex; + flex-direction: column; + width: 100%; + margin-bottom: 6dp; + padding: 2dp 0; +} + +.slider_container +{ + width: 100%; + height: 30dp; + position: relative; + decorator: image(images/lce/Slider_Background.png); + border: 1dp transparent; +} + +.slider_container:hover +{ + border-color: #ffff00; +} + +.slider_label +{ + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + font-size: 20dp; + color: #ffffff; + text-align: center; + line-height: 30dp; +} + +.slider_container:hover .slider_label +{ + color: #ffff00; +} + +.slider_track +{ + position: absolute; + left: 8dp; + right: 8dp; + top: 0; + height: 100%; + cursor: resize; +} + +.slider_thumb +{ + position: absolute; + width: 12dp; + height: 30dp; + decorator: image(images/lce/Slider.png); + cursor: resize; + transform: translateX(-50%); +} diff --git a/Minecraft.Client/Assets/UI/SettingsUIMenu.rml b/Minecraft.Client/Assets/UI/SettingsUIMenu.rml new file mode 100644 index 00000000..f2db8b0c --- /dev/null +++ b/Minecraft.Client/Assets/UI/SettingsUIMenu.rml @@ -0,0 +1,57 @@ + + + UI Settings + + + +
+
+
+ + [IDS_CHECKBOX_DISPLAY_HUD] +
+
+ + [IDS_CHECKBOX_DISPLAY_HAND] +
+
+ + [IDS_CHECKBOX_DEATH_MESSAGES] +
+
+ + [IDS_CHECKBOX_ANIMATED_CHARACTER] +
+
+ + [IDS_CHECKBOX_VERTICAL_SPLIT_SCREEN] +
+
+ + [IDS_CHECKBOX_DISPLAY_SPLITSCREENGAMERTAGS] +
+
+ + [IDS_CHECKBOX_CLASSICCRAFTING] +
+ +
+
+
+
+ [IDS_SLIDER_UISIZE]: 2 +
+
+
+
+
+
+
+ [IDS_SLIDER_UISIZESPLITSCREEN]: 2 +
+
+
+
+
+ +
diff --git a/Minecraft.Client/CMakeLists.txt b/Minecraft.Client/CMakeLists.txt index b0819f3d..ed9932f0 100644 --- a/Minecraft.Client/CMakeLists.txt +++ b/Minecraft.Client/CMakeLists.txt @@ -76,6 +76,8 @@ if(PLATFORM_NAME STREQUAL "Windows64") # not to the whole target (avoids PCH macro conflicts with windows.h). set(RMLUI_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/Windows64/Libs/RmlUi/Include") set(_RMLUI_SOURCES + "${CMAKE_CURRENT_SOURCE_DIR}/Common/UI/UIScene_RmlBase.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/Common/UI/UIScene_RmlBase.h" "${CMAKE_CURRENT_SOURCE_DIR}/Common/UI/UIScene_HelpAndOptionsMenu.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/Common/UI/UIScene_HelpAndOptionsMenu.h" "${CMAKE_CURRENT_SOURCE_DIR}/Common/UI/UIScene_PauseMenu.cpp" @@ -86,6 +88,8 @@ if(PLATFORM_NAME STREQUAL "Windows64") "${CMAKE_CURRENT_SOURCE_DIR}/Common/UI/UIScene_SkinSelectMenu.h" "${CMAKE_CURRENT_SOURCE_DIR}/Common/UI/UIScene_LoadCreateJoinMenu.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/Common/UI/UIScene_LoadCreateJoinMenu.h" + "${CMAKE_CURRENT_SOURCE_DIR}/Common/UI/UIScene_MessageBox.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/Common/UI/UIScene_MessageBox.h" "${CMAKE_CURRENT_SOURCE_DIR}/Windows64/RmlUi_Renderer_D3D11.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/Windows64/RmlUi_Renderer_D3D11.h" "${CMAKE_CURRENT_SOURCE_DIR}/Windows64/RmlUi_SystemInterface_Win64.cpp" diff --git a/Minecraft.Client/Common/UI/UIScene_HelpAndOptionsMenu.cpp b/Minecraft.Client/Common/UI/UIScene_HelpAndOptionsMenu.cpp index e2f0f85a..da7a0e71 100644 --- a/Minecraft.Client/Common/UI/UIScene_HelpAndOptionsMenu.cpp +++ b/Minecraft.Client/Common/UI/UIScene_HelpAndOptionsMenu.cpp @@ -1,8 +1,6 @@ -// Non-RmlUi includes that depend on Windows macros #include "UI.h" #include "../../Minecraft.h" -// RmlUi includes (Windows macros temporarily suppressed) #pragma push_macro("byte") #pragma push_macro("GetNextSibling") #pragma push_macro("GetFirstChild") @@ -21,8 +19,7 @@ #pragma pop_macro("byte") UIScene_HelpAndOptionsMenu::UIScene_HelpAndOptionsMenu(int iPad, void *initData, UILayer *parentLayer) - : UIScene(iPad, parentLayer) - , m_document(nullptr) + : UIScene_RmlBase(iPad, parentLayer) { Rml::Context* ctx = RmlManager::Get().GetContext(); if (!ctx) @@ -32,43 +29,30 @@ UIScene_HelpAndOptionsMenu::UIScene_HelpAndOptionsMenu(int iPad, void *initData, } m_document = ctx->LoadDocument("HelpOptions.rml"); - if (m_document) - { - m_document->Show(); - - bool bNotInGame = (Minecraft::GetInstance()->level == nullptr); - - // Change Skin: hide if not full version - if (!ProfileManager.IsFullVersion()) - { - auto* el = m_document->GetElementById("change_skin"); - if (el) el->SetProperty("display", "none"); - } - - // Credits: hide in splitscreen - if (app.GetLocalPlayerCount() > 1) - { - auto* el = m_document->GetElementById("credits"); - if (el) el->SetProperty("display", "none"); - } - - // Register button click listeners - m_document->GetElementById("change_skin")->AddEventListener(Rml::EventId::Click, this); - m_document->GetElementById("how_to_play")->AddEventListener(Rml::EventId::Click, this); - m_document->GetElementById("controls")->AddEventListener(Rml::EventId::Click, this); - m_document->GetElementById("settings")->AddEventListener(Rml::EventId::Click, this); - m_document->GetElementById("credits")->AddEventListener(Rml::EventId::Click, this); - - // Focus first visible button - m_document->GetElementById("change_skin")->Focus(); - } - else + if (!m_document) { app.DebugPrintf("[RmlHelpAndOptions] Failed to load HelpOptions.rml\n"); + return; } - ui.HidePressStart(); + m_document->Show(); + if (!ProfileManager.IsFullVersion()) + { + auto* el = m_document->GetElementById("change_skin"); + if (el) el->SetProperty("display", "none"); + } + + if (app.GetLocalPlayerCount() > 1) + { + auto* el = m_document->GetElementById("credits"); + if (el) el->SetProperty("display", "none"); + } + + RegisterEvents({ "change_skin", "how_to_play", "controls", "settings", "credits" }); + m_document->GetElementById("change_skin")->Focus(); + + ui.HidePressStart(); TelemetryManager->RecordMenuShown(m_iPad, eUIScene_HelpAndOptionsMenu, 0); } @@ -76,76 +60,11 @@ UIScene_HelpAndOptionsMenu::~UIScene_HelpAndOptionsMenu() { if (m_document) { - m_document->GetElementById("change_skin")->RemoveEventListener(Rml::EventId::Click, this); - m_document->GetElementById("how_to_play")->RemoveEventListener(Rml::EventId::Click, this); - m_document->GetElementById("controls")->RemoveEventListener(Rml::EventId::Click, this); - m_document->GetElementById("settings")->RemoveEventListener(Rml::EventId::Click, this); - m_document->GetElementById("credits")->RemoveEventListener(Rml::EventId::Click, this); + UnregisterEvents({ "change_skin", "how_to_play", "controls", "settings", "credits" }); m_document->Close(); - m_document = nullptr; } } -void UIScene_HelpAndOptionsMenu::gainFocus() -{ - if (!bHasFocus && stealsFocus()) - { - bHasFocus = true; - updateTooltips(); - updateComponents(); - if (!m_bFocussedOnce) - { - } - handleGainFocus(m_bFocussedOnce); - if (bHasFocus) - m_bFocussedOnce = true; - if (m_document) - m_document->Show(); - } -} - -void UIScene_HelpAndOptionsMenu::handleLoseFocus() -{ - if (m_document) - m_document->Hide(); -} - -void UIScene_HelpAndOptionsMenu::reloadMovie(bool force) -{ -} - -void UIScene_HelpAndOptionsMenu::tick() -{ - m_hasTickedOnce = true; - - UIScene::tick(); - - Rml::Context* ctx = RmlManager::Get().GetContext(); - if (!ctx || !bHasFocus) - return; - - ctx->ProcessMouseMove(g_KBMInput.GetMouseX(), g_KBMInput.GetMouseY(), 0); - - if (g_KBMInput.IsMouseButtonPressed(KeyboardMouseInput::MOUSE_LEFT)) - ctx->ProcessMouseButtonDown(0, 0); - if (g_KBMInput.IsMouseButtonReleased(KeyboardMouseInput::MOUSE_LEFT)) - ctx->ProcessMouseButtonUp(0, 0); - if (g_KBMInput.IsMouseButtonPressed(KeyboardMouseInput::MOUSE_RIGHT)) - ctx->ProcessMouseButtonDown(1, 0); - if (g_KBMInput.IsMouseButtonReleased(KeyboardMouseInput::MOUSE_RIGHT)) - ctx->ProcessMouseButtonUp(1, 0); - - int wheelDelta = g_KBMInput.GetMouseWheel(); - if (wheelDelta != 0) - ctx->ProcessMouseWheel(wheelDelta / -120, 0); - - ctx->Update(); -} - -void UIScene_HelpAndOptionsMenu::render(S32 width, S32 height, C4JRender::eViewportType viewport) -{ -} - void UIScene_HelpAndOptionsMenu::handleInput(int iPad, int key, bool repeat, bool pressed, bool released, bool &handled) { Rml::Context* ctx = RmlManager::Get().GetContext(); @@ -196,10 +115,6 @@ void UIScene_HelpAndOptionsMenu::ProcessEvent(Rml::Event& event) } } -void UIScene_HelpAndOptionsMenu::updateTooltips() -{ -} - void UIScene_HelpAndOptionsMenu::updateComponents() { bool bNotInGame = (Minecraft::GetInstance()->level == nullptr); @@ -211,11 +126,7 @@ void UIScene_HelpAndOptionsMenu::updateComponents() else { m_parentLayer->showComponent(m_iPad, eUIComponent_Panorama, false); - - if (app.GetLocalPlayerCount() == 1) - m_parentLayer->showComponent(m_iPad, eUIComponent_Logo, true); - else - m_parentLayer->showComponent(m_iPad, eUIComponent_Logo, false); + m_parentLayer->showComponent(m_iPad, eUIComponent_Logo, app.GetLocalPlayerCount() == 1); } } @@ -254,5 +165,3 @@ void UIScene_HelpAndOptionsMenu::OnCredits() ui.PlayUISFX(eSFX_Press); ui.NavigateToScene(m_iPad, eUIScene_Credits); } - - diff --git a/Minecraft.Client/Common/UI/UIScene_HelpAndOptionsMenu.h b/Minecraft.Client/Common/UI/UIScene_HelpAndOptionsMenu.h index a8c720d4..ae012ad0 100644 --- a/Minecraft.Client/Common/UI/UIScene_HelpAndOptionsMenu.h +++ b/Minecraft.Client/Common/UI/UIScene_HelpAndOptionsMenu.h @@ -7,39 +7,21 @@ #undef GetNextSibling #undef GetFirstChild -#include "UIScene.h" -#include -#include +#include "UIScene_RmlBase.h" -// NOTE: pop_macro at end of file - -class UIScene_HelpAndOptionsMenu : public UIScene, public Rml::EventListener +class UIScene_HelpAndOptionsMenu : public UIScene_RmlBase { public: UIScene_HelpAndOptionsMenu(int iPad, void *initData, UILayer *parentLayer); virtual ~UIScene_HelpAndOptionsMenu(); - virtual EUIScene getSceneType() { return eUIScene_HelpAndOptionsMenu; } + EUIScene getSceneType() override { return eUIScene_HelpAndOptionsMenu; } + void handleInput(int iPad, int key, bool repeat, bool pressed, bool released, bool &handled) override; + void updateComponents() override; - virtual void tick(); - virtual void render(S32 width, S32 height, C4JRender::eViewportType viewport); - - virtual void handleInput(int iPad, int key, bool repeat, bool pressed, bool released, bool &handled); - - // Override focus/movie lifecycle for RmlUi (no Iggy movie) - virtual void gainFocus() override; - virtual void reloadMovie(bool force) override; - - // Rml::EventListener void ProcessEvent(Rml::Event& event) override; -protected: - virtual wstring getMoviePath() { return L""; } - - virtual void handleLoseFocus() override; - virtual void updateTooltips() override; - virtual void updateComponents() override; - +private: void navigateBack(); void OnChangeSkin(); @@ -47,9 +29,6 @@ protected: void OnControls(); void OnSettings(); void OnCredits(); - -private: - Rml::ElementDocument* m_document; }; #pragma pop_macro("GetFirstChild") diff --git a/Minecraft.Client/Common/UI/UIScene_LoadCreateJoinMenu.cpp b/Minecraft.Client/Common/UI/UIScene_LoadCreateJoinMenu.cpp index d073cf5b..92630746 100644 --- a/Minecraft.Client/Common/UI/UIScene_LoadCreateJoinMenu.cpp +++ b/Minecraft.Client/Common/UI/UIScene_LoadCreateJoinMenu.cpp @@ -251,12 +251,11 @@ void UIScene_LoadCreateJoinMenu::SetListTexture(int itemIndex, const char* listI // -- Construction / Destruction -- -UIScene_LoadCreateJoinMenu::UIScene_LoadCreateJoinMenu(int iPad, void* initData, UILayer* parentLayer) : UIScene(iPad, parentLayer) +UIScene_LoadCreateJoinMenu::UIScene_LoadCreateJoinMenu(int iPad, void* initData, UILayer* parentLayer) : UIScene_RmlBase(iPad, parentLayer) { constexpr uint64_t MAXIMUM_SAVE_STORAGE = 4LL * 1024LL * 1024LL * 1024LL; // Initialize all members before any function calls - m_document = nullptr; m_iRequestingThumbnailId = 0; m_iSaveInfoC = 0; m_bIgnoreInput = false; @@ -383,44 +382,6 @@ UIScene_LoadCreateJoinMenu::~UIScene_LoadCreateJoinMenu() } } -// -- RmlUi lifecycle overrides -- - -void UIScene_LoadCreateJoinMenu::gainFocus() -{ - if (!bHasFocus && stealsFocus()) - { - bHasFocus = true; - updateTooltips(); - updateComponents(); - - if (!m_bFocussedOnce) - { - } - - handleGainFocus(m_bFocussedOnce); - - if (bHasFocus) - m_bFocussedOnce = true; - - if (m_document) - m_document->Show(); - } -} - -void UIScene_LoadCreateJoinMenu::handleLoseFocus() -{ - if (m_document) - m_document->Hide(); -} - -void UIScene_LoadCreateJoinMenu::reloadMovie(bool force) -{ -} - -void UIScene_LoadCreateJoinMenu::render(S32 width, S32 height, C4JRender::eViewportType viewport) -{ -} - void UIScene_LoadCreateJoinMenu::ProcessEvent(Rml::Event& event) { if (m_bIgnoreInput) diff --git a/Minecraft.Client/Common/UI/UIScene_LoadCreateJoinMenu.h b/Minecraft.Client/Common/UI/UIScene_LoadCreateJoinMenu.h index 67a577f7..caa25ac6 100644 --- a/Minecraft.Client/Common/UI/UIScene_LoadCreateJoinMenu.h +++ b/Minecraft.Client/Common/UI/UIScene_LoadCreateJoinMenu.h @@ -7,16 +7,12 @@ #undef GetNextSibling #undef GetFirstChild -#include "UIScene.h" -#include -#include - -// NOTE: pop_macro at end of file +#include "UIScene_RmlBase.h" class LevelGenerationOptions; class C4JThread; -class UIScene_LoadCreateJoinMenu : public UIScene, public Rml::EventListener +class UIScene_LoadCreateJoinMenu : public UIScene_RmlBase { private: enum EControls @@ -112,29 +108,22 @@ public: UIScene_LoadCreateJoinMenu(int iPad, void *initData, UILayer *parentLayer); virtual ~UIScene_LoadCreateJoinMenu(); - virtual void updateTooltips(); - virtual void updateComponents(); + virtual void updateTooltips() override; + virtual void updateComponents() override; virtual UIControl* GetMainPanel(); - virtual void handleDestroy(); - virtual void handleLoseFocus(); - virtual void handleGainFocus(bool navBack); - virtual void handleTimerComplete(int id); - // INPUT - virtual void handleInput(int iPad, int key, bool repeat, bool pressed, bool released, bool &handled); - virtual void handleFocusChange(F64 controlId, F64 childId); - virtual void handleInitFocus(F64 controlId, F64 childId); + virtual void handleDestroy() override; + virtual void handleGainFocus(bool navBack) override; + virtual void handleTimerComplete(int id) override; + virtual void handleInput(int iPad, int key, bool repeat, bool pressed, bool released, bool &handled) override; + virtual void handleFocusChange(F64 controlId, F64 childId) override; + virtual void handleInitFocus(F64 controlId, F64 childId) override; - virtual EUIScene getSceneType() { return eUIScene_LoadCreateJoinMenu; } + virtual EUIScene getSceneType() override { return eUIScene_LoadCreateJoinMenu; } static void UpdateGamesListCallback(LPVOID pParam); - virtual void tick(); - - // Override focus/movie lifecycle for RmlUi (no Iggy movie) - virtual void gainFocus() override; - virtual void reloadMovie(bool force) override; - virtual void render(S32 width, S32 height, C4JRender::eViewportType viewport) override; + void tick() override; // Rml::EventListener void ProcessEvent(Rml::Event& event) override; @@ -166,7 +155,7 @@ private: int GetListItemCount(const char* listId); protected: - virtual wstring getMoviePath(); + virtual wstring getMoviePath() override; public: static int LoadSaveDataThumbnailReturned(LPVOID lpParam,PBYTE pbThumbnail,DWORD dwThumbnailBytes); @@ -184,7 +173,7 @@ protected: void LoadSaveFromDisk(File *saveFile, ESavePlatform savePlatform = SAVE_FILE_PLATFORM_LOCAL); public: - virtual void HandleDLCMountingComplete(); + virtual void HandleDLCMountingComplete() override; private: void CheckAndJoinGame(int gameIndex); @@ -200,12 +189,8 @@ private: void AppendServerToFile(const wstring& ip, const wstring& port, const wstring& name); static int AddServerKeyboardCallback(LPVOID lpParam, bool bRes); #endif - -// RmlUi document -private: - Rml::ElementDocument* m_document; }; #pragma pop_macro("GetFirstChild") #pragma pop_macro("GetNextSibling") -#pragma pop_macro("byte") \ No newline at end of file +#pragma pop_macro("byte") diff --git a/Minecraft.Client/Common/UI/UIScene_MessageBox.cpp b/Minecraft.Client/Common/UI/UIScene_MessageBox.cpp index 915f373b..5b11b0df 100644 --- a/Minecraft.Client/Common/UI/UIScene_MessageBox.cpp +++ b/Minecraft.Client/Common/UI/UIScene_MessageBox.cpp @@ -17,11 +17,8 @@ #pragma pop_macro("GetNextSibling") #pragma pop_macro("byte") -extern KeyboardMouseInput g_KBMInput; - UIScene_MessageBox::UIScene_MessageBox(int iPad, void *initData, UILayer *parentLayer) - : UIScene(iPad, parentLayer) - , m_document(nullptr) + : UIScene_RmlBase(iPad, parentLayer) , m_buttonCount(0) , m_Func(nullptr) , m_lpParam(nullptr) @@ -59,7 +56,6 @@ UIScene_MessageBox::UIScene_MessageBox(int iPad, void *initData, UILayer *parent if (auto* descEl = m_document->GetElementById("description")) descEl->SetInnerRML(descUtf8); - int buttonIndex = 0; Rml::Element* buttons[4] = { m_document->GetElementById("button0"), m_document->GetElementById("button1"), @@ -76,10 +72,7 @@ UIScene_MessageBox::UIScene_MessageBox(int iPad, void *initData, UILayer *parent } } - int startIndex = 4 - m_buttonCount; - if (startIndex < 0) - startIndex = 0; - + int startIndex = max(0, 4 - m_buttonCount); int labelIndex = 0; for (int i = startIndex; i < 4; i++) { @@ -98,7 +91,6 @@ UIScene_MessageBox::UIScene_MessageBox(int iPad, void *initData, UILayer *parent buttons[focusButton]->Focus(); m_document->Show(); - parentLayer->addComponent(iPad, eUIComponent_MenuBackground); } @@ -106,12 +98,18 @@ UIScene_MessageBox::~UIScene_MessageBox() { if (m_document) { - m_document->GetElementById("button0")->RemoveEventListener(Rml::EventId::Click, this); - m_document->GetElementById("button1")->RemoveEventListener(Rml::EventId::Click, this); - m_document->GetElementById("button2")->RemoveEventListener(Rml::EventId::Click, this); - m_document->GetElementById("button3")->RemoveEventListener(Rml::EventId::Click, this); + Rml::Element* buttons[4] = { + m_document->GetElementById("button0"), + m_document->GetElementById("button1"), + m_document->GetElementById("button2"), + m_document->GetElementById("button3") + }; + for (int i = 0; i < 4; i++) + { + if (buttons[i]) + buttons[i]->RemoveEventListener(Rml::EventId::Click, this); + } m_document->Close(); - m_document = nullptr; } m_parentLayer->removeComponent(eUIComponent_MenuBackground); @@ -204,7 +202,7 @@ void UIScene_MessageBox::handleInput(int iPad, int key, bool repeat, bool presse case ACTION_MENU_CANCEL: { C4JStorage::EMessageResult result = C4JStorage::EMessage_Cancelled; - int( *tmpFunc)(LPVOID,int,const C4JStorage::EMessageResult) = m_Func; + auto tmpFunc = m_Func; LPVOID tmpParam = m_lpParam; int tmpPad = m_iPad; @@ -223,11 +221,11 @@ void UIScene_MessageBox::handleInput(int iPad, int key, bool repeat, bool presse bool UIScene_MessageBox::hasFocus(int iPad) { - if (m_iPad == 255) // Message box is for everyone + if (m_iPad == 255) return bHasFocus; - else if (ProfileManager.IsSignedIn(m_iPad)) // Owner is still present + else if (ProfileManager.IsSignedIn(m_iPad)) return bHasFocus && (iPad == m_iPad); - else // Original owner has left so let everyone interact + else return bHasFocus; } @@ -246,12 +244,7 @@ void UIScene_MessageBox::ProcessEvent(Rml::Event& event) void UIScene_MessageBox::OnButtonClicked(int buttonIndex) { - //GabsPuN: Something is wrong with the IDs. This fixed it but - //I don't know if this is the right way to do it - int startIndex = 4 - m_buttonCount; - if (startIndex < 0) - startIndex = 0; - + int startIndex = max(0, 4 - m_buttonCount); int RButtonIndex = buttonIndex - startIndex; C4JStorage::EMessageResult result = C4JStorage::EMessage_Cancelled; @@ -265,7 +258,7 @@ void UIScene_MessageBox::OnButtonClicked(int buttonIndex) ui.PlayUISFX(eSFX_Press); - int( *tmpFunc)(LPVOID,int,const C4JStorage::EMessageResult) = m_Func; + auto tmpFunc = m_Func; LPVOID tmpParam = m_lpParam; int tmpPad = m_iPad; diff --git a/Minecraft.Client/Common/UI/UIScene_MessageBox.h b/Minecraft.Client/Common/UI/UIScene_MessageBox.h index c2bc5967..84c13213 100644 --- a/Minecraft.Client/Common/UI/UIScene_MessageBox.h +++ b/Minecraft.Client/Common/UI/UIScene_MessageBox.h @@ -7,41 +7,28 @@ #undef GetNextSibling #undef GetFirstChild -#include "UIScene.h" -#include -#include +#include "UIScene_RmlBase.h" -class UIScene_MessageBox : public UIScene, public Rml::EventListener +class UIScene_MessageBox : public UIScene_RmlBase { public: UIScene_MessageBox(int iPad, void *initData, UILayer *parentLayer); virtual ~UIScene_MessageBox(); - virtual EUIScene getSceneType() { return eUIScene_MessageBox; } + EUIScene getSceneType() override { return eUIScene_MessageBox; } - virtual bool hidesLowerScenes() { return false; } - virtual bool blocksInput() { return true; } + bool hidesLowerScenes() override { return false; } + bool blocksInput() override { return true; } - virtual void tick(); - virtual void render(S32 width, S32 height, C4JRender::eViewportType viewport); - - virtual void handleInput(int iPad, int key, bool repeat, bool pressed, bool released, bool &handled); - virtual bool hasFocus(int iPad); - - virtual void gainFocus() override; - virtual void reloadMovie(bool force) override; + void handleInput(int iPad, int key, bool repeat, bool pressed, bool released, bool &handled) override; + bool hasFocus(int iPad) override; void ProcessEvent(Rml::Event& event) override; -protected: - virtual wstring getMoviePath() { return L""; } - virtual void handleLoseFocus() override; - +private: void OnButtonClicked(int buttonIndex); void navigateBack(); -private: - Rml::ElementDocument* m_document; int m_buttonCount; int(*m_Func)(LPVOID, int, const C4JStorage::EMessageResult); LPVOID m_lpParam; diff --git a/Minecraft.Client/Common/UI/UIScene_PauseMenu.cpp b/Minecraft.Client/Common/UI/UIScene_PauseMenu.cpp index 600fe990..9f9ff6f0 100644 --- a/Minecraft.Client/Common/UI/UIScene_PauseMenu.cpp +++ b/Minecraft.Client/Common/UI/UIScene_PauseMenu.cpp @@ -1,9 +1,7 @@ -// Non-RmlUi includes that depend on Windows macros #include "UI.h" #include "../../MinecraftServer.h" #include "../../MultiPlayerLocalPlayer.h" -// RmlUi includes (Windows macros temporarily suppressed) #pragma push_macro("byte") #pragma push_macro("GetNextSibling") #pragma push_macro("GetFirstChild") @@ -22,9 +20,7 @@ #pragma pop_macro("byte") UIScene_PauseMenu::UIScene_PauseMenu(int iPad, void *initData, UILayer *parentLayer) - : UIScene(iPad, parentLayer) - , m_document(nullptr) - , m_bIgnoreInput(false) + : UIScene_RmlBase(iPad, parentLayer) { Rml::Context* ctx = RmlManager::Get().GetContext(); if (!ctx) @@ -40,11 +36,8 @@ UIScene_PauseMenu::UIScene_PauseMenu(int iPad, void *initData, UILayer *parentLa m_document->Show(); app.DebugPrintf("[RmlPauseMenu] Document shown, visible=%d, context docs=%d\n", m_document->IsVisible(), ctx->GetNumDocuments()); - m_document->GetElementById("resume")->AddEventListener(Rml::EventId::Click, this); - m_document->GetElementById("help_options")->AddEventListener(Rml::EventId::Click, this); - m_document->GetElementById("achievements")->AddEventListener(Rml::EventId::Click, this); - m_document->GetElementById("save_game")->AddEventListener(Rml::EventId::Click, this); - m_document->GetElementById("exit_game")->AddEventListener(Rml::EventId::Click, this); + + RegisterEvents({ "resume", "help_options", "achievements", "save_game", "exit_game" }); m_document->GetElementById("resume")->Focus(); } else @@ -67,13 +60,8 @@ UIScene_PauseMenu::~UIScene_PauseMenu() { if (m_document) { - m_document->GetElementById("resume")->RemoveEventListener(Rml::EventId::Click, this); - m_document->GetElementById("help_options")->RemoveEventListener(Rml::EventId::Click, this); - m_document->GetElementById("achievements")->RemoveEventListener(Rml::EventId::Click, this); - m_document->GetElementById("save_game")->RemoveEventListener(Rml::EventId::Click, this); - m_document->GetElementById("exit_game")->RemoveEventListener(Rml::EventId::Click, this); + UnregisterEvents({ "resume", "help_options", "achievements", "save_game", "exit_game" }); m_document->Close(); - m_document = nullptr; } m_parentLayer->showComponent(m_iPad, eUIComponent_Panorama, false); @@ -181,9 +169,6 @@ void UIScene_PauseMenu::handleInput(int iPad, int key, bool repeat, bool pressed if (!ctx) return; - // Translate game actions to RmlUi key events. - // Mouse clicks are forwarded in tick() via ProcessMouseButtonDown/Up, - // so here we only handle keyboard-originated actions. if (!pressed) return; @@ -198,8 +183,6 @@ void UIScene_PauseMenu::handleInput(int iPad, int key, bool repeat, bool pressed handled = true; break; case ACTION_MENU_OK: - // Only forward as keyboard Enter if actually coming from keyboard, - // not from mouse click (mouse is handled in tick()). if (g_KBMInput.IsKeyPressed(VK_RETURN)) { ctx->ProcessKeyDown(Rml::Input::KI_RETURN, 0); @@ -274,11 +257,9 @@ void UIScene_PauseMenu::OnSaveGame() if (m_iPad != ProfileManager.GetPrimaryPad()) return; - // Does the save exist? bool bSaveExists; StorageManager.DoesSaveExist(&bSaveExists); - // We need to ask if they are sure they want to overwrite the existing game if (bSaveExists) { UINT uiIDA[2]; @@ -288,7 +269,6 @@ void UIScene_PauseMenu::OnSaveGame() } else { - // Flag a app action of save game app.SetAction(m_iPad, eAppAction_SaveGame); } } @@ -299,7 +279,6 @@ void UIScene_PauseMenu::OnExitGame() UINT uiIDA[3]; - // Is it the primary player exiting? if (m_iPad == ProfileManager.GetPrimaryPad()) { int playTime = -1; @@ -334,7 +313,7 @@ void UIScene_PauseMenu::OnExitGame() } } } - else // Non-primary pad: exit directly without dialog + else { int playTime = -1; if (pMinecraft->localplayers[m_iPad] != NULL) @@ -346,4 +325,4 @@ void UIScene_PauseMenu::OnExitGame() app.SetAction(m_iPad, eAppAction_ExitPlayer); return; } -} \ No newline at end of file +} diff --git a/Minecraft.Client/Common/UI/UIScene_PauseMenu.h b/Minecraft.Client/Common/UI/UIScene_PauseMenu.h index 8ec681ed..03ef5d0e 100644 --- a/Minecraft.Client/Common/UI/UIScene_PauseMenu.h +++ b/Minecraft.Client/Common/UI/UIScene_PauseMenu.h @@ -7,38 +7,22 @@ #undef GetNextSibling #undef GetFirstChild -#include "UIScene.h" +#include "UIScene_RmlBase.h" #include "IUIScene_PauseMenu.h" -#include -#include -// NOTE: pop_macro at end of file - -class UIScene_PauseMenu : public UIScene, public IUIScene_PauseMenu, public Rml::EventListener +class UIScene_PauseMenu : public UIScene_RmlBase, public IUIScene_PauseMenu { public: UIScene_PauseMenu(int iPad, void *initData, UILayer *parentLayer); virtual ~UIScene_PauseMenu(); - virtual EUIScene getSceneType() { return eUIScene_PauseMenu; } + EUIScene getSceneType() override { return eUIScene_PauseMenu; } - virtual void tick(); - virtual void render(S32 width, S32 height, C4JRender::eViewportType viewport); + void handleInput(int iPad, int key, bool repeat, bool pressed, bool released, bool &handled) override; - virtual void handleInput(int iPad, int key, bool repeat, bool pressed, bool released, bool &handled); - - // Override focus/movie lifecycle for RmlUi (no Iggy movie) - virtual void gainFocus() override; - virtual void reloadMovie(bool force) override; - - // Rml::EventListener void ProcessEvent(Rml::Event& event) override; protected: - virtual wstring getMoviePath() { return L""; } - - virtual void handleLoseFocus() override; - void ShowScene(bool show) override; void SetIgnoreInput(bool ignoreInput) override { m_bIgnoreInput = ignoreInput; } @@ -51,8 +35,7 @@ protected: void OnExitGame(); private: - Rml::ElementDocument* m_document; - bool m_bIgnoreInput; + bool m_bIgnoreInput = false; }; #pragma pop_macro("GetFirstChild") diff --git a/Minecraft.Client/Common/UI/UIScene_RmlBase.cpp b/Minecraft.Client/Common/UI/UIScene_RmlBase.cpp new file mode 100644 index 00000000..d27ebaf6 --- /dev/null +++ b/Minecraft.Client/Common/UI/UIScene_RmlBase.cpp @@ -0,0 +1,99 @@ +#include "UI.h" + +#pragma push_macro("byte") +#pragma push_macro("GetNextSibling") +#pragma push_macro("GetFirstChild") +#undef byte +#undef GetNextSibling +#undef GetFirstChild + +#include "UIScene_RmlBase.h" +#include "RmlManager.h" +#include "../../Windows64/KeyboardMouseInput.h" +#include +#include + +#pragma pop_macro("GetFirstChild") +#pragma pop_macro("GetNextSibling") +#pragma pop_macro("byte") + +UIScene_RmlBase::UIScene_RmlBase(int iPad, UILayer *parentLayer) + : UIScene(iPad, parentLayer) +{ +} + +UIScene_RmlBase::~UIScene_RmlBase() +{ +} + +void UIScene_RmlBase::tick() +{ + m_hasTickedOnce = true; + UIScene::tick(); + + Rml::Context* ctx = RmlManager::Get().GetContext(); + if (!ctx || !bHasFocus) + return; + + ForwardRmlInput(ctx); + ctx->Update(); +} + +void UIScene_RmlBase::gainFocus() +{ + if (!bHasFocus && stealsFocus()) + { + bHasFocus = true; + updateTooltips(); + updateComponents(); + handleGainFocus(m_bFocussedOnce); + if (bHasFocus) + m_bFocussedOnce = true; + if (m_document) + m_document->Show(); + } +} + +void UIScene_RmlBase::handleLoseFocus() +{ + if (m_document) + m_document->Hide(); +} + +void UIScene_RmlBase::ForwardRmlInput(Rml::Context* ctx) +{ + ctx->ProcessMouseMove(g_KBMInput.GetMouseX(), g_KBMInput.GetMouseY(), 0); + + if (g_KBMInput.IsMouseButtonPressed(KeyboardMouseInput::MOUSE_LEFT)) + ctx->ProcessMouseButtonDown(0, 0); + if (g_KBMInput.IsMouseButtonReleased(KeyboardMouseInput::MOUSE_LEFT)) + ctx->ProcessMouseButtonUp(0, 0); + if (g_KBMInput.IsMouseButtonPressed(KeyboardMouseInput::MOUSE_RIGHT)) + ctx->ProcessMouseButtonDown(1, 0); + if (g_KBMInput.IsMouseButtonReleased(KeyboardMouseInput::MOUSE_RIGHT)) + ctx->ProcessMouseButtonUp(1, 0); + + int wheelDelta = g_KBMInput.GetMouseWheel(); + if (wheelDelta != 0) + ctx->ProcessMouseWheel(wheelDelta / -120, 0); +} + +void UIScene_RmlBase::RegisterEvents(std::initializer_list ids) +{ + if (!m_document) return; + for (const char* id : ids) + { + auto* el = m_document->GetElementById(id); + if (el) el->AddEventListener(Rml::EventId::Click, this); + } +} + +void UIScene_RmlBase::UnregisterEvents(std::initializer_list ids) +{ + if (!m_document) return; + for (const char* id : ids) + { + auto* el = m_document->GetElementById(id); + if (el) el->RemoveEventListener(Rml::EventId::Click, this); + } +} diff --git a/Minecraft.Client/Common/UI/UIScene_RmlBase.h b/Minecraft.Client/Common/UI/UIScene_RmlBase.h new file mode 100644 index 00000000..7d0ed222 --- /dev/null +++ b/Minecraft.Client/Common/UI/UIScene_RmlBase.h @@ -0,0 +1,38 @@ +#pragma once + +#pragma push_macro("byte") +#pragma push_macro("GetNextSibling") +#pragma push_macro("GetFirstChild") +#undef byte +#undef GetNextSibling +#undef GetFirstChild + +#include "UIScene.h" +#include +#include + +class UIScene_RmlBase : public UIScene, public Rml::EventListener +{ +public: + UIScene_RmlBase(int iPad, UILayer *parentLayer); + virtual ~UIScene_RmlBase(); + + void tick() override; + void render(S32 width, S32 height, C4JRender::eViewportType viewport) override {} + void gainFocus() override; + void reloadMovie(bool force) override {} + +protected: + wstring getMoviePath() override { return L""; } + void handleLoseFocus() override; + + void ForwardRmlInput(Rml::Context* ctx); + void RegisterEvents(std::initializer_list ids); + void UnregisterEvents(std::initializer_list ids); + + Rml::ElementDocument* m_document = nullptr; +}; + +#pragma pop_macro("GetFirstChild") +#pragma pop_macro("GetNextSibling") +#pragma pop_macro("byte") diff --git a/Minecraft.Client/Common/UI/UIScene_SettingsMenu.cpp b/Minecraft.Client/Common/UI/UIScene_SettingsMenu.cpp index 9ec16616..126a8507 100644 --- a/Minecraft.Client/Common/UI/UIScene_SettingsMenu.cpp +++ b/Minecraft.Client/Common/UI/UIScene_SettingsMenu.cpp @@ -1,8 +1,6 @@ -// Non-RmlUi includes that depend on Windows macros #include "UI.h" #include "../../Minecraft.h" -// RmlUi includes (Windows macros temporarily suppressed) #pragma push_macro("byte") #pragma push_macro("GetNextSibling") #pragma push_macro("GetFirstChild") @@ -21,8 +19,7 @@ #pragma pop_macro("byte") UIScene_SettingsMenu::UIScene_SettingsMenu(int iPad, void *initData, UILayer *parentLayer) - : UIScene(iPad, parentLayer) - , m_document(nullptr) + : UIScene_RmlBase(iPad, parentLayer) { Rml::Context* ctx = RmlManager::Get().GetContext(); if (!ctx) @@ -32,40 +29,26 @@ UIScene_SettingsMenu::UIScene_SettingsMenu(int iPad, void *initData, UILayer *pa } m_document = ctx->LoadDocument("SettingsMenu.rml"); - if (m_document) - { - m_document->Show(); - - // Apply conditional visibility matching original Iggy scene behavior - bool bNotInGame = (Minecraft::GetInstance()->level == nullptr); - - // Audio and Graphics: hidden if not primary pad - if (ProfileManager.GetPrimaryPad() != m_iPad) - { - auto* elAudio = m_document->GetElementById("audio"); - if (elAudio) elAudio->SetProperty("display", "none"); - auto* elGraphics = m_document->GetElementById("graphics"); - if (elGraphics) elGraphics->SetProperty("display", "none"); - } - - // Register button click listeners - m_document->GetElementById("options")->AddEventListener(Rml::EventId::Click, this); - m_document->GetElementById("audio")->AddEventListener(Rml::EventId::Click, this); - m_document->GetElementById("controls")->AddEventListener(Rml::EventId::Click, this); - m_document->GetElementById("graphics")->AddEventListener(Rml::EventId::Click, this); - m_document->GetElementById("ui")->AddEventListener(Rml::EventId::Click, this); - m_document->GetElementById("reset_defaults")->AddEventListener(Rml::EventId::Click, this); - - // Focus first visible button - m_document->GetElementById("options")->Focus(); - } - else + if (!m_document) { app.DebugPrintf("[RmlSettingsMenu] Failed to load SettingsMenu.rml\n"); + return; } - updateComponents(); + m_document->Show(); + if (ProfileManager.GetPrimaryPad() != m_iPad) + { + auto* elAudio = m_document->GetElementById("audio"); + if (elAudio) elAudio->SetProperty("display", "none"); + auto* elGraphics = m_document->GetElementById("graphics"); + if (elGraphics) elGraphics->SetProperty("display", "none"); + } + + RegisterEvents({ "options", "audio", "controls", "graphics", "ui", "reset_defaults" }); + m_document->GetElementById("options")->Focus(); + + updateComponents(); ui.HidePressStart(); TelemetryManager->RecordMenuShown(m_iPad, eUIScene_SettingsMenu, 0); } @@ -74,101 +57,11 @@ UIScene_SettingsMenu::~UIScene_SettingsMenu() { if (m_document) { - m_document->GetElementById("options")->RemoveEventListener(Rml::EventId::Click, this); - m_document->GetElementById("audio")->RemoveEventListener(Rml::EventId::Click, this); - m_document->GetElementById("controls")->RemoveEventListener(Rml::EventId::Click, this); - m_document->GetElementById("graphics")->RemoveEventListener(Rml::EventId::Click, this); - m_document->GetElementById("ui")->RemoveEventListener(Rml::EventId::Click, this); - m_document->GetElementById("reset_defaults")->RemoveEventListener(Rml::EventId::Click, this); + UnregisterEvents({ "options", "audio", "controls", "graphics", "ui", "reset_defaults" }); m_document->Close(); - m_document = nullptr; } } -void UIScene_SettingsMenu::gainFocus() -{ - if (!bHasFocus && stealsFocus()) - { - bHasFocus = true; - updateTooltips(); - updateComponents(); - if (!m_bFocussedOnce) - { - } - handleGainFocus(m_bFocussedOnce); - if (bHasFocus) - m_bFocussedOnce = true; - if (m_document) - m_document->Show(); - } -} - -void UIScene_SettingsMenu::handleLoseFocus() -{ - if (m_document) - m_document->Hide(); -} - -void UIScene_SettingsMenu::updateTooltips() -{ -} - -void UIScene_SettingsMenu::updateComponents() -{ - bool bNotInGame = (Minecraft::GetInstance()->level == nullptr); - - if (bNotInGame) - { - m_parentLayer->showComponent(m_iPad, eUIComponent_Panorama, true); - m_parentLayer->showComponent(m_iPad, eUIComponent_Logo, true); - } - else - { - m_parentLayer->showComponent(m_iPad, eUIComponent_Panorama, false); - - if (app.GetLocalPlayerCount() == 1) - m_parentLayer->showComponent(m_iPad, eUIComponent_Logo, true); - else - m_parentLayer->showComponent(m_iPad, eUIComponent_Logo, false); - } -} - -void UIScene_SettingsMenu::reloadMovie(bool force) -{ -} - -void UIScene_SettingsMenu::tick() -{ - m_hasTickedOnce = true; - - UIScene::tick(); - - Rml::Context* ctx = RmlManager::Get().GetContext(); - if (!ctx || !bHasFocus) - return; - - ctx->ProcessMouseMove(g_KBMInput.GetMouseX(), g_KBMInput.GetMouseY(), 0); - - if (g_KBMInput.IsMouseButtonPressed(KeyboardMouseInput::MOUSE_LEFT)) - ctx->ProcessMouseButtonDown(0, 0); - if (g_KBMInput.IsMouseButtonReleased(KeyboardMouseInput::MOUSE_LEFT)) - ctx->ProcessMouseButtonUp(0, 0); - if (g_KBMInput.IsMouseButtonPressed(KeyboardMouseInput::MOUSE_RIGHT)) - ctx->ProcessMouseButtonDown(1, 0); - if (g_KBMInput.IsMouseButtonReleased(KeyboardMouseInput::MOUSE_RIGHT)) - ctx->ProcessMouseButtonUp(1, 0); - - int wheelDelta = g_KBMInput.GetMouseWheel(); - if (wheelDelta != 0) - ctx->ProcessMouseWheel(wheelDelta / -120, 0); - - ctx->Update(); -} - -void UIScene_SettingsMenu::render(S32 width, S32 height, C4JRender::eViewportType viewport) -{ -} - void UIScene_SettingsMenu::handleInput(int iPad, int key, bool repeat, bool pressed, bool released, bool &handled) { Rml::Context* ctx = RmlManager::Get().GetContext(); @@ -221,6 +114,21 @@ void UIScene_SettingsMenu::ProcessEvent(Rml::Event& event) } } +void UIScene_SettingsMenu::updateComponents() +{ + bool bNotInGame = (Minecraft::GetInstance()->level == nullptr); + if (bNotInGame) + { + m_parentLayer->showComponent(m_iPad, eUIComponent_Panorama, true); + m_parentLayer->showComponent(m_iPad, eUIComponent_Logo, true); + } + else + { + m_parentLayer->showComponent(m_iPad, eUIComponent_Panorama, false); + m_parentLayer->showComponent(m_iPad, eUIComponent_Logo, app.GetLocalPlayerCount() == 1); + } +} + void UIScene_SettingsMenu::navigateBack() { ui.PlayUISFX(eSFX_Back); @@ -260,24 +168,20 @@ void UIScene_SettingsMenu::OnUI() void UIScene_SettingsMenu::OnResetToDefaults() { UINT uiIDA[2]; - uiIDA[0]=IDS_CONFIRM_CANCEL; - uiIDA[1]=IDS_CONFIRM_OK; + uiIDA[0] = IDS_CONFIRM_CANCEL; + uiIDA[1] = IDS_CONFIRM_OK; - ui.RequestAlertMessage(IDS_DEFAULTS_TITLE, IDS_DEFAULTS_TEXT, uiIDA, 2, m_iPad,&UIScene_SettingsMenu::ResetDefaultsDialogReturned,this); + ui.RequestAlertMessage(IDS_DEFAULTS_TITLE, IDS_DEFAULTS_TEXT, uiIDA, 2, m_iPad, &UIScene_SettingsMenu::ResetDefaultsDialogReturned, this); } -int UIScene_SettingsMenu::ResetDefaultsDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) +int UIScene_SettingsMenu::ResetDefaultsDialogReturned(void *pParam, int iPad, C4JStorage::EMessageResult result) { - UIScene_SettingsMenu* pClass = (UIScene_SettingsMenu*)pParam; + auto pClass = static_cast(pParam); - // results switched for this dialog - if(result==C4JStorage::EMessage_ResultDecline) + if (result == C4JStorage::EMessage_ResultDecline) { - app.SetDefaultOptions(ProfileManager.GetDashboardProfileSettings(pClass->m_iPad),pClass->m_iPad); - - // if the profile data has been changed, then force a profile write - // It seems we're allowed to break the 5 minute rule if it's the result of a user action - app.CheckGameSettingsChanged(true,iPad); + app.SetDefaultOptions(ProfileManager.GetDashboardProfileSettings(pClass->m_iPad), pClass->m_iPad); + app.CheckGameSettingsChanged(true, iPad); } return 0; -} \ No newline at end of file +} diff --git a/Minecraft.Client/Common/UI/UIScene_SettingsMenu.h b/Minecraft.Client/Common/UI/UIScene_SettingsMenu.h index 7987d825..bf853909 100644 --- a/Minecraft.Client/Common/UI/UIScene_SettingsMenu.h +++ b/Minecraft.Client/Common/UI/UIScene_SettingsMenu.h @@ -7,39 +7,21 @@ #undef GetNextSibling #undef GetFirstChild -#include "UIScene.h" -#include -#include +#include "UIScene_RmlBase.h" -// NOTE: pop_macro at end of file - -class UIScene_SettingsMenu : public UIScene, public Rml::EventListener +class UIScene_SettingsMenu : public UIScene_RmlBase { public: UIScene_SettingsMenu(int iPad, void *initData, UILayer *parentLayer); virtual ~UIScene_SettingsMenu(); - virtual EUIScene getSceneType() { return eUIScene_SettingsMenu; } + EUIScene getSceneType() override { return eUIScene_SettingsMenu; } + void handleInput(int iPad, int key, bool repeat, bool pressed, bool released, bool &handled) override; + void updateComponents() override; - virtual void tick(); - virtual void render(S32 width, S32 height, C4JRender::eViewportType viewport); - - virtual void handleInput(int iPad, int key, bool repeat, bool pressed, bool released, bool &handled); - - // Override focus/movie lifecycle for RmlUi (no Iggy movie) - virtual void gainFocus() override; - virtual void reloadMovie(bool force) override; - - // Rml::EventListener void ProcessEvent(Rml::Event& event) override; -protected: - virtual wstring getMoviePath() { return L""; } - - virtual void handleLoseFocus() override; - virtual void updateTooltips() override; - virtual void updateComponents() override; - +private: void navigateBack(); void OnOptions(); @@ -49,10 +31,7 @@ protected: void OnUI(); void OnResetToDefaults(); - static int ResetDefaultsDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result); - -private: - Rml::ElementDocument* m_document; + static int ResetDefaultsDialogReturned(void *pParam, int iPad, C4JStorage::EMessageResult result); }; #pragma pop_macro("GetFirstChild") diff --git a/Minecraft.Client/Common/UI/UIScene_SettingsUIMenu.cpp b/Minecraft.Client/Common/UI/UIScene_SettingsUIMenu.cpp index 1a3db51e..3706d01c 100644 --- a/Minecraft.Client/Common/UI/UIScene_SettingsUIMenu.cpp +++ b/Minecraft.Client/Common/UI/UIScene_SettingsUIMenu.cpp @@ -1,184 +1,419 @@ +#include "stdafx.h" + +// Non-RmlUi includes that depend on Windows macros #include "UI.h" +#include "../../Minecraft.h" + +// RmlUi includes (Windows macros temporarily suppressed) +#pragma push_macro("byte") +#pragma push_macro("GetNextSibling") +#pragma push_macro("GetFirstChild") +#undef byte +#undef GetNextSibling +#undef GetFirstChild + #include "UIScene_SettingsUIMenu.h" +#include "RmlManager.h" +#include "../../Windows64/KeyboardMouseInput.h" +#include +#include +#include +#include -UIScene_SettingsUIMenu::UIScene_SettingsUIMenu(int iPad, void *initData, UILayer *parentLayer) : UIScene(iPad, parentLayer) +#pragma pop_macro("GetFirstChild") +#pragma pop_macro("GetNextSibling") +#pragma pop_macro("byte") + +static Rml::String WideToUTF8(LPCWSTR wsz) { - // Setup all the Iggy references we need for this scene - initialiseMovie(); - - m_bNotInGame=(Minecraft::GetInstance()->level==nullptr); - - m_checkboxDisplayHUD.init(app.GetString(IDS_CHECKBOX_DISPLAY_HUD),eControl_DisplayHUD,(app.GetGameSettings(m_iPad,eGameSetting_DisplayHUD)!=0)); - m_checkboxDisplayHand.init(app.GetString(IDS_CHECKBOX_DISPLAY_HAND),eControl_DisplayHand,(app.GetGameSettings(m_iPad,eGameSetting_DisplayHand)!=0)); - m_checkboxDisplayDeathMessages.init(app.GetString(IDS_CHECKBOX_DEATH_MESSAGES),eControl_DisplayDeathMessages,(app.GetGameSettings(m_iPad,eGameSetting_DeathMessages)!=0)); - m_checkboxDisplayAnimatedCharacter.init(app.GetString(IDS_CHECKBOX_ANIMATED_CHARACTER),eControl_DisplayAnimatedCharacter,(app.GetGameSettings(m_iPad,eGameSetting_AnimatedCharacter)!=0)); - m_checkboxSplitscreen.init(app.GetString(IDS_CHECKBOX_VERTICAL_SPLIT_SCREEN),eControl_Splitscreen,(app.GetGameSettings(m_iPad,eGameSetting_SplitScreenVertical)!=0)); - m_checkboxShowSplitscreenGamertags.init(app.GetString(IDS_CHECKBOX_DISPLAY_SPLITSCREENGAMERTAGS),eControl_ShowSplitscreenGamertags,(app.GetGameSettings(m_iPad,eGameSetting_DisplaySplitscreenGamertags)!=0)); - m_checkboxShowClassicCrafting.init(IDS_CHECKBOX_CLASSICCRAFTING, eControl_ShowClassicCrafting,(app.GetGameSettings(m_iPad,eGameSetting_ClassicCrafting)!=0)); - - WCHAR TempString[256]; - - swprintf( (WCHAR *)TempString, 256, L"%ls: %d", app.GetString( IDS_SLIDER_UISIZE ),app.GetGameSettings(m_iPad,eGameSetting_UISize)+1); - m_sliderUISize.init(TempString,eControl_UISize,1,3,app.GetGameSettings(m_iPad,eGameSetting_UISize)+1); - - swprintf( (WCHAR *)TempString, 256, L"%ls: %d", app.GetString( IDS_SLIDER_UISIZESPLITSCREEN ),app.GetGameSettings(m_iPad,eGameSetting_UISizeSplitscreen)+1); - m_sliderUISizeSplitscreen.init(TempString,eControl_UISizeSplitscreen,1,3,app.GetGameSettings(m_iPad,eGameSetting_UISizeSplitscreen)+1); - - doHorizontalResizeCheck(); - - bool bInGame=(Minecraft::GetInstance()->level!=nullptr); - bool bPrimaryPlayer = ProfileManager.GetPrimaryPad()==m_iPad; - - // if we're not in the game, we need to use basescene 0 - if(bInGame) - { - // If the game has started, then you need to be the host to change the in-game gamertags - if(!bPrimaryPlayer) - { - // hide things we don't want the splitscreen player changing - removeControl(&m_checkboxSplitscreen, true); - removeControl(&m_checkboxShowSplitscreenGamertags, true); - } - } - - - if(app.GetLocalPlayerCount()>1) - { -#if TO_BE_IMPLEMENTED - app.AdjustSplitscreenScene(m_hObj,&m_OriginalPosition,m_iPad); -#endif - } + if (!wsz) return Rml::String(); + int len = WideCharToMultiByte(CP_UTF8, 0, wsz, -1, nullptr, 0, nullptr, nullptr); + if (len <= 0) return Rml::String(); + Rml::String result(static_cast(len) - 1, '\0'); + WideCharToMultiByte(CP_UTF8, 0, wsz, -1, &result[0], len, nullptr, nullptr); + return result; } -void UIScene_SettingsUIMenu::updateTooltips() +struct ToggleEntry { const char* id; eGameSetting setting; }; +struct SliderEntry { const char* id; int* value; int idsString; int setting; }; + +static const ToggleEntry s_toggles[] = { - ui.SetTooltips( m_iPad, IDS_TOOLTIPS_SELECT,IDS_TOOLTIPS_BACK); -} + { "DisplayHUD", eGameSetting_DisplayHUD }, + { "DisplayHand", eGameSetting_DisplayHand }, + { "DisplayDeathMessages", eGameSetting_DeathMessages }, + { "DisplayAnimatedCharacter", eGameSetting_AnimatedCharacter }, + { "Splitscreen", eGameSetting_SplitScreenVertical }, + { "ShowSplitscreenGamertags", eGameSetting_DisplaySplitscreenGamertags }, + { "ShowClassicCrafting", eGameSetting_ClassicCrafting }, +}; -void UIScene_SettingsUIMenu::updateComponents() +static const char* s_sliderIds[] = { "UISize", "UISizeSplitscreen" }; + +UIScene_SettingsUIMenu::UIScene_SettingsUIMenu(int iPad, void *initData, UILayer *parentLayer) + : UIScene(iPad, parentLayer) + , m_document(nullptr) + , m_uiSizeValue(2) + , m_uiSizeSplitscreenValue(2) + , m_dragSliderIndex(-1) { - bool bNotInGame=(Minecraft::GetInstance()->level==nullptr); - if(bNotInGame) + Rml::Context* ctx = RmlManager::Get().GetContext(); + if (!ctx) { - m_parentLayer->showComponent(m_iPad,eUIComponent_Panorama,true); - m_parentLayer->showComponent(m_iPad,eUIComponent_Logo,true); + app.DebugPrintf("[RmlSettingsUIMenu] No RmlUi context available\n"); + return; } - else + + m_document = ctx->LoadDocument("SettingsUIMenu.rml"); + if (!m_document) { - m_parentLayer->showComponent(m_iPad,eUIComponent_Panorama,false); - - if( app.GetLocalPlayerCount() == 1 ) m_parentLayer->showComponent(m_iPad,eUIComponent_Logo,true); - else m_parentLayer->showComponent(m_iPad,eUIComponent_Logo,false); - + app.DebugPrintf("[RmlSettingsUIMenu] Failed to load SettingsUIMenu.rml\n"); + return; } + + m_document->Show(); + + for (size_t i = 0; i < sizeof(s_toggles) / sizeof(s_toggles[0]); i++) + setToggleChecked(s_toggles[i].id, app.GetGameSettings(m_iPad, s_toggles[i].setting) != 0); + + m_uiSizeValue = app.GetGameSettings(m_iPad, eGameSetting_UISize) + 1; + m_uiSizeSplitscreenValue = app.GetGameSettings(m_iPad, eGameSetting_UISizeSplitscreen) + 1; + + setSliderValue("UISize", WideToUTF8(app.GetString(IDS_SLIDER_UISIZE)), m_uiSizeValue, 1, 3); + setSliderValue("UISizeSplitscreen", WideToUTF8(app.GetString(IDS_SLIDER_UISIZESPLITSCREEN)), m_uiSizeSplitscreenValue, 1, 3); + + registerEvents(); + + bool bInGame = (Minecraft::GetInstance()->level != nullptr); + bool bPrimaryPlayer = ProfileManager.GetPrimaryPad() == m_iPad; + + if (bInGame && !bPrimaryPlayer) + { + Rml::Element* el = m_document->GetElementById("Splitscreen"); + if (el) el->SetProperty("display", "none"); + el = m_document->GetElementById("ShowSplitscreenGamertags"); + if (el) el->SetProperty("display", "none"); + } + + ui.HidePressStart(); + TelemetryManager->RecordMenuShown(m_iPad, eUIScene_SettingsUIMenu, 0); } UIScene_SettingsUIMenu::~UIScene_SettingsUIMenu() { + if (m_document) + { + deregisterEvents(); + m_document->Close(); + m_document = nullptr; + } } -wstring UIScene_SettingsUIMenu::getMoviePath() +void UIScene_SettingsUIMenu::registerEvents() { - if(app.GetLocalPlayerCount() > 1) + for (size_t i = 0; i < sizeof(s_toggles) / sizeof(s_toggles[0]); i++) { - return L"SettingsUIMenuSplit"; + Rml::Element* el = m_document->GetElementById(Rml::String(s_toggles[i].id) + "_toggle"); + if (el) el->AddEventListener(Rml::EventId::Click, this); + } + + for (size_t i = 0; i < sizeof(s_sliderIds) / sizeof(s_sliderIds[0]); i++) + { + Rml::Element* elTrack = m_document->GetElementById(Rml::String(s_sliderIds[i]) + "_track"); + if (elTrack) elTrack->AddEventListener(Rml::EventId::Mousedown, this); + + Rml::Element* elThumb = m_document->GetElementById(Rml::String(s_sliderIds[i]) + "_thumb"); + if (elThumb) elThumb->AddEventListener(Rml::EventId::Mousedown, this); + } + + m_document->AddEventListener(Rml::EventId::Mousemove, this); + m_document->AddEventListener(Rml::EventId::Mouseup, this); +} + +void UIScene_SettingsUIMenu::deregisterEvents() +{ + for (size_t i = 0; i < sizeof(s_toggles) / sizeof(s_toggles[0]); i++) + { + Rml::Element* el = m_document->GetElementById(Rml::String(s_toggles[i].id) + "_toggle"); + if (el) el->RemoveEventListener(Rml::EventId::Click, this); + } + + for (size_t i = 0; i < sizeof(s_sliderIds) / sizeof(s_sliderIds[0]); i++) + { + Rml::Element* elTrack = m_document->GetElementById(Rml::String(s_sliderIds[i]) + "_track"); + if (elTrack) elTrack->RemoveEventListener(Rml::EventId::Mousedown, this); + + Rml::Element* elThumb = m_document->GetElementById(Rml::String(s_sliderIds[i]) + "_thumb"); + if (elThumb) elThumb->RemoveEventListener(Rml::EventId::Mousedown, this); + } + + m_document->RemoveEventListener(Rml::EventId::Mousemove, this); + m_document->RemoveEventListener(Rml::EventId::Mouseup, this); +} + +void UIScene_SettingsUIMenu::setToggleChecked(const Rml::String& id, bool checked) +{ + Rml::Element* el = m_document->GetElementById(id); + if (!el) return; + el->SetClass("checked", checked); +} + +bool UIScene_SettingsUIMenu::isToggleChecked(const Rml::String& id) +{ + Rml::Element* el = m_document->GetElementById(id); + return el && el->IsClassSet("checked"); +} + +void UIScene_SettingsUIMenu::setSliderValue(const Rml::String& id, const Rml::String& labelPrefix, int value, int min, int max) +{ + Rml::Element* label = m_document->GetElementById(id + "_label"); + if (label) + { + char buf[64]; + snprintf(buf, sizeof(buf), "%s: %d", labelPrefix.c_str(), value); + label->SetInnerRML(Rml::String(buf)); + } + + Rml::Element* thumb = m_document->GetElementById(id + "_thumb"); + if (thumb) + { + float fraction = (max > min) ? (float)(value - min) / (float)(max - min) : 0.0f; + char buf[16]; + snprintf(buf, sizeof(buf), "%.0f%%", fraction * 100.0f); + thumb->SetProperty("left", Rml::String(buf)); + } +} + +int UIScene_SettingsUIMenu::getSliderValue(const Rml::String& id) +{ + if (id == "UISize") + return m_uiSizeValue; + if (id == "UISizeSplitscreen") + return m_uiSizeSplitscreenValue; + return 0; +} + +void UIScene_SettingsUIMenu::handleSliderMouseEvent(int sliderIndex, const Rml::Event& event) +{ + if (!m_document) return; + + Rml::String trackId = Rml::String(s_sliderIds[sliderIndex]) + "_track"; + Rml::Element* track = m_document->GetElementById(trackId); + if (!track) return; + + float mouseX = event.GetParameter("mouse_x", 0.0f); + Rml::Box box = track->GetBox(); + float boxLeft = track->GetAbsoluteOffset().x; + float boxWidth = box.GetSize().x; + + if (boxWidth > 0.0f) + { + float fraction = (mouseX - boxLeft) / boxWidth; + if (fraction < 0.0f) fraction = 0.0f; + if (fraction > 1.0f) fraction = 1.0f; + + int newValue = 1 + static_cast(fraction * 2.0f + 0.5f); + if (newValue < 1) newValue = 1; + if (newValue > 3) newValue = 3; + + handleSliderMove(sliderIndex, newValue); + } +} + +void UIScene_SettingsUIMenu::updateComponents() +{ + bool bNotInGame = (Minecraft::GetInstance()->level == nullptr); + if (bNotInGame) + { + m_parentLayer->showComponent(m_iPad, eUIComponent_Panorama, true); + m_parentLayer->showComponent(m_iPad, eUIComponent_Logo, true); } else { - return L"SettingsUIMenu"; + m_parentLayer->showComponent(m_iPad, eUIComponent_Panorama, false); + + if (app.GetLocalPlayerCount() == 1) m_parentLayer->showComponent(m_iPad, eUIComponent_Logo, true); + else m_parentLayer->showComponent(m_iPad, eUIComponent_Logo, false); } } +void UIScene_SettingsUIMenu::gainFocus() +{ + if (!bHasFocus && stealsFocus()) + { + bHasFocus = true; + updateComponents(); + handleGainFocus(m_bFocussedOnce); + if (bHasFocus) + m_bFocussedOnce = true; + if (m_document) + m_document->Show(); + } +} + +void UIScene_SettingsUIMenu::handleLoseFocus() +{ + if (m_document) + m_document->Hide(); +} + +void UIScene_SettingsUIMenu::tick() +{ + m_hasTickedOnce = true; + + UIScene::tick(); + + Rml::Context* ctx = RmlManager::Get().GetContext(); + if (!ctx || !bHasFocus) + return; + + ctx->ProcessMouseMove(g_KBMInput.GetMouseX(), g_KBMInput.GetMouseY(), 0); + + if (g_KBMInput.IsMouseButtonPressed(KeyboardMouseInput::MOUSE_LEFT)) + ctx->ProcessMouseButtonDown(0, 0); + if (g_KBMInput.IsMouseButtonReleased(KeyboardMouseInput::MOUSE_LEFT)) + ctx->ProcessMouseButtonUp(0, 0); + if (g_KBMInput.IsMouseButtonPressed(KeyboardMouseInput::MOUSE_RIGHT)) + ctx->ProcessMouseButtonDown(1, 0); + if (g_KBMInput.IsMouseButtonReleased(KeyboardMouseInput::MOUSE_RIGHT)) + ctx->ProcessMouseButtonUp(1, 0); + + int wheelDelta = g_KBMInput.GetMouseWheel(); + if (wheelDelta != 0) + ctx->ProcessMouseWheel(wheelDelta / -120, 0); + + RmlManager::Get().Update(); +} + +void UIScene_SettingsUIMenu::ProcessEvent(Rml::Event& event) +{ + if (event.GetId() == Rml::EventId::Click) + { + Rml::Element* el = event.GetCurrentElement(); + const Rml::String& id = el->GetId(); + + for (size_t i = 0; i < sizeof(s_toggles) / sizeof(s_toggles[0]); i++) + { + if (id == Rml::String(s_toggles[i].id) + "_toggle") + { + Rml::Element* row = el->GetParentNode(); + if (row) + row->SetClass("checked", !row->IsClassSet("checked")); + ui.PlayUISFX(eSFX_Press); + return; + } + } + } + else if (event.GetId() == Rml::EventId::Mousedown) + { + Rml::Element* el = event.GetCurrentElement(); + const Rml::String& id = el->GetId(); + + for (size_t i = 0; i < sizeof(s_sliderIds) / sizeof(s_sliderIds[0]); i++) + { + Rml::String trackId = Rml::String(s_sliderIds[i]) + "_track"; + Rml::String thumbId = Rml::String(s_sliderIds[i]) + "_thumb"; + if (id == trackId || id == thumbId) + { + m_dragSliderIndex = static_cast(i); + handleSliderMouseEvent(static_cast(i), event); + ui.PlayUISFX(eSFX_Scroll); + return; + } + } + } + else if (event.GetId() == Rml::EventId::Mousemove) + { + if (m_dragSliderIndex >= 0) + { + int oldValue = getSliderValue(s_sliderIds[m_dragSliderIndex]); + handleSliderMouseEvent(m_dragSliderIndex, event); + if (getSliderValue(s_sliderIds[m_dragSliderIndex]) != oldValue) + ui.PlayUISFX(eSFX_Scroll); + } + } + else if (event.GetId() == Rml::EventId::Mouseup) + { + m_dragSliderIndex = -1; + } +} + +static void saveToggle(Rml::ElementDocument* doc, int iPad, const ToggleEntry& t) +{ + Rml::Element* el = doc->GetElementById(t.id); + bool checked = el && el->IsClassSet("checked"); + app.SetGameSettings(iPad, t.setting, checked ? 1 : 0); +} + void UIScene_SettingsUIMenu::handleInput(int iPad, int key, bool repeat, bool pressed, bool released, bool &handled) { - ui.AnimateKeyPress(iPad, key, repeat, pressed, released); + Rml::Context* ctx = RmlManager::Get().GetContext(); + if (!ctx) + return; - switch(key) + if (!pressed) + return; + + switch (key) { - case ACTION_MENU_CANCEL: - if(pressed) - { - // check the checkboxes - app.SetGameSettings(m_iPad,eGameSetting_DisplayHUD,m_checkboxDisplayHUD.IsChecked()?1:0); - app.SetGameSettings(m_iPad,eGameSetting_DisplayHand,m_checkboxDisplayHand.IsChecked()?1:0); - app.SetGameSettings(m_iPad,eGameSetting_DisplaySplitscreenGamertags,m_checkboxShowSplitscreenGamertags.IsChecked()?1:0); - app.SetGameSettings(m_iPad,eGameSetting_ClassicCrafting,m_checkboxShowClassicCrafting.IsChecked()?1:0); - app.SetGameSettings(m_iPad,eGameSetting_DeathMessages,m_checkboxDisplayDeathMessages.IsChecked()?1:0); - app.SetGameSettings(m_iPad,eGameSetting_AnimatedCharacter,m_checkboxDisplayAnimatedCharacter.IsChecked()?1:0); - - // if the splitscreen vertical/horizontal has changed, need to update the scenes - if(app.GetGameSettings(m_iPad,eGameSetting_SplitScreenVertical)!=(m_checkboxSplitscreen.IsChecked()?1:0)) - { - // changed - app.SetGameSettings(m_iPad,eGameSetting_SplitScreenVertical,m_checkboxSplitscreen.IsChecked()?1:0); - - // close the xui scenes, so we don't have the navigate backed to menu at the wrong place - if(app.GetLocalPlayerCount()==2) - { - ui.CloseAllPlayersScenes(); - } - else - { - navigateBack(); - } - } - else - { - navigateBack(); - } - handled = true; - } + case ACTION_MENU_UP: + ctx->ProcessKeyDown(Rml::Input::KI_UP, 0); + handled = true; + break; + case ACTION_MENU_DOWN: + ctx->ProcessKeyDown(Rml::Input::KI_DOWN, 0); + handled = true; + break; + case ACTION_MENU_LEFT: + ctx->ProcessKeyDown(Rml::Input::KI_LEFT, 0); + handled = true; + break; + case ACTION_MENU_RIGHT: + ctx->ProcessKeyDown(Rml::Input::KI_RIGHT, 0); + handled = true; break; case ACTION_MENU_OK: -#ifdef __ORBIS__ - case ACTION_MENU_TOUCHPAD_PRESS: -#endif - sendInputToMovie(key, repeat, pressed, released); + ctx->ProcessKeyDown(Rml::Input::KI_RETURN, 0); + handled = true; break; - case ACTION_MENU_UP: - case ACTION_MENU_DOWN: - case ACTION_MENU_LEFT: - case ACTION_MENU_RIGHT: - sendInputToMovie(key, repeat, pressed, released); + case ACTION_MENU_CANCEL: + case ACTION_MENU_PAUSEMENU: + for (size_t i = 0; i < sizeof(s_toggles) / sizeof(s_toggles[0]); i++) + saveToggle(m_document, m_iPad, s_toggles[i]); + + if (app.GetGameSettings(m_iPad, eGameSetting_SplitScreenVertical) != (isToggleChecked("Splitscreen") ? 1 : 0)) + { + app.SetGameSettings(m_iPad, eGameSetting_SplitScreenVertical, isToggleChecked("Splitscreen") ? 1 : 0); + if (app.GetLocalPlayerCount() == 2) + ui.CloseAllPlayersScenes(); + else + navigateBack(); + } + else + { + navigateBack(); + } + handled = true; + break; + default: break; } } -void UIScene_SettingsUIMenu::handleSliderMove(F64 sliderId, F64 currentValue) +void UIScene_SettingsUIMenu::handleSliderMove(int sliderIndex, int value) { - WCHAR TempString[256]; - int value = static_cast(currentValue); - switch(static_cast(sliderId)) + int* member = (sliderIndex == 0) ? &m_uiSizeValue : &m_uiSizeSplitscreenValue; + const char* id = s_sliderIds[sliderIndex]; + int idsString = (sliderIndex == 0) ? IDS_SLIDER_UISIZE : IDS_SLIDER_UISIZESPLITSCREEN; + eGameSetting setting = (sliderIndex == 0) ? eGameSetting_UISize : eGameSetting_UISizeSplitscreen; + + *member = value; + Rml::String prefix = WideToUTF8(app.GetString(idsString)); + setSliderValue(id, prefix, value, 1, 3); + + if (value != app.GetGameSettings(m_iPad, setting) + 1) { - case eControl_UISize: - m_sliderUISize.handleSliderMove(value); - - swprintf( (WCHAR *)TempString, 256, L"%ls: %d", app.GetString( IDS_SLIDER_UISIZE ),value); - m_sliderUISize.setLabel(TempString); - - // is this different from the current value? - if(value != app.GetGameSettings(m_iPad,eGameSetting_UISize)+1) - { - app.SetGameSettings(m_iPad,eGameSetting_UISize,value-1); - // Apply the changes to the selected text position - ui.UpdateSelectedItemPos(m_iPad); - } - - break; - case eControl_UISizeSplitscreen: - m_sliderUISizeSplitscreen.handleSliderMove(value); - - swprintf( (WCHAR *)TempString, 256, L"%ls: %d", app.GetString( IDS_SLIDER_UISIZESPLITSCREEN ),value); - m_sliderUISizeSplitscreen.setLabel(TempString); - - if(value != app.GetGameSettings(m_iPad,eGameSetting_UISizeSplitscreen)+1) - { - // slider is 1 to 3 - app.SetGameSettings(m_iPad,eGameSetting_UISizeSplitscreen,value-1); - // Apply the changes to the selected text position - ui.UpdateSelectedItemPos(m_iPad); - } - - break; + app.SetGameSettings(m_iPad, setting, value - 1); + ui.UpdateSelectedItemPos(m_iPad); } } diff --git a/Minecraft.Client/Common/UI/UIScene_SettingsUIMenu.h b/Minecraft.Client/Common/UI/UIScene_SettingsUIMenu.h index a7635fec..15471482 100644 --- a/Minecraft.Client/Common/UI/UIScene_SettingsUIMenu.h +++ b/Minecraft.Client/Common/UI/UIScene_SettingsUIMenu.h @@ -1,55 +1,57 @@ #pragma once -#include "UIScene.h" +#pragma push_macro("byte") +#pragma push_macro("GetNextSibling") +#pragma push_macro("GetFirstChild") +#undef byte +#undef GetNextSibling +#undef GetFirstChild -class UIScene_SettingsUIMenu : public UIScene +#include "UIScene.h" +#include +#include + +class UIScene_SettingsUIMenu : public UIScene, public Rml::EventListener { private: - enum EControls - { - eControl_DisplayHUD, - eControl_DisplayHand, - eControl_DisplayDeathMessages, - eControl_DisplayAnimatedCharacter, - eControl_Splitscreen, - eControl_ShowSplitscreenGamertags, - eControl_ShowClassicCrafting, - eControl_UISize, - eControl_UISizeSplitscreen - }; + Rml::ElementDocument* m_document; - UIControl_CheckBox m_checkboxDisplayHUD, m_checkboxDisplayHand, m_checkboxDisplayDeathMessages, m_checkboxDisplayAnimatedCharacter, m_checkboxSplitscreen, m_checkboxShowSplitscreenGamertags, m_checkboxShowClassicCrafting; // Checkboxes - UIControl_Slider m_sliderUISize, m_sliderUISizeSplitscreen; // Sliders - UI_BEGIN_MAP_ELEMENTS_AND_NAMES(UIScene) - UI_MAP_ELEMENT( m_checkboxDisplayHUD, "DisplayHUD") - UI_MAP_ELEMENT( m_checkboxDisplayHand, "DisplayHand") - UI_MAP_ELEMENT( m_checkboxDisplayDeathMessages, "DisplayDeathMessages") - UI_MAP_ELEMENT( m_checkboxDisplayAnimatedCharacter, "DisplayAnimatedCharacter") - UI_MAP_ELEMENT( m_checkboxSplitscreen, "Splitscreen") - UI_MAP_ELEMENT( m_checkboxShowSplitscreenGamertags, "ShowSplitscreenGamertags") - UI_MAP_ELEMENT( m_checkboxShowClassicCrafting, "ShowClassicCrafting") + int m_uiSizeValue; + int m_uiSizeSplitscreenValue; + int m_dragSliderIndex; - UI_MAP_ELEMENT( m_sliderUISize, "UISize") - UI_MAP_ELEMENT( m_sliderUISizeSplitscreen, "UISizeSplitscreen") - UI_END_MAP_ELEMENTS_AND_NAMES() + void setToggleChecked(const Rml::String& id, bool checked); + bool isToggleChecked(const Rml::String& id); + void setSliderValue(const Rml::String& id, const Rml::String& labelPrefix, int value, int min, int max); + int getSliderValue(const Rml::String& id); + + void registerEvents(); + void deregisterEvents(); - bool m_bNotInGame; public: UIScene_SettingsUIMenu(int iPad, void *initData, UILayer *parentLayer); virtual ~UIScene_SettingsUIMenu(); - virtual EUIScene getSceneType() { return eUIScene_SettingsUIMenu;} - - virtual void updateTooltips(); + virtual EUIScene getSceneType() { return eUIScene_SettingsUIMenu; } + + virtual void tick(); virtual void updateComponents(); -protected: - // TODO: This should be pure virtual in this class - virtual wstring getMoviePath(); + virtual void gainFocus() override; + + void ProcessEvent(Rml::Event& event) override; + +protected: + virtual wstring getMoviePath() { return L""; } + + virtual void handleLoseFocus() override; -public: - // INPUT virtual void handleInput(int iPad, int key, bool repeat, bool pressed, bool released, bool &handled); - virtual void handleSliderMove(F64 sliderId, F64 currentValue); -}; \ No newline at end of file + virtual void handleSliderMove(int sliderIndex, int value); + void handleSliderMouseEvent(int sliderIndex, const Rml::Event& event); +}; + +#pragma pop_macro("GetFirstChild") +#pragma pop_macro("GetNextSibling") +#pragma pop_macro("byte") diff --git a/Minecraft.Client/Windows64/Libs/RmlUi/Backends/RmlUi_Renderer_DX12.cpp b/Minecraft.Client/Windows64/Libs/RmlUi/Backends/RmlUi_Renderer_DX12.cpp index f8b2c647..d55f58ca 100644 --- a/Minecraft.Client/Windows64/Libs/RmlUi/Backends/RmlUi_Renderer_DX12.cpp +++ b/Minecraft.Client/Windows64/Libs/RmlUi/Backends/RmlUi_Renderer_DX12.cpp @@ -1,4 +1,4 @@ -#include "RmlUi_Renderer_DX12.h" +#include "RmlUi_Renderer_DX12.h" #include "RmlUi_Backend.h" #include #include diff --git a/Minecraft.Client/Windows64/Libs/RmlUi/CMake/Utilities.cmake b/Minecraft.Client/Windows64/Libs/RmlUi/CMake/Utilities.cmake index ca7f6973..eab61b92 100644 --- a/Minecraft.Client/Windows64/Libs/RmlUi/CMake/Utilities.cmake +++ b/Minecraft.Client/Windows64/Libs/RmlUi/CMake/Utilities.cmake @@ -98,7 +98,11 @@ endfunction() - target: The name of the target to set ]] function(set_common_target_options target) - target_compile_features(${target} PUBLIC cxx_std_17) + if(MSVC) + set_target_properties(${target} PROPERTIES CXX_STANDARD 17 CXX_STANDARD_REQUIRED ON) + else() + target_compile_features(${target} PUBLIC cxx_std_17) + endif() set_target_properties(${target} PROPERTIES C_EXTENSIONS OFF CXX_EXTENSIONS OFF) if(RMLUI_COMPILER_OPTIONS) diff --git a/Minecraft.Client/Windows64/Libs/RmlUi/Samples/basic/animation/src/main.cpp b/Minecraft.Client/Windows64/Libs/RmlUi/Samples/basic/animation/src/main.cpp index 022c7ca8..4e55aec3 100644 --- a/Minecraft.Client/Windows64/Libs/RmlUi/Samples/basic/animation/src/main.cpp +++ b/Minecraft.Client/Windows64/Libs/RmlUi/Samples/basic/animation/src/main.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/Minecraft.Client/Windows64/Libs/RmlUi/Samples/basic/benchmark/src/main.cpp b/Minecraft.Client/Windows64/Libs/RmlUi/Samples/basic/benchmark/src/main.cpp index 7605b6db..7c2b1935 100644 --- a/Minecraft.Client/Windows64/Libs/RmlUi/Samples/basic/benchmark/src/main.cpp +++ b/Minecraft.Client/Windows64/Libs/RmlUi/Samples/basic/benchmark/src/main.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/Minecraft.Client/Windows64/Libs/RmlUi/Samples/basic/data_binding/src/main.cpp b/Minecraft.Client/Windows64/Libs/RmlUi/Samples/basic/data_binding/src/main.cpp index 2af4a0c6..f505f5f2 100644 --- a/Minecraft.Client/Windows64/Libs/RmlUi/Samples/basic/data_binding/src/main.cpp +++ b/Minecraft.Client/Windows64/Libs/RmlUi/Samples/basic/data_binding/src/main.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/Minecraft.Client/Windows64/Libs/RmlUi/Samples/basic/demo/src/main.cpp b/Minecraft.Client/Windows64/Libs/RmlUi/Samples/basic/demo/src/main.cpp index b9ee669b..15a53947 100644 --- a/Minecraft.Client/Windows64/Libs/RmlUi/Samples/basic/demo/src/main.cpp +++ b/Minecraft.Client/Windows64/Libs/RmlUi/Samples/basic/demo/src/main.cpp @@ -1,4 +1,4 @@ -#include "DemoEventListener.h" +#include "DemoEventListener.h" #include "DemoWindow.h" #include #include diff --git a/Minecraft.Client/Windows64/Libs/RmlUi/Samples/basic/effects/src/main.cpp b/Minecraft.Client/Windows64/Libs/RmlUi/Samples/basic/effects/src/main.cpp index 2581cb43..eb6e0f81 100644 --- a/Minecraft.Client/Windows64/Libs/RmlUi/Samples/basic/effects/src/main.cpp +++ b/Minecraft.Client/Windows64/Libs/RmlUi/Samples/basic/effects/src/main.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/Minecraft.Client/Windows64/Libs/RmlUi/Samples/basic/harfbuzz/src/main.cpp b/Minecraft.Client/Windows64/Libs/RmlUi/Samples/basic/harfbuzz/src/main.cpp index 3a153420..ca1c6de8 100644 --- a/Minecraft.Client/Windows64/Libs/RmlUi/Samples/basic/harfbuzz/src/main.cpp +++ b/Minecraft.Client/Windows64/Libs/RmlUi/Samples/basic/harfbuzz/src/main.cpp @@ -1,4 +1,4 @@ -#include "FontEngineInterfaceHarfBuzz.h" +#include "FontEngineInterfaceHarfBuzz.h" #include #include #include diff --git a/Minecraft.Client/Windows64/Libs/RmlUi/Samples/basic/ime/src/main.cpp b/Minecraft.Client/Windows64/Libs/RmlUi/Samples/basic/ime/src/main.cpp index fa78ed91..ea4d9435 100644 --- a/Minecraft.Client/Windows64/Libs/RmlUi/Samples/basic/ime/src/main.cpp +++ b/Minecraft.Client/Windows64/Libs/RmlUi/Samples/basic/ime/src/main.cpp @@ -1,4 +1,4 @@ -#include +#include #if !defined RMLUI_IME_SAMPLE_USE_NOTO_FONTS #include "SystemFontWin32.h" #endif diff --git a/Minecraft.Client/Windows64/Libs/RmlUi/Source/Core/EventDispatcher.cpp b/Minecraft.Client/Windows64/Libs/RmlUi/Source/Core/EventDispatcher.cpp index c621de50..0ec8c9c1 100644 --- a/Minecraft.Client/Windows64/Libs/RmlUi/Source/Core/EventDispatcher.cpp +++ b/Minecraft.Client/Windows64/Libs/RmlUi/Source/Core/EventDispatcher.cpp @@ -34,7 +34,10 @@ EventDispatcher::~EventDispatcher() { // Detach from all event dispatchers for (const auto& event : listeners) - event.listener->OnDetach(element); + { + if (event.listener) + event.listener->OnDetach(element); + } } void EventDispatcher::AttachEvent(const EventId id, EventListener* listener, const bool in_capture_phase) @@ -64,7 +67,10 @@ void EventDispatcher::DetachEvent(const EventId id, EventListener* listener, con void EventDispatcher::DetachAllEvents() { for (const auto& event : listeners) - event.listener->OnDetach(element); + { + if (event.listener) + event.listener->OnDetach(element); + } listeners.clear(); @@ -198,26 +204,32 @@ void EventDispatcher::CollectListeners(int dom_distance_from_target, const Event const bool in_target_phase = (dom_distance_from_target == 0); - if (in_target_phase) - { - // Listeners always attach to target phase, but make sure the event can actually execute in target phase. - if ((int)event_executes_in_phases & (int)EventPhase::Target) + if (in_target_phase) { + // Listeners always attach to target phase, but make sure the event can actually execute in target phase. + if ((int)event_executes_in_phases & (int)EventPhase::Target) + { + for (auto it = begin; it != end; ++it) + { + if (auto* listener = it->listener.get()) + collect_listeners.emplace_back(element, listener, dom_distance_from_target, false); + } + } + } + else + { + // Iterate through all the listeners and collect those matching the event execution phase. for (auto it = begin; it != end; ++it) - collect_listeners.emplace_back(element, it->listener, dom_distance_from_target, false); + { + // Listeners will either attach to capture or bubble phase, make sure the event can execute in the same phase. + const EventPhase listener_executes_in_phase = (it->in_capture_phase ? EventPhase::Capture : EventPhase::Bubble); + if ((int)event_executes_in_phases & (int)listener_executes_in_phase) + { + if (auto* listener = it->listener.get()) + collect_listeners.emplace_back(element, listener, dom_distance_from_target, it->in_capture_phase); + } + } } - } - else - { - // Iterate through all the listeners and collect those matching the event execution phase. - for (auto it = begin; it != end; ++it) - { - // Listeners will either attach to capture or bubble phase, make sure the event can execute in the same phase. - const EventPhase listener_executes_in_phase = (it->in_capture_phase ? EventPhase::Capture : EventPhase::Bubble); - if ((int)event_executes_in_phases & (int)listener_executes_in_phase) - collect_listeners.emplace_back(element, it->listener, dom_distance_from_target, it->in_capture_phase); - } - } } String EventDispatcher::ToString() const diff --git a/Minecraft.Client/Windows64/Libs/RmlUi/Source/Core/EventDispatcher.h b/Minecraft.Client/Windows64/Libs/RmlUi/Source/Core/EventDispatcher.h index d887b51b..a3ca8b33 100644 --- a/Minecraft.Client/Windows64/Libs/RmlUi/Source/Core/EventDispatcher.h +++ b/Minecraft.Client/Windows64/Libs/RmlUi/Source/Core/EventDispatcher.h @@ -1,6 +1,7 @@ #pragma once #include "../../Include/RmlUi/Core/Event.h" +#include "../../Include/RmlUi/Core/EventListener.h" #include "../../Include/RmlUi/Core/Types.h" namespace Rml { @@ -11,12 +12,12 @@ struct CollectedListener; struct EventListenerEntry { EventListenerEntry(const EventId id, EventListener* listener, const bool in_capture_phase) : - id(id), in_capture_phase(in_capture_phase), listener(listener) + id(id), in_capture_phase(in_capture_phase), listener(listener ? listener->GetObserverPtr() : ObserverPtr()) {} EventId id; bool in_capture_phase; - EventListener* listener; + ObserverPtr listener; }; /** diff --git a/Minecraft.Client/Windows64/Libs/RmlUi/Source/Core/Factory.cpp b/Minecraft.Client/Windows64/Libs/RmlUi/Source/Core/Factory.cpp index e360e347..4690e354 100644 --- a/Minecraft.Client/Windows64/Libs/RmlUi/Source/Core/Factory.cpp +++ b/Minecraft.Client/Windows64/Libs/RmlUi/Source/Core/Factory.cpp @@ -412,10 +412,6 @@ bool Factory::InstanceElementText(Element* parent, const String& in_text) text_element->SetText(text); - // Store original untranslated text for runtime re-translation support. - if (in_text.size() > 2 && in_text[0] == '[') - element->SetAttribute("data-rml-source", in_text); - // Add to active node. parent->AppendChild(std::move(element)); } diff --git a/Minecraft.Client/Windows64/Libs/RmlUi/Tests/Source/Benchmarks/FontEffect.cpp b/Minecraft.Client/Windows64/Libs/RmlUi/Tests/Source/Benchmarks/FontEffect.cpp index 77093b02..9feab9cd 100644 --- a/Minecraft.Client/Windows64/Libs/RmlUi/Tests/Source/Benchmarks/FontEffect.cpp +++ b/Minecraft.Client/Windows64/Libs/RmlUi/Tests/Source/Benchmarks/FontEffect.cpp @@ -1,4 +1,4 @@ -#include "../Common/TestsShell.h" +#include "../Common/TestsShell.h" #include #include #include diff --git a/Minecraft.Client/Windows64/Libs/RmlUi/Tests/Source/UnitTests/Core.cpp b/Minecraft.Client/Windows64/Libs/RmlUi/Tests/Source/UnitTests/Core.cpp index cc17b471..4a59b603 100644 --- a/Minecraft.Client/Windows64/Libs/RmlUi/Tests/Source/UnitTests/Core.cpp +++ b/Minecraft.Client/Windows64/Libs/RmlUi/Tests/Source/UnitTests/Core.cpp @@ -1,4 +1,4 @@ -#include "../Common/TestsInterface.h" +#include "../Common/TestsInterface.h" #include "../Common/TestsShell.h" #include #include @@ -302,7 +302,7 @@ TEST_CASE("core.release_resources") CHECK(counters.generate_texture == counter_generate_before); // However, when we display a non-ASCII character not part of the initial cache, the font texture needs to be regenerated. - element->SetInnerRML(reinterpret_cast(u8"π")); + element->SetInnerRML(reinterpret_cast(u8"p")); TestsShell::RenderLoop(); CHECK(counters.generate_texture == counter_generate_before + 1); CHECK(counters.release_texture == counter_release_before + 1); diff --git a/Minecraft.Client/cmake/sources/Windows.cmake b/Minecraft.Client/cmake/sources/Windows.cmake index 357e987e..55d5fdda 100644 --- a/Minecraft.Client/cmake/sources/Windows.cmake +++ b/Minecraft.Client/cmake/sources/Windows.cmake @@ -123,6 +123,8 @@ set(_MINECRAFT_CLIENT_WINDOWS_COMMON_UI_SCENES "${CMAKE_CURRENT_SOURCE_DIR}/Common/UI/UIScene_Keyboard.h" "${CMAKE_CURRENT_SOURCE_DIR}/Common/UI/UIScene_MessageBox.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/Common/UI/UIScene_MessageBox.h" + "${CMAKE_CURRENT_SOURCE_DIR}/Common/UI/UIScene_RmlBase.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/Common/UI/UIScene_RmlBase.h" "${CMAKE_CURRENT_SOURCE_DIR}/Common/UI/UIScene_QuadrantSignin.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/Common/UI/UIScene_QuadrantSignin.h" "${CMAKE_CURRENT_SOURCE_DIR}/Common/UI/UIScene_Timer.cpp"