881 lines
28 KiB
Lua
881 lines
28 KiB
Lua
if not WeakAuras.IsLibsOK() then return end
|
||
local AddonName = ...
|
||
local OptionsPrivate = select(2, ...)
|
||
|
||
-- Lua APIs
|
||
local pairs, type, ipairs = pairs, type, ipairs
|
||
local gsub = gsub
|
||
|
||
-- WoW APIs
|
||
local CreateFrame = CreateFrame
|
||
|
||
local AceGUI = LibStub("AceGUI-3.0")
|
||
local SharedMedia = LibStub("LibSharedMedia-3.0")
|
||
local IndentationLib = IndentationLib
|
||
|
||
local WeakAuras = WeakAuras
|
||
local L = WeakAuras.L
|
||
|
||
local textEditor
|
||
|
||
local editor_themes = {
|
||
["Standard"] = {
|
||
["Table"] = "|c00ff3333",
|
||
["Arithmetic"] = "|c00ff3333",
|
||
["Relational"] = "|c00ff3333",
|
||
["Logical"] = "|c004444ff",
|
||
["Special"] = "|c00ff3333",
|
||
["Keyword"] = "|c004444ff",
|
||
["Comment"] = "|c0000aa00",
|
||
["Number"] = "|c00ff9900",
|
||
["String"] = "|c00999999"
|
||
},
|
||
["Monokai"] = {
|
||
["Table"] = "|c00ffffff",
|
||
["Arithmetic"] = "|c00f92672",
|
||
["Relational"] = "|c00ff3333",
|
||
["Logical"] = "|c00f92672",
|
||
["Special"] = "|c0066d9ef",
|
||
["Keyword"] = "|c00f92672",
|
||
["Comment"] = "|c0075715e",
|
||
["Number"] = "|c00ae81ff",
|
||
["String"] = "|c00e6db74"
|
||
},
|
||
["Obsidian"] = {
|
||
["Table"] = "|c00AFC0E5",
|
||
["Arithmetic"] = "|c00E0E2E4",
|
||
["Relational"] = "|c00B3B689",
|
||
["Logical"] = "|c0093C763",
|
||
["Special"] = "|c00AFC0E5",
|
||
["Keyword"] = "|c0093C763",
|
||
["Comment"] = "|c0066747B",
|
||
["Number"] = "|c00FFCD22",
|
||
["String"] = "|c00EC7600"
|
||
}
|
||
}
|
||
|
||
if not WeakAurasSaved.editor_tab_spaces then WeakAurasSaved.editor_tab_spaces = 4 end
|
||
if not WeakAurasSaved.editor_font_size then WeakAurasSaved.editor_font_size = 12 end -- set default font size if missing
|
||
local color_scheme = {[0] = "|r"}
|
||
local function set_scheme()
|
||
if not WeakAurasSaved.editor_theme then
|
||
WeakAurasSaved.editor_theme = "Monokai"
|
||
end
|
||
local theme = editor_themes[WeakAurasSaved.editor_theme]
|
||
color_scheme[IndentationLib.tokens.TOKEN_SPECIAL] = theme["Special"]
|
||
color_scheme[IndentationLib.tokens.TOKEN_KEYWORD] = theme["Keyword"]
|
||
color_scheme[IndentationLib.tokens.TOKEN_COMMENT_SHORT] = theme["Comment"]
|
||
color_scheme[IndentationLib.tokens.TOKEN_COMMENT_LONG] = theme["Comment"]
|
||
color_scheme[IndentationLib.tokens.TOKEN_NUMBER] = theme["Number"]
|
||
color_scheme[IndentationLib.tokens.TOKEN_STRING] = theme["String"]
|
||
|
||
color_scheme["..."] = theme["Table"]
|
||
color_scheme["{"] = theme["Table"]
|
||
color_scheme["}"] = theme["Table"]
|
||
color_scheme["["] = theme["Table"]
|
||
color_scheme["]"] = theme["Table"]
|
||
|
||
color_scheme["+"] = theme["Arithmetic"]
|
||
color_scheme["-"] = theme["Arithmetic"]
|
||
color_scheme["/"] = theme["Arithmetic"]
|
||
color_scheme["*"] = theme["Arithmetic"]
|
||
color_scheme[".."] = theme["Arithmetic"]
|
||
|
||
color_scheme["=="] = theme["Relational"]
|
||
color_scheme["<"] = theme["Relational"]
|
||
color_scheme["<="] = theme["Relational"]
|
||
color_scheme[">"] = theme["Relational"]
|
||
color_scheme[">="] = theme["Relational"]
|
||
color_scheme["~="] = theme["Relational"]
|
||
|
||
color_scheme["and"] = theme["Logical"]
|
||
color_scheme["or"] = theme["Logical"]
|
||
color_scheme["not"] = theme["Logical"]
|
||
end
|
||
|
||
-- Define the premade snippets
|
||
local premadeSnippets = {
|
||
{
|
||
name = "Basic function",
|
||
snippet = [=[
|
||
function()
|
||
|
||
return
|
||
end]=]
|
||
},
|
||
{
|
||
name = "Custom Activation",
|
||
snippet = [=[
|
||
function(trigger)
|
||
return trigger[1] and (trigger[2] or trigger[3])
|
||
end]=]
|
||
},
|
||
{
|
||
name = "Trigger: CLEU",
|
||
snippet = [=[
|
||
function(event, timestamp, subEvent, sourceGUID, sourceName, sourceFlags, destGUID, destName, destFlags, ...)
|
||
|
||
return
|
||
end]=]
|
||
},
|
||
{
|
||
name = "Simple throttle",
|
||
snippet = [=[
|
||
if not aura_env.last or aura_env.last < GetTime() - 1 then
|
||
aura_env.last = GetTime()
|
||
|
||
end]=]
|
||
},
|
||
{
|
||
name = "Trigger State Updater",
|
||
snippet = [=[
|
||
function(allstates, event, ...)
|
||
allstates:Update("", {
|
||
progressType = "static"||"timed",
|
||
value = ,
|
||
total = ,
|
||
duration = ,
|
||
expirationTime = ,
|
||
autoHide = true,
|
||
name = ,
|
||
icon = ,
|
||
stacks = ,
|
||
index = ,
|
||
})
|
||
-- allstates:Remove("")
|
||
-- allstates:RemoveAll()
|
||
end]=]
|
||
},
|
||
}
|
||
|
||
local function ConstructTextEditor(frame)
|
||
local group = AceGUI:Create("WeakAurasInlineGroup")
|
||
group.frame:SetParent(frame)
|
||
group.frame:SetPoint("TOPLEFT", frame, "TOPLEFT", 17, -63);
|
||
group.frame:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -17, 46);
|
||
group.frame:Hide()
|
||
group:SetLayout("flow")
|
||
|
||
local editor = AceGUI:Create("MultiLineEditBox")
|
||
editor.editBox.group = group
|
||
editor:SetFullWidth(true)
|
||
editor:SetFullHeight(true)
|
||
editor:DisableButton(true)
|
||
local fontPath = SharedMedia:Fetch("font", "Fira Mono Medium")
|
||
if (fontPath) then
|
||
editor.editBox:SetFont(fontPath, WeakAurasSaved.editor_font_size)
|
||
end
|
||
group:AddChild(editor)
|
||
|
||
local originalOnCursorChanged = editor.editBox:GetScript("OnCursorChanged")
|
||
editor.editBox:SetScript("OnCursorChanged", function(self, ...)
|
||
-- WORKAROUND the editbox sends spurious OnCursorChanged events if its resized
|
||
-- That makes AceGUI scroll the editbox to make the cursor visible, leading to unintended
|
||
-- movements. Prevent all of that by checking if the edit box has focus, as otherwise the cursor
|
||
-- is invisible, and we don't care about making it visible
|
||
if not self:HasFocus() then
|
||
return
|
||
end
|
||
originalOnCursorChanged(self, ...)
|
||
end)
|
||
|
||
-- The indention lib overrides GetText, but for the line number
|
||
-- display we ned the original, so save it here.
|
||
local originalGetText = editor.editBox.GetText
|
||
local originalSetText = editor.editBox.SetText
|
||
set_scheme()
|
||
IndentationLib.enable(editor.editBox, color_scheme, WeakAurasSaved.editor_tab_spaces)
|
||
|
||
local cancel = CreateFrame("Button", nil, group.frame, "UIPanelButtonTemplate")
|
||
cancel:SetScript(
|
||
"OnClick",
|
||
function()
|
||
group:CancelClose()
|
||
end
|
||
)
|
||
cancel:SetPoint("BOTTOMRIGHT", -20, -24)
|
||
cancel:SetFrameLevel(cancel:GetFrameLevel() + 1)
|
||
cancel:SetHeight(20)
|
||
cancel:SetWidth(100)
|
||
cancel:SetText(L["Cancel"])
|
||
|
||
local close = CreateFrame("Button", nil, group.frame, "UIPanelButtonTemplate")
|
||
close:SetScript(
|
||
"OnClick",
|
||
function()
|
||
group:Close()
|
||
end
|
||
)
|
||
close:SetPoint("RIGHT", cancel, "LEFT", -10, 0)
|
||
close:SetFrameLevel(close:GetFrameLevel() + 1)
|
||
close:SetHeight(20)
|
||
close:SetWidth(100)
|
||
close:SetText(L["Done"])
|
||
|
||
local settings_frame = CreateFrame("Button", "WASettingsButton", close, "UIPanelButtonTemplate")
|
||
settings_frame:SetPoint("RIGHT", close, "LEFT", -10, 0)
|
||
settings_frame:SetHeight(20)
|
||
settings_frame:SetWidth(100)
|
||
settings_frame:SetText(L["Settings"])
|
||
settings_frame:RegisterForClicks("LeftButtonUp")
|
||
|
||
local helpButton = CreateFrame("Button", nil, group.frame, "UIPanelButtonTemplate")
|
||
helpButton:SetPoint("BOTTOMLEFT", 0, -24)
|
||
helpButton:SetFrameLevel(cancel:GetFrameLevel() + 1)
|
||
helpButton:SetHeight(20)
|
||
helpButton:SetWidth(100)
|
||
helpButton:SetText(L["Help"])
|
||
|
||
local dropdown = CreateFrame("Frame", "SettingsMenuFrame", settings_frame, "UIDropDownMenuTemplate")
|
||
|
||
local function settings_dropdown_initialize(frame, level, menu)
|
||
if level == 1 then
|
||
for k, v in pairs(editor_themes) do
|
||
local item = {
|
||
text = k,
|
||
isNotRadio = false,
|
||
checked = function()
|
||
return WeakAurasSaved.editor_theme == k
|
||
end,
|
||
func = function()
|
||
WeakAurasSaved.editor_theme = k
|
||
set_scheme()
|
||
editor.editBox:SetText(editor.editBox:GetText())
|
||
end
|
||
}
|
||
UIDropDownMenu_AddButton(item, level)
|
||
end
|
||
UIDropDownMenu_AddButton(
|
||
{
|
||
text = L["Bracket Matching"],
|
||
isNotRadio = true,
|
||
checked = function()
|
||
return WeakAurasSaved.editor_bracket_matching
|
||
end,
|
||
func = function()
|
||
WeakAurasSaved.editor_bracket_matching = not WeakAurasSaved.editor_bracket_matching
|
||
end
|
||
},
|
||
level)
|
||
UIDropDownMenu_AddButton(
|
||
{
|
||
text = L["Indent Size"],
|
||
hasArrow = true,
|
||
notCheckable = true,
|
||
menuList = "spaces"
|
||
},
|
||
level)
|
||
UIDropDownMenu_AddButton(
|
||
{
|
||
text = WeakAuras.newFeatureString .. L["Font Size"],
|
||
hasArrow = true,
|
||
notCheckable = true,
|
||
menuList = "sizes"
|
||
},
|
||
level)
|
||
elseif menu == "spaces" then
|
||
local spaces = {2,4}
|
||
for _, i in pairs(spaces) do
|
||
UIDropDownMenu_AddButton(
|
||
{
|
||
text = i,
|
||
isNotRadio = false,
|
||
checked = function()
|
||
return WeakAurasSaved.editor_tab_spaces == i
|
||
end,
|
||
func = function()
|
||
WeakAurasSaved.editor_tab_spaces = i
|
||
IndentationLib.enable(editor.editBox, color_scheme, WeakAurasSaved.editor_tab_spaces)
|
||
editor.editBox:SetText(editor.editBox:GetText().."\n")
|
||
IndentationLib.indentEditbox(editor.editBox)
|
||
end
|
||
},
|
||
level)
|
||
end
|
||
elseif menu == "sizes" then
|
||
local sizes = {10, 12, 14, 16}
|
||
for _, i in pairs(sizes) do
|
||
UIDropDownMenu_AddButton(
|
||
{
|
||
text = i,
|
||
isNotRadio = false,
|
||
checked = function()
|
||
return WeakAurasSaved.editor_font_size == i
|
||
end,
|
||
func = function()
|
||
WeakAurasSaved.editor_font_size = i
|
||
editor.editBox:SetFont(fontPath, WeakAurasSaved.editor_font_size)
|
||
end
|
||
},
|
||
level)
|
||
end
|
||
end
|
||
end
|
||
UIDropDownMenu_Initialize(dropdown, settings_dropdown_initialize, "MENU")
|
||
|
||
settings_frame:SetScript(
|
||
"OnClick",
|
||
function(self, button, down)
|
||
ToggleDropDownMenu(1, nil, dropdown, settings_frame, 0, 0)
|
||
end
|
||
)
|
||
|
||
-- Make Snippets button (top right, near the line number)
|
||
local snippetsButton = CreateFrame("Button", "WASnippetsButton", group.frame, "UIPanelButtonTemplate")
|
||
snippetsButton:SetPoint("BOTTOMRIGHT", editor.frame, "TOPRIGHT", -20, -10)
|
||
snippetsButton:SetFrameLevel(group.frame:GetFrameLevel() + 2)
|
||
snippetsButton:SetHeight(20)
|
||
snippetsButton:SetWidth(100)
|
||
snippetsButton:SetText(L["Snippets"])
|
||
snippetsButton:RegisterForClicks("LeftButtonUp")
|
||
|
||
-- Get the saved snippets from SavedVars
|
||
WeakAurasOptionsSaved.savedSnippets = WeakAurasOptionsSaved.savedSnippets or {}
|
||
local savedSnippets = WeakAurasOptionsSaved.savedSnippets
|
||
|
||
-- function to build snippet selection list
|
||
local function UpdateSnippets(frame)
|
||
-- release first before rebuilding
|
||
frame:ReleaseChildren()
|
||
table.sort(
|
||
savedSnippets,
|
||
function(a, b)
|
||
return a.name < b.name
|
||
end
|
||
)
|
||
|
||
local heading1 = AceGUI:Create("Heading")
|
||
heading1:SetText(L["Premade Snippets"])
|
||
heading1:SetRelativeWidth(0.7)
|
||
frame:AddChild(heading1)
|
||
|
||
-- Iterate premade snippets and make buttons for them
|
||
for order, snippet in ipairs(premadeSnippets) do
|
||
local button = AceGUI:Create("WeakAurasSnippetButton")
|
||
button:SetTitle(snippet.name)
|
||
button:SetDescription(snippet.snippet)
|
||
button:SetCallback(
|
||
"OnClick",
|
||
function()
|
||
editor.editBox:Insert(snippet.snippet)
|
||
editor:SetFocus()
|
||
end
|
||
)
|
||
button:SetRelativeWidth(1)
|
||
frame:AddChild(button)
|
||
end
|
||
|
||
local heading2 = AceGUI:Create("Heading")
|
||
heading2:SetText(L["Your Saved Snippets"])
|
||
heading2:SetRelativeWidth(1)
|
||
frame:AddChild(heading2)
|
||
|
||
-- iterate saved snippets and make buttons
|
||
for order, snippet in ipairs(savedSnippets) do
|
||
local button = AceGUI:Create("WeakAurasSnippetButton")
|
||
local snippetInsert = gsub(snippet.snippet, "|", "||")
|
||
button:SetTitle(snippet.name)
|
||
button:SetDescription(snippetInsert)
|
||
button:SetEditable(true)
|
||
button:SetRelativeWidth(1)
|
||
button:SetNew(snippet.new)
|
||
snippet.new = false
|
||
button:SetCallback(
|
||
"OnClick",
|
||
function()
|
||
editor.editBox:Insert(snippetInsert)
|
||
editor:SetFocus()
|
||
end
|
||
)
|
||
button.deleteButton:SetScript(
|
||
"OnClick",
|
||
function()
|
||
table.remove(savedSnippets, order)
|
||
UpdateSnippets(frame)
|
||
end
|
||
)
|
||
button:SetCallback(
|
||
"OnEnterPressed",
|
||
function()
|
||
local newName = button.renameEditBox:GetText()
|
||
if newName and #newName > 0 then
|
||
local found = false
|
||
for _, snippet in ipairs(savedSnippets) do
|
||
if snippet.name == newName then
|
||
found = true
|
||
break
|
||
end
|
||
end
|
||
if not found then
|
||
savedSnippets[order].name = newName
|
||
UpdateSnippets(frame)
|
||
end
|
||
end
|
||
end
|
||
)
|
||
frame:AddChild(button)
|
||
end
|
||
end
|
||
|
||
-- Make sidebar for snippets
|
||
local snippetsFrame = CreateFrame("Frame", "WeakAurasSnippets", group.frame, "WA_PortraitFrameTemplate")
|
||
snippetsFrame:HidePortrait()
|
||
snippetsFrame:SetPoint("TOPLEFT", group.frame, "TOPRIGHT", 20, 0)
|
||
snippetsFrame:SetPoint("BOTTOMLEFT", group.frame, "BOTTOMRIGHT", 20, 0)
|
||
snippetsFrame:SetWidth(250)
|
||
--[[
|
||
snippetsFrame:SetBackdrop(
|
||
{
|
||
bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background",
|
||
edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border",
|
||
tile = true,
|
||
tileSize = 32,
|
||
edgeSize = 32,
|
||
insets = {left = 8, right = 8, top = 8, bottom = 8}
|
||
}
|
||
)
|
||
snippetsFrame:SetBackdropColor(0, 0, 0, 1)
|
||
]]
|
||
-- Add button to save new snippet
|
||
local AddSnippetButton = CreateFrame("Button", nil, snippetsFrame, "UIPanelButtonTemplate")
|
||
AddSnippetButton:SetPoint("TOPLEFT", snippetsFrame, "TOPLEFT", 13, -25)
|
||
AddSnippetButton:SetPoint("TOPRIGHT", snippetsFrame, "TOPRIGHT", -13, -25)
|
||
AddSnippetButton:SetHeight(20)
|
||
AddSnippetButton:SetText(L["Add Snippet"])
|
||
AddSnippetButton:RegisterForClicks("LeftButtonUp")
|
||
|
||
-- house the buttons in a scroll frame
|
||
-- All AceGUI from this point, so that buttons can be released and reused
|
||
local snippetsScrollContainer = AceGUI:Create("SimpleGroup")
|
||
snippetsScrollContainer:SetFullWidth(true)
|
||
snippetsScrollContainer:SetFullHeight(true)
|
||
snippetsScrollContainer:SetLayout("Fill")
|
||
snippetsScrollContainer.frame:SetParent(snippetsFrame)
|
||
snippetsScrollContainer.frame:SetPoint("TOPLEFT", snippetsFrame, "TOPLEFT", 17, -50)
|
||
snippetsScrollContainer.frame:SetPoint("BOTTOMRIGHT", snippetsFrame, "BOTTOMRIGHT", -10, 10)
|
||
local snippetsScroll = AceGUI:Create("ScrollFrame")
|
||
snippetsScroll:SetLayout("List")
|
||
snippetsScrollContainer:AddChild(snippetsScroll)
|
||
snippetsScroll:FixScroll(true)
|
||
snippetsScroll.scrollframe:SetScript(
|
||
"OnScrollRangeChanged",
|
||
function(frame)
|
||
frame.obj:DoLayout()
|
||
end
|
||
)
|
||
|
||
snippetsFrame:Hide()
|
||
|
||
-- Toggle the side bar on click
|
||
snippetsButton:SetScript(
|
||
"OnClick",
|
||
function(self, button, down)
|
||
if not snippetsFrame:IsShown() then
|
||
snippetsFrame:Show()
|
||
UpdateSnippets(snippetsScroll)
|
||
else
|
||
snippetsFrame:Hide()
|
||
end
|
||
end
|
||
)
|
||
|
||
AddSnippetButton:SetScript(
|
||
"OnClick",
|
||
function(self)
|
||
local snippet = editor.editBox:GetText()
|
||
if snippet and #snippet > 0 then
|
||
local baseName, name, index = "New Snippet", "New Snippet", 0
|
||
local snippetExists = function(name)
|
||
for _, snippet in ipairs(savedSnippets) do
|
||
if snippet.name == name then
|
||
return true
|
||
end
|
||
end
|
||
end
|
||
while snippetExists(name) do
|
||
index = index + 1
|
||
name = format("%s %d", baseName, index)
|
||
end
|
||
table.insert(savedSnippets, {name = name, snippet = snippet, new = true})
|
||
UpdateSnippets(snippetsScroll)
|
||
end
|
||
end
|
||
)
|
||
|
||
editor.editBox.timeMachine = {}
|
||
editor.editBox.timeMachinePos = 1
|
||
local TimeMachineMaximumRollback = 10
|
||
|
||
-- These events aren’t supported in the editbox, so we add undo/redo buttons below instead...
|
||
--[[editor.editBox:HookScript(
|
||
"OnKeyDown",
|
||
function(self, key)
|
||
-- CTRL + S saves and closes
|
||
if IsControlKeyDown() and key == "S" then
|
||
group:Close()
|
||
elseif key == "Z" and IsControlKeyDown() then
|
||
self:SetPropagateKeyboardInput(false)
|
||
if self.timeMachine[self.timeMachinePos + 1] then
|
||
self.timeMachinePos = self.timeMachinePos + 1
|
||
self.skipOnTextChanged = true
|
||
originalSetText(self, self.timeMachine[self.timeMachinePos][1])
|
||
self:SetCursorPosition(self.timeMachine[self.timeMachinePos][2])
|
||
end
|
||
elseif key == "Y" and IsControlKeyDown() then
|
||
self:SetPropagateKeyboardInput(false)
|
||
if self.timeMachine[self.timeMachinePos - 1] then
|
||
self.timeMachinePos = self.timeMachinePos - 1
|
||
self.skipOnTextChanged = true
|
||
originalSetText(self, self.timeMachine[self.timeMachinePos][1])
|
||
self:SetCursorPosition(self.timeMachine[self.timeMachinePos][2])
|
||
end
|
||
end
|
||
end
|
||
)]]
|
||
|
||
editor.editBox:HookScript(
|
||
"OnTextChanged",
|
||
function(self, userInput)
|
||
local str = editor.editBox:GetText()
|
||
if not str or str:trim() == "" or editor.combinedText == true then
|
||
self.group.editorError:SetText("")
|
||
else
|
||
local func, errorString
|
||
if (self.group.enclose) then
|
||
func, errorString = OptionsPrivate.Private.LoadFunction("return function() " .. str .. "\n end", self.group.data.id, true)
|
||
else
|
||
func, errorString = OptionsPrivate.Private.LoadFunction("return " .. str, self.group.data.id, true)
|
||
end
|
||
if not errorString and self.group.validator then
|
||
errorString = self.group.validator(func)
|
||
end
|
||
if errorString then
|
||
if self.url then
|
||
helpButton:Show()
|
||
end
|
||
self.group.editorError:Show()
|
||
self.group.editorError:SetText(errorString)
|
||
else
|
||
self.group.editorError:SetText("")
|
||
end
|
||
end
|
||
|
||
if not userInput then return end
|
||
if self.skipOnTextChanged then
|
||
self.skipOnTextChanged = false
|
||
return
|
||
end
|
||
local cursorPosition = self:GetCursorPosition()
|
||
local text = originalGetText(self)
|
||
if IndentationLib then
|
||
text, cursorPosition = IndentationLib.stripWowColorsWithPos(text, cursorPosition)
|
||
end
|
||
if self.timeMachine[1] and text == self.timeMachine[1][1] then
|
||
return
|
||
end
|
||
-- if cursor is not at position 1, remove elements before cursor
|
||
for i = 2, self.timeMachinePos do
|
||
table.remove(self.timeMachine, 1)
|
||
end
|
||
-- insert current text
|
||
table.insert(self.timeMachine, 1, {text, cursorPosition - 1})
|
||
-- timeMachine is limited to a number of TimeMachineMaximumRollback elements
|
||
for i = #self.timeMachine, TimeMachineMaximumRollback + 1, -1 do
|
||
table.remove(self.timeMachine, i)
|
||
end
|
||
self.timeMachinePos = 1
|
||
end
|
||
)
|
||
|
||
-- bracket matching
|
||
editor.editBox:HookScript(
|
||
"OnChar",
|
||
function(_, char)
|
||
if not IsControlKeyDown() and WeakAurasSaved.editor_bracket_matching then
|
||
if char == "(" then
|
||
editor.editBox:Insert(")")
|
||
editor.editBox:SetCursorPosition(editor.editBox:GetCursorPosition() - 1)
|
||
elseif char == "{" then
|
||
editor.editBox:Insert("}")
|
||
editor.editBox:SetCursorPosition(editor.editBox:GetCursorPosition() - 1)
|
||
elseif char == "[" then
|
||
editor.editBox:Insert("]")
|
||
editor.editBox:SetCursorPosition(editor.editBox:GetCursorPosition() - 1)
|
||
end
|
||
end
|
||
end
|
||
)
|
||
|
||
local editorError = group.frame:CreateFontString(nil, "OVERLAY")
|
||
editorError:SetFont(STANDARD_TEXT_FONT, 12)
|
||
editorError:SetJustifyH("LEFT")
|
||
editorError:SetJustifyV("TOP")
|
||
editorError:SetTextColor(1, 0, 0)
|
||
editorError:SetPoint("LEFT", helpButton, "RIGHT", 0, 4)
|
||
editorError:SetPoint("RIGHT", settings_frame, "LEFT")
|
||
group.editorError = editorError
|
||
|
||
local editorLine = CreateFrame("EditBox", nil, group.frame, "WA_InputBoxTemplate")
|
||
-- Set script on enter pressed..
|
||
editorLine:SetPoint("RIGHT", snippetsButton, "LEFT", -10, 0)
|
||
editorLine:SetFont(STANDARD_TEXT_FONT, 10)
|
||
editorLine:SetJustifyH("RIGHT")
|
||
editorLine:SetWidth(30)
|
||
editorLine:SetHeight(20)
|
||
editorLine:SetNumeric(true)
|
||
editorLine:SetTextInsets(0, 5, 0, 0)
|
||
editorLine:SetAutoFocus(false)
|
||
|
||
local editorLineText = group.frame:CreateFontString(nil, "OVERLAY")
|
||
editorLineText:SetFont(STANDARD_TEXT_FONT, 10)
|
||
editorLineText:SetTextColor(1, 1, 1)
|
||
editorLineText:SetText(L["Line"])
|
||
editorLineText:SetPoint("RIGHT", editorLine, "LEFT", -8, 0)
|
||
|
||
local redoButton = CreateFrame("Button", nil, editorLine)
|
||
redoButton:SetPoint("RIGHT", editorLineText, "LEFT", -10, 0)
|
||
redoButton:SetSize(20, 20)
|
||
redoButton:SetNormalTexture("Interface\\AddOns\\WeakAuras\\Media\\Textures\\undo")
|
||
local redoNormal = redoButton:GetNormalTexture()
|
||
redoNormal:SetAllPoints()
|
||
redoNormal:SetTexCoord(1, 0, 0, 1)
|
||
redoNormal:SetBlendMode("BLEND")
|
||
redoButton:SetHighlightTexture("Interface\\AddOns\\WeakAuras\\Media\\Textures\\undo-highlight")
|
||
local redoHighlight = redoButton:GetHighlightTexture()
|
||
redoHighlight:SetAllPoints()
|
||
redoHighlight:SetTexCoord(1, 0, 0, 1)
|
||
redoHighlight:SetBlendMode("BLEND")
|
||
|
||
local undoButton = CreateFrame("Button", nil, redoButton)
|
||
undoButton:SetPoint("RIGHT", redoButton, "LEFT", -10, 0)
|
||
undoButton:SetSize(20, 20)
|
||
undoButton:SetNormalTexture("Interface\\AddOns\\WeakAuras\\Media\\Textures\\undo")
|
||
local undoNormal = undoButton:GetNormalTexture()
|
||
undoNormal:SetAllPoints()
|
||
undoNormal:SetTexCoord(0, 1, 0, 1)
|
||
undoNormal:SetBlendMode("BLEND")
|
||
undoButton:SetHighlightTexture("Interface\\AddOns\\WeakAuras\\Media\\Textures\\undo-highlight")
|
||
local undoHighlight = undoButton:GetHighlightTexture()
|
||
undoHighlight:SetAllPoints()
|
||
undoHighlight:SetTexCoord(0, 1, 0, 1)
|
||
undoHighlight:SetBlendMode("BLEND")
|
||
|
||
redoButton:SetScript("OnClick", function()
|
||
local self = editor.editBox
|
||
if self.timeMachine[self.timeMachinePos - 1] then
|
||
self.timeMachinePos = self.timeMachinePos - 1
|
||
self.skipOnTextChanged = true
|
||
originalSetText(self, self.timeMachine[self.timeMachinePos][1])
|
||
self:SetCursorPosition(self.timeMachine[self.timeMachinePos][2])
|
||
end
|
||
end)
|
||
|
||
undoButton:SetScript("OnClick", function()
|
||
local self = editor.editBox
|
||
if self.timeMachine[self.timeMachinePos + 1] then
|
||
self.timeMachinePos = self.timeMachinePos + 1
|
||
self.skipOnTextChanged = true
|
||
originalSetText(self, self.timeMachine[self.timeMachinePos][1])
|
||
self:SetCursorPosition(self.timeMachine[self.timeMachinePos][2])
|
||
end
|
||
end)
|
||
|
||
helpButton:SetScript("OnClick", function()
|
||
OptionsPrivate.ToggleTip(helpButton, group.url, L["Help"], "")
|
||
end)
|
||
|
||
local oldOnCursorChanged = editor.editBox:GetScript("OnCursorChanged")
|
||
editor.editBox:SetScript(
|
||
"OnCursorChanged",
|
||
function(...)
|
||
oldOnCursorChanged(...)
|
||
local cursorPosition = editor.editBox:GetCursorPosition()
|
||
local next = -1
|
||
local line = 0
|
||
while (next and cursorPosition >= next) do
|
||
next = originalGetText(editor.editBox):find("[\n]", next + 1)
|
||
line = line + 1
|
||
end
|
||
editorLine:SetNumber(line)
|
||
end
|
||
)
|
||
|
||
editorLine:SetScript(
|
||
"OnEnterPressed",
|
||
function()
|
||
local newLine = editorLine:GetNumber()
|
||
local newPosition = 0
|
||
while (newLine > 1 and newPosition) do
|
||
newPosition = originalGetText(editor.editBox):find("[\n]", newPosition + 1)
|
||
newLine = newLine - 1
|
||
end
|
||
|
||
if (newPosition) then
|
||
editor.editBox:SetCursorPosition(newPosition)
|
||
editor.editBox:SetFocus()
|
||
end
|
||
end
|
||
)
|
||
|
||
function group.Open(self, data, path, enclose, multipath, reloadOptions, setOnParent, url, validator)
|
||
self.data = data
|
||
self.path = path
|
||
self.multipath = multipath
|
||
self.reloadOptions = reloadOptions
|
||
self.setOnParent = setOnParent
|
||
self.url = url
|
||
self.enclose = enclose
|
||
self.validator = validator
|
||
if url then
|
||
helpButton:Show()
|
||
else
|
||
helpButton:Hide()
|
||
end
|
||
if (frame.window == "texture") then
|
||
local texturepicker = OptionsPrivate.TexturePicker(frame, true)
|
||
if texturepicker then
|
||
texturepicker:CancelClose()
|
||
end
|
||
elseif (frame.window == "icon") then
|
||
local iconpicker = OptionsPrivate.IconPicker(frame, true)
|
||
if iconpicker then
|
||
iconpicker:CancelClose()
|
||
end
|
||
end
|
||
frame.window = "texteditor"
|
||
frame:UpdateFrameVisible()
|
||
local title = (type(data.id) == "string" and data.id or L["Temporary Group"]) .. " -"
|
||
if (not multipath) then
|
||
for index, field in pairs(path) do
|
||
if (type(field) == "number") then
|
||
field = "Trigger " .. field
|
||
end
|
||
title = title .. " " .. field:sub(1, 1):upper() .. field:sub(2)
|
||
end
|
||
end
|
||
editor:SetLabel(title)
|
||
editor.editBox.timeMachine = {}
|
||
editor.editBox.timeMachinePos = 1
|
||
editor.editBox:SetScript(
|
||
"OnEscapePressed",
|
||
function()
|
||
-- catch it so that escape doesn't default to losing focus (after which another escape would close config)
|
||
end
|
||
)
|
||
|
||
if setOnParent then
|
||
editor:SetText(OptionsPrivate.Private.ValueFromPath(data, path) or "")
|
||
else
|
||
local singleText
|
||
local sameTexts = true
|
||
local combinedText = ""
|
||
for child in OptionsPrivate.Private.TraverseLeafsOrAura(data) do
|
||
local text
|
||
if multipath then
|
||
text = path[child.id] and OptionsPrivate.Private.ValueFromPath(child, path[child.id])
|
||
else
|
||
text = OptionsPrivate.Private.ValueFromPath(child, path)
|
||
end
|
||
if text then
|
||
if not (singleText) then
|
||
singleText = text
|
||
else
|
||
if singleText ~= text then
|
||
sameTexts = false
|
||
end
|
||
end
|
||
if combinedText ~= "" then
|
||
combinedText = combinedText .. "\n\n"
|
||
end
|
||
|
||
combinedText =
|
||
combinedText .. L["-- Do not remove this comment, it is part of this aura: "] .. child.id .. "\n"
|
||
combinedText = combinedText .. (text or "")
|
||
end
|
||
end
|
||
if (sameTexts) then
|
||
editor:SetText(singleText or "")
|
||
editor.combinedText = false
|
||
else
|
||
editor:SetText(combinedText)
|
||
editor.combinedText = true
|
||
end
|
||
end
|
||
editor:SetFocus()
|
||
end
|
||
|
||
function group.CancelClose(self)
|
||
editor:ClearFocus()
|
||
frame:HideTip()
|
||
frame.window = "default"
|
||
frame:UpdateFrameVisible()
|
||
end
|
||
|
||
local function extractTexts(input)
|
||
local texts = {}
|
||
|
||
local currentPos, id, startIdLine, startId, endId, endIdLine
|
||
while (true) do
|
||
startIdLine, startId =
|
||
string.find(input, L["-- Do not remove this comment, it is part of this aura: "], currentPos, true)
|
||
if (not startId) then
|
||
break
|
||
end
|
||
|
||
endId, endIdLine = string.find(input, "\n", startId, true)
|
||
if (not endId) then
|
||
break
|
||
end
|
||
|
||
if (currentPos) then
|
||
local trimmedPosition = startIdLine - 1
|
||
while (string.sub(input, trimmedPosition, trimmedPosition) == "\n") do
|
||
trimmedPosition = trimmedPosition - 1
|
||
end
|
||
|
||
texts[id] = string.sub(input, currentPos, trimmedPosition)
|
||
end
|
||
|
||
id = string.sub(input, startId + 1, endId - 1)
|
||
|
||
currentPos = endIdLine + 1
|
||
end
|
||
|
||
if (id) then
|
||
texts[id] = string.sub(input, currentPos, string.len(input))
|
||
end
|
||
|
||
return texts
|
||
end
|
||
|
||
function group.Close(self)
|
||
if self.setOnParent then
|
||
OptionsPrivate.Private.ValueToPath(self.data, self.path, editor:GetText())
|
||
WeakAuras.Add(self.data)
|
||
else
|
||
local textById = editor.combinedText and extractTexts(editor:GetText())
|
||
for child in OptionsPrivate.Private.TraverseLeafsOrAura(self.data) do
|
||
local text = editor.combinedText and (textById[child.id] or "") or editor:GetText()
|
||
OptionsPrivate.Private.ValueToPath(child, self.multipath and self.path[child.id] or self.path, text)
|
||
WeakAuras.Add(child)
|
||
OptionsPrivate.ClearOptions(child.id)
|
||
end
|
||
end
|
||
|
||
WeakAuras.ClearAndUpdateOptions(self.data.id)
|
||
|
||
editor:ClearFocus()
|
||
|
||
frame.window = "default"
|
||
frame:UpdateFrameVisible()
|
||
WeakAuras.FillOptions()
|
||
end
|
||
|
||
return group
|
||
end
|
||
|
||
function OptionsPrivate.TextEditor(frame, noConstruct)
|
||
textEditor = textEditor or (not noConstruct and ConstructTextEditor(frame))
|
||
return textEditor
|
||
end
|