From fc54a6e418f61d44f6aa308a65eed527ea934b07 Mon Sep 17 00:00:00 2001 From: Sam Date: Mon, 18 Nov 2013 18:58:15 +0100 Subject: [PATCH] Full modal dialog functionality --- modules/game_modaldialog/modaldialog.lua | 102 ++++++++++++++++------ modules/game_modaldialog/modaldialog.otui | 87 +++++++++--------- modules/game_textmessage/textmessage.lua | 2 +- src/client/game.cpp | 4 +- src/client/game.h | 2 +- src/client/protocolcodes.h | 2 +- src/client/protocolgame.h | 2 +- src/client/protocolgameparse.cpp | 26 ++---- 8 files changed, 135 insertions(+), 92 deletions(-) diff --git a/modules/game_modaldialog/modaldialog.lua b/modules/game_modaldialog/modaldialog.lua index 3a13ecf9..d39ba98f 100644 --- a/modules/game_modaldialog/modaldialog.lua +++ b/modules/game_modaldialog/modaldialog.lua @@ -1,71 +1,117 @@ +modalDialog = nil + function init() g_ui.importStyle('modaldialog') connect(g_game, { onModalDialog = onModalDialog, - onGameEnd = destroy }) + onGameEnd = destroyDialog }) + + local dialog = rootWidget:recursiveGetChildById('modalDialog') + if dialog then + modalDialog = dialog + end end function terminate() disconnect(g_game, { onModalDialog = onModalDialog, - onGameEnd = destroy }) - - destroy() + onGameEnd = destroyDialog }) end -function destroy() +function destroyDialog() if modalDialog then modalDialog:destroy() modalDialog = nil end end -function onModalDialog(id, title, message, enterId, enterText, escapeId, escapeText, choices) - if modalDialog then return end - +function onModalDialog(id, title, message, buttons, enterButton, escapeButton, choices, priority) + -- priority parameter is unused, not sure what its use is. + if modalDialog then + return + end + modalDialog = g_ui.createWidget('ModalDialog', rootWidget) - local enterButton = modalDialog:getChildById('enterButton') - local escapeButton = modalDialog:getChildById('escapeButton') local messageLabel = modalDialog:getChildById('messageLabel') local choiceList = modalDialog:getChildById('choiceList') + local choiceScrollbar = modalDialog:getChildById('choiceScrollBar') + local buttonList = modalDialog:getChildById('buttonList') modalDialog:setText(title) messageLabel:setText(message) - enterButton:setText(enterText) - escapeButton:setText(escapeText) - local focusLabel = nil - for k, v in pairs(choices) do - local choiceId = v[1] - local choiceName = v[2] + local horizontalPadding = modalDialog:getPaddingLeft() + modalDialog:getPaddingRight() + modalDialog:setWidth(math.min(modalDialog.maximumWidth, math.max(messageLabel:getWidth(), modalDialog.minimumWidth))) + messageLabel:setWidth(math.min(modalDialog.maximumWidth, math.max(messageLabel:getWidth(), modalDialog.minimumWidth)) - horizontalPadding) + + local labelHeight = nil + for i = 1, #choices do + local choiceId = choices[i][1] + local choiceName = choices[i][2] local label = g_ui.createWidget('ChoiceListLabel', choiceList) label.choiceId = choiceId label:setText(choiceName) label:setPhantom(false) - - if not focusLabel then - focusLabel = label + if not labelHeight then + labelHeight = label:getHeight() end end - choiceList:focusChild(focusLabel) + choiceList:focusNextChild() + + for i = 1, #buttons do + local buttonId = buttons[i][1] + local buttonText = buttons[i][2] + + local button = g_ui.createWidget('ModalButton', buttonList) + button:setText(buttonText) + button.onClick = function(self) + local focusedChoice = choiceList:getFocusedChild() + local choice = 0xFF + if focusedChoice then + choice = focusedChoice.choiceId + end + g_game.answerModalDialog(id, buttonId, choice) + destroyDialog() + end + end + + local additionalHeight = 0 + if #choices > 0 then + choiceList:setVisible(true) + choiceScrollbar:setVisible(true) + + additionalHeight = math.min(modalDialog.maximumChoices, math.max(modalDialog.minimumChoices, #choices)) * labelHeight + additionalHeight = additionalHeight + choiceList:getPaddingTop() + choiceList:getPaddingBottom() + end + modalDialog:setHeight(modalDialog:getHeight() + additionalHeight) + + addEvent(function() + modalDialog:setHeight(modalDialog:getHeight() + messageLabel:getHeight() - 14) + end) local enterFunc = function() - g_game.answerModalDialog(id, enterId, choiceList:getFocusedChild().choiceId) - destroy() + local focusedChoice = choiceList:getFocusedChild() + local choice = 0xFF + if focusedChoice then + choice = focusedChoice.choiceId + end + g_game.answerModalDialog(id, enterButton, choice) + destroyDialog() end local escapeFunc = function() - g_game.answerModalDialog(id, escapeId, choiceList:getFocusedChild().choiceId) - destroy() + local focusedChoice = choiceList:getFocusedChild() + local choice = 0xFF + if focusedChoice then + choice = focusedChoice.choiceId + end + g_game.answerModalDialog(id, escapeButton, choice) + destroyDialog() end choiceList.onDoubleClick = enterFunc - enterButton.onClick = enterFunc modalDialog.onEnter = enterFunc - - escapeButton.onClick = escapeFunc modalDialog.onEscape = escapeFunc - return end \ No newline at end of file diff --git a/modules/game_modaldialog/modaldialog.otui b/modules/game_modaldialog/modaldialog.otui index 375e717e..b4fe180b 100644 --- a/modules/game_modaldialog/modaldialog.otui +++ b/modules/game_modaldialog/modaldialog.otui @@ -8,52 +8,61 @@ ChoiceListLabel < Label background-color: #ffffff22 color: #ffffff +ChoiceList < TextList + id: choiceList + vertical-scrollbar: choiceScrollBar + anchors.fill: parent + anchors.top: prev.bottom + anchors.bottom: next.top + padding: 1 + margin-top: 4 + margin-bottom: 10 + focusable: false + visible: false + +ChoiceScrollBar < VerticalScrollBar + id: choiceScrollBar + anchors.top: choiceList.top + anchors.bottom: choiceList.bottom + anchors.right: choiceList.right + step: 14 + pixels-scroll: true + visible: false + +ModalButton < Button + width: 60 + margin: 2 + ModalDialog < MainWindow id: modalDialog - !text: tr('Title') - size: 280 230 - @onEscape: self:destroy() + size: 280 97 + &minimumWidth: 200 + &maximumWidth: 500 + &minimumChoices: 4 + &maximumChoices: 10 Label id: messageLabel anchors.top: parent.top anchors.left: parent.left - anchors.right: parent.right text-align: left - text: Message - height: 60 - - TextList - id: choiceList - vertical-scrollbar: choiceScrollBar - anchors.fill: parent - anchors.top: prev.bottom + text-auto-resize: true + text-wrap: true + + ChoiceList + + HorizontalSeparator + anchors.left: parent.left + anchors.right: parent.right anchors.bottom: next.top - margin-bottom: 10 - margin-top: 10 - padding: 1 - focusable: false - - Button - id: enterButton - !text: tr('Ok') - anchors.top: next.top - anchors.right: next.left - margin-right: 8 - width: 60 - - Button - id: escapeButton - !text: tr('Cancel') - anchors.bottom: parent.bottom + + Panel + id: buttonList + anchors.left: parent.left anchors.right: parent.right - margin-top: 10 - width: 60 - - VerticalScrollBar - id: choiceScrollBar - anchors.top: choiceList.top - anchors.bottom: choiceList.bottom - anchors.right: choiceList.right - step: 14 - pixels-scroll: true + anchors.bottom: parent.bottom + height: 24 + layout: horizontalBox + align-right: true + + ChoiceScrollBar diff --git a/modules/game_textmessage/textmessage.lua b/modules/game_textmessage/textmessage.lua index eca542c0..e8c4a7cc 100644 --- a/modules/game_textmessage/textmessage.lua +++ b/modules/game_textmessage/textmessage.lua @@ -61,7 +61,7 @@ end function terminate() disconnect(g_game, 'onTextMessage', displayMessage) - disconnect(g_game, 'onGameEnd',clearMessages) + disconnect(g_game, 'onGameEnd', clearMessages) clearMessages() messagesPanel:destroy() end diff --git a/src/client/game.cpp b/src/client/game.cpp index 3e1bde4a..6a9506d4 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -506,9 +506,9 @@ void Game::processQuestLine(int questId, const std::vector > choiceList) +void Game::processModalDialog(uint32 id, std::string title, std::string message, std::vector > buttonList, int enterButton, int escapeButton, std::vector > choiceList, bool priority) { - g_lua.callGlobalField("g_game", "onModalDialog", id, title, message, enterId, enterText, escapeId, escapeText, choiceList); + g_lua.callGlobalField("g_game", "onModalDialog", id, title, message, buttonList, enterButton, escapeButton, choiceList, priority); } void Game::processAttackCancel(uint seq) diff --git a/src/client/game.h b/src/client/game.h index c9bdc317..a63ff0f0 100644 --- a/src/client/game.h +++ b/src/client/game.h @@ -132,7 +132,7 @@ protected: void processQuestLine(int questId, const std::vector >& questMissions); // modal dialogs >= 970 - void processModalDialog(uint32 id, std::string title, std::string message, int enterId, std::string enterText, int escapeId, std::string escapeText, std::vector > choiceList); + void processModalDialog(uint32 id, std::string title, std::string message, std::vector > buttonList, int enterButton, int escapeButton, std::vector > choiceList, bool priority); friend class ProtocolGame; friend class Map; diff --git a/src/client/protocolcodes.h b/src/client/protocolcodes.h index c12a4e13..ad45de36 100644 --- a/src/client/protocolcodes.h +++ b/src/client/protocolcodes.h @@ -145,7 +145,7 @@ namespace Proto { GameServerMarketLeave = 247, // 944 GameServerMarketDetail = 248, // 944 GameServerMarketBrowse = 249, // 944 - GameServerShowModalDialog = 250 // 960 + GameServerModalDialog = 250 // 960 }; enum ClientOpcodes : uint8 diff --git a/src/client/protocolgame.h b/src/client/protocolgame.h index 477141de..87e35d73 100644 --- a/src/client/protocolgame.h +++ b/src/client/protocolgame.h @@ -212,7 +212,7 @@ private: void parseChannelEvent(const InputMessagePtr& msg); void parseItemInfo(const InputMessagePtr& msg); void parsePlayerInventory(const InputMessagePtr& msg); - void parseShowModalDialog(const InputMessagePtr& msg); + void parseModalDialog(const InputMessagePtr& msg); void parseExtendedOpcode(const InputMessagePtr& msg); void parseChangeMapAwareRange(const InputMessagePtr& msg); void parseCreaturesMark(const InputMessagePtr& msg); diff --git a/src/client/protocolgameparse.cpp b/src/client/protocolgameparse.cpp index d1bfa5c8..4bb6b0d5 100644 --- a/src/client/protocolgameparse.cpp +++ b/src/client/protocolgameparse.cpp @@ -316,8 +316,8 @@ void ProtocolGame::parseMessage(const InputMessagePtr& msg) parsePlayerInfo(msg); break; // PROTOCOL>=970 - case Proto::GameServerShowModalDialog: - parseShowModalDialog(msg); + case Proto::GameServerModalDialog: + parseModalDialog(msg); break; // PROTOCOL>=980 case Proto::GameServerLoginSuccess: @@ -1596,18 +1596,18 @@ void ProtocolGame::parsePlayerInventory(const InputMessagePtr& msg) } } -void ProtocolGame::parseShowModalDialog(const InputMessagePtr& msg) +void ProtocolGame::parseModalDialog(const InputMessagePtr& msg) { uint32 id = msg->getU32(); std::string title = msg->getString(); std::string message = msg->getString(); int sizeButtons = msg->getU8(); - std::map buttonList; + std::vector > buttonList; for(int i = 0; i < sizeButtons; ++i) { std::string value = msg->getString(); int id = msg->getU8(); - buttonList[id] = value; + buttonList.push_back(std::make_tuple(id, value)); } int sizeChoices = msg->getU8(); @@ -1628,21 +1628,9 @@ void ProtocolGame::parseShowModalDialog(const InputMessagePtr& msg) escapeButton = msg->getU8(); } - msg->getU8(); // popup value (no clue what it is for) + bool priority = msg->getU8() == 0x01; - std::map::iterator itEnter = buttonList.find(enterButton); - if(itEnter == buttonList.end()) { - g_logger.info(stdext::format("Enter button does not exist for dialog id: %d", id)); - return; - } - - std::map::iterator itEscape = buttonList.find(escapeButton); - if(itEscape == buttonList.end()) { - g_logger.info(stdext::format("Escape button does not exist for dialog id: %d", id)); - return; - } - - g_game.processModalDialog(id, title, message, itEnter->first, itEnter->second, itEscape->first, itEscape->second, choiceList); + g_game.processModalDialog(id, title, message, buttonList, enterButton, escapeButton, choiceList, priority); } void ProtocolGame::parseExtendedOpcode(const InputMessagePtr& msg)