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.
1837 lines
72 KiB
1837 lines
72 KiB
local COMPAT, api, _, T = select(4,GetBuildInfo()), {}, ...
|
|
local PC, RK, ORI, config = T.OPieCore, T.RingKeeper, OPie.UI, T.config
|
|
local L, MODERN = T.L, COMPAT >= 8e4
|
|
local AB = assert(T.ActionBook:compatible(2,23), "A compatible version of ActionBook is required")
|
|
local EV, TS, XU = T.Evie, T.TenSettings, T.exUI
|
|
local GameTooltip = T.NotGameTooltip or GameTooltip
|
|
|
|
local FULLNAME, SHORTNAME do
|
|
function EV.PLAYER_LOGIN()
|
|
local name, realm = UnitFullName("player")
|
|
FULLNAME, SHORTNAME = name .. "-" .. realm, name
|
|
end
|
|
end
|
|
|
|
local function prepEditBoxCancel(self)
|
|
self.oldValue = self:GetText()
|
|
if self.placeholder then self.placeholder:Hide() end
|
|
end
|
|
local function cancelEditBoxInput(self)
|
|
local h = self:GetScript("OnEditFocusLost")
|
|
self:SetText(self.oldValue or self:GetText())
|
|
self:SetScript("OnEditFocusLost", nil)
|
|
self:ClearFocus()
|
|
self:SetScript("OnEditFocusLost", h)
|
|
if self.placeholder and self:GetText() == "" then self.placeholder:Show() end
|
|
end
|
|
local function prepEditBox(self, save)
|
|
if self:IsMultiLine() then
|
|
self:SetScript("OnEscapePressed", self.ClearFocus)
|
|
else
|
|
self:SetScript("OnEditFocusGained", prepEditBoxCancel)
|
|
self:SetScript("OnEscapePressed", cancelEditBoxInput)
|
|
self:SetScript("OnEnterPressed", self.ClearFocus)
|
|
end
|
|
self:SetScript("OnEditFocusLost", save)
|
|
end
|
|
local function addIconSlotTextures(tex, sz)
|
|
local p = tex:GetParent()
|
|
local bg = p:CreateTexture(nil, "BACKGROUND", nil, -1)
|
|
bg:SetTexture("Interface/Buttons/UI-EmptySlot-Disabled")
|
|
bg:SetPoint("CENTER", tex, "CENTER")
|
|
bg:SetSize(1.5*sz, 1.5*sz)
|
|
local edge = p:CreateTexture(nil, "OVERLAY", nil, -1)
|
|
edge:SetTexture("Interface/Buttons/UI-Quickslot2")
|
|
edge:SetSize(1.625*sz, 1.625*sz)
|
|
edge:SetPoint("CENTER", tex, "CENTER", 0.25, -0.25)
|
|
if MODERN then
|
|
local m = p:CreateMaskTexture()
|
|
m:SetTexture("Interface/FrameGeneral/UIFrameIconMask")
|
|
m:SetAllPoints(tex)
|
|
tex:AddMaskTexture(m)
|
|
end
|
|
return bg, edge
|
|
end
|
|
local function createIconButton(name, parent, id, skipSlotDecorations)
|
|
local f = CreateFrame("CheckButton", name, parent, nil, id or 0)
|
|
f:SetSize(32,32)
|
|
f:SetNormalTexture("")
|
|
f:SetHighlightTexture("Interface/Buttons/ButtonHilight-Square")
|
|
f:GetHighlightTexture():SetBlendMode("ADD")
|
|
f:SetCheckedTexture("Interface/Buttons/CheckButtonHilight")
|
|
f:GetCheckedTexture():SetBlendMode("ADD")
|
|
f:SetPushedTexture("Interface/Buttons/UI-Quickslot-Depress")
|
|
f.tex = f:CreateTexture(nil, "ARTWORK")
|
|
f.tex:SetAllPoints()
|
|
if skipSlotDecorations ~= true then
|
|
f.background, f.edge = addIconSlotTextures(f.tex, 32)
|
|
end
|
|
return f
|
|
end
|
|
local function PlayCheckboxSound(self)
|
|
PlaySound(SOUNDKIT[self:GetChecked() and "IG_MAINMENU_OPTION_CHECKBOX_ON" or "IG_MAINMENU_OPTION_CHECKBOX_OFF"])
|
|
end
|
|
local function SetCursor(tex)
|
|
tex = type(tex) == "string" and GetFileIDFromPath(tex) or tex
|
|
_G.SetCursor(type(tex) == "number" and tex > 0 and tex or tex and 132761)
|
|
end
|
|
local CallSetRing
|
|
local function SaveRingVersion(name, liveData)
|
|
local key = "RKRing#" .. name
|
|
if not config.undo:search(key) then
|
|
if liveData == true then
|
|
liveData = RK:GetRingDescription(name) or false
|
|
end
|
|
config.undo:push(key, CallSetRing, name, liveData)
|
|
end
|
|
end
|
|
function CallSetRing(msg, ...)
|
|
if msg == "archive-unwind" then
|
|
SaveRingVersion((...), true)
|
|
end
|
|
RK:SetRing(...)
|
|
end
|
|
local function CreateToggleButton(parent)
|
|
local button = CreateFrame("CheckButton", nil, parent)
|
|
button:SetSize(175, 30)
|
|
button:SetNormalFontObject(GameFontHighlightMedium)
|
|
button:SetPushedTextOffset(-1, -1)
|
|
button:SetNormalTexture("Interface\\PVPFrame\\PvPMegaQueue")
|
|
button:GetNormalTexture():SetTexCoord(0.00195313,0.58789063, 0.87304688,0.92773438)
|
|
button:SetPushedTexture("Interface\\PVPFrame\\PvPMegaQueue")
|
|
button:GetPushedTexture():SetTexCoord(0.00195313,0.58789063,0.92968750,0.98437500)
|
|
button:SetHighlightTexture("Interface\\PVPFrame\\PvPMegaQueue")
|
|
button:GetHighlightTexture():SetTexCoord(0.00195313,0.63867188, 0.70703125,0.76757813)
|
|
button:SetCheckedTexture("Interface\\PVPFrame\\PvPMegaQueue")
|
|
button:GetCheckedTexture():SetTexCoord(0.00195313,0.63867188, 0.76953125,0.83007813)
|
|
for i=1,2 do
|
|
local tex = i == 1 and button:GetHighlightTexture() or button:GetCheckedTexture()
|
|
tex:ClearAllPoints()
|
|
tex:SetPoint("TOPLEFT", button, "LEFT", 1.5, 12.3)
|
|
tex:SetPoint("BOTTOMRIGHT", button, "RIGHT", -1.5, -12.3)
|
|
tex:SetBlendMode("ADD")
|
|
end
|
|
return button
|
|
end
|
|
local function CreateButton(parent, width)
|
|
local btn = CreateFrame("Button", nil, parent, "UIPanelButtonTemplate")
|
|
btn:SetWidth(width or 150)
|
|
return btn
|
|
end
|
|
local function setIcon(self, path, ext)
|
|
local plainTexturePath, atlasName
|
|
if type(path) == "string" and GetFileIDFromPath(path) == nil and C_Texture.GetAtlasInfo(path) then
|
|
atlasName = path
|
|
self:SetAtlas(path)
|
|
else
|
|
plainTexturePath = path
|
|
self:SetTexture(path or "Interface/Icons/Inv_Misc_QuestionMark")
|
|
self:SetTexCoord(0,1,0,1)
|
|
end
|
|
if ext then
|
|
if type(ext.iconR) == "number" and type(ext.iconG) == "number" and type(ext.iconB) == "number" then
|
|
self:SetVertexColor(ext.iconR, ext.iconG, ext.iconB)
|
|
end
|
|
if type(ext.iconCoords) == "table" then
|
|
securecall(self.SetTexCoord, self, unpack(ext.iconCoords))
|
|
plainTexturePath = nil
|
|
elseif type(ext.iconCoords) == "function" or type(ext.iconCoords) == "userdata" then
|
|
securecall(self.SetTexCoord, self, securecall(ext.iconCoords))
|
|
plainTexturePath = nil
|
|
end
|
|
end
|
|
return plainTexturePath, atlasName
|
|
end
|
|
|
|
local ringContainer, ringDetail, sliceDetail, newSlice, newRing, editorHost
|
|
local panel = TS:CreateOptionsPanel(L"Custom Rings", "OPie")
|
|
panel.desc:SetText(L"Customize OPie by modifying existing rings, or creating your own.")
|
|
local ringDropDown = CreateFrame("Frame", "RKC_RingSelectionDropDown", panel, "UIDropDownMenuTemplate")
|
|
ringDropDown:SetPoint("TOP", -70, -60)
|
|
UIDropDownMenu_SetWidth(ringDropDown, 260)
|
|
local btnNewRing = CreateButton(panel)
|
|
btnNewRing:SetPoint("LEFT", ringDropDown, "RIGHT", -5, 3)
|
|
btnNewRing:SetText(L"New Ring...")
|
|
local dragBackdrop = CreateFrame("Frame") do
|
|
dragBackdrop:Hide()
|
|
dragBackdrop:SetFrameStrata("BACKGROUND")
|
|
dragBackdrop:SetAllPoints()
|
|
dragBackdrop:EnableMouse(true)
|
|
dragBackdrop:SetScript("OnMouseDown", dragBackdrop.Hide)
|
|
end
|
|
|
|
newRing = CreateFrame("Frame") do
|
|
newRing:SetSize(400, 115)
|
|
newRing:Hide()
|
|
local title = newRing:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
|
|
local toggle1, toggle2 = CreateToggleButton(newRing), CreateToggleButton(newRing)
|
|
local name, snap = XU:Create("LineInput", nil, newRing), XU:Create("LineInput", nil, newRing)
|
|
local nameLabel, snapLabel = newRing:CreateFontString(nil, "OVERLAY", "GameFontHighlight"), snap:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
|
|
local accept, cancel = CreateButton(newRing, 125), CreateButton(newRing, 125)
|
|
local importNested = TS:CreateOptionsCheckButton(nil, newRing)
|
|
local state = {selected=toggle1, buncount=0}
|
|
title:SetPoint("TOP", 0, -3)
|
|
toggle1:SetPoint("TOPLEFT", 20, -25)
|
|
toggle2:SetPoint("TOPRIGHT", -20, -25)
|
|
name:SetPoint("TOPRIGHT", -15, -62)
|
|
name:SetWidth(240)
|
|
nameLabel:SetPoint("TOPLEFT", newRing, "TOPLEFT", 15, -67)
|
|
snap:SetPoint("TOPRIGHT", -15, -85)
|
|
snap:SetWidth(240)
|
|
snapLabel:SetPoint("TOPLEFT", newRing, "TOPLEFT", 15, -90)
|
|
accept:SetPoint("BOTTOMRIGHT", newRing, "BOTTOM", -2, 4)
|
|
cancel:SetPoint("BOTTOMLEFT", newRing, "BOTTOM", 2, 4)
|
|
toggle1:SetChecked(1)
|
|
importNested:SetScript("OnClick", PlayCheckboxSound)
|
|
importNested:SetPoint("TOPLEFT", snap, "BOTTOMLEFT", -9, -2)
|
|
importNested:SetHitRectInsets(0, -222, 0, 0)
|
|
importNested:SetScript("OnHide", function(self) self:SetChecked(nil) end)
|
|
|
|
snap:Hide()
|
|
local function updateSnap(snapText, speculativeNameCheck)
|
|
if state.snap == snapText and not speculativeNameCheck then
|
|
return
|
|
end
|
|
local bc, ring, bun = 0, RK:GetSnapshotRing(snapText)
|
|
if speculativeNameCheck == true and not ring then
|
|
return
|
|
end
|
|
if type(bun) == "table" then
|
|
for _,v in pairs(bun) do
|
|
if type(v) == "table" then
|
|
bc = bc + 1
|
|
end
|
|
end
|
|
end
|
|
state.snap, state.ring, state.bundle, state.buncount = snapText, ring, bun, bc
|
|
if speculativeNameCheck == true then
|
|
name:SetText("")
|
|
snap:SetText(snapText)
|
|
toggle2:Click()
|
|
end
|
|
if state.ring and name:GetText() == "" then
|
|
snap:SetCursorPosition(0)
|
|
name:SetText(state.ring.name or "")
|
|
name:SetFocus()
|
|
name:HighlightText()
|
|
end
|
|
snap:SetTextColor((ring and GameFontGreen or ChatFontNormal):GetTextColor())
|
|
importNested.Text:SetText((L"Import %s |4nested ring:nested rings;"):format(NORMAL_FONT_COLOR_CODE .. "|t" .. bc .. "|r"))
|
|
return not not ring
|
|
end
|
|
local function validate()
|
|
local nameText = name:GetText() or ""
|
|
if toggle2:GetChecked() then
|
|
updateSnap(snap:GetText() or "")
|
|
elseif #nameText > 32 and nameText:match("^%s*oetohH7") then
|
|
updateSnap(nameText, true)
|
|
end
|
|
local isSnapImport = toggle2:GetChecked()
|
|
local snapOK = state.ring and true or not isSnapImport
|
|
local hasBundledRings = isSnapImport and state.ring and state.buncount ~= 0
|
|
newRing:SetSize(400, hasBundledRings and 162 or isSnapImport and 140 or 115)
|
|
snap:SetShown(isSnapImport)
|
|
importNested:SetShown(hasBundledRings)
|
|
accept:SetEnabled(type(nameText) == "string" and nameText:match("%S") and snapOK)
|
|
if newRing:IsVisible() then
|
|
TS:ShowFrameOverlay(panel, newRing)
|
|
end
|
|
end
|
|
local function toggle(self)
|
|
if self:GetChecked() then
|
|
state.selected:SetChecked(nil)
|
|
state.selected = self
|
|
if self == toggle1 then
|
|
snap:SetText("")
|
|
end
|
|
if newRing:IsVisible() then
|
|
PlaySound(SOUNDKIT.U_CHAT_SCROLL_BUTTON)
|
|
validate();
|
|
(self == toggle1 and name or snap):SetFocus()
|
|
end
|
|
else
|
|
self:SetChecked(1)
|
|
end
|
|
end
|
|
local function navigate(self)
|
|
if IsControlKeyDown() then
|
|
(toggle1:GetChecked() and toggle2 or toggle1):Click()
|
|
elseif self ~= snap and snap:IsShown() then
|
|
snap:SetFocus()
|
|
else
|
|
name:SetFocus()
|
|
end
|
|
end
|
|
local function submit(self)
|
|
if accept:IsEnabled() then
|
|
accept:Click()
|
|
else
|
|
navigate(self)
|
|
end
|
|
end
|
|
cancel:SetScript("OnClick", function() newRing:Hide() end)
|
|
accept:SetScript("OnClick", function()
|
|
if state.selected == toggle1 then
|
|
api.createRing(name:GetText(), {limit="PLAYER"})
|
|
newRing:Hide()
|
|
elseif api.createRing(name:GetText(), state.ring, state.bundle, importNested:GetChecked()) then
|
|
newRing:Hide()
|
|
end
|
|
end)
|
|
toggle1:SetScript("OnClick", toggle)
|
|
toggle2:SetScript("OnClick", toggle)
|
|
for i=1,2 do
|
|
local v = i == 1 and name or snap
|
|
v:SetScript("OnTabPressed", navigate)
|
|
v:SetScript("OnEnterPressed", submit)
|
|
v:SetScript("OnTextChanged", validate)
|
|
v:SetScript("OnEditFocusLost", EditBox_ClearHighlight)
|
|
end
|
|
btnNewRing:SetScript("OnClick", function()
|
|
title:SetText(L"Create a New Ring")
|
|
toggle1:SetText(L"Empty ring")
|
|
toggle2:SetText(L"Import snapshot")
|
|
local w1, w2 = 32+toggle1:GetFontString():GetStringWidth(), 32+toggle2:GetFontString():GetStringWidth()
|
|
toggle1:SetWidth(math.max(w1, 350 - math.max(175, w2)))
|
|
toggle2:SetWidth(math.max(w2, 350 - math.max(175, w1)))
|
|
nameLabel:SetText(L"Ring name:")
|
|
snapLabel:SetText(L"Snapshot:")
|
|
accept:SetText(L"Add Ring")
|
|
cancel:SetText(L"Cancel")
|
|
snap:SetText("")
|
|
snap.cachedText, snap.cachedValue = nil
|
|
name:SetText("")
|
|
toggle1:Click()
|
|
accept:Disable()
|
|
importNested:SetChecked(false)
|
|
TS:ShowFrameOverlay(panel, newRing)
|
|
name:SetFocus()
|
|
end)
|
|
end
|
|
|
|
ringContainer = CreateFrame("Frame", nil, panel) do
|
|
ringContainer:SetPoint("TOP", ringDropDown, "BOTTOM", 75, 0)
|
|
ringContainer:SetPoint("BOTTOM", panel, 0, 6)
|
|
ringContainer:SetPoint("LEFT", panel, 50, 0)
|
|
ringContainer:SetPoint("RIGHT", panel, -10, 0)
|
|
XU:Create("Backdrop", ringContainer, {edgeFile="Interface/Tooltips/UI-Tooltip-Border", tile=true, edgeSize=14, edgeColor=0x7f7f7f})
|
|
local function UpdateOnShow(self) self:SetScript("OnUpdate", nil) api.refreshDisplay() end
|
|
ringContainer:SetScript("OnHide", function(self) if self:IsShown() then self:SetScript("OnUpdate", UpdateOnShow) end end)
|
|
do -- up/down arrow buttons: ringContainer.prev and ringContainer.next
|
|
local prev, next = CreateFrame("Button", nil, ringContainer), CreateFrame("Button", nil, ringContainer)
|
|
prev:SetSize(22, 22) next:SetSize(22, 22)
|
|
next:SetPoint("TOPRIGHT", ringContainer, "TOPLEFT", 2, 0)
|
|
prev:SetPoint("RIGHT", next, "LEFT", 4, 0)
|
|
prev:SetNormalTexture("Interface/ChatFrame/UI-ChatIcon-ScrollUp-Up")
|
|
prev:SetPushedTexture("Interface/ChatFrame/UI-ChatIcon-ScrollUp-Down")
|
|
prev:SetDisabledTexture("Interface/ChatFrame/UI-ChatIcon-ScrollUp-Disabled")
|
|
prev:SetHighlightTexture("Interface/Buttons/UI-Common-MouseHilight")
|
|
next:SetNormalTexture("Interface/ChatFrame/UI-ChatIcon-ScrollDown-Up")
|
|
next:SetPushedTexture("Interface/ChatFrame/UI-ChatIcon-ScrollDown-Down")
|
|
next:SetDisabledTexture("Interface/ChatFrame/UI-ChatIcon-ScrollDown-Disabled")
|
|
next:SetHighlightTexture("Interface/Buttons/UI-Common-MouseHilight")
|
|
next:SetID(1) prev:SetID(-1)
|
|
local function handler(self) api.scrollSliceList(self:GetID()) end
|
|
next:SetScript("OnClick", handler) prev:SetScript("OnClick", handler)
|
|
ringContainer.prev, ringContainer.next = prev, next
|
|
local cap = CreateFrame("Frame", nil, ringContainer)
|
|
cap:SetPoint("TOPLEFT", ringContainer, "TOPLEFT", -38, 0)
|
|
cap:SetPoint("BOTTOMRIGHT", ringContainer, "BOTTOMLEFT", -1, 0)
|
|
cap:SetScript("OnMouseWheel", function(_, delta)
|
|
local b = delta == 1 and prev or next
|
|
if b:IsEnabled() then b:Click() end
|
|
end)
|
|
end
|
|
ringContainer.slices = {} do
|
|
local function onClick(self)
|
|
PlaySound(SOUNDKIT.U_CHAT_SCROLL_BUTTON)
|
|
api.selectSlice(self:GetID(), self:GetChecked())
|
|
end
|
|
local function dragStart(self)
|
|
if ringContainer.disableSliceDrag then return end
|
|
PlaySound(832)
|
|
self.source = api.resolveSliceOffset(self:GetID())
|
|
dragBackdrop:Show()
|
|
SetCursor(self.plainTex or "Interface/Icons/Temp")
|
|
end
|
|
local function dragAbort(self)
|
|
local src = self.source
|
|
if src then
|
|
SetCursor(nil)
|
|
dragBackdrop:Hide()
|
|
self.source = nil
|
|
end
|
|
return src
|
|
end
|
|
local function dragStop(self)
|
|
local source = dragAbort(self)
|
|
if ringContainer.disableSliceDrag then return end
|
|
local x, y = GetCursorPosition()
|
|
PlaySound(833)
|
|
local scale, l, b, w, h = self:GetEffectiveScale(), self:GetRect()
|
|
local dy, dx = math.floor(-(y / scale - b - h-1)/(h+2)), x / scale - l
|
|
if dx < -2*w or dx > 2*w then return api.deleteSlice(source) end
|
|
if dx < -w/2 or dx > 3*w/2 then return end
|
|
local dest = self:GetID() + dy
|
|
if not ringContainer.slices[dest+1] or not ringContainer.slices[dest+1]:IsShown() then return end
|
|
dest = api.resolveSliceOffset(dest)
|
|
if dest ~= source then api.moveSlice(source, dest) end
|
|
end
|
|
for i=0,11 do
|
|
local ico = createIconButton(nil, ringContainer, i)
|
|
ico:SetPoint("TOP", ringContainer.prev, "BOTTOMRIGHT", -2, -34*i)
|
|
ico:SetScript("OnClick", onClick)
|
|
ico:RegisterForDrag("LeftButton")
|
|
ico:SetScript("OnDragStart", dragStart)
|
|
ico:SetScript("OnDragStop", dragStop)
|
|
ico:SetScript("OnHide", dragAbort)
|
|
ico.check = ico:CreateTexture(nil, "OVERLAY")
|
|
ico.check:SetSize(8,8) ico.check:SetPoint("BOTTOMRIGHT", -1, 1)
|
|
ico.check:SetTexture("Interface/FriendsFrame/StatusIcon-Online")
|
|
ico.auto = ico:CreateTexture(nil, "OVERLAY", nil, 4)
|
|
ico.auto:SetAllPoints()
|
|
ico.auto:SetTexture("Interface/Buttons/UI-AutoCastableOverlay")
|
|
ico.auto:SetTexCoord(14/64, 49/64, 14/64, 49/64)
|
|
ringContainer.slices[i+1] = ico
|
|
end
|
|
end
|
|
ringContainer.newSlice = createIconButton(nil, ringContainer, nil, true) do
|
|
local b = ringContainer.newSlice
|
|
b:SetSize(24,24)
|
|
b.tex:SetTexture("Interface/GuildBankFrame/UI-GuildBankFrame-NewTab")
|
|
b:SetScript("OnClick", function(self)
|
|
PlaySound(SOUNDKIT.U_CHAT_SCROLL_BUTTON)
|
|
config.ui.HideTooltip(self)
|
|
if IsAltKeyDown() then
|
|
self:SetChecked(not self:GetChecked())
|
|
TS:ShowPromptOverlay(panel, L"Custom slice", L"Input a slice action specification:", (L"Example: %s."):format(GREEN_FONT_COLOR_CODE .. '"item", 19019|r'), nil, api.addCustomSlice, 0.95)
|
|
return
|
|
end
|
|
if newSlice:IsShown() then
|
|
return api.closeActionPicker("add-new-slice-button")
|
|
end
|
|
if sliceDetail:IsShown() then
|
|
api.selectSlice()
|
|
for i=1,#ringContainer.slices do
|
|
ringContainer.slices[i]:SetChecked(nil)
|
|
end
|
|
end
|
|
ringDetail:Hide()
|
|
api.endSliceRepick()
|
|
newSlice:Show()
|
|
end)
|
|
b:SetScript("OnEnter", function(self)
|
|
GameTooltip:SetOwner(self, "ANCHOR_NONE")
|
|
GameTooltip:SetPoint("LEFT", self, "RIGHT", 2, 0)
|
|
GameTooltip:AddLine(L"Add a new slice", 1, 1, 1)
|
|
GameTooltip:Show()
|
|
end)
|
|
b:SetScript("OnLeave", config.ui.HideTooltip)
|
|
b:SetPoint("TOP", ringContainer.slices[12], "BOTTOM", 0, -2)
|
|
end
|
|
end
|
|
ringDetail = CreateFrame("Frame", nil, ringContainer) do
|
|
ringDetail:SetAllPoints()
|
|
TS:EscapeCallback(ringDetail, function() api.deselectRing() end)
|
|
ringDetail.name = CreateFrame("EditBox", nil, ringDetail) do
|
|
local e = ringDetail.name
|
|
e:SetHeight(24)
|
|
e:SetPoint("TOPLEFT", 5, -5)
|
|
e:SetPoint("TOPRIGHT", -5, -5)
|
|
e:SetTextInsets(2,2,2,2)
|
|
e:SetFontObject(GameFontNormalLarge)
|
|
e:SetAutoFocus(false)
|
|
prepEditBox(e, function(self) api.setRingProperty("name", self:GetText()) end)
|
|
local ht = e:CreateTexture(nil, "BACKGROUND", nil, -3)
|
|
ht:SetColorTexture(1,1,1,0.08)
|
|
ht:SetAllPoints()
|
|
ht:Hide()
|
|
local function hideHilight() ht:Hide() end
|
|
e:SetScript("OnEnter", function(self) if not self:HasFocus() then ht:Show() end end)
|
|
e:SetScript("OnLeave", hideHilight)
|
|
e:HookScript("OnEditFocusGained", hideHilight)
|
|
end
|
|
local tex = ringDetail.name:CreateTexture()
|
|
tex:SetHeight(1) tex:SetPoint("BOTTOMLEFT", 0, -2) tex:SetPoint("BOTTOMRIGHT", 0, -2)
|
|
tex:SetColorTexture(1,0.82,0, 0.5)
|
|
ringDetail.scope = CreateFrame("Frame", "RKC_RingScopeDropDown", ringDetail, "UIDropDownMenuTemplate")
|
|
ringDetail.scope:SetPoint("TOPLEFT", 250, -37) UIDropDownMenu_SetWidth(ringDetail.scope, 250)
|
|
ringDetail.scope.label = ringDetail.scope:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
|
|
ringDetail.scope.label:SetPoint("TOPLEFT", ringDetail, "TOPLEFT", 10, -47)
|
|
ringDetail.scope.label:SetText(L"Make this ring available to:")
|
|
ringDetail.binding = config.createBindingButton(ringDetail)
|
|
ringDetail.bindingContainerFrame = panel
|
|
ringDetail.binding:SetPoint("TOPLEFT", 267, -68) ringDetail.binding:SetWidth(265)
|
|
function ringDetail:SetBinding(bind) return api.setRingBinding(bind or false) end
|
|
function ringDetail:OnBindingAltClick() self:ToggleAlternateEditor(api.getRingBinding()) end
|
|
ringDetail.binding.label = ringDetail.scope:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
|
|
ringDetail.binding.label:SetPoint("TOPLEFT", ringDetail, "TOPLEFT", 10, -73)
|
|
ringDetail.binding.label:SetText(L"Binding:")
|
|
do -- ringDetail.rotation
|
|
local s, sliderLeftMargin, centerLine = TS:CreateOptionsSlider(ringDetail, nil, 250)
|
|
s:SetPoint("TOPLEFT", 270-sliderLeftMargin, -95)
|
|
s:SetMinMaxValues(0, 345)
|
|
s:SetValueStep(15)
|
|
s:SetObeyStepOnDrag(true)
|
|
s:SetScript("OnValueChanged", function(_, value) api.setRingProperty("offset", value) end)
|
|
s.lo:SetText("0°")
|
|
s.hi:SetText("345°")
|
|
s.text:SetPoint("LEFT", ringDetail, "TOPLEFT", 10, -95-centerLine)
|
|
s.text:SetText(L"Rotation:")
|
|
s.text:Show()
|
|
ringDetail.rotation, s.label = s, s.text
|
|
end
|
|
ringDetail.opportunistCA = TS:CreateOptionsCheckButton(nil, ringDetail)
|
|
ringDetail.opportunistCA:SetPoint("TOPLEFT", 266, -118)
|
|
ringDetail.opportunistCA:SetMotionScriptsWhileDisabled(1)
|
|
ringDetail.opportunistCA.Text:SetText(L"Pre-select a quick action slice")
|
|
ringDetail.opportunistCA:SetScript("OnEnter", config.ui.ShowControlTooltip)
|
|
ringDetail.opportunistCA:SetScript("OnLeave", config.ui.HideTooltip)
|
|
ringDetail.opportunistCA:SetScript("OnClick", function(self) PlayCheckboxSound(self) api.setRingProperty("noOpportunisticCA", (not self:GetChecked()) or nil) api.setRingProperty("noPersistentCA", (not self:GetChecked()) or nil) end)
|
|
ringDetail.hiddenRing = TS:CreateOptionsCheckButton(nil, ringDetail)
|
|
ringDetail.hiddenRing:SetPoint("TOPLEFT", ringDetail.opportunistCA, "BOTTOMLEFT", 0, 2)
|
|
ringDetail.hiddenRing.Text:SetText(L"Hide this ring")
|
|
ringDetail.hiddenRing:SetScript("OnClick", function(self) PlayCheckboxSound(self) api.setRingProperty("internal", self:GetChecked() and true or nil) end)
|
|
ringDetail.embedRing = TS:CreateOptionsCheckButton(nil, ringDetail)
|
|
ringDetail.embedRing:SetPoint("TOPLEFT", ringDetail.hiddenRing, "BOTTOMLEFT", 0, 2)
|
|
ringDetail.embedRing.Text:SetText(L"Embed into other rings by default")
|
|
ringDetail.embedRing:SetScript("OnClick", function(self) PlayCheckboxSound(self) api.setRingProperty("embed", self:GetChecked() and true or nil) end)
|
|
ringDetail.firstOnOpen = TS:CreateOptionsCheckButton(nil, ringDetail) do
|
|
local f = ringDetail.firstOnOpen
|
|
f:SetPoint("TOPLEFT", ringDetail.embedRing, "BOTTOMLEFT", 0, 2)
|
|
f:SetMotionScriptsWhileDisabled(1)
|
|
f.Text:SetText(L"Use first slice when opened")
|
|
f:SetScript("OnClick", function(self)
|
|
PlayCheckboxSound(self)
|
|
self.quarantineMark:Hide()
|
|
api.setRingProperty("onOpen", self:GetChecked() and 1 or nil)
|
|
end)
|
|
f.quarantineMark = f:CreateTexture(nil, "ARTWORK")
|
|
f.quarantineMark:SetAllPoints()
|
|
f.quarantineMark:SetTexture(f:GetCheckedTexture():GetTexture())
|
|
f.quarantineMark:SetDesaturated(true)
|
|
f.quarantineMark:SetVertexColor(1, 0.95, 0.85, 0.65)
|
|
end
|
|
|
|
ringDetail.optionsLabel = ringDetail:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
|
|
ringDetail.optionsLabel:SetPoint("TOPLEFT", ringDetail, "TOPLEFT", 10, -125)
|
|
ringDetail.optionsLabel:SetText(L"Options:")
|
|
|
|
ringDetail.editBindings = CreateButton(ringDetail, 210)
|
|
ringDetail.editBindings:SetPoint("TOPLEFT", ringDetail, "TOPLEFT", 292, -214)
|
|
ringDetail.editBindings:SetText(L"Customize bindings")
|
|
ringDetail.editBindings:SetScript("OnClick", function() PlaySound(SOUNDKIT.U_CHAT_SCROLL_BUTTON) api.showExternalEditor("slice-binding") end)
|
|
|
|
ringDetail.editOptions = CreateButton(ringDetail, 210)
|
|
ringDetail.editOptions:SetPoint("TOPLEFT", ringDetail.editBindings, "BOTTOMLEFT", 0, -2)
|
|
ringDetail.editOptions:SetText(L"Customize options")
|
|
ringDetail.editOptions:SetScript("OnClick", function() PlaySound(SOUNDKIT.U_CHAT_SCROLL_BUTTON) api.showExternalEditor("opie-options") end)
|
|
|
|
ringDetail.shareLabel = ringDetail:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
|
|
ringDetail.shareLabel:SetPoint("TOPLEFT", ringDetail, "TOPLEFT", 10, -265)
|
|
ringDetail.shareLabel:SetText(L"Snapshot:")
|
|
ringDetail.shareLabel2 = ringDetail:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmallLeft")
|
|
ringDetail.shareLabel2:SetPoint("TOPLEFT", ringDetail, "TOPLEFT", 270, -265)
|
|
ringDetail.shareLabel2:SetWidth(275)
|
|
ringDetail.export = CreateButton(ringDetail)
|
|
ringDetail.export:SetPoint("TOP", ringDetail.shareLabel2, "BOTTOM", 0, -4)
|
|
ringDetail.export:SetText(L"Share ring")
|
|
ringDetail.export:SetScript("OnClick", function(self) PlaySound(SOUNDKIT.U_CHAT_SCROLL_BUTTON) api.exportRing(self.nested:IsShown() and self.nested:GetChecked() and true) end)
|
|
ringDetail.export.nested = TS:CreateOptionsCheckButton(nil, ringDetail.export) do
|
|
local f = ringDetail.export.nested
|
|
f:SetPoint("TOPLEFT", ringDetail.shareLabel2, "BOTTOMLEFT", -4, -1)
|
|
f.Text:SetText(L"Include nested rings")
|
|
local function moveExportButton(self)
|
|
ringDetail.export:SetPoint("TOP", ringDetail.shareLabel2, "BOTTOM", 0, self:IsVisible() and -22 or -4)
|
|
end
|
|
f:SetScript("OnClick", PlayCheckboxSound)
|
|
f:SetScript("OnShow", moveExportButton)
|
|
f:SetScript("OnHide", moveExportButton)
|
|
end
|
|
|
|
local textArea = XU:Create("TextArea", "RKC_ExportInput", ringDetail)
|
|
textArea:SetStyle("tooltip")
|
|
textArea:SetSize(265, 124)
|
|
textArea:Hide()
|
|
textArea:SetPoint("TOPLEFT", ringDetail.shareLabel2, "BOTTOMLEFT", -2, -2)
|
|
ringDetail.exportArea = textArea
|
|
textArea:SetFontObject(GameFontHighlightSmall)
|
|
textArea:SetScript("OnEscapePressed", function() textArea:Hide() ringDetail.export:Show() end)
|
|
textArea:SetScript("OnChar", function(self) local text = self:GetText() if text ~= "" and text ~= self.text then self:SetText(self.text or "") self:SetCursorPosition(0) self:HighlightText() end end)
|
|
textArea:SetScript("OnTextSet", function(self) self.text = self:GetText() end)
|
|
textArea:SetScript("OnHide", function(self)
|
|
self:Hide()
|
|
ringDetail.export:Show()
|
|
ringDetail.shareLabel2:SetText(L"Take a snapshot of this ring to share it with others.")
|
|
end)
|
|
textArea:SetScript("OnShow", function()
|
|
ringDetail.export:Hide()
|
|
ringDetail.shareLabel2:SetText((L"Import snapshots by clicking %s above."):format(NORMAL_FONT_COLOR_CODE .. L"New Ring..." .. "|r"))
|
|
end)
|
|
|
|
ringDetail.remove = CreateButton(ringDetail)
|
|
ringDetail.remove:SetPoint("BOTTOMRIGHT", -10, 10)
|
|
ringDetail.remove:SetText(L"Delete ring")
|
|
ringDetail.remove:SetScript("OnClick", function() PlaySound(SOUNDKIT.U_CHAT_SCROLL_BUTTON) api.deleteRing() end)
|
|
|
|
ringDetail.restore = CreateButton(ringDetail)
|
|
ringDetail.restore:SetPoint("RIGHT", ringDetail.remove, "LEFT", -20, 0)
|
|
ringDetail.restore:SetText(L"Restore default")
|
|
ringDetail.restore:SetScript("OnClick", function() PlaySound(SOUNDKIT.U_CHAT_SCROLL_BUTTON) api.restoreDefault() end)
|
|
|
|
ringDetail:Hide()
|
|
end
|
|
sliceDetail = CreateFrame("Frame", nil, ringContainer) do
|
|
sliceDetail:SetAllPoints()
|
|
sliceDetail.desc = sliceDetail:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
|
|
sliceDetail.desc:SetPoint("TOPLEFT", 7, -9) sliceDetail.desc:SetPoint("TOPRIGHT", -7, -7) sliceDetail.desc:SetJustifyH("LEFT")
|
|
TS:EscapeCallback(sliceDetail, "TAB", function(_, key)
|
|
if sliceDetail.iconSelector:IsShown() then
|
|
if key == "TAB" then
|
|
sliceDetail.iconSelector:FocusManualInput()
|
|
else
|
|
sliceDetail.iconSelector:Hide()
|
|
end
|
|
elseif key == "ESCAPE" then
|
|
api.selectSlice()
|
|
end
|
|
end)
|
|
local oy = 37
|
|
sliceDetail.skipSpecs = CreateFrame("Frame", "RKC_SkipSpecDropdown", sliceDetail, "UIDropDownMenuTemplate") do
|
|
local s = sliceDetail.skipSpecs
|
|
s:SetPoint("TOPLEFT", 250, -oy)
|
|
UIDropDownMenu_SetWidth(s, 250)
|
|
oy = oy + 31
|
|
s.label = s:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
|
|
s.label:SetPoint("TOPLEFT", sliceDetail, "TOPLEFT", 10, -47)
|
|
s.label:SetText(L"Show this slice for:")
|
|
end
|
|
sliceDetail.showConditional = XU:Create("LineInput", nil, sliceDetail) do
|
|
local c = sliceDetail.showConditional
|
|
c:SetWidth(260)
|
|
c:SetPoint("TOPLEFT", 274, -oy)
|
|
oy = oy + 23
|
|
c.label = c:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
|
|
c.label:SetPoint("TOPLEFT", sliceDetail, "TOPLEFT", 10, -73)
|
|
c.label:SetText(L"Visibility conditional:")
|
|
prepEditBox(c, function(self) api.setSliceProperty("show", self:GetText()) end)
|
|
c:SetScript("OnEnter", function(self)
|
|
GameTooltip:SetOwner(self, "ANCHOR_TOP")
|
|
GameTooltip:AddLine(L"Conditional Visibility")
|
|
GameTooltip:AddLine((L"If this macro conditional evaluates to %s, or if none of its clauses apply, this slice will be hidden."):format(GREEN_FONT_COLOR_CODE .. "hide" .. "|r"), HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b, 1)
|
|
GameTooltip:AddLine((L"You may use extended macro conditionals; see %s for details."):format("|cff33DDFFhttps://townlong-yak.com/addons/opie/extended-conditionals|r"), HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b, 1)
|
|
GameTooltip:AddLine((L"Example: %s."):format(GREEN_FONT_COLOR_CODE .. "[nocombat][mod]|r"), NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b)
|
|
GameTooltip:AddLine((L"Example: %s."):format(GREEN_FONT_COLOR_CODE .. "[combat,@target,noexists] hide; show|r"), NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b)
|
|
GameTooltip:Show()
|
|
end)
|
|
c:SetScript("OnLeave", config.ui.HideTooltip)
|
|
end
|
|
sliceDetail.color = XU:Create("LineInput", nil, sliceDetail) do
|
|
local c = sliceDetail.color
|
|
c:SetPoint("TOPLEFT", 274, -oy)
|
|
c:SetWidth(85)
|
|
oy = oy + 23
|
|
c:SetTextInsets(22, 0, 0, 0) c:SetMaxBytes(7)
|
|
prepEditBox(c, function(self)
|
|
local r,g,b = self:GetText():match("(%x%x)(%x%x)(%x%x)")
|
|
if self:GetText() == "" then
|
|
api.setSliceProperty("color")
|
|
elseif not r then
|
|
if self.oldValue == "" then self.placeholder:Show() end
|
|
self:SetText(self.oldValue)
|
|
else
|
|
api.setSliceProperty("color", tonumber(r,16)/255, tonumber(g,16)/255, tonumber(b,16)/255)
|
|
end
|
|
end)
|
|
c.label = c:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
|
|
c.label:SetPoint("TOPLEFT", sliceDetail, "TOPLEFT", 10, -96)
|
|
c.label:SetText(L"Color:")
|
|
c.placeholder = c:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
|
|
c.placeholder:SetPoint("LEFT", 18, 0)
|
|
c.placeholder:SetText("|cffa0a0a0" .. L"(default)")
|
|
c.button = CreateFrame("Button", nil, c)
|
|
local b = sliceDetail.color.button
|
|
b:SetSize(14, 14) b:SetPoint("LEFT")
|
|
b.bg = sliceDetail.color.button:CreateTexture(nil, "BACKGROUND")
|
|
b.bg:SetSize(12, 12) b.bg:SetPoint("CENTER")
|
|
b.bg:SetColorTexture(1,1,1)
|
|
b.bg:SetSnapToPixelGrid(false)
|
|
b.bg:SetTexelSnappingBias(0)
|
|
b:SetNormalTexture("Interface/ChatFrame/ChatFrameColorSwatch")
|
|
b:SetScript("OnEnter", function(self) self.bg:SetVertexColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b) end)
|
|
b:SetScript("OnLeave", function(self) self.bg:SetVertexColor(1, 1, 1) end)
|
|
b:SetScript("OnShow", b:GetScript("OnLeave"))
|
|
local ctex = b:GetNormalTexture()
|
|
ctex:SetSnapToPixelGrid(false)
|
|
ctex:SetTexelSnappingBias(0)
|
|
local function update()
|
|
if not ColorPickerFrame:IsShown() or ColorPickerFrame.Footer and ColorPickerFrame.Footer.OkayButton:GetButtonState() == "PUSHED" then
|
|
api.setSliceProperty("color", ColorPickerFrame:GetColorRGB())
|
|
end
|
|
end
|
|
b:SetScript("OnClick", function()
|
|
local cp, r,g,b = ColorPickerFrame, ctex:GetVertexColor()
|
|
cp.previousValues, cp.hasOpacity, cp.func, cp.cancelFunc, cp.swatchFunc, cp.opacityFunc = true
|
|
if cp.SetColorRGB then
|
|
cp:SetColorRGB(r,g,b)
|
|
cp.func = update
|
|
else
|
|
cp.Content.ColorSwatchOriginal:SetColorTexture(r,g,b)
|
|
cp.Content.HexBox:OnColorSelect(r,g,b)
|
|
cp.Content.ColorPicker:SetColorRGB(r,g,b)
|
|
cp.swatchFunc = update
|
|
end
|
|
cp:Show()
|
|
end)
|
|
local ceil = math.ceil
|
|
function c:SetColor(r,g,b, custom)
|
|
if r and g and b and custom then
|
|
c:SetText(("%02X%02X%02X"):format(ceil((r or 0)*255),ceil((g or 0)*255),ceil((b or 0)*255)))
|
|
c.placeholder:Hide()
|
|
else
|
|
c:SetText("")
|
|
c.placeholder:Show()
|
|
end
|
|
ctex:SetVertexColor(r or 0,g or 0,b or 0)
|
|
end
|
|
end
|
|
sliceDetail.icon = CreateFrame("Button", nil, sliceDetail) do
|
|
local f = sliceDetail.icon
|
|
f:SetHitRectInsets(0,-280,0,0) f:SetSize(18, 18)
|
|
f:SetPoint("TOPLEFT", 270, -oy-2)
|
|
oy = oy + 23
|
|
f:SetHighlightTexture("Interface/Buttons/ButtonHilight-Square")
|
|
f:SetNormalFontObject(GameFontHighlight) f:SetHighlightFontObject(GameFontGreen) f:SetPushedTextOffset(3/4, -3/4)
|
|
f:SetText(" ") f:GetFontString():ClearAllPoints() f:GetFontString():SetPoint("LEFT", f, "RIGHT", 4, 0)
|
|
f.icon = f:CreateTexture() f.icon:SetAllPoints()
|
|
f.label = f:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
|
|
f.label:SetPoint("TOPLEFT", sliceDetail, "TOPLEFT", 10, -119)
|
|
f.label:SetText(L"Icon:")
|
|
|
|
local isd = XU:Create("IconSelector", nil, sliceDetail)
|
|
isd:SetPoint("TOPLEFT", f, "TOPLEFT", -268, -18)
|
|
isd:SetManualInputHintText("|cffa0a0a0" .. L"(enter an icon name or path here)")
|
|
sliceDetail.iconSelector = isd
|
|
f:SetScript("OnClick", function()
|
|
isd:SetShown(not isd:IsShown())
|
|
PlaySound(SOUNDKIT.U_CHAT_SCROLL_BUTTON)
|
|
end)
|
|
isd:SetScript("OnIconSelect", function(_, asset)
|
|
api.setSliceProperty("icon", asset)
|
|
end)
|
|
isd:SetScript("OnEditFocusGained", function(self, editbox)
|
|
local nc = NORMAL_FONT_COLOR
|
|
GameTooltip:SetOwner(editbox, "ANCHOR_NONE")
|
|
GameTooltip:SetPoint("BOTTOMLEFT", editbox, "TOPLEFT", -6, 0)
|
|
GameTooltip:AddLine(L"Override Icon", 1,1,1)
|
|
GameTooltip:AddLine(L"Specify an icon by entering an icon file name, texture path, atlas name, or a known ability name.", nc.r, nc.g, nc.b, 1)
|
|
if self:IsSearchPossible() then
|
|
GameTooltip:AddLine((L"Press %s to search"):format(HIGHLIGHT_FONT_COLOR_CODE .. GetBindingText("ALT-ENTER") .. "|r"), nc.r, nc.g, nc.b, 1)
|
|
else
|
|
local at = HIGHLIGHT_FONT_COLOR_CODE .. "IconFileNames |cff606060<|cff40a0ffhttps://townlong-yak.com/addons/iconfilenames|r>|r|r"
|
|
GameTooltip:AddLine((L"Install and enable %s to search by file name."):format(at), nc.r, nc.g, nc.b, 1)
|
|
end
|
|
GameTooltip:Show()
|
|
end)
|
|
isd:SetScript("OnEditFocusLost", function(_, editbox)
|
|
if GameTooltip:IsOwned(editbox) then
|
|
GameTooltip:Hide()
|
|
end
|
|
end)
|
|
function f:SetIcon(ico, forced, ext)
|
|
local plainTexture, atlas = setIcon(self.icon, forced or ico, ext)
|
|
self:SetText(forced and L"Customized icon" or L"Based on slice action")
|
|
isd:SetFirstAsset(atlas or plainTexture)
|
|
isd:SetSelectedAsset(forced)
|
|
end
|
|
end
|
|
sliceDetail.fastClick = TS:CreateOptionsCheckButton(nil, sliceDetail) do
|
|
local e = sliceDetail.fastClick
|
|
e:SetHitRectInsets(0, -200, 4, 4) e:SetMotionScriptsWhileDisabled(1)
|
|
e:SetPoint("TOPLEFT", 266, -oy)
|
|
e:SetScript("OnClick", function(self) PlayCheckboxSound(self) return api.setSliceProperty("fastClick", self:GetChecked() and true or nil) end)
|
|
e:SetScript("OnEnter", config.ui.ShowControlTooltip)
|
|
e:SetScript("OnLeave", config.ui.HideTooltip)
|
|
e.Text:SetText(L"Allow as quick action")
|
|
e.label = sliceDetail:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
|
|
e.label:SetPoint("TOPLEFT", sliceDetail, "TOPLEFT", 10, -142)
|
|
e.label:SetText(L"Options:")
|
|
oy = oy + 21
|
|
end
|
|
sliceDetail.collectionDrop = CreateFrame("Frame", "RKC_SliceOptions_Collection", sliceDetail, "UIDropDownMenuTemplate") do
|
|
local w = sliceDetail.collectionDrop
|
|
w:SetPoint("TOPLEFT", 250, -oy)
|
|
UIDropDownMenu_SetWidth(w, 250)
|
|
w.label = w:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
|
|
w.label:SetText(L"Display as:")
|
|
w.label:SetPoint("LEFT", -240, 0)
|
|
local modes = {
|
|
false, "cycle", "shuffle", "random", "reset", "jump",
|
|
[false]=L"Remember last rotation",
|
|
cycle=L"Advance rotation after use",
|
|
shuffle=L"Randomize rotation after use",
|
|
random=L"Randomize rotation on display",
|
|
reset=L"Reset rotation on display",
|
|
jump=L"Display a jump slice",
|
|
}
|
|
function w:set(opt)
|
|
if opt == "default" then
|
|
w.rotationMode, w.embed = nil, nil
|
|
elseif opt == "embed" then
|
|
w.embed, w.rotationMode = true, nil
|
|
else
|
|
w.rotationMode, w.embed = opt, nil
|
|
if opt == nil then
|
|
w.embed = false
|
|
end
|
|
end
|
|
api.setSliceProperty("rotationMode", opt, w.embed)
|
|
w:text()
|
|
end
|
|
function w:text()
|
|
local text, mode = "", modes[self.rotationMode or false]
|
|
if self.embed == nil and self.rotationMode == nil then
|
|
text = L"Not customized"
|
|
elseif self.embed then
|
|
text = L"Embed slices in this ring"
|
|
elseif self.rotationMode == "jump" then
|
|
text = mode
|
|
elseif mode then
|
|
text = (NORMAL_FONT_COLOR_CODE .. L"Nested ring: %s"):format("|r" .. mode)
|
|
end
|
|
UIDropDownMenu_SetText(self, text)
|
|
end
|
|
function w:initialize()
|
|
local info = {minWidth=self:GetWidth()-40, func=w.set}
|
|
local isNotEmbed, isDefault = not self.embed, self.embed == nil and self.rotationMode == nil
|
|
info.text, info.arg1, info.checked = L"Not customized", "default", isDefault
|
|
UIDropDownMenu_AddButton(info)
|
|
UIDropDownMenu_AddSeparator()
|
|
info.text, info.isTitle, info.notCheckable = L"Display as a nested ring", true, true
|
|
UIDropDownMenu_AddButton(info)
|
|
info.isTitle, info.disabled, info.notCheckable = nil
|
|
for i=1,#modes do
|
|
local v = modes[i]
|
|
info.arg1, info.text = v or nil, modes[v]
|
|
info.checked = isNotEmbed and self.rotationMode == (v or nil) and not isDefault
|
|
if v == "jump" then
|
|
UIDropDownMenu_AddSeparator()
|
|
end
|
|
UIDropDownMenu_AddButton(info)
|
|
end
|
|
UIDropDownMenu_AddSeparator()
|
|
info.arg1, info.text = "embed", L"Embed slices in this ring"
|
|
info.checked = not isNotEmbed
|
|
UIDropDownMenu_AddButton(info)
|
|
end
|
|
end
|
|
|
|
do -- .editorContainer
|
|
local f; f, editorHost = AB:CreateEditorHost(sliceDetail)
|
|
f:SetPoint("TOPLEFT", sliceDetail.fastClick.label, "BOTTOMLEFT", 0, -10)
|
|
f:SetPoint("BOTTOMRIGHT", -10, 36)
|
|
f.optionsColumnOffset = 256
|
|
function f:OnActionChanged(ed)
|
|
return editorHost:IsCurrentEditor(ed) and api.setSliceAction()
|
|
end
|
|
function f:SaveAction() -- DEPRECATED [2303/Y8]
|
|
api.setSliceAction()
|
|
end
|
|
function f:SetVerticalOffset(ofsY)
|
|
f:SetPoint("TOPLEFT", sliceDetail.fastClick.label, "BOTTOMLEFT", 0, -6-ofsY)
|
|
end
|
|
sliceDetail.editorContainer = f
|
|
end
|
|
sliceDetail.remove = CreateButton(sliceDetail)
|
|
sliceDetail.remove:SetPoint("BOTTOMRIGHT", -10, 10)
|
|
sliceDetail.remove:SetText(L"Delete slice")
|
|
sliceDetail.remove:SetScript("OnClick", function() return api.deleteSlice() end)
|
|
sliceDetail.repick = CreateButton(sliceDetail)
|
|
sliceDetail.repick:SetPoint("BOTTOMLEFT", 10, 10)
|
|
sliceDetail.repick:SetText(L"Change action")
|
|
sliceDetail.repick:SetScript("OnClick", function()
|
|
PlaySound(SOUNDKIT.U_CHAT_SCROLL_BUTTON)
|
|
return api.beginSliceRepick()
|
|
end)
|
|
sliceDetail.restore = CreateButton(sliceDetail)
|
|
sliceDetail.restore:SetPoint("RIGHT", sliceDetail.remove, "LEFT", -20, 0)
|
|
sliceDetail.restore:SetText(L"Restore default")
|
|
sliceDetail.restore:SetScript("OnClick", function() PlaySound(SOUNDKIT.U_CHAT_SCROLL_BUTTON) api.restoreSliceDefault() end)
|
|
end
|
|
newSlice = CreateFrame("Frame", nil, ringContainer) do
|
|
newSlice:SetAllPoints()
|
|
newSlice:Hide()
|
|
local NUM_VISIBLE_CATS, NUM_VISIBLE_ACTION_ROWS = 22, 12
|
|
newSlice.slider = XU:Create("ScrollBar", nil, newSlice) do
|
|
local s = newSlice.slider
|
|
s:SetPoint("TOPLEFT", 162, -3)
|
|
s:SetPoint("BOTTOMLEFT", 162, 3)
|
|
s:SetMinMaxValues(0, 20)
|
|
s:SetValueStep(1)
|
|
s:SetWindowRange(NUM_VISIBLE_CATS)
|
|
s:SetStepsPerPage(5)
|
|
s:SetStyle("common")
|
|
end
|
|
|
|
local cats, actions, searchCat, selectCategory, selectedCategory, selectedCategoryId = {}, {}
|
|
local performSearch do
|
|
local function matchAction(q, ...)
|
|
local _, aname = AB:GetActionDescription(...)
|
|
if type(aname) ~= "string" then return end
|
|
aname = aname:match("|") and aname:gsub("|c%x%x%x%x%x%x%x%x", ""):gsub("|r", ""):gsub("|T.-|t", ""):lower() or aname:lower()
|
|
return not not aname:match(q)
|
|
end
|
|
function performSearch(query, inCurrentCategory)
|
|
searchCat = selectedCategory
|
|
if not inCurrentCategory then
|
|
searchCat = AB:GetCategoryContents(1)
|
|
for i=2,AB:GetNumCategories() do
|
|
searchCat = AB:GetCategoryContents(i, searchCat)
|
|
end
|
|
end
|
|
searchCat:filter(matchAction, query:lower())
|
|
selectCategory(-1)
|
|
end
|
|
end
|
|
do -- newSlice.search
|
|
local s = XU:Create("LineInput", nil, newSlice)
|
|
s:SetWidth(153)
|
|
s:SetPoint("TOPLEFT", 7, -1) s:SetTextInsets(16, 0, 0, 0)
|
|
local i = s:CreateTexture(nil, "OVERLAY")
|
|
i:SetSize(14, 14) i:SetPoint("LEFT", 0, -1)
|
|
i:SetTexture("Interface/Common/UI-Searchbox-Icon")
|
|
local l, tip = s:CreateFontString(nil, "OVERLAY", "GameFontDisableSmall"), CreateFrame("GameTooltip", "RKC_SearchTip", newSlice, "GameTooltipTemplate")
|
|
l:SetPoint("LEFT", 16, 0)
|
|
l:SetText(L"Search")
|
|
s:SetScript("OnEditFocusGained", function(s)
|
|
l:Hide()
|
|
i:SetVertexColor(0.90, 0.90, 0.90)
|
|
tip:SetFrameStrata("TOOLTIP")
|
|
tip:SetOwner(s, "ANCHOR_BOTTOM")
|
|
tip:AddLine((L"Press %s to search"):format(HIGHLIGHT_FONT_COLOR_CODE .. GetBindingText("ENTER") .. "|r"))
|
|
tip:AddLine((L"%s to search within current results"):format(HIGHLIGHT_FONT_COLOR_CODE .. GetBindingText("CTRL-ENTER") .. "|r"), nil, nil, nil, true)
|
|
tip:AddLine((L"%s to cancel"):format(HIGHLIGHT_FONT_COLOR_CODE .. GetBindingText("ESCAPE") .. "|r"), true)
|
|
tip:Show()
|
|
end)
|
|
s:SetScript("OnEditFocusLost", function(s)
|
|
l:SetShown(not s:GetText():match("%S"))
|
|
i:SetVertexColor(0.75, 0.75, 0.75)
|
|
tip:Hide()
|
|
end)
|
|
s:SetScript("OnEnterPressed", function(s)
|
|
s:ClearFocus()
|
|
if s:GetText():match("%S") then
|
|
performSearch(s:GetText(), IsControlKeyDown() and selectedCategory)
|
|
end
|
|
end)
|
|
newSlice.search, s.ico, s.label = s, i, l
|
|
end
|
|
|
|
local catbg = newSlice:CreateTexture(nil, "BACKGROUND")
|
|
catbg:SetPoint("TOPLEFT", 2, -2) catbg:SetPoint("RIGHT", newSlice, "RIGHT", -2, 0) catbg:SetPoint("BOTTOM", 0, 2)
|
|
catbg:SetColorTexture(0,0,0, 0.65)
|
|
local function onCatClick(self)
|
|
PlaySound(SOUNDKIT.U_CHAT_SCROLL_BUTTON)
|
|
selectCategory(self:GetID())
|
|
end
|
|
local catContainer = CreateFrame("Frame", nil, newSlice)
|
|
catContainer:SetClipsChildren(true)
|
|
catContainer:SetSize(159, NUM_VISIBLE_CATS*20)
|
|
catContainer:SetPoint("TOPLEFT", 2, -22)
|
|
newSlice.slider:SetWheelScrollTarget(catContainer)
|
|
local catOrigin = CreateFrame("Frame", nil, catContainer)
|
|
catOrigin:Hide()
|
|
catOrigin:SetSize(159, 1)
|
|
catOrigin:SetPoint("TOPLEFT")
|
|
for i=1, NUM_VISIBLE_CATS+1 do
|
|
local b = CreateFrame("Button", nil, catContainer)
|
|
b:SetSize(159, 20)
|
|
b:SetNormalTexture("Interface/AchievementFrame/UI-Achievement-Category-Background")
|
|
b:SetHighlightTexture("Interface/AchievementFrame/UI-Achievement-Category-Highlight")
|
|
b:GetNormalTexture():SetTexCoord(7/256, 162/256, 5/32, 24/32)
|
|
b:GetHighlightTexture():SetTexCoord(7/256, 163/256, 5/32, 24/32)
|
|
b:GetNormalTexture():SetVertexColor(0.6, 0.6, 0.6)
|
|
b:SetNormalFontObject(GameFontHighlight)
|
|
b:SetHighlightFontObject(GameFontHighlight)
|
|
b:SetPushedTextOffset(0,0)
|
|
b:SetText(" ") b:GetFontString():SetPoint("CENTER", 0, 1)
|
|
b:SetScript("OnClick", onCatClick)
|
|
cats[i] = b
|
|
b:SetPoint("TOPLEFT", catOrigin, 0, 20-20*i)
|
|
end
|
|
|
|
newSlice.desc = newSlice:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
|
|
newSlice.desc:SetPoint("TOPLEFT", newSlice.slider, "TOPRIGHT", 2, -6)
|
|
newSlice.desc:SetPoint("RIGHT", -24, 0)
|
|
newSlice.desc:SetHeight(26)
|
|
newSlice.desc:SetJustifyV("TOP") newSlice.desc:SetJustifyH("CENTER")
|
|
newSlice.desc:SetText(L"Select an action by double clicking.")
|
|
|
|
newSlice.close = CreateFrame("Button", "RKC_CloseNewSliceBrowser", newSlice, "UIPanelCloseButton")
|
|
newSlice.close:SetPoint("TOPRIGHT", 3, 4)
|
|
newSlice.close:SetSize(30, 30)
|
|
newSlice.close:SetFrameLevel(newSlice:GetFrameLevel()+120)
|
|
newSlice.close:SetScript("OnClick", function()
|
|
PlaySound(SOUNDKIT.U_CHAT_SCROLL_BUTTON)
|
|
api.closeActionPicker("close-picker-button")
|
|
end)
|
|
TS:EscapeCallback(newSlice.close, function() api.closeActionPicker() end)
|
|
|
|
local b = newSlice.close:CreateTexture(nil, "BACKGROUND")
|
|
b:SetAtlas("UI-Frame-TopCornerRight")
|
|
b:SetTexCoord(9/33, 1, 0, 23/33)
|
|
b:SetPoint("TOPLEFT", 4, -5) b:SetPoint("BOTTOMRIGHT", -5, 4)
|
|
b:SetVertexColor(0.6,0.6,0.6)
|
|
|
|
newSlice.slider2 = XU:Create("ScrollBar", nil, newSlice) do
|
|
local s = newSlice.slider2
|
|
s:SetPoint("TOPRIGHT", -2, COMPAT > 11403 and -26 or -22)
|
|
s:SetPoint("BOTTOMRIGHT", -2, 2)
|
|
s:SetMinMaxValues(0, 20)
|
|
s:SetWindowRange(NUM_VISIBLE_ACTION_ROWS)
|
|
s:SetStepsPerPage(4)
|
|
end
|
|
|
|
local function onClick(self)
|
|
PlaySound(SOUNDKIT.U_CHAT_SCROLL_BUTTON)
|
|
api.addSlice(nil, selectedCategory(self:GetID()))
|
|
end
|
|
local function onDragStart(self)
|
|
if newSlice.disableDrag then return end
|
|
PlaySound(832)
|
|
dragBackdrop:Show()
|
|
SetCursor(self.plainTex or "Interface/Icons/Temp")
|
|
self.dragActive = true
|
|
end
|
|
local function onDragAbort(self)
|
|
if self.dragActive then
|
|
self.dragActive = nil
|
|
SetCursor(nil)
|
|
dragBackdrop:Hide()
|
|
end
|
|
end
|
|
local function onDragStop(self)
|
|
onDragAbort(self)
|
|
if newSlice.disableDrag then return end
|
|
PlaySound(833)
|
|
local e, x, y = ringContainer.slices[1], GetCursorPosition()
|
|
if not e:GetLeft() then e = ringContainer.prev end
|
|
local scale, l, b, w, h = e:GetEffectiveScale(), e:GetRect()
|
|
local dy, dx = math.floor(-(y / scale - b - h-1)/(h+2)+0.5), x / scale - l
|
|
if dx < -w/2 or dx > 3*w/2 then return end
|
|
if dy < -1 or dy > (#ringContainer.slices+1) then return end
|
|
api.addSlice(dy, selectedCategory(self:GetID()))
|
|
end
|
|
local function onEnter(self)
|
|
GameTooltip_SetDefaultAnchor(GameTooltip, self)
|
|
if type(self.tipFunc) == "function" then
|
|
securecall(self.tipFunc, GameTooltip, self.tipFuncArg)
|
|
else
|
|
GameTooltip:AddLine(self.name:GetText())
|
|
end
|
|
GameTooltip:Show()
|
|
end
|
|
local actionsContainer = CreateFrame("Frame", nil, newSlice)
|
|
actionsContainer:SetClipsChildren(true)
|
|
actionsContainer:SetPoint("TOPLEFT", newSlice.desc, "BOTTOMLEFT", 0, 8)
|
|
actionsContainer:SetSize(344, 36*NUM_VISIBLE_ACTION_ROWS-1)
|
|
newSlice.slider2:SetWheelScrollTarget(actionsContainer)
|
|
local actionsOrigin = CreateFrame("Frame", nil, actionsContainer)
|
|
actionsOrigin:SetSize(1,1)
|
|
actionsOrigin:SetPoint("TOPLEFT")
|
|
actionsOrigin:Hide()
|
|
|
|
for i=1,NUM_VISIBLE_ACTION_ROWS*2+2 do
|
|
local f = CreateFrame("Button", nil, actionsContainer)
|
|
f:SetSize(170, 34)
|
|
f:SetPoint("TOPLEFT", actionsOrigin, "TOPLEFT", 172*(1 - i % 2), -math.floor((i-1)/2)*36)
|
|
f:RegisterForDrag("LeftButton")
|
|
actions[i] = f
|
|
f:SetScript("OnDragStart", onDragStart)
|
|
f:SetScript("OnDragStop", onDragStop)
|
|
f:SetScript("OnDoubleClick", onClick)
|
|
f:SetScript("OnEnter", onEnter)
|
|
f:SetScript("OnHide", onDragAbort)
|
|
f:SetScript("OnLeave", config.ui.HideTooltip)
|
|
f.ico = f:CreateTexture(nil, "ARTWORK")
|
|
f.ico:SetSize(32,32) f.ico:SetPoint("LEFT", 1, 0)
|
|
addIconSlotTextures(f.ico, 32)
|
|
f.name = f:CreateFontString(nil, "OVERLAY", "GameFontNormal")
|
|
f.name:SetHeight(12)
|
|
f.name:SetPoint("TOPLEFT", f.ico, "TOPRIGHT", 3, -2)
|
|
f.name:SetPoint("RIGHT", -2, 0)
|
|
f.name:SetJustifyH("LEFT")
|
|
f.sub = f:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
|
|
f.sub:SetPoint("TOPLEFT", f.name, "BOTTOMLEFT", 0, -2)
|
|
f.sub:SetPoint("RIGHT", -2, 0)
|
|
f.sub:SetJustifyH("LEFT")
|
|
f:SetHighlightTexture("Interface/Buttons/ButtonHilight-Square")
|
|
f:GetHighlightTexture():SetAllPoints(f.ico)
|
|
end
|
|
|
|
local function syncActions()
|
|
local sv = newSlice.slider2:GetValue()
|
|
local base = math.floor(sv)*2
|
|
actionsOrigin:SetPoint("TOPLEFT", 0, 36*(sv%1))
|
|
for i=1,#actions do
|
|
local e, id = actions[i], i + base
|
|
if id <= #selectedCategory then
|
|
local stype, sname, sicon, extico, tipfunc, tiparg = AB:GetActionListDescription(selectedCategory(id))
|
|
local ok, pt = pcall(setIcon, e.ico, sicon, extico)
|
|
e.tipFunc, e.tipFuncArg, e.plainTex = tipfunc, tiparg, ok and pt or nil
|
|
e.name:SetText(sname)
|
|
e.sub:SetText(stype)
|
|
e:SetID(id)
|
|
e:Show()
|
|
else
|
|
e:Hide()
|
|
end
|
|
end
|
|
end
|
|
local function syncCats(_, base)
|
|
local fr = base % 1
|
|
base = base - fr
|
|
catOrigin:SetPoint("TOPLEFT", 0, fr*20)
|
|
for i=1,#cats do
|
|
local e, category, id = cats[i], AB:GetCategoryInfo(i+base), i+base
|
|
e:SetShown(not not category)
|
|
e:SetID(id)
|
|
e[id == selectedCategoryId and "LockHighlight" or "UnlockHighlight"](e)
|
|
e:SetText(category)
|
|
end
|
|
if selectedCategoryId == -1 then
|
|
newSlice.search.ico:SetVertexColor(0.3, 1, 0)
|
|
else
|
|
newSlice.search.ico:SetVertexColor(0.75, 0.75, 0.75)
|
|
end
|
|
end
|
|
function selectCategory(id)
|
|
selectedCategoryId, selectedCategory = id, id == -1 and searchCat or AB:GetCategoryContents(id)
|
|
if id ~= -1 then
|
|
newSlice.search:SetText("")
|
|
newSlice.search.label:Show()
|
|
end
|
|
syncCats(newSlice.slider, newSlice.slider:GetValue())
|
|
local xv = math.max(0, math.ceil((#selectedCategory - #actions + 2)/2))
|
|
newSlice.slider2:SetMinMaxValues(0, xv)
|
|
newSlice.slider2:SetValue(0)
|
|
syncActions()
|
|
newSlice.search:ClearFocus()
|
|
end
|
|
newSlice.slider:SetScript("OnValueChanged", syncCats)
|
|
newSlice.slider2:SetScript("OnValueChanged", syncActions)
|
|
newSlice:SetScript("OnShow", function(self)
|
|
selectCategory(1)
|
|
self.slider:SetMinMaxValues(0, math.max(0, AB:GetNumCategories() - #cats))
|
|
self.slider:SetValue(0)
|
|
end)
|
|
end
|
|
|
|
local PLAYER_CLASS, PLAYER_CLASS_UC = UnitClass("player")
|
|
local PLAYER_CLASS_COLOR_HEX = RAID_CLASS_COLORS[PLAYER_CLASS_UC].colorStr:sub(3)
|
|
|
|
local function getSliceInfo(slice)
|
|
return securecall(AB.GetActionDescription, AB, slice)
|
|
end
|
|
local function getSliceColor(slice, sicon)
|
|
local c, r,g,b = true, (type(slice.c) == "string" and slice.c or ""):match("(%x%x)(%x%x)(%x%x)")
|
|
if ORI and not r then
|
|
c, r,g,b = false, ORI:GetTexColor(slice.icon or sicon or "Interface\\Icons\\INV_Misc_QuestionMark")
|
|
elseif r then
|
|
r,g,b = tonumber(r,16)/255, tonumber(g,16)/255, tonumber(b,16)/255
|
|
end
|
|
return r,g,b, c
|
|
end
|
|
local function isCollectionSlice(...)
|
|
local actType = select(7, AB:GetActionDescription(...))
|
|
if actType ~= nil then
|
|
return actType == "collection"
|
|
end
|
|
local aid = AB:GetActionSlot(...)
|
|
if aid then
|
|
return AB:GetSlotImplementation(aid) == "collection"
|
|
end
|
|
end
|
|
local decodeConstantList do
|
|
local stringEscapes = {a="\a",b="\b",f="\f",n="\n",r="\r",t="\t",v="\v",["\\"]="\\",["'"]="'",['"']='"'}
|
|
local function decodeStringEscape(w, f, s)
|
|
local v = stringEscapes[f]
|
|
if v then
|
|
return v .. s
|
|
end
|
|
v = f >= "0" and f <= "9" and tonumber(w)
|
|
return v and (v < 256 and string.char(v) or error("Invalid escape sequence")) or w
|
|
end
|
|
function decodeConstantList(text, start)
|
|
local rv, ve, ps, w, c, pe = nil, nil, text:match("^%s*()(([%dtfn\"'%[])[^,%s\\\"']*)%s*()", start)
|
|
if c == "'" or c == '"' then
|
|
repeat
|
|
w, pe = text:match('(\\*)' .. c .. '()', pe)
|
|
until pe == nil or #w % 2 == 0
|
|
if pe then
|
|
rv, ve = text:sub(ps+1,pe-2):gsub('||','|'):gsub('\\((.)(%d?%d?))', decodeStringEscape), pe
|
|
end
|
|
elseif c == '[' then
|
|
w, rv, ve = text:match('^%[(=*)%[(.-)%]%1%]()', ps)
|
|
if rv then
|
|
rv = rv:gsub('||', '|')
|
|
end
|
|
elseif w == "false" or w == "true" then
|
|
ve, rv = pe, w == "true"
|
|
elseif w == "nil" or tonumber(w) then
|
|
ve, rv = pe, tonumber(w)
|
|
end
|
|
if ve then
|
|
local ns = text:match("^%s*,()", ve)
|
|
if ns then
|
|
return rv, decodeConstantList(text, ns)
|
|
elseif text:match("^%s*$", ve) then
|
|
return rv
|
|
end
|
|
end
|
|
error("Invalid encoding at position " .. tostring(start))
|
|
end
|
|
end
|
|
local function genBundledRingName(mainNew, mainOld, nestName, usedNames, seq)
|
|
if type(mainOld) == "string" and type(nestName) == "string" and nestName:sub(1,#mainOld) == mainOld then
|
|
nestName = nestName:sub(#mainOld + 1 + #nestName:match("^%s*:?%s*", 1+#mainOld))
|
|
end
|
|
local cand = mainNew .. ": " .. (nestName or seq)
|
|
if usedNames[cand] then
|
|
cand = cand .. "/" .. seq
|
|
while usedNames[cand] do
|
|
cand = ("%s: %s [%04x%04x]"):format(mainNew, nestName or seq, math.random(2^16)-1, math.random(2^16)-1)
|
|
end
|
|
end
|
|
usedNames[cand] = seq
|
|
return cand
|
|
end
|
|
local function setImportedRingProps(name, data)
|
|
data.name, data.limit = name, data.limit == "PLAYER" and FULLNAME or (type(data.limit) == "string" and data.limit:match("^[A-Z]+$") or nil)
|
|
end
|
|
local function updateImportedRingContents(data, ringNameMap)
|
|
for i=1,#data do
|
|
local e = data[i]
|
|
local s = ringNameMap[e and e[1] == "ring" and e[2] or nil]
|
|
if s then
|
|
e[2] = s
|
|
end
|
|
end
|
|
end
|
|
|
|
local ringNameMap, ringOrderMap, ringTypeMap, ringNames, currentRing, currentRingName, sliceBaseIndex, currentSliceIndex, repickSlice = {}, {}, {}, {}
|
|
local typePrefix = {
|
|
MINE="|cff25bdff|TInterface/FriendsFrame/UI-Toast-FriendOnlineIcon:14:14:0:1:32:32:8:24:8:24:30:190:255|t ",
|
|
PERSONAL="|cffd659ff|TInterface/FriendsFrame/UI-Toast-FriendOnlineIcon:14:14:0:1:32:32:8:24:8:24:180:0:255|t ",
|
|
HORDE=MODERN and "|cffff3000|A:QuestPortraitIcon-Horde-small:18:18:-1:-2|a" or "|cffff3000|A:poi-horde:16:16:-2:0|a",
|
|
ALLIANCE=MODERN and "|cff00a0ff|A:QuestPortraitIcon-Alliance-small:20:18:-2:0|a" or "|cff00a0ff|A:poi-alliance:17:20:-2:0|a",
|
|
}
|
|
do
|
|
for k, v in pairs(CLASS_ICON_TCOORDS) do
|
|
local cc = RAID_CLASS_COLORS[k]
|
|
typePrefix[k] = ("|cff%s|TInterface/GLUES/CHARACTERCREATE/UI-CharacterCreate-Classes:16:16:0:0:256:256:%d:%d:%d:%d|t "):format(cc and cc.colorStr:sub(3) or "a0ff00", v[1]*256+6,v[2]*256-6,v[3]*256+6,v[4]*256-6)
|
|
end
|
|
end
|
|
local function sortNames(a,b)
|
|
local oa, ob, na, nb, ta, tb = ringOrderMap[a] or 5, ringOrderMap[b] or 5, ringNameMap[a] or "", ringNameMap[b] or "", ringTypeMap[a] or "", ringTypeMap[b] or ""
|
|
return oa < ob or (oa == ob and ta < tb) or (oa == ob and ta == tb and na < nb) or false
|
|
end
|
|
local function ringDropDown_EntryFormat(k)
|
|
return (typePrefix[ringTypeMap[k]] or "") .. (ringNameMap[k] or "?"), currentRingName == k
|
|
end
|
|
function ringDropDown:initialize(level, nameList)
|
|
local playerName, playerServer = UnitFullName("player")
|
|
local playerFullName = playerName .. "-" .. playerServer
|
|
local info = {func=api.selectRing, minWidth=level == 1 and (self:GetWidth()-40) or nil}
|
|
if level == 1 then
|
|
ringNames = {hidden={}, other={}}
|
|
for name, dname, active, _slices, internal, limit in RK:GetManagedRings() do
|
|
table.insert(active and (internal and ringNames.hidden or ringNames) or ringNames.other, name)
|
|
local isFactionLimit = (limit == "Alliance" or limit == "Horde") and limit:upper() or nil
|
|
local rtype = type(limit) ~= "string" and "GLOBAL" or limit == playerFullName and "MINE" or isFactionLimit or limit:match("[^A-Z]") and "PERSONAL" or limit
|
|
ringNameMap[name], ringOrderMap[name], ringTypeMap[name] = dname, (not active and (rtype == "PERSONAL" and 12 or 10)) or isFactionLimit and 4 or (limit and (limit:match("[^A-Z]") and 0 or 2)), rtype
|
|
end
|
|
table.sort(ringNames, sortNames)
|
|
table.sort(ringNames.hidden, sortNames)
|
|
table.sort(ringNames.other, sortNames)
|
|
if #ringNames == 0 and #ringNames.hidden == 0 and #ringNames.other == 0 then
|
|
btnNewRing:Click()
|
|
return
|
|
end
|
|
elseif nameList then
|
|
XU:Create("ScrollableDropDownList", 2, nameList, ringDropDown_EntryFormat, api.selectRing)
|
|
return
|
|
end
|
|
local hasHidden = ringNames.hidden and #ringNames.hidden > 0
|
|
local hasOther = ringNames.other and #ringNames.other > 0
|
|
XU:Create("ScrollableDropDownList", 1, ringNames, ringDropDown_EntryFormat, api.selectRing, hasHidden or hasOther)
|
|
info.hasArrow, info.notCheckable, info.padding, info.fontObject = 1, 1, 32, GameFontNormalSmall
|
|
info.text, info.func, info.checked = nil
|
|
if hasHidden then
|
|
info.menuList, info.text = ringNames.hidden, L"Hidden rings"
|
|
UIDropDownMenu_AddButton(info, level)
|
|
end
|
|
if hasOther then
|
|
info.menuList, info.text = ringNames.other, L"Inactive rings"
|
|
UIDropDownMenu_AddButton(info, level)
|
|
end
|
|
end
|
|
function api.createRing(name, data, bundle, importNested)
|
|
local name = name:match("^%s*(.-)%s*$")
|
|
if name == "" then return false end
|
|
local iname = RK:GenFreeRingName(name)
|
|
local mapRings, reservedINames, usedNames, nr = {}, importNested and {[iname]=1}, {[name]=true}, 2
|
|
if bundle then
|
|
for k,v in pairs(bundle) do
|
|
if v == 0 then
|
|
mapRings[k] = iname
|
|
elseif type(v) == "table" and importNested then
|
|
setImportedRingProps(genBundledRingName(name, data.name, v.name, usedNames, nr), v)
|
|
local n = RK:GenFreeRingName(v.name, reservedINames)
|
|
mapRings[k], reservedINames[n], nr = n, nr, nr + 1
|
|
end
|
|
end
|
|
if importNested then
|
|
for k,v in pairs(bundle) do
|
|
if type(v) == "table" then
|
|
updateImportedRingContents(v, mapRings)
|
|
SaveRingVersion(mapRings[k], false)
|
|
api.saveRing(mapRings[k], v)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
setImportedRingProps(name, data)
|
|
updateImportedRingContents(data, mapRings)
|
|
SaveRingVersion(iname, false)
|
|
api.saveRing(iname, data)
|
|
api:selectRing(iname)
|
|
return true
|
|
end
|
|
function api.selectRing(_, name)
|
|
CloseDropDownMenus()
|
|
ringDetail:Hide()
|
|
api.hideSliceDetail()
|
|
newSlice:Hide()
|
|
ringContainer.newSlice:SetChecked(nil)
|
|
local desc = RK:GetRingDescription(name)
|
|
currentRing, currentRingName, repickSlice = nil
|
|
if not desc then return end
|
|
RK:SoftSync(name)
|
|
UIDropDownMenu_SetText(ringDropDown, desc.name or name)
|
|
ringDetail.rotation:SetValue(desc.offset or 0)
|
|
ringDetail.name:SetText(desc.name or name)
|
|
ringDetail.hiddenRing:SetChecked(desc.internal)
|
|
ringDetail.embedRing:SetChecked(desc.embed)
|
|
currentRing, currentRingName, sliceBaseIndex, currentSliceIndex = desc, name, 1
|
|
api.refreshDisplay()
|
|
ringDetail:Show()
|
|
ringDetail.scope:text()
|
|
ringDetail.export.nested:SetChecked(true)
|
|
api.updateRingLine(true)
|
|
ringContainer:Show()
|
|
end
|
|
function api.hideSliceDetail()
|
|
sliceDetail:Hide()
|
|
editorHost:Clear()
|
|
end
|
|
function api.updateRingLine(scanForNestedRings)
|
|
ringContainer.prev:SetEnabled(sliceBaseIndex > 1)
|
|
ringContainer.next:Disable()
|
|
local onOpen, lastWidget = currentRing.onOpen
|
|
for i=sliceBaseIndex,#currentRing do
|
|
local e = ringContainer.slices[i-sliceBaseIndex+1]
|
|
if not e then ringContainer.next:Enable() break end
|
|
local _, _, sicon, icoext = getSliceInfo(currentRing[i])
|
|
local ok, pt = pcall(setIcon, e.tex, currentRing[i].icon or sicon, icoext)
|
|
e.plainTex = ok and pt or nil
|
|
e.check:SetShown(RK:IsRingSliceActive(currentRingName, i))
|
|
e.auto:SetShown(onOpen == i)
|
|
e:SetChecked(currentSliceIndex == i)
|
|
e:Show()
|
|
lastWidget = e
|
|
end
|
|
ringContainer.newSlice:SetPoint("TOP", lastWidget or ringContainer.slices[1], lastWidget and "BOTTOM" or "TOP", 0, -2)
|
|
for i=#currentRing-sliceBaseIndex+2,#ringContainer.slices do
|
|
ringContainer.slices[i]:Hide()
|
|
end
|
|
if scanForNestedRings then
|
|
local hasNestedCustomRings = false
|
|
for i=1,#currentRing do
|
|
local e = currentRing[i]
|
|
if e[1] == "ring" and e[2] ~= currentRingName and select(4,RK:GetRingInfo(e[2])) then
|
|
hasNestedCustomRings = true
|
|
break
|
|
end
|
|
end
|
|
ringDetail.export.nested:SetShown(hasNestedCustomRings)
|
|
end
|
|
end
|
|
function api.scrollSliceList(dir)
|
|
sliceBaseIndex = math.max(1,sliceBaseIndex + dir)
|
|
api.updateRingLine()
|
|
end
|
|
function api.resolveSliceOffset(id)
|
|
return sliceBaseIndex + id
|
|
end
|
|
function sliceDetail.skipSpecs:toggle(id)
|
|
self = sliceDetail.skipSpecs
|
|
local v, c = self.val:gsub("/" .. id .. "/", "/")
|
|
if c == 0 then v = "/" .. id .. v end
|
|
self.val = v
|
|
api.setSliceProperty("skipSpecs")
|
|
self:text()
|
|
end
|
|
function sliceDetail.skipSpecs:SetValue(skip)
|
|
self.val = type(skip) == "string" and skip ~= "" and ("/" .. skip .. "/") or "/"
|
|
self:text()
|
|
end
|
|
function sliceDetail.skipSpecs:GetValue()
|
|
return self.val:match("^/(.+)/$")
|
|
end
|
|
function sliceDetail.skipSpecs:text()
|
|
if not MODERN then
|
|
UIDropDownMenu_DisableDropDown(self)
|
|
return UIDropDownMenu_SetText(self, L"All characters")
|
|
end
|
|
local text, u, skipSpecs = "", GetNumSpecializations(), self.val
|
|
for i=1, u do
|
|
local id, name = GetSpecializationInfo(i)
|
|
if not skipSpecs:match("/" .. id .. "/") then
|
|
text, u = text .. (text == "" and "" or ", ") .. name, u - 1
|
|
end
|
|
end
|
|
if u == 0 then
|
|
text = (L"All %s specializations"):format("|cff" .. PLAYER_CLASS_COLOR_HEX .. PLAYER_CLASS .. "|r")
|
|
elseif text == "" then
|
|
text = (L"No %s specializations"):format("|cff" .. PLAYER_CLASS_COLOR_HEX .. PLAYER_CLASS .. "|r")
|
|
else
|
|
text = (L"Only %s"):format("|cff" .. PLAYER_CLASS_COLOR_HEX .. text .. "|r")
|
|
end
|
|
UIDropDownMenu_SetText(self, text)
|
|
end
|
|
function sliceDetail.skipSpecs:initialize()
|
|
local info = {func=self.toggle, isNotRadio=true, minWidth=self:GetWidth()-40, keepShownOnClick=true}
|
|
local skip = self.val or ""
|
|
for i=1, GetNumSpecializations() do
|
|
local id, name, _, icon = GetSpecializationInfo(i)
|
|
info.text, info.arg1, info.checked = "|T" .. icon .. ":16:16:0:0:64:64:4:60:4:60|t " .. name, id, not skip:match("/" .. id .. "/")
|
|
UIDropDownMenu_AddButton(info)
|
|
end
|
|
end
|
|
function ringDetail.scope:initialize()
|
|
local luFaction, lFaction = UnitFactionGroup("player")
|
|
local info = {func=self.set, minWidth=self:GetWidth()-40}
|
|
info.text, info.checked = L"All characters", currentRing.limit == nil
|
|
UIDropDownMenu_AddButton(info)
|
|
info.text, info.checked, info.arg1 = (L"All %s characters"):format("|cff" .. (luFaction == "Horde" and "ff3000" or "00a0ff") .. lFaction .. "|r"), currentRing.limit == luFaction, luFaction
|
|
UIDropDownMenu_AddButton(info)
|
|
info.text, info.checked, info.arg1 = (L"All %s characters"):format("|cff" .. PLAYER_CLASS_COLOR_HEX .. PLAYER_CLASS .. "|r"), currentRing.limit == PLAYER_CLASS_UC, PLAYER_CLASS_UC
|
|
UIDropDownMenu_AddButton(info)
|
|
info.text, info.checked, info.arg1 = (L"Only %s"):format("|cff" .. PLAYER_CLASS_COLOR_HEX .. SHORTNAME .. "|r"), currentRing.limit == FULLNAME, FULLNAME
|
|
UIDropDownMenu_AddButton(info)
|
|
end
|
|
function ringDetail.scope:set(arg1)
|
|
api.setRingProperty("limit", arg1)
|
|
end
|
|
function ringDetail.scope:text()
|
|
local limit = currentRing.limit
|
|
local isFactionLimit = (limit == "Alliance" or limit == "Horde")
|
|
UIDropDownMenu_SetText(self, type(limit) ~= "string" and L"All characters" or
|
|
isFactionLimit and (L"All %s characters"):format((limit == "Horde" and "|cffff3000" or "|cff00a0ff") .. (limit == "Horde" and FACTION_HORDE or FACTION_ALLIANCE) .. "|r") or
|
|
limit:match("[^A-Z]") and (L"Only %s"):format("|cff" .. (limit == FULLNAME and PLAYER_CLASS_COLOR_HEX .. SHORTNAME or ("d659ff" .. limit)) .. "|r") or
|
|
RAID_CLASS_COLORS[limit] and (L"All %s characters"):format("|cff" .. RAID_CLASS_COLORS[limit].colorStr:sub(3) .. (UnitSex("player") == 3 and LOCALIZED_CLASS_NAMES_FEMALE or LOCALIZED_CLASS_NAMES_MALE)[limit] .. "|r")
|
|
)
|
|
end
|
|
function api.getRingProperty(key)
|
|
return currentRing[key]
|
|
end
|
|
function api.getRingBinding()
|
|
if PC:GetRingInfo(currentRingName) then
|
|
local skey, _, over = PC:GetRingBinding(currentRingName, 1)
|
|
if over then
|
|
return skey
|
|
end
|
|
end
|
|
if currentRing.hotkey then
|
|
return currentRing.hotkey, PC:GetOption("UseDefaultBindings", currentRingName) and "" or "|cffa0a0a0"
|
|
end
|
|
end
|
|
function api.setRingBinding(value)
|
|
if PC:GetRingInfo(currentRingName) then
|
|
config.undo:saveActiveProfile()
|
|
PC:SetRingBinding(currentRingName, 1, value)
|
|
ringDetail.binding:SetBindingText(value)
|
|
end
|
|
end
|
|
function api.setRingProperty(name, value)
|
|
if not currentRing then return end
|
|
currentRing[name] = value
|
|
if name == "limit" then
|
|
ringDetail.scope:text()
|
|
ringOrderMap[currentRingName] = value ~= nil and (value:match("[^A-Z]") and 0 or 2) or nil
|
|
elseif name == "internal" then
|
|
local source, dest = value and ringNames or ringNames.hidden, value and ringNames.hidden or ringNames
|
|
for i=1,#source do if source[i] == currentRingName then
|
|
table.remove(source, i)
|
|
break
|
|
end end
|
|
table.insert(dest, currentRingName)
|
|
elseif name == "onOpen" then
|
|
currentRing.quarantineOnOpen = nil
|
|
api.updateRingLine()
|
|
end
|
|
api.saveRing(currentRingName, currentRing)
|
|
if name == "name" then
|
|
UIDropDownMenu_SetText(ringDropDown, value or currentRingName)
|
|
end
|
|
end
|
|
function api.setSliceAction()
|
|
if currentRing and currentSliceIndex then
|
|
api.setSliceProperty("*")
|
|
end
|
|
end
|
|
function api.setSliceProperty(prop, ...)
|
|
local slice = assert(currentRing[currentSliceIndex], "Setting a slice property on an unknown slice")
|
|
if prop == "color" then
|
|
local r, g, b = ...
|
|
slice.c = r and ("%02x%02x%02x"):format(r*255, g*255, b*255) or nil
|
|
elseif prop == "*" then
|
|
if editorHost:GetAction(slice) then
|
|
api.updateSliceDisplay(currentSliceIndex, slice)
|
|
end
|
|
elseif prop == "skipSpecs" or prop == "show" then
|
|
local ss = sliceDetail.skipSpecs:GetValue()
|
|
local sh = sliceDetail.showConditional:GetText()
|
|
slice.show = (ss or sh ~= "") and ((ss and ("[spec:" .. ss .. "] hide;") or "") .. sh) or nil
|
|
elseif prop == "rotationMode" then
|
|
if ... == "default" then
|
|
slice.embed, slice.rotationMode = nil, nil
|
|
elseif ... == "embed" then
|
|
slice.embed, slice.rotationMode = true, nil
|
|
else
|
|
slice.rotationMode, slice.embed = ..., false
|
|
end
|
|
else
|
|
slice[prop] = (...)
|
|
end
|
|
api.saveRing(currentRingName, currentRing)
|
|
if prop == "icon" or prop == "color" then
|
|
local _, _, ico, icoext = getSliceInfo(currentRing[currentSliceIndex])
|
|
if prop ~= "color" then sliceDetail.icon:SetIcon(ico, slice.icon, icoext) end
|
|
sliceDetail.color:SetColor(getSliceColor(slice, ico))
|
|
end
|
|
api.updateRingLine()
|
|
end
|
|
function api.updateSliceOptions(slice)
|
|
local extraY, isCollection = 0, securecall(isCollectionSlice, slice)
|
|
local fc, cd = sliceDetail.fastClick, sliceDetail.collectionDrop
|
|
fc:SetChecked(not not slice.fastClick)
|
|
if PC:GetOption("CenterAction", currentRingName) or PC:GetOption("MotionAction", currentRingName) then
|
|
fc:SetEnabled(true)
|
|
fc.tooltipText = nil
|
|
fc.Text:SetVertexColor(1, 1, 1)
|
|
else
|
|
fc.tooltipText = (L"You must enable the %s option for this ring in OPie options to use quick actions."):format(
|
|
"|cffffffff" .. L"Quick action at ring center" .. "|r|cff909090 / |r|cffffffff" .. L"Quick action if mouse remains still" .. "|r")
|
|
fc:SetChecked(false)
|
|
fc:SetEnabled(false)
|
|
fc.Text:SetVertexColor(0.6, 0.6, 0.6)
|
|
end
|
|
cd:SetShown(isCollection)
|
|
if isCollection then
|
|
cd:SetPoint("TOPLEFT", fc, "BOTTOMLEFT", -16, 1)
|
|
extraY = 34
|
|
cd.embed, cd.rotationMode = slice.embed, slice.rotationMode
|
|
cd:text()
|
|
end
|
|
sliceDetail.editorContainer:SetVerticalOffset(extraY)
|
|
end
|
|
function api.selectSlice(offset, select)
|
|
if not select then
|
|
-- This can trigger save-on-hide logic, which in turn forces a
|
|
-- (redundant) sliceDetail update.
|
|
api.hideSliceDetail()
|
|
newSlice:Hide()
|
|
api.endSliceRepick()
|
|
currentSliceIndex = nil
|
|
ringDetail:Show()
|
|
api.updateRingLine()
|
|
return
|
|
end
|
|
ringDetail:Hide()
|
|
newSlice:Hide()
|
|
api.hideSliceDetail()
|
|
ringContainer.newSlice:SetChecked(nil)
|
|
local old, id = ringContainer.slices[(currentSliceIndex or 0) + 1 - sliceBaseIndex], sliceBaseIndex + offset
|
|
local desc = currentRing[id]
|
|
if old then old:SetChecked(nil) end
|
|
currentSliceIndex = nil
|
|
if not desc then
|
|
return ringDetail:Show()
|
|
end
|
|
api.updateSliceDisplay(id, desc)
|
|
api.endSliceRepick()
|
|
sliceDetail:Show()
|
|
currentSliceIndex = id
|
|
end
|
|
function api.updateSliceDisplay(_id, desc)
|
|
local stype, sname, sicon, icoext = getSliceInfo(desc)
|
|
if (sname or "") ~= "" and stype ~= sname then
|
|
sliceDetail.desc:SetFormattedText("%s: |cffffffff%s|r", stype or "?", sname or "?")
|
|
else
|
|
sliceDetail.desc:SetText(stype or "?")
|
|
end
|
|
local skipSpecs, showConditional = (desc.show or ""):match("^%[spec:([%d/]+)%] hide;(.*)")
|
|
sliceDetail.iconSelector:Hide()
|
|
sliceDetail.icon:SetIcon(sicon, desc.icon, icoext)
|
|
sliceDetail.color:SetColor(getSliceColor(desc, sicon))
|
|
sliceDetail.skipSpecs:SetValue(skipSpecs)
|
|
sliceDetail.showConditional:SetText(showConditional or desc.show or "")
|
|
api.updateSliceOptions(desc)
|
|
editorHost:SetAction(desc)
|
|
local canRestore, hasRestore = RK:CanRestoreSlice(currentRingName, desc)
|
|
sliceDetail.restore:SetShown(hasRestore)
|
|
sliceDetail.restore:SetEnabled(canRestore)
|
|
end
|
|
function api.moveSlice(source, dest)
|
|
if not (currentRing and currentRing[source] and currentRing[dest]) then return end
|
|
table.insert(currentRing, dest, table.remove(currentRing, source))
|
|
if currentSliceIndex == source then currentSliceIndex = dest end
|
|
api.saveRing(currentRingName, currentRing)
|
|
api.updateRingLine()
|
|
end
|
|
function api.deleteSlice(id)
|
|
if id == nil then id = currentSliceIndex end
|
|
if id and currentRing and currentRing[id] then
|
|
if id == currentSliceIndex then
|
|
api.hideSliceDetail()
|
|
currentSliceIndex = nil
|
|
ringDetail:Show()
|
|
end
|
|
table.remove(currentRing, id)
|
|
if sliceBaseIndex == id and sliceBaseIndex > 1 then
|
|
sliceBaseIndex = sliceBaseIndex - 1
|
|
end
|
|
if id == currentRing.onOpen then
|
|
currentRing.onOpen = nil
|
|
elseif currentRing.onOpen and id < currentRing.onOpen then
|
|
currentRing.onOpen = currentRing.onOpen - 1
|
|
end
|
|
api.saveRing(currentRingName, currentRing)
|
|
api.updateRingLine(true)
|
|
end
|
|
end
|
|
function api.beginSliceRepick()
|
|
repickSlice = currentRing[currentSliceIndex]
|
|
api.hideSliceDetail()
|
|
ringContainer.disableSliceDrag, newSlice.disableDrag = true, true
|
|
newSlice:Show()
|
|
end
|
|
function api.endSliceRepick()
|
|
ringContainer.disableSliceDrag, newSlice.disableDrag = nil, nil
|
|
repickSlice = nil
|
|
end
|
|
function api.finishSliceRepick()
|
|
for i=1,#currentRing do
|
|
if currentRing[i] == repickSlice then
|
|
api.endSliceRepick()
|
|
api.selectSlice(i-sliceBaseIndex, true)
|
|
api.updateRingLine()
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
function api.deleteRing()
|
|
if currentRing then
|
|
ringContainer:Hide()
|
|
config.undo:saveActiveProfile()
|
|
api.saveRing(currentRingName, false)
|
|
api.deselectRing()
|
|
end
|
|
end
|
|
function api.deselectRing()
|
|
ringContainer:Hide()
|
|
currentRing, currentRingName, ringNames = nil
|
|
UIDropDownMenu_SetText(ringDropDown, L"Select a ring to modify")
|
|
end
|
|
function api.restoreDefault()
|
|
if currentRingName then
|
|
local _, _, isDefaultAvailable, isDefaultOverriden = RK:GetRingInfo(currentRingName)
|
|
if isDefaultAvailable and isDefaultOverriden then
|
|
SaveRingVersion(currentRingName, true)
|
|
RK:RestoreDefaults(currentRingName)
|
|
end
|
|
api.selectRing(nil, currentRingName)
|
|
end
|
|
end
|
|
function api.restoreSliceDefault()
|
|
if currentRingName and currentSliceIndex then
|
|
local ns = RK:GetRestoredSlice(currentRingName, currentRing[currentSliceIndex])
|
|
if ns then
|
|
currentRing[currentSliceIndex] = ns
|
|
api.saveRing(currentRingName, currentRing)
|
|
api.updateSliceDisplay(currentSliceIndex, ns)
|
|
api.updateRingLine()
|
|
end
|
|
end
|
|
end
|
|
function api.addSlice(pos, ...)
|
|
local wasRepick
|
|
if pos == nil and repickSlice then
|
|
for k in pairs(repickSlice) do
|
|
if type(k) == "number" then
|
|
repickSlice[k] = nil
|
|
end
|
|
end
|
|
for i=1,select("#", ...),2 do
|
|
repickSlice[i], repickSlice[i+1] = select(i, ...)
|
|
end
|
|
wasRepick = true
|
|
else
|
|
pos = math.max(1, math.min(#currentRing+1, pos and (pos + sliceBaseIndex) or (#currentRing+1)))
|
|
table.insert(currentRing, pos, {sliceToken=AB:CreateToken(), ...})
|
|
sliceBaseIndex = math.min(pos, math.max(1 + pos - #ringContainer.slices, sliceBaseIndex))
|
|
end
|
|
api.saveRing(currentRingName, currentRing)
|
|
api.updateRingLine(true)
|
|
if wasRepick then
|
|
api.finishSliceRepick()
|
|
end
|
|
end
|
|
local function resolveCustomSliceAdd(ok, ...)
|
|
if ok and type((...)) == "string" and AB:GetActionDescription(...) then
|
|
api.addSlice(nil, ...)
|
|
return true
|
|
end
|
|
return false
|
|
end
|
|
function api.addCustomSlice(_editbox, text, attemptAccept)
|
|
if not attemptAccept then
|
|
return true
|
|
end
|
|
return resolveCustomSliceAdd(pcall(decodeConstantList, text, 1))
|
|
end
|
|
function api.closeActionPicker(source)
|
|
if source == "add-new-slice-button" and repickSlice then
|
|
api.endSliceRepick()
|
|
currentSliceIndex = nil
|
|
api.updateRingLine()
|
|
ringContainer.newSlice:SetChecked(true)
|
|
return
|
|
elseif repickSlice and api.finishSliceRepick() then
|
|
return
|
|
end
|
|
newSlice:Hide()
|
|
ringDetail:Show()
|
|
api.updateRingLine()
|
|
ringContainer.newSlice:SetChecked(false)
|
|
end
|
|
function api.saveRing(name, data)
|
|
SaveRingVersion(name, true)
|
|
if data ~= nil then
|
|
if type(data) == "table" then
|
|
data.save = true
|
|
end
|
|
RK:SetRing(name, data)
|
|
end
|
|
ringDetail.exportArea:Hide()
|
|
ringDetail.binding:SetEnabled(not not PC:GetRingInfo(name))
|
|
end
|
|
function api.refreshDisplay()
|
|
if currentRing and currentRing[currentSliceIndex] then
|
|
api.updateSliceOptions(currentRing[currentSliceIndex])
|
|
end
|
|
if currentRing then
|
|
ringDetail.binding:SetBindingText(api.getRingBinding())
|
|
ringDetail.binding:SetEnabled(not not PC:GetRingInfo(currentRingName))
|
|
ringDetail.exportArea:GetScript("OnHide")(ringDetail.exportArea)
|
|
local caOptionNames = "|cffffffff" .. L"Quick action at ring center" .. "|r|cff909090 / |r|cffffffff" .. L"Quick action if mouse remains still" .. "|r"
|
|
local noCA = not PC:GetOption("CenterAction", currentRingName) and (L"You must enable the %s option for this ring in OPie options to use quick actions."):format(caOptionNames) or nil
|
|
ringDetail.opportunistCA.tooltipText = noCA
|
|
ringDetail.opportunistCA:SetEnabled(not noCA)
|
|
ringDetail.opportunistCA:SetChecked(not noCA and not currentRing.noOpportunisticCA)
|
|
ringDetail.opportunistCA.Text:SetVertexColor(noCA and 0.6 or 1,noCA and 0.6 or 1,noCA and 0.6 or 1)
|
|
ringDetail.firstOnOpen:SetChecked(currentRing.onOpen == 1)
|
|
ringDetail.firstOnOpen.quarantineMark:SetShown(currentRing.quarantineOnOpen == 1)
|
|
end
|
|
end
|
|
function api.exportRing(includeNestedRings)
|
|
local input = ringDetail.exportArea
|
|
ringDetail.export:Hide()
|
|
input:Show()
|
|
input:SetText(RK:GetRingSnapshot(currentRingName, includeNestedRings))
|
|
input:SetCursorPosition(0)
|
|
input:HighlightText()
|
|
input:SetFocus()
|
|
end
|
|
function api.showExternalEditor(which)
|
|
if which == "slice-binding" then
|
|
T.ShowSliceBindingPanel(currentRingName)
|
|
elseif which == "opie-options" then
|
|
T.ShowOPieOptionsPanel(currentRingName)
|
|
end
|
|
end
|
|
|
|
ringDetail:SetScript("OnShow", function()
|
|
local _,_, isDefaultAvailable, isDefaultOverriden = RK:GetRingInfo(currentRingName)
|
|
ringDetail.restore:SetText(isDefaultAvailable and L"Restore default" or L"Undo changes")
|
|
ringDetail.restore:SetShown(isDefaultAvailable and isDefaultOverriden)
|
|
end)
|
|
|
|
local function resetView()
|
|
currentRingName, currentRing, currentSliceIndex, ringNames = nil
|
|
ringContainer:Hide()
|
|
end
|
|
function panel:refresh()
|
|
local oRingName, oBaseIndex, oSliceIndex = currentRingName, sliceBaseIndex, currentSliceIndex
|
|
local oSliceToken = currentRing and currentRing[currentSliceIndex] and currentRing[currentSliceIndex].sliceToken
|
|
currentRingName, currentRing, currentSliceIndex, ringNames = nil
|
|
ringContainer:Hide()
|
|
ringDetail:Hide()
|
|
api.hideSliceDetail()
|
|
newSlice:Hide()
|
|
if oRingName and RK:GetRingInfo(oRingName) then
|
|
api.selectRing(nil, oRingName)
|
|
for i=1, oSliceToken and type(currentRing) == "table" and #currentRing or 0 do
|
|
local s = currentRing[i]
|
|
if s and s.sliceToken == oSliceToken then
|
|
api.selectSlice(i-sliceBaseIndex, true)
|
|
break
|
|
end
|
|
end
|
|
local cbi = currentSliceIndex and (currentSliceIndex - oSliceIndex + oBaseIndex) or oBaseIndex
|
|
if currentRing and cbi > 0 and cbi < #currentRing and cbi ~= sliceBaseIndex then
|
|
sliceBaseIndex = cbi
|
|
api.updateRingLine()
|
|
end
|
|
end
|
|
if not currentRing then
|
|
UIDropDownMenu_SetText(ringDropDown, L"Select a ring to modify")
|
|
end
|
|
end
|
|
function panel:default()
|
|
for key in RK:GetManagedRings() do
|
|
local _, _, isDefault, isOverriden = RK:GetRingInfo(key)
|
|
if isDefault and isOverriden then
|
|
SaveRingVersion(key, true)
|
|
end
|
|
end
|
|
for key in RK:GetDeletedRings() do
|
|
SaveRingVersion(key, false)
|
|
end
|
|
RK:RestoreDefaults()
|
|
panel:refresh()
|
|
end
|
|
function panel:okay()
|
|
ringContainer:Hide()
|
|
resetView()
|
|
end
|
|
panel.cancel = resetView
|
|
panel:SetScript("OnShow", config.checkSVState)
|
|
|
|
SLASH_OPIE_CUSTOM_RINGS1 = "/rk"
|
|
function SlashCmdList.OPIE_CUSTOM_RINGS()
|
|
panel:OpenPanel()
|
|
end
|
|
T.AddSlashSuffix(SlashCmdList.OPIE_CUSTOM_RINGS, "custom", "rings")
|