diff --git a/Minecraft.Client/Assets/UI/MessageBox.rcss b/Minecraft.Client/Assets/UI/MessageBox.rcss new file mode 100644 index 00000000..650b1412 --- /dev/null +++ b/Minecraft.Client/Assets/UI/MessageBox.rcss @@ -0,0 +1,84 @@ +body +{ + width: 100%; + height: 100%; + font-family: Minecraft Default; + font-size: 14dp; + color: #ffffff; + background: transparent; + display: flex; + align-items: center; + justify-content: center; +} + +div#message_box +{ + width: 624dp; + height: auto; + margin: auto; + padding: 40dp 48dp; + decorator: image(images/lce/frame_MessageBox_background.png); + display: flex; + flex-direction: column; + align-items: center; +} + +p#title +{ + font-size: 31dp; + color: #333333; + margin-bottom: 23dp; + text-align: left; + width: 100%; +} + +div#text_container +{ + width: 100%; + height: auto; + max-height: 400dp; + overflow: auto; + margin-bottom: 23dp; + padding: 8dp; +} + +p#description +{ + font-size: 18dp; + color: #333333; + line-height: 1.5; + white-space: pre-wrap; +} + +div#buttons +{ + width: 100%; + display: flex; + flex-direction: column; + align-items: center; +} + +button +{ + display: block; + width: 674dp; + height: 60dp; + margin-bottom: 15dp; + color: #ffffff; + font-size: 36dp; + text-align: center; + line-height: 60dp; + cursor: pointer; + background: transparent; + decorator: image(images/lce/Button/MainMenuButton_Norm.png); +} + +button:hover +{ + decorator: image(images/lce/Button/MainMenuButton_Over.png); +} + +button:last-child +{ + margin-bottom: 0; +} diff --git a/Minecraft.Client/Assets/UI/MessageBox.rml b/Minecraft.Client/Assets/UI/MessageBox.rml new file mode 100644 index 00000000..45c79c5f --- /dev/null +++ b/Minecraft.Client/Assets/UI/MessageBox.rml @@ -0,0 +1,20 @@ + + + Message Box + + + +
+

+
+

+
+
+ + + + +
+
+ +
diff --git a/Minecraft.Client/Assets/UI/PauseMenu.rcss b/Minecraft.Client/Assets/UI/PauseMenu.rcss index 00a6a35d..6c6449c6 100644 --- a/Minecraft.Client/Assets/UI/PauseMenu.rcss +++ b/Minecraft.Client/Assets/UI/PauseMenu.rcss @@ -56,13 +56,15 @@ div#exit_dialog display: none; width: 100%; margin-top: 16dp; - text-align: center; + text-align: left; + padding: 24dp 32dp; + decorator: image(images/lce/frame_MessageBox_background.png); } p#exit_text { font-size: 31dp; - color: #ffffff; + color: #333333; margin-bottom: 23dp; } @@ -70,26 +72,22 @@ div#exit_buttons { width: 100%; display: flex; - justify-content: center; - gap: 10dp; - flex-wrap: wrap; + flex-direction: column; + align-items: center; } button#exit_save, button#exit_nosave, button#exit_cancel { - display: inline-block; - width: auto; - min-width: 233dp; - height: 58dp; - margin: 0; - padding-left: 29dp; - padding-right: 29dp; + display: block; + width: 524dp; + height: 60dp; + margin-bottom: 11dp; color: #ffffff; font-size: 36dp; text-align: center; - line-height: 58dp; + line-height: 60dp; cursor: pointer; background: transparent; decorator: image(images/lce/Button/MainMenuButton_Norm.png); @@ -103,18 +101,25 @@ button#exit_cancel:hover decorator: image(images/lce/Button/MainMenuButton_Over.png); } +button#exit_cancel +{ + margin-bottom: 0; +} + div#save_dialog { display: none; width: 100%; margin-top: 16dp; - text-align: center; + text-align: left; + padding: 24dp 32dp; + decorator: image(images/new/frame_background.png); } p#save_text { - font-size: 36dp; - color: #ffffff; + font-size: 31dp; + color: #333333; margin-bottom: 23dp; } @@ -122,24 +127,21 @@ div#save_buttons { width: 100%; display: flex; - justify-content: center; - gap: 10dp; + flex-direction: column; + align-items: center; } button#save_cancel, button#save_confirm { - display: inline-block; - width: auto; - min-width: 204dp; - height: 58dp; - margin: 0; - padding-left: 29dp; - padding-right: 29dp; + display: block; + width: 524dp; + height: 60dp; + margin-bottom: 11dp; color: #ffffff; font-size: 36dp; text-align: center; - line-height: 58dp; + line-height: 60dp; cursor: pointer; background: transparent; decorator: image(images/lce/Button/MainMenuButton_Norm.png); @@ -151,3 +153,8 @@ button#save_confirm:hover color: #ffff00; decorator: image(images/lce/Button/MainMenuButton_Over.png); } + +button#save_confirm +{ + margin-bottom: 0; +} diff --git a/Minecraft.Client/Assets/UI/images/lce/frame_MessageBox_background.png b/Minecraft.Client/Assets/UI/images/lce/frame_MessageBox_background.png new file mode 100644 index 00000000..f7553715 Binary files /dev/null and b/Minecraft.Client/Assets/UI/images/lce/frame_MessageBox_background.png differ diff --git a/Minecraft.Client/Common/UI/UIScene_MessageBox.cpp b/Minecraft.Client/Common/UI/UIScene_MessageBox.cpp index b816fda8..3b1b0e5b 100644 --- a/Minecraft.Client/Common/UI/UIScene_MessageBox.cpp +++ b/Minecraft.Client/Common/UI/UIScene_MessageBox.cpp @@ -1,160 +1,282 @@ #include "UI.h" + +#pragma push_macro("byte") +#pragma push_macro("GetNextSibling") +#pragma push_macro("GetFirstChild") +#undef byte +#undef GetNextSibling +#undef GetFirstChild + #include "UIScene_MessageBox.h" +#include "RmlManager.h" +#include "../../Windows64/KeyboardMouseInput.h" +#include +#include -UIScene_MessageBox::UIScene_MessageBox(int iPad, void *initData, UILayer *parentLayer) : UIScene(iPad, parentLayer) +#pragma pop_macro("GetFirstChild") +#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) + , m_buttonCount(0) + , m_Func(nullptr) + , m_lpParam(nullptr) { - // Setup all the Iggy references we need for this scene - initialiseMovie(); - MessageBoxInfo *param = static_cast(initData); - m_buttonCount = param->uiOptionC; - - IggyDataValue result; - IggyDataValue value[2]; - value[0].type = IGGY_DATATYPE_number; - value[0].number = param->uiOptionC; - - value[1].type = IGGY_DATATYPE_number; - value[1].number = param->dwFocusButton; - IggyResult out = IggyPlayerCallMethodRS ( getMovie() , &result, IggyPlayerRootPath( getMovie() ), m_funcInit , 2 , value ); - - int buttonIndex = 0; - if(param->uiOptionC > 3) - { - m_buttonButtons[eControl_Button0].init(app.GetString(param->uiOptionA[buttonIndex]),buttonIndex); - ++buttonIndex; - } - if(param->uiOptionC > 2) - { - m_buttonButtons[eControl_Button1].init(app.GetString(param->uiOptionA[buttonIndex]),buttonIndex); - ++buttonIndex; - } - if(param->uiOptionC > 1) - { - m_buttonButtons[eControl_Button2].init(app.GetString(param->uiOptionA[buttonIndex]),buttonIndex); - ++buttonIndex; - } - m_buttonButtons[eControl_Button3].init(app.GetString(param->uiOptionA[buttonIndex]),buttonIndex); - - m_labelTitle.init(app.GetString(param->uiTitle)); - m_labelContent.init(app.GetString(param->uiText)); - - out = IggyPlayerCallMethodRS ( getMovie() , &result, IggyPlayerRootPath( getMovie() ), m_funcAutoResize , 0 , nullptr ); - m_Func = param->Func; m_lpParam = param->lpParam; + m_buttonCount = param->uiOptionC; - parentLayer->addComponent(iPad,eUIComponent_MenuBackground); + Rml::Context* ctx = RmlManager::Get().GetContext(); + if (!ctx) + { + app.DebugPrintf("[RmlMsgBox] No RmlUi context available\n"); + return; + } - // 4J-TomK - rebuild touch after auto resize -#ifdef __PSVITA__ - ui.TouchBoxRebuild(this); -#endif + m_document = ctx->LoadDocument("MessageBox.rml"); + if (!m_document) + { + app.DebugPrintf("[RmlMsgBox] Failed to load MessageBox.rml\n"); + return; + } + + app.DebugPrintf("[RmlMsgBox] Document loaded OK\n"); + + m_document->GetElementById("button0")->AddEventListener(Rml::EventId::Click, this); + m_document->GetElementById("button1")->AddEventListener(Rml::EventId::Click, this); + m_document->GetElementById("button2")->AddEventListener(Rml::EventId::Click, this); + m_document->GetElementById("button3")->AddEventListener(Rml::EventId::Click, this); + + wstring titleText = app.GetString(param->uiTitle); + wstring descText = app.GetString(param->uiText); + + auto* titleEl = m_document->GetElementById("title"); + auto* descEl = m_document->GetElementById("description"); + + Rml::String titleUtf8(titleText.begin(), titleText.end()); + Rml::String descUtf8(descText.begin(), descText.end()); + + if (titleEl) titleEl->SetInnerRML(titleUtf8); + if (descEl) descEl->SetInnerRML(descUtf8); + + int buttonIndex = 0; + 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]->SetProperty("display", "none"); + } + + if (m_buttonCount > 3 && buttons[0]) + { + wstring label = app.GetString(param->uiOptionA[buttonIndex]); + buttons[0]->SetInnerRML(Rml::String(label.begin(), label.end())); + buttons[0]->SetProperty("display", "block"); + ++buttonIndex; + } + if (m_buttonCount > 2 && buttons[1]) + { + wstring label = app.GetString(param->uiOptionA[buttonIndex]); + buttons[1]->SetInnerRML(Rml::String(label.begin(), label.end())); + buttons[1]->SetProperty("display", "block"); + ++buttonIndex; + } + if (m_buttonCount > 1 && buttons[2]) + { + wstring label = app.GetString(param->uiOptionA[buttonIndex]); + buttons[2]->SetInnerRML(Rml::String(label.begin(), label.end())); + buttons[2]->SetProperty("display", "block"); + ++buttonIndex; + } + if (buttons[3]) + { + wstring label = app.GetString(param->uiOptionA[buttonIndex]); + buttons[3]->SetInnerRML(Rml::String(label.begin(), label.end())); + buttons[3]->SetProperty("display", "block"); + } + + int focusButton = param->dwFocusButton; + if (focusButton >= 0 && focusButton < 4 && buttons[focusButton]) + buttons[focusButton]->Focus(); + + m_document->Show(); + + parentLayer->addComponent(iPad, eUIComponent_MenuBackground); } 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); + m_document->Close(); + m_document = nullptr; + } + m_parentLayer->removeComponent(eUIComponent_MenuBackground); } -wstring UIScene_MessageBox::getMoviePath() +void UIScene_MessageBox::gainFocus() { - if(app.GetLocalPlayerCount() > 1 && !m_parentLayer->IsFullscreenGroup()) + if (!bHasFocus && stealsFocus()) { - return L"MessageBoxSplit"; - } - else - { - return L"MessageBox"; + bHasFocus = true; + updateTooltips(); + updateComponents(); + handleGainFocus(m_bFocussedOnce); + if (bHasFocus) + m_bFocussedOnce = true; + + if (m_document) + m_document->Show(); } } -void UIScene_MessageBox::updateTooltips() +void UIScene_MessageBox::handleLoseFocus() { - ui.SetTooltips( m_parentLayer->IsFullscreenGroup()?XUSER_INDEX_ANY:m_iPad, IDS_TOOLTIPS_SELECT, IDS_TOOLTIPS_CANCEL); + if (m_document) + m_document->Hide(); } -void UIScene_MessageBox::handleReload() +void UIScene_MessageBox::reloadMovie(bool force) { - IggyDataValue result; - IggyDataValue value[2]; - value[0].type = IGGY_DATATYPE_number; - value[0].number = m_buttonCount; +} - value[1].type = IGGY_DATATYPE_number; - value[1].number = static_cast(getControlFocus()); - IggyResult out = IggyPlayerCallMethodRS ( getMovie() , &result, IggyPlayerRootPath( getMovie() ), m_funcInit , 2 , value ); +void UIScene_MessageBox::tick() +{ + m_hasTickedOnce = true; - out = IggyPlayerCallMethodRS ( getMovie() , &result, IggyPlayerRootPath( getMovie() ), m_funcAutoResize , 0 , nullptr ); + 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_MessageBox::render(S32 width, S32 height, C4JRender::eViewportType viewport) +{ } void UIScene_MessageBox::handleInput(int iPad, int key, bool repeat, bool pressed, bool released, bool &handled) { - //app.DebugPrintf("UIScene_DebugOverlay handling input for pad %d, key %d, down- %s, pressed- %s, released- %s\n", iPad, key, down?"TRUE":"FALSE", pressed?"TRUE":"FALSE", released?"TRUE":"FALSE"); - ui.AnimateKeyPress(m_iPad, key, repeat, pressed, released); - switch(key) + Rml::Context* ctx = RmlManager::Get().GetContext(); + if (!ctx) + return; + + if (!pressed) + return; + + switch (key) { - case ACTION_MENU_CANCEL: - if(pressed) - { - navigateBack(); - if(m_Func) m_Func(m_lpParam, iPad, C4JStorage::EMessage_Cancelled); - } + 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_OK: -#ifdef __ORBIS__ - case ACTION_MENU_TOUCHPAD_PRESS: -#endif - sendInputToMovie(key, repeat, pressed, released); + if (g_KBMInput.IsKeyPressed(VK_RETURN)) + { + ctx->ProcessKeyDown(Rml::Input::KI_RETURN, 0); + handled = true; + } break; - case ACTION_MENU_UP: - case ACTION_MENU_DOWN: - sendInputToMovie(key, repeat, pressed, released); - break; - } - handled = true; -} - -void UIScene_MessageBox::handlePress(F64 controlId, F64 childId) -{ - C4JStorage::EMessageResult result = C4JStorage::EMessage_Cancelled; - switch(static_cast(controlId)) + case ACTION_MENU_CANCEL: { - case 0: - result = C4JStorage::EMessage_ResultAccept; - break; - case 1: - result = C4JStorage::EMessage_ResultDecline; - break; - case 2: - result = C4JStorage::EMessage_ResultThirdOption; - break; - case 3: - result = C4JStorage::EMessage_ResultFourthOption; + C4JStorage::EMessageResult result = C4JStorage::EMessage_Cancelled; + int( *tmpFunc)(LPVOID,int,const C4JStorage::EMessageResult) = m_Func; + LPVOID tmpParam = m_lpParam; + int tmpPad = m_iPad; + + navigateBack(); + if (tmpFunc) tmpFunc(tmpParam, tmpPad, result); + handled = true; + break; + } + default: break; } - - navigateBack(); - if(m_Func) m_Func(m_lpParam, m_iPad, result); } bool UIScene_MessageBox::hasFocus(int iPad) { - // 4J-JEV: Fix for PS4 #5204 - [TRC][R4033] The application can be locked up by second user logging out of the system. if (m_iPad == 255) - { - // Message box is for everyone return bHasFocus; - } else if (ProfileManager.IsSignedIn(m_iPad)) - { - // Owner is still present return bHasFocus && (iPad == m_iPad); - } else - { - // Original owner has left so let everyone interact return bHasFocus; +} + +void UIScene_MessageBox::ProcessEvent(Rml::Event& event) +{ + const Rml::String& id = event.GetCurrentElement()->GetId(); + + if (event == Rml::EventId::Click) + { + if (id == "button0") OnButtonClicked(0); + else if (id == "button1") OnButtonClicked(1); + else if (id == "button2") OnButtonClicked(2); + else if (id == "button3") OnButtonClicked(3); } -} \ No newline at end of file +} + +void UIScene_MessageBox::OnButtonClicked(int buttonIndex) +{ + C4JStorage::EMessageResult result = C4JStorage::EMessage_Cancelled; + switch (buttonIndex) + { + case 0: result = C4JStorage::EMessage_ResultAccept; break; + case 1: result = C4JStorage::EMessage_ResultDecline; break; + case 2: result = C4JStorage::EMessage_ResultThirdOption; break; + case 3: result = C4JStorage::EMessage_ResultFourthOption; break; + } + + ui.PlayUISFX(eSFX_Press); + + int( *tmpFunc)(LPVOID,int,const C4JStorage::EMessageResult) = m_Func; + LPVOID tmpParam = m_lpParam; + int tmpPad = m_iPad; + + navigateBack(); + if (tmpFunc) tmpFunc(tmpParam, tmpPad, result); +} + +void UIScene_MessageBox::navigateBack() +{ + UIScene::navigateBack(); +} diff --git a/Minecraft.Client/Common/UI/UIScene_MessageBox.h b/Minecraft.Client/Common/UI/UIScene_MessageBox.h index c10f6ab8..c2bc5967 100644 --- a/Minecraft.Client/Common/UI/UIScene_MessageBox.h +++ b/Minecraft.Client/Common/UI/UIScene_MessageBox.h @@ -1,60 +1,52 @@ #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_MessageBox : public UIScene +class UIScene_MessageBox : public UIScene, public Rml::EventListener { -private: - enum EControls - { - eControl_Button0, - eControl_Button1, - eControl_Button2, - eControl_Button3, - - eControl_COUNT - }; - - int( *m_Func)(LPVOID,int,const C4JStorage::EMessageResult); - LPVOID m_lpParam; - int m_buttonCount; - - UIControl_Button m_buttonButtons[eControl_COUNT]; - UIControl_Label m_labelTitle, m_labelContent; - IggyName m_funcInit, m_funcAutoResize; - UI_BEGIN_MAP_ELEMENTS_AND_NAMES(UIScene) - UI_MAP_ELEMENT( m_buttonButtons[eControl_Button0], "Button0") - UI_MAP_ELEMENT( m_buttonButtons[eControl_Button1], "Button1") - UI_MAP_ELEMENT( m_buttonButtons[eControl_Button2], "Button2") - UI_MAP_ELEMENT( m_buttonButtons[eControl_Button3], "Button3") - - UI_MAP_ELEMENT( m_labelTitle, "Title") - UI_MAP_ELEMENT( m_labelContent, "Content") - - UI_MAP_NAME( m_funcInit, L"Init") - UI_MAP_NAME( m_funcAutoResize, L"AutoResize") - UI_END_MAP_ELEMENTS_AND_NAMES() public: UIScene_MessageBox(int iPad, void *initData, UILayer *parentLayer); - ~UIScene_MessageBox(); + virtual ~UIScene_MessageBox(); - virtual EUIScene getSceneType() { return eUIScene_MessageBox;} + virtual EUIScene getSceneType() { return eUIScene_MessageBox; } - // Returns true if lower scenes in this scenes layer, or in any layer below this scenes layers should be hidden - virtual bool hidesLowerScenes() { return false; } + virtual bool hidesLowerScenes() { return false; } virtual bool blocksInput() { return true; } -protected: - // TODO: This should be pure virtual in this class - virtual wstring getMoviePath(); - - virtual void updateTooltips(); + virtual void tick(); + virtual void render(S32 width, S32 height, C4JRender::eViewportType viewport); -public: - virtual void handleReload(); - virtual void handleInput(int iPad, int key, bool repeat, bool pressed, bool released, bool &handled); + 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 ProcessEvent(Rml::Event& event) override; + protected: - void handlePress(F64 controlId, F64 childId); -}; \ No newline at end of file + virtual wstring getMoviePath() { return L""; } + virtual void handleLoseFocus() override; + + 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; +}; + +#pragma pop_macro("GetFirstChild") +#pragma pop_macro("GetNextSibling") +#pragma pop_macro("byte")