Full modal dialog functionality

This commit is contained in:
Sam 2013-11-18 18:58:15 +01:00
parent 25d3019d1a
commit fc54a6e418
8 changed files with 133 additions and 90 deletions

View File

@ -1,71 +1,117 @@
modalDialog = nil
function init() function init()
g_ui.importStyle('modaldialog') g_ui.importStyle('modaldialog')
connect(g_game, { onModalDialog = onModalDialog, connect(g_game, { onModalDialog = onModalDialog,
onGameEnd = destroy }) onGameEnd = destroyDialog })
local dialog = rootWidget:recursiveGetChildById('modalDialog')
if dialog then
modalDialog = dialog
end
end end
function terminate() function terminate()
disconnect(g_game, { onModalDialog = onModalDialog, disconnect(g_game, { onModalDialog = onModalDialog,
onGameEnd = destroy }) onGameEnd = destroyDialog })
destroy()
end end
function destroy() function destroyDialog()
if modalDialog then if modalDialog then
modalDialog:destroy() modalDialog:destroy()
modalDialog = nil modalDialog = nil
end end
end end
function onModalDialog(id, title, message, enterId, enterText, escapeId, escapeText, choices) function onModalDialog(id, title, message, buttons, enterButton, escapeButton, choices, priority)
if modalDialog then return end -- priority parameter is unused, not sure what its use is.
if modalDialog then
return
end
modalDialog = g_ui.createWidget('ModalDialog', rootWidget) modalDialog = g_ui.createWidget('ModalDialog', rootWidget)
local enterButton = modalDialog:getChildById('enterButton')
local escapeButton = modalDialog:getChildById('escapeButton')
local messageLabel = modalDialog:getChildById('messageLabel') local messageLabel = modalDialog:getChildById('messageLabel')
local choiceList = modalDialog:getChildById('choiceList') local choiceList = modalDialog:getChildById('choiceList')
local choiceScrollbar = modalDialog:getChildById('choiceScrollBar')
local buttonList = modalDialog:getChildById('buttonList')
modalDialog:setText(title) modalDialog:setText(title)
messageLabel:setText(message) messageLabel:setText(message)
enterButton:setText(enterText)
escapeButton:setText(escapeText)
local focusLabel = nil local horizontalPadding = modalDialog:getPaddingLeft() + modalDialog:getPaddingRight()
for k, v in pairs(choices) do modalDialog:setWidth(math.min(modalDialog.maximumWidth, math.max(messageLabel:getWidth(), modalDialog.minimumWidth)))
local choiceId = v[1] messageLabel:setWidth(math.min(modalDialog.maximumWidth, math.max(messageLabel:getWidth(), modalDialog.minimumWidth)) - horizontalPadding)
local choiceName = v[2]
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) local label = g_ui.createWidget('ChoiceListLabel', choiceList)
label.choiceId = choiceId label.choiceId = choiceId
label:setText(choiceName) label:setText(choiceName)
label:setPhantom(false) label:setPhantom(false)
if not labelHeight then
if not focusLabel then labelHeight = label:getHeight()
focusLabel = label
end end
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() local enterFunc = function()
g_game.answerModalDialog(id, enterId, choiceList:getFocusedChild().choiceId) local focusedChoice = choiceList:getFocusedChild()
destroy() local choice = 0xFF
if focusedChoice then
choice = focusedChoice.choiceId
end
g_game.answerModalDialog(id, enterButton, choice)
destroyDialog()
end end
local escapeFunc = function() local escapeFunc = function()
g_game.answerModalDialog(id, escapeId, choiceList:getFocusedChild().choiceId) local focusedChoice = choiceList:getFocusedChild()
destroy() local choice = 0xFF
if focusedChoice then
choice = focusedChoice.choiceId
end
g_game.answerModalDialog(id, escapeButton, choice)
destroyDialog()
end end
choiceList.onDoubleClick = enterFunc choiceList.onDoubleClick = enterFunc
enterButton.onClick = enterFunc
modalDialog.onEnter = enterFunc modalDialog.onEnter = enterFunc
escapeButton.onClick = escapeFunc
modalDialog.onEscape = escapeFunc modalDialog.onEscape = escapeFunc
return
end end

View File

@ -8,52 +8,61 @@ ChoiceListLabel < Label
background-color: #ffffff22 background-color: #ffffff22
color: #ffffff 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 ModalDialog < MainWindow
id: modalDialog id: modalDialog
!text: tr('Title') size: 280 97
size: 280 230 &minimumWidth: 200
@onEscape: self:destroy() &maximumWidth: 500
&minimumChoices: 4
&maximumChoices: 10
Label Label
id: messageLabel id: messageLabel
anchors.top: parent.top anchors.top: parent.top
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right
text-align: left text-align: left
text: Message text-auto-resize: true
height: 60 text-wrap: true
TextList ChoiceList
id: choiceList
vertical-scrollbar: choiceScrollBar
anchors.fill: parent
anchors.top: prev.bottom
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 HorizontalSeparator
id: escapeButton anchors.left: parent.left
!text: tr('Cancel')
anchors.bottom: parent.bottom
anchors.right: parent.right anchors.right: parent.right
margin-top: 10 anchors.bottom: next.top
width: 60
VerticalScrollBar Panel
id: choiceScrollBar id: buttonList
anchors.top: choiceList.top anchors.left: parent.left
anchors.bottom: choiceList.bottom anchors.right: parent.right
anchors.right: choiceList.right anchors.bottom: parent.bottom
step: 14 height: 24
pixels-scroll: true layout: horizontalBox
align-right: true
ChoiceScrollBar

View File

@ -61,7 +61,7 @@ end
function terminate() function terminate()
disconnect(g_game, 'onTextMessage', displayMessage) disconnect(g_game, 'onTextMessage', displayMessage)
disconnect(g_game, 'onGameEnd',clearMessages) disconnect(g_game, 'onGameEnd', clearMessages)
clearMessages() clearMessages()
messagesPanel:destroy() messagesPanel:destroy()
end end

View File

@ -506,9 +506,9 @@ void Game::processQuestLine(int questId, const std::vector<std::tuple<std::strin
g_lua.callGlobalField("g_game", "onQuestLine", questId, questMissions); g_lua.callGlobalField("g_game", "onQuestLine", questId, questMissions);
} }
void Game::processModalDialog(uint32 id, std::string title, std::string message, int enterId, std::string enterText, int escapeId, std::string escapeText, std::vector<std::tuple<int, std::string> > choiceList) void Game::processModalDialog(uint32 id, std::string title, std::string message, std::vector<std::tuple<int, std::string> > buttonList, int enterButton, int escapeButton, std::vector<std::tuple<int, std::string> > 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) void Game::processAttackCancel(uint seq)

View File

@ -132,7 +132,7 @@ protected:
void processQuestLine(int questId, const std::vector<std::tuple<std::string, std::string> >& questMissions); void processQuestLine(int questId, const std::vector<std::tuple<std::string, std::string> >& questMissions);
// modal dialogs >= 970 // 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<std::tuple<int, std::string> > choiceList); void processModalDialog(uint32 id, std::string title, std::string message, std::vector<std::tuple<int, std::string> > buttonList, int enterButton, int escapeButton, std::vector<std::tuple<int, std::string> > choiceList, bool priority);
friend class ProtocolGame; friend class ProtocolGame;
friend class Map; friend class Map;

View File

@ -145,7 +145,7 @@ namespace Proto {
GameServerMarketLeave = 247, // 944 GameServerMarketLeave = 247, // 944
GameServerMarketDetail = 248, // 944 GameServerMarketDetail = 248, // 944
GameServerMarketBrowse = 249, // 944 GameServerMarketBrowse = 249, // 944
GameServerShowModalDialog = 250 // 960 GameServerModalDialog = 250 // 960
}; };
enum ClientOpcodes : uint8 enum ClientOpcodes : uint8

View File

@ -212,7 +212,7 @@ private:
void parseChannelEvent(const InputMessagePtr& msg); void parseChannelEvent(const InputMessagePtr& msg);
void parseItemInfo(const InputMessagePtr& msg); void parseItemInfo(const InputMessagePtr& msg);
void parsePlayerInventory(const InputMessagePtr& msg); void parsePlayerInventory(const InputMessagePtr& msg);
void parseShowModalDialog(const InputMessagePtr& msg); void parseModalDialog(const InputMessagePtr& msg);
void parseExtendedOpcode(const InputMessagePtr& msg); void parseExtendedOpcode(const InputMessagePtr& msg);
void parseChangeMapAwareRange(const InputMessagePtr& msg); void parseChangeMapAwareRange(const InputMessagePtr& msg);
void parseCreaturesMark(const InputMessagePtr& msg); void parseCreaturesMark(const InputMessagePtr& msg);

View File

@ -316,8 +316,8 @@ void ProtocolGame::parseMessage(const InputMessagePtr& msg)
parsePlayerInfo(msg); parsePlayerInfo(msg);
break; break;
// PROTOCOL>=970 // PROTOCOL>=970
case Proto::GameServerShowModalDialog: case Proto::GameServerModalDialog:
parseShowModalDialog(msg); parseModalDialog(msg);
break; break;
// PROTOCOL>=980 // PROTOCOL>=980
case Proto::GameServerLoginSuccess: 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(); uint32 id = msg->getU32();
std::string title = msg->getString(); std::string title = msg->getString();
std::string message = msg->getString(); std::string message = msg->getString();
int sizeButtons = msg->getU8(); int sizeButtons = msg->getU8();
std::map<int, std::string > buttonList; std::vector<std::tuple<int, std::string> > buttonList;
for(int i = 0; i < sizeButtons; ++i) { for(int i = 0; i < sizeButtons; ++i) {
std::string value = msg->getString(); std::string value = msg->getString();
int id = msg->getU8(); int id = msg->getU8();
buttonList[id] = value; buttonList.push_back(std::make_tuple(id, value));
} }
int sizeChoices = msg->getU8(); int sizeChoices = msg->getU8();
@ -1628,21 +1628,9 @@ void ProtocolGame::parseShowModalDialog(const InputMessagePtr& msg)
escapeButton = msg->getU8(); escapeButton = msg->getU8();
} }
msg->getU8(); // popup value (no clue what it is for) bool priority = msg->getU8() == 0x01;
std::map<int, std::string>::iterator itEnter = buttonList.find(enterButton); g_game.processModalDialog(id, title, message, buttonList, enterButton, escapeButton, choiceList, priority);
if(itEnter == buttonList.end()) {
g_logger.info(stdext::format("Enter button does not exist for dialog id: %d", id));
return;
}
std::map<int, std::string >::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);
} }
void ProtocolGame::parseExtendedOpcode(const InputMessagePtr& msg) void ProtocolGame::parseExtendedOpcode(const InputMessagePtr& msg)