------------------------------------------------------- ----------Constants ------------------------------------------------------- MAX_LFG_LIST_APPLICATIONS = 5; MAX_LFG_LIST_SEARCH_AUTOCOMPLETE_ENTRIES = 6; MAX_LFG_LIST_GROUP_DROPDOWN_ENTRIES = 10; LFG_LIST_DELISTED_FONT_COLOR = {r=0.3, g=0.3, b=0.3}; LFG_LIST_COMMENT_FONT_COLOR = {r=0.6, g=0.6, b=0.6}; ACTIVITY_RETURN_VALUES = { fullName = 1, shortName = 2, categoryID = 3, groupID = 4, itemLevel = 5, filters = 6, minLevel = 7, maxPlayers = 8, displayType = 9, orderIndex = 10, useHonorLevel = 11, }; --Hard-coded values. Should probably make these part of the DB, but it gets a little more complicated with the per-expansion textures LFG_LIST_CATEGORY_TEXTURES = { [1] = "questing", [2] = "dungeons", [3] = "raids", --Prefix for expansion [4] = "arenas", [5] = "scenarios", [6] = "custom", -- Prefix for "-pve" or "-pvp" [7] = "skirmishes", [8] = "battlegrounds", [9] = "ratedbgs", [10] = "ashran", }; LFG_LIST_PER_EXPANSION_TEXTURES = { [0] = "classic", [1] = "bc", [2] = "wrath", [3] = "cataclysm", [4] = "mists", [5] = "warlords", [6] = "legion", } LFG_LIST_GROUP_DATA_ATLASES = { --Roles TANK = "groupfinder-icon-role-large-tank", HEALER = "groupfinder-icon-role-large-heal", DAMAGER = "groupfinder-icon-role-large-dps", }; --Fill out classes for i=1, #CLASS_SORT_ORDER do LFG_LIST_GROUP_DATA_ATLASES[CLASS_SORT_ORDER[i]] = "groupfinder-icon-class-"..string.lower(CLASS_SORT_ORDER[i]); end LFG_LIST_GROUP_DATA_ROLE_ORDER = { "TANK", "HEALER", "DAMAGER" }; LFG_LIST_GROUP_DATA_CLASS_ORDER = CLASS_SORT_ORDER; StaticPopupDialogs["LFG_LIST_INVITING_CONVERT_TO_RAID"] = { text = LFG_LIST_CONVERT_TO_RAID_WARNING, button1 = INVITE, button2 = CANCEL, OnAccept = function(self, applicantID) ConvertToRaid(); C_LFGList.InviteApplicant(applicantID) end, timeout = 0, whileDead = 1, hideOnEscape = 1, } ------------------------------------------------------- ----------Base Frame ------------------------------------------------------- LFG_LIST_EDIT_BOX_TAB_CATEGORIES = {}; function LFGListFrame_OnLoad(self) self:RegisterEvent("PARTY_LEADER_CHANGED"); self:RegisterEvent("GROUP_ROSTER_UPDATE"); self:RegisterEvent("PLAYER_SPECIALIZATION_CHANGED"); self:RegisterEvent("PLAYER_ROLES_ASSIGNED"); self:RegisterEvent("LFG_LIST_AVAILABILITY_UPDATE"); self:RegisterEvent("LFG_LIST_ACTIVE_ENTRY_UPDATE"); self:RegisterEvent("LFG_LIST_ENTRY_CREATION_FAILED"); self:RegisterEvent("LFG_LIST_SEARCH_RESULTS_RECEIVED"); self:RegisterEvent("LFG_LIST_SEARCH_RESULT_UPDATED"); self:RegisterEvent("LFG_LIST_SEARCH_FAILED"); self:RegisterEvent("LFG_LIST_APPLICANT_LIST_UPDATED"); self:RegisterEvent("LFG_LIST_APPLICANT_UPDATED"); self:RegisterEvent("LFG_LIST_ENTRY_EXPIRED_TOO_MANY_PLAYERS"); self:RegisterEvent("LFG_LIST_ENTRY_EXPIRED_TIMEOUT"); self:RegisterEvent("LFG_LIST_APPLICATION_STATUS_UPDATED"); self:RegisterEvent("VARIABLES_LOADED"); self:RegisterEvent("ADDON_LOADED"); self:RegisterEvent("UNIT_CONNECTION"); for i=1, #LFG_LIST_ACTIVE_QUEUE_MESSAGE_EVENTS do self:RegisterEvent(LFG_LIST_ACTIVE_QUEUE_MESSAGE_EVENTS[i]); end LFGListFrame_SetBaseFilters(self, LE_LFG_LIST_FILTER_PVE); LFGListFrame_SetActivePanel(self, self.NothingAvailable); self.EventsInBackground = { LFG_LIST_SEARCH_FAILED = { self.SearchPanel }; }; end function LFGListFrame_OnEvent(self, event, ...) if ( event == "LFG_LIST_AVAILABILITY_UPDATE" ) then LFGListFrame_FixPanelValid(self); elseif ( event == "LFG_LIST_ACTIVE_ENTRY_UPDATE" ) then local createdNew = ...; LFGListFrame_FixPanelValid(self); --If our current panel isn't valid, change it. if ( C_LFGList.GetActiveEntryInfo() ) then self.EntryCreation.WorkingCover:Hide(); end if ( createdNew ) then PlaySound("PVPEnterQueue"); end elseif ( event == "LFG_LIST_ENTRY_CREATION_FAILED" ) then self.EntryCreation.WorkingCover:Hide(); elseif ( event == "LFG_LIST_APPLICANT_LIST_UPDATED" ) then local hasNewPending, hasNewPendingWithData = ...; if ( hasNewPending and hasNewPendingWithData and LFGListUtil_IsEntryEmpowered() ) then local isLeader = UnitIsGroupLeader("player", LE_PARTY_CATEGORY_HOME); local autoAccept = select(9, C_LFGList.GetActiveEntryInfo()); local numPings = nil; if ( not isLeader ) then numPings = 6; end --Non-leaders don't get another ping until they open the panel or we reset the count to 0 if ( isLeader or not self.stopAssistPings ) then if ( autoAccept ) then --Check if we would be auto-inviting more people if we were in a raid if ( not IsInRaid(LE_PARTY_CATEGORY_HOME) and GetNumGroupMembers(LE_PARTY_CATEGORY_HOME) + C_LFGList.GetNumInvitedApplicantMembers() + C_LFGList.GetNumPendingApplicantMembers() > (MAX_PARTY_MEMBERS+1) ) then if ( self.displayedAutoAcceptConvert ) then QueueStatusMinimapButton_SetGlowLock(QueueStatusMinimapButton, "lfglist-applicant", true, numPings); self.stopAssistPings = true; else self.displayedAutoAcceptConvert = true; StaticPopup_Show("LFG_LIST_AUTO_ACCEPT_CONVERT_TO_RAID"); end end elseif ( not self:IsVisible() ) then QueueStatusMinimapButton_SetGlowLock(QueueStatusMinimapButton, "lfglist-applicant", true, numPings); self.stopAssistPings = true; end end end elseif ( event == "LFG_LIST_APPLICANT_UPDATED" ) then local numApps, numActiveApps = C_LFGList.GetNumApplicants(); if ( numActiveApps == 0 ) then QueueStatusMinimapButton_SetGlowLock(QueueStatusMinimapButton, "lfglist-applicant", false); self.stopAssistPings = false; end elseif ( event == "LFG_LIST_ENTRY_EXPIRED_TOO_MANY_PLAYERS" ) then if ( UnitIsGroupLeader("player", LE_PARTY_CATEGORY_HOME) ) then StaticPopup_Show("LFG_LIST_ENTRY_EXPIRED_TOO_MANY_PLAYERS"); end elseif ( event == "LFG_LIST_ENTRY_EXPIRED_TIMEOUT" ) then if ( UnitIsGroupLeader("player", LE_PARTY_CATEGORY_HOME) ) then StaticPopup_Show("LFG_LIST_ENTRY_EXPIRED_TIMEOUT"); end elseif ( event == "LFG_LIST_APPLICATION_STATUS_UPDATED" ) then local id, newStatus, oldStatus = ...; if ( newStatus == "declined" ) then local info = ChatTypeInfo["SYSTEM"]; local id, activity, name = C_LFGList.GetSearchResultInfo(id); DEFAULT_CHAT_FRAME:AddMessage(string.format(LFG_LIST_APP_DECLINED_MESSAGE, name), info.r, info.g, info.b); elseif ( newStatus == "timedout" ) then local info = ChatTypeInfo["SYSTEM"]; local id, activity, name = C_LFGList.GetSearchResultInfo(id); DEFAULT_CHAT_FRAME:AddMessage(string.format(LFG_LIST_APP_TIMED_OUT_MESSAGE, name), info.r, info.g, info.b); end elseif ( event == "VARIABLES_LOADED" or event == "ADDON_LOADED" ) then if ( not GetCVarBitfield("closedInfoFrames", LE_FRAME_TUTORIAL_LFG_LIST) and UnitLevel("player") >= 90 ) then PremadeGroupsPvETutorialAlert:Show(); if ( PremadeGroupsPvPTutorialAlert ) then PremadeGroupsPvPTutorialAlert:Show(); end end elseif ( event == "GROUP_ROSTER_UPDATE" ) then if ( not IsInGroup(LE_PARTY_CATEGORY_HOME) ) then self.displayedAutoAcceptConvert = false; end end --Dispatch the event to our currently active panel local onEvent = self.activePanel and self.activePanel:GetScript("OnEvent"); if ( onEvent ) then onEvent(self.activePanel, event, ...); end --Dispatch the event to any panels that want the event in the background local bg = self.EventsInBackground[event]; if ( bg ) then for i=1, #bg do if ( bg[i] ~= self.activePanel ) then bg[i]:GetScript("OnEvent")(bg[i], event, ...); end end end end function LFGListFrame_OnShow(self) LFGListFrame_FixPanelValid(self); C_LFGList.RequestAvailableActivities(); self.stopAssistPings = false; QueueStatusMinimapButton_SetGlowLock(QueueStatusMinimapButton, "lfglist-applicant", false); PlaySound("igCharacterInfoOpen"); end function LFGListFrame_SetActivePanel(self, panel) if ( self.activePanel ) then self.activePanel:Hide(); end self.activePanel = panel; self.activePanel:Show(); end function LFGListFrame_IsPanelValid(self, panel) local listed = C_LFGList.GetActiveEntryInfo(); --If we're listed, make sure we're either viewing applicants or editing our group if ( listed and panel ~= self.ApplicationViewer and not (panel == self.EntryCreation and LFGListEntryCreation_IsEditMode(self.EntryCreation)) ) then return false; end --If we're not listed, we can't be viewing applicants or editing our group if ( not listed and (panel == self.ApplicationViewer or (panel == self.EntryCreation and LFGListEntryCreation_IsEditMode(self.EntryCreation)) ) ) then return false; end --Make sure we aren't creating a new entry with different baseFilters if ( panel == self.EntryCreation ) then if ( not LFGListEntryCreation_IsEditMode(self.EntryCreation) and self.baseFilters ~= self.EntryCreation.baseFilters ) then return false; end end --Make sure we aren't searching with different baseFilters if ( panel == self.SearchPanel ) then if ( self.baseFilters ~= self.SearchPanel.preferredFilters ) then return false; end end --If we're a trial account, we can only see the NothingAvailable and ApplicationViewer if ( IsRestrictedAccount() ) then if ( panel ~= self.NothingAvailable and panel ~= self.ApplicationViewer ) then return false; end end --If we don't have any available activities, say so if ( #C_LFGList.GetAvailableCategories(self.baseFilters) == 0 ) then if ( panel == self.CategorySelection ) then return false; end else if ( panel == self.NothingAvailable and not IsRestrictedAccount() ) then return false; end end return true; end function LFGListFrame_GetBestPanel(self) local listed = C_LFGList.GetActiveEntryInfo(); if ( listed ) then return self.ApplicationViewer; elseif ( IsRestrictedAccount() ) then return self.NothingAvailable; elseif ( #C_LFGList.GetAvailableCategories(self.baseFilters) == 0 ) then return self.NothingAvailable; else return self.CategorySelection; end end function LFGListFrame_FixPanelValid(self) if ( not LFGListFrame_IsPanelValid(self, self.activePanel) ) then LFGListFrame_SetActivePanel(self, LFGListFrame_GetBestPanel(self)); end end function LFGListFrame_SetBaseFilters(self, filters) self.baseFilters = filters; --If we need to change panels, do so LFGListFrame_FixPanelValid(self); --Update the current panel if ( self.activePanel and self.activePanel.updateAll ) then self.activePanel.updateAll(self.activePanel); end end ------------------------------------------------------- ----------Nothing available frame ------------------------------------------------------- function LFGListNothingAvailable_OnEvent(self, event, ...) --Note: events are dispatched from the base frame. Add RegisterEvent there. if ( event == "LFG_LIST_AVAILABILITY_UPDATE" ) then LFGListNothingAvailable_Update(self); end end function LFGListNothingAvailable_Update(self) if ( IsRestrictedAccount() ) then self.Label:SetText(ERR_RESTRICTED_ACCOUNT_LFG_LIST_TRIAL); elseif ( C_LFGList.HasActivityList() ) then self.Label:SetText(NO_LFG_LIST_AVAILABLE); else self.Label:SetText(LFG_LIST_LOADING); end end ------------------------------------------------------- ----------Category selection ------------------------------------------------------- function LFGListCategorySelection_OnLoad(self) LFGListCategorySelection_UpdateNavButtons(self); end function LFGListCategorySelection_OnEvent(self, event, ...) --Note: events are dispatched from the base frame. Add RegisterEvent there. if ( event == "LFG_LIST_AVAILABILITY_UPDATE" ) then LFGListCategorySelection_UpdateCategoryButtons(self); end if ( tContains(LFG_LIST_ACTIVE_QUEUE_MESSAGE_EVENTS, event) ) then LFGListCategorySelection_UpdateNavButtons(self); end end function LFGListCategorySelection_OnShow(self) LFGListCategorySelection_UpdateCategoryButtons(self); LFGListCategorySelection_UpdateNavButtons(self); end function LFGListCategorySelection_UpdateCategoryButtons(self) local baseFilters = self:GetParent().baseFilters; local categories = C_LFGList.GetAvailableCategories(baseFilters); local nextBtn = 1; local hasSelected = false; --Update category buttons for i=1, #categories do local isSelected = false; local categoryID = categories[i]; local name, separateRecommended = C_LFGList.GetCategoryInfo(categoryID); if ( separateRecommended ) then nextBtn, isSelected = LFGListCategorySelection_AddButton(self, nextBtn, categoryID, LE_LFG_LIST_FILTER_RECOMMENDED); hasSelected = hasSelected or isSelected; nextBtn, isSelected = LFGListCategorySelection_AddButton(self, nextBtn, categoryID, LE_LFG_LIST_FILTER_NOT_RECOMMENDED); else nextBtn, isSelected = LFGListCategorySelection_AddButton(self, nextBtn, categoryID, 0); end hasSelected = hasSelected or isSelected; end --Hide any extra buttons for i=nextBtn, #self.CategoryButtons do self.CategoryButtons[i]:Hide(); end --If the selected item isn't in the list, deselect it if ( self.selectedCategory and not hasSelected ) then LFGListCategorySelection_SelectCategory(self, nil, nil); end end function LFGListCategorySelection_AddButton(self, btnIndex, categoryID, filters) --Check that we have activities with this filter local baseFilters = self:GetParent().baseFilters; local allFilters = bit.bor(baseFilters, filters); if ( filters ~= 0 and #C_LFGList.GetAvailableActivities(categoryID, nil, allFilters) == 0) then return btnIndex, false; end local name, separateRecommended = C_LFGList.GetCategoryInfo(categoryID); local button = self.CategoryButtons[btnIndex]; if ( not button ) then self.CategoryButtons[btnIndex] = CreateFrame("BUTTON", nil, self, "LFGListCategoryTemplate"); self.CategoryButtons[btnIndex]:SetPoint("TOP", self.CategoryButtons[btnIndex - 1], "BOTTOM", 0, -3); button = self.CategoryButtons[btnIndex]; end button:SetText(LFGListUtil_GetDecoratedCategoryName(name, filters, true)); button.categoryID = categoryID; button.filters = filters; local atlasName = nil; if ( bit.band(allFilters, LE_LFG_LIST_FILTER_RECOMMENDED) ~= 0 ) then atlasName = "groupfinder-button-"..(LFG_LIST_CATEGORY_TEXTURES[categoryID] or "raids").."-"..LFG_LIST_PER_EXPANSION_TEXTURES[LFGListUtil_GetCurrentExpansion()]; elseif ( bit.band(allFilters, LE_LFG_LIST_FILTER_NOT_RECOMMENDED) ~= 0 ) then atlasName = "groupfinder-button-"..(LFG_LIST_CATEGORY_TEXTURES[categoryID] or "raids").."-"..LFG_LIST_PER_EXPANSION_TEXTURES[math.max(0,LFGListUtil_GetCurrentExpansion() - 1)]; else atlasName = "groupfinder-button-"..(LFG_LIST_CATEGORY_TEXTURES[categoryID] or "questing"); end local suffix = ""; if ( bit.band(allFilters, LE_LFG_LIST_FILTER_PVE) ~= 0 ) then suffix = "-pve"; elseif ( bit.band(allFilters, LE_LFG_LIST_FILTER_PVP) ~= 0 ) then suffix = "-pvp"; end --Try with the suffix and then without it if ( not button.Icon:SetAtlas(atlasName..suffix) ) then button.Icon:SetAtlas(atlasName); end local selected = self.selectedCategory == categoryID and self.selectedFilters == filters; button.SelectedTexture:SetShown(selected); button:Show(); return btnIndex + 1, selected; end function LFGListCategorySelection_SelectCategory(self, categoryID, filters) self.selectedCategory = categoryID; self.selectedFilters = filters; LFGListCategorySelection_UpdateCategoryButtons(self); LFGListCategorySelection_UpdateNavButtons(self); end function LFGListCategorySelection_UpdateNavButtons(self) local findEnabled, startEnabled = true, true; self.FindGroupButton.tooltip = nil; self.StartGroupButton.tooltip = nil; --Check if the user needs to select a category if ( not self.selectedCategory ) then findEnabled = false; self.FindGroupButton.tooltip = LFG_LIST_SELECT_A_CATEGORY; startEnabled = false; self.StartGroupButton.tooltip = LFG_LIST_SELECT_A_CATEGORY; end --Check if the user can't start a group due to not being a leader if ( IsInGroup(LE_PARTY_CATEGORY_HOME) and not UnitIsGroupLeader("player", LE_PARTY_CATEGORY_HOME) ) then startEnabled = false; self.StartGroupButton.tooltip = LFG_LIST_NOT_LEADER; end --Check if the player is currently in some incompatible queue local messageStart = LFGListUtil_GetActiveQueueMessage(false); if ( messageStart ) then startEnabled = false; self.StartGroupButton.tooltip = messageStart; end self.FindGroupButton:SetEnabled(findEnabled); self.StartGroupButton:SetEnabled(startEnabled); end function LFGListCategorySelectionStartGroupButton_OnClick(self) local panel = self:GetParent(); if ( not panel.selectedCategory ) then return; end PlaySound("igMainMenuOptionCheckBoxOn"); local baseFilters = panel:GetParent().baseFilters; local entryCreation = panel:GetParent().EntryCreation; LFGListEntryCreation_Show(entryCreation, baseFilters, panel.selectedCategory, panel.selectedFilters); end function LFGListCategorySelectionFindGroupButton_OnClick(self) local panel = self:GetParent(); if ( not panel.selectedCategory ) then return; end PlaySound("igMainMenuOptionCheckBoxOn"); local baseFilters = panel:GetParent().baseFilters; local searchPanel = panel:GetParent().SearchPanel; LFGListSearchPanel_Clear(searchPanel); LFGListSearchPanel_SetCategory(searchPanel, panel.selectedCategory, panel.selectedFilters, baseFilters); LFGListSearchPanel_DoSearch(searchPanel); LFGListFrame_SetActivePanel(panel:GetParent(), searchPanel); end --The individual category buttons function LFGListCategorySelectionButton_OnClick(self) local panel = self:GetParent(); PlaySound("igMainMenuOptionCheckBoxOn"); LFGListCategorySelection_SelectCategory(panel, self.categoryID, self.filters); end ------------------------------------------------------- ----------List Entry Creation ------------------------------------------------------- function LFGListEntryCreation_OnLoad(self) self.Name.Instructions:SetText(LFG_LIST_ENTER_NAME); self.Description.EditBox:SetScript("OnEnterPressed", nop); LFGListUtil_SetUpDropDown(self, self.CategoryDropDown, LFGListEntryCreation_PopulateCategories, LFGListEntryCreation_OnCategorySelected); LFGListUtil_SetUpDropDown(self, self.GroupDropDown, LFGListEntryCreation_PopulateGroups, LFGListEntryCreation_OnGroupSelected); LFGListUtil_SetUpDropDown(self, self.ActivityDropDown, LFGListEntryCreation_PopulateActivities, LFGListEntryCreation_OnActivitySelected); LFGListEntryCreation_SetBaseFilters(self, 0); end function LFGListEntryCreation_OnEvent(self, event, ...) if ( event == "GROUP_ROSTER_UPDATE" ) then LFGListEntryCreation_UpdateValidState(self); elseif ( tContains(LFG_LIST_ACTIVE_QUEUE_MESSAGE_EVENTS, event) ) then LFGListEntryCreation_UpdateValidState(self); end end function LFGListEntryCreation_OnShow(self) LFGListEntryCreation_UpdateValidState(self); end function LFGListEntryCreation_Show(self, baseFilters, selectedCategory, selectedFilters) --If this was what the player selected last time, just leave it filled out with the same info. --Also don't save it for categories that try to set it to the current area. local _, _, _, preferCurrentArea = C_LFGList.GetCategoryInfo(selectedCategory); local keepOldData = not preferCurrentArea and self.selectedCategory == selectedCategory and baseFilters == self.baseFilters and self.selectedFilters == selectedFilters; LFGListEntryCreation_SetBaseFilters(self, baseFilters); if ( not keepOldData ) then LFGListEntryCreation_Clear(self); LFGListEntryCreation_Select(self, selectedFilters, selectedCategory); end LFGListEntryCreation_SetEditMode(self, false); LFGListEntryCreation_UpdateValidState(self); LFGListFrame_SetActivePanel(self:GetParent(), self); self.Name:SetFocus(); end function LFGListEntryCreation_Clear(self) --Clear selections self.selectedCategory = nil; self.selectedGroup = nil; self.selectedActivity = nil; self.selectedFilters = nil; --Reset widgets self.Name:SetText(""); self.ItemLevel.CheckButton:SetChecked(false); self.ItemLevel.EditBox:SetText(""); self.HonorLevel.CheckButton:SetChecked(false); self.HonorLevel.EditBox:SetText(""); self.VoiceChat.CheckButton:SetChecked(false); self.VoiceChat.EditBox:SetText(""); self.Description.EditBox:SetText(""); self.ActivityFinder:Hide(); end function LFGListEntryCreation_ClearFocus(self) self.Name:ClearFocus(); self.ItemLevel.EditBox:ClearFocus(); self.HonorLevel.EditBox:ClearFocus(); self.VoiceChat.EditBox:ClearFocus(); self.Description.EditBox:ClearFocus(); end --This function accepts any or all of categoryID, groupId, and activityID function LFGListEntryCreation_Select(self, filters, categoryID, groupID, activityID) filters, categoryID, groupID, activityID = LFGListUtil_AugmentWithBest(bit.bor(self.baseFilters,filters or 0), categoryID, groupID, activityID); self.selectedCategory = categoryID; self.selectedGroup = groupID; self.selectedActivity = activityID; self.selectedFilters = filters; --Update the category dropdown local categoryName, _, autoChoose = C_LFGList.GetCategoryInfo(categoryID); UIDropDownMenu_SetText(self.CategoryDropDown, LFGListUtil_GetDecoratedCategoryName(categoryName, filters, false)); --Update the activity dropdown local _, shortName, _, _, iLevel, _, _, _, _, _, useHonorLevel = C_LFGList.GetActivityInfo(activityID); UIDropDownMenu_SetText(self.ActivityDropDown, shortName); --Update the group dropdown. If the group dropdown is showing an activity, hide the activity dropdown local groupName = C_LFGList.GetActivityGroupInfo(groupID); UIDropDownMenu_SetText(self.GroupDropDown, groupName or shortName); self.ActivityDropDown:SetShown(groupName and not autoChoose); self.GroupDropDown:SetShown(not autoChoose); --Update the recommended item level box if ( iLevel ~= 0 ) then self.ItemLevel.EditBox.Instructions:SetFormattedText(LFG_LIST_RECOMMENDED_ILVL, iLevel); else self.ItemLevel.EditBox.Instructions:SetText(LFG_LIST_ITEM_LEVEL_INSTR_SHORT); end if ( useHonorLevel ) then self.HonorLevel:Show(); self.VoiceChat:SetPoint("TOPLEFT", self.HonorLevel, "BOTTOMLEFT", 0, -5); else self.HonorLevel:Hide(); self.VoiceChat:SetPoint("TOPLEFT", self.ItemLevel, "BOTTOMLEFT", 0, -5); end LFGListRequirement_Validate(self.ItemLevel, self.ItemLevel.EditBox:GetText()); if ( useHonorLevel ) then LFGListRequirement_Validate(self.HonorLevel, self.HonorLevel.EditBox:GetText()); end LFGListEntryCreation_UpdateValidState(self); end function LFGListEntryCreation_PopulateCategories(self, dropDown, info) local categories = C_LFGList.GetAvailableCategories(self.baseFilters); for i=1, #categories do local categoryID = categories[i]; local name, separateRecommended = C_LFGList.GetCategoryInfo(categoryID); if ( separateRecommended ) then LFGListEntryCreation_AddCategoryEntry(self, info, categoryID, name, LE_LFG_LIST_FILTER_RECOMMENDED); LFGListEntryCreation_AddCategoryEntry(self, info, categoryID, name, LE_LFG_LIST_FILTER_NOT_RECOMMENDED); else LFGListEntryCreation_AddCategoryEntry(self, info, categoryID, name, 0); end end end function LFGListEntryCreation_AddCategoryEntry(self, info, categoryID, name, filters) if ( filters ~= 0 and #C_LFGList.GetAvailableActivities(categoryID, nil, filters) == 0 ) then return; end info.text = LFGListUtil_GetDecoratedCategoryName(name, filters, false); info.value = categoryID; info.arg1 = filters; info.checked = (self.selectedCategory == categoryID and self.selectedFilters == filters); info.isRadio = true; UIDropDownMenu_AddButton(info); end function LFGListEntryCreation_OnCategorySelected(self, categoryID, filters) LFGListEntryCreation_Select(self, filters, categoryID, nil, nil); end function LFGListEntryCreation_PopulateGroups(self, dropDown, info) if ( not self.selectedCategory ) then --We don't have a category, so we can't fill out groups. return; end local useMore = false; --Start out displaying everything local groups = C_LFGList.GetAvailableActivityGroups(self.selectedCategory, bit.bor(self.baseFilters, self.selectedFilters)); local activities = C_LFGList.GetAvailableActivities(self.selectedCategory, 0, bit.bor(self.baseFilters, self.selectedFilters)); if ( self.selectedFilters == 0 ) then --We don't bother filtering if we have less than 5 items anyway if ( #groups + #activities > 5 ) then --Try just displaying the recommended local filters = bit.bor(self.selectedFilters, self.baseFilters, LE_LFG_LIST_FILTER_RECOMMENDED); local recGroups = C_LFGList.GetAvailableActivityGroups(self.selectedCategory, filters); local recActivities = C_LFGList.GetAvailableActivities(self.selectedCategory, 0, filters); --If we have some recommended, just display those if ( #recGroups + #recActivities > 0 ) then --If we still have just as many, we don't need to display more useMore = #recGroups ~= #groups or #recActivities ~= #activities; groups = recGroups; activities = recActivities; end end end local groupOrder = groups[1] and select(2, C_LFGList.GetActivityGroupInfo(groups[1])); local activityOrder = activities[1] and select(10, C_LFGList.GetActivityInfo(activities[1])); local groupIndex, activityIndex = 1, 1; --Start merging for i=1, MAX_LFG_LIST_GROUP_DROPDOWN_ENTRIES do if ( not groupOrder and not activityOrder ) then break; end if ( activityOrder and (not groupOrder or activityOrder < groupOrder) ) then local activityID = activities[activityIndex]; local name = select(ACTIVITY_RETURN_VALUES.shortName, C_LFGList.GetActivityInfo(activityID)); info.text = name; info.value = activityID; info.arg1 = "activity"; info.checked = (self.selectedActivity == activityID); info.isRadio = true; UIDropDownMenu_AddButton(info); activityIndex = activityIndex + 1; activityOrder = activities[activityIndex] and select(10, C_LFGList.GetActivityInfo(activities[activityIndex])); else local groupID = groups[groupIndex]; local name = C_LFGList.GetActivityGroupInfo(groupID); info.text = name; info.value = groupID; info.arg1 = "group"; info.checked = (self.selectedGroup == groupID); info.isRadio = true; UIDropDownMenu_AddButton(info); groupIndex = groupIndex + 1; groupOrder = groups[groupIndex] and select(2, C_LFGList.GetActivityGroupInfo(groups[groupIndex])); end end if ( #activities + #groups > MAX_LFG_LIST_GROUP_DROPDOWN_ENTRIES ) then useMore = true; end if ( useMore ) then info.text = LFG_LIST_MORE; info.value = nil; info.arg1 = "more"; info.notCheckable = true; info.checked = false; info.isRadio = false; UIDropDownMenu_AddButton(info); end end function LFGListEntryCreation_OnGroupSelected(self, id, buttonType) if ( buttonType == "activity" ) then LFGListEntryCreation_Select(self, nil, nil, nil, id); elseif ( buttonType == "group" ) then LFGListEntryCreation_Select(self, self.selectedFilters, self.selectedCategory, id, nil); elseif ( buttonType == "more" ) then LFGListEntryCreationActivityFinder_Show(self.ActivityFinder, self.selectedCategory, nil, bit.bor(self.baseFilters, self.selectedFilters)); end end function LFGListEntryCreation_PopulateActivities(self, dropDown, info) local useMore = self.selectedFilters == 0; local filters = bit.bor(self.baseFilters, self.selectedFilters); --Start out displaying everything local activities = C_LFGList.GetAvailableActivities(self.selectedCategory, self.selectedGroup, filters); --If we're displaying more than 5, see if we can just display recommended if ( useMore ) then if ( #activities > 5 ) then filters = bit.bor(filters, LE_LFG_LIST_FILTER_RECOMMENDED); local recActivities = C_LFGList.GetAvailableActivities(self.selectedCategory, self.selectedGroup, filters); useMore = #recActivities ~= #activities; if ( #recActivities > 0 ) then activities = recActivities; else --Just display up to 5 non-recommended activities for i=#activities, 5, -1 do activities[i] = nil; end end else useMore = false; end end for i=1, #activities do local activityID = activities[i]; local shortName = select(ACTIVITY_RETURN_VALUES.shortName, C_LFGList.GetActivityInfo(activityID)); info.text = shortName; info.value = activityID; info.arg1 = "activity"; info.checked = (self.selectedActivity == activityID); info.isRadio = true; UIDropDownMenu_AddButton(info); end if ( useMore ) then info.text = LFG_LIST_MORE; info.value = nil; info.arg1 = "more"; info.notCheckable = true; info.checked = false; info.isRadio = false; UIDropDownMenu_AddButton(info); end end function LFGListEntryCreation_OnActivitySelected(self, activityID, buttonType) if ( buttonType == "activity" ) then LFGListEntryCreation_Select(self, nil, nil, nil, activityID); elseif ( buttonType == "more" ) then LFGListEntryCreationActivityFinder_Show(self.ActivityFinder, self.selectedCategory, self.selectedGroup, bit.bor(self.baseFilters, self.selectedFilters)); end end function LFGListEntryCreation_GetSanitizedName(self) return string.match(self.Name:GetText(), "^%s*(.-)%s*$"); end function LFGListEntryCreation_ListGroup(self) local name = LFGListEntryCreation_GetSanitizedName(self); local iLevel = tonumber(self.ItemLevel.EditBox:GetText()) or 0; local honorLevel = tonumber(self.HonorLevel.EditBox:GetText()) or 0; if ( LFGListEntryCreation_IsEditMode(self) ) then local autoAccept = select(9, C_LFGList.GetActiveEntryInfo()); C_LFGList.UpdateListing(self.selectedActivity, name, iLevel, honorLevel, self.VoiceChat.EditBox:GetText(), self.Description.EditBox:GetText(), autoAccept); LFGListFrame_SetActivePanel(self:GetParent(), self:GetParent().ApplicationViewer); else if(C_LFGList.CreateListing(self.selectedActivity, name, iLevel, honorLevel, self.VoiceChat.EditBox:GetText(), self.Description.EditBox:GetText(), false)) then self.WorkingCover:Show(); LFGListEntryCreation_ClearFocus(self); end end end function LFGListEntryCreation_UpdateValidState(self) local errorText; local maxPlayers, _, _, useHonorLevel = select(ACTIVITY_RETURN_VALUES.maxPlayers, C_LFGList.GetActivityInfo(self.selectedActivity)); if ( maxPlayers > 0 and GetNumGroupMembers(LE_PARTY_CATEGORY_HOME) >= maxPlayers ) then errorText = string.format(LFG_LIST_TOO_MANY_FOR_ACTIVITY, maxPlayers); elseif ( LFGListEntryCreation_GetSanitizedName(self) == "" ) then errorText = LFG_LIST_MUST_HAVE_NAME; elseif ( self.ItemLevel.warningText ) then errorText = self.ItemLevel.warningText; elseif ( useHonorLevel and self.HonorLevel.warningText ) then errorText = self.HonorLevel.warningText; else errorText = LFGListUtil_GetActiveQueueMessage(false); end self.ListGroupButton:SetEnabled(not errorText); self.ListGroupButton.errorText = errorText; end function LFGListEntryCreation_SetBaseFilters(self, baseFilters) self.baseFilters = baseFilters; end function LFGListEntryCreation_SetEditMode(self, editMode) self.editMode = editMode; if ( editMode ) then local active, activityID, ilvl, honorLevel, name, comment, voiceChat = C_LFGList.GetActiveEntryInfo(); assert(active); --Update the dropdowns LFGListEntryCreation_Select(self, nil, nil, nil, activityID); UIDropDownMenu_DisableDropDown(self.CategoryDropDown); UIDropDownMenu_DisableDropDown(self.GroupDropDown); UIDropDownMenu_DisableDropDown(self.ActivityDropDown); --Update edit boxes self.Name:SetText(name); self.ItemLevel.EditBox:SetText(ilvl ~= 0 and ilvl or ""); self.HonorLevel.EditBox:SetText(honorLevel ~= 0 and honorLevel or "") self.VoiceChat.EditBox:SetText(voiceChat); self.Description.EditBox:SetText(comment); self.ListGroupButton:SetText(DONE_EDITING); else UIDropDownMenu_EnableDropDown(self.CategoryDropDown); UIDropDownMenu_EnableDropDown(self.GroupDropDown); UIDropDownMenu_EnableDropDown(self.ActivityDropDown); self.ListGroupButton:SetText(LIST_GROUP); end end function LFGListEntryCreation_IsEditMode(self) return self.editMode; end function LFGListEntryCreationCancelButton_OnClick(self) local panel = self:GetParent(); PlaySound("igMainMenuOptionCheckBoxOn"); if ( LFGListEntryCreation_IsEditMode(panel) ) then LFGListFrame_SetActivePanel(panel:GetParent(), panel:GetParent().ApplicationViewer); else LFGListFrame_SetActivePanel(panel:GetParent(), panel:GetParent().CategorySelection); end end function LFGListEntryCreationListGroupButton_OnClick(self) PlaySound("igMainMenuOptionCheckBoxOn"); LFGListEntryCreation_ListGroup(self:GetParent()); end function LFGListEntryCreationActivityFinder_OnLoad(self) self.Dialog.ScrollFrame.update = function() LFGListEntryCreationActivityFinder_Update(self); end; self.Dialog.ScrollFrame.scrollBar.doNotHide = true; HybridScrollFrame_CreateButtons(self.Dialog.ScrollFrame, "LFGListEntryCreationActivityListTemplate"); self.matchingActivities = {}; end function LFGListEntryCreationActivityFinder_Show(self, categoryID, groupID, filters) self.Dialog.EntryBox:SetText(""); self.categoryID = categoryID; self.groupID = groupID; self.filters = filters; self.selectedActivity = nil; LFGListEntryCreationActivityFinder_UpdateMatching(self); self:Show(); self.Dialog.EntryBox:SetFocus(); end function LFGListEntryCreationActivityFinder_UpdateMatching(self) self.matchingActivities = C_LFGList.GetAvailableActivities(self.categoryID, self.groupID, self.filters, self.Dialog.EntryBox:GetText()); LFGListUtil_SortActivitiesByRelevancy(self.matchingActivities); if ( not self.selectedActivity or not tContains(self.matchingActivities, self.selectedActivity) ) then self.selectedActivity = self.matchingActivities[1]; end LFGListEntryCreationActivityFinder_Update(self); end function LFGListEntryCreationActivityFinder_Update(self) local actitivities = self.matchingActivities; local offset = HybridScrollFrame_GetOffset(self.Dialog.ScrollFrame); for i=1, #self.Dialog.ScrollFrame.buttons do local button = self.Dialog.ScrollFrame.buttons[i]; local idx = i + offset; local id = actitivities[idx]; if ( id ) then button:SetText( (C_LFGList.GetActivityInfo(id)) ); button.activityID = id; button.Selected:SetShown(self.selectedActivity == id); if ( self.selectedActivity == id ) then button:LockHighlight(); else button:UnlockHighlight(); end button:Show(); else button:Hide(); end end HybridScrollFrame_Update(self.Dialog.ScrollFrame, self.Dialog.ScrollFrame.buttons[1]:GetHeight() * #actitivities, self.Dialog.ScrollFrame:GetHeight()); end function LFGListEntryCreationActivityFinder_Accept(self) if ( self.selectedActivity ) then LFGListEntryCreation_Select(self:GetParent(), nil, nil, nil, self.selectedActivity); end self:Hide(); end function LFGListEntryCreationActivityFinder_Cancel(self) self:Hide(); end function LFGListEntryCreationActivityFinder_Select(self, activityID) self.selectedActivity = activityID; LFGListEntryCreationActivityFinder_Update(self); end ------------------------------------------------------- ----------Application Viewing ------------------------------------------------------- function LFGListApplicationViewer_OnLoad(self) self.ScrollFrame.update = function() LFGListApplicationViewer_UpdateResults(self); end; self.ScrollFrame.dynamic = function(offset) return LFGListApplicationViewer_GetScrollOffset(self, offset) end self.ScrollFrame.scrollBar.doNotHide = true; self.NameColumnHeader:Disable(); self.RoleColumnHeader:Disable(); self.ItemLevelColumnHeader:Disable(); HybridScrollFrame_CreateButtons(self.ScrollFrame, "LFGListApplicantTemplate"); end function LFGListApplicationViewer_OnEvent(self, event, ...) if ( event == "LFG_LIST_ACTIVE_ENTRY_UPDATE" ) then LFGListApplicationViewer_UpdateInfo(self); elseif ( event == "PARTY_LEADER_CHANGED" ) then LFGListApplicationViewer_UpdateAvailability(self); LFGListApplicationViewer_UpdateInfo(self); elseif ( event == "LFG_LIST_APPLICANT_LIST_UPDATED" ) then LFGListApplicationViewer_UpdateResultList(self); LFGListApplicationViewer_UpdateResults(self); elseif ( event == "LFG_LIST_APPLICANT_UPDATED" ) then --If we can't make changes, we just remove people immediately local id = ...; if ( not LFGListUtil_IsEntryEmpowered() ) then C_LFGList.RemoveApplicant(id); end --Update whether we can invite people LFGListApplicationViewer_UpdateInviteState(self); elseif ( event == "GROUP_ROSTER_UPDATE" ) then LFGListApplicationViewer_UpdateAvailability(self); LFGListApplicationViewer_UpdateGroupData(self); LFGListApplicationViewer_UpdateInviteState(self); LFGListApplicationViewer_UpdateInfo(self); elseif ( event == "PLAYER_ROLES_ASSIGNED") then LFGListApplicationViewer_UpdateGroupData(self); end end function LFGListApplicationViewer_OnShow(self) C_LFGList.RefreshApplicants(); LFGListApplicationViewer_UpdateResultList(self); LFGListApplicationViewer_UpdateResults(self); LFGListApplicationViewer_UpdateInfo(self); LFGListApplicationViewer_UpdateAvailability(self); LFGListApplicationViewer_UpdateGroupData(self); end function LFGListApplicationViewer_UpdateGroupData(self) local active, activityID = C_LFGList.GetActiveEntryInfo(); if ( not active ) then return; end local data = GetGroupMemberCounts(); data.DAMAGER = data.DAMAGER + data.NOROLE; --People without a role count as damage data.NOROLE = 0; LFGListGroupDataDisplay_Update(self.DataDisplay, activityID, data); end function LFGListApplicationViewer_UpdateInfo(self) local active, activityID, ilvl, honorLevel, name, comment, voiceChat, duration, autoAccept = C_LFGList.GetActiveEntryInfo(); local fullName, shortName, categoryID, groupID, iLevel, filters, minLevel, maxPlayers, displayType = C_LFGList.GetActivityInfo(activityID); local _, separateRecommended = C_LFGList.GetCategoryInfo(categoryID); assert(active); self.EntryName:SetWidth(0); self.EntryName:SetText(name); self.DescriptionFrame.activityName = C_LFGList.GetActivityInfo(activityID); self.DescriptionFrame.comment = comment; if ( comment == "" ) then self.DescriptionFrame.Text:SetText(self.DescriptionFrame.activityName); else self.DescriptionFrame.Text:SetFormattedText("%s |cff888888- %s|r", self.DescriptionFrame.activityName, self.DescriptionFrame.comment); end local hasRestrictions = false; if ( ilvl == 0 ) then self.ItemLevel:SetText(""); else self.ItemLevel:SetFormattedText(LFG_LIST_ITEM_LEVEL_CURRENT, ilvl); end if ( voiceChat == "" ) then self.VoiceChatFrame.tooltip = nil; self.VoiceChatFrame:Hide(); else self.VoiceChatFrame.tooltip = voiceChat; self.VoiceChatFrame:Show(); end if ( self.EntryName:GetWidth() > 290 ) then self.EntryName:SetWidth(290); end --Set the background local atlasName = nil; if ( separateRecommended and bit.band(filters, LE_LFG_LIST_FILTER_RECOMMENDED) ~= 0 ) then atlasName = "groupfinder-background-"..(LFG_LIST_CATEGORY_TEXTURES[categoryID] or "raids").."-"..LFG_LIST_PER_EXPANSION_TEXTURES[LFGListUtil_GetCurrentExpansion()]; elseif ( separateRecommended and bit.band(filters, LE_LFG_LIST_FILTER_NOT_RECOMMENDED) ~= 0 ) then atlasName = "groupfinder-background-"..(LFG_LIST_CATEGORY_TEXTURES[categoryID] or "raids").."-"..LFG_LIST_PER_EXPANSION_TEXTURES[math.max(0,LFGListUtil_GetCurrentExpansion() - 1)]; else atlasName = "groupfinder-background-"..(LFG_LIST_CATEGORY_TEXTURES[categoryID] or "questing"); end local suffix = ""; if ( bit.band(filters, LE_LFG_LIST_FILTER_PVE) ~= 0 ) then suffix = "-pve"; elseif ( bit.band(filters, LE_LFG_LIST_FILTER_PVP) ~= 0 ) then suffix = "-pvp"; end --Try with the suffix and then without it if ( not self.InfoBackground:SetAtlas(atlasName..suffix) ) then self.InfoBackground:SetAtlas(atlasName); end --Update the AutoAccept button self.AutoAcceptButton:SetChecked(autoAccept); if ( UnitIsGroupLeader("player", LE_PARTY_CATEGORY_HOME) ) then self.AutoAcceptButton:Show(); self.AutoAcceptButton:Enable(); self.AutoAcceptButton.Label:SetFontObject(GameFontHighlightSmall); elseif ( UnitIsGroupAssistant("player", LE_PARTY_CATEGORY_HOME) ) then self.AutoAcceptButton:Show(); self.AutoAcceptButton:Disable(); self.AutoAcceptButton.Label:SetFontObject(GameFontDisableSmall); else self.AutoAcceptButton:SetShown(autoAccept); self.AutoAcceptButton:Disable(); self.AutoAcceptButton.Label:SetFontObject(GameFontDisableSmall); end end function LFGListApplicationViewer_UpdateAvailability(self) if ( UnitIsGroupLeader("player", LE_PARTY_CATEGORY_HOME) ) then self.RemoveEntryButton:Show(); self.EditButton:Show(); else self.RemoveEntryButton:Hide(); self.EditButton:Hide(); end if ( IsRestrictedAccount() ) then self.EditButton:Disable(); self.EditButton.tooltip = ERR_RESTRICTED_ACCOUNT_LFG_LIST_TRIAL; else self.EditButton:Enable(); self.EditButton.tooltip = nil; end local empowered = LFGListUtil_IsEntryEmpowered(); self.UnempoweredCover:SetShown(not empowered); self.ScrollFrame.NoApplicants:SetShown(empowered and (not self.applicants or #self.applicants == 0)); end function LFGListApplicationViewer_UpdateResultList(self) self.applicants = C_LFGList.GetApplicants(); --Filter applicants. Don't worry about order. LFGListUtil_FilterApplicants(self.applicants); --Sort applicants LFGListUtil_SortApplicants(self.applicants); --Cache off the group sizes for the scroll frame and the total height local totalHeight = 0; self.applicantSizes = {}; for i=1, #self.applicants do local _, _, _, numMembers = C_LFGList.GetApplicantInfo(self.applicants[i]); self.applicantSizes[i] = numMembers; totalHeight = totalHeight + LFGListApplicationViewerUtil_GetButtonHeight(numMembers); end self.totalApplicantHeight = totalHeight; LFGListApplicationViewer_UpdateAvailability(self); end function LFGListApplicationViewer_UpdateInviteState(self) local active, activityID, ilvl, honorLevel, name, comment, voiceChat = C_LFGList.GetActiveEntryInfo(); if ( not active ) then return; end local numAllowed = select(ACTIVITY_RETURN_VALUES.maxPlayers, C_LFGList.GetActivityInfo(activityID)); if ( numAllowed == 0 ) then numAllowed = MAX_RAID_MEMBERS; end local currentCount = GetNumGroupMembers(LE_PARTY_CATEGORY_HOME); local numInvited = C_LFGList.GetNumInvitedApplicantMembers(); local buttons = self.ScrollFrame.buttons; for i=1, #buttons do local button = buttons[i]; if ( button.applicantID ) then if ( button.numMembers + currentCount > numAllowed ) then button.InviteButton:Disable(); button.InviteButton.tooltip = LFG_LIST_GROUP_TOO_FULL; elseif ( button.numMembers + currentCount + numInvited > numAllowed ) then button.InviteButton:Disable(); button.InviteButton.tooltip = LFG_LIST_INVITED_APP_FILLS_GROUP; else button.InviteButton:Enable(); button.InviteButton.tooltip = nil; end --If our mouse is already over the button, update the tooltip if ( button.InviteButton:IsMouseOver() ) then if ( button.InviteButton.tooltip ) then button.InviteButton:GetScript("OnEnter")(button.InviteButton); else GameTooltip:Hide(); end end end end end function LFGListApplicationViewer_UpdateResults(self) local offset = HybridScrollFrame_GetOffset(self.ScrollFrame); local buttons = self.ScrollFrame.buttons; --If the mouse is over something in this frame, update it local mouseover = GetMouseFocus(); local mouseoverParent = mouseover and mouseover:GetParent(); local parentParent = mouseoverParent and mouseoverParent:GetParent(); if ( mouseoverParent == self.ScrollFrame or parentParent == self.ScrollFrame ) then --Just hide the tooltip. We should show it again inside the update function. GameTooltip:Hide(); end for i=1, #buttons do local button = buttons[i]; local idx = i + offset; local id = self.applicants[idx]; if ( id ) then button.applicantID = id; LFGListApplicationViewer_UpdateApplicant(button, id); button.Background:SetAlpha(idx % 2 == 0 and 0.1 or 0.05); button:Show(); else button.applicantID = nil; button:Hide(); end end HybridScrollFrame_Update(self.ScrollFrame, self.totalApplicantHeight, self.ScrollFrame:GetHeight()); LFGListApplicationViewer_UpdateInviteState(self); end function LFGListApplicationViewer_UpdateApplicant(button, id) local id, status, pendingStatus, numMembers, isNew = C_LFGList.GetApplicantInfo(id); button:SetHeight(LFGListApplicationViewerUtil_GetButtonHeight(numMembers)); --Update individual members for i=1, numMembers do local member = button.Members[i]; if ( not member ) then member = CreateFrame("BUTTON", nil, button, "LFGListApplicantMemberTemplate"); member:SetPoint("TOPLEFT", button.Members[i-1], "BOTTOMLEFT", 0, 0); button.Members[i] = member; end LFGListApplicationViewer_UpdateApplicantMember(member, id, i, status, pendingStatus); member:Show(); end --Hide extra member buttons for i=numMembers+1, #button.Members do button.Members[i]:Hide(); end --Update the Invite and Decline buttons based on group size if ( numMembers > 1 ) then button.DeclineButton:SetHeight(36); button.InviteButton:SetHeight(36); button.InviteButton:SetFormattedText(LFG_LIST_INVITE_GROUP, numMembers); else button.DeclineButton:SetHeight(22); button.InviteButton:SetHeight(22); button.InviteButton:SetText(INVITE); end if ( pendingStatus or status == "applied" ) then button.Status:Hide(); elseif ( status == "invited" ) then button.Status:Show(); button.Status:SetText(LFG_LIST_APP_INVITED); button.Status:SetTextColor(GREEN_FONT_COLOR.r, GREEN_FONT_COLOR.g, GREEN_FONT_COLOR.b); elseif ( status == "failed" or status == "cancelled" ) then button.Status:Show(); button.Status:SetText(LFG_LIST_APP_CANCELLED); button.Status:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b); elseif ( status == "declined" ) then button.Status:Show(); button.Status:SetText(LFG_LIST_APP_DECLINED); button.Status:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b); elseif ( status == "timedout" ) then button.Status:Show(); button.Status:SetText(LFG_LIST_APP_TIMED_OUT); button.Status:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b); elseif ( status == "inviteaccepted" ) then button.Status:Show(); button.Status:SetText(LFG_LIST_APP_INVITE_ACCEPTED); button.Status:SetTextColor(GREEN_FONT_COLOR.r, GREEN_FONT_COLOR.g, GREEN_FONT_COLOR.b); elseif ( status == "invitedeclined" ) then button.Status:Show(); button.Status:SetText(LFG_LIST_APP_INVITE_DECLINED); button.Status:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b); end button.numMembers = numMembers; button.InviteButton:SetShown(not pendingStatus and status == "applied" and LFGListUtil_IsEntryEmpowered()); button.DeclineButton:SetShown(not pendingStatus and status ~= "invited" and LFGListUtil_IsEntryEmpowered()); button.DeclineButton.isAck = (status ~= "applied" and status ~= "invited"); button.Spinner:SetShown(pendingStatus); end function LFGListApplicationViewer_UpdateApplicantMember(member, appID, memberIdx, status, pendingStatus) local grayedOut = not pendingStatus and (status == "failed" or status == "cancelled" or status == "declined" or status == "invitedeclined" or status == "timedout"); local noTouchy = (status == "invited" or status == "inviteaccepted" or status == "invitedeclined"); local name, class, localizedClass, level, itemLevel, honorLevel, tank, healer, damage, assignedRole, relationship = C_LFGList.GetApplicantMemberInfo(appID, memberIdx); member.memberIdx = memberIdx; member.Name:SetWidth(0); if ( name ) then local displayName = Ambiguate(name, "short"); if ( memberIdx > 1 ) then member.Name:SetText(" "..displayName); else member.Name:SetText(displayName); end local classTextColor = grayedOut and GRAY_FONT_COLOR or RAID_CLASS_COLORS[class]; member.Name:SetTextColor(classTextColor.r, classTextColor.g, classTextColor.b); else --We might still be requesting the name and class from the server. member.Name:SetText(""); end member.FriendIcon:SetShown(relationship); member.FriendIcon.relationship = relationship; member.FriendIcon.Icon:SetDesaturated(grayedOut); member.FriendIcon:SetAlpha(grayedOut and 0.5 or 1.0); --Adjust name width depending on whether we have the friend icon local nameLength = 100; if ( relationship ) then nameLength = nameLength - 22; end if ( member.Name:GetWidth() > nameLength ) then member.Name:SetWidth(nameLength); end --Update the roles. if ( grayedOut ) then member.RoleIcon1:Hide(); member.RoleIcon2:Hide(); else local role1 = tank and "TANK" or (healer and "HEALER" or (damage and "DAMAGER")); local role2 = (tank and healer and "HEALER") or ((tank or healer) and damage and "DAMAGER"); member.RoleIcon1:GetNormalTexture():SetAtlas(LFG_LIST_GROUP_DATA_ATLASES[role1]); member.RoleIcon1:GetHighlightTexture():SetAtlas(LFG_LIST_GROUP_DATA_ATLASES[role1]); if ( role2 ) then member.RoleIcon2:GetNormalTexture():SetAtlas(LFG_LIST_GROUP_DATA_ATLASES[role2]); member.RoleIcon2:GetHighlightTexture():SetAtlas(LFG_LIST_GROUP_DATA_ATLASES[role2]); end member.RoleIcon1:SetEnabled(not noTouchy and role1 ~= assignedRole); member.RoleIcon1:SetAlpha(role1 == assignedRole and 1 or 0.3); member.RoleIcon1:Show(); member.RoleIcon2:SetEnabled(not noTouchy and role2 ~= assignedRole); member.RoleIcon2:SetAlpha(role2 == assignedRole and 1 or 0.3); member.RoleIcon2:SetShown(role2); member.RoleIcon1.role = role1; member.RoleIcon2.role = role2; end member.ItemLevel:SetShown(not grayedOut); member.ItemLevel:SetText(math.floor(itemLevel)); local mouseFocus = GetMouseFocus(); if ( mouseFocus == member ) then LFGListApplicantMember_OnEnter(member); elseif ( mouseFocus == member.FriendIcon ) then member.FriendIcon:GetScript("OnEnter")(member.FriendIcon); end end function LFGListApplicationViewer_GetScrollOffset(self, offset) local acum = 0; for i=1, #self.applicantSizes do local height = LFGListApplicationViewerUtil_GetButtonHeight(self.applicantSizes[i]); acum = acum + height; if ( acum > offset ) then return i - 1, height + offset - acum; end end --We're scrolled completely off the bottom return #self.applicantSizes, 0; end function LFGListApplicationViewerUtil_GetButtonHeight(numApplicants) return 20 * numApplicants + 6; end function LFGListApplicationViewerEditButton_OnClick(self) PlaySound("igMainMenuOptionCheckBoxOn"); local panel = self:GetParent(); local entryCreation = panel:GetParent().EntryCreation; LFGListEntryCreation_SetEditMode(entryCreation, true); LFGListFrame_SetActivePanel(panel:GetParent(), entryCreation); end --Applicant members function LFGListApplicantMember_OnEnter(self) local applicantID = self:GetParent().applicantID; local memberIdx = self.memberIdx; local active, activityID = C_LFGList.GetActiveEntryInfo(); if ( not active ) then return; end local useHonorLevel = select(11, C_LFGList.GetActivityInfo(activityID)); local id, status, pendingStatus, numMembers, isNew, comment = C_LFGList.GetApplicantInfo(applicantID); local name, class, localizedClass, level, itemLevel, honorLevel, tank, healer, damage, assignedRole = C_LFGList.GetApplicantMemberInfo(applicantID, memberIdx); GameTooltip:SetOwner(self, "ANCHOR_NONE"); GameTooltip:SetPoint("BOTTOMLEFT", self, "TOPLEFT", 105, 0); if ( name ) then local classTextColor = RAID_CLASS_COLORS[class]; GameTooltip:SetText(name, classTextColor.r, classTextColor.g, classTextColor.b); GameTooltip:AddLine(string.format(UNIT_TYPE_LEVEL_TEMPLATE, level, localizedClass), 1, 1, 1); else GameTooltip:SetText(" "); --Just make it empty until we get the name update end GameTooltip:AddLine(string.format(LFG_LIST_ITEM_LEVEL_CURRENT, itemLevel), 1, 1, 1); if ( useHonorLevel ) then GameTooltip:AddLine(string.format(LFG_LIST_HONOR_LEVEL_CURRENT_PVP, honorLevel), 1, 1, 1); end if ( comment and comment ~= "" ) then GameTooltip:AddLine(" "); GameTooltip:AddLine(string.format(LFG_LIST_COMMENT_FORMAT, comment), LFG_LIST_COMMENT_FONT_COLOR.r, LFG_LIST_COMMENT_FONT_COLOR.g, LFG_LIST_COMMENT_FONT_COLOR.b, true); end --Add statistics local stats = C_LFGList.GetApplicantMemberStats(applicantID, memberIdx); local lastTitle = nil; --Tank proving ground if ( stats[23690] and stats[23690] > 0 ) then LFGListUtil_AppendStatistic(LFG_LIST_PROVING_TANK_GOLD, nil, LFG_LIST_PROVING_GROUND_TITLE, lastTitle); lastTitle = LFG_LIST_PROVING_GROUND_TITLE; elseif ( stats[23687] and stats[23687] > 0 ) then LFGListUtil_AppendStatistic(LFG_LIST_PROVING_TANK_SILVER, nil, LFG_LIST_PROVING_GROUND_TITLE, lastTitle); lastTitle = LFG_LIST_PROVING_GROUND_TITLE; elseif ( stats[23684] and stats[23684] > 0 ) then LFGListUtil_AppendStatistic(LFG_LIST_PROVING_TANK_BRONZE, nil, LFG_LIST_PROVING_GROUND_TITLE, lastTitle); lastTitle = LFG_LIST_PROVING_GROUND_TITLE; end --Healer proving ground if ( stats[23691] and stats[23691] > 0 ) then LFGListUtil_AppendStatistic(LFG_LIST_PROVING_HEALER_GOLD, nil, LFG_LIST_PROVING_GROUND_TITLE, lastTitle); lastTitle = LFG_LIST_PROVING_GROUND_TITLE; elseif ( stats[23688] and stats[23688] > 0 ) then LFGListUtil_AppendStatistic(LFG_LIST_PROVING_HEALER_SILVER, nil, LFG_LIST_PROVING_GROUND_TITLE, lastTitle); lastTitle = LFG_LIST_PROVING_GROUND_TITLE; elseif ( stats[23685] and stats[23685] > 0 ) then LFGListUtil_AppendStatistic(LFG_LIST_PROVING_HEALER_BRONZE, nil, LFG_LIST_PROVING_GROUND_TITLE, lastTitle); lastTitle = LFG_LIST_PROVING_GROUND_TITLE; end --Damage proving ground if ( stats[23689] and stats[23689] > 0 ) then LFGListUtil_AppendStatistic(LFG_LIST_PROVING_DAMAGER_GOLD, nil, LFG_LIST_PROVING_GROUND_TITLE, lastTitle); lastTitle = LFG_LIST_PROVING_GROUND_TITLE; elseif ( stats[23686] and stats[23686] > 0 ) then LFGListUtil_AppendStatistic(LFG_LIST_PROVING_DAMAGER_SILVER, nil, LFG_LIST_PROVING_GROUND_TITLE, lastTitle); lastTitle = LFG_LIST_PROVING_GROUND_TITLE; elseif ( stats[23683] and stats[23683] > 0 ) then LFGListUtil_AppendStatistic(LFG_LIST_PROVING_DAMAGER_BRONZE, nil, LFG_LIST_PROVING_GROUND_TITLE, lastTitle); lastTitle = LFG_LIST_PROVING_GROUND_TITLE; end GameTooltip:Show(); end ------------------------------------------------------- ----------Searching ------------------------------------------------------- function LFGListSearchPanel_OnLoad(self) self.SearchBox.Instructions:SetText(FILTER); self.ScrollFrame.update = function() LFGListSearchPanel_UpdateResults(self); end; self.ScrollFrame.scrollBar.doNotHide = true; HybridScrollFrame_CreateButtons(self.ScrollFrame, "LFGListSearchEntryTemplate"); self.SearchBox.clearButton:SetScript("OnClick", function(btn) SearchBoxTemplateClearButton_OnClick(btn); LFGListSearchPanel_DoSearch(self); end); end function LFGListSearchPanel_OnEvent(self, event, ...) --Note: events are dispatched from the base frame. Add RegisterEvent there. if ( event == "LFG_LIST_SEARCH_RESULTS_RECEIVED" ) then StaticPopupSpecial_Hide(LFGListApplicationDialog); self.searching = false; self.searchFailed = false; LFGListSearchPanel_UpdateResultList(self); LFGListSearchPanel_UpdateResults(self); elseif ( event == "LFG_LIST_SEARCH_FAILED" ) then self.searching = false; self.searchFailed = true; LFGListSearchPanel_UpdateResultList(self); LFGListSearchPanel_UpdateResults(self); elseif ( event == "LFG_LIST_SEARCH_RESULT_UPDATED" ) then local id = ...; if ( self.selectedResult == id ) then LFGListSearchPanel_ValidateSelected(self); if ( self.selectedResult ~= id ) then LFGListSearchPanel_UpdateResults(self); end end LFGListSearchPanel_UpdateButtonStatus(self); elseif ( event == "LFG_LIST_SEARCH_RESULT_UPDATED" ) then LFGListSearchPanel_UpdateButtonStatus(self); elseif ( event == "PARTY_LEADER_CHANGED" ) then LFGListSearchPanel_UpdateButtonStatus(self); elseif ( event == "GROUP_ROSTER_UPDATE" ) then LFGListSearchPanel_UpdateButtonStatus(self); elseif ( event == "PLAYER_SPECIALIZATION_CHANGED" ) then local unit = ...; if ( unit == "player" ) then LFGListSearchPanel_UpdateButtonStatus(self); end elseif ( event == "UNIT_CONNECTION" ) then LFGListSearchPanel_UpdateButtonStatus(self); end if ( tContains(LFG_LIST_ACTIVE_QUEUE_MESSAGE_EVENTS, event) ) then LFGListSearchPanel_UpdateButtonStatus(self); end end function LFGListSearchPanel_OnShow(self) LFGListSearchPanel_UpdateResultList(self); LFGListSearchPanel_UpdateResults(self); --LFGListSearchPanel_UpdateButtonStatus(self); --Called by UpdateResults local availableLanguages = C_LFGList.GetAvailableLanguageSearchFilter(); local defaultLanguages = C_LFGList.GetDefaultLanguageSearchFilter(); local canChangeLanguages = false; for i=1, #availableLanguages do if ( not defaultLanguages[availableLanguages[i]] ) then canChangeLanguages = true; break; end end if ( canChangeLanguages ) then self.SearchBox:SetWidth(228); self.FilterButton:Show(); else self.SearchBox:SetWidth(319); self.FilterButton:Hide(); end end function LFGListSearchPanel_Clear(self) C_LFGList.ClearSearchResults(); self.SearchBox:SetText(""); self.selectedResult = nil; LFGListSearchPanel_UpdateResultList(self); LFGListSearchPanel_UpdateResults(self); end function LFGListSearchPanel_SetCategory(self, categoryID, filters, preferredFilters) self.categoryID = categoryID; self.filters = filters; self.preferredFilters = preferredFilters; local name = LFGListUtil_GetDecoratedCategoryName(C_LFGList.GetCategoryInfo(categoryID), filters, false); self.CategoryName:SetText(name); end function LFGListSearchPanel_DoSearch(self) local searchText = self.SearchBox:GetText(); local languages = C_LFGList.GetLanguageSearchFilter(); C_LFGList.Search(self.categoryID, searchText, self.filters, self.preferredFilters, languages); self.searching = true; self.searchFailed = false; self.selectedResult = nil; LFGListSearchPanel_UpdateResultList(self); LFGListSearchPanel_UpdateResults(self); end function LFGListSearchPanel_CreateGroupInstead(self) LFGListEntryCreation_Show(self:GetParent().EntryCreation, self.preferredFilters, self.categoryID, self.filters); end function LFGListSearchPanel_UpdateResultList(self) self.totalResults, self.results = C_LFGList.GetSearchResults(); self.applications = C_LFGList.GetApplications(); LFGListUtil_SortSearchResults(self.results); end function LFGListSearchPanel_ValidateSelected(self) if ( self.selectedResult and not LFGListSearchPanelUtil_CanSelectResult(self.selectedResult)) then self.selectedResult = nil; end end function LFGListSearchPanelUtil_CanSelectResult(resultID) local _, appStatus, pendingStatus, appDuration = C_LFGList.GetApplicationInfo(resultID); local id, activityID, name, comment, voiceChat, iLvl, honorLevel, age, numBNetFriends, numCharFriends, numGuildMates, isDelisted = C_LFGList.GetSearchResultInfo(resultID); if ( appStatus ~= "none" or pendingStatus or isDelisted ) then return false; end return true; end function LFGListSearchPanel_UpdateResults(self) local offset = HybridScrollFrame_GetOffset(self.ScrollFrame); local buttons = self.ScrollFrame.buttons; --If we have an application selected, deselect it. LFGListSearchPanel_ValidateSelected(self); if ( self.searching ) then self.SearchingSpinner:Show(); self.ScrollFrame.NoResultsFound:Hide(); self.ScrollFrame.StartGroupButton:Hide(); for i=1, #buttons do buttons[i]:Hide(); end else self.SearchingSpinner:Hide(); local results = self.results; local apps = self.applications; for i=1, #buttons do local button = buttons[i]; local idx = i + offset; local result = (idx <= #apps) and apps[idx] or results[idx - #apps]; if ( result ) then button.resultID = result; LFGListSearchEntry_Update(button); button:Show(); else button.resultID = nil; button:Hide(); end end local totalHeight = buttons[1]:GetHeight() * (#results + #apps); --Reanchor the errors to not overlap applications if ( totalHeight < self.ScrollFrame:GetHeight() ) then self.ScrollFrame.NoResultsFound:SetPoint("TOP", self.ScrollFrame, "TOP", 0, -totalHeight - 27); end self.ScrollFrame.NoResultsFound:SetShown(self.totalResults == 0); self.ScrollFrame.StartGroupButton:SetShown(self.totalResults == 0 and not self.searchFailed); self.ScrollFrame.NoResultsFound:SetText(self.searchFailed and LFG_LIST_SEARCH_FAILED or LFG_LIST_NO_RESULTS_FOUND); HybridScrollFrame_Update(self.ScrollFrame, totalHeight, self.ScrollFrame:GetHeight()); end LFGListSearchPanel_UpdateButtonStatus(self); end function LFGListSearchPanel_SelectResult(self, resultID) self.selectedResult = resultID; LFGListSearchPanel_UpdateResults(self); end function LFGListSearchPanel_UpdateButtonStatus(self) --Update the SignUpButton local resultID = self.selectedResult; local numApplications, numActiveApplications = C_LFGList.GetNumApplications(); local messageApply = LFGListUtil_GetActiveQueueMessage(true); local availTank, availHealer, availDPS = C_LFGList.GetAvailableRoles(); if ( messageApply ) then self.SignUpButton:Disable(); self.SignUpButton.tooltip = messageApply; elseif ( not LFGListUtil_IsAppEmpowered() ) then self.SignUpButton:Disable(); self.SignUpButton.tooltip = LFG_LIST_APP_UNEMPOWERED; elseif ( IsInGroup(LE_PARTY_CATEGORY_HOME) and C_LFGList.IsCurrentlyApplying() ) then self.SignUpButton:Disable(); self.SignUpButton.tooltip = LFG_LIST_APP_CURRENTLY_APPLYING; elseif ( numActiveApplications >= MAX_LFG_LIST_APPLICATIONS ) then self.SignUpButton:Disable(); self.SignUpButton.tooltip = string.format(LFG_LIST_HIT_MAX_APPLICATIONS, MAX_LFG_LIST_APPLICATIONS); elseif ( GetNumGroupMembers(LE_PARTY_CATEGORY_HOME) > MAX_PARTY_MEMBERS + 1 ) then self.SignUpButton:Disable(); self.SignUpButton.tooltip = LFG_LIST_MAX_MEMBERS; elseif ( not (availTank or availHealer or availDPS) ) then self.SignUpButton:Disable(); self.SignUpButton.tooltip = LFG_LIST_MUST_CHOOSE_SPEC; elseif ( GroupHasOfflineMember(LE_PARTY_CATEGORY_HOME) ) then self.SignUpButton:Disable(); self.SignUpButton.tooltip = LFG_LIST_OFFLINE_MEMBER; elseif ( resultID ) then self.SignUpButton:Enable(); self.SignUpButton.tooltip = nil; else self.SignUpButton:Disable(); self.SignUpButton.tooltip = LFG_LIST_SELECT_A_SEARCH_RESULT; end --Update the StartGroupButton if ( IsInGroup(LE_PARTY_CATEGORY_HOME) and not UnitIsGroupLeader("player", LE_PARTY_CATEGORY_HOME) ) then self.ScrollFrame.StartGroupButton:Disable(); self.ScrollFrame.StartGroupButton.tooltip = LFG_LIST_NOT_LEADER; else local messageStart = LFGListUtil_GetActiveQueueMessage(false); if ( messageStart ) then self.ScrollFrame.StartGroupButton:Disable(); self.ScrollFrame.StartGroupButton.tooltip = messageStart; else self.ScrollFrame.StartGroupButton:Enable(); self.ScrollFrame.StartGroupButton.tooltip = nil; end end end function LFGListSearchPanel_SignUp(self) LFGListApplicationDialog_Show(LFGListApplicationDialog, self.selectedResult); end function LFGListSearchPanelSearchBox_OnEnterPressed(self) local parent = self:GetParent(); if ( parent.AutoCompleteFrame:IsShown() and parent.AutoCompleteFrame.selected ) then self:SetText( (C_LFGList.GetActivityInfo(parent.AutoCompleteFrame.selected)) ); end LFGListSearchPanel_DoSearch(self:GetParent()); self:ClearFocus(); end function LFGListSearchPanelSearchBox_OnTabPressed(self) if ( IsShiftKeyDown() ) then LFGListSearchPanel_AutoCompleteAdvance(self:GetParent(), -1); else LFGListSearchPanel_AutoCompleteAdvance(self:GetParent(), 1); end end function LFGListSearchPanelSearchBox_OnArrowPressed(self, key) if ( key == "UP" ) then LFGListSearchPanel_AutoCompleteAdvance(self:GetParent(), -1); elseif ( key == "DOWN" ) then LFGListSearchPanel_AutoCompleteAdvance(self:GetParent(), 1); end end function LFGListSearchPanelSearchBox_OnTextChanged(self) SearchBoxTemplate_OnTextChanged(self); LFGListSearchPanel_UpdateAutoComplete(self:GetParent()); end function LFGListSearchAutoCompleteButton_OnClick(self) local panel = self:GetParent():GetParent(); PlaySound("igMainMenuOptionCheckBoxOn"); panel.SearchBox:SetText( (C_LFGList.GetActivityInfo(self.activityID)) ); LFGListSearchPanel_DoSearch(panel); panel.SearchBox:ClearFocus(); end function LFGListSearchPanel_AutoCompleteAdvance(self, offset) local selected = self.AutoCompleteFrame.selected; --Find the index of the current selection and how many results we have displayed local idx = nil; local numDisplayed = 0; for i=1, #self.AutoCompleteFrame.Results do local btn = self.AutoCompleteFrame.Results[i]; if ( btn:IsShown() and btn.activityID ) then numDisplayed = i; if ( btn.activityID == selected ) then idx = i; end else break; end end local newIndex = nil; if ( not idx ) then --We had nothing selected, advance from the front or back if ( offset > 0 ) then newIndex = offset; else newIndex = numDisplayed + 1 + offset; end else --Advance from our old location newIndex = ((idx - 1 + offset + numDisplayed) % numDisplayed) + 1; end self.AutoCompleteFrame.selected = self.AutoCompleteFrame.Results[newIndex].activityID; LFGListSearchPanel_UpdateAutoComplete(self); end function LFGListSearchPanel_UpdateAutoComplete(self) local text = self.SearchBox:GetText(); if ( text == "" or not self.SearchBox:HasFocus() ) then self.AutoCompleteFrame:Hide(); self.AutoCompleteFrame.selected = nil; return; end --Choose the autocomplete results local matchingActivities = C_LFGList.GetAvailableActivities(self.categoryID, nil, self.filters, text); LFGListUtil_SortActivitiesByRelevancy(matchingActivities); local numResults = math.min(#matchingActivities, MAX_LFG_LIST_SEARCH_AUTOCOMPLETE_ENTRIES); if ( numResults == 0 ) then self.AutoCompleteFrame:Hide(); self.AutoCompleteFrame.selected = nil; return; end --Update the buttons local foundSelected = false; for i=1, numResults do local id = matchingActivities[i]; local button = self.AutoCompleteFrame.Results[i]; if ( not button ) then button = CreateFrame("BUTTON", nil, self.AutoCompleteFrame, "LFGListSearchAutoCompleteButtonTemplate"); button:SetPoint("TOPLEFT", self.AutoCompleteFrame.Results[i-1], "BOTTOMLEFT", 0, 0); button:SetPoint("TOPRIGHT", self.AutoCompleteFrame.Results[i-1], "BOTTOMRIGHT", 0, 0); self.AutoCompleteFrame.Results[i] = button; end if ( i == numResults and numResults < #matchingActivities ) then --This is just a "x more" button button:SetFormattedText(LFG_LIST_AND_MORE, #matchingActivities - numResults + 1); button:Disable(); button.Selected:Hide(); button.activityID = nil; else --This is an actual activity button:SetText( (C_LFGList.GetActivityInfo(id)) ); button:Enable(); button.activityID = id; if ( id == self.AutoCompleteFrame.selected ) then button.Selected:Show(); foundSelected = true; else button.Selected:Hide(); end end button:Show(); end if ( not foundSelected ) then self.selected = nil; end --Hide unused buttons for i=numResults + 1, #self.AutoCompleteFrame.Results do self.AutoCompleteFrame.Results[i]:Hide(); end --Update the frames height and show it self.AutoCompleteFrame:SetHeight(numResults * self.AutoCompleteFrame.Results[1]:GetHeight() + 8); self.AutoCompleteFrame:Show(); end function LFGListSearchEntry_OnLoad(self) self:RegisterEvent("LFG_LIST_SEARCH_RESULT_UPDATED"); self:RegisterEvent("LFG_ROLE_CHECK_UPDATE"); self:RegisterForClicks("LeftButtonUp", "RightButtonUp"); end function LFGListSearchEntry_Update(self) local resultID = self.resultID; local _, appStatus, pendingStatus, appDuration = C_LFGList.GetApplicationInfo(resultID); local isApplication = (appStatus ~= "none" or pendingStatus); local isAppFinished = LFGListUtil_IsStatusInactive(appStatus) or LFGListUtil_IsStatusInactive(pendingStatus); --Update visibility based on whether we're an application or not self.isApplication = isApplication; self.ApplicationBG:SetShown(isApplication and not isAppFinished); self.ResultBG:SetShown(not isApplication or isAppFinished); self.DataDisplay:SetShown(not isApplication); self.CancelButton:SetShown(isApplication and pendingStatus ~= "applied"); self.CancelButton:SetEnabled(LFGListUtil_IsAppEmpowered()); self.CancelButton.Icon:SetDesaturated(not LFGListUtil_IsAppEmpowered()); self.CancelButton.tooltip = (not LFGListUtil_IsAppEmpowered()) and LFG_LIST_APP_UNEMPOWERED; self.Spinner:SetShown(pendingStatus == "applied"); if ( pendingStatus == "applied" and C_LFGList.GetRoleCheckInfo() ) then self.PendingLabel:SetText(LFG_LIST_ROLE_CHECK); self.PendingLabel:SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b); self.PendingLabel:Show(); self.ExpirationTime:Hide(); self.CancelButton:Hide(); elseif ( pendingStatus == "cancelled" or appStatus == "cancelled" or appStatus == "failed" ) then self.PendingLabel:SetText(LFG_LIST_APP_CANCELLED); self.PendingLabel:SetTextColor(RED_FONT_COLOR.r, RED_FONT_COLOR.g, RED_FONT_COLOR.b); self.PendingLabel:Show(); self.ExpirationTime:Hide(); self.CancelButton:Hide(); elseif ( appStatus == "declined" ) then self.PendingLabel:SetText(LFG_LIST_APP_DECLINED); self.PendingLabel:SetTextColor(RED_FONT_COLOR.r, RED_FONT_COLOR.g, RED_FONT_COLOR.b); self.PendingLabel:Show(); self.ExpirationTime:Hide(); self.CancelButton:Hide(); elseif ( appStatus == "timedout" ) then self.PendingLabel:SetText(LFG_LIST_APP_TIMED_OUT); self.PendingLabel:SetTextColor(RED_FONT_COLOR.r, RED_FONT_COLOR.g, RED_FONT_COLOR.b); self.PendingLabel:Show(); self.ExpirationTime:Hide(); self.CancelButton:Hide(); elseif ( appStatus == "invited" ) then self.PendingLabel:SetText(LFG_LIST_APP_INVITED); self.PendingLabel:SetTextColor(GREEN_FONT_COLOR.r, GREEN_FONT_COLOR.g, GREEN_FONT_COLOR.b); self.PendingLabel:Show(); self.ExpirationTime:Hide(); self.CancelButton:Hide(); elseif ( appStatus == "inviteaccepted" ) then self.PendingLabel:SetText(LFG_LIST_APP_INVITE_ACCEPTED); self.PendingLabel:SetTextColor(GREEN_FONT_COLOR.r, GREEN_FONT_COLOR.g, GREEN_FONT_COLOR.b); self.PendingLabel:Show(); self.ExpirationTime:Hide(); self.CancelButton:Hide(); elseif ( appStatus == "invitedeclined" ) then self.PendingLabel:SetText(LFG_LIST_APP_INVITE_DECLINED); self.PendingLabel:SetTextColor(RED_FONT_COLOR.r, RED_FONT_COLOR.g, RED_FONT_COLOR.b); self.PendingLabel:Show(); self.ExpirationTime:Hide(); self.CancelButton:Hide(); elseif ( isApplication and pendingStatus ~= "applied" ) then self.PendingLabel:SetText(LFG_LIST_PENDING); self.PendingLabel:SetTextColor(GREEN_FONT_COLOR.r, GREEN_FONT_COLOR.g, GREEN_FONT_COLOR.b); self.PendingLabel:Show(); self.ExpirationTime:Show(); self.CancelButton:Show(); else self.PendingLabel:Hide(); self.ExpirationTime:Hide(); self.CancelButton:Hide(); end --Center justify if we're on more than one line if ( self.PendingLabel:GetHeight() > 15 ) then self.PendingLabel:SetJustifyH("CENTER"); else self.PendingLabel:SetJustifyH("RIGHT"); end --Change the anchor of the label depending on whether we have the expiration time if ( self.ExpirationTime:IsShown() ) then self.PendingLabel:SetPoint("RIGHT", self.ExpirationTime, "LEFT", -3, 0); else self.PendingLabel:SetPoint("RIGHT", self.ExpirationTime, "RIGHT", -3, 0); end self.expiration = GetTime() + appDuration; local panel = self:GetParent():GetParent():GetParent(); local id, activityID, name, comment, voiceChat, iLvl, honorLevel, age, numBNetFriends, numCharFriends, numGuildMates, isDelisted = C_LFGList.GetSearchResultInfo(resultID); local activityName = C_LFGList.GetActivityInfo(activityID); self.resultID = resultID; self.Selected:SetShown(panel.selectedResult == resultID and not isApplication and not isDelisted); self.Highlight:SetShown(panel.selectedResult ~= resultID and not isApplication and not isDelisted); local nameColor = NORMAL_FONT_COLOR; local activityColor = GRAY_FONT_COLOR; if ( isDelisted or isAppFinished ) then nameColor = LFG_LIST_DELISTED_FONT_COLOR; activityColor = LFG_LIST_DELISTED_FONT_COLOR; elseif ( numBNetFriends > 0 or numCharFriends > 0 or numGuildMates > 0 ) then nameColor = BATTLENET_FONT_COLOR; end self.Name:SetWidth(0); self.Name:SetText(name); self.Name:SetTextColor(nameColor.r, nameColor.g, nameColor.b); self.ActivityName:SetText(activityName); self.ActivityName:SetTextColor(activityColor.r, activityColor.g, activityColor.b); self.VoiceChat:SetShown(voiceChat ~= ""); self.VoiceChat.tooltip = voiceChat; local displayData = C_LFGList.GetSearchResultMemberCounts(resultID); LFGListGroupDataDisplay_Update(self.DataDisplay, activityID, displayData, isDelisted); local nameWidth = isApplication and 165 or 176; if ( voiceChat ~= "" ) then nameWidth = nameWidth - 22; end if ( self.Name:GetWidth() > nameWidth ) then self.Name:SetWidth(nameWidth); end self.ActivityName:SetWidth(nameWidth); local mouseFocus = GetMouseFocus(); if ( mouseFocus == self ) then LFGListSearchEntry_OnEnter(self); end if ( mouseFocus == self.VoiceChat ) then mouseFocus:GetScript("OnEnter")(mouseFocus); end if ( isApplication ) then self:SetScript("OnUpdate", LFGListSearchEntry_UpdateExpiration); LFGListSearchEntry_UpdateExpiration(self); else self:SetScript("OnUpdate", nil); end end function LFGListSearchEntry_UpdateExpiration(self) local duration = 0; local now = GetTime(); if ( self.expiration and self.expiration > now ) then duration = self.expiration - now; end local minutes = math.floor(duration / 60); local seconds = duration % 60; self.ExpirationTime:SetFormattedText("%d:%.2d", minutes, seconds); end function LFGListSearchEntry_OnEvent(self, event, ...) if ( event == "LFG_LIST_SEARCH_RESULT_UPDATED" ) then local id = ...; if ( id == self.resultID ) then LFGListSearchEntry_Update(self); end elseif ( event == "LFG_ROLE_CHECK_UPDATE" ) then if ( self.resultID ) then LFGListSearchEntry_Update(self); end end end function LFGListSearchEntry_OnClick(self, button) local scrollFrame = self:GetParent():GetParent(); if ( button == "RightButton" ) then PlaySound("igMainMenuOptionCheckBoxOn"); EasyMenu(LFGListUtil_GetSearchEntryMenu(self.resultID), LFGListFrameDropDown, self, 0, -2, "MENU"); elseif ( scrollFrame:GetParent().selectedResult ~= self.resultID and LFGListSearchPanelUtil_CanSelectResult(self.resultID) ) then PlaySound("igMainMenuOptionCheckBoxOn"); LFGListSearchPanel_SelectResult(scrollFrame:GetParent(), self.resultID); end end function LFGListSearchEntry_OnEnter(self) local resultID = self.resultID; local id, activityID, name, comment, voiceChat, iLvl, honorLevel, age, numBNetFriends, numCharFriends, numGuildMates, isDelisted, leaderName, numMembers = C_LFGList.GetSearchResultInfo(resultID); local activityName, shortName, categoryID, groupID, minItemLevel, filters, minLevel, maxPlayers, displayType, _, useHonorLevel = C_LFGList.GetActivityInfo(activityID); local memberCounts = C_LFGList.GetSearchResultMemberCounts(resultID); GameTooltip:SetOwner(self, "ANCHOR_RIGHT", 25, 0); GameTooltip:SetText(name, 1, 1, 1, true); GameTooltip:AddLine(activityName); if ( comment ~= "" ) then GameTooltip:AddLine(string.format(LFG_LIST_COMMENT_FORMAT, comment), LFG_LIST_COMMENT_FONT_COLOR.r, LFG_LIST_COMMENT_FONT_COLOR.g, LFG_LIST_COMMENT_FONT_COLOR.b, true); end GameTooltip:AddLine(" "); if ( iLvl > 0 ) then GameTooltip:AddLine(string.format(LFG_LIST_TOOLTIP_ILVL, iLvl)); end if ( useHonorLevel and honorLevel > 0 ) then GameTooltip:AddLine(string.format(LFG_LIST_TOOLTIP_HONOR_LEVEL, honorLevel)); end if ( voiceChat ~= "" ) then GameTooltip:AddLine(string.format(LFG_LIST_TOOLTIP_VOICE_CHAT, voiceChat), nil, nil, nil, true); end if ( iLvl > 0 or (useHonorLevel and honorLevel > 0) or voiceChat ~= "" ) then GameTooltip:AddLine(" "); end if ( leaderName ) then GameTooltip:AddLine(string.format(LFG_LIST_TOOLTIP_LEADER, leaderName)); end if ( age > 0 ) then GameTooltip:AddLine(string.format(LFG_LIST_TOOLTIP_AGE, SecondsToTime(age, false, false, 1, false))); end if ( leaderName or age > 0 ) then GameTooltip:AddLine(" "); end if ( displayType == LE_LFG_LIST_DISPLAY_TYPE_CLASS_ENUMERATE ) then GameTooltip:AddLine(string.format(LFG_LIST_TOOLTIP_MEMBERS_SIMPLE, numMembers)); for i=1, numMembers do local role, class, classLocalized = C_LFGList.GetSearchResultMemberInfo(resultID, i); local classColor = RAID_CLASS_COLORS[class] or NORMAL_FONT_COLOR; GameTooltip:AddLine(string.format(LFG_LIST_TOOLTIP_CLASS_ROLE, classLocalized, _G[role]), classColor.r, classColor.g, classColor.b); end else GameTooltip:AddLine(string.format(LFG_LIST_TOOLTIP_MEMBERS, numMembers, memberCounts.TANK, memberCounts.HEALER, memberCounts.DAMAGER)); end if ( numBNetFriends + numCharFriends + numGuildMates > 0 ) then GameTooltip:AddLine(" "); GameTooltip:AddLine(LFG_LIST_TOOLTIP_FRIENDS_IN_GROUP); GameTooltip:AddLine(LFGListSearchEntryUtil_GetFriendList(resultID), 1, 1, 1, true); end local completedEncounters = C_LFGList.GetSearchResultEncounterInfo(resultID); if ( completedEncounters and #completedEncounters > 0 ) then GameTooltip:AddLine(" "); GameTooltip:AddLine(LFG_LIST_BOSSES_DEFEATED); for i=1, #completedEncounters do GameTooltip:AddLine(completedEncounters[i], RED_FONT_COLOR.r, RED_FONT_COLOR.g, RED_FONT_COLOR.b); end end if ( isDelisted ) then GameTooltip:AddLine(" "); GameTooltip:AddLine(LFG_LIST_ENTRY_DELISTED, RED_FONT_COLOR.r, RED_FONT_COLOR.g, RED_FONT_COLOR.b, true); end GameTooltip:Show(); end function LFGListSearchEntryUtil_GetFriendList(resultID) local list = ""; local bNetFriends, charFriends, guildMates = C_LFGList.GetSearchResultFriends(resultID); local displayedFirst = false; --BNet friends for i=1, #bNetFriends do if ( displayedFirst ) then list = list..PLAYER_LIST_DELIMITER; else displayedFirst = true; end list = list..FRIENDS_BNET_NAME_COLOR_CODE..bNetFriends[i]..FONT_COLOR_CODE_CLOSE; end --Character friends for i=1, #charFriends do if ( displayedFirst ) then list = list..PLAYER_LIST_DELIMITER; else displayedFirst = true; end list = list..FRIENDS_WOW_NAME_COLOR_CODE..charFriends[i]..FONT_COLOR_CODE_CLOSE; end --Guild mates for i=1, #guildMates do if ( displayedFirst ) then list = list..PLAYER_LIST_DELIMITER; else displayedFirst = true; end list = list..RGBTableToColorCode(ChatTypeInfo.GUILD)..guildMates[i]..FONT_COLOR_CODE_CLOSE; end return list; end ------------------------------------------------------- ----------Application dialog functions ------------------------------------------------------- function LFGListApplicationDialog_OnLoad(self) self:RegisterEvent("LFG_ROLE_UPDATE"); self.Description.EditBox:SetScript("OnEnterPressed", nop); self.hideOnEscape = true; end function LFGListApplicationDialog_OnEvent(self, event) if ( event == "LFG_ROLE_UPDATE" ) then LFGListApplicationDialog_UpdateRoles(self); end end function LFGListApplicationDialog_Show(self, resultID) self.resultID = resultID; self.Description.EditBox:SetText(""); LFGListApplicationDialog_UpdateRoles(self); StaticPopupSpecial_Show(self); end function LFGListApplicationDialog_UpdateRoles(self) local availTank, availHealer, availDPS = C_LFGList.GetAvailableRoles(); local avail1, avail2; if ( availTank ) then avail1 = self.TankButton; end if ( availHealer ) then if ( avail1 ) then avail2 = self.HealerButton; else avail1 = self.HealerButton; end end if ( availDPS ) then if ( avail1 ) then avail2 = self.DamagerButton; else avail1 = self.DamagerButton; end end self.TankButton:SetShown(availTank); self.HealerButton:SetShown(availHealer); self.DamagerButton:SetShown(availDPS); if ( avail2 ) then avail1:ClearAllPoints(); avail1:SetPoint("TOPRIGHT", self, "TOP", -5, -35); avail2:ClearAllPoints(); avail2:SetPoint("TOPLEFT", self, "TOP", 5, -35); elseif ( avail1 ) then avail1:ClearAllPoints(); avail1:SetPoint("TOP", self, "TOP", 0, -35); end local _, tank, healer, dps = GetLFGRoles(); self.TankButton.CheckButton:SetChecked(tank); self.HealerButton.CheckButton:SetChecked(healer); self.DamagerButton.CheckButton:SetChecked(dps); LFGListApplicationDialog_UpdateValidState(self); end function LFGListApplicationDialog_UpdateValidState(self) if ( ( self.TankButton:IsShown() and self.TankButton.CheckButton:GetChecked()) or ( self.HealerButton:IsShown() and self.HealerButton.CheckButton:GetChecked()) or ( self.DamagerButton:IsShown() and self.DamagerButton.CheckButton:GetChecked()) ) then self.SignUpButton:Enable(); self.SignUpButton.errorText = nil; else self.SignUpButton:Disable(); self.SignUpButton.errorText = LFG_LIST_MUST_SELECT_ROLE; end end function LFGListRoleButtonCheckButton_OnClick(self) if ( self:GetChecked() ) then PlaySound("igMainMenuOptionCheckBoxOn"); else PlaySound("igMainMenuOptionCheckBoxOff"); end local dialog = self:GetParent():GetParent(); local leader, tank, healer, dps = GetLFGRoles(); SetLFGRoles(leader, dialog.TankButton.CheckButton:GetChecked(), dialog.HealerButton.CheckButton:GetChecked(), dialog.DamagerButton.CheckButton:GetChecked()); end ------------------------------------------------------- ----------Invite dialog functions ------------------------------------------------------- function LFGListInviteDialog_OnLoad(self) self:RegisterEvent("LFG_LIST_SEARCH_RESULTS_RECEIVED"); self:RegisterEvent("LFG_LIST_SEARCH_RESULT_UPDATED"); self:RegisterEvent("LFG_LIST_JOINED_GROUP"); self:RegisterEvent("PARTY_LEADER_CHANGED"); self:RegisterEvent("UNIT_CONNECTION"); end function LFGListInviteDialog_OnEvent(self, event, ...) if ( event == "LFG_LIST_SEARCH_RESULTS_RECEIVED" ) then LFGListInviteDialog_CheckPending(self); elseif ( event == "LFG_LIST_SEARCH_RESULT_UPDATED" ) then local id = ...; local _, status, pendingStatus = C_LFGList.GetApplicationInfo(id); local empowered = LFGListUtil_IsAppEmpowered(); if ( self.resultID == id and not self.informational and (status ~= "invited" or not empowered) ) then --Check if we need to hide the panel StaticPopupSpecial_Hide(self); LFGListInviteDialog_CheckPending(self); elseif ( status == "invited" and not pendingStatus ) then --Check if we need to show this result LFGListInviteDialog_CheckPending(self); end elseif ( event == "PARTY_LEADER_CHANGED" ) then --Check if we need to hide the current panel if ( not LFGListUtil_IsAppEmpowered() and self:IsShown() and not self.informational ) then StaticPopupSpecial_Hide(self); end --Check if we need to show any panels LFGListInviteDialog_CheckPending(self); elseif ( event == "LFG_LIST_JOINED_GROUP" ) then if ( not LFGListUtil_IsAppEmpowered() ) then --Show the informational dialog, regardless of whether we already had something up local id = ...; StaticPopupSpecial_Hide(self); LFGListInviteDialog_Show(self, id); end elseif ( event == "UNIT_CONNECTION" ) then LFGListInviteDialog_UpdateOfflineNotice(self); end end function LFGListInviteDialog_CheckPending(self) --If we're already showing one, don't replace it if ( self:IsShown() ) then return; end --If we're not empowered to make changes to applications, don't pop up anything. if ( not LFGListUtil_IsAppEmpowered() ) then return; end local apps = C_LFGList.GetApplications(); for i=1, #apps do local id, status, pendingStatus = C_LFGList.GetApplicationInfo(apps[i]); if ( status == "invited" and not pendingStatus ) then LFGListInviteDialog_Show(self, apps[i]); return; end end end function LFGListInviteDialog_Show(self, resultID) local id, activityID, name, comment, voiceChat, iLvl, honorLevel, age, numBNetFriends, numCharFriends, numGuildMates, isDelisted = C_LFGList.GetSearchResultInfo(resultID); local activityName = C_LFGList.GetActivityInfo(activityID); local _, status, _, _, role = C_LFGList.GetApplicationInfo(resultID); local informational = (status ~= "invited"); assert(not informational or status == "inviteaccepted"); self.resultID = resultID; self.GroupName:SetText(name); self.ActivityName:SetText(activityName); self.Role:SetText(_G[role]); self.RoleIcon:SetTexCoord(GetTexCoordsForRole(role)); self.Label:SetText(informational and LFG_LIST_JOINED_GROUP_NOTICE or LFG_LIST_INVITED_TO_GROUP); self.informational = informational; self.AcceptButton:SetShown(not informational); self.DeclineButton:SetShown(not informational); self.AcknowledgeButton:SetShown(informational); if ( not informational and GroupHasOfflineMember(LE_PARTY_CATEGORY_HOME) ) then self:SetHeight(250); self.OfflineNotice:Show(); LFGListInviteDialog_UpdateOfflineNotice(self); else self:SetHeight(210); self.OfflineNotice:Hide(); end StaticPopupSpecial_Show(self); PlaySound("ReadyCheck"); FlashClientIcon(); end function LFGListInviteDialog_UpdateOfflineNotice(self) if ( GroupHasOfflineMember(LE_PARTY_CATEGORY_HOME) ) then self.OfflineNotice:SetText(LFG_LIST_OFFLINE_MEMBER_NOTICE); self.OfflineNotice:SetFontObject(GameFontRed); else self.OfflineNotice:SetText(LFG_LIST_OFFLINE_MEMBER_NOTICE_GONE); self.OfflineNotice:SetFontObject(GameFontGreen); end end function LFGListInviteDialog_Accept(self) C_LFGList.AcceptInvite(self.resultID); StaticPopupSpecial_Hide(self); LFGListInviteDialog_CheckPending(self); end function LFGListInviteDialog_Decline(self) C_LFGList.DeclineInvite(self.resultID); StaticPopupSpecial_Hide(self); LFGListInviteDialog_CheckPending(self); end function LFGListInviteDialog_Acknowledge(self) StaticPopupSpecial_Hide(self); LFGListInviteDialog_CheckPending(self); end ------------------------------------------------------- ----------Group Data Display functions ------------------------------------------------------- function LFGListGroupDataDisplay_Update(self, activityID, displayData, disabled) local fullName, shortName, categoryID, groupID, iLevel, filters, minLevel, maxPlayers, displayType = C_LFGList.GetActivityInfo(activityID); if ( displayType == LE_LFG_LIST_DISPLAY_TYPE_ROLE_COUNT ) then self.RoleCount:Show(); self.Enumerate:Hide(); self.PlayerCount:Hide(); LFGListGroupDataDisplayRoleCount_Update(self.RoleCount, displayData, disabled); elseif ( displayType == LE_LFG_LIST_DISPLAY_TYPE_ROLE_ENUMERATE ) then self.RoleCount:Hide(); self.Enumerate:Show(); self.PlayerCount:Hide(); LFGListGroupDataDisplayEnumerate_Update(self.Enumerate, maxPlayers, displayData, disabled, LFG_LIST_GROUP_DATA_ROLE_ORDER); elseif ( displayType == LE_LFG_LIST_DISPLAY_TYPE_CLASS_ENUMERATE ) then self.RoleCount:Hide(); self.Enumerate:Show(); self.PlayerCount:Hide(); LFGListGroupDataDisplayEnumerate_Update(self.Enumerate, maxPlayers, displayData, disabled, LFG_LIST_GROUP_DATA_CLASS_ORDER); elseif ( displayType == LE_LFG_LIST_DISPLAY_TYPE_PLAYER_COUNT ) then self.RoleCount:Hide(); self.Enumerate:Hide(); self.PlayerCount:Show(); LFGListGroupDataDisplayPlayerCount_Update(self.PlayerCount, displayData, disabled); elseif ( displayType == LE_LFG_LIST_DISPLAY_TYPE_HIDE_ALL ) then self.RoleCount:Hide(); self.Enumerate:Hide(); self.PlayerCount:Hide(); else GMError("Unknown display type"); self.RoleCount:Hide(); self.Enumerate:Hide(); self.PlayerCount:Hide(); end end function LFGListGroupDataDisplayRoleCount_Update(self, displayData, disabled) self.TankCount:SetText(displayData.TANK); self.HealerCount:SetText(displayData.HEALER); self.DamagerCount:SetText(displayData.DAMAGER); --Update for the disabled state local r = disabled and LFG_LIST_DELISTED_FONT_COLOR.r or HIGHLIGHT_FONT_COLOR.r; local g = disabled and LFG_LIST_DELISTED_FONT_COLOR.g or HIGHLIGHT_FONT_COLOR.g; local b = disabled and LFG_LIST_DELISTED_FONT_COLOR.b or HIGHLIGHT_FONT_COLOR.b; self.TankCount:SetTextColor(r, g, b); self.HealerCount:SetTextColor(r, g, b); self.DamagerCount:SetTextColor(r, g, b); self.TankIcon:SetDesaturated(disabled); self.HealerIcon:SetDesaturated(disabled); self.DamagerIcon:SetDesaturated(disabled); self.TankIcon:SetAlpha(disabled and 0.5 or 0.70); self.HealerIcon:SetAlpha(disabled and 0.5 or 0.70); self.DamagerIcon:SetAlpha(disabled and 0.5 or 0.70); end function LFGListGroupDataDisplayEnumerate_Update(self, numPlayers, displayData, disabled, iconOrder) --Show/hide the required icons for i=1, #self.Icons do if ( i > numPlayers ) then self.Icons[i]:Hide(); else self.Icons[i]:Show(); self.Icons[i]:SetDesaturated(disabled); self.Icons[i]:SetAlpha(disabled and 0.5 or 1.0); end end --Note that icons are numbered from right to left local iconIndex = numPlayers; for i=1, #iconOrder do for j=1, displayData[iconOrder[i]] do self.Icons[iconIndex]:SetAtlas(LFG_LIST_GROUP_DATA_ATLASES[iconOrder[i]], false); iconIndex = iconIndex - 1; if ( iconIndex < 1 ) then return; end end end for i=1, iconIndex do self.Icons[i]:SetAtlas("groupfinder-icon-emptyslot", false); end end function LFGListGroupDataDisplayPlayerCount_Update(self, displayData, disabled) local numPlayers = displayData.TANK + displayData.HEALER + displayData.DAMAGER + displayData.NOROLE; local color = disabled and LFG_LIST_DELISTED_FONT_COLOR or HIGHLIGHT_FONT_COLOR; self.Count:SetText(numPlayers); self.Count:SetTextColor(color.r, color.g, color.b); self.Icon:SetDesaturated(disabled); self.Icon:SetAlpha(disabled and 0.5 or 1); end ------------------------------------------------------- ----------Edit Box functions ------------------------------------------------------- function LFGListEditBox_AddToTabCategory(self, tabCategory) self.tabCategory = tabCategory; local cat = LFG_LIST_EDIT_BOX_TAB_CATEGORIES[tabCategory]; if ( not cat ) then cat = {}; LFG_LIST_EDIT_BOX_TAB_CATEGORIES[tabCategory] = cat; end self.tabCategoryIndex = #cat+1; cat[self.tabCategoryIndex] = self; end function LFGListEditBox_OnTabPressed(self) if ( self.tabCategory ) then local offset = IsShiftKeyDown() and -1 or 1; local cat = LFG_LIST_EDIT_BOX_TAB_CATEGORIES[self.tabCategory]; if ( cat ) then --It's times like this when I wish Lua was 0-based... cat[((self.tabCategoryIndex - 1 + offset + #cat) % #cat) + 1]:SetFocus(); end end end ------------------------------------------------------- ----------Requirement functions ------------------------------------------------------- function LFGListRequirement_Validate(self, text) if ( self.validateFunc ) then self.warningText = self:validateFunc(text); self.WarningFrame:SetShown(self.warningText); self.CheckButton:SetShown(not self.warningText); end LFGListEntryCreation_UpdateValidState(self:GetParent()); end ------------------------------------------------------- ----------Utility functions ------------------------------------------------------- function LFGListUtil_AugmentWithBest(filters, categoryID, groupID, activityID) local myNumMembers = math.max(GetNumGroupMembers(LE_PARTY_CATEGORY_HOME), 1); local myItemLevel = GetAverageItemLevel(); if ( not activityID ) then --Find the best activity by iLevel and recommended flag local activities = C_LFGList.GetAvailableActivities(categoryID, groupID, filters); local bestItemLevel, bestRecommended, bestCurrentArea, bestMinLevel, bestMaxPlayers; for i=1, #activities do local fullName, shortName, categoryID, groupID, iLevel, filters, minLevel, maxPlayers, displayType, orderIndex, useHonorLevel = C_LFGList.GetActivityInfo(activities[i]); local isRecommended = bit.band(filters, LE_LFG_LIST_FILTER_RECOMMENDED) ~= 0; local currentArea = C_LFGList.GetActivityInfoExpensive(activities[i]); local usedItemLevel = myItemLevel; local isBetter = false; if ( not activityID ) then isBetter = true; elseif ( currentArea ~= bestCurrentArea ) then isBetter = currentArea; elseif ( bestRecommended ~= isRecommended ) then isBetter = isRecommended; elseif ( bestMinLevel ~= minLevel ) then isBetter = minLevel > bestMinLevel; elseif ( iLevel ~= bestItemLevel ) then isBetter = (iLevel > bestItemLevel and iLevel <= usedItemLevel) or (iLevel <= usedItemLevel and bestItemLevel > usedItemLevel) or (iLevel < bestItemLevel and iLevel > usedItemLevel); elseif ( (myNumMembers < maxPlayers) ~= (myNumMembers < bestMaxPlayers) ) then isBetter = myNumMembers < maxPlayers; end if ( isBetter ) then activityID = activities[i]; bestItemLevel = iLevel; bestRecommended = isRecommended; bestCurrentArea = currentArea; bestMinLevel = minLevel; bestMaxPlayers = maxPlayers; end end end assert(activityID); --Update the categoryID and groupID with what we get from the activity categoryID, groupID, _, filters = select(ACTIVITY_RETURN_VALUES.categoryID, C_LFGList.GetActivityInfo(activityID)); --Update the filters if needed local _, separateRecommended = C_LFGList.GetCategoryInfo(categoryID); if ( separateRecommended ) then if ( bit.band(filters, LE_LFG_LIST_FILTER_RECOMMENDED) == 0 ) then filters = LE_LFG_LIST_FILTER_NOT_RECOMMENDED; else filters = LE_LFG_LIST_FILTER_RECOMMENDED; end else filters = 0; end return filters, categoryID, groupID, activityID; end function LFGListUtil_SetUpDropDown(context, dropdown, populateFunc, onClickFunc) local onClick = function(self, ...) onClickFunc(context, self.value, ...); end local initialize = function(self) local info = UIDropDownMenu_CreateInfo(); info.func = onClick; populateFunc(context, dropdown, info); end dropdown:SetScript("OnShow", function(self) UIDropDownMenu_SetWidth(self, dropdown:GetWidth() - 50); UIDropDownMenu_Initialize(self, initialize); end); UIDropDownMenu_JustifyText(dropdown, "LEFT"); UIDropDownMenu_SetAnchor(dropdown, -20, 7, "TOPRIGHT", dropdown, "BOTTOMRIGHT"); end function LFGListUtil_ValidateLevelReq(self, text) local myItemLevel = GetAverageItemLevel(); if ( text ~= "" and tonumber(text) > myItemLevel) then return LFG_LIST_ILVL_ABOVE_YOURS; end end function LFGListUtil_ValidateHonorLevelReq(self, text) local myHonorLevel = UnitHonorLevel("player"); if (text ~= "" and tonumber(text) > myHonorLevel) then return LFG_LIST_HONOR_LEVEL_ABOVE_YOURS; end end function LFGListUtil_GetCurrentExpansion() for i=0, #MAX_PLAYER_LEVEL_TABLE do if ( UnitLevel("player") <= MAX_PLAYER_LEVEL_TABLE[i] ) then return i; end end --We're higher than the highest level. Weird. return #MAX_PLAYER_LEVEL_TABLE; end function LFGListUtil_GetDecoratedCategoryName(categoryName, filter, useColors) if ( filter == 0 ) then return categoryName; end local colorStart = ""; local colorEnd = ""; if ( useColors ) then colorStart = "|cffffffff"; colorEnd = "|r"; end local extraName = ""; if ( filter == LE_LFG_LIST_FILTER_NOT_RECOMMENDED ) then extraName = LFG_LIST_LEGACY; elseif ( filter == LE_LFG_LIST_FILTER_RECOMMENDED ) then local exp = LFGListUtil_GetCurrentExpansion(); extraName = _G["EXPANSION_NAME"..exp]; end return string.format(LFG_LIST_CATEGORY_FORMAT, categoryName, colorStart, extraName, colorEnd); end function LFGListUtil_SortSearchResultsCB(id1, id2) local id1, activityID1, name1, comment1, voiceChat1, iLvl1, honorLevel1, age1, numBNetFriends1, numCharFriends1, numGuildMates1, isDelisted1 = C_LFGList.GetSearchResultInfo(id1); local id2, activityID2, name2, comment2, voiceChat2, iLvl2, honorLevel2, age2, numBNetFriends2, numCharFriends2, numGuildMates2, isDelisted2 = C_LFGList.GetSearchResultInfo(id2); --If one has more friends, do that one first if ( numBNetFriends1 ~= numBNetFriends2 ) then return numBNetFriends1 > numBNetFriends2; end if ( numCharFriends1 ~= numCharFriends2 ) then return numCharFriends1 > numCharFriends2; end if ( numGuildMates1 ~= numGuildMates2 ) then return numGuildMates1 > numGuildMates2; end --If we aren't sorting by anything else, just go by ID return id1 < id2; end function LFGListUtil_SortSearchResults(results) table.sort(results, LFGListUtil_SortSearchResultsCB); end function LFGListUtil_FilterApplicants(applicants) --[[for i=#applicants, 1, -1 do local id, status, pendingStatus, numMembers, isNew = C_LFGList.GetApplicantInfo(applicants[i]); if ( status ~= "applied" and status ~= "invited" ) then --Remove this applicant. Don't worry about order. applicants[i] = applicants[#applicants]; applicants[#applicants] = nil; end end--]] end function LFGListUtil_SortApplicantsCB(id1, id2) local _, _, _, _, isNew1, _, orderID1 = C_LFGList.GetApplicantInfo(id1); local _, _, _, _, isNew2, _, orderID2 = C_LFGList.GetApplicantInfo(id2); --New items go to the bottom if ( isNew1 ~= isNew2 ) then return isNew2; end return orderID1 < orderID2; end function LFGListUtil_SortApplicants(applicants) table.sort(applicants, LFGListUtil_SortApplicantsCB); end function LFGListUtil_IsAppEmpowered() return not IsInGroup(LE_PARTY_CATEGORY_HOME) or UnitIsGroupLeader("player", LE_PARTY_CATEGORY_HOME); end function LFGListUtil_IsEntryEmpowered() return UnitIsGroupLeader("player", LE_PARTY_CATEGORY_HOME) or UnitIsGroupAssistant("player", LE_PARTY_CATEGORY_HOME); end function LFGListUtil_AppendStatistic(label, value, title, lastTitle) if ( title ~= lastTitle ) then GameTooltip:AddLine(" "); GameTooltip:AddLine(title, 1, 1, 1); end GameTooltip:AddLine(string.format(label, value)); end local LFG_LIST_SEARCH_ENTRY_MENU = { { text = nil, --Group name goes here isTitle = true, notCheckable = true, }, { text = WHISPER_LEADER, func = function(_, name) ChatFrame_SendTell(name); end, notCheckable = true, arg1 = nil, --Leader name goes here disabled = nil, --Disabled if we don't have a leader name yet or you haven't applied tooltipWhileDisabled = 1, tooltipOnButton = 1, tooltipTitle = nil, --The title to display on mouseover tooltipText = nil, --The text to display on mouseover }, { text = LFG_LIST_REPORT_GROUP_FOR, hasArrow = true, notCheckable = true, menuList = { { text = LFG_LIST_BAD_NAME, func = function(_, id) C_LFGList.ReportSearchResult(id, "lfglistname"); end, arg1 = nil, --Search result ID goes here notCheckable = true, }, { text = LFG_LIST_BAD_DESCRIPTION, func = function(_, id) C_LFGList.ReportSearchResult(id, "lfglistcomment"); end, arg1 = nil, --Search reuslt ID goes here notCheckable = true, disabled = nil, --Disabled if the description is just an empty string }, { text = LFG_LIST_BAD_VOICE_CHAT_COMMENT, func = function(_, id) C_LFGList.ReportSearchResult(id, "lfglistvoicechat"); end, arg1 = nil, --Search reuslt ID goes here notCheckable = true, disabled = nil, --Disabled if the description is just an empty string }, { text = LFG_LIST_BAD_LEADER_NAME, func = function(_, id) C_LFGList.ReportSearchResult(id, "badplayername"); end, arg1 = nil, --Search reuslt ID goes here notCheckable = true, disabled = nil, --Disabled if we don't have a name for the leader }, }, }, { text = CANCEL, notCheckable = true, }, }; function LFGListUtil_GetSearchEntryMenu(resultID) local id, activityID, name, comment, voiceChat, iLvl, honorLevel, age, numBNetFriends, numCharFriends, numGuildMates, isDelisted, leaderName = C_LFGList.GetSearchResultInfo(resultID); local _, appStatus, pendingStatus, appDuration = C_LFGList.GetApplicationInfo(resultID); LFG_LIST_SEARCH_ENTRY_MENU[1].text = name; LFG_LIST_SEARCH_ENTRY_MENU[2].arg1 = leaderName; local applied = (appStatus == "applied" or appStatus == "invited"); LFG_LIST_SEARCH_ENTRY_MENU[2].disabled = not leaderName or not applied; LFG_LIST_SEARCH_ENTRY_MENU[2].tooltipTitle = (not applied) and WHISPER LFG_LIST_SEARCH_ENTRY_MENU[2].tooltipText = (not applied) and LFG_LIST_MUST_SIGN_UP_TO_WHISPER; LFG_LIST_SEARCH_ENTRY_MENU[3].menuList[1].arg1 = resultID; LFG_LIST_SEARCH_ENTRY_MENU[3].menuList[2].arg1 = resultID; LFG_LIST_SEARCH_ENTRY_MENU[3].menuList[2].disabled = (comment == ""); LFG_LIST_SEARCH_ENTRY_MENU[3].menuList[3].arg1 = resultID; LFG_LIST_SEARCH_ENTRY_MENU[3].menuList[3].disabled = (voiceChat == ""); LFG_LIST_SEARCH_ENTRY_MENU[3].menuList[4].arg1 = resultID; LFG_LIST_SEARCH_ENTRY_MENU[3].menuList[4].disabled = not leaderName; return LFG_LIST_SEARCH_ENTRY_MENU; end local LFG_LIST_APPLICANT_MEMBER_MENU = { { text = nil, --Player name goes here isTitle = true, notCheckable = true, }, { text = WHISPER, func = function(_, name) ChatFrame_SendTell(name); end, notCheckable = true, arg1 = nil, --Player name goes here disabled = nil, --Disabled if we don't have a name yet }, { text = LFG_LIST_REPORT_FOR, hasArrow = true, notCheckable = true, menuList = { { text = LFG_LIST_BAD_PLAYER_NAME, notCheckable = true, func = function(_, id, memberIdx) C_LFGList.ReportApplicant(id, "badplayername", memberIdx); end, arg1 = nil, --Applicant ID goes here arg2 = nil, --Applicant Member index goes here }, { text = LFG_LIST_BAD_DESCRIPTION, notCheckable = true, func = function(_, id) C_LFGList.ReportApplicant(id, "lfglistappcomment"); end, arg1 = nil, --Applicant ID goes here }, }, }, { text = IGNORE_PLAYER, notCheckable = true, func = function(_, name, applicantID) AddIgnore(name); C_LFGList.DeclineApplicant(applicantID); end, arg1 = nil, --Player name goes here arg2 = nil, --Applicant ID goes here disabled = nil, --Disabled if we don't have a name yet }, { text = CANCEL, notCheckable = true, }, }; function LFGListUtil_GetApplicantMemberMenu(applicantID, memberIdx) local name, class, localizedClass, level, itemLevel, honorLevel, tank, healer, damage, assignedRole = C_LFGList.GetApplicantMemberInfo(applicantID, memberIdx); local id, status, pendingStatus, numMembers, isNew, comment = C_LFGList.GetApplicantInfo(applicantID); LFG_LIST_APPLICANT_MEMBER_MENU[1].text = name or " "; LFG_LIST_APPLICANT_MEMBER_MENU[2].arg1 = name; LFG_LIST_APPLICANT_MEMBER_MENU[2].disabled = not name or (status ~= "applied" and status ~= "invited"); LFG_LIST_APPLICANT_MEMBER_MENU[3].menuList[1].arg1 = applicantID; LFG_LIST_APPLICANT_MEMBER_MENU[3].menuList[1].arg2 = memberIdx; LFG_LIST_APPLICANT_MEMBER_MENU[3].menuList[2].arg1 = applicantID; LFG_LIST_APPLICANT_MEMBER_MENU[3].menuList[2].disabled = (comment == ""); LFG_LIST_APPLICANT_MEMBER_MENU[4].arg1 = name; LFG_LIST_APPLICANT_MEMBER_MENU[4].arg2 = applicantID; LFG_LIST_APPLICANT_MEMBER_MENU[4].disabled = not name; return LFG_LIST_APPLICANT_MEMBER_MENU; end function LFGListUtil_InitializeLangaugeFilter(dropdown) local info = UIDropDownMenu_CreateInfo(); local languages = C_LFGList.GetAvailableLanguageSearchFilter(); local enabled = C_LFGList.GetLanguageSearchFilter(); local defaults = C_LFGList.GetDefaultLanguageSearchFilter(); local entry = UIDropDownMenu_CreateInfo(); for i=1, #languages do local lang = languages[i]; entry.text = _G["LFG_LIST_LANGUAGE_"..string.upper(lang)]; entry.checked = enabled[lang] or defaults[lang]; entry.disabled = defaults[lang]; entry.isNotRadio = true; entry.keepShownOnClick = true; entry.func = function(self,_,_,checked) enabled[lang] = checked; C_LFGList.SaveLanguageSearchFilter(enabled); end UIDropDownMenu_AddButton(entry); end end function LFGListUtil_OpenBestWindow(toggle) local func = toggle and PVEFrame_ToggleFrame or PVEFrame_ShowFrame; local active, activityID, ilvl, honorLevel, name, comment, voiceChat = C_LFGList.GetActiveEntryInfo(); if ( active ) then --Open to the window of our active activity local fullName, shortName, categoryID, groupID, iLevel, filters = C_LFGList.GetActivityInfo(activityID); if ( bit.band(filters, LE_LFG_LIST_FILTER_PVE) ~= 0 ) then func("GroupFinderFrame", "LFGListPVEStub"); else func("PVPUIFrame", "LFGListPVPStub"); end else --Open to the last window we had open if ( bit.band(LFGListFrame.baseFilters, LE_LFG_LIST_FILTER_PVE) ~= 0 ) then func("GroupFinderFrame", "LFGListPVEStub"); else func("PVPUIFrame", "LFGListPVPStub"); end end end function LFGListUtil_SortActivitiesByRelevancyCB(id1, id2) local fullName1, _, _, _, iLevel1, _, minLevel1 = C_LFGList.GetActivityInfo(id1); local fullName2, _, _, _, iLevel2, _, minLevel2 = C_LFGList.GetActivityInfo(id2); if ( minLevel1 ~= minLevel2 ) then return minLevel1 > minLevel2; elseif ( iLevel1 ~= iLevel2 ) then local myILevel = GetAverageItemLevel(); if ((iLevel1 <= myILevel) ~= (iLevel2 <= myILevel) ) then --If one is below our item level and the other above, choose the one we meet return iLevel1 < myILevel; else --If both are above or both are below, choose the one closest to our iLevel return math.abs(iLevel1 - myILevel) < math.abs(iLevel2 - myILevel); end else return strcmputf8i(fullName1, fullName2) < 0; end end function LFGListUtil_SortActivitiesByRelevancy(activities) table.sort(activities, LFGListUtil_SortActivitiesByRelevancyCB); end LFG_LIST_ACTIVE_QUEUE_MESSAGE_EVENTS = { "LFG_LIST_ACTIVE_ENTRY_UPDATE", "LFG_LIST_SEARCH_RESULT_UPDATED", "PVP_ROLE_CHECK_UPDATED", "UPDATE_BATTLEFIELD_STATUS", "LFG_UPDATE", "LFG_ROLE_CHECK_UPDATE", "LFG_PROPOSAL_UPDATE", "LFG_PROPOSAL_FAILED", "LFG_PROPOSAL_SUCCEEDED", "LFG_PROPOSAL_SHOW", "LFG_QUEUE_STATUS_UPDATE", }; function LFGListUtil_GetActiveQueueMessage(isApplication) --Check for applications if we're trying to list if ( not isApplication and select(2,C_LFGList.GetNumApplications()) > 0 ) then return CANNOT_DO_THIS_WITH_LFGLIST_APP; end --Check for listings if we have an application if ( isApplication and C_LFGList.GetActiveEntryInfo() ) then return CANNOT_DO_THIS_WHILE_LFGLIST_LISTED; end --Check all LFG categories for category=1, NUM_LE_LFG_CATEGORYS do local mode = GetLFGMode(category); if ( mode ) then if ( mode == "lfgparty" ) then return CANNOT_DO_THIS_IN_LFG_PARTY; elseif ( mode == "rolecheck" or (mode and not isApplication) ) then return CANNOT_DO_THIS_IN_PVE_QUEUE; end end end --Check PvP role check local inProgress, _, _, _, _, isBattleground = GetLFGRoleUpdate(); if ( inProgress ) then return isBattleground and CANNOT_DO_THIS_WHILE_PVP_QUEUING or CANNOT_DO_THIS_WHILE_PVE_QUEUING; end for i=1, GetMaxBattlefieldID() do local status, mapName, teamSize, registeredMatch, suspend = GetBattlefieldStatus(i); if ( status and status ~= "none" ) then return CANNOT_DO_THIS_IN_BATTLEGROUND; end end end local LFG_LIST_INACTIVE_STATUSES = { cancelled = true, failed = true, declined = true, timedout = true, invitedeclined = true, } function LFGListUtil_IsStatusInactive(status) return LFG_LIST_INACTIVE_STATUSES[status]; end function LFGListUtil_SetAutoAccept(autoAccept) local active, activityID, iLevel, honorLevel, name, comment, voiceChat, expiration, oldAutoAccept = C_LFGList.GetActiveEntryInfo(); if ( not active ) then --If we're not listed, we can't change the value. return; end C_LFGList.UpdateListing(activityID, name, iLevel, honorLevel, voiceChat, comment, autoAccept); end