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.

621 lines
22 KiB

local _,L = ...
local rematch = Rematch
local panel = RematchTeamTabs
local dialog, iconPicker, settings, saved
--[[ Team tabs are defined in settings.TeamGroups as an ordered table (tab#=table index)
Within each index of TeamGroups is a table of the following:
[1] = Name of the tab
[2] = Icon of the tab
[3] = An ordered table of keys if the tab is custom sorted, nil if not custom sorted
[4] = A table of leveling preferences if the tab has any, nil otherwise
[5] = True if the tab is to be sorted by win record
]]
local MAX_DISPLAYED_TABS = 14 -- number of team tabs that can be dispayed at once
panel.MAX_TABS = 32 -- number of team tabs possible
panel.isScrolling = nil -- true while there are more tabs than can be displayed and the tabs are scrollable
-- this table describes the {yoffset,scale} to nudge the tabs to make room for more.
-- the index is the number of tabs to display (not including the + New Tabs button)
-- a nil yoffset means to center it to the side of the parent
local tabNudges = {[11]={-64,1},[12]={-28,1},[13]={nil,0.95},[14]={nil,0.9},[15]={nil,0.85},[16]={nil,0.85}}
rematch:InitModule(function()
rematch.TeamTabs = panel
settings = RematchSettings
saved = RematchSaved
dialog = RematchDialog
iconPicker = dialog.TeamTabIconPicker
panel.Tabs = {} -- where the tab buttons will go
local function isFirstTab(self,index) return index==1 end
rematch:RegisterMenu("TabMenu", { -- menu for Tab buttons
{ title=true, text=function(self,index) return settings.TeamGroups[index][1] end, },
{ text=L["Edit Tab"], func=panel.ShowTabEditDialog, tooltipBody=L["Change the name or icon of this tab."] },
{ text=L["Custom Sort"], check=true,
value=function(entry,index)
return settings.TeamGroups[index] and settings.TeamGroups[index][3] and true
end,
func=function(entry,index)
local tab = settings.TeamGroups[index]
if not tab then return end
if tab[3] then
local dialog = rematch:ShowDialog("DeleteCustomSort",300,172,L["Remove Custom Sort"],nil,YES,function() tab[3]=nil rematch:UpdateUI() end,NO)
dialog:ShowText(L["Are you sure you want to remove the custom sort order?\n\nThe saved order of teams will be lost and turning this option back on will not restore the old order."],240,96,"TOP",0,-32)
else
tab[3] = {}
end
rematch:HideMenu()
rematch:UpdateUI()
end,
tooltipBody=L["While checked, you can rearrange the order of teams within this tab from the teams' right-click menu."] },
{ text=L["Sort By Wins"], check=true,
disabled=function(entry,index) return settings.TeamGroups[index][3] and true end,
disabledReason=L["This option is disabled while Custom Sort is active."],
value=function(entry,index) return settings.TeamGroups[index][5] end,
func=function(entry,index)
local tab = settings.TeamGroups[index]
tab[5] = not tab[5]
rematch:UpdateUI()
end,
tooltipBody=L["Sort teams in this tab by their wins.\n\nFavorited teams will still list at the top."]
},
{ text=L["Leveling Preferences"], func=function(entry,index) rematch:ShowPreferencesDialog("tab",index) end, tooltipBody=L["Set leveling preferences for all teams within this tab.\n\nIf a team within this tab also has preferences, the tab's preferences will take priority over the team's preferences."] },
{ text=L["Export Tab"], func=function() Rematch.Dialog.Share:ExportTeamTab() end, tooltipBody=L["Export all teams in this tab to a string you can copy elsewhere, such as forums or emails.\n\nOther Rematch users can then paste these teams into their Rematch via Import Teams.\n\nYou can export a single team by right-clicking one and choosing its Share menu."] },
{ text=L["Import Teams"], func=rematch.ShowImportDialog, tooltipBody=L["Import a single team or many teams that were exported from Rematch."] },
{ text=L["Delete Tab"], hidden=isFirstTab, func=panel.ShowTabDeleteDialog, tooltipBody=L["Delete this tab and either move all of its teams to the default tab or delete the teams too."] },
{ text=L["Delete Teams"], hidden=function(self,index) return index~=1 end, func=panel.ShowDeleteFirstTabDialog, tooltipBody=L["Permanently delete all teams in this tab."] },
{ text=L["Move Up"], hidden=isFirstTab, icon="Interface\\Buttons\\UI-MicroStream-Yellow", iconCoords={0.075,0.925,0.925,0.075}, stay=true,
disabled=function(entry,index) return index==2 end,
func=function(entry,index) panel:SwapTabs(index,index-1) end },
{ text=L["Move Down"], hidden=isFirstTab, icon="Interface\\Buttons\\UI-MicroStream-Yellow", stay=true,
disabled=function(entry,index) return index==#settings.TeamGroups end,
func=function(entry,index) panel:SwapTabs(index,index+1) end },
{ text=OKAY },
})
-- the offset (in increments of 44px) of the scrollframe
panel.scrollOffset = 0
end)
-- returns the selected team tab (and assigns it to first tab if anything weird happened)
function panel:GetSelectedTab()
local selected = settings.SelectedTab
if not selected or not settings.TeamGroups[selected] then
settings.SelectedTab = 1
return 1
else
return selected
end
end
function panel:Update()
panel:GetSelectedTab() -- changes settings.SelectedTab to 1 if selected tab doesn't eixt
for index=1,panel.MAX_TABS do
panel:TabButtonUpdate(index)
end
local maxHeight = MAX_DISPLAYED_TABS * 44
local height = min(maxHeight,min(panel.MAX_TABS,#settings.TeamGroups+1)*44)
panel:SetHeight(height)
-- anchor/rescale the parent TeamTabs frame depending on number of tabs to show
local numTabs = #settings.TeamGroups
local yoffset, scale = -92, 1 -- default to -92 from top of parent, 1.0 scale
local parent = panel:GetParent()
-- local tabNudges = {[11]={-64,1},[12]={-28,1},[13]={nil,0.95},[14]={nil,0.9},[15]={nil,0.85},[16]={nil,0.85}}
if numTabs<11 then
yoffset, scale = -92, 1
elseif numTabs==11 then
yoffset, scale = -64, 1
elseif numTabs==12 then
yoffset, scale = -28, 1
elseif numTabs==13 then
yoffset, scale = nil, 0.95
else -- for 14 or more tabs
yoffset, scale = nil, 0.85
end
panel:ClearAllPoints()
if yoffset then
if settings.TeamTabsToLeft and settings.AlwaysTeamTabs and parent==rematch.Frame then
panel:SetPoint("TOPRIGHT",parent,"TOPLEFT",-1,yoffset) -- tabs anchored to topleft
else
panel:SetPoint("TOPLEFT",parent,"TOPRIGHT",-1,yoffset) -- tabs anchored to topright
end
else
if settings.TeamTabsToLeft and settings.AlwaysTeamTabs and parent==rematch.Frame then
panel:SetPoint("RIGHT",parent,"LEFT",-1,0) -- tabs anchored to left center
else
panel:SetPoint("LEFT",parent,"RIGHT",-1,0) -- tabs anchored to right center
end
end
panel:SetScale(scale)
panel:UpdateScroll() -- updates state of scroll buttons and the scrollframe
end
function panel:SelectTeamTab(index)
rematch.TeamPanel:SetTeamSearch(nil)
settings.SelectedTab = index or 1
panel:Update()
if not rematch.TeamPanel:IsVisible() and not rematch:IsDialogOpen("SaveAs") and not rematch:IsDialogOpen("ImportDialog") and not rematch:IsDialogOpen("ReceiveDialog") then
rematch:ShowTeam() -- if teams not shown then switch to panel
else
rematch.TeamPanel:Update() -- if not visible but shouldn't be, this Update will be ignored in the function
end
panel:ScrollToTab(settings.SelectedTab)
if rematch.TeamPanel:IsVisible() then
rematch.TeamPanel.List:ScrollToIndex(1)
end
rematch.Dialog:UpdateTabPicker()
end
function panel:TabOnClick(button)
rematch:HideMenu()
local index = self:GetID()
local groups = settings.TeamGroups
if button=="RightButton" then
if index<=#groups then
rematch:SetMenuSubject(index)
panel:SelectTeamTab(index)
rematch:ShowMenu("TabMenu","cursor")
end
return
end
if index>0 and index<=#groups then
panel:SelectTeamTab(index)
else
if index>#groups then
panel:ShowTabEditDialog(index)
end
end
end
function panel:TabButtonOnEnter()
local index = self:GetID()
if index==0 then
rematch.ShowTooltip(self,self==panel.UpButton and L["Previous Tabs"] or L["Next Tabs"])
elseif index>#settings.TeamGroups then
rematch.ShowTooltip(self,L["Create New Tab"])
else
local numTeams = 0
for k,v in pairs(saved) do
if (v.tab or 1)==index then
numTeams = numTeams + 1
end
end
local info = rematch.info
wipe(info)
tinsert(info,settings.TeamGroups[index][1])
tinsert(info,format(L["Teams: %d"],numTeams))
if settings.TeamGroups[index][4] then
tinsert(info,"")
rematch.ShowPreferencesTooltip(self,"tab",index,nil,info)
else
rematch:ShowTableTooltip(self,info)
end
end
end
function panel:ShowTabEditDialog(index)
local groups = settings.TeamGroups
local name, icon
if index>#groups then
name = L["New Tab"]
icon = "Interface\\Icons\\PetJournalPortrait"
else
name = groups[index][1]
icon = groups[index][2]
end
rematch:ShowDialog("TabEdit",390,456,name or L["New Tab"],L["Choose a name and icon"],SAVE,panel.IconPickerSave,CANCEL)
dialog:SetContext("tab",index)
dialog:SetContext("name",name)
dialog:SetContext("icon",icon)
dialog.EditBox:SetPoint("TOP",22,-40)
dialog.EditBox:SetWidth(180)
dialog.EditBox:Show()
dialog.EditBox:SetText(name)
dialog.Slot:SetPoint("RIGHT",dialog.EditBox,"LEFT",-8,0)
dialog.Slot:Show()
dialog.Slot.Icon:SetTexture(icon)
iconPicker:SetPoint("TOP",0,-80)
if not iconPicker.ScrollFrame.buttons then
-- scrollframe hasn't been set up yet
local scrollFrame = iconPicker.ScrollFrame
scrollFrame.update = panel.UpdateTabIconPickerList
scrollFrame.ScrollBar.doNotHide = true
scrollFrame.stepSize = 270
HybridScrollFrame_CreateButtons(scrollFrame,"RematchTeamTabPickerListTemplate")
end
-- set up icon choices (recreating table each time on purpose; don't want to keep these huge tables)
local iconChoices = dialog:SetContext("iconChoices",{})
tinsert(iconChoices,"Interface\\Icons\\PetJournalPortrait")
panel:AddMoreIcons(iconChoices) -- add icons from bags, inventory, etc
-- GetLooseMacroIcons(iconChoices)
GetMacroIcons(iconChoices)
GetMacroItemIcons(iconChoices)
panel:UpdateTabIconPickerList()
iconPicker:Show()
end
-- when save clicked on IconPicker
function panel:IconPickerSave()
local groups = settings.TeamGroups
local index = dialog:GetContext("tab")
local scrollDown = not groups[index] -- whether to scroll down after adding the tab (if group doesn't exist, it's a new tab)
groups[index] = groups[index] or {}
groups[index][1] = dialog.EditBox:GetText() or ""
groups[index][2] = dialog:GetContext("icon")
panel:SelectTeamTab(index)
if scrollDown then
panel:ScrollTabs(-1)
end
end
-- update of icon list in iconpicker
function panel:UpdateTabIconPickerList()
-- data points to searchChoices if a search is used, or iconChoices (all icons) otherwise
local data = dialog:GetContext("iconChoices")
if not data then return end
local numData = ceil(#data/10)
local scrollFrame = iconPicker.ScrollFrame
local offset = HybridScrollFrame_GetOffset(scrollFrame)
local buttons = scrollFrame.buttons
local selectedIcon = dialog:GetContext("icon")
for i=1,#buttons do
local index = i + offset
local button = buttons[i]
if ( index <= numData) then
for j=1,10 do
local subbutton = button.Icons[j]
local iconID = data[(index-1)*10+j]
subbutton.iconID = iconID
if iconID then
subbutton.Texture:SetTexture(iconID)
subbutton.Selected:SetShown(iconID==selectedIcon)
subbutton:Show()
else
subbutton:Hide()
end
end
button:Show()
else
button:Hide()
end
end
HybridScrollFrame_Update(scrollFrame,30*numData,30)
end
function panel:IconOnClick()
local iconID = self.iconID
if iconID then
dialog:SetContext("icon",iconID)
dialog.Slot.Icon:SetTexture(iconID)
panel:UpdateTabIconPickerList()
end
end
--[[ Delete ]]
-- (for now) the first team tab can't be deleted, so it has its own dialog to delete teams within the team
function panel:ShowDeleteFirstTabDialog()
rematch:ShowDialog("TabDeleteFirst",300,150,L["Delete Teams?"],L["Delete ALL teams in the first tab?"],YES,
function()
for key,team in pairs(saved) do
if not team.tab or team.tab==1 then
saved[key] = nil
end
end
rematch:UpdateUI()
end,NO)
dialog:ShowText(format(L["%sWARNING!\124r This will %sPERMANENTLY DELETE\124r all teams in this tab!"],rematch.hexRed,rematch.hexWhite),180,40,"TOP",0,-40)
end
-- non-default tabs get a "Delete Tab" option instead with an option to delete teams too
function panel:ShowTabDeleteDialog(index)
local groups = settings.TeamGroups
rematch:ShowDialog("TabDelete",300,192,groups[index][1],L["Delete this tab?"],YES,panel.ConfirmDeleteTab,NO)
dialog:SetContext("tab",index)
dialog:ShowText(format(L["Deleting this tab will move its teams to the %s tab."],groups[1][1]),180,40,"TOP",22,-40)
dialog.Slot:SetPoint("RIGHT",dialog.Text,"LEFT",-8,0)
dialog.Slot:Show()
dialog.Slot.Icon:SetTexture(groups[index][2])
dialog.CheckButton:SetPoint("BOTTOMLEFT",32,70)
dialog.CheckButton.text:SetText(L["Delete teams within the tab too"])
dialog.CheckButton:SetChecked(false)
dialog.CheckButton:Show()
dialog.CheckButton:SetScript("OnClick",panel.DeleteTeamsOnClick)
end
function panel:DeleteTeamsOnClick()
local deleteTeams = self:GetChecked() and true
local groups = settings.TeamGroups
dialog:SetContext("TabDeleteTeamsToo",deleteTeams)
dialog.Text:SetText(deleteTeams and format(L["%sWARNING!\124r This will %sPERMANENTLY DELETE\124r all teams in this tab!"],rematch.hexRed,rematch.hexWhite) or format(L["Deleting this tab will move its teams to the %s tab."],groups[1][1]))
end
function panel:ConfirmDeleteTab()
local index = dialog:GetContext("tab")
if index and index>1 then
-- if checkbutton "Delete teams within this tab too" is checked, remove teams
if dialog:GetContext("TabDeleteTeamsToo") then
for key,team in pairs(saved) do
if team.tab==index then
saved[key] = nil
end
end
end
-- move any teams that belong to this tab to the general tab
-- (and move any beyond this tab to the prior tab)
for _,team in pairs(saved) do
if team.tab==index then
team.tab = nil -- remove .tab from teams belonging to this tab (move them to general)
elseif team.tab and team.tab>index then
team.tab = team.tab-1 -- move teams in tabs beyond deleted one to one previous
end
end
tremove(settings.TeamGroups,index) -- and delete the tab
panel:SelectTeamTab(1) -- go to first tab (this will update tabs and team panel)
end
end
-- swaps two tabs (index 2 to #groups) for moving tabs up/down
function panel:SwapTabs(index1,index2)
local groups = settings.TeamGroups
if index1==1 or index2==1 or index1>#groups or index2>#groups then
return -- don't swap first tab! (or beyond last tab)
end
for teamName,teamData in pairs(saved) do
local teamTab = teamData.tab
if teamTab==index1 then
teamData.tab = index2
elseif teamTab==index2 then
teamData.tab = index1
end
end
-- swap the contents of groups[index1] and groups[index2]
for i=1,5 do
local old = groups[index1][i]
groups[index1][i] = groups[index2][i]
groups[index2][i] = old
end
rematch:SetMenuSubject(index2) -- change menu subject to destination tab
panel:SelectTeamTab(index2)
end
function panel:Configure(parent)
panel:SetParent(parent)
-- there used to be a lot more here (to reanchor tabs) that's now handled in the Update
panel:Show()
end
-- adds more icons to iconChoices (since default has only like 3.8k out of 15k icons)
function panel:AddMoreIcons(iconChoices)
local function add(icon)
if icon and not tContains(iconChoices,icon) then
tinsert(iconChoices,icon)
end
end
-- add icons from items in bags
for i=0,4 do
for j=1,GetContainerNumSlots(i) do
add(GetContainerItemInfo(i,j))
end
end
-- add icons from worn gear
for i=1,19 do
add(GetInventoryItemTexture("player",i))
end
-- add all pet icons
for speciesID in rematch.Roster:AllSpecies() do
add(rematch:GetPetIcon(speciesID))
end
end
-- returns the tab index that a team key belongs to
function rematch:GetTabFromTeam(key)
if saved[key] then
return saved[key].tab or 1
end
end
-- locks highlights on a specific tab (or unlocks highlight of all tabs if tab is nil)
function rematch:HighlightTeamTab(tab)
local searching = rematch.TeamPanel:GetTeamSearchInfo()
for i=1,panel.MAX_TABS do
if panel.Tabs[i] then
if i==tab and searching then
panel.Tabs[i]:LockHighlight()
else
panel.Tabs[i]:UnlockHighlight()
end
end
end
end
function panel:TabButtonOnMouseDown()
if self:IsEnabled() then
self.Icon:SetSize(28,28)
self.Icon:SetVertexColor(0.75,0.75,0.75)
end
end
function panel:TabButtonOnMouseUp()
self.Icon:SetSize(30,30)
self.Icon:SetVertexColor(1,1,1)
end
-- returns a tab button by its index (and creates if it hasn't been made yet)
function panel:GetTabButton(index)
if not panel.Tabs[index] then
panel.Tabs[index] = CreateFrame("Button",nil,panel.Layout,"RematchTeamTabTemplate")
panel.Tabs[index]:RegisterForClicks("AnyUp")
panel.Tabs[index]:SetID(index)
panel.Tabs[index]:SetPoint("TOPLEFT",0,(index-1)*-44)
end
return panel.Tabs[index]
end
function panel:TabButtonUpdate(index)
local selected = panel:GetSelectedTab()
local numGroups = #settings.TeamGroups
local searchText,searchTabs = rematch.TeamPanel:GetTeamSearchInfo()
-- texcoords and icon anchoring is flipped when button goes to left
local left,right,centerSelected,centerUnselected = 0,0.6875,1,-5
if settings.TeamTabsToLeft and settings.AlwaysTeamTabs and panel:GetParent()==rematch.Frame then
left,right,centerSelected,centerUnselected = 0.6875,0,-1,5
end
if index>0 and index<=numGroups then
local button = panel:GetTabButton(index)
if index==selected and not searchText then
button.Background:SetTexCoord(left,right,0,0.34375)
button.Icon:SetPoint("CENTER",centerSelected,2)
else
button.Background:SetTexCoord(left,right,0.5,0.84375)
button.Icon:SetPoint("CENTER",centerUnselected,2)
end
local desat = searchText and not searchTabs[index]
button.Icon:SetDesaturated(desat)
button.Custom:SetDesaturated(desat)
button.Preferences:SetDesaturated(desat)
if searchText and not searchTabs[index] then
button.Icon:SetVertexColor(0.4,0.4,0.4)
else
button.Icon:SetVertexColor(1,1,1)
end
local group = settings.TeamGroups[index]
button.Icon:SetTexture(group[2])
button.Custom:SetShown(group[3] and true)
button.Preferences:SetShown(group[4] and true)
button:Show()
elseif index==(numGroups+1) and index<=panel.MAX_TABS then
local button = panel:GetTabButton(index)
button.Background:SetTexCoord(left,right,0.5,0.84375)
button.Icon:SetPoint("CENTER",centerUnselected,2)
button.Icon:SetTexture("Interface\\GuildBankFrame\\UI-GuildBankFrame-NewTab")
button.Custom:Hide()
button.Preferences:Hide()
button:Show()
elseif panel.Tabs[index] then
panel.Tabs[index]:Hide()
end
end
function panel:UpdateScroll()
if #settings.TeamGroups < MAX_DISPLAYED_TABS then
panel:SetVerticalScroll(0)
panel.UpButton:Hide()
panel.DownButton:Hide()
panel.isScrolling = nil
return
end
local left,right,center = 0,0.6875,-5
if settings.TeamTabsToLeft and settings.AlwaysTeamTabs and panel:GetParent()==rematch.Frame then
left,right,center = 0.6875,0,5
end
panel.UpButton.Background:SetTexCoord(left,right,0.5,0.84375)
panel.UpButton.Icon:SetPoint("CENTER",center,2)
panel.DownButton.Background:SetTexCoord(left,right,0.5,0.84375)
panel.DownButton.Icon:SetPoint("CENTER",center,2)
panel.UpButton.Icon:SetTexture("Interface\\Icons\\misc_arrowlup.blp")
panel.DownButton.Icon:SetTexture("Interface\\Icons\\misc_arrowdown.blp")
panel.UpButton:Show()
panel.DownButton:Show()
panel.isScrolling = true
panel:ScrollTabs()
end
-- this will scroll tabs up (direction>0), down (direction<0) or just update (direction==0)
-- and also call UpdateUpDownButtons afterwards
function panel:ScrollTabs(direction)
local delta
if not direction then -- if no direction given, just update scroll
delta = 0
elseif direction<0 then -- scrolling down
delta = 44 * (MAX_DISPLAYED_TABS-1)
else -- scrolling up
delta = -44 * (MAX_DISPLAYED_TABS-1)
end
local offset = panel.scrollOffset + delta
offset = max(0,offset)
local numTabs = #settings.TeamGroups
-- if we're not even supposed to be scrolling, offset is 0
local maxOffset
if numTabs < MAX_DISPLAYED_TABS then
offset = 0
else
-- if we've not reached the maximum possible team tabs, then add one more
-- tab for the "New Tab" tab
if numTabs < panel.MAX_TABS then
numTabs = numTabs + 1
end
maxOffset = (numTabs)*44 - (MAX_DISPLAYED_TABS)*44
-- constrain offset to scrolldown as far as the last tab
offset = min(offset,maxOffset)
end
-- and finally scroll there
panel.scrollOffset = offset
panel:SetVerticalScroll(offset)
-- enable/disable up/down buttons if at top/bottom of scroll
local atTop = offset==0
panel.UpButton.Icon:SetDesaturated(atTop)
panel.UpButton.Icon:SetAlpha(atTop and 0.65 or 1)
panel.UpButton:SetEnabled(not atTop)
local atBottom = offset==maxOffset
panel.DownButton.Icon:SetDesaturated(atBottom)
panel.DownButton.Icon:SetAlpha(atBottom and 0.65 or 1)
panel.DownButton:SetEnabled(not atBottom)
end
-- this will move the tab index as close as possible to the middle of the scrollframe
function panel:ScrollToTab(index)
if not panel.isScrolling then -- if not scrolling, always at the top
panel.scrollOffset = 0
else -- otherwise try to position index to middle of displayed tabs
-- if position is beyond range, it's okay; ScrollTabs will constrain it
-- (rounding to whole number since division involved)
panel.scrollOffset = floor((index*44-(MAX_DISPLAYED_TABS*44)/2)+0.5)
end
-- and do an update
panel:ScrollTabs()
end
-- this will scroll to the tab of the loaded team
function panel:ScrollToTeamTab(key)
key = key or settings.loadedTeam -- if no key given, scroll to loaded team's tab
if key and saved[key] then
panel:ScrollToTab(saved[key].tab or 1)
end
end