You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

371 lines
15 KiB

local _,rematch = ...
local L = rematch.localization
local C = rematch.constants
local settings = rematch.settings
rematch.dialog = RematchDialog
--[[
dialogInfo properties
title = string text to display in titlebar of dialog
width = number width of canvas (will use default if none given)
height = number height of canvas (will use default if none given)
minHeight = minimum height of canvas if height not given
prompt = text to display in the prompt at bottom of dialog
cancel = text for the CancelButton
cancelFunc = function(canvas,info,subject) to run when CancelButton is clicked
accept = text for the AcceptButton
acceptFunc = function(canvas,info,subject) to run when AcceptButton is clicked
stayOnAccept = boolean whether to keep dialog up if AcceptButton clicked
other = text for the OtherButton
otherFunc = function(canvas,info,subject) to run when Other Button is clicked
stayOnOther = boolean whether to keep dialog up if OtherButton clicked
refreshFunc = function(canvas,info,subject,firstRun) to refresh dialog contents
changeFunc = function(canvas,info,subject) called when a control in dialog changes from the user
conditions = { -- condition across all layouts; for more complex differences, use different layouts
"CheckButton" = function(canvas,info,subject) return true if CheckButton should show end,
"Widget" = function(canvas,info,subject) return true if Widget should show end,
}
layouts = { -- for multi-layout dialogs
["Default"] = {"Text","Pet","etc"}, -- list of controls to use when dialog first opened
["AltLayout"] = {"Text","Pet","Feedback","etc"}, -- alternate layout for adding/removing controls
},
layout = {"Text","Pet","etc"} -- for single-layout dialogs
To change the displayed title:
rematch.dialog:SetTitle(text)
]]
local dialogInfo = {}
local openDialog -- name of the dialog that's currently open
local openLayout -- name of the dialog's layout currently applied
local lastLayout -- name of the dialog's previous layout (should be nil when dialog first shown)
local refreshHappening -- true of a refresh is happening (to ignore changes)
local applyLayout -- will be ApplyLayout function, to stop me from using it outside this module (use ChangeLayout instead!)
rematch.events:Register(rematch.dialog,"PLAYER_LOGIN",function(self)
self.InsetBg:SetPoint("BOTTOMRIGHT",-6,C.BOTTOMBAR_HEIGHT+6)
self:Reset()
self.CloseButton:SetScript("OnKeyDown",self.CloseButton.OnKeyDown)
end)
function rematch.dialog:OnMouseDown()
self:StartMoving()
end
function rematch.dialog:OnMouseUp()
self:StopMovingOrSizing()
end
function rematch.dialog:Register(name,info)
assert(type(name)=="string","Dialog "..(name or "nil").." has an invalid name")
assert(type(info)=="table","Dialog "..name.." has no info table")
info.name = name
dialogInfo[name] = info
dialogInfo[name].hasPrompt = info.prompt and true
-- if single-layout table defined, make it Default of layouts table
if info.layout then
assert(type(select(2,next(info.layout)))~="table","Default layout for "..name.." is a nested table. Meant to use layouts?")
info.layouts= {Default = CopyTable(info.layout)}
info.layout = nil
end
-- assert that all parentKeys in the layouts are valid
if info.layouts then
for layoutName,layout in pairs(info.layouts) do
for _,parentKey in ipairs(layout) do
assert(self.Canvas[parentKey],"Dialog layout "..layoutName.." for "..name.." has an invalid control "..parentKey)
end
end
end
end
-- returns definition of named dialog (or open one if no name given)
function rematch.dialog:GetDialogInfo(dialog)
if dialog then
return dialogInfo[dialog]
elseif self:IsVisible() then
return dialogInfo[openDialog]
end
end
function rematch.dialog:GetOpenDialog()
return rematch.dialog:IsVisible() and openDialog
end
function rematch.dialog:GetOpenLayout()
return rematch.dialog:IsVisible() and openLayout or "Default"
end
-- returns the subject of the currently-opened dialog
function rematch.dialog:GetSubject()
if openDialog and rematch.dialog:IsVisible() and dialogInfo[openDialog] then
return dialogInfo[openDialog].subject
end
end
-- if any dialog is open, close it by clicking the Cancel button (if on screen; hide directly otherwise)
-- this allows cancelFuncs to happen when dismissing a dialog
function rematch.dialog:HideDialog()
if openDialog and rematch.dialog:IsVisible() then
rematch.dialog.CancelButton:Click()
else
rematch.dialog:Hide()
end
end
function rematch.dialog:ToggleDialog(name,subject,layoutTab)
if openDialog==name and dialogInfo[name] and rematch.utils:AreSame(dialogInfo[name].subject,subject) then
rematch.dialog:HideDialog()
else
rematch.dialog:ShowDialog(name,subject,layoutTab)
end
end
function rematch.dialog:ShowDialog(name,subject,layoutTab)
local info = dialogInfo[name]
assert(info,"Dialog named "..(name or "nil").." doesn't exist.")
if not info then return end
rematch.utils:HideWidgets()
rematch.dialog:Hide()
openDialog = name
lastLayout = nil
-- add the info to the info space
info.subject = subject
info.layoutTab = layoutTab or "Default"
-- setup title
self.Title:SetText(info.title)
-- setup prompt and adjust canvas size for the prompt
local yoff = C.DIALOG_BOTTOM_MARGIN
if info.hasPrompt then
self.Prompt.Text:SetText(info.prompt)
self.Prompt:Show()
yoff = yoff + C.DIALOG_PROMPT_HEIGHT
else
self.Prompt:Hide()
end
self.Canvas:SetPoint("TOPLEFT",C.DIALOG_LEFT_MARGIN,-C.DIALOG_TOP_MARGIN)
self.Canvas:SetPoint("BOTTOMRIGHT",-C.DIALOG_RIGHT_MARGIN,yoff)
-- setup panel buttons
self.CancelButton.Text:SetText(info.cancel)
self.CancelButton:SetShown(info.cancel and true)
self.AcceptButton.Text:SetText(info.accept)
self.AcceptButton:SetShown(info.accept and true)
self.OtherButton.Text:SetText(info.other)
self.OtherButton:SetShown(info.other and true)
-- start with the Default layout
self:ChangeLayout("Default",true)
-- if info.layouts and info.layouts.Default then
-- self:ApplyLayout("Default")
-- end
-- -- run first refresh
-- if info.refreshFunc then
-- refreshHappening = true
-- self:StartRefresh()
-- info.refreshFunc(self.Canvas,info,subject,true)
-- end
-- -- set up dialog size
-- self:Resize()
-- finally, show the dialog
rematch.dialog:Show()
-- if choosing to open in a layoutTab (dialog mixin) other than Default, go to it now
if layoutTab and layoutTab~="Default" and self.Canvas.LayoutTabs:IsVisible() then
self.Canvas.LayoutTabs:GoToTab(layoutTab)
end
end
-- changes the currently-opened dialog to the given layoutName; firstRun is true if this is the first layout
-- being applied
function rematch.dialog:ChangeLayout(layoutName,firstRun)
local info = dialogInfo[openDialog]
if info.layouts[layoutName] and (openLayout~=layoutName or firstRun) then -- only attempt to change to a layout that exists and we're not already in
applyLayout(self,layoutName)
if info.refreshFunc then
refreshHappening = true
self:StartRefresh()
info.refreshFunc(self.Canvas,info,info.subject,firstRun)
end
self:Resize()
end
end
-- some dialogs may want to change the title displayed at the top
function rematch.dialog:SetTitle(text)
self.Title:SetText(text)
end
-- clear out everything
function rematch.dialog:Reset()
openDialog = nil
openLayout = nil
-- hide all children of the canvas
for _,child in pairs({self.Canvas:GetChildren()}) do
child:Hide()
if type(child.Reset)=="function" then
child.Reset(child) -- if element has a reset function, run it
end
end
-- enable buttons that may have been disabled
self.AcceptButton:Enable()
self.OtherButton:Enable()
self.CancelButton:Enable()
-- clear tooltips on panel buttons (so far just OtherButton has one; add RematchTooltipScripts to Accept or Cancel if needed)
self.OtherButton.tooltipTitle = nil
self.OtherButton.tooltipBody = nil
end
-- call when the currently opened dialog needs to be refreshed
function rematch.dialog:Refresh()
local info = dialogInfo[openDialog]
if not info then return end
if info.refreshFunc then
self:StartRefresh()
info.refreshFunc(self.Canvas,info,info.subject)
end
end
-- when dialog hides, reset the dialog
function rematch.dialog:OnHide()
self:Reset()
rematch.utils:SetUIJustChanged()
rematch.menus:Hide()
PlaySound(C.SOUND_DIALOG_CLOSE)
end
function rematch.dialog:OnShow()
PlaySound(C.SOUND_DIALOG_OPEN)
-- if settings.DialogX and settings.DialogY then
-- self:ClearAllPoints()
-- self:SetPoint("CENTER",UIParent,"BOTTOMLEFT",settings.DialogX,settings.DialogY)
-- end
end
-- if ESC is hit, close dialog via the cancel button
function rematch.dialog.CloseButton:OnKeyDown(key)
if key==GetBindingKey("TOGGLEGAMEMENU") then
-- if a teampicker list is expanded and CollapseOnEsc enabled, collapse list
if settings.CollapseOnEsc and rematch.dialog.Canvas.TeamPicker.Picker.List:IsVisible() and rematch.dialog.Canvas.TeamPicker.Picker.List:IsAnyExpanded() then
rematch.dialog.Canvas.TeamPicker.Picker.List:ToggleAllHeaders()
else
rematch.dialog.CancelButton:Click()
end
self:SetPropagateKeyboardInput(false)
else
self:SetPropagateKeyboardInput(true)
end
end
-- takes a layout name (index into dialogInfo[openDialog].layouts) and displays the layout's controls on the canvas
-- (it's up to the refresh function to modify the controls)
function applyLayout(self,layoutName)
local info = dialogInfo[openDialog]
if not info then return end
-- hide all children of the canvas
for _,child in pairs({self.Canvas:GetChildren()}) do
child:Hide()
end
local layout = info.layouts and info.layouts[layoutName]
assert(type(layout)=="table","Layout "..(layoutName or "nil").. " doesn't exist for "..info.name)
lastLayout = openLayout
openLayout = layoutName
local canvas = self.Canvas
local lastControl
for _,parentKey in pairs(layout) do
if parentKey=="Help" and settings.HideMenuHelp then
-- do nothing with "Help" while HideMenuHelp is enabled
elseif info.conditions and type(info.conditions[parentKey])=="function" and not info.conditions[parentKey](self.Canvas,info,info.subject) then
-- do nothing with parentKey if it has a condition and the condition isn't met (function returns false)
else
local control = canvas[parentKey]
if control then
if control.fixedWidth==0 then
-- don't touch width if fixedWidth is 0
elseif control.fixedWidth then
control:SetWidth(control.fixedWidth)
else
control:SetWidth((info.width or C.DIALOG_DEFAULT_WIDTH)-2*C.DIALOG_OUTER_PADDING)
end
control:ClearAllPoints()
if not lastControl then
control:SetPoint("TOP",0,-C.DIALOG_OUTER_PADDING)
else
control:SetPoint("TOP",lastControl,"BOTTOM",0,-C.DIALOG_INNER_PADDING)
end
lastControl = control
control:Show()
end
end
end
end
-- changes layout to the previous layout within the same dialog
function rematch.dialog:ReturnToPreviousLayout()
local info = dialogInfo[openDialog]
if not info then return end
if lastLayout and info.layouts and info.layouts[lastLayout] then
rematch.dialog:ChangeLayout(lastLayout)
end
end
-- resizes the dialog (based on layout, defined height or default height of canvas)
function rematch.dialog:Resize()
local width,height
local info = dialogInfo[openDialog]
if not info then return end
-- width generally won't change for the life of the dialog
width = max(info.width or C.DIALOG_DEFAULT_WIDTH,C.DIALOG_MIN_WIDTH)
self:SetWidth(width + C.DIALOG_LEFT_MARGIN + C.DIALOG_RIGHT_MARGIN)
local buttonWidth = (width+10)/3
self.CancelButton:SetWidth(buttonWidth)
self.AcceptButton:SetWidth(buttonWidth)
self.OtherButton:SetWidth(buttonWidth)
-- if using a layout, use it for height
if info.layouts and openLayout and info.layouts[openLayout] then
height = C.DIALOG_OUTER_PADDING*2
for _,parentKey in pairs(info.layouts[openLayout]) do
if parentKey=="Help" and settings.HideMenuHelp then
-- don't add Help if HideMenuHelp enabled
elseif info.conditions and type(info.conditions[parentKey])=="function" and not info.conditions[parentKey](self.Canvas,info,info.subject) then
-- don't add parentKey if it has a condition and the condition isn't met (function returns false)
else
height = height + self.Canvas[parentKey]:GetHeight() + C.DIALOG_INNER_PADDING
end
end
height = height - C.DIALOG_INNER_PADDING -- remove last inner padding
else -- otherwise use a defined height or default if none defined
height = info.height or C.DIALOG_DEFAULT_HEIGHT
end
height = max(height,C.DIALOG_MIN_HEIGHT)
if info.minHeight and not info.height then
height = max(height,info.minHeight)
end
--local left = self:GetLeft() -- storing topleft position before resize
--local top = self:GetTop()
self:SetHeight(height + C.DIALOG_TOP_MARGIN + (info.hasPrompt and C.DIALOG_PROMPT_HEIGHT or 0) + C.DIALOG_BOTTOM_MARGIN)
--self:ClearAllPoints()
--self:SetPoint("TOPLEFT",UIParent,"BOTTOMLEFT",left,top) -- restore topleft so shifting height keeps topleft stable
end
-- any control that can change (editboxes, checkbuttons, etc) should call this to run the dialog's changeFunc
function rematch.dialog:OnChange(force)
if refreshHappening then
return -- ignoring changes happening during a refresh
end
local info = dialogInfo[openDialog]
if not info then return end
if info.changeFunc then
info.changeFunc(rematch.dialog.Canvas,info,info.subject)
end
end
-- called a frame after StartRefresh() to reset the refreshHappening flag
local function finishRefresh()
refreshHappening = false
end
-- call this before a refresh starts to set the refreshHappening flag to true
function rematch.dialog:StartRefresh()
refreshHappening = true
rematch.timer:Start(0,finishRefresh) -- wait a frame to set it back to false
end