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.
370 lines
15 KiB
370 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
|
|
|