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.

677 lines
22 KiB

--[[
MainPanel.lua
@Author : DengSir (tdaddon@163.com)
@Link : https://dengsir.github.io
]]
local ns = select(2, ...)
local Addon = ns.Addon
local UI = ns.UI
local L = ns.L
local Director = ns.Director
local GUI = LibStub('tdGUI-1.0')
local Class = LibStub('LibClass-2.0')
local STATUS_NONE = 0
local STATUS_ADD = 1
local STATUS_EDIT = 2
local STATUS_LABELS = {
[STATUS_ADD] = L['Create script'],
[STATUS_EDIT] = L['Edit script'],
}
local Module = Addon:NewModule('UI.MainPanel', 'AceEvent-3.0')
function Module:OnInitialize()
local function UpdateLayout() self:UpdateLayout() end
local function UpdateSaveButton() self:UpdateSaveButton() end
local MainPanel = GUI:GetClass('BasicPanel'):New(UIParent) do
MainPanel.SetTitle = function(p, t) return p:SetText('tdBattlePetScript - ' .. t) end
MainPanel:Hide()
MainPanel:SetSize(550, 450)
MainPanel:SetPoint('CENTER')
MainPanel:SetMovable(true)
MainPanel:SetResizable(true)
MainPanel:SetMinResize(550, 350)
MainPanel:SetMaxResize(900, 700)
MainPanel:ShowPortrait()
MainPanel:SetFrameStrata('DIALOG')
MainPanel:SetTitle(L['Script editor'])
MainPanel:SetPortrait(ns.ICON)
MainPanel:RegisterConfig(Addon.db.profile.position)
MainPanel:SetAttribute('UIPanelLayout-enabled', true)
MainPanel:SetAttribute('UIPanelLayout-whileDead', true)
MainPanel:SetAttribute('UIPanelLayout-area', 'left')
MainPanel:SetAttribute('UIPanelLayout-pushable', 1)
end
local Inset = CreateFrame('Frame', nil, MainPanel, 'InsetFrameTemplate') do
Inset:SetPoint('TOPLEFT', 4, -60)
Inset:SetPoint('BOTTOMRIGHT', -6, 26)
Inset.Bg:SetDrawLayer('BACKGROUND')
end
local ScriptList = GUI:GetClass('ListView'):New(Inset) do
ScriptList:SetPoint('TOPLEFT', 0, 0)
ScriptList:SetPoint('BOTTOMLEFT', 0, -1)
ScriptList:SetWidth(200)
ScriptList:SetItemHeight(30)
ScriptList:SetPadding(5)
ScriptList:SetSelectMode('RADIO')
ScriptList:SetItemClass(Addon:GetClass('ScriptItem'))
ScriptList:SetCallback('OnItemFormatting', function(ScriptList, button, d)
if d.type == 'plugin' then
button:SetText(d.value:GetPluginTitle())
button:SetTexture(d.value:GetPluginIcon())
button:ShowIcon()
button:SetSelectable(false)
button:SetType(d.type)
elseif d.type == 'script' then
button:SetText(d.value:GetName())
button:HideIcon()
button:SetSelectable(true)
button:SetType(d.type)
end
end)
ScriptList:SetCallback('OnSelectChanged', function(ScriptList, index, d)
local script = d.value
self:OpenScript(script:GetPlugin(), script:GetKey(), script:GetName())
end)
ScriptList:SetCallback('OnItemEnter', function(ScriptList, button, d)
if d.type == 'script' then
UI.OpenScriptTooltip(d.value, button, 'ANCHOR_RIGHT')
else
end
end)
ScriptList:SetCallback('OnItemLeave', function()
GameTooltip:Hide()
end)
ScriptList:SetScript('OnShow', function()
self:UpdateLayout()
self:UpdateScriptList()
end)
ScriptList:SetScript('OnHide', UpdateLayout)
end
local Content = CreateFrame('Frame', nil, Inset) do
Content:SetPoint('TOPLEFT', ScriptList, 'TOPRIGHT', 2, 0)
Content:SetPoint('BOTTOMRIGHT')
end
local Banner = CreateFrame('Frame', nil, Content) do
Banner:SetPoint('BOTTOMLEFT', Content, 'TOPLEFT')
Banner:SetPoint('BOTTOMRIGHT', Content, 'TOPRIGHT', -30, 0)
Banner:SetHeight(35)
end
local ShareButton = CreateFrame('Button', nil, MainPanel) do
ShareButton:SetSize(26, 26)
ShareButton:SetPoint('LEFT', Banner, 'RIGHT')
ShareButton:SetNormalTexture([[Interface\CHATFRAME\UI-ChatIcon-Chat-Up]])
ShareButton:SetPushedTexture([[Interface\CHATFRAME\UI-ChatIcon-Chat-Down]])
ShareButton:SetHighlightTexture([[Interface\CHATFRAME\UI-ChatIcon-BlinkHilight]], 'ADD')
ShareButton:SetScript('OnClick', function()
self:OnShareButtonClick()
end)
end
local HelpIcon = CreateFrame('Button', nil, Banner) do
HelpIcon:SetSize(28, 28)
HelpIcon:SetPoint('LEFT', 5, 0)
local Border = HelpIcon:CreateTexture(nil, 'ARTWORK') do
Border:SetTexture([[Interface\PetBattles\PetBattleHUD]])
Border:SetPoint('TOPLEFT', 0, 1)
Border:SetPoint('BOTTOMRIGHT', 1, 0)
Border:SetTexCoord(0.884765625, 0.943359375, 0.681640625, 0.798828125)
end
local Highlight = HelpIcon:CreateTexture(nil, 'HIGHLIGHT') do
Highlight:SetPoint('TOPLEFT', -1, 1)
Highlight:SetPoint('BOTTOMRIGHT', 2, -2)
Highlight:SetBlendMode('ADD')
Highlight:SetTexture([[Interface\Minimap\UI-Minimap-ZoomButton-Highlight]])
end
local Icon = HelpIcon:CreateTexture(nil, 'BORDER') do
Icon:SetMask([[Interface\Minimap\UI-Minimap-Background]])
Icon:SetSize(28, 28)
Icon:SetAllPoints(true)
end
HelpIcon:SetScript('OnEnter', function(HelpIcon)
UI.OpenScriptTooltip(self.script, HelpIcon, 'ANCHOR_BOTTOMRIGHT')
end)
HelpIcon:SetScript('OnLeave', function()
GameTooltip:Hide()
end)
function HelpIcon:SetTexture(texture)
return Icon:SetTexture(texture)
end
end
local ExtraButton = CreateFrame('CheckButton', nil, Banner) do
ExtraButton:SetSize(26, 26)
ExtraButton:SetPoint('RIGHT')
ExtraButton:SetNormalTexture([[Interface\CHATFRAME\UI-ChatIcon-ScrollDown-Up]])
ExtraButton:SetPushedTexture([[Interface\CHATFRAME\UI-ChatIcon-ScrollDown-Down]])
ExtraButton:SetHighlightTexture([[Interface\CHATFRAME\UI-ChatIcon-BlinkHilight]], 'ADD')
ExtraButton:SetScript('OnClick', function(ExtraButton)
if ExtraButton:GetChecked() then
ExtraButton:SetNormalTexture([[Interface\CHATFRAME\UI-ChatIcon-ScrollUp-Up]])
ExtraButton:SetPushedTexture([[Interface\CHATFRAME\UI-ChatIcon-ScrollUp-Down]])
PlaySound(SOUNDKIT and SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_OFF or 'igMainMenuOptionCheckBoxOff')
else
ExtraButton:SetNormalTexture([[Interface\CHATFRAME\UI-ChatIcon-ScrollDown-Up]])
ExtraButton:SetPushedTexture([[Interface\CHATFRAME\UI-ChatIcon-ScrollDown-Down]])
PlaySound(SOUNDKIT and SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON or 'igMainMenuOptionCheckBoxOn')
end
self.ExtraFrame:SetShown(ExtraButton:GetChecked())
end)
ExtraButton:SetScript('OnEnter', function(ExtraButton)
GameTooltip:SetOwner(ExtraButton, 'ANCHOR_BOTTOMLEFT')
GameTooltip:SetText(L.SCRIPT_EDITOR_LABEL_TOGGLE_EXTRA)
GameTooltip:Show()
end)
ExtraButton:SetScript('OnLeave', function()
GameTooltip:Hide()
end)
end
local Name = Banner:CreateFontString(nil, 'ARTWORK', 'GameFontNormalOutline') do
Name:SetHeight(30)
Name:SetJustifyH('CENTER')
Name:SetJustifyV('MIDDLE')
Name:SetPoint('LEFT', HelpIcon, 'RIGHT', 2, 0)
Name:SetPoint('RIGHT', ExtraButton, 'LEFT', -2, 0)
end
local SaveButton = CreateFrame('Button', nil, Content, 'UIPanelButtonTemplate') do
SaveButton:SetPoint('BOTTOMRIGHT', MainPanel, 'BOTTOMRIGHT', -10, 4)
SaveButton:SetSize(80, 22)
SaveButton:SetText(SAVE)
SaveButton:SetScript('OnClick', function()
self:OnSaveButtonClick()
end)
end
local DebugButton = CreateFrame('Button', nil, Content, 'UIPanelButtonTemplate') do
DebugButton:SetPoint('RIGHT', SaveButton, 'LEFT')
DebugButton:SetSize(80, 22)
DebugButton:SetText(L['Run'])
DebugButton:SetScript('OnClick', function()
self:Run()
end)
end
local DeleteButton = CreateFrame('Button', nil, Content, 'UIPanelButtonTemplate') do
DeleteButton:SetPoint('BOTTOMLEFT', MainPanel, 'BOTTOMLEFT', 8, 4)
DeleteButton:SetSize(80, 22)
DeleteButton:SetText(DELETE)
DeleteButton:SetScript('OnClick', function()
self:OnDeleteButtonClick()
end)
end
local ExtraFrame = CreateFrame('Frame', nil, Content) do
ExtraFrame:Hide()
ExtraFrame:SetPoint('TOPLEFT')
ExtraFrame:SetPoint('TOPRIGHT')
ExtraFrame:SetHeight(40)
ExtraFrame:EnableMouse(true)
ExtraFrame:SetScript('OnShow', UpdateLayout)
ExtraFrame:SetScript('OnHide', UpdateLayout)
end
local function MakeBox(className, parent, labelText)
local class = Class:IsClass(className) and className or GUI:GetClass(className)
local box = class:New(parent, true) do
local label = box:CreateFontString(nil, 'ARTWORK', 'GameFontNormalSmall') do
label:SetPoint('BOTTOMLEFT', box, 'TOPLEFT')
label:SetText(labelText)
end
end
return box
end
local NameBox = MakeBox('InputBox', ExtraFrame, L['Script name']) do
NameBox:SetPoint('TOPLEFT', 10, -25)
NameBox:SetPoint('TOPRIGHT', -10, -25)
NameBox:SetHeight(22)
NameBox:SetCallback('OnTextChanged', UpdateSaveButton)
end
local ScriptEditor = CreateFrame('Frame', nil, Content) do
ScriptEditor:SetPoint('TOPLEFT')
ScriptEditor:SetPoint('BOTTOMRIGHT')
end
local ScriptBox = MakeBox(Addon:GetClass('ScriptEditor'), ScriptEditor, L['Script']) do
ScriptBox:SetPoint('TOPLEFT', 10, -25)
ScriptBox:SetPoint('BOTTOMRIGHT', -10, 10)
ScriptBox:SetCallback('OnTextChanged', function(ScriptBox, userInput)
ScriptBox:OnTextChanged(userInput)
self.BugFrame:Hide()
self:UpdateSaveButton()
end)
end
local BugFrame = CreateFrame('Frame', nil, Content, 'BackdropTemplate') do
BugFrame:Hide()
BugFrame:SetPoint('BOTTOMLEFT', 8, 6)
BugFrame:SetPoint('BOTTOMRIGHT', -8, 6)
BugFrame:SetHeight(32)
BugFrame:SetBackdrop{
edgeFile = [[Interface\Tooltips\UI-Tooltip-Border]],
tile = true,
edgeSize = 16,
}
BugFrame:SetBackdropBorderColor(0.5, 0.5, 0.5)
local Bg = BugFrame:CreateTexture(nil, 'BACKGROUND') do
Bg:SetTexture([[Interface\FrameGeneral\UI-Background-Marble]])
Bg:SetPoint('TOPLEFT', 3, -3)
Bg:SetPoint('BOTTOMRIGHT', -3, 3)
Bg:SetTexCoord(0, 1, 0, 0.2)
end
local Icon = BugFrame:CreateTexture(nil, 'ARTWORK') do
Icon:SetSize(26, 26)
Icon:SetTexture([[Interface\HELPFRAME\HelpIcon-Bug]])
Icon:SetPoint('LEFT', 10, 0)
end
local Text = BugFrame:CreateFontString(nil, 'ARTWORK', 'GameFontRed') do
Text:SetPoint('LEFT', Icon, 'RIGHT', 5, 0)
Text:SetPoint('RIGHT', -5, 0)
Text:SetJustifyH('LEFT')
Text:SetWordWrap(false)
end
BugFrame.Text = Text
BugFrame.Icon = Icon
BugFrame:SetScript('OnEnter', function(BugFrame)
if not BugFrame.err then
return
end
GameTooltip:SetOwner(BugFrame, 'ANCHOR_TOP')
GameTooltip:SetText('Bug')
GameTooltip:AddLine(BugFrame.message, 1, 1, 1, true)
GameTooltip:AddLine(BugFrame.err, 1, 0, 0, true)
GameTooltip:Show()
end)
BugFrame:SetScript('OnLeave', GameTooltip_Hide)
BugFrame:SetScript('OnShow', UpdateLayout)
BugFrame:SetScript('OnHide', UpdateLayout)
end
local EditBoxGroup = GUI:GetClass('EditBoxGroup'):New() do
EditBoxGroup:RegisterEditBox(NameBox)
EditBoxGroup:RegisterEditBox(ScriptBox.EditBox)
end
local BlockDialog = GUI:GetClass('BlockDialog'):New(MainPanel) do
BlockDialog:SetPoint('TOPLEFT', 3, -22)
BlockDialog:SetPoint('BOTTOMRIGHT', -3, 3)
BlockDialog:SetFrameLevel(MainPanel:GetFrameLevel() + 100)
end
self.Banner = Banner
self.BlockDialog = BlockDialog
self.BugFrame = BugFrame
self.CollapseButton = CollapseButton
self.Content = Content
self.Content = Content
self.DebugButton = DebugButton
self.DeleteButton = DeleteButton
self.EditBoxGroup = EditBoxGroup
self.ExtraFrame = ExtraFrame
self.HelpIcon = HelpIcon
self.MainPanel = MainPanel
self.Name = Name
self.NameBox = NameBox
self.SaveButton = SaveButton
self.ScriptBox = ScriptBox
self.ScriptEditor = ScriptEditor
self.ScriptList = ScriptList
self.ShareButton = ShareButton
self:Bind('UpdateLayout', MainPanel)
self:Bind('UpdateStatus', Content)
self:Bind('UpdateSaveButton', SaveButton)
end
function Module:OnEnable()
self:OnFontChanged()
self:RegisterEvent('PET_BATTLE_ACTION_SELECTED')
self:RegisterEvent('PET_BATTLE_OPENING_START', 'UpdateDebugButton')
self:RegisterEvent('PET_BATTLE_CLOSE', 'UpdateDebugButton')
self:RegisterEvent('PET_BATTLE_PET_ROUND_PLAYBACK_COMPLETE', 'UpdateDebugButton')
self:RegisterMessage('PET_BATTLE_SCRIPT_SCRIPT_LIST_UPDATE', 'UpdateScriptList')
self:RegisterMessage('PET_BATTLE_SCRIPT_RESET_FRAMES')
self:RegisterMessage('PET_BATTLE_SCRIPT_SETTING_CHANGED_editorFontFace', 'OnFontChanged')
self:RegisterMessage('PET_BATTLE_SCRIPT_SETTING_CHANGED_editorFontSize', 'OnFontChanged')
end
function Module:OnFontChanged()
self.ScriptBox:SetFont(Addon:GetSetting('editorFontFace'), Addon:GetSetting('editorFontSize'))
end
function Module:PET_BATTLE_ACTION_SELECTED()
self.DebugButton:Disable()
end
function Module:PET_BATTLE_SCRIPT_RESET_FRAMES()
self.MainPanel:RestorePosition()
self.MainPanel:RestoreSize()
end
function Module:UpdateScriptList()
if not self.ScriptList:IsShown() then
return
end
local list = {} do
for _, plugin in Addon:IteratePlugins() do
tinsert(list, {
type = 'plugin',
value = plugin
})
local scripts = {} do
for _, script in plugin:IterateScripts() do
tinsert(scripts, script)
end
sort(scripts, function(a, b)
return a:GetName() < b:GetName()
end)
end
for _, script in ipairs(scripts) do
tinsert(list, {
type = 'script',
value = script
})
end
end
end
self.ScriptList:SetItemList(list)
self.ScriptList:Refresh()
end
function Module:Message(flag, message, err)
self.BugFrame.Icon:SetTexture(flag and [[Interface\DialogFrame\UI-Dialog-Icon-AlertOther]] or [[Interface\DialogFrame\UI-Dialog-Icon-AlertNew]])
self.BugFrame.Text:SetFontObject(flag and 'GameFontNormalSmall' or 'GameFontRedSmall')
self.BugFrame.Text:SetText(err and message .. ': ' .. err or message)
self.BugFrame:Show()
self.BugFrame.err = err
self.BugFrame.message = message
end
function Module:Clear()
self.isDialog = false
self.script = nil
self.plugin = nil
self.key = nil
self.status = STATUS_NONE
end
function Module:OpenScript(plugin, key, defaultName)
local script = plugin:GetScript(key)
if script then
self.script = script
self.status = STATUS_EDIT
else
self.script = Addon:GetClass('Script'):New({}, plugin, key)
self.status = STATUS_ADD
end
self.plugin = plugin
self.key = key
self.defaultName = self.script:GetName() or defaultName
self:UpdateLayout()
self:UpdateSaveButton()
self:UpdateStatus()
self:UpdateScript()
self.Content:Show()
end
function Module:OpenScriptDialog(...)
self:OpenScript(...)
self:ShowDialog()
end
function Module:ShowDialog()
self.isDialog = true
self.ScriptList:Hide()
self.MainPanel:RestorePosition()
self.MainPanel:RestoreSize()
self.MainPanel:SetMovable(true)
self.MainPanel:SetResizable(true)
self.MainPanel:SetFrameStrata('DIALOG')
self.MainPanel:SetTitle(L['Script editor'])
if self.MainPanel:IsShown() then
self:HidePanel()
end
self.MainPanel:Show()
end
function Module:ShowPanel()
self:Clear()
self.ScriptList:Show()
self.Content:Hide()
self.MainPanel:SetSize(550, 450)
self.MainPanel:SetMovable(false)
self.MainPanel:SetResizable(false)
self.MainPanel:SetFrameStrata('MEDIUM')
self.MainPanel:SetTitle(L['Script manager'])
if self.MainPanel:IsShown() then
self:HidePanel()
end
self.MainPanel:SetAttribute('UIPanelLayout-defined', true)
ShowUIPanel(self.MainPanel)
end
function Module:TogglePanel()
if self.MainPanel:IsShown() then
self:HidePanel()
else
self:ShowPanel()
end
end
function Module:HidePanel()
HideUIPanel(self.MainPanel)
end
function Module:UpdateLayout()
if not self.MainPanel:IsVisible() then
return
end
if self.ScriptList:IsShown() then
self.Content:SetPoint('TOPLEFT', self.ScriptList, 'TOPRIGHT', 2, 0)
self.MainPanel:SetMinResize(550, 350)
self.MainPanel:SetMaxResize(900, 700)
self.MainPanel:ShowPortrait()
else
self.Content:SetPoint('TOPLEFT')
self.MainPanel:SetMinResize(350, 350)
self.MainPanel:SetMaxResize(700, 700)
self.MainPanel:HidePortrait()
end
if self.ExtraFrame:IsShown() then
self.ScriptEditor:SetPoint('TOPLEFT', self.ExtraFrame, 'BOTTOMLEFT')
else
self.ScriptEditor:SetPoint('TOPLEFT')
end
if self.BugFrame:IsShown() then
self.ScriptEditor:SetPoint('BOTTOMRIGHT', 0, 30)
else
self.ScriptEditor:SetPoint('BOTTOMRIGHT')
end
end
function Module:UpdateScript()
self.BugFrame:Hide()
self.BlockDialog:Hide()
self.HelpIcon:SetTexture(self.plugin:GetPluginIcon())
self.NameBox:SetText(self.defaultName)
self.ScriptBox:SetText(self.script:GetCode() or '')
end
function Module:UpdateDebugButton()
self.DebugButton:SetShown(C_PetBattles.IsInBattle())
self.DebugButton:SetEnabled(C_PetBattles.IsSkipAvailable() or C_PetBattles.ShouldShowPetSelect())
end
function Module:UpdateSaveButton()
self.SaveButton:SetEnabled(self:IsCanSave())
end
function Module:UpdateStatus()
self.Name:SetFormattedText('%s: |cff00ff00%s|r-|cffffffff%s|r', STATUS_LABELS[self.status], self.plugin:GetPluginTitle(), self.defaultName)
self.DeleteButton:SetShown(self.status == STATUS_EDIT)
self.DebugButton:SetShown(C_PetBattles.IsInBattle())
end
function Module:IsCanSave()
if not self:GetEditBoxText(self.ScriptBox) then
return false
end
return self.script:GetCode() ~= self:GetEditBoxText(self.ScriptBox) or
self.script:GetName() ~= self:GetEditBoxText(self.NameBox)
end
function Module:GetEditBoxText(editBox)
local text = editBox:GetText():trim()
return text ~= '' and text or nil
end
function Module:OnSaveButtonClick()
local ok, err = self.script:SetCode(self.ScriptBox:GetText():trim())
if ok and not self.status ~= STATUS_EDIT then
self.status = STATUS_EDIT
self.plugin:AddScript(self.key, self.script)
end
self:Message(ok, ok and L['Save success'] or L['Found error'], err)
if not ok then
return
end
self.script:SetName(self:GetEditBoxText(self.NameBox))
self.EditBoxGroup:ClearFocus()
self:UpdateSaveButton()
self:UpdateStatus()
end
function Module:OnBeautyButtonClick()
if not self.script:GetCode() or self:IsCanSave() then
return
end
local code = Director:BeautyScript(self.script:GetScript())
self.ScriptBox:SetText(code)
end
function Module:OnDeleteButtonClick()
self.EditBoxGroup:ClearFocus()
self.BlockDialog:Open{
text = format(L.SCRIPT_EDITOR_DELETE_SCRIPT, self.plugin:GetPluginTitle(), self.script:GetName()),
delay = Addon:GetSetting('noWaitDeleteScript') and 0 or 3,
ctx = self.script,
OnAccept = function(script)
script:GetPlugin():RemoveScript(script:GetKey())
if self.isDialog then
self:HidePanel()
else
self:ShowPanel()
end
end,
}
end
function Module:Run()
local script, err = Director:BuildScript(self:GetEditBoxText(self.ScriptBox))
if not script then
self:Message(false, L['Found error'], err)
else
Director:Debug(script)
end
end
function Module:OnShareButtonClick()
GUI:ToggleMenu(self.ShareButton, {
{
text = L['Beauty script'],
disabled = not self.script or not self.script:GetCode() or self:IsCanSave(),
func = function()
self:OnBeautyButtonClick()
end
},
{
text = L['Import'],
func = function()
UI.Import.Frame:Show()
self:HidePanel()
end
},
{
text = L['Export'],
disabled = self.status ~= STATUS_EDIT,
func = function()
self.BlockDialog:Open{
text = L['Export'],
cancelHidden = true,
acceptText = OKAY,
editBox = true,
editText = Addon:Export(self.script),
editFocus = true,
editHighlightAll = true,
editFocusLost = 'ACCEPT',
}
end
},
{
text = L['Options'],
func = function()
Addon:OpenOptionFrame()
end
}
})
end
function Module:Bind(method, obj)
GUI:Embed(obj, 'Refresh')
local fn = self[method]
obj.Update = function(...)
return fn(self, ...)
end
self[method] = function()
return obj:Refresh()
end
end