From f5481388d7d2ec6bf5cda27ce0f189d8acbd50a7 Mon Sep 17 00:00:00 2001 From: past-due <30942300+past-due@users.noreply.github.com> Date: Thu, 19 Oct 2023 18:14:51 -0400 Subject: [PATCH] intelmap: Refactor Intelligence screen as overlay screen --- src/hci.cpp | 2 +- src/intelmap.cpp | 718 ++++++++++++++++++++++++++++------------------ src/intelmap.h | 3 - src/multimenu.cpp | 8 +- src/multimenu.h | 1 + 5 files changed, 441 insertions(+), 291 deletions(-) diff --git a/src/hci.cpp b/src/hci.cpp index cfe7e4f742c..3b78dc942e0 100644 --- a/src/hci.cpp +++ b/src/hci.cpp @@ -1575,7 +1575,7 @@ INT_RETVAL intRunWidgets() intProcessDesign(retID); break; case INT_INTELMAP: - intProcessIntelMap(retID); + // no-op here break; case INT_TRANSPORTER: intProcessTransporter(retID); diff --git a/src/intelmap.cpp b/src/intelmap.cpp index 61c185aab6a..974f9220369 100644 --- a/src/intelmap.cpp +++ b/src/intelmap.cpp @@ -1,7 +1,7 @@ /* This file is part of Warzone 2100. Copyright (C) 1999-2004 Eidos Interactive - Copyright (C) 2005-2020 Warzone 2100 Project + Copyright (C) 2005-2023 Warzone 2100 Project Warzone 2100 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -126,16 +126,16 @@ /* the widget screen */ extern std::shared_ptr psWScreen; +static std::shared_ptr intelligenceOverlayScreen; -static UDWORD messageID; static bool immediateMessage = false; //flags whether to open the Intel Screen with a message static bool playCurrent; /* functions declarations ****************/ -static bool intAddMessageForm(bool playCurrent); static const char* getMessageTitle(const MESSAGE& message); +static void StartMessageSequences(MESSAGE *psMessage, bool Start); /*Displays the buttons used on the intelligence map */ class IntMessageButton : public IntFancyButton { @@ -156,14 +156,21 @@ class IntMessageButton : public IntFancyButton return (pMessageTitle != nullptr) ? pMessageTitle : ""; } + MESSAGE* getMessage() const { return psMsg; } + + typedef std::function W_BUTTON_ONCLICK_FUNC; + void setOnClickHandler(const W_BUTTON_ONCLICK_FUNC& onClickFunc) { onClickHandler = onClickFunc; } + +protected: + void released(W_CONTEXT *context, WIDGET_KEY mouseButton = WKEY_PRIMARY) override; + bool clickHeld(W_CONTEXT *psContext, WIDGET_KEY key) override; + protected: MESSAGE *psMsg; +private: + W_BUTTON_ONCLICK_FUNC onClickHandler; }; -/*deal with the actual button press - proxMsg is set to true if a proximity - button has been pressed*/ -static void intIntelButtonPressed(bool proxMsg, UDWORD id); - static void intDisplayPIEView(WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset); static void intDisplayFLICView(WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset); static void addVideoText(SEQ_DISPLAY *psSeqDisplay, UDWORD sequence); @@ -175,8 +182,6 @@ MESSAGE *psCurrentMsg = nullptr; #define PAUSE_DISPLAY_CONDITION (!bMultiPlayer) #define PAUSEMESSAGE_YOFFSET (0) - - // MARK: - WzMessageView class WzMessageView : public IntFormAnimated @@ -194,7 +199,6 @@ class WzMessageView : public IntFormAnimated public: std::function onCloseFunc; private: - MESSAGE *psCurrentMessage = nullptr; // not used? std::shared_ptr closeButton; }; @@ -222,8 +226,6 @@ void WzMessageView::geometryChanged() bool WzMessageView::initialize(MESSAGE *psMessage) { - psCurrentMessage = psMessage; - /* Add the close box */ W_BUTINIT sButInit; sButInit.id = IDINTMAP_CLOSE; @@ -361,316 +363,306 @@ void WzMessageView::close(bool animated) } } -// MARK: - +// MARK: - Intelligence screen -/* Add the Intelligence Map widgets to the widget screen */ -bool intAddIntelMap() +class W_INTELLIGENCEOVERLAY_FORM : public W_FORM { - bool Animate = true; - - //check playCurrent with psCurrentMsg - if (psCurrentMsg == nullptr) - { - playCurrent = false; - } - else - { - playCurrent = true; - } - - // Is the form already up? - if (widgGetFromID(psWScreen, IDINTMAP_FORM) != nullptr) - { - intRemoveIntelMapNoAnim(); - Animate = false; - } - else - { - audio_StopAll(); - } +protected: + W_INTELLIGENCEOVERLAY_FORM(W_FORMINIT const *init); + W_INTELLIGENCEOVERLAY_FORM(); +public: + static std::shared_ptr make(bool _playCurrent, UDWORD formID = 0); + void clicked(W_CONTEXT *psContext, WIDGET_KEY key) override; + void display(int xOffset, int yOffset) override; + void run(W_CONTEXT *psContext) override; + virtual void geometryChanged() override; - //add message to indicate game is paused - single player mode - if (PAUSE_DISPLAY_CONDITION) - { - if (widgGetFromID(psWScreen, IDINTMAP_PAUSELABEL) == nullptr) - { - W_LABINIT sLabInit; - sLabInit.id = IDINTMAP_PAUSELABEL; - sLabInit.formID = 0; - sLabInit.x = INTMAP_LABELX; - sLabInit.y = INTMAP_LABELY + PAUSEMESSAGE_YOFFSET; - sLabInit.width = INTMAP_LABELWIDTH; - sLabInit.height = INTMAP_LABELHEIGHT; - sLabInit.pText = WzString::fromUtf8(_("PAUSED")); - if (!widgAddLabel(psWScreen, &sLabInit)) - { - return false; - } - } - } +public: + void closeAnimated(std::function onCompleteHandler); - //set pause states before putting the interface up - setIntelligencePauseState(); +private: + void initialize(bool _playCurrent, bool animate); + std::shared_ptr createMultiMenuForm(); + void intIntelButtonPressed(const std::shared_ptr& button); + void intShowMessageView(MESSAGE *psMessage); - auto const &parent = psWScreen->psForm; +private: + std::shared_ptr multiMenuForm; + std::shared_ptr msgForm; + std::shared_ptr selectedMsgButton; + std::shared_ptr msgDetailsView; + bool isClosing = false; + bool delayedPlayCurrent = false; +}; - // Add the main Intelligence Map form - auto intMapForm = std::make_shared(Animate); // Do not animate the opening, if the window was already open. - parent->attach(intMapForm); - intMapForm->id = IDINTMAP_FORM; - intMapForm->setCalcLayout(LAMBDA_CALCLAYOUT_SIMPLE({ - psWidget->setGeometry(INTMAP_X, INTMAP_Y, INTMAP_WIDTH, INTMAP_HEIGHT); - })); +constexpr int OVERLAY_MULTIMENU_FORM_Y = 50; - if (!intAddMessageForm(playCurrent)) +void W_INTELLIGENCEOVERLAY_FORM::geometryChanged() +{ + if (multiMenuForm) { - return false; + multiMenuForm->callCalcLayout(); } - - if (bMultiPlayer && !MultiMenuUp && !playCurrent) + if (msgForm) { - intAddMultiMenu(); + msgForm->callCalcLayout(); + } + if (msgDetailsView) + { + msgDetailsView->callCalcLayout(); } - - return true; } -/* Add the Message sub form */ -static bool intAddMessageForm(bool _playCurrent) +std::shared_ptr W_INTELLIGENCEOVERLAY_FORM::createMultiMenuForm() { - if (selectedPlayer >= MAX_PLAYERS) { return true; } - - WIDGET *msgForm = widgGetFromID(psWScreen, IDINTMAP_FORM); + auto form = std::make_shared(); + form->id = MULTIMENU_FORM; - /* Add the Message form */ - auto msgList = IntListTabWidget::make(); - msgForm->attach(msgList); - msgList->id = IDINTMAP_MSGFORM; - msgList->setChildSize(OBJ_BUTWIDTH, OBJ_BUTHEIGHT); - msgList->setChildSpacing(OBJ_GAP, OBJ_GAP); - int msgListWidth = OBJ_BUTWIDTH * 5 + OBJ_GAP * 4; - msgList->setGeometry((msgForm->width() - msgListWidth) / 2, INTMAP_MSGY, msgListWidth, msgForm->height() - INTMAP_MSGY); + auto grid = intCreateMultiMenuWidget(); + form->attach(grid); - /* Add the message buttons */ - int nextButtonId = IDINTMAP_MSGSTART; - - //add each button - messageID = 0; - for (MESSAGE *psMessage = apsMessages[selectedPlayer]; psMessage != nullptr; psMessage = psMessage->psNext) - { - /*if (psMessage->type == MSG_TUTORIAL) - { - //tutorial cases should never happen - ASSERT( false, "Tutorial message in Intelligence screen!" ); - continue; - }*/ - if (psMessage->type == MSG_PROXIMITY) + std::weak_ptr weakGrid = grid; + form->setCalcLayout([weakGrid](WIDGET *form) { + auto psParent = form->parent(); + if (psParent == nullptr) { - //ignore proximity messages here - continue; - } - - auto button = std::make_shared(); - msgList->attach(button); - button->id = nextButtonId; - button->setMessage(psMessage); - msgList->addWidgetToLayout(button); - - /* if the current message matches psSelected lock the button */ - if (psMessage == psCurrentMsg) - { - messageID = nextButtonId; - button->setState(WBUT_LOCK); - msgList->setCurrentPage(msgList->pages() - 1); + return; } + auto strongGrid = weakGrid.lock(); + ASSERT_OR_RETURN(, strongGrid != nullptr, "No grid"); + auto width = std::min((int32_t)psParent->width() - 20, strongGrid->idealWidth()); + auto height = strongGrid->idealHeight(); + strongGrid->setGeometry(0, 0, width, height); + form->setGeometry((psParent->width() - width) / 2, OVERLAY_MULTIMENU_FORM_Y, width, height); + }); - /* Update the init struct for the next button */ - ++nextButtonId; - - // stop adding the buttons when at max - if (nextButtonId > IDINTMAP_MSGEND) - { - break; - } - } - //check to play current message instantly - if (_playCurrent) - { - //is it a proximity message? - if (psCurrentMsg->type == MSG_PROXIMITY) - { - //intIntelButtonPressed(true, messageID); - } - else - { - intIntelButtonPressed(false, messageID); - } - } - return true; + return form; } -/*Add the 3D world view for the particular message */ -bool intAddMessageView(MESSAGE *psMessage) +void W_INTELLIGENCEOVERLAY_FORM::closeAnimated(std::function onCompleteHandler) { - bool Animate = true; - - // Is the form already up? - if (widgGetFromID(psWScreen, IDINTMAP_MSGVIEW) != nullptr) + //remove 3dView if still there + if (msgDetailsView) { - intRemoveMessageView(false); - Animate = false; + msgDetailsView->close(false); + msgDetailsView.reset(); } - if (MultiMenuUp) + + // Start the window close animation. + if (msgForm) { - intCloseMultiMenuNoAnim(); + msgForm->closeAnimateDelete([onCompleteHandler](IntFormAnimated&) { + // Trigger onCompleteHandler once close animation is complete + if (onCompleteHandler) + { + onCompleteHandler(); + } + }); } - auto const &parent = psWScreen->psForm; - - auto intMapMsgView = WzMessageView::make(psMessage, Animate); - parent->attach(intMapMsgView); - intMapMsgView->setCalcLayout(LAMBDA_CALCLAYOUT_SIMPLE({ - psWidget->setGeometry(INTMAP_RESEARCHX, INTMAP_RESEARCHY, INTMAP_RESEARCHWIDTH, INTMAP_RESEARCHHEIGHT); - })); - - intMapMsgView->onCloseFunc = []() { - //if close button pressed on 3D View then close the view only - psCurrentMsg = nullptr; - if (bMultiPlayer && !MultiMenuUp) - { - intAddMultiMenu(); - } - }; - - return true; -} + //remove the text label + widgDelete(screenPointer.lock(), IDINTMAP_PAUSELABEL); -/* Process return codes from the Intelligence Map */ -void intProcessIntelMap(UDWORD id) -{ - if (id >= IDINTMAP_MSGSTART && id <= IDINTMAP_MSGEND) + if (bMultiPlayer && multiMenuForm) { - intIntelButtonPressed(false, id); + multiMenuForm->closeAnimateDelete(); } + + isClosing = true; } +W_INTELLIGENCEOVERLAY_FORM::W_INTELLIGENCEOVERLAY_FORM(W_FORMINIT const *init) : W_FORM(init) {} +W_INTELLIGENCEOVERLAY_FORM::W_INTELLIGENCEOVERLAY_FORM() : W_FORM() {} -// Add all the Video Sequences for a message -static void StartMessageSequences(MESSAGE *psMessage, bool Start) +std::shared_ptr W_INTELLIGENCEOVERLAY_FORM::make(bool _playCurrent, UDWORD formID) { - bool bLoop = false; + W_FORMINIT sInit; + sInit.id = formID; + sInit.style = WFORM_PLAIN; + sInit.x = 0; + sInit.y = 0; + sInit.width = screenWidth - 1; + sInit.height = screenHeight - 1; + sInit.calcLayout = LAMBDA_CALCLAYOUT_SIMPLE({ + psWidget->setGeometry(0, 0, screenWidth, screenHeight); + }); - debug(LOG_GUI, "StartMessageSequences: start message sequence"); + class make_shared_enabler: public W_INTELLIGENCEOVERLAY_FORM + { + public: + make_shared_enabler(W_FORMINIT const *init): W_INTELLIGENCEOVERLAY_FORM(init) {} + }; + auto result = std::make_shared(&sInit); + result->initialize(_playCurrent, true); + return result; +} - //should never have a proximity message here - if (psMessage->type == MSG_PROXIMITY) +void W_INTELLIGENCEOVERLAY_FORM::initialize(bool _playCurrent, bool animate) +{ + //add message to indicate game is paused - single player mode + if (PAUSE_DISPLAY_CONDITION) { - return; + W_LABINIT sLabInit; + sLabInit.id = IDINTMAP_PAUSELABEL; + sLabInit.formID = 0; + sLabInit.x = INTMAP_LABELX; + sLabInit.y = INTMAP_LABELY + PAUSEMESSAGE_YOFFSET; + sLabInit.width = INTMAP_LABELWIDTH; + sLabInit.height = INTMAP_LABELHEIGHT; + sLabInit.pText = WzString::fromUtf8(_("PAUSED")); + auto pausedLabel = std::make_shared(&sLabInit); + attach(pausedLabel); } - ASSERT_OR_RETURN(, psMessage->pViewData != nullptr, "Invalid ViewData pointer"); + std::weak_ptr weakParent = std::dynamic_pointer_cast(shared_from_this()); - if (psMessage->pViewData->type == VIEW_RPL) + // Add the main Intelligence Map form + if (selectedPlayer < MAX_PLAYERS) { - VIEW_REPLAY *psViewReplay; - UDWORD Sequence; - - // Surely we don't need to set up psCurrentMsg when we pass the message into this routine ... tim - psViewReplay = (VIEW_REPLAY *)psMessage->pViewData->pData; - - seq_ClearSeqList(); - - //add any sequences to the list to be played when the first one is finished - for (Sequence = 0; Sequence < psViewReplay->seqList.size(); Sequence++) + msgForm = std::make_shared(animate); // Do not animate the opening, if the window was already open. + attach(msgForm); + msgForm->id = IDINTMAP_FORM; + msgForm->setCalcLayout(LAMBDA_CALCLAYOUT_SIMPLE({ + psWidget->setGeometry(INTMAP_X, INTMAP_Y, INTMAP_WIDTH, INTMAP_HEIGHT); + })); + + /* Add the Message form */ + auto msgList = IntListTabWidget::make(); + msgForm->attach(msgList); + msgList->id = IDINTMAP_MSGFORM; + msgList->setChildSize(OBJ_BUTWIDTH, OBJ_BUTHEIGHT); + msgList->setChildSpacing(OBJ_GAP, OBJ_GAP); + int msgListWidth = OBJ_BUTWIDTH * 5 + OBJ_GAP * 4; + msgList->setGeometry((msgForm->width() - msgListWidth) / 2, INTMAP_MSGY, msgListWidth, msgForm->height() - INTMAP_MSGY); + + /* Add the message buttons */ + + //add each button + for (MESSAGE *psMessage = apsMessages[selectedPlayer]; psMessage != nullptr; psMessage = psMessage->psNext) { - if (psViewReplay->seqList.at(Sequence).flag == 1) + /*if (psMessage->type == MSG_TUTORIAL) { - bLoop = true; - } - else + //tutorial cases should never happen + ASSERT( false, "Tutorial message in Intelligence screen!" ); + continue; + }*/ + if (psMessage->type == MSG_PROXIMITY) { - bLoop = false; + //ignore proximity messages here + continue; } - seq_AddSeqToList(psViewReplay->seqList.at(Sequence).sequenceName, psViewReplay->seqList.at(Sequence).audio, nullptr, bLoop); + auto button = std::make_shared(); + msgList->attach(button); + button->setMessage(psMessage); + msgList->addWidgetToLayout(button); - debug(LOG_GUI, "StartMessageSequences: sequence=%d", Sequence); - addVideoText(&psViewReplay->seqList.at(Sequence), Sequence); + /* if the current message matches psSelected lock the button */ + if (psMessage == psCurrentMsg) + { + selectedMsgButton = button; + button->setState(WBUT_LOCK); + msgList->setCurrentPage(msgList->pages() - 1); + } + + /* Add the click handler */ + button->setOnClickHandler([weakParent](IntMessageButton& widg, WIDGET_KEY mouseButton) { + auto messageButton = std::dynamic_pointer_cast(widg.shared_from_this()); + widgScheduleTask([weakParent, messageButton]() { + auto strongParent = weakParent.lock(); + ASSERT_OR_RETURN(, strongParent != nullptr, "No parent"); + strongParent->intIntelButtonPressed(messageButton); + }); + }); } - //play first full screen video - if (Start == true) + //check to play current message instantly + if (_playCurrent && selectedMsgButton) { - seq_StartNextFullScreenVideo(); + if (psCurrentMsg->type != MSG_PROXIMITY) + { + delayedPlayCurrent = true; + } } } - else if (psMessage->pViewData->type == VIEW_RES) + if (bMultiPlayer && !multiMenuForm) { - VIEW_RESEARCH *psViewReplay; - //UDWORD Sequence; + multiMenuForm = createMultiMenuForm(); + attach(multiMenuForm); + multiMenuForm->callCalcLayout(); + } +} - psViewReplay = (VIEW_RESEARCH *)psCurrentMsg->pViewData->pData; +void W_INTELLIGENCEOVERLAY_FORM::clicked(W_CONTEXT *psContext, WIDGET_KEY key) +{ + // no-op +} - seq_ClearSeqList(); - seq_AddSeqToList(psViewReplay->sequenceName, psViewReplay->audio, nullptr, false); - //play first full screen video - if (Start == true) - { - seq_StartNextFullScreenVideo(); - } +void W_INTELLIGENCEOVERLAY_FORM::display(int xOffset, int yOffset) +{ + // no-op +} + +void W_INTELLIGENCEOVERLAY_FORM::run(W_CONTEXT *psContext) +{ + if (isClosing) { return; } + if (keyPressed(KEY_ESC)) + { + inputLoseFocus(); // clear the input buffer. + widgScheduleTask([](){ + intResetScreen(false); + }); } + //check to play current message instantly + if (delayedPlayCurrent && selectedMsgButton) + { + delayedPlayCurrent = false; + std::weak_ptr weakSelf = std::dynamic_pointer_cast(shared_from_this()); + auto scheduledClickButton = selectedMsgButton; + widgScheduleTask([weakSelf, scheduledClickButton]() { + auto strongSelf = weakSelf.lock(); + ASSERT_OR_RETURN(, strongSelf != nullptr, "Null"); + strongSelf->intIntelButtonPressed(scheduledClickButton); + }); + } } /* deal with the actual button press - proxMsg is set to true if a proximity button has been pressed */ -void intIntelButtonPressed(bool proxMsg, UDWORD id) +void W_INTELLIGENCEOVERLAY_FORM::intIntelButtonPressed(const std::shared_ptr& button) { - MESSAGE *psMessage; - UDWORD currID; RESEARCH *psResearch; - ASSERT_OR_RETURN(, proxMsg != true, "Shouldn't be able to get a proximity message!"); - - if (id == 0) + /* message button has been pressed - clear the old button and messageView*/ + if (selectedMsgButton && selectedMsgButton != button) { - intRemoveIntelMap(); - return; + selectedMsgButton->setState(0); + psCurrentMsg = nullptr; + selectedMsgButton.reset(); } - /* message button has been pressed - clear the old button and messageView*/ - if (messageID != 0) + if (!button) { - widgSetButtonState(psWScreen, messageID, 0); - intRemoveMessageView(false); - psCurrentMsg = nullptr; + return; } + selectedMsgButton = button; + /* Lock the new button */ // This means we can't click on the same movie button twice. - widgSetButtonState(psWScreen, id, WBUT_CLICKLOCK); - messageID = id; + selectedMsgButton->setState(WBUT_CLICKLOCK); - //Find the message for the new button */ - currID = IDINTMAP_MSGSTART; - for (psMessage = apsMessages[selectedPlayer]; psMessage; psMessage = - psMessage->psNext) - { - if (psMessage->type != MSG_PROXIMITY) - { - if (currID == id) - { - break; - } - currID++; - } - } + // Get the message for the new button */ + MESSAGE *psMessage = selectedMsgButton->getMessage(); //deal with the message if one if (psMessage) { + ASSERT_OR_RETURN(, psMessage->type != MSG_PROXIMITY, "Shouldn't be able to get a proximity message!"); + //set the current message psCurrentMsg = psMessage; @@ -678,7 +670,7 @@ void intIntelButtonPressed(bool proxMsg, UDWORD id) psCurrentMsg->read = true; debug(LOG_GUI, "intIntelButtonPressed: Dealing with a new message type=%d", - psMessage->type); + psMessage->type); //should never have a proximity message if (psMessage->type == MSG_PROXIMITY) @@ -693,7 +685,7 @@ void intIntelButtonPressed(bool proxMsg, UDWORD id) { if (psMessage->pViewData) { - intAddMessageView(psMessage); + intShowMessageView(psMessage); } // only attempt to show videos if they are installed if (seq_hasVideos()) @@ -750,16 +742,159 @@ void intIntelButtonPressed(bool proxMsg, UDWORD id) } } - //and finally for the dumb? if (psMessage->pViewData) { - intAddMessageView(psMessage); + intShowMessageView(psMessage); } } } } } +/*Add the 3D world view for the particular message */ +void W_INTELLIGENCEOVERLAY_FORM::intShowMessageView(MESSAGE *psMessage) +{ + bool animate = true; + + // Is the form already up? + if (msgDetailsView) + { + msgDetailsView->close(false); + animate = false; + } + if (multiMenuForm) + { + multiMenuForm->hide(); + } + + msgDetailsView = WzMessageView::make(psMessage, animate); + attach(msgDetailsView); + msgDetailsView->setCalcLayout(LAMBDA_CALCLAYOUT_SIMPLE({ + psWidget->setGeometry(INTMAP_RESEARCHX, INTMAP_RESEARCHY, INTMAP_RESEARCHWIDTH, INTMAP_RESEARCHHEIGHT); + })); + + std::weak_ptr weakSelf = std::dynamic_pointer_cast(shared_from_this()); + msgDetailsView->onCloseFunc = [weakSelf]() { + auto strongSelf = weakSelf.lock(); + ASSERT_OR_RETURN(, strongSelf != nullptr, "Null"); + // if close button pressed on 3D View then close the view only + psCurrentMsg = nullptr; + if (bMultiPlayer && strongSelf->multiMenuForm) + { + strongSelf->multiMenuForm->show(); + } + }; +} + +std::shared_ptr createIntelligenceScreen() +{ + // Initialize the intelligence overlay screen + auto result = W_SCREEN::make(); + auto newRootFrm = W_INTELLIGENCEOVERLAY_FORM::make(playCurrent); + newRootFrm->setTransparentToMouse(true); + result->psForm->hide(); // hide actual root form so it doesn't get clicks + result->psForm->attach(newRootFrm); + + return result; +} + + +// MARK: - + +bool intAddIntelMap() +{ + if (intelligenceOverlayScreen) + { + // overlay screen already up + return true; + } + + //check playCurrent with psCurrentMsg + if (psCurrentMsg == nullptr) + { + playCurrent = false; + } + else + { + playCurrent = true; + } + + //set pause states before putting the interface up + audio_StopAll(); + setIntelligencePauseState(); + + intelligenceOverlayScreen = createIntelligenceScreen(); + widgRegisterOverlayScreenOnTopOfScreen(intelligenceOverlayScreen, psWScreen); + + return true; +} + +// Add all the Video Sequences for a message +static void StartMessageSequences(MESSAGE *psMessage, bool Start) +{ + bool bLoop = false; + + debug(LOG_GUI, "StartMessageSequences: start message sequence"); + + //should never have a proximity message here + if (psMessage->type == MSG_PROXIMITY) + { + return; + } + + ASSERT_OR_RETURN(, psMessage->pViewData != nullptr, "Invalid ViewData pointer"); + + if (psMessage->pViewData->type == VIEW_RPL) + { + VIEW_REPLAY *psViewReplay; + UDWORD Sequence; + + // Surely we don't need to set up psCurrentMsg when we pass the message into this routine ... tim + psViewReplay = (VIEW_REPLAY *)psMessage->pViewData->pData; + + seq_ClearSeqList(); + + //add any sequences to the list to be played when the first one is finished + for (Sequence = 0; Sequence < psViewReplay->seqList.size(); Sequence++) + { + if (psViewReplay->seqList.at(Sequence).flag == 1) + { + bLoop = true; + } + else + { + bLoop = false; + } + + seq_AddSeqToList(psViewReplay->seqList.at(Sequence).sequenceName, psViewReplay->seqList.at(Sequence).audio, nullptr, bLoop); + + debug(LOG_GUI, "StartMessageSequences: sequence=%d", Sequence); + addVideoText(&psViewReplay->seqList.at(Sequence), Sequence); + } + //play first full screen video + if (Start == true) + { + seq_StartNextFullScreenVideo(); + } + } + + else if (psMessage->pViewData->type == VIEW_RES) + { + VIEW_RESEARCH *psViewReplay; + //UDWORD Sequence; + + psViewReplay = (VIEW_RESEARCH *)psCurrentMsg->pViewData->pData; + + seq_ClearSeqList(); + seq_AddSeqToList(psViewReplay->sequenceName, psViewReplay->audio, nullptr, false); + //play first full screen video + if (Start == true) + { + seq_StartNextFullScreenVideo(); + } + } + +} static void intCleanUpIntelMap() { @@ -792,26 +927,30 @@ static void intCleanUpIntelMap() /* Remove the Intelligence Map widgets from the screen */ void intRemoveIntelMap() { - //remove 3dView if still there - WIDGET *Widg = widgGetFromID(psWScreen, IDINTMAP_MSGVIEW); - if (Widg) + if (!intelligenceOverlayScreen) { - intRemoveMessageView(false); + return; } // Start the window close animation. - IntFormAnimated *form = (IntFormAnimated *)widgGetFromID(psWScreen, IDINTMAP_FORM); - if (form) + auto rootIntelligenceForm = std::dynamic_pointer_cast(intelligenceOverlayScreen->psForm->children().front()); + if (rootIntelligenceForm == nullptr) { - form->closeAnimateDelete(); + ASSERT(rootIntelligenceForm != nullptr, "Failed to get intelligence form?"); + intRemoveIntelMapNoAnim(); + return; } - //remove the text label - widgDelete(psWScreen, IDINTMAP_PAUSELABEL); - if (bMultiPlayer && MultiMenuUp) - { - intCloseMultiMenu(); - } + std::weak_ptr weakOverlayScreen = intelligenceOverlayScreen; + rootIntelligenceForm->closeAnimated([weakOverlayScreen]() { + // on animation complete: remove the overlay screen + if (auto strongOverlayScreen = weakOverlayScreen.lock()) + { + widgRemoveOverlayScreen(strongOverlayScreen); + } + }); + + intelligenceOverlayScreen.reset(); intCleanUpIntelMap(); } @@ -819,39 +958,17 @@ void intRemoveIntelMap() /* Remove the Intelligence Map widgets from the screen */ void intRemoveIntelMapNoAnim() { - WIDGET *Widg; - - //remove 3dView if still there - Widg = widgGetFromID(psWScreen, IDINTMAP_MSGVIEW); - if (Widg) + if (!intelligenceOverlayScreen) { - intRemoveMessageView(false); + return; } - //remove main Intelligence screen - widgDelete(psWScreen, IDINTMAP_FORM); - //remove the text label - widgDelete(psWScreen, IDINTMAP_PAUSELABEL); - if (bMultiPlayer && MultiMenuUp) - { - intCloseMultiMenuNoAnim(); - } + widgRemoveOverlayScreen(intelligenceOverlayScreen); + intelligenceOverlayScreen.reset(); intCleanUpIntelMap(); } -/* Remove the Message View from the Intelligence screen */ -void intRemoveMessageView(bool animated) -{ - //remove 3dView if still there - WzMessageView *form = (WzMessageView *)widgGetFromID(psWScreen, IDINTMAP_MSGVIEW); - if (form == nullptr) - { - return; - } - form->close(animated); -} - IntMessageButton::IntMessageButton() : IntFancyButton() , psMsg(nullptr) @@ -941,6 +1058,35 @@ void IntMessageButton::display(int xOffset, int yOffset) displayIfHighlight(xOffset, yOffset); } +void IntMessageButton::released(W_CONTEXT *context, WIDGET_KEY mouseButton) +{ + bool clickAndReleaseOnThisButton = ((state & WBUT_DOWN) != 0); // relies on W_CLICKFORM handling to properly set WBUT_DOWN + + IntFancyButton::released(context, mouseButton); + + if (!clickAndReleaseOnThisButton) + { + return; // do nothing + } + + if (onClickHandler) + { + onClickHandler(*this, mouseButton); + } +} + +bool IntMessageButton::clickHeld(W_CONTEXT *psContext, WIDGET_KEY key) +{ + if (key == WKEY_PRIMARY) + { + if (onClickHandler) + { + onClickHandler(*this, WKEY_SECONDARY); + } + return true; + } + return false; +} /* displays the PIE view for the current message */ void intDisplayPIEView(WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset) diff --git a/src/intelmap.h b/src/intelmap.h index 123731d6886..1edbc3cf631 100644 --- a/src/intelmap.h +++ b/src/intelmap.h @@ -40,9 +40,6 @@ bool intAddMessageView(MESSAGE *psMessage); /* Remove the Message View from the Intelligence screen */ void intRemoveMessageView(bool animated); -/* Process return codes from the Intelligence Map */ -void intProcessIntelMap(UDWORD id); - /* Remove the Intelligence Map widgets from the screen */ void intRemoveIntelMap(); diff --git a/src/multimenu.cpp b/src/multimenu.cpp index 0ce670199e0..a1eff8fa017 100644 --- a/src/multimenu.cpp +++ b/src/multimenu.cpp @@ -1248,6 +1248,12 @@ class MultiMenuGrid: public GridLayout std::vector playersWidgets; }; +std::shared_ptr intCreateMultiMenuWidget() +{ + auto grid = MultiMenuGrid::make(); + return grid; +} + bool intAddMultiMenu() { //check for already open. @@ -1279,7 +1285,7 @@ bool intAddMultiMenu() }); form->attach(closeButton); - auto grid = MultiMenuGrid::make(); + auto grid = intCreateMultiMenuWidget(); form->attach(grid); form->setCalcLayout([closeButton, grid](WIDGET *form) { diff --git a/src/multimenu.h b/src/multimenu.h index b3cd31719df..606bb1dc27f 100644 --- a/src/multimenu.h +++ b/src/multimenu.h @@ -41,6 +41,7 @@ void displayRequestOption(WIDGET *psWidget, UDWORD xOffset, UDWORD yOffset); bool intCloseMultiMenu(); void intCloseMultiMenuNoAnim(); bool intAddMultiMenu(); +std::shared_ptr intCreateMultiMenuWidget(); void multiMenuScreenSizeDidChange(unsigned int oldWidth, unsigned int oldHeight, unsigned int newWidth, unsigned int newHeight);