133 | function HUDPopupMessage:assignCurrentMessage(message) |
134 | self.time = 0 |
135 | self.currentMessage = message |
136 | |
137 | local reqHeight = self:getTitleHeight() + self:getTextHeight() + self:getInputRowsHeight() |
138 | reqHeight = reqHeight + self.borderPaddingY * 2 + self.textOffsetY + self.titleTextSize + self.textSize |
139 | if #message.controls > 0 then |
140 | reqHeight = reqHeight + self.inputRowsOffsetY |
141 | end |
142 | |
143 | if not g_isServerStreamingVersion then |
144 | reqHeight = reqHeight + self.skipButtonHeight |
145 | end |
146 | |
147 | self:setDimension(self:getWidth(), math.max(self.minHeight, reqHeight)) |
148 | self:updateButtonGlyphs() |
149 | end |
457 | function HUDPopupMessage:createComponents(hudAtlasPath) |
458 | local basePosX, basePosY = self:getPosition() |
459 | local baseWidth, baseHeight = self:getWidth(), self:getHeight() |
460 | |
461 | local frame = HUDFrameElement:new(hudAtlasPath, basePosX, basePosY, baseWidth, baseHeight) |
462 | self.frameElement = frame |
463 | self:addChild(frame) |
464 | |
465 | local _, inputRowHeight = self:scalePixelToScreenVector(HUDPopupMessage.SIZE.INPUT_ROW) |
466 | |
467 | local posY = basePosY + inputRowHeight -- add one row's height as spacing for the skip button |
468 | local buttonRow, inputGlyph = nil, nil |
469 | for i = 1, HUDPopupMessage.MAX_INPUT_ROW_COUNT do |
470 | buttonRow, inputGlyph, posY = self:createInputRow(hudAtlasPath, basePosX, posY) |
471 | local rowIndex = HUDPopupMessage.MAX_INPUT_ROW_COUNT - i + 1 |
472 | self.inputRows[rowIndex] = buttonRow |
473 | self.inputGlyphs[rowIndex] = inputGlyph |
474 | self:addChild(buttonRow) |
475 | end |
476 | |
477 | if not g_isServerStreamingVersion then |
478 | local offX, offY = self:scalePixelToScreenVector(HUDPopupMessage.POSITION.SKIP_BUTTON) |
479 | local glyphWidth, glyphHeight = self:scalePixelToScreenVector(HUDPopupMessage.SIZE.INPUT_GLYPH) |
480 | local skipGlyph = InputGlyphElement:new(self.inputDisplayManager, glyphWidth, glyphHeight) |
481 | skipGlyph:setPosition(basePosX + (baseWidth - glyphWidth) * 0.5 + offX, basePosY - offY) |
482 | skipGlyph:setAction(InputAction.SKIP_MESSAGE_BOX, self.l10n:getText(HUDPopupMessage.L10N_SYMBOL.BUTTON_OK), self.skipTextSize, true, false) |
483 | |
484 | self.skipGlyph = skipGlyph |
485 | self:addChild(skipGlyph) |
486 | end |
487 | end |
491 | function HUDPopupMessage:createInputRow(hudAtlasPath, posX, posY) |
492 | local overlay = Overlay:new(hudAtlasPath, posX, posY, self.inputRowWidth, self.inputRowHeight) |
493 | overlay:setUVs(getNormalizedUVs(HUDPopupMessage.UV.BACKGROUND)) |
494 | overlay:setColor(unpack(HUDPopupMessage.COLOR.INPUT_ROW)) |
495 | local buttonPanel = HUDElement:new(overlay) |
496 | |
497 | local rowHeight = buttonPanel:getHeight() |
498 | |
499 | local glyphWidth, glyphHeight = self:scalePixelToScreenVector(HUDPopupMessage.SIZE.INPUT_GLYPH) |
500 | local inputGlyph = InputGlyphElement:new(self.inputDisplayManager, glyphWidth, glyphHeight) |
501 | local offX, offY = self:scalePixelToScreenVector(HUDPopupMessage.POSITION.INPUT_GLYPH) |
502 | local glyphX, glyphY = posX + self.borderPaddingX + offX, posY + (rowHeight - glyphHeight) * 0.5 + offY |
503 | inputGlyph:setPosition(glyphX, glyphY) |
504 | buttonPanel:addChild(inputGlyph) |
505 | |
506 | local width, height = self:scalePixelToScreenVector(HUDPopupMessage.SIZE.SEPARATOR) |
507 | height = math.max(height, HUDPopupMessage.SIZE.SEPARATOR[2] / g_screenHeight) |
508 | local offX, offY = self:scalePixelToScreenVector(HUDPopupMessage.POSITION.SEPARATOR) |
509 | overlay = Overlay:new(hudAtlasPath, posX + offX, posY + offY, width, height) |
510 | overlay:setUVs(getNormalizedUVs(GameInfoDisplay.UV.SEPARATOR)) |
511 | overlay:setColor(unpack(GameInfoDisplay.COLOR.SEPARATOR)) |
512 | local separator = HUDElement:new(overlay) |
513 | buttonPanel:addChild(separator) |
514 | |
515 | return buttonPanel, inputGlyph, posY + rowHeight |
516 | end |
340 | function HUDPopupMessage:draw() |
341 | if not self.isMenuVisible and self:getVisible() and self.currentMessage ~= nil then |
342 | HUDPopupMessage:superClass().draw(self) |
343 | |
344 | local baseX, baseY = self:getPosition() |
345 | local width, height = self:getWidth(), self:getHeight() |
346 | |
347 | -- title |
348 | setTextColor(unpack(HUDPopupMessage.COLOR.TITLE)) |
349 | setTextBold(true) |
350 | setTextAlignment(RenderText.ALIGN_CENTER) |
351 | setTextWrapWidth(width - 2 * self.borderPaddingX) |
352 | local textPosY = baseY + height - self.borderPaddingY |
353 | |
354 | if self.currentMessage.title ~= "" then |
355 | local title = utf8ToUpper(self.currentMessage.title) |
356 | textPosY = textPosY - self.titleTextSize |
357 | renderText(baseX + width * 0.5, textPosY, self.titleTextSize, title) |
358 | end |
359 | |
360 | -- message |
361 | setTextBold(false) |
362 | setTextColor(unpack(HUDPopupMessage.COLOR.TEXT)) |
363 | setTextAlignment(RenderText.ALIGN_LEFT) |
364 | setTextLineHeightScale(HUDPopupMessage.TEXT_LINE_HEIGHT_SCALE) |
365 | textPosY = textPosY - self.textSize + self.textOffsetY |
366 | renderText(baseX + self.borderPaddingX, textPosY, self.textSize, self.currentMessage.message) |
367 | textPosY = textPosY - getTextHeight(self.textSize, self.currentMessage.message) |
368 | |
369 | -- input rows |
370 | setTextColor(unpack(HUDPopupMessage.COLOR.SKIP_TEXT)) |
371 | setTextAlignment(RenderText.ALIGN_RIGHT) |
372 | local posX = baseX + width - self.borderPaddingX |
373 | local posY = textPosY + self.inputRowsOffsetY - self.inputRowHeight - self.textSize |
374 | for i = 1, #self.currentMessage.controls do |
375 | local inputText = self.currentMessage.controls[i].textRight |
376 | local offX, offY = self.inputRowTextX, self.inputRowTextY |
377 | renderText(posX + self.inputRowTextX, posY + self.inputRowTextY, self.textSize, inputText) |
378 | |
379 | posY = posY - self.inputRowHeight |
380 | end |
381 | |
382 | -- reset uncommon text settings: |
383 | setTextWrapWidth(0) |
384 | setTextLineHeightScale(RenderText.DEFAULT_LINE_HEIGHT_SCALE) |
385 | end |
386 | end |
41 | function HUDPopupMessage:new(hudAtlasPath, l10n, inputManager, inputDisplayManager, ingameMap, guiSoundPlayer) |
42 | local backgroundOverlay = HUDPopupMessage.createBackground(hudAtlasPath) |
43 | local self = HUDPopupMessage:superClass().new(HUDPopupMessage_mt, backgroundOverlay, nil) |
44 | |
45 | self.l10n = l10n |
46 | self.inputManager = inputManager |
47 | self.inputDisplayManager = inputDisplayManager |
48 | self.ingameMap = ingameMap -- in game map reference required to hide the map when showing a message |
49 | self.guiSoundPlayer = guiSoundPlayer |
50 | |
51 | self.pendingMessages = {} -- {i={<message as defined in showMessage()>}}, ordered as a queue |
52 | self.isCustomInputActive = false -- input state flag |
53 | self.lastInputMode = self.inputManager:getInputHelpMode() |
54 | |
55 | self.inputRows = {} -- {i=HUDElement} |
56 | self.inputGlyphs = {} -- {i=InputGlyphElement}, synchronous with self.inputRows |
57 | self.skipGlyph = nil -- InputGlyphElement |
58 | self.frameElement = nil -- FrameElement |
59 | |
60 | self.isMenuVisible = false |
61 | self.time = 0 -- accumulated message display time |
62 | self.isGamePaused = false -- game paused state |
63 | |
64 | self:storeScaledValues() |
65 | self:createComponents(hudAtlasPath) |
66 | |
67 | return self |
68 | end |
308 | function HUDPopupMessage:setInputActive(isActive) |
309 | if not self.isCustomInputActive and isActive then |
310 | self.inputManager:setContext(HUDPopupMessage.INPUT_CONTEXT_NAME, true, false) |
311 | |
312 | local _, eventId = self.inputManager:registerActionEvent(InputAction.MENU_ACCEPT, self, self.onConfirmMessage, false, true, false, true) |
313 | self.inputManager:setActionEventTextVisibility(eventId, false) |
314 | |
315 | _, eventId = self.inputManager:registerActionEvent(InputAction.SKIP_MESSAGE_BOX, self, self.onConfirmMessage, false, true, false, true) |
316 | self.inputManager:setActionEventTextVisibility(eventId, false) |
317 | |
318 | self.isCustomInputActive = true |
319 | elseif self.isCustomInputActive and not isActive then |
320 | self.inputManager:removeActionEventsByTarget(self) |
321 | self.inputManager:revertContext(true) -- revert and clear message context |
322 | self.isCustomInputActive = false |
323 | end |
324 | end |
80 | function HUDPopupMessage:showMessage(title, message, duration, controls, callback, target) |
81 | if duration == 0 then -- if no duration indicated, adjust duration according to message length |
82 | duration = HUDPopupMessage.MIN_DURATION + string.len(message) * HUDPopupMessage.DURATION_PER_CHARACTER |
83 | elseif duration < 0 then -- a negative duration is adjusted to five minutes ("almost" indefinite) |
84 | duration = HUDPopupMessage.MAX_DURATION |
85 | end |
86 | |
87 | while #self.pendingMessages > HUDPopupMessage.MAX_PENDING_MESSAGE_COUNT do |
88 | table.remove(self.pendingMessages, 1) |
89 | end |
90 | |
91 | local message = {isDialog=false, title=title, message=message, duration=duration, |
92 | controls=Utils.getNoNil(controls, {}), callback=callback, target=target} |
93 | |
94 | if #message.controls > HUDPopupMessage.MAX_INPUT_ROW_COUNT then -- truncate |
95 | for i = #message.controls, HUDPopupMessage.MAX_INPUT_ROW_COUNT + 1, -1 do |
96 | table.remove(message.controls, i) |
97 | end |
98 | end |
99 | |
100 | table.insert(self.pendingMessages, message) |
101 | end |
421 | function HUDPopupMessage:storeScaledValues() |
422 | self.minWidth, self.minHeight = self:scalePixelToScreenVector(HUDPopupMessage.SIZE.SELF) |
423 | |
424 | self.textOffsetX, self.textOffsetY = self:scalePixelToScreenVector(HUDPopupMessage.POSITION.MESSAGE_TEXT) |
425 | self.inputRowsOffsetX, self.inputRowsOffsetY = self:scalePixelToScreenVector(HUDPopupMessage.POSITION.INPUT_ROWS) |
426 | self.skipButtonOffsetX, self.skipButtonOffsetY = self:scalePixelToScreenVector(HUDPopupMessage.POSITION.SKIP_BUTTON) |
427 | self.skipButtonWidth, self.skipButtonHeight = self:scalePixelToScreenVector(HUDPopupMessage.SIZE.SKIP_BUTTON) |
428 | |
429 | self.inputRowWidth, self.inputRowHeight = self:scalePixelToScreenVector(HUDPopupMessage.SIZE.INPUT_ROW) |
430 | self.borderPaddingX, self.borderPaddingY = self:scalePixelToScreenVector(HUDPopupMessage.SIZE.BORDER_PADDING) |
431 | |
432 | self.inputRowTextX, self.inputRowTextY = self:scalePixelToScreenVector(HUDPopupMessage.POSITION.INPUT_TEXT) |
433 | |
434 | self.titleTextSize = self:scalePixelToScreenHeight(HUDPopupMessage.TEXT_SIZE.TITLE) |
435 | self.textSize = self:scalePixelToScreenHeight(HUDPopupMessage.TEXT_SIZE.TEXT) |
436 | self.skipTextSize = self:scalePixelToScreenHeight(HUDPopupMessage.TEXT_SIZE.SKIP_TEXT) |
437 | end |
244 | function HUDPopupMessage:update(dt) |
245 | if not self.isMenuVisible then |
246 | HUDPopupMessage:superClass().update(self, dt) |
247 | |
248 | if not self.isGamePaused then |
249 | self.time = self.time + dt |
250 | self:updateCurrentMessage() |
251 | end |
252 | |
253 | if self:getVisible() then |
254 | local inputMode = self.inputManager:getInputHelpMode() |
255 | if inputMode ~= self.lastInputMode then |
256 | self.lastInputMode = inputMode |
257 | self:updateButtonGlyphs() |
258 | end |
259 | end |
260 | end |
261 | end |
280 | function HUDPopupMessage:updateButtonGlyphs() |
281 | if self.skipGlyph ~= nil then |
282 | self.skipGlyph:setAction(InputAction.SKIP_MESSAGE_BOX, self.l10n:getText(HUDPopupMessage.L10N_SYMBOL.BUTTON_OK), self.skipTextSize, true, false) |
283 | end |
284 | |
285 | if self.currentMessage ~= nil then |
286 | local controlIndex = 1 |
287 | for i = 1, HUDPopupMessage.MAX_INPUT_ROW_COUNT do |
288 | local rowIndex = HUDPopupMessage.MAX_INPUT_ROW_COUNT - i + 1 |
289 | local inputRowVisible = rowIndex <= #self.currentMessage.controls |
290 | self.inputRows[i]:setVisible(inputRowVisible) |
291 | |
292 | if inputRowVisible then |
293 | local control = self.currentMessage.controls[controlIndex] |
294 | self.inputGlyphs[i]:setActions(control:getActionNames(), "", self.textSize, false, false) |
295 | self.inputGlyphs[i]:setKeyboardGlyphColor(HUDPopupMessage.COLOR.INPUT_GLYPH) |
296 | controlIndex = controlIndex + 1 |
297 | end |
298 | end |
299 | end |
300 | end |