work in progress

This commit is contained in:
2026-05-06 23:15:58 +04:00
parent e8f1ae4ab9
commit 255485daca
1342 changed files with 263968 additions and 0 deletions
Binary file not shown.
@@ -0,0 +1,544 @@
UIPanelWindows["ItemBrowser"] = { area = "left", pushable = 0, whileDead = 1, width = 830, xOffset = "15", yOffset = "-10"}
local type = type
local mathmax = math.max
local strfind, strlower, strtrim = string.find, string.lower, string.trim
local tinsert, twipe = table.insert, table.wipe
local debugprofilestop = debugprofilestop
local COLUMNS = {
{
name = "Name",
dataProviderKey = "name",
template = "ItemBrowserListCellNameIconTemplate",
},
{
name = "ItemLevel",
dataProviderKey = "itemLevel",
width = 70,
template = "ItemBrowserListCellItemLevelTemplate",
},
{
name = "ID",
dataProviderKey = "itemID",
width = 90,
template = "ItemBrowserListCellItemIDTemplate",
},
}
ItemBrowserMixin = {}
function ItemBrowserMixin:OnLoad()
self.TitleText:SetText(ITEM_BROWSER)
SetPortraitToTexture(self.portrait, [[Interface\Icons\Achievement_General_ClassicBattles_64]])
self.inset.Bgs:SetAtlas("UI-EJ-BattleforAzeroth")
do -- tabs
self:RegisterCustomEvent("SERVICE_DATA_UPDATE")
self:RegisterCustomEvent("CUSTOM_CHALLENGE_DEACTIVATED")
self.tab1:SetFrameLevel(1)
self.tab2:SetFrameLevel(1)
self.tab3:SetFrameLevel(1)
self.tab4:SetFrameLevel(1)
self.maxTabWidth = (self:GetWidth() - 19) / 4
PanelTemplates_SetNumTabs(self, 4)
end
do -- coroutine
self.COROUTINE_HANDLER = CreateFrame("Frame")
self.COROUTINE_HANDLER:Hide()
self.COROUTINE_HANDLER.FRAMETIME_TARGET = 1 / 55
self.COROUTINE_HANDLER.FRAMETIME_AVAILABLE = 8
self.COROUTINE_HANDLER.FRAMETIME_RESERVE = 4
self.COROUTINE_HANDLER.DEBUG = false
self.COROUTINE_HANDLER:SetScript("OnUpdate", function(this, elapsed)
local frametimeStep = this.FRAMETIME_TARGET - elapsed
if frametimeStep ~= 0 then
frametimeStep = frametimeStep * 1000
this.FRAMETIME_AVAILABLE = mathmax(5, this.FRAMETIME_AVAILABLE + frametimeStep)
end
if this.COROUTINE then
this.COROUTINE_TIMESTAMP = debugprofilestop()
local status, result, progress = coroutine.resume(this.COROUTINE)
if not status then
this.COROUTINE = nil
this:Hide()
self.PROGRESS = 1
error(result, 2)
elseif not result then
if this.DEBUG then print("ITEM_BROWSER_COROUTINE", progress) end
self.PROGRESS = progress
self:OnSearchResultUpdate()
else
if this.DEBUG then print("ITEM_BROWSER_COROUTINE", 1) end
this.COROUTINE = nil
this:Hide()
self.PROGRESS = 1
self:OnSearchResultUpdate()
end
else
this:Hide()
end
end)
end
self.BUTTON_OFFSET_Y = 0
self.PROGRESS = 1
self.results = {}
self.Scroll.ScrollBar:SetBackgroundShown(false)
self.Scroll.update = function(scrollFrame)
self:UpdateResultList()
end
self.Scroll.ScrollBar.doNotHide = true
self.Scroll.scrollBar = self.Scroll.ScrollBar
HybridScrollFrame_CreateButtons(self.Scroll, "ItemBrowserListRowButtonTemplate", 0, 0, nil, nil, nil, -self.BUTTON_OFFSET_Y)
self.SearchBox:ToggleOnCharFilter(true, 0.3)
self.tableBuilder = CreateTableBuilder(HybridScrollFrame_GetButtons(self.Scroll))
self.tableBuilder:SetHeaderContainer(self.HeaderHolder)
self:ConstructTable()
end
function ItemBrowserMixin:OnShow()
SetParentFrameLevel(self.inset)
PanelTemplates_SetTab(self, 4)
self.dirty = true
self.Scroll.ScrollBar:SetValue(0)
self:UpdateResultList()
self.SearchBox:SetFocus()
end
function ItemBrowserMixin:OnEvent(event, ...)
if event == "SERVICE_DATA_UPDATE"
or (event == "CUSTOM_CHALLENGE_DEACTIVATED" and select(2, ...) ~= Enum.HardcoreDeathReason.FAILED_DEATH)
then
if not C_Service.IsRenegadeRealm() then
PanelTemplates_HideTab(self, 2)
self.tab3:SetPoint("LEFT", self.tab1, "RIGHT", -16, 0);
end
if not C_Service.IsHardcoreEnabledOnRealm() then
PanelTemplates_HideTab(self, 3)
end
if not C_Service.IsGMAccount() and not IsInterfaceDevClient() then
PanelTemplates_HideTab(self, 4)
end
end
end
function ItemBrowserMixin:GetRowProvider()
return function(itemIndex)
if itemIndex > #self.results then
return nil
end
local itemID = self.results[itemIndex]
local itemName, itemLink, itemRarity, itemLevel, itemMinLevel, itemType, itemSubType, itemStackCount, itemEquipLoc, itemTexture, vendorPrice = C_Item.GetItemInfo(itemID, false, nil, true, true)
return {
itemID = itemID,
name = itemName,
itemLink = itemLink,
itemLevel = itemLevel,
itemType = itemType,
itemSubType = itemSubType,
icon = itemTexture,
}
end
end
function ItemBrowserMixin:ConstructTable()
local textPadding = 1
local cellPadding = 10
self.tableBuilder:Reset()
self.tableBuilder:SetDataProvider(self:GetRowProvider())
self.tableBuilder:SetTableMargins(5)
self.tableBuilder:SetTableWidth(self.Scroll:GetWidth() or select(3, self.Scroll:GetRect()))
for index, columnInfo in ipairs(COLUMNS) do
local column = self.tableBuilder:AddColumn()
column:ConstructHeader("Button", "ItemBrowserListHeaderButtonTemplate", columnInfo.name)
column:ConstrainToHeader(textPadding)
column:ConstructCells("Frame", columnInfo.template)
if columnInfo.width then
column:SetFixedConstraints(columnInfo.width, cellPadding)
else
column:SetFillConstraints(1, cellPadding)
end
end
self.tableBuilder:Arrange()
end
function ItemBrowserMixin:GetNumItems()
if not self.NUM_ITEMS then
self.NUM_ITEMS = tCount(ItemsCache)
end
return self.NUM_ITEMS
end
function ItemBrowserMixin:SearchItem(item)
item = strtrim(item)
if item == "" then
self:ClearResults()
return
end
local itemID = C_Item.GetItemIDFromString(item)
local searchField, searchValue, useStringFind
if itemID then
searchField = Enum.ItemCacheField.ITEM_ID
searchValue = itemID
elseif item ~= "" then
searchField = GetLocale() == "ruRU" and Enum.ItemCacheField.NAME_RURU or Enum.ItemCacheField.NAME_ENGB
searchValue = strlower(item)
useStringFind = true
end
if not searchField then
self:ClearResults()
return
end
self:StartSearch(searchField, searchValue, useStringFind)
end
function ItemBrowserMixin:StartSearch(searchField, searchValue, useStringFind)
if self.SEARCH_FIELD == searchField and self.SEARCH_VALUE == searchValue then
return
end
if self.COROUTINE then
coroutine.close(self.COROUTINE)
self.COROUTINE = nil
self:ClearResults()
end
self.SEARCH_FIELD = searchField
self.SEARCH_VALUE = searchValue
self.USE_STRING_FIND = useStringFind
local framerate = GetFramerate()
self.COROUTINE_HANDLER.FRAMETIME_TARGET = framerate > 63 and (1 / 60) or (1 / 55)
self.COROUTINE_HANDLER.FRAMETIME_BUDGET = 1000 / framerate - self.COROUTINE_HANDLER.FRAMETIME_RESERVE
self.COROUTINE_HANDLER.COROUTINE = coroutine.create(self.SearchProcess)
self.COROUTINE_HANDLER.COROUTINE_TIMESTAMP = debugprofilestop()
local status, result, progress = coroutine.resume(self.COROUTINE_HANDLER.COROUTINE, self)
if not status then
self.COROUTINE_HANDLER.COROUTINE = nil
self.COROUTINE_HANDLER:Hide()
self.PROGRESS = 1
self:ClearResults()
geterrorhandler()(result)
elseif coroutine.status(self.COROUTINE_HANDLER.COROUTINE) == "dead" then
self.COROUTINE_HANDLER.COROUTINE = nil
self.PROGRESS = 1
else
if self.COROUTINE_HANDLER.DEBUG then print("ITEM_BROWSER_COROUTINE", progress) end
self.PROGRESS = progress
self.COROUTINE_HANDLER:Show()
end
self:OnSearchResultUpdate()
end
function ItemBrowserMixin:SearchProcess()
twipe(self.results)
if not ItemsCache then
return true, 1
end
local processedEntries = 0
local fieldValue
for itemID, itemInfo in pairs(ItemsCache) do
processedEntries = processedEntries + 1
fieldValue = itemInfo[self.SEARCH_FIELD]
if type(fieldValue) == "string" then
fieldValue = strlower(fieldValue)
end
if fieldValue == self.SEARCH_VALUE
or (self.USE_STRING_FIND and strfind(fieldValue, self.SEARCH_VALUE, 1, true))
then
tinsert(self.results, itemInfo[Enum.ItemCacheField.ITEM_ID])
end
if (debugprofilestop() - self.COROUTINE_HANDLER.COROUTINE_TIMESTAMP) > self.COROUTINE_HANDLER.FRAMETIME_BUDGET then
coroutine.yield(false, processedEntries / self:GetNumItems())
end
end
return true, 1
end
function ItemBrowserMixin:OnSearchResultUpdate()
self.dirty = true
self:UpdateSearchProgress()
self:UpdateResultList()
end
function ItemBrowserMixin:UpdateSearchProgress()
local progress = Clamp(self.PROGRESS or 1, 0, 1)
self.SearchProgressBar:SetValue(progress)
self.SearchProgressBar:SetAlpha(progress < 1 and 1 or 0)
end
function ItemBrowserMixin:ClearResults()
twipe(self.results)
self.SEARCH_FIELD = nil
self.SEARCH_VALUE = nil
self.USE_STRING_FIND = nil
self.PROGRESS = 1
self.dirty = true
self:UpdateSearchProgress()
self:UpdateResultList()
end
function ItemBrowserMixin:UpdateResultList()
local scrollFrame = self.Scroll
local offset = HybridScrollFrame_GetOffset(scrollFrame)
local numResults = self.results and #self.results or 0
if self.numItems ~= numResults then
self.numItems = numResults
self.dirty = true
end
local populateCount = math.min(#scrollFrame.buttons, numResults)
self.tableBuilder:Populate(offset, populateCount)
local mouseFocus = GetMouseFocus()
for index, button in ipairs(scrollFrame.buttons) do
button:SetOwner(self)
button:SetShown(index <= numResults)
if button == mouseFocus then
button:OnEnter()
end
end
if self.dirty then
local buttonHeight = scrollFrame.buttons[1] and scrollFrame.buttons[1]:GetHeight() or 0
local scrollHeight = buttonHeight * numResults + self.BUTTON_OFFSET_Y * (numResults - 1) + self.BUTTON_OFFSET_Y / 3
HybridScrollFrame_Update(scrollFrame, scrollHeight, scrollFrame:GetHeight())
self.dirty = nil
end
end
ItemBrowserSearchBoxMixin = CreateFromMixins(PKBT_EditBoxMixin)
function ItemBrowserSearchBoxMixin:OnLoad()
PKBT_EditBoxMixin.OnLoad(self)
local l, r, t, b = self:GetTextInsets()
self:SetTextInsets(l + 10, r + 10, t - 1, b)
self:SetInstructions(SEARCH)
self.Instructions:ClearAllPoints()
self.Instructions:SetPoint("LEFT", 19, -2)
self.searchIcon:SetVertexColor(0.6, 0.6, 0.6)
self:SetCustomCharFilter(function(text)
text = string.gsub(text, "%s%s+", " ")
text = utf8.gsub(text, "[^A-zА-я0-9':%- ]+", "")
return text
end)
self.value = ""
end
function ItemBrowserSearchBoxMixin:OnHide()
self:StopOnCharSearchDelay()
end
function ItemBrowserSearchBoxMixin:OnEnterPressed()
self:ClearFocus()
self:DoSearch()
end
function ItemBrowserSearchBoxMixin:OnEditFocusLost()
SearchBoxTemplate_OnEditFocusLost(self)
self:HighlightText(0, 0)
self:DoSearch()
end
function ItemBrowserSearchBoxMixin:OnUpdate(elapsed)
self.searchDelay = self.searchDelay - elapsed
if self.searchDelay <= 0 then
self:SetScript("OnUpdate", nil)
self.searchDelay = nil
self:DoSearch()
end
end
function ItemBrowserSearchBoxMixin:DoSearch()
local newValue = self:GetText()
if self.value ~= newValue and not (self.value == nil and newValue == "") then
self.value = newValue
self:GetParent():SearchItem(newValue)
end
end
function ItemBrowserSearchBoxMixin:ToggleOnCharFilter(state, searchUpdateDelay)
if state then
self.searchUpdateDelay = searchUpdateDelay
self.searchDelay = searchUpdateDelay
else
self:SetScript("OnUpdate", nil)
self.searchUpdateDelay = nil
self.searchDelay = nil
end
end
function ItemBrowserSearchBoxMixin:OnTextChanged(userInput)
PKBT_EditBoxMixin.OnTextChanged(self, userInput)
SearchBoxTemplate_OnTextChanged(self)
end
function ItemBrowserSearchBoxMixin:OnTextValueChanged(value, userInput)
if userInput then
if self.searchUpdateDelay then
self.searchDelay = self.searchUpdateDelay
self:SetScript("OnUpdate", self.OnUpdate)
end
else
self:StopOnCharSearchDelay()
end
end
function ItemBrowserSearchBoxMixin:OnUpdate(elapsed)
self.searchDelay = self.searchDelay - elapsed
if self.searchDelay <= 0 then
self:SetScript("OnUpdate", nil)
self.searchDelay = nil
self:DoSearch()
end
end
function ItemBrowserSearchBoxMixin:StopOnCharSearchDelay()
self:SetScript("OnUpdate", nil)
if self.searchUpdateDelay then
self.searchDelay = self.searchUpdateDelay
end
end
function ItemBrowserSearchBoxMixin:OnClearClick(button)
SearchBoxTemplateClearButton_OnClick(self.clearButton, button)
self:StopOnCharSearchDelay()
self:DoSearch()
end
ItemBrowserListHeaderButtonMixin = CreateFromMixins(TableBuilderElementMixin)
function ItemBrowserListHeaderButtonMixin:Init(name)
self:SetText(name)
end
function ItemBrowserListHeaderButtonMixin:OnClick(button)
end
ItemBrowserListRowButton = CreateFromMixins(PKBT_OwnerMixin, TableBuilderRowMixin)
function ItemBrowserListRowButton:OnLoad()
self.UpdateTooltip = self.OnEnter
end
function ItemBrowserListRowButton:OnEnter()
if self.itemLink then
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
GameTooltip:SetHyperlink(self.itemLink)
GameTooltip:Show()
end
end
function ItemBrowserListRowButton:OnLeave()
GameTooltip:Hide()
end
function ItemBrowserListRowButton:OnClick(button)
if self.itemLink then
HandleModifiedItemClick(self.itemLink)
end
end
function ItemBrowserListRowButton:Populate(rowData, dataIndex)
self:SetID(dataIndex)
self.itemID = rowData.itemID
self.itemLink = rowData.itemLink
end
ItemBrowserListCellMixin = {}
function ItemBrowserListCellMixin:OnLoad()
end
function ItemBrowserListCellMixin:Init(dataProviderKey)
self.dataProviderKey = dataProviderKey
end
function ItemBrowserListCellMixin:Populate(rowData, dataIndex)
local value = rowData[self.dataProviderKey]
self.Text:SetJustifyH(self.textAlignment or "CENTER")
self.Text:SetText(value or "?")
end
ItemBrowserListCellNameIconMixin = CreateFromMixins(ItemBrowserListCellMixin)
function ItemBrowserListCellNameIconMixin:Populate(rowData, dataIndex)
local textWidth = self:GetWidth() - 10
self.Text:SetText(rowData.name or UNKNOWN)
self.Text:SetWidth(textWidth)
self.SubText:SetWidth(textWidth)
if rowData.itemType and rowData.itemSubType then
self.SubText:SetFormattedText("%s - %s", rowData.itemType, rowData.itemSubType)
elseif rowData.itemType or rowData.itemSubType then
self.SubText:SetText(rowData.itemType or rowData.itemSubType)
else
self.SubText:SetText("")
end
self.Icon:SetTexture(rowData.icon or QUESTION_MARK_ICON)
local r, g, b = GetItemQualityColor(rowData.rarity or 1)
self.Border:SetVertexColor(r, g, b)
end
ItemBrowserListCellItemLevelMixin = CreateFromMixins(ItemBrowserListCellMixin)
function ItemBrowserListCellItemLevelMixin:Populate(rowData, dataIndex)
self.Text:SetText(rowData.itemLevel and rowData.itemLevel ~= 0 and rowData.itemLevel or "")
end
ItemBrowserListCellItemIDMixin = CreateFromMixins(ItemBrowserListCellMixin)
function ItemBrowserListCellItemIDMixin:Populate(rowData, dataIndex)
self.Text:SetText(rowData.itemID)
end
@@ -0,0 +1,331 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
..\..\FrameXML\UI.xsd">
<Script file="Custom_ItemBrowser.lua"/>
<Button name="ItemBrowserListHeaderButtonTemplate" virtual="true">
<Size x="50" y="30"/>
<Layers>
<Layer level="BACKGROUND">
<Texture name="$parentBackground" parentKey="Background" setAllPoints="true">
<Color r="0.2" g="0.2" b="0.2"/>
</Texture>
</Layer>
<!--
<Layer level="HIGHLIGHT">
<Texture name="$parentHighlight" parentKey="Highlight" setAllPoints="true" alpha="0.2" alphaMode="ADD">
<Color r="1" g="1" b="1"/>
</Texture>
</Layer>
-->
</Layers>
<NormalFont style="SystemFont_Shadow_Small"/>
<PushedTextOffset x="0" y="0"/>
<!--
<PushedTextOffset x="1" y="-1"/>
<ButtonText name="$parentButtonText" parentKey="ButtonText">
<Anchors>
<Anchor point="CENTER" x="0" y="0"/>
</Anchors>
</ButtonText>
-->
<Scripts>
<OnLoad>
Mixin(self, ItemBrowserListHeaderButtonMixin)
</OnLoad>
<!--
<OnClick>
self:OnClick(button)
</OnClick>
-->
</Scripts>
</Button>
<Button name="ItemBrowserListRowButtonTemplate" virtual="true">
<Size x="0" y="46"/>
<Anchors>
<Anchor point="LEFT" x="1" y="0"/>
<Anchor point="RIGHT" x="-1" y="0"/>
</Anchors>
<Layers>
<Layer level="BACKGROUND">
<Texture name="$parentBackground" parentKey="Background" setAllPoints="true" inherits="_SearchBarLg"/>
</Layer>
</Layers>
<HighlightTexture file="Interface\Common\Search">
<TexCoords left="0.001953" right="0.501953" top="0.234375" bottom="0.601562"/>
</HighlightTexture>
<Scripts>
<OnLoad>
Mixin(self, ItemBrowserListRowButton)
self:OnLoad()
</OnLoad>
<OnEvent>
self:OnEvent(event, ...)
</OnEvent>
<OnEnter>
self:OnEnter()
</OnEnter>
<OnLeave>
self:OnLeave()
</OnLeave>
<OnClick>
self:OnClick()
</OnClick>
</Scripts>
</Button>
<Frame name="ItemBrowserListCellNameIconTemplate" virtual="true">
<Layers>
<Layer level="OVERLAY">
<Texture name="$parentBorder" parentKey="Border" file="Interface\Common\Search">
<Size x="40" y="40"/>
<Anchors>
<Anchor point="LEFT" x="10" y="0"/>
</Anchors>
<TexCoords left="0.755859" right="0.830078" top="0.234375" bottom="0.531250"/>
</Texture>
</Layer>
<Layer level="ARTWORK">
<Texture name="$parentIcon" parentKey="Icon">
<Anchors>
<Anchor point="TOPLEFT" relativeTo="$parentBorder" x="1" y="-2"/>
<Anchor point="BOTTOMRIGHT" relativeTo="$parentBorder" x="-1" y="1"/>
</Anchors>
</Texture>
<FontString name="$parentText" parentKey="Text" inherits="GameFontNormalLarge" justifyH="LEFT" maxLines="1">
<Size x="0" y="0"/>
<Anchors>
<Anchor point="LEFT" relativeTo="$parentIcon" relativePoint="RIGHT" x="10" y="8"/>
</Anchors>
<Color r="0.96875" g="0.8984375" b="0.578125" a="1"/>
</FontString>
<FontString name="$parentSubText" parentKey="SubText" inherits="GameFontNormal" justifyH="LEFT">
<Size x="400" y="0"/>
<Anchors>
<Anchor point="TOPLEFT" relativeTo="$parentText" relativePoint="BOTTOMLEFT" x="0" y="-5"/>
</Anchors>
<Color r="0.66796875" g="0.51171875" b="0.3359375" a="1"/>
</FontString>
</Layer>
</Layers>
<Scripts>
<OnLoad>
Mixin(self, ItemBrowserListCellNameIconMixin)
self:OnLoad()
</OnLoad>
</Scripts>
</Frame>
<Frame name="ItemBrowserListCellItemLevelTemplate" virtual="true">
<Layers>
<Layer level="ARTWORK">
<FontString name="$parentText" parentKey="Text" inherits="GameFontNormalLarge" maxLines="1">
<Size x="0" y="0"/>
<Anchors>
<Anchor point="CENTER" x="0" y="0"/>
</Anchors>
<Color r="1" g="1" b="1"/>
</FontString>
</Layer>
</Layers>
<Scripts>
<OnLoad>
Mixin(self, ItemBrowserListCellItemLevelMixin)
self:OnLoad()
</OnLoad>
</Scripts>
</Frame>
<Frame name="ItemBrowserListCellItemIDTemplate" virtual="true">
<Layers>
<Layer level="ARTWORK">
<FontString name="$parentText" parentKey="Text" inherits="GameFontNormalLarge" maxLines="1">
<Size x="0" y="0"/>
<Anchors>
<Anchor point="CENTER" x="0" y="0"/>
</Anchors>
<Color r="1" g="1" b="1"/>
</FontString>
</Layer>
</Layers>
<Scripts>
<OnLoad>
Mixin(self, ItemBrowserListCellItemIDMixin)
self:OnLoad()
</OnLoad>
</Scripts>
</Frame>
<Frame name="ItemBrowser" inherits="PortraitFrameTemplate" toplevel="true" enableMouse="true" parent="UIParent" hidden="true">
<Size x="800" y="496"/>
<Anchors>
<Anchor point="CENTER" x="0" y="0"/>
</Anchors>
<Frames>
<Frame name="$parentInset" inherits="InsetFrameTemplate" parentKey="inset">
<Anchors>
<Anchor point="TOPRIGHT" x="-4" y="-60"/>
<Anchor point="BOTTOMLEFT" x="4" y="5"/>
</Anchors>
</Frame>
<EditBox name="$parentSearchBox" parentKey="SearchBox" inherits="PKBT_EditBoxTemplate" letters="64">
<Size x="130" y="36"/>
<Anchors>
<Anchor point="TOPLEFT" x="60" y="-22"/>
<Anchor point="TOPRIGHT" x="-10" y="-22"/>
</Anchors>
<Layers>
<Layer level="OVERLAY">
<Texture name="$parentSearchIcon" parentKey="searchIcon" file="Interface\Common\UI-Searchbox-Icon">
<Size x="14" y="14"/>
<Anchors>
<Anchor point="LEFT" x="5" y="-2"/>
</Anchors>
</Texture>
</Layer>
</Layers>
<Frames>
<Button name="$parentClearButton" parentKey="clearButton" hidden="true">
<Size x="22" y="22"/>
<Anchors>
<Anchor point="RIGHT" x="-5" y="-1"/>
</Anchors>
<Layers>
<Layer level="ARTWORK">
<Texture parentKey="texture" file="Interface\FriendsFrame\ClearBroadcastIcon" alpha="0.5" setAllPoints="true"/>
</Layer>
</Layers>
<Scripts>
<OnEnter>
self.texture:SetAlpha(1.0)
</OnEnter>
<OnLeave>
self.texture:SetAlpha(0.5)
</OnLeave>
<OnMouseDown>
if self:IsEnabled() == 1 then
self.texture:SetPoint("TOPLEFT", self, "TOPLEFT", 1, -1)
end
</OnMouseDown>
<OnMouseUp>
self.texture:SetPoint("TOPLEFT", self, "TOPLEFT", 0, 0)
</OnMouseUp>
<OnClick>
self:GetParent():OnClearClick(button)
</OnClick>
</Scripts>
</Button>
</Frames>
<Scripts>
<OnLoad>
Mixin(self, ItemBrowserSearchBoxMixin)
self:OnLoad()
</OnLoad>
<OnHide>
self:OnHide()
</OnHide>
<OnTextChanged>
self:OnTextChanged(userInput)
</OnTextChanged>
<OnEnterPressed>
self:OnEnterPressed()
</OnEnterPressed>
<OnEditFocusLost>
self:OnEditFocusLost()
</OnEditFocusLost>
<OnEditFocusGained function="SearchBoxTemplate_OnEditFocusGained"/>
</Scripts>
</EditBox>
<StatusBar name="$parentSearchProgressBar" parentKey="SearchProgressBar" minValue="0" maxValue="1" alpha="0">
<Size x="0" y="6"/>
<Anchors>
<Anchor point="TOPLEFT" relativeTo="$parentSearchBox" relativePoint="BOTTOMLEFT" x="7" y="1"/>
<Anchor point="TOPRIGHT" relativeTo="$parentSearchBox" relativePoint="BOTTOMRIGHT" x="-7" y="1"/>
</Anchors>
<Layers>
<Layer level="BACKGROUND">
<Texture parentKey="Background">
<Anchors>
<Anchor point="TOPLEFT"/>
<Anchor point="BOTTOMRIGHT"/>
</Anchors>
<Color r="0" g="0" b="0" a="0.3"/>
</Texture>
</Layer>
</Layers>
<BarTexture file="Interface\TargetingFrame\UI-StatusBar"/>
<BarColor r="0" g="1" b="0"/>
</StatusBar>
<ScrollFrame name="$parentScroll" parentKey="Scroll" inherits="HybridScrollFrameTemplate">
<Anchors>
<Anchor point="TOPLEFT" relativeTo="$parentInset" relativePoint="TOPLEFT" x="10" y="-50"/>
<Anchor point="BOTTOMRIGHT" relativeTo="$parentInset" relativePoint="BOTTOMRIGHT" x="-36" y="10"/>
</Anchors>
<Frames>
<Slider name="$parentScrollBar" parentKey="ScrollBar" inherits="PKBT_HybridScrollBarTemplate">
<Anchors>
<Anchor point="TOPLEFT" relativePoint="TOPRIGHT" x="5" y="-25"/>
<Anchor point="BOTTOMLEFT" relativePoint="BOTTOMRIGHT" x="5" y="27"/>
</Anchors>
</Slider>
</Frames>
</ScrollFrame>
<Frame name="$parentHeaderHolder" parentKey="HeaderHolder">
<Size x="0" y="30"/>
<Anchors>
<Anchor point="BOTTOMLEFT" relativeTo="$parentScroll" relativePoint="TOPLEFT" x="0" y="12"/>
<Anchor point="BOTTOMRIGHT" relativeTo="$parentScroll" relativePoint="TOPRIGHT" x="0" y="12"/>
</Anchors>
</Frame>
<Button name="$parentTab1" inherits="CharacterFrameTabButtonTemplate" text="ADVENTURE_JOURNAL" id="1" parentKey="tab1">
<Anchors>
<Anchor point="BOTTOMLEFT" relativeTo="$parent" relativePoint="BOTTOMLEFT" x="19" y="-30"/>
</Anchors>
<Scripts>
<OnClick function="Adventure_TabOnClick"/>
</Scripts>
</Button>
<Button name="$parentTab2" inherits="CharacterFrameTabButtonTemplate" text="HEADHUNTING" id="2" parentKey="tab2">
<Anchors>
<Anchor point="LEFT" relativeTo="$parentTab1" relativePoint="RIGHT" x="-16" y="0"/>
</Anchors>
<Scripts>
<OnClick function="Adventure_TabOnClick"/>
</Scripts>
</Button>
<Button name="$parentTab3" inherits="CharacterFrameTabButtonTemplate" text="HARDCORE_CHALLENGES_TITLE" id="3" parentKey="tab3">
<Anchors>
<Anchor point="LEFT" relativeTo="$parentTab2" relativePoint="RIGHT" x="-16" y="0"/>
</Anchors>
<Scripts>
<OnClick function="Adventure_TabOnClick"/>
</Scripts>
</Button>
<Button name="$parentTab4" inherits="CharacterFrameTabButtonTemplate" text="ITEM_BROWSER" id="4" parentKey="tab4">
<Anchors>
<Anchor point="LEFT" relativeTo="$parentTab3" relativePoint="RIGHT" x="-16" y="0"/>
</Anchors>
<Scripts>
<OnClick function="Adventure_TabOnClick"/>
</Scripts>
</Button>
</Frames>
<Scripts>
<OnLoad>
Mixin(self, ItemBrowserMixin)
self:OnLoad()
</OnLoad>
<OnShow>
self:OnShow()
</OnShow>
<OnEvent>
self:OnEvent(event, ...)
</OnEvent>
</Scripts>
</Frame>
</Ui>
@@ -0,0 +1,491 @@
do
local tonumber = tonumber
local unpack = unpack
local bitband = bit.band
local strsub = string.sub
local LJ_BUFFER = {}
local NO_CLASS_FILTER = 0
local NO_SPEC_FILTER = 0
local LJ_ITEMSET_REALM_FLAG = {
[E_REALM_ID.SOULSEEKER] = 0x1,
[E_REALM_ID.SIRUS] = 0x2,
[E_REALM_ID.SCOURGE] = 0x4,
[E_REALM_ID.ALGALON] = 0x8,
[E_REALM_ID.NEVEREST] = 0x10,
}
local function getPlayerFactionID()
local factionGroup = UnitFactionGroup("player") or "NEUTRAL"
if factionGroup == "Renegade" then
return (C_FactionManager.GetFactionInfoOriginal())
end
return PLAYER_FACTION_GROUP[factionGroup]
end
local function filterByFaction(factionID, playerFactionID)
if factionID == PLAYER_FACTION_GROUP.Neutral then
return true
elseif factionID == playerFactionID then
return true
end
return false
end
local function filterByClassAndSpecFilters(classID, specID, classFilter, specFilter)
if classFilter and specFilter then
if specFilter == 3 then
specFilter = 4
end
if classFilter == NO_CLASS_FILTER and specFilter == NO_SPEC_FILTER then
return true
elseif classFilter == classID and specFilter == NO_SPEC_FILTER then
return true
elseif classFilter == classID and bitband(specFilter, specID) == specFilter then
return true
end
end
return false
end
local function sortItemSets(a, b)
if a[4] == b[4] then
if a[6] ~= b[6] then
return a[6]
end
return (tonumber(strsub(a[3], 3, -1) or 0)) > (tonumber(strsub(b[3], 3, -1) or 0))
end
return a[4] > b[4]
end
C_LootJournal = {}
function C_LootJournal.GenerateLootData(classFilter, specFilter)
table.wipe(LJ_BUFFER)
local serverID = C_Service.GetRealmID()
local playerFactionID = getPlayerFactionID()
local itemSetSourceRealm = EJ_ITEMSET_SOURCE_REALM[serverID]
for setIndex, itemSetData in pairs(EJ_ITEMSET_DATA) do
local name, itemlevel, tierName, sourceID, classID, specID, isPVP, itemList, factionID, realmFlag = unpack(itemSetData, 1, 10)
if not factionID then
factionID = 0
end
if filterByClassAndSpecFilters(classID, specID, classFilter or 0, specFilter or 0)
and filterByFaction(factionID, playerFactionID)
then
if itemSetSourceRealm and itemSetSourceRealm[setIndex] then
sourceID = itemSetSourceRealm[setIndex]
end
local sourceText = EJ_ITEMSET_SOURCE[sourceID] or ""
local numItems = type(itemList) == "table" and #itemList or 0
local items = {}
for i = 1, numItems do
local itemID = itemList[i]
items[i] = {
itemID = itemID,
icon = GetItemIcon(itemID) or [[Interface\Icons\INV_Misc_QuestionMark]],
}
end
LJ_BUFFER[#LJ_BUFFER + 1] = {setIndex, name, tierName or "", itemlevel, sourceText, isPVP == 1, items, numItems}
end
end
table.sort(LJ_BUFFER, sortItemSets)
return LJ_BUFFER
end
function C_LootJournal.GetNumItemSets()
return #LJ_BUFFER
end
function C_LootJournal.GetItemSetInfo(index)
if index and LJ_BUFFER[index] then
return unpack(LJ_BUFFER[index])
end
end
end
local NO_SPEC_FILTER = 0;
local NO_CLASS_FILTER = 0;
local NO_INV_TYPE_FILTER = 0;
--===================================================================================================================================
LootJournalItemsMixin = { };
function LootJournalItemsMixin:OnLoad()
self.Background:SetAtlas("loottab-background", true)
self:SetView(LOOT_JOURNAL_ITEM_SETS);
local _, _, classID = UnitClass("player");
local specIndex = C_Talent.GetCurrentSpecTabIndex()
self:SetClassAndSpecFilters(classID, specIndex);
end
function LootJournalItemsMixin:SetClassAndSpecFilters(classID, specID)
self.classFilter = classID;
self.specFilter = specID;
end
function LootJournalItemsMixin:GetClassAndSpecFilters()
return self.classFilter or NO_CLASS_FILTER, self.specFilter or NO_SPEC_FILTER;
end
function LootJournalItemsMixin:SetView(view)
if ( self.view == view ) then
return;
end
self.view = view;
self.ItemSetsFrame:Show();
end
function LootJournalItemsMixin:GetActiveList()
return self.ItemSetsFrame;
end
function LootJournalItemsMixin:Refresh()
self:GetActiveList():Refresh();
end
function LootJournalItemButtonTemplate_OnEnter(self)
local listFrame = self:GetParent();
while ( listFrame and not listFrame.ShowItemTooltip ) do
listFrame = listFrame:GetParent();
end
if ( listFrame ) then
listFrame:ShowItemTooltip(self);
self:SetScript("OnUpdate", LootJournalItemButton_OnUpdate);
self.UpdateTooltip = LootJournalItemButtonTemplate_OnEnter;
end
end
function LootJournalItemButtonTemplate_OnLeave(self)
self.UpdateTooltip = nil;
GameTooltip:Hide();
self:SetScript("OnUpdate", nil);
ResetCursor();
end
function LootJournalItemButton_OnClick(self, button)
if HandleModifiedItemClick(self.itemLink) then
return
end
LootJournal_OpenItemByEntry(self.itemID)
end
--===================================================================================================================================
LootJournalItemSetsMixin = {}
local LJ_ITEMSET_X_OFFSET = 10;
local LJ_ITEMSET_Y_OFFSET = 10;
local LJ_ITEMSET_BUTTON_SPACING = 13;
local LJ_ITEMSET_BOTTOM_BUFFER = 4;
function LootJournalItemSetsMixin:Refresh()
self.dirty = true;
local offset = self.scrollBar:GetValue();
if ( offset == 0 ) then
self:UpdateList();
else
self.scrollBar:SetValue(0);
end
if ( self.ClassButton ) then
self:UpdateClassButtonText();
end
end
function LootJournalItemSetsMixin:GetClassAndSpecFilters()
return self:GetParent():GetClassAndSpecFilters();
end
function LootJournalItemSetsMixin:UpdateClassButtonText()
end
function LootJournalItemSetsMixin:ShowItemTooltip(button)
-- itemLink may not be available
if not button.itemLink then
GameTooltip:Hide()
return
end
GameTooltip:SetOwner(button, "ANCHOR_RIGHT");
GameTooltip:SetHyperlink(button.itemLink);
if LootJournal_CanOpenItemByEntry(button.itemID) then
GameTooltip:AddLine(LOOTJOURNAL_ITEM_CLICK_TO_OPEN_LOOT, 0, 0.8, 1)
end
self.tooltipItemID = button.itemID;
GameTooltip:Show();
end
function LootJournalItemSetsMixin:CheckItemButtonTooltip(button)
if ( GameTooltip:GetOwner() == button and self.tooltipItemID ~= button.itemID ) then
self:ShowItemTooltip(button);
end
end
function LootJournalItemSetsMixin:GetClassFilter()
local classFilter, specFilter = self:GetClassAndSpecFilters();
return classFilter;
end
function LootJournalItemSetsMixin:GetSpecFilter()
local classFilter, specFilter = self:GetClassAndSpecFilters();
return specFilter;
end
function LootJournalItemSetsMixin:SetClassAndSpecFilters(newClassFilter, newSpecFilter)
local classFilter, specFilter = self:GetClassAndSpecFilters();
if not self.classAndSpecFiltersSet or classFilter ~= newClassFilter or specFilter ~= newSpecFilter then
--[[
-- if choosing just a class without a spec, pick a spec
if newClassFilter ~= NO_CLASS_FILTER and newSpecFilter == NO_SPEC_FILTER then
local _, _, classID = UnitClass("player");
-- if player's class, choose active spec
-- otherwise use 1st spec
if classID == newClassFilter then
local specIndex = C_Talent.GetCurrentSpecTabIndex()
newSpecFilter = specIndex
else
newSpecFilter = 1
end
end
--]]
self:GetParent():SetClassAndSpecFilters(newClassFilter, newSpecFilter);
self.scrollBar:SetValue(0);
self:Refresh();
end
CloseDropDownMenus(1);
self.classAndSpecFiltersSet = true;
end
do
function LootJournalItemButton_OnUpdate(self)
if GameTooltip:IsOwned(self) then
if IsModifiedClick("DRESSUP") then
ShowInspectCursor();
else
ResetCursor();
end
end
end
local function OpenClassFilterDropDown(self, level)
if level then
self:GetParent():GetActiveList():OpenClassFilterDropDown(level);
end
end
function LootJournalItemsClassDropDown_OnLoad(self)
UIDropDownMenu_Initialize(self, OpenClassFilterDropDown, "MENU");
end
local CLASS_DROPDOWN = 1;
function LootJournalItemSetsMixin:OpenClassFilterDropDown(level)
local filterClassID = self:GetClassFilter();
local filterSpecID = self:GetSpecFilter();
local classDisplayName, classTag, classID;
local function SetClassAndSpecFilters(_, classFilter, specFilter)
self:SetClassAndSpecFilters(classFilter, specFilter);
end
local info = UIDropDownMenu_CreateInfo();
if UIDROPDOWNMENU_MENU_VALUE == CLASS_DROPDOWN then
info.text = ALL_CLASSES;
info.checked = filterClassID == NO_CLASS_FILTER;
info.arg1 = NO_CLASS_FILTER;
info.arg2 = NO_SPEC_FILTER;
info.func = SetClassAndSpecFilters;
UIDropDownMenu_AddButton(info, level);
local numClasses = GetNumClasses();
for i = 1, numClasses do
classDisplayName, classTag, classID = GetClassInfo(i);
if classID ~= 10 then
info.text = classDisplayName;
info.checked = filterClassID == classID;
info.arg1 = classID;
info.arg2 = NO_SPEC_FILTER;
info.func = SetClassAndSpecFilters;
UIDropDownMenu_AddButton(info, level);
end
end
end
if level == 1 then
info.text = CLASS;
info.func = nil;
info.notCheckable = true;
info.hasArrow = true;
info.value = CLASS_DROPDOWN;
UIDropDownMenu_AddButton(info, level);
local classDisplayName, classTag, classID;
if filterClassID ~= NO_CLASS_FILTER then
classID = filterClassID;
classDisplayName = GetClassInfo(classID)
else
classDisplayName, classTag, classID = UnitClass("player");
end
info.text = classDisplayName;
info.notCheckable = true;
info.arg1 = nil;
info.arg2 = nil;
info.func = nil;
info.hasArrow = false;
UIDropDownMenu_AddButton(info, level);
info.notCheckable = nil;
for i = 1, GetNumSpecializationsForClassID(classID) do
local _, specName = GetSpecializationInfoForClassID(classID, i)
info.leftPadding = 10;
info.text = specName;
info.checked = filterSpecID == i;
info.arg1 = classID;
info.arg2 = i;
info.func = SetClassAndSpecFilters;
UIDropDownMenu_AddButton(info, level);
end
info.text = ALL_SPECS;
info.leftPadding = 10;
info.checked = (classID == filterClassID and filterSpecID == NO_SPEC_FILTER) or (filterClassID == NO_CLASS_FILTER and filterSpecID == NO_SPEC_FILTER);
info.arg1 = classID;
info.arg2 = NO_SPEC_FILTER;
info.func = SetClassAndSpecFilters;
UIDropDownMenu_AddButton(info, level);
end
end
end
function LootJournalItemSetsMixin:OnLoad()
self.scrollBar.trackBG:Hide();
self.update = LootJournalItemSetsMixin.UpdateList;
HybridScrollFrame_CreateButtons(self, "LootJournalItemSetButtonTemplate", LJ_ITEMSET_X_OFFSET, -LJ_ITEMSET_Y_OFFSET, "TOPLEFT", nil, nil, -LJ_ITEMSET_BUTTON_SPACING);
end
function LootJournalItemSetsMixin:OnShow()
if not self.init then
self.init = true;
self:Refresh();
end
end
local function onItemLoaded(itemID)
local self = EncounterJournal.LootJournalItems.ItemSetsFrame
for i = 1, #self.buttons do
local itemButtons = self.buttons[i].ItemButtons;
for j = 1, #itemButtons do
if ( itemButtons[j].itemID == itemID ) then
self:ConfigureItemButton(itemButtons[j]);
return;
end
end
end
end
function LootJournalItemSetsMixin:ConfigureItemButton(button)
local _, itemLink, itemQuality, _, _, _, _, _, _, icon = C_Item.GetItemInfo(button.itemID, false, onItemLoaded, true);
button.itemLink = itemLink;
itemQuality = itemQuality or Enum.ItemQuality.Epic; -- sets are most likely rare
if ( itemQuality == Enum.ItemQuality.Uncommon ) then
button.Border:SetAtlas("loottab-set-itemborder-green", true);
elseif ( itemQuality == Enum.ItemQuality.Rare ) then
button.Border:SetAtlas("loottab-set-itemborder-blue", true);
elseif ( itemQuality == Enum.ItemQuality.Epic ) then
button.Border:SetAtlas("loottab-set-itemborder-purple", true);
end
button.Icon:SetTexture(icon or "Interface\\ICONS\\temp")
button:GetParent().SetName:SetTextColor(GetItemQualityColor(itemQuality));
self:CheckItemButtonTooltip(button);
end
function LootJournalItemSetsMixin:UpdateList()
if ( self.dirty ) then
C_LootJournal.GenerateLootData(self:GetClassAndSpecFilters())
self.dirty = nil;
end
local buttons = self.buttons;
local offset = HybridScrollFrame_GetOffset(self);
local numSets = C_LootJournal.GetNumItemSets()
for i = 1, #buttons do
local button = buttons[i];
local index = offset + i;
if ( index <= numSets ) then
local setIndex, name, tierName, itemlevel, sourceText, isPVP, items, numItems = C_LootJournal.GetItemSetInfo(index)
button:Show();
button.SetName:SetText(name);
button.ItemLevel:SetFormattedText(EJ_SET_ITEM_LEVEL, tierName, itemlevel);
button.PVPIcon:SetShown(isPVP);
button.setIndex = setIndex
button.tooltipText = sourceText
button:CheckItemButtonTooltip()
for j = 1, numItems do
local itemButton = button.ItemButtons[j];
if ( not itemButton ) then
itemButton = CreateFrame("BUTTON", string.format("$parentItemButton%i", j), button, "LootJournalItemSetItemButtonTemplate");
button[string.format("$parentItemButton%i", j)] = itemButton
itemButton:SetPoint("LEFT", button.ItemButtons[j-1], "RIGHT", 5, 0);
end
itemButton.Icon:SetTexture(items[j].icon);
itemButton.itemID = items[j].itemID;
itemButton:Show();
self:ConfigureItemButton(itemButton);
end
for j = numItems + 1, #button.ItemButtons do
button.ItemButtons[j].itemID = nil;
button.ItemButtons[j]:Hide();
end
else
button:Hide();
end
end
local totalHeight = numSets * buttons[1]:GetHeight() + (numSets - 1) * LJ_ITEMSET_BUTTON_SPACING + LJ_ITEMSET_Y_OFFSET + LJ_ITEMSET_BOTTOM_BUFFER
HybridScrollFrame_Update(self, totalHeight, self:GetHeight());
end
LootJournalItemSetButtonMixin = {}
function LootJournalItemSetButtonMixin:OnEnter()
if self.tooltipText then
GameTooltip:SetOwner(self, "ANCHOR_TOP")
GameTooltip:SetText(LOOTJOURNAL_SOURCE_TOOLTIP_HEAD, 1, 1, 1)
GameTooltip:AddLine(self.tooltipText, nil, nil, nil, 1)
self.tooltipSetIndex = self.setIndex
GameTooltip:Show()
else
GameTooltip:Hide()
end
end
function LootJournalItemSetButtonMixin:CheckItemButtonTooltip()
if ( GameTooltip:GetOwner() == self and self.tooltipSetIndex ~= self.setIndex ) then
self:OnEnter();
end
end
@@ -0,0 +1,164 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
..\..\FrameXML\UI.xsd">
<Script file="Custom_LootJournalItems.lua"/>
<Button name="LootJournalItemButtonTemplate" virtual="true">
<Scripts>
<OnEnter function="LootJournalItemButtonTemplate_OnEnter"/>
<OnLeave function="LootJournalItemButtonTemplate_OnLeave"/>
<OnClick function="LootJournalItemButton_OnClick"/>
</Scripts>
</Button>
<Button name="LootJournalItemSetItemButtonTemplate" inherits="LootJournalItemButtonTemplate" virtual="true" hidden="true">
<Size x="32" y="32"/>
<Layers>
<Layer level="BACKGROUND">
<Texture name="$parentIcon" parentKey="Icon">
<Size x="28" y="28"/>
<Anchors>
<Anchor point="CENTER"/>
</Anchors>
</Texture>
</Layer>
<Layer level="BORDER">
<Texture parentKey="Border">
<Anchors>
<Anchor point="RIGHT" relativeTo="$parentIcon" relativePoint="CENTER" x="20" y="1"/>
</Anchors>
</Texture>
</Layer>
</Layers>
<Scripts>
<OnLoad>
self:SetParentArray("ItemButtons")
self.Border:SetAtlas("loottab-set-itemborder-green", true)
</OnLoad>
</Scripts>
</Button>
<Button name="LootJournalItemSetButtonTemplate" virtual="true">
<Size x="744" y="41"/>
<HitRectInsets left="34" right="390" top="1" bottom="1"/>
<Layers>
<Layer level="BACKGROUND">
<Texture parentKey="Background">
<Anchors>
<Anchor point="TOPLEFT" x="0" y="0"/>
</Anchors>
</Texture>
</Layer>
<Layer level="ARTWORK">
<FontString name="$parentSetName" parentKey="SetName" inherits="GameFontNormalMed2" maxLines="1" justifyH="LEFT">
<Size x="320" y="0"/>
<Anchors>
<Anchor point="TOPLEFT" x="38" y="-6"/>
</Anchors>
</FontString>
<FontString name="$parentItemLevel" parentKey="ItemLevel" inherits="GameFontNormal" text="Item Level" maxLines="1" justifyH="LEFT">
<Size x="320" y="0"/>
<Anchors>
<Anchor point="TOPLEFT" relativeTo="$parentSetName" relativePoint="BOTTOMLEFT" x="0" y="-2"/>
</Anchors>
<Color r="0.718" g="0.561" b="0.416"/>
</FontString>
</Layer>
</Layers>
<Frames>
<Frame name="$parentPVPIcon" parentKey="PVPIcon" hidden="true">
<Size x="30" y="30"/>
<Anchors>
<Anchor point="LEFT" relativePoint="LEFT" x="0" y="2"/>
</Anchors>
<Layers>
<Layer level="BACKGROUND">
<Texture name="$parentIcon" parentKey="Icon" file="Interface\PVPFrame\Icons\prestige-icon-4"/>
</Layer>
</Layers>
<Scripts>
<OnEnter>
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
GameTooltip:AddLine(LOOTJOURNAL_PVPICON_TOOLTIP_HEAD, 1, 1, 1)
GameTooltip:AddLine(LOOTJOURNAL_PVPICON_TOOLTIP, nil, nil, nil, 1)
GameTooltip:Show()
</OnEnter>
<OnLeave function="GameTooltip_Hide"/>
</Scripts>
</Frame>
<Button name="$parentItemButton1" parentKey="ItemButton1" inherits="LootJournalItemSetItemButtonTemplate">
<Anchors>
<Anchor point="LEFT" x="397" y="0"/>
</Anchors>
</Button>
</Frames>
<Scripts>
<OnLoad>
Mixin(self, LootJournalItemSetButtonMixin)
self.Background:SetAtlas("loottab-set-background", true)
</OnLoad>
<OnEnter>
self:OnEnter()
</OnEnter>
<OnLeave function="GameTooltip_Hide"/>
</Scripts>
</Button>
<Frame parent="EncounterJournal" name="$parentLootJournalItems" parentKey="LootJournalItems" hidden="true">
<Anchors>
<Anchor point="TOPLEFT" relativeTo="$parentInset" x="4" y="-51" />
<Anchor point="BOTTOMRIGHT" relativeTo="$parentInset" x="-4" y="0"/>
</Anchors>
<Layers>
<Layer level="BACKGROUND">
<Texture parentKey="Background">
<Anchors>
<Anchor point="TOP" x="0" y="4"/>
</Anchors>
</Texture>
</Layer>
</Layers>
<Frames>
<Frame name="LootJournalItemsClassDropDown" parentKey="ClassDropDown" inherits="UIDropDownMenuTemplate" hidden="true">
<Scripts>
<OnLoad function="LootJournalItemsClassDropDown_OnLoad"/>
</Scripts>
</Frame>
<ScrollFrame name="$parentItemSetsFrame" parentKey="ItemSetsFrame" inherits="MinimalHybridScrollFrameTemplate" hidden="true">
<Size x="762" y="332"/>
<Anchors>
<Anchor point="BOTTOMLEFT" x="0" y="3"/>
</Anchors>
<Frames>
<Button parentKey="ClassButton" inherits="EJButtonTemplate" text="FILTER">
<Size x="114" y="26"/>
<Anchors>
<Anchor point="TOPRIGHT" x="-12" y="35"/>
</Anchors>
<Scripts>
<OnMouseDown>
EJButtonMixin.OnMouseDown(self, button);
ToggleDropDownMenu(1, nil, self:GetParent():GetParent().ClassDropDown, self, 5, 0);
PlaySound("igMainMenuOptionCheckBoxOn");
</OnMouseDown>
</Scripts>
</Button>
</Frames>
<Scripts>
<OnLoad>
Mixin(self, LootJournalItemSetsMixin)
self:OnLoad()
</OnLoad>
<OnShow>
self:OnShow()
</OnShow>
</Scripts>
</ScrollFrame>
</Frames>
<Scripts>
<OnLoad>
Mixin(self, LootJournalItemsMixin)
self:OnLoad()
</OnLoad>
</Scripts>
</Frame>
</Ui>
@@ -0,0 +1,919 @@
-- Compatibility shims for the Sirus Encounter Journal backport on 3.3.5a.
if not tIndexOf then
function tIndexOf(tbl, value)
if not tbl then
return nil
end
for index, entry in ipairs(tbl) do
if entry == value then
return index
end
end
return nil
end
end
if not CopyTable then
function CopyTable(tbl)
if type(tbl) ~= "table" then
return tbl
end
local copy = {}
for key, value in pairs(tbl) do
copy[key] = CopyTable(value)
end
return copy
end
end
if not table.wipe then
function table.wipe(tbl)
for key in pairs(tbl) do
tbl[key] = nil
end
return tbl
end
end
if not tCompare then
function tCompare(lhsTable, rhsTable, depth)
depth = depth or 1
for key, value in pairs(lhsTable) do
if type(value) == "table" then
local rhsValue = rhsTable[key]
if type(rhsValue) ~= "table" then
return false
end
if depth > 1 then
if not tCompare(value, rhsValue, depth - 1) then
return false
end
end
elseif value ~= rhsTable[key] then
return false
end
end
for key in pairs(rhsTable) do
if lhsTable[key] == nil then
return false
end
end
return true
end
end
tsort = tsort or table.sort
bit = bit or {}
if not bit.band then
function bit.band(a, b)
local result = 0
local bitValue = 1
a = a or 0
b = b or 0
while a > 0 or b > 0 do
local aBit = a % 2
local bBit = b % 2
if aBit == 1 and bBit == 1 then
result = result + bitValue
end
a = math.floor(a / 2)
b = math.floor(b / 2)
bitValue = bitValue * 2
end
return result
end
end
bitband = bitband or bit.band
if not string.trim then
function string.trim(value)
return value and value:match("^%s*(.-)%s*$") or value
end
end
utf8 = utf8 or {}
utf8.find = utf8.find or string.find
utf8.upper = utf8.upper or string.upper
LE_EXPANSION_CLASSIC = LE_EXPANSION_CLASSIC or 0
LE_EXPANSION_BURNING_CRUSADE = LE_EXPANSION_BURNING_CRUSADE or 1
LE_EXPANSION_WRATH_OF_THE_LICH_KING = LE_EXPANSION_WRATH_OF_THE_LICH_KING or 2
LE_EXPANSION_CATACLYSM = LE_EXPANSION_CATACLYSM or 3
LE_EXPANSION_MISTS_OF_PANDARIA = LE_EXPANSION_MISTS_OF_PANDARIA or 4
LE_EXPANSION_WARLORDS_OF_DRAENOR = LE_EXPANSION_WARLORDS_OF_DRAENOR or 5
LE_EXPANSION_LEGION = LE_EXPANSION_LEGION or 6
LE_EXPANSION_BATTLE_FOR_AZEROTH = LE_EXPANSION_BATTLE_FOR_AZEROTH or 7
LE_EXPANSION_SHADOWLANDS = LE_EXPANSION_SHADOWLANDS or 8
LE_EXPANSION_DRAGONFLIGHT = LE_EXPANSION_DRAGONFLIGHT or 9
LE_EXPANSION_WAR_WITHIN = LE_EXPANSION_WAR_WITHIN or 10
LE_EXPANSION_MIDNIGHT = LE_EXPANSION_MIDNIGHT or 11
LE_EXPANSION_LEVEL_CURRENT = LE_EXPANSION_LEVEL_CURRENT or LE_EXPANSION_WRATH_OF_THE_LICH_KING
MAX_PLAYER_LEVEL_TABLE = MAX_PLAYER_LEVEL_TABLE or {}
MAX_PLAYER_LEVEL_TABLE[LE_EXPANSION_CLASSIC] = MAX_PLAYER_LEVEL_TABLE[LE_EXPANSION_CLASSIC] or 60
MAX_PLAYER_LEVEL_TABLE[LE_EXPANSION_BURNING_CRUSADE] = MAX_PLAYER_LEVEL_TABLE[LE_EXPANSION_BURNING_CRUSADE] or 70
MAX_PLAYER_LEVEL_TABLE[LE_EXPANSION_WRATH_OF_THE_LICH_KING] = MAX_PLAYER_LEVEL_TABLE[LE_EXPANSION_WRATH_OF_THE_LICH_KING] or 80
PLAYER_FACTION_GROUP = PLAYER_FACTION_GROUP or {}
PLAYER_FACTION_GROUP.Alliance = PLAYER_FACTION_GROUP.Alliance or 1
PLAYER_FACTION_GROUP.Horde = PLAYER_FACTION_GROUP.Horde or 2
PLAYER_FACTION_GROUP.Neutral = PLAYER_FACTION_GROUP.Neutral or 3
PLAYER_FACTION_GROUP.Renegade = PLAYER_FACTION_GROUP.Renegade or 4
QUESTION_MARK_ICON = QUESTION_MARK_ICON or "Interface\\Icons\\INV_Misc_QuestionMark"
CLASS_ID_WARRIOR = CLASS_ID_WARRIOR or 1
CLASS_ID_PALADIN = CLASS_ID_PALADIN or 2
CLASS_ID_HUNTER = CLASS_ID_HUNTER or 3
CLASS_ID_ROGUE = CLASS_ID_ROGUE or 4
CLASS_ID_PRIEST = CLASS_ID_PRIEST or 5
CLASS_ID_DEATHKNIGHT = CLASS_ID_DEATHKNIGHT or 6
CLASS_ID_SHAMAN = CLASS_ID_SHAMAN or 7
CLASS_ID_MAGE = CLASS_ID_MAGE or 8
CLASS_ID_WARLOCK = CLASS_ID_WARLOCK or 9
CLASS_ID_DRUID = CLASS_ID_DRUID or 11
if not SetParentFrameLevel then
function SetParentFrameLevel(frame, offset)
frame:SetFrameLevel(frame:GetParent():GetFrameLevel() + (offset or 0))
end
end
if not IsOnGlueScreen then
function IsOnGlueScreen() return false end
end
if not RegisterCustomEvent then
function RegisterCustomEvent() end
end
if not UnregisterCustomEvent then
function UnregisterCustomEvent() end
end
C_Timer = C_Timer or {}
if not C_Timer.NewTimer then
local timerFrame
local timers = {}
local function EnsureTimerFrame()
if timerFrame or not CreateFrame then
return
end
timerFrame = CreateFrame("Frame")
timerFrame:SetScript("OnUpdate", function(_, elapsed)
for timer in pairs(timers) do
timer.remaining = timer.remaining - elapsed
if timer.remaining <= 0 then
timers[timer] = nil
if not timer.cancelled then
timer.callback()
end
end
end
end)
end
function C_Timer.NewTimer(seconds, callback)
local timer = {
remaining = seconds or 0,
callback = callback or function() end,
}
function timer:Cancel()
self.cancelled = true
timers[self] = nil
end
EnsureTimerFrame()
timers[timer] = true
return timer
end
end
C_Timer.After = C_Timer.After or function(seconds, callback)
return C_Timer.NewTimer(seconds, callback)
end
if not IsInterfaceDevClient then
function IsInterfaceDevClient()
return false
end
end
if not IsGMAccount then
function IsGMAccount()
return false
end
end
if not FireCustomClientEvent then
function FireCustomClientEvent(event, ...)
if EventRegistry and EventRegistry.TriggerEvent then
EventRegistry:TriggerEvent(event, ...)
end
end
end
EventRegistry = EventRegistry or {}
EventRegistry.registry = EventRegistry.registry or {}
EventRegistry.TriggerEvent = EventRegistry.TriggerEvent or function(self, event, ...)
local callbacks = self.registry[event]
if callbacks then
for _, callback in ipairs(callbacks) do
callback(...)
end
end
end
EventRegistry.RegisterCallback = EventRegistry.RegisterCallback or function(self, event, callback)
self.registry[event] = self.registry[event] or {}
table.insert(self.registry[event], callback)
end
C_Service = C_Service or {}
C_Service.GetRealmID = function() return 0 end
C_Service.GetRealmStage = C_Service.GetRealmStage or function() return 0 end
C_Service.GetCustomValue = C_Service.GetCustomValue or function() return 0 end
C_Service.IsInGMMode = C_Service.IsInGMMode or IsGMAccount
C_Service.IsGMAccount = C_Service.IsGMAccount or IsGMAccount
C_Service.IsRenegadeRealm = C_Service.IsRenegadeRealm or function() return false end
C_Service.IsHardcoreEnabledOnRealm = C_Service.IsHardcoreEnabledOnRealm or function() return false end
C_MythicPlus = C_MythicPlus or {}
C_MythicPlus.IsMythicPlusActive = C_MythicPlus.IsMythicPlusActive or function() return false end
C_PvP = C_PvP or {}
C_LFGList = C_LFGList or {}
C_LFGList.IsPremadeGroupFinderEnabled = C_LFGList.IsPremadeGroupFinderEnabled or function() return false end
if not MicroButtonPulseStop then
function MicroButtonPulseStop() end
end
if not EJSuggestFrame_OpenFrame then
function EJSuggestFrame_OpenFrame() end
end
if not EJSuggestTab_GetPlayerTierIndex then
function EJSuggestTab_GetPlayerTierIndex()
if EJ_GetCurrentTier then
return EJ_GetCurrentTier()
end
return 1
end
end
if not ChatEdit_TryInsertChatLink then
function ChatEdit_TryInsertChatLink()
return false
end
end
if not SharedTooltip_SetBackdropStyle then
function SharedTooltip_SetBackdropStyle(tooltip)
if not tooltip then
return
end
if tooltip.SetBackdropBorderColor and TOOLTIP_DEFAULT_COLOR then
tooltip:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b)
end
if tooltip.SetBackdropColor and TOOLTIP_DEFAULT_BACKGROUND_COLOR then
tooltip:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b)
end
end
end
if not HelpPlate_Hide then
function HelpPlate_Hide() end
end
if not HelpPlate_Show then
function HelpPlate_Show() end
end
-- 3.3.5 has no GetNumClasses/GetClassInfo (added in Cataclysm). Sirus EJ uses
-- them to populate the loot class filter dropdown.
local MOONWELL_CLASS_INFO = {
{LOCALIZED_CLASS_NAMES_MALE and LOCALIZED_CLASS_NAMES_MALE.WARRIOR or "Warrior", "WARRIOR", CLASS_ID_WARRIOR},
{LOCALIZED_CLASS_NAMES_MALE and LOCALIZED_CLASS_NAMES_MALE.PALADIN or "Paladin", "PALADIN", CLASS_ID_PALADIN},
{LOCALIZED_CLASS_NAMES_MALE and LOCALIZED_CLASS_NAMES_MALE.HUNTER or "Hunter", "HUNTER", CLASS_ID_HUNTER},
{LOCALIZED_CLASS_NAMES_MALE and LOCALIZED_CLASS_NAMES_MALE.ROGUE or "Rogue", "ROGUE", CLASS_ID_ROGUE},
{LOCALIZED_CLASS_NAMES_MALE and LOCALIZED_CLASS_NAMES_MALE.PRIEST or "Priest", "PRIEST", CLASS_ID_PRIEST},
{LOCALIZED_CLASS_NAMES_MALE and LOCALIZED_CLASS_NAMES_MALE.DEATHKNIGHT or "Death Knight", "DEATHKNIGHT", CLASS_ID_DEATHKNIGHT},
{LOCALIZED_CLASS_NAMES_MALE and LOCALIZED_CLASS_NAMES_MALE.SHAMAN or "Shaman", "SHAMAN", CLASS_ID_SHAMAN},
{LOCALIZED_CLASS_NAMES_MALE and LOCALIZED_CLASS_NAMES_MALE.MAGE or "Mage", "MAGE", CLASS_ID_MAGE},
{LOCALIZED_CLASS_NAMES_MALE and LOCALIZED_CLASS_NAMES_MALE.WARLOCK or "Warlock", "WARLOCK", CLASS_ID_WARLOCK},
{LOCALIZED_CLASS_NAMES_MALE and LOCALIZED_CLASS_NAMES_MALE.DRUID or "Druid", "DRUID", CLASS_ID_DRUID},
}
if not GetNumClasses then
function GetNumClasses()
return #MOONWELL_CLASS_INFO
end
end
if not GetClassInfo then
function GetClassInfo(index)
local info = MOONWELL_CLASS_INFO[index]
if info then
return info[1], info[2], info[3]
end
end
end
CLASS_ID_DEMONHUNTER = CLASS_ID_DEMONHUNTER or 12
local function EnsureColorMethods(color)
if type(color) ~= "table" then
return color
end
color.GetRGB = color.GetRGB or function(self)
return self.r or 1, self.g or 1, self.b or 1
end
color.GetRGBA = color.GetRGBA or function(self)
return self.r or 1, self.g or 1, self.b or 1, self.a or 1
end
color.WrapTextInColorCode = color.WrapTextInColorCode or function(self, text)
if self.colorStr then
return "|c" .. self.colorStr .. text .. "|r"
end
return text
end
return color
end
EnsureColorMethods(NORMAL_FONT_COLOR)
EnsureColorMethods(HIGHLIGHT_FONT_COLOR)
EnsureColorMethods(RED_FONT_COLOR)
EnsureColorMethods(GREEN_FONT_COLOR)
EnsureColorMethods(DISABLED_FONT_COLOR)
LOOTJOURNAL_SOURCE_TOOLTIP_HEAD = LOOTJOURNAL_SOURCE_TOOLTIP_HEAD or "Способ получения:"
RETURN_TO_DEFAULT = RETURN_TO_DEFAULT or "Настройки по умолчанию"
INSTANCES = INSTANCES or "Подземелья"
RAIDS = RAIDS or "Рейды"
LOOT_JOURNAL_ITEM_SETS = LOOT_JOURNAL_ITEM_SETS or "Комплекты"
-- Format string used by EncounterJournal_SetLootButton to label the loot
-- source ("Босс: <name>"). Sirus ships it via locale globals; default to a
-- compact form on 3.3.5.
BOSS_INFO_STRING = BOSS_INFO_STRING or "Босс: %s"
-- Sirus ships a PKBT model mixin in SharedXML/SharedUIPanelPKBTTemplates;
-- we don't carry it. The EJ DressUpModel OnShow does `self:OnShow()` and
-- OnEvent does `self:OnEvent(...)`, expecting the mixin to provide them.
PKBT_ModelMixin = PKBT_ModelMixin or {}
PKBT_ModelMixin.OnShow = PKBT_ModelMixin.OnShow or function() end
PKBT_ModelMixin.OnEvent = PKBT_ModelMixin.OnEvent or function() end
PKBT_ModelMixin.OnLoad = PKBT_ModelMixin.OnLoad or function() end
if not SharedXML_Model_OnLoad then
function SharedXML_Model_OnLoad() end
end
if not SharedXML_Model_OnEvent then
function SharedXML_Model_OnEvent() end
end
ITEM_CLASS_2 = ITEM_CLASS_2 or 2
ITEM_CLASS_4 = ITEM_CLASS_4 or 4
for _, classID in ipairs({0, 2, 4, 5, 7, 9, 11, 12, 13, 14, 15}) do
for subclassID = 0, 20 do
local key = string.format("ITEM_SUB_CLASS_%d_%d", classID, subclassID)
if _G[key] == nil then
_G[key] = subclassID
end
end
end
LE_ITEM_FILTER_TYPE_HEAD = LE_ITEM_FILTER_TYPE_HEAD or 1
LE_ITEM_FILTER_TYPE_NECK = LE_ITEM_FILTER_TYPE_NECK or 2
LE_ITEM_FILTER_TYPE_SHOULDER = LE_ITEM_FILTER_TYPE_SHOULDER or 3
LE_ITEM_FILTER_TYPE_CLOAK = LE_ITEM_FILTER_TYPE_CLOAK or 16
LE_ITEM_FILTER_TYPE_CHEST = LE_ITEM_FILTER_TYPE_CHEST or 5
LE_ITEM_FILTER_TYPE_WRIST = LE_ITEM_FILTER_TYPE_WRIST or 9
LE_ITEM_FILTER_TYPE_HAND = LE_ITEM_FILTER_TYPE_HAND or 10
LE_ITEM_FILTER_TYPE_WAIST = LE_ITEM_FILTER_TYPE_WAIST or 6
LE_ITEM_FILTER_TYPE_LEGS = LE_ITEM_FILTER_TYPE_LEGS or 7
LE_ITEM_FILTER_TYPE_FEET = LE_ITEM_FILTER_TYPE_FEET or 8
LE_ITEM_FILTER_TYPE_MAIN_HAND = LE_ITEM_FILTER_TYPE_MAIN_HAND or 21
LE_ITEM_FILTER_TYPE_OFF_HAND = LE_ITEM_FILTER_TYPE_OFF_HAND or 22
LE_ITEM_FILTER_TYPE_2HWEAPON = LE_ITEM_FILTER_TYPE_2HWEAPON or 17
LE_ITEM_FILTER_TYPE_HWEAPON = LE_ITEM_FILTER_TYPE_HWEAPON or 13
LE_ITEM_FILTER_TYPE_RANGED = LE_ITEM_FILTER_TYPE_RANGED or 15
LE_ITEM_FILTER_TYPE_FINGER = LE_ITEM_FILTER_TYPE_FINGER or 11
LE_ITEM_FILTER_TYPE_TRINKET = LE_ITEM_FILTER_TYPE_TRINKET or 12
LE_ITEM_QUALITY_COMMON = LE_ITEM_QUALITY_COMMON or 1
BAG_ITEM_QUALITY_COLORS = BAG_ITEM_QUALITY_COLORS or {}
local itemQualityColors = ITEM_QUALITY_COLORS or {}
for quality = 0, 7 do
local color = BAG_ITEM_QUALITY_COLORS[quality] or itemQualityColors[quality] or NORMAL_FONT_COLOR
BAG_ITEM_QUALITY_COLORS[quality] = EnsureColorMethods(color or {})
end
if not SetItemButtonQuality then
function SetItemButtonQuality(button, quality)
if not button or not button.IconBorder then
return
end
local color = quality and BAG_ITEM_QUALITY_COLORS[quality]
if color then
button.IconBorder:Show()
button.IconBorder:SetVertexColor(color.r or 1, color.g or 1, color.b or 1)
else
button.IconBorder:Hide()
end
end
end
Enum = Enum or {}
Enum.ItemQuality = Enum.ItemQuality or {
Poor = 0,
Common = 1,
Uncommon = 2,
Rare = 3,
Epic = 4,
Legendary = 5,
Artifact = 6,
Heirloom = 7,
}
Enum.ModelType = Enum.ModelType or {
M2 = 0,
Unit = 1,
Creature = 2,
Item = 3,
ItemSet = 4,
Illusion = 5,
ItemTransmog = 6,
Customization = 7,
}
Enum.HardcoreDeathReason = Enum.HardcoreDeathReason or {
FAILED_DEATH = 1,
RESTORE = 2,
}
local ITEM_CACHE_FIELD = {
NAME_ENGB = 1,
NAME_RURU = 2,
RARITY = 3,
ILEVEL = 4,
MINLEVEL = 5,
TYPE = 6,
SUBTYPE = 7,
STACKCOUNT = 8,
EQUIPLOC = 9,
TEXTURE = 10,
VENDORPRICE = 11,
VENDORPRIC = 11,
}
local ITEM_ID_FIELD = 0
local ITEM_LINK_FIELD = -1
Enum.ItemCacheField = Enum.ItemCacheField or {}
for key, value in pairs(ITEM_CACHE_FIELD) do
Enum.ItemCacheField[key] = value
end
Enum.ItemCacheField.ITEM_ID = ITEM_ID_FIELD
SHARED_INVTYPE_BY_ID = SHARED_INVTYPE_BY_ID or {
[0] = "",
[1] = "INVTYPE_HEAD",
[2] = "INVTYPE_NECK",
[3] = "INVTYPE_SHOULDER",
[4] = "INVTYPE_BODY",
[5] = "INVTYPE_CHEST",
[6] = "INVTYPE_WAIST",
[7] = "INVTYPE_LEGS",
[8] = "INVTYPE_FEET",
[9] = "INVTYPE_WRIST",
[10] = "INVTYPE_HAND",
[11] = "INVTYPE_FINGER",
[12] = "INVTYPE_TRINKET",
[13] = "INVTYPE_WEAPON",
[14] = "INVTYPE_SHIELD",
[15] = "INVTYPE_RANGED",
[16] = "INVTYPE_CLOAK",
[17] = "INVTYPE_2HWEAPON",
[18] = "INVTYPE_BAG",
[19] = "INVTYPE_TABARD",
[20] = "INVTYPE_ROBE",
[21] = "INVTYPE_WEAPONMAINHAND",
[22] = "INVTYPE_WEAPONOFFHAND",
[23] = "INVTYPE_HOLDABLE",
[24] = "INVTYPE_AMMO",
[25] = "INVTYPE_THROWN",
[26] = "INVTYPE_RANGEDRIGHT",
[27] = "INVTYPE_QUIVER",
[28] = "INVTYPE_RELIC",
}
C_FactionManager = C_FactionManager or {}
C_FactionManager.GetFactionInfoOriginal = C_FactionManager.GetFactionInfoOriginal or function()
local faction = UnitFactionGroup and UnitFactionGroup("player")
return PLAYER_FACTION_GROUP[faction] or PLAYER_FACTION_GROUP.Alliance
end
C_FactionManager.RegisterCallback = C_FactionManager.RegisterCallback or function(callback)
if callback then
callback()
end
end
C_Item = C_Item or {}
local ExistingCItemGetItemInfo = C_Item.GetItemInfo
local ExistingCItemRequestServerCache = C_Item.RequestServerCache
local ExistingCItemGetItemIDFromString = C_Item.GetItemIDFromString
local ITEM_CACHE_CALLBACKS = {}
local ITEM_QUALITY_HEX = {
[0] = "ff9d9d9d",
[1] = "ffffffff",
[2] = "ff1eff00",
[3] = "ff0070dd",
[4] = "ffa335ee",
[5] = "ffff8000",
[6] = "ffe6cc80",
[7] = "ffe6cc80",
}
local ITEMS_CACHE_INITIALIZED
local function GetItemIDFromAny(item)
if type(item) == "number" then
return item
end
if type(item) == "string" then
local itemsCache = _G.ItemsCache
if type(itemsCache) == "table" and type(itemsCache[item]) == "table" then
return itemsCache[item][ITEM_ID_FIELD]
end
return tonumber(item:match("item:(%d+)") or item:match("^(%d+)$"))
end
end
local function CreateItemCacheLink(itemName, itemID, itemRarity, itemMinLevel)
return string.format("|c%s|Hitem:%d:0:0:0:0:0:0:0:%d|h[%s]|h|r",
ITEM_QUALITY_HEX[itemRarity] or "ffffffff",
itemID or 0,
itemMinLevel or 0,
itemName or UNKNOWN or ""
)
end
local function EnsureItemsCache()
if ITEMS_CACHE_INITIALIZED then
return _G.ItemsCache
end
local itemsCache = type(_G.ItemsCache) == "table" and _G.ItemsCache or nil
local fileIndex = 1
local itemCacheTable = _G["ItemsCache" .. fileIndex]
while type(itemCacheTable) == "table" do
if not itemsCache then
itemsCache = itemCacheTable
_G.ItemsCache = itemsCache
elseif itemCacheTable ~= itemsCache then
for itemID, itemData in pairs(itemCacheTable) do
itemsCache[itemID] = itemData
end
table.wipe(itemCacheTable)
end
_G["ItemsCache" .. fileIndex] = nil
fileIndex = fileIndex + 1
itemCacheTable = _G["ItemsCache" .. fileIndex]
end
if itemsCache then
local localeIndex = GetLocale and GetLocale() == "ruRU" and ITEM_CACHE_FIELD.NAME_RURU or ITEM_CACHE_FIELD.NAME_ENGB
local namedItems = {}
for itemID, itemData in pairs(itemsCache) do
if type(itemID) == "number" and type(itemData) == "table" then
itemData[ITEM_ID_FIELD] = itemID
itemData[ITEM_LINK_FIELD] = nil
local itemName = itemData[localeIndex]
if itemName and itemName ~= "" then
namedItems[itemName] = itemData
end
end
end
setmetatable(itemsCache, {__index = namedItems})
end
ITEMS_CACHE_INITIALIZED = true
return itemsCache
end
function C_Item.GetItemInfoCache(item)
local itemsCache = EnsureItemsCache()
if not itemsCache then
return
end
local itemID = GetItemIDFromAny(item)
if not itemID then
return
end
local cacheData = itemsCache[itemID]
if type(cacheData) ~= "table" then
return
end
local localeIndex = GetLocale and GetLocale() == "ruRU" and ITEM_CACHE_FIELD.NAME_RURU or ITEM_CACHE_FIELD.NAME_ENGB
local itemName = cacheData[localeIndex] or cacheData[ITEM_CACHE_FIELD.NAME_ENGB]
if not itemName or itemName == "" then
return
end
local itemRarity = cacheData[ITEM_CACHE_FIELD.RARITY] or LE_ITEM_QUALITY_COMMON
local itemMinLevel = cacheData[ITEM_CACHE_FIELD.MINLEVEL] or 0
local classID = cacheData[ITEM_CACHE_FIELD.TYPE]
local subclassID = cacheData[ITEM_CACHE_FIELD.SUBTYPE]
local equipLocID = cacheData[ITEM_CACHE_FIELD.EQUIPLOC] or 0
if not cacheData[ITEM_LINK_FIELD] then
cacheData[ITEM_LINK_FIELD] = CreateItemCacheLink(itemName, itemID, itemRarity, itemMinLevel)
end
return itemName,
cacheData[ITEM_LINK_FIELD],
itemRarity,
cacheData[ITEM_CACHE_FIELD.ILEVEL],
itemMinLevel,
_G["ITEM_CLASS_" .. tostring(classID)] or classID,
_G["ITEM_SUB_CLASS_" .. tostring(classID) .. "_" .. tostring(subclassID)] or subclassID,
cacheData[ITEM_CACHE_FIELD.STACKCOUNT],
SHARED_INVTYPE_BY_ID[equipLocID],
"Interface\\Icons\\" .. tostring(cacheData[ITEM_CACHE_FIELD.TEXTURE] or "INV_Misc_QuestionMark"),
cacheData[ITEM_CACHE_FIELD.VENDORPRICE],
itemID,
classID,
subclassID,
equipLocID
end
local function GetItemInfoCompat(item)
local name, link, quality, itemLevel, reqLevel, itemType, itemSubType, maxStack, equipSlot, icon, vendorPrice = GetItemInfo(item)
if name then
return name, link, quality, itemLevel, reqLevel, itemType, itemSubType, maxStack, equipSlot, icon, vendorPrice
end
return C_Item.GetItemInfoCache(item)
end
local function FireItemCacheCallbacks(itemID)
local callbacks = ITEM_CACHE_CALLBACKS[itemID]
if not callbacks then
return
end
local name, link, quality, itemLevel, reqLevel, itemType, itemSubType, maxStack, equipSlot, icon, vendorPrice = GetItemInfoCompat(itemID)
if not name then
return
end
ITEM_CACHE_CALLBACKS[itemID] = nil
for _, callback in ipairs(callbacks) do
callback(itemID, name, link, quality, itemLevel, reqLevel, itemType, itemSubType, maxStack, equipSlot, icon, vendorPrice)
end
end
local function QueueItemCacheCallback(item, callback)
if not callback then
return
end
local itemID = tonumber(item)
if not itemID and type(item) == "string" then
itemID = tonumber(item:match("item:(%d+)") or item:match("^(%d+)$"))
end
if not itemID then
return
end
ITEM_CACHE_CALLBACKS[itemID] = ITEM_CACHE_CALLBACKS[itemID] or {}
table.insert(ITEM_CACHE_CALLBACKS[itemID], callback)
end
local itemCacheFrame
local function EnsureItemCacheFrame()
if itemCacheFrame or not CreateFrame then
return
end
itemCacheFrame = CreateFrame("Frame")
itemCacheFrame:RegisterEvent("GET_ITEM_INFO_RECEIVED")
itemCacheFrame:SetScript("OnEvent", function(_, _, itemID)
if itemID then
FireItemCacheCallbacks(itemID)
else
for queuedItemID in pairs(ITEM_CACHE_CALLBACKS) do
FireItemCacheCallbacks(queuedItemID)
end
end
end)
end
C_Item.GetItemInfo = function(item, skipClientCache, callback, ...)
local name, link, quality, itemLevel, reqLevel, itemType, itemSubType, maxStack, equipSlot, icon, vendorPrice
if ExistingCItemGetItemInfo then
name, link, quality, itemLevel, reqLevel, itemType, itemSubType, maxStack, equipSlot, icon, vendorPrice = ExistingCItemGetItemInfo(item, skipClientCache, nil, ...)
end
if not name then
name, link, quality, itemLevel, reqLevel, itemType, itemSubType, maxStack, equipSlot, icon, vendorPrice = GetItemInfoCompat(item)
end
if callback then
if name then
callback(GetItemIDFromAny(item) or item, name, link, quality, itemLevel, reqLevel, itemType, itemSubType, maxStack, equipSlot, icon, vendorPrice)
else
QueueItemCacheCallback(item, callback)
EnsureItemCacheFrame()
end
end
return name, link, quality, itemLevel, reqLevel, itemType, itemSubType, maxStack, equipSlot, icon, vendorPrice
end
C_Item.RequestServerCache = function(item, callback)
local name, link, quality, itemLevel, reqLevel, itemType, itemSubType, maxStack, equipSlot, icon, vendorPrice = GetItemInfoCompat(item)
if callback then
if name then
callback(GetItemIDFromAny(item) or item, name, link, quality, itemLevel, reqLevel, itemType, itemSubType, maxStack, equipSlot, icon, vendorPrice)
elseif ExistingCItemRequestServerCache then
return ExistingCItemRequestServerCache(item, callback)
else
QueueItemCacheCallback(item, callback)
EnsureItemCacheFrame()
end
end
return name, link, quality, itemLevel, reqLevel, itemType, itemSubType, maxStack, equipSlot, icon, vendorPrice
end
C_Item.GetItemIDFromString = function(item)
local itemID = ExistingCItemGetItemIDFromString and ExistingCItemGetItemIDFromString(item)
if itemID then
return itemID
end
EnsureItemsCache()
return GetItemIDFromAny(item)
end
EnsureItemsCache()
if not Mixin then
function Mixin(object, ...)
for i = 1, select("#", ...) do
local mixin = select(i, ...)
for key, value in pairs(mixin) do
object[key] = value
end
end
return object
end
end
if not CreateFromMixins then
function CreateFromMixins(...)
return Mixin({}, ...)
end
end
if not CreateAndInitFromMixin then
function CreateAndInitFromMixin(mixin, ...)
local object = CreateFromMixins(mixin)
object:Init(...)
return object
end
end
if not InlineHyperlinkFrame_SimpleHTMLAsFontString_OnLoad then
function InlineHyperlinkFrame_SimpleHTMLAsFontString_OnLoad(self)
if PKBT_SimpleHTMLAsFontStringMixin then
Mixin(self, PKBT_SimpleHTMLAsFontStringMixin)
if self.OnLoadSimpleHTMLAsFontString then
self:OnLoadSimpleHTMLAsFontString()
end
elseif self.GetRegions and not self:GetRegions() then
local meta = getmetatable(self)
local methods = meta and meta.__index
if methods and methods.SetText then
methods.SetText(self, "")
end
end
end
end
local function InstallTextureAtlasShim()
if not CreateFrame then
return
end
local texture = CreateFrame("Frame"):CreateTexture(nil, "ARTWORK")
local meta = getmetatable(texture)
local methods = meta and meta.__index
local atlasToTexture = {
["adventureguide-pane-large"] = {335, 337, 0.001953, 0.656250, 0.320312, 0.978516, "Interface\\EncounterJournal\\AdventureGuide"},
["adventureguide-pane-small"] = {344, 161, 0.001953, 0.673828, 0.001953, 0.316406, "Interface\\EncounterJournal\\AdventureGuide"},
["adventureguide-ring"] = {94, 95, 0.775391, 0.958984, 0.001953, 0.187500, "Interface\\EncounterJournal\\AdventureGuide"},
["adventureguide-rewardring"] = {48, 48, 0.677734, 0.771484, 0.001953, 0.095703, "Interface\\EncounterJournal\\AdventureGuide"},
["adventureguide-redx"] = {35, 34, 0.677734, 0.746094, 0.175781, 0.242188, "Interface\\EncounterJournal\\AdventureGuide"},
["UI-EJ-Classic"] = {786, 425, 0.000977, 0.768555, 0.417969, 0.833008, "Interface\\EncounterJournal\\DungeonJournalTierBackgrounds1"},
["UI-EJ-BurningCrusade"] = {786, 425, 0.000977, 0.768555, 0.000977, 0.416016, "Interface\\EncounterJournal\\DungeonJournalTierBackgrounds1"},
["UI-EJ-WrathoftheLichKing"] = {786, 425, 0.000977, 0.768555, 0.417969, 0.833008, "Interface\\EncounterJournal\\DungeonJournalTierBackgrounds2"},
["UI-EJ-Cataclysm"] = {786, 425, 0.000977, 0.768555, 0.000977, 0.416016, "Interface\\EncounterJournal\\DungeonJournalTierBackgrounds2"},
["UI-EJ-MistsofPandaria"] = {786, 425, 0.000977, 0.768555, 0.000977, 0.416016, "Interface\\EncounterJournal\\DungeonJournalTierBackgrounds3"},
["UI-EJ-WarlordsofDraenor"] = {786, 425, 0.000977, 0.768555, 0.417969, 0.833008, "Interface\\EncounterJournal\\DungeonJournalTierBackgrounds3"},
["UI-EJ-BattleforAzeroth"] = {786, 425, 0.000977, 0.768555, 0.000977, 0.416016, "Interface\\EncounterJournal\\DungeonJournalTierBackgrounds4"},
["UI-EJ-Legion"] = {786, 425, 0.000977, 0.768555, 0.417969, 0.833008, "Interface\\EncounterJournal\\DungeonJournalTierBackgrounds4"},
["UI-EJ-Dragonflight"] = {786, 425, 0.000977, 0.768555, 0.000977, 0.416016, "Interface\\EncounterJournal\\DungeonJournalTierBackgrounds5"},
["UI-EJ-Shadowlands"] = {786, 425, 0.000977, 0.768555, 0.417969, 0.833008, "Interface\\EncounterJournal\\DungeonJournalTierBackgrounds5"},
["UI-EJ-TheWarWithin"] = {786, 425, 0.000977, 0.768555, 0.000977, 0.416016, "Interface\\EncounterJournal\\DungeonJournalTierBackgrounds6"},
["UI-EJ-Midnight"] = {786, 425, 0.000977, 0.768555, 0.417969, 0.833008, "Interface\\EncounterJournal\\DungeonJournalTierBackgrounds6"},
}
if type(methods) == "table" and not methods.SetAtlas then
methods.SetAtlas = function(self, atlas, useAtlasSize)
local atlasInfo = atlasToTexture[atlas]
if atlasInfo then
self:SetTexture(atlasInfo[7])
self:SetTexCoord(atlasInfo[3], atlasInfo[4], atlasInfo[5], atlasInfo[6])
if useAtlasSize then
self:SetSize(atlasInfo[1], atlasInfo[2])
end
elseif SetAtlasTexture then
local ok = pcall(SetAtlasTexture, self, atlas)
if not ok then
self:SetTexture(nil)
end
else
self:SetTexture(nil)
end
end
end
end
InstallTextureAtlasShim()
local function InstallFrameMethodShims()
if not CreateFrame then
return
end
local frame = CreateFrame("Frame")
local meta = getmetatable(frame)
local methods = meta and meta.__index
if type(methods) ~= "table" or methods.SetParentArray then
return
end
methods.SetParentArray = function(self, arrayName)
local parent = self:GetParent()
if not parent or not arrayName then
return
end
parent[arrayName] = parent[arrayName] or {}
table.insert(parent[arrayName], self)
end
end
InstallFrameMethodShims()
if not EncounterJournal_SetSearchPreviewSelection then
function EncounterJournal_SetSearchPreviewSelection(selectedIndex)
if not EncounterJournal or not EncounterJournal.searchBox then
return
end
local searchBox = EncounterJournal.searchBox
searchBox.selectedIndex = selectedIndex or 1
if searchBox.searchPreview then
for index, button in ipairs(searchBox.searchPreview) do
if button.selectedTexture then
if index == searchBox.selectedIndex then
button.selectedTexture:Show()
else
button.selectedTexture:Hide()
end
end
end
end
if searchBox.showAllResults and searchBox.showAllResults.selectedTexture then
searchBox.showAllResults.selectedTexture:Hide()
end
end
end
@@ -0,0 +1,32 @@
-- Optional AIO bridge: lets the server push fresh Encounter Journal data at runtime.
-- The static fallback is loaded from Generated_EncounterJournal.lua, so the journal works
-- without ever calling ApplyEncounterJournalData.
local function ApplyEncounterJournalData(data)
if type(data) ~= "table" then
return
end
JOURNALINSTANCE = data.JOURNALINSTANCE or data.instances or JOURNALINSTANCE
JOURNALENCOUNTER = data.JOURNALENCOUNTER or data.encounters or JOURNALENCOUNTER
JOURNALENCOUNTERCREATURE = data.JOURNALENCOUNTERCREATURE or data.creatures or JOURNALENCOUNTERCREATURE
JOURNALENCOUNTERITEM = data.JOURNALENCOUNTERITEM or data.items or JOURNALENCOUNTERITEM
JOURNALENCOUNTERSECTION = data.JOURNALENCOUNTERSECTION or data.sections or JOURNALENCOUNTERSECTION
JOURNALTIER = data.JOURNALTIER or data.tiers or JOURNALTIER
JOURNALTIERXINSTANCE = data.JOURNALTIERXINSTANCE or data.tierInstances or JOURNALTIERXINSTANCE
JOURNAACTUALRAIDS = data.JOURNAACTUALRAIDS or data.actualRaids or JOURNAACTUALRAIDS
if C_EncounterJournal and C_EncounterJournal.ReloadData then
C_EncounterJournal.ReloadData()
end
end
MoonWell_ApplyEncounterJournalData = ApplyEncounterJournalData
if AIO then
local Handler = AIO.AddHandlers("MoonWellEncounterJournal", {})
function Handler.SetData(_, data)
ApplyEncounterJournalData(data)
end
end
@@ -0,0 +1,155 @@
-- Hide the Sirus Encounter Journal panels we don't ship: suggested content,
-- LootJournal/ItemBrowser, search box, retail-era top tabs. Dungeons + Raids stay.
-- The shipped Sirus tab layout assumes all four content tabs are visible; this
-- skin repositions the two tabs we keep.
local function HideFrame(frame)
if frame then
frame:Hide()
end
end
local function HideTabKeepEnabled(tab)
if not tab then
return
end
tab:Hide()
-- Keep the tab enabled so Sirus EJ_OnShow does not fall back to the
-- suggest-tier code path (EJSuggestTab_GetPlayerTierIndex etc).
end
local function ConfigureTierTab(tab, text)
if not tab then
return
end
tab:SetText(text or "")
if tab.SetNormalFontObject and GameFontNormal then
tab:SetNormalFontObject(GameFontNormal)
end
if tab.SetHighlightFontObject and GameFontHighlight then
tab:SetHighlightFontObject(GameFontHighlight)
end
if tab.SetDisabledFontObject and GameFontNormal then
tab:SetDisabledFontObject(GameFontNormal)
end
local fontString = tab:GetFontString()
if fontString then
fontString:SetText(text or "")
fontString:ClearAllPoints()
fontString:SetPoint("CENTER", tab, "CENTER", 0, -3)
if fontString.SetDrawLayer then
fontString:SetDrawLayer("OVERLAY", 7)
end
end
tab:SetWidth(math.max((tab:GetTextWidth() or 0) + 28, 92))
end
local function PositionVisibleTierTabs(instanceSelect)
local dungeonsTab = instanceSelect and instanceSelect.dungeonsTab
local raidsTab = instanceSelect and instanceSelect.raidsTab
if not dungeonsTab or not raidsTab then
return
end
ConfigureTierTab(dungeonsTab, INSTANCES or "Instances")
ConfigureTierTab(raidsTab, RAIDS or "Raids")
dungeonsTab:ClearAllPoints()
dungeonsTab:SetPoint("BOTTOMLEFT", instanceSelect, "TOPLEFT", 150, -45)
raidsTab:ClearAllPoints()
raidsTab:SetPoint("BOTTOMLEFT", dungeonsTab, "BOTTOMRIGHT", 22, 0)
end
local function GetVisibleSelectedTabID(instanceSelect)
if not instanceSelect then
return
end
local selectedTab = instanceSelect.selectedTab
local dungeonsTab = instanceSelect.dungeonsTab
local raidsTab = instanceSelect.raidsTab
if raidsTab and selectedTab == raidsTab.id then
return selectedTab
end
if dungeonsTab then
dungeonsTab.id = dungeonsTab.id or dungeonsTab:GetID()
return dungeonsTab.id
end
end
local function SelectVisibleInstanceTab(journal)
local instanceSelect = journal and journal.instanceSelect
if not instanceSelect then
return
end
local selectedTab = GetVisibleSelectedTabID(instanceSelect)
if selectedTab then
instanceSelect.selectedTab = selectedTab
end
if journal:IsShown()
and instanceSelect:IsShown()
and (not journal.encounter or not journal.encounter:IsShown())
and selectedTab
and EJ_ContentTab_Select
then
EJ_ContentTab_Select(selectedTab)
end
end
local function ApplyDungeonAndRaidOnlySkin()
local journal = EncounterJournal
if not journal then
return
end
-- Sirus EJ_OnLoad sets numTabs at the very end; if anything earlier in
-- OnLoad bails out, PanelTemplates_UpdateTabs blows up later with a nil
-- for-limit when OnShow calls PanelTemplates_SetTab. Guard it.
if journal.numTabs == nil then
journal.numTabs = 4
end
HideFrame(journal.searchBox)
HideFrame(journal.searchResults)
HideFrame(journal.suggestFrame)
HideFrame(journal.LootJournal)
HideFrame(journal.LootJournalItems)
HideFrame(journal.TutorialButton)
for index = 1, 4 do
HideFrame(_G["EncounterJournalTab" .. index])
end
local instanceSelect = journal.instanceSelect
if instanceSelect then
HideTabKeepEnabled(instanceSelect.suggestTab)
HideTabKeepEnabled(instanceSelect.LootJournalTab)
-- Sirus EJ_OnShow forwards instanceSelect.selectedTab into
-- EJ_ContentTab_Select; if it's nil the tab loop matches nothing and
-- selectedTab.selectedGlow blows up. Default to the dungeons tab.
local dungeonsTab = instanceSelect.dungeonsTab
if dungeonsTab then
dungeonsTab.id = dungeonsTab.id or dungeonsTab:GetID()
end
PositionVisibleTierTabs(instanceSelect)
SelectVisibleInstanceTab(journal)
end
end
MoonWell_EncounterJournalApplyDungeonMode = ApplyDungeonAndRaidOnlySkin
if EncounterJournal then
ApplyDungeonAndRaidOnlySkin()
EncounterJournal:HookScript("OnShow", ApplyDungeonAndRaidOnlySkin)
end
@@ -0,0 +1,34 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
..\FrameXML\UI.xsd">
<Font name="QuestFont_Super_Huge" font="Fonts\MORPHEUS.ttf" virtual="true">
<FontHeight val="24"/>
<Color r="1" g=".82" b="0"/>
</Font>
<Font name="QuestFont_Super_Huge2" font="Fonts\MORPHEUS.ttf" virtual="true">
<FontHeight val="26"/>
<Shadow>
<Offset x="2" y="-2"/>
<Color r="0" g="0" b="0"/>
</Shadow>
</Font>
<Font name="GameFontNormalMed1" inherits="GameFontNormal" virtual="true">
<FontHeight val="12"/>
<Shadow>
<Offset x="1" y="-1"/>
<Color r="0" g="0" b="0"/>
</Shadow>
<Color r="1" g=".82" b="0"/>
</Font>
<Font name="QuestFont22" font="Fonts\MORPHEUS.ttf" virtual="true">
<FontHeight val="22"/>
<Color r="1" g=".82" b="0"/>
</Font>
<Font name="QuestFont_Enormous" font="Fonts\MORPHEUS.ttf" virtual="true">
<FontHeight val="30"/>
<Color r="1" g=".82" b="0"/>
</Font>
<Font name="DestinyFontHuge" font="Fonts\MORPHEUS.ttf" virtual="true">
<FontHeight val="32"/>
<Color r="1" g=".82" b="0"/>
</Font>
</Ui>
@@ -0,0 +1,131 @@
-- Minimal Frame metatable extensions used by Sirus EJ. Replaces Sirus
-- SharedExtendedMethods.lua, which clobbers SetUnit/PlayerModel methods with
-- retail-only API (ResetAllSpells, SetSpell, SetUnitRaw, GetDisplayIDs,
-- C_CustomizationsCollection.*) and breaks TabardFrame/DressUpFrame on 3.3.5.
local function getMeta(objType)
local frame = CreateFrame(objType)
frame:Hide()
return getmetatable(frame).__index
end
local function RegisterCustomEventNoop() end
local function UnregisterCustomEventNoop() end
local function SetShown(self, shown)
if shown then
self:Show()
else
self:Hide()
end
end
local function SetParentArray(self, arrayName)
local parent = self:GetParent()
if not parent or not arrayName then
return
end
parent[arrayName] = parent[arrayName] or {}
table.insert(parent[arrayName], self)
end
local function SetEnabled(self, enabled)
if enabled then
self:Enable()
else
self:Disable()
end
end
-- Sirus EJ calls Frame/Button:IsMouseOverEx() (Cataclysm+ retail-only).
-- Map to the 3.3.5 IsMouseOver().
local function IsMouseOverEx(self)
return self:IsMouseOver()
end
local metas = {
getMeta("Frame"),
getMeta("Button"),
getMeta("CheckButton"),
getMeta("EditBox"),
getMeta("Slider"),
getMeta("StatusBar"),
getMeta("ScrollFrame"),
getMeta("MessageFrame"),
getMeta("ScrollingMessageFrame"),
}
for _, meta in ipairs(metas) do
if type(meta) == "table" then
if not meta.RegisterCustomEvent then
meta.RegisterCustomEvent = RegisterCustomEventNoop
end
if not meta.UnregisterCustomEvent then
meta.UnregisterCustomEvent = UnregisterCustomEventNoop
end
if not meta.SetShown then
meta.SetShown = SetShown
end
if not meta.SetParentArray then
meta.SetParentArray = SetParentArray
end
if not meta.SetEnabled then
meta.SetEnabled = SetEnabled
end
if not meta.IsMouseOverEx then
meta.IsMouseOverEx = IsMouseOverEx
end
end
end
-- Sirus EJ calls FontString:IsTruncated() (Cataclysm+) to detect overflow for
-- header tooltips. Always return false on 3.3.5 — we just don't show the
-- "expand" tooltip.
do
local frame = CreateFrame("Frame")
local fs = frame:CreateFontString()
local meta = getmetatable(fs)
local methods = meta and meta.__index
if type(methods) == "table" and not methods.IsTruncated then
methods.IsTruncated = function() return false end
end
end
-- Sirus EJ description fields are SimpleHTML frames; the EJ logic does
-- `self.description:GetText()` (Cataclysm+ on SimpleHTML). 3.3.5 SimpleHTML
-- only has SetText, no GetText. Hook SetText to remember the last text and
-- expose GetText that returns it.
do
local ok, simple = pcall(CreateFrame, "SimpleHTML")
if ok and simple then
local meta = getmetatable(simple)
local methods = meta and meta.__index
if type(methods) == "table" then
local origSetText = methods.SetText
if origSetText and not methods.GetText then
methods.SetText = function(self, text, ...)
self.__moonwellText = text
return origSetText(self, text, ...)
end
methods.GetText = function(self)
return self.__moonwellText
end
end
end
end
end
-- Sirus EJ calls Texture:SetPortrait(displayID) for boss/creature portraits.
-- 3.3.5 has no SetPortraitTextureFromCreatureDisplayID equivalent, so leave
-- the texture blank — the static UI-EJ-BOSS-* icon set elsewhere is enough.
do
local frame = CreateFrame("Frame")
local texture = frame:CreateTexture()
local meta = getmetatable(texture)
local methods = meta and meta.__index
if type(methods) == "table" and not methods.SetPortrait then
methods.SetPortrait = function(self)
self:SetTexture(nil)
end
end
end
@@ -0,0 +1,41 @@
-- Force C_EncounterJournal to copy the freshly loaded JOURNAL* globals into its
-- internal locals. Without this the EJ data API returns nil and the instance
-- list comes up empty.
if C_EncounterJournal and C_EncounterJournal.ReloadData then
C_EncounterJournal.ReloadData()
end
-- EJ_GetLootFilter returns nil until a class filter is set; Sirus
-- EncounterJournal_UpdateFilterString does `if classID > 0 then`, which blows
-- up when classID is nil. Coerce to 0.
if EJ_GetLootFilter then
local _GetLootFilter = EJ_GetLootFilter
function EJ_GetLootFilter()
return _GetLootFilter() or 0
end
end
-- Sirus C_AdventureJournal sometimes fails to fully initialize on 3.3.5
-- because PRIVATE.Initialize() inside Utils/C_AdventureJournal.lua hits an
-- unsupported API mid-way and aborts before `C_AdventureJournal = {}` is
-- reached. Provide a no-op stub so suggestFrame OnShow doesn't blow up.
C_AdventureJournal = C_AdventureJournal or {}
local function noop() end
C_AdventureJournal.UpdateSuggestions = C_AdventureJournal.UpdateSuggestions or noop
C_AdventureJournal.GetPrimaryOffset = C_AdventureJournal.GetPrimaryOffset or function() return 0 end
C_AdventureJournal.SetPrimaryOffset = C_AdventureJournal.SetPrimaryOffset or noop
C_AdventureJournal.GetNumAvailableSuggestions = C_AdventureJournal.GetNumAvailableSuggestions or function() return 0 end
C_AdventureJournal.GetSuggestion = C_AdventureJournal.GetSuggestion or function() end
C_AdventureJournal.CanBeShown = C_AdventureJournal.CanBeShown or function() return true end
C_AdventureJournal.ReloadData = C_AdventureJournal.ReloadData or noop
C_AdventureJournal.ActivateEntry = C_AdventureJournal.ActivateEntry or noop
C_AdventureJournal.GetSuggestions = C_AdventureJournal.GetSuggestions or function(out)
if type(out) == "table" then
for k in pairs(out) do out[k] = nil end
end
return out or {}
end
C_AdventureJournal.GetReward = C_AdventureJournal.GetReward or function() end
C_AdventureJournal.GetPrimaryReward = C_AdventureJournal.GetPrimaryReward or function() end
C_AdventureJournal.GetSecondaryReward = C_AdventureJournal.GetSecondaryReward or function() end
@@ -0,0 +1,30 @@
-- Explicit entry point for 3.3.5 clients, which do not have the retail
-- EncounterJournal micro button.
local function MoonWell_ToggleEncounterJournal()
if not EncounterJournal then
return
end
if EncounterJournal:IsShown() then
HideUIPanel(EncounterJournal)
return
end
if MoonWell_EncounterJournalApplyDungeonMode then
MoonWell_EncounterJournalApplyDungeonMode()
end
if EncounterJournal_OpenJournal then
EncounterJournal_OpenJournal()
else
ShowUIPanel(EncounterJournal)
end
end
SLASH_MOONWELLENCOUNTERJOURNAL1 = "/ej"
SLASH_MOONWELLENCOUNTERJOURNAL2 = "/journal"
SLASH_MOONWELLENCOUNTERJOURNAL3 = "/encounterjournal"
SlashCmdList.MOONWELLENCOUNTERJOURNAL = MoonWell_ToggleEncounterJournal
MoonWell_ToggleEncounterJournal = MoonWell_ToggleEncounterJournal
@@ -0,0 +1,24 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
..\FrameXML\UI.xsd">
<!--
Sirus EncounterJournalScrollBarTemplate inherits MinimalScrollBarTemplate
and references self.trackBG inside its inline OnLoad. On 3.3.5 the
parentKey="trackBG" attribute on the inherited template does not
propagate, leaving self.trackBG nil and crashing OnLoad. Define the
template here ourselves with trackBG as a direct child texture, before
Sirus Custom_EncounterJournal.xml gets a chance to register its own.
-->
<Slider name="EncounterJournalScrollBarTemplate" inherits="MinimalScrollBarTemplate" parentKey="ScrollBar" virtual="true">
<Anchors>
<Anchor point="TOPRIGHT" x="0" y="-17"/>
<Anchor point="BOTTOMRIGHT" x="0" y="17"/>
</Anchors>
<Layers>
<Layer level="ARTWORK">
<Texture parentKey="trackBG" setAllPoints="true">
<Color r="0.2" g="0.13" b="0.08" a="0.25"/>
</Texture>
</Layer>
</Layers>
</Slider>
</Ui>
@@ -0,0 +1,40 @@
-- Sirus EJ XML for lootScroll/searchResults.scrollFrame omits the scrollUp /
-- scrollDown buttons that the stock 3.3.5 HybridScrollFrame implementation
-- requires (HybridScrollFrame_Update / HybridScrollFrame_UpdateButtonStates
-- index them directly). Wire up no-op buttons so the stock helpers don't
-- index nil and the rest of the EJ flow works.
local function AttachFakeScrollButtons(scrollFrame)
if not scrollFrame then
return
end
if not scrollFrame.scrollUp then
local btn = CreateFrame("Button", nil, scrollFrame)
btn:Hide()
btn:SetSize(1, 1)
btn:SetPoint("TOPLEFT")
scrollFrame.scrollUp = btn
end
if not scrollFrame.scrollDown then
local btn = CreateFrame("Button", nil, scrollFrame)
btn:Hide()
btn:SetSize(1, 1)
btn:SetPoint("BOTTOMLEFT")
scrollFrame.scrollDown = btn
end
if scrollFrame.scrollBar and not scrollFrame.scrollBar.thumbTexture then
scrollFrame.scrollBar.thumbTexture = scrollFrame.scrollBar:GetThumbTexture()
or scrollFrame.scrollBar:CreateTexture(nil, "ARTWORK")
end
if scrollFrame.scrollBar and not scrollFrame.scrollBar.trackBG then
scrollFrame.scrollBar.trackBG = scrollFrame.scrollBar:CreateTexture(nil, "BACKGROUND")
end
end
if EncounterJournal then
AttachFakeScrollButtons(EncounterJournal.encounter
and EncounterJournal.encounter.info
and EncounterJournal.encounter.info.lootScroll)
AttachFakeScrollButtons(EncounterJournal.searchResults
and EncounterJournal.searchResults.scrollFrame)
end
@@ -0,0 +1,38 @@
-- Restrict Sirus EJ data tables to expansions that exist on 3.3.5a (Classic, TBC, WotLK).
-- Must run AFTER Generated_EncounterJournal.lua (where the globals are populated) and BEFORE
-- Utils/C_EncounterJournal.lua reads them into locals on first ReloadData.
local ALLOWED_TIER_IDS = {
[68] = true, -- Classic
[70] = true, -- Burning Crusade
[72] = true, -- Wrath of the Lich King
}
local TIER_FIELD_ID = 1
if type(JOURNALTIER) == "table" then
local filtered = {}
for _, tierInfo in ipairs(JOURNALTIER) do
if ALLOWED_TIER_IDS[tierInfo[TIER_FIELD_ID]] then
filtered[#filtered + 1] = tierInfo
end
end
JOURNALTIER = filtered
end
if type(JOURNALTIERXINSTANCE) == "table" then
for instanceID, tierList in pairs(JOURNALTIERXINSTANCE) do
local kept
for _, tierID in ipairs(tierList) do
if ALLOWED_TIER_IDS[tierID] then
kept = kept or {}
kept[#kept + 1] = tierID
end
end
if kept then
JOURNALTIERXINSTANCE[instanceID] = kept
else
JOURNALTIERXINSTANCE[instanceID] = nil
end
end
end
@@ -0,0 +1,6 @@
-- Keep tier tables available for the 3.3.5a dungeon-list shim.
-- C_EncounterJournal imports Sirus globals into locals and clears the globals.
MoonWell_EncounterJournalTiers = CopyTable(JOURNALTIER or {})
MoonWell_EncounterJournalTierInstances = CopyTable(JOURNALTIERXINSTANCE or {})
@@ -0,0 +1,38 @@
ADVENTURE_JOURNAL = "Путеводитель по приключениям"
AJ_ACTION_TEXT_JOIN_BATTLE = "Вступить в бой"
AJ_ACTION_TEXT_JOIN_GROUP = "Вступить в группу"
AJ_ACTION_TEXT_OPEN_EJ = "Открыть журнал"
AJ_ACTION_TEXT_SHOW_QUEST = "Открыть задания"
AJ_ACTION_TEXT_START_HUNT = "Открыть охоту"
AJ_ACTION_TEXT_START_QUEST = "Начать задание"
AJ_LFG_REWARD_DEFAULT_IRANGE_TEXT = "%s: здесь можно получить предметы экипировки %i - %i уровней."
AJ_LFG_REWARD_DEFAULT_TEXT = "%s: здесь можно получить предметы экипировки %i-го уровня."
AJ_LFG_REWARD_DIFFICULTY_IRANGE_TEXT = "%s (%s): здесь можно получить предметы экипировки %i - %i уровней."
AJ_LFG_REWARD_DIFFICULTY_TEXT = "%s (%s): здесь можно получить предметы экипировки %i-го уровня."
AJ_PRIMARY_REWARD_TEXT = "Награда:"
AJ_REWARD_CLICK_TEXT = "Щелкните для просмотра всех наград."
AJ_SAMPLE_REWARD_TEXT = "\n\nПример награды:"
AJ_SUGGESTED_CONTENT_TAB = "Рекомендуемый контент"
EJ_CLASS_FILTER = "Фильтр по классу: %s"
EJ_FILTER_ALL_CLASS = "Все классы"
EJ_INSTANCE_REQUIREMENT_ACHIEVEMENTS = "Достижения:"
EJ_INSTANCE_REQUIREMENT_DIFFICULTY = "Сложность: %s"
EJ_INSTANCE_REQUIREMENT_ITEM_LEVEL = "Средний уровень предметов: %s"
EJ_INSTANCE_REQUIREMENT_LABLE = "Требования:"
EJ_INSTANCE_REQUIREMENT_LEVEL = "Уровень: %s"
EJ_INSTANCE_REQUIREMENT_LEVEL_RANGE = "Уровень: %s-%s"
EJ_INSTANCE_REQUIREMENT_NONE = "Вход свободный"
EJ_INSTANCE_REQUIREMENT_QUESTS = "Задания:"
EJ_INSTANCE_REQUIREMENT_RAID_GROUP = "Для входа требуется быть участником рейдовой группы"
EJ_SET_ITEM_LEVEL = "|cffcc4040[%s]|r Уровень предмета: %d"
ENCOUNTER_JOURNAL_ABILITY = "Способность"
ENCOUNTER_JOURNAL_ENCOUNTER = "Босс"
ENCOUNTER_JOURNAL_ENCOUNTER_ADD = "Помощник"
ENCOUNTER_JOURNAL_FIND_GROUP = "Найти\nгруппу"
ENCOUNTER_JOURNAL_FIND_RAID = "Найти\nрейд"
ENCOUNTER_JOURNAL_INSTANCE = "Подземелье"
ENCOUNTER_JOURNAL_ITEM = "Предмет"
ENCOUNTER_JOURNAL_SEARCH_RESULTS = "Результаты поиска для \"%s\" (%d)"
ENCOUNTER_JOURNAL_SHOW_MAP = "Показать\nкарту"
ENCOUNTER_JOURNAL_SHOW_SEARCH_RESULTS = "Показать все результаты: %d"
LOOT_JOURNAL_ITEM_SETS = "Комплекты"
@@ -0,0 +1,128 @@
local securecall = securecall
local ipairs = ipairs
local next = next
local type = type
local strsplit = string.split
local ExecuteFrameScript = ExecuteFrameScript
local GetFramesRegisteredForEvent = GetFramesRegisteredForEvent
local UnitName = UnitName
local UnitTokenFromGUID = UnitTokenFromGUID
local REGISTERED_CUSTOM_EVENTS = {}
local REGISTERED_CUSTOM_EVENTS_ALL
local function SecureNext(elements, key)
return securecall(next, elements, key)
end
function FireClientEvent(event, ...)
for _, frame in SecureNext, {GetFramesRegisteredForEvent(event)} do
securecall(ExecuteFrameScript, frame, "OnEvent", event, ...)
end
end
function FireCustomClientEvent(event, ...)
if REGISTERED_CUSTOM_EVENTS[event] then
for frame in SecureNext, REGISTERED_CUSTOM_EVENTS[event] do
securecall(ExecuteFrameScript, frame, "OnEvent", event, ...)
end
end
if REGISTERED_CUSTOM_EVENTS_ALL then
for frame in SecureNext, REGISTERED_CUSTOM_EVENTS_ALL do
securecall(ExecuteFrameScript, frame, "OnEvent", event, ...)
end
end
end
local eventRegistrar = CreateFrame("Frame")
eventRegistrar:SetScript("OnAttributeChanged", function(this, name, value)
if name == "1" then
if not REGISTERED_CUSTOM_EVENTS[value] then
REGISTERED_CUSTOM_EVENTS[value] = {}
end
REGISTERED_CUSTOM_EVENTS[value][this:GetAttribute("f")] = true
elseif name == "0" then
if REGISTERED_CUSTOM_EVENTS[value] then
REGISTERED_CUSTOM_EVENTS[value][this:GetAttribute("f")] = nil
end
elseif name == "2" then
REGISTERED_CUSTOM_EVENTS_ALL[value] = true
elseif name == "3" then
REGISTERED_CUSTOM_EVENTS_ALL[value] = nil
end
end)
function RegisterCustomEvent(self, event)
eventRegistrar:SetAttribute("f", self)
eventRegistrar:SetAttribute("1", event)
end
function UnregisterCustomEvent(self, event)
eventRegistrar:SetAttribute("f", self)
eventRegistrar:SetAttribute("0", event)
end
function RegisterAllCustomEvents(self)
if not REGISTERED_CUSTOM_EVENTS_ALL then
REGISTERED_CUSTOM_EVENTS_ALL = {}
end
eventRegistrar:SetAttribute("2", self)
end
function UnregisterAllCustomEvents(self)
if not REGISTERED_CUSTOM_EVENTS_ALL then
return
end
eventRegistrar:SetAttribute("3", self)
end
function FireCustomClientUnitGroupEvent(event, unitGUID, ...)
if event and REGISTERED_CUSTOM_EVENTS[event] and unitGUID then
local units = {UnitTokenFromGUID(unitGUID)}
if #units > 0 then
for frame in SecureNext, REGISTERED_CUSTOM_EVENTS[event] do
for _, unit in ipairs(units) do
securecall(ExecuteFrameScript, frame, "OnEvent", event, unit, ...)
end
end
end
end
end
EventHandler = setmetatable(
{
events = {}, -- Original events
listeners = {}, -- New tables for handling events outside og EventHandler
RegisterListener = function(self, listener)
self.listeners[listener] = true
end,
Handle = function(self, opcode, message, unk, sender)
if sender == UnitName("player") then
for listener in SecureNext, self.listeners do
if listener[opcode] then
securecall(listener[opcode], listener, message)
end
end
if self.events[opcode] then
securecall(self.events[opcode], self, message)
end
end
end
},
{
__newindex = function(self, key, value)
if type(value) == "function" then
self.events[key] = value
end
rawset(self, key, value)
end
}
)
local EventHandlerFrame = CreateFrame("Frame")
EventHandlerFrame:RegisterEvent("CHAT_MSG_ADDON")
EventHandlerFrame:SetScript("OnEvent", function(self, event, opcode, message, unk, sender)
EventHandler:Handle(opcode, message, unk, sender)
end)
@@ -0,0 +1,427 @@
--[[-----------------------------------------------------------------------------------------------
For a hybrid scroll frame with buttons of varying size, set .dynamic on the scroll frame
to be a function which will take the offset and return:
1. how many buttons the offset is completely past
2. how many pixels the offset is into the topmost button
So with buttons of size 20, .dynamic(0) should return 0,0 and .dynamic(34) should return 1,14
-----------------------------------------------------------------------------------------------]]--
local round = function (num) return math.floor(num + .5); end
local function HybridScrollFrame_SetVerticalScrollOffset(self, offset)
if self.SetVerticalScroll then
self:SetVerticalScroll(offset);
end
end
local function HybridScrollFrame_UpdateScrollChildRectSafe(self)
if self.UpdateScrollChildRect then
self:UpdateScrollChildRect();
end
end
local function HybridScrollFrame_GetScrollFrame(self)
if not self then
return self;
end
if self.SetVerticalScroll then
return self;
end
local name = self.GetName and self:GetName();
local scrollFrame = self.Container or (name and _G[name.."Container"]);
return scrollFrame or self;
end
local function HybridScrollFrame_GetScrollBar(self)
if self.scrollBar then
return self.scrollBar;
end
local name = self.GetName and self:GetName();
local scrollBar = self.ScrollBar or (name and (_G[name.."ScrollBar"] or _G[name.."ContainerScrollBar"]));
if scrollBar then
self.scrollBar = scrollBar;
end
return scrollBar;
end
function HybridScrollFrame_OnLoad (self)
self:EnableMouse(true);
end
function HybridScrollFrameScrollUp_OnLoad (self)
self:GetParent():GetParent().scrollUp = self;
self:Disable();
self:RegisterForClicks("LeftButtonUp", "LeftButtonDown");
self.direction = 1;
end
function HybridScrollFrameScrollDown_OnLoad (self)
self:GetParent():GetParent().scrollDown = self;
self:Disable();
self:RegisterForClicks("LeftButtonUp", "LeftButtonDown");
self.direction = -1;
end
function HybridScrollFrame_OnValueChanged (self, value)
local scrollFrame = self;
if self.SetMinMaxValues and self.GetParent then
scrollFrame = self:GetParent();
end
scrollFrame = HybridScrollFrame_GetScrollFrame(scrollFrame);
HybridScrollFrame_SetOffset(scrollFrame, value);
HybridScrollFrame_UpdateButtonStates(scrollFrame, value);
end
function HybridScrollFrame_UpdateButtonStates (self, currValue)
local scrollBar = HybridScrollFrame_GetScrollBar(self);
if ( not scrollBar ) then
return;
end
local scrollBarName = scrollBar.GetName and scrollBar:GetName();
local scrollUp = self.scrollUp or scrollBar.ScrollUpButton or (scrollBarName and _G[scrollBarName.."ScrollUpButton"]);
local scrollDown = self.scrollDown or scrollBar.ScrollDownButton or (scrollBarName and _G[scrollBarName.."ScrollDownButton"]);
if ( not currValue ) then
currValue = scrollBar:GetValue();
end
if ( scrollUp ) then
scrollUp:Enable();
end
if ( scrollDown ) then
scrollDown:Enable();
end
local minVal, maxVal = scrollBar:GetMinMaxValues();
if ( currValue >= maxVal ) then
if ( scrollBar.thumbTexture ) then
scrollBar.thumbTexture:Show();
end
if ( scrollDown ) then
scrollDown:Disable()
end
end
if ( currValue <= minVal ) then
if ( scrollBar.thumbTexture ) then
scrollBar.thumbTexture:Show();
end
if ( scrollUp ) then
scrollUp:Disable();
end
end
end
function HybridScrollFrame_OnMouseWheel (self, delta, stepSize)
self = HybridScrollFrame_GetScrollFrame(self);
local scrollBar = HybridScrollFrame_GetScrollBar(self);
if ( not scrollBar or not scrollBar:IsVisible() ) then
return;
end
local isEnabled = not scrollBar.IsEnabled or scrollBar:IsEnabled();
if ( not isEnabled or isEnabled == 0 ) then
return;
end
local minVal, maxVal = scrollBar:GetMinMaxValues();
minVal = minVal or 0;
maxVal = maxVal or self.range or 0;
stepSize = stepSize or self.stepSize or self.buttonHeight or 1;
if ( delta == 1 ) then
scrollBar:SetValue(max(minVal, scrollBar:GetValue() - stepSize));
else
scrollBar:SetValue(min(maxVal, scrollBar:GetValue() + stepSize));
end
end
function HybridScrollFrameScrollButton_OnUpdate (self, elapsed)
self.timeSinceLast = self.timeSinceLast + elapsed;
if ( self.timeSinceLast >= ( self.updateInterval or 0.08 ) ) then
if ( not IsMouseButtonDown("LeftButton") ) then
self:SetScript("OnUpdate", nil);
elseif ( self:IsMouseOver() ) then
local parent = self.parent or self:GetParent():GetParent();
HybridScrollFrame_OnMouseWheel (parent, self.direction, (self.stepSize or parent.buttonHeight/3));
self.timeSinceLast = 0;
end
end
end
function HybridScrollFrameScrollButton_OnClick (self, button, down)
local parent = self.parent or self:GetParent():GetParent();
if ( down ) then
if IsMouseButtonDown then
self.timeSinceLast = (self.timeToStart or -0.2);
self:SetScript("OnUpdate", HybridScrollFrameScrollButton_OnUpdate);
end
HybridScrollFrame_OnMouseWheel (parent, self.direction);
PlaySound("UChatScrollButton");
else
self:SetScript("OnUpdate", nil);
end
end
function HybridScrollFrame_SetPercentageHeight(self, percentageHeight)
local offset = percentageHeight * (self.totalHeight or 0);
HybridScrollFrame_SetOffset(self, offset);
end
function HybridScrollFrame_GetVisiblePercentage(self)
local totalHeight = (self.totalHeight or 0);
if totalHeight == 0 then
return 0;
end
return self.scrollChild:GetHeight() / totalHeight;
end
function HybridScrollFrame_GetScrollPercentage(self)
local scrollableHeight = (self.totalHeight or 0) - self.scrollChild:GetHeight();
if scrollableHeight == 0 then
return 0;
end
return (self.offset or 0) / scrollableHeight;
end
function HybridScrollFrame_Update (self, totalHeight, displayedHeight)
local range = floor(totalHeight - self:GetHeight() + 0.5);
local scrollBar = HybridScrollFrame_GetScrollBar(self);
if ( range > 0 and scrollBar ) then
local minVal, maxVal = scrollBar:GetMinMaxValues();
if ( math.floor(scrollBar:GetValue()) >= math.floor(maxVal) ) then
scrollBar:SetMinMaxValues(0, range);
if ( math.floor(scrollBar:GetValue()) ~= math.floor(range) ) then
scrollBar:SetValue(range);
else
HybridScrollFrame_SetOffset(self, range); -- If we've scrolled to the bottom, we need to recalculate the offset.
end
else
scrollBar:SetMinMaxValues(0, range)
end
scrollBar:Enable();
HybridScrollFrame_UpdateButtonStates(self);
scrollBar:Show();
elseif ( scrollBar ) then
scrollBar:SetValue(0);
if ( scrollBar.doNotHide ) then
scrollBar:Disable();
if ( self.scrollUp ) then
self.scrollUp:Disable();
end
if ( self.scrollDown ) then
self.scrollDown:Disable();
end
if ( scrollBar.thumbTexture ) then
scrollBar.thumbTexture:Hide();
end
else
scrollBar:Hide();
end
end
self.range = range;
self.totalHeight = totalHeight;
self.scrollChild:SetHeight(displayedHeight);
HybridScrollFrame_UpdateScrollChildRectSafe(self);
end
function HybridScrollFrame_GetOffset (self)
return math.floor(self.offset or 0), (self.offset or 0);
end
function HybridScrollFrameScrollChild_OnLoad (self)
self:GetParent().scrollChild = self;
end
function HybridScrollFrame_ExpandButton (self, offset, height)
self.largeButtonTop = round(offset);
self.largeButtonHeight = round(height)
local scrollBar = HybridScrollFrame_GetScrollBar(self);
HybridScrollFrame_SetOffset(self, scrollBar and scrollBar:GetValue() or 0);
end
function HybridScrollFrame_CollapseButton (self)
self.largeButtonTop = nil;
self.largeButtonHeight = nil;
end
function HybridScrollFrame_SetOffset (self, offset)
local buttons = self.buttons
local buttonHeight = self.buttonHeight;
local element, overflow;
if ( not buttonHeight and buttons and buttons[1] ) then
buttonHeight = round(buttons[1]:GetHeight());
self.buttonHeight = buttonHeight;
end
if ( not buttonHeight or buttonHeight == 0 ) then
self.offset = 0;
HybridScrollFrame_SetVerticalScrollOffset(self, 0);
return;
end
local scrollHeight = 0;
local largeButtonTop = self.largeButtonTop
if ( self.dynamic ) then --This is for frames where buttons will have different heights
if ( offset < buttonHeight ) then
-- a little optimization
element = 0;
scrollHeight = offset;
else
element, scrollHeight = self.dynamic(offset);
end
elseif ( largeButtonTop and offset >= largeButtonTop ) then
local largeButtonHeight = self.largeButtonHeight;
-- Initial offset...
element = largeButtonTop / buttonHeight;
if ( offset >= (largeButtonTop + largeButtonHeight) ) then
element = element + 1;
local leftovers = (offset - (largeButtonTop + largeButtonHeight) );
element = element + ( leftovers / buttonHeight );
overflow = element - math.floor(element);
scrollHeight = overflow * buttonHeight;
else
scrollHeight = math.abs(offset - largeButtonTop);
end
else
element = offset / buttonHeight;
overflow = element - math.floor(element);
scrollHeight = overflow * buttonHeight;
end
if ( math.floor(self.offset or 0) ~= math.floor(element) and self.update ) then
self.offset = element;
self:update();
else
self.offset = element;
end
HybridScrollFrame_SetVerticalScrollOffset(self, scrollHeight);
end
function HybridScrollFrame_CreateButtons (self, buttonTemplate, initialOffsetX, initialOffsetY, initialPoint, initialRelative, offsetX, offsetY, point, relativePoint)
local scrollChild = self.scrollChild;
local button, buttonHeight, buttons, numButtons;
local parentName = self:GetName();
local buttonName = parentName and (parentName .. "Button") or nil;
initialPoint = initialPoint or "TOPLEFT";
initialRelative = initialRelative or "TOPLEFT";
point = point or "TOPLEFT";
relativePoint = relativePoint or "BOTTOMLEFT";
offsetX = offsetX or 0;
offsetY = offsetY or 0;
if ( self.buttons ) then
buttons = self.buttons;
buttonHeight = buttons[1]:GetHeight();
else
button = CreateFrame("BUTTON", buttonName and (buttonName .. 1) or nil, scrollChild, buttonTemplate);
buttonHeight = button:GetHeight();
button:SetPoint(initialPoint, scrollChild, initialRelative, initialOffsetX, initialOffsetY);
buttons = {}
tinsert(buttons, button);
end
self.buttonHeight = round(buttonHeight) - offsetY;
numButtons = math.ceil(self:GetHeight() / buttonHeight) + 1;
for i = #buttons + 1, numButtons do
button = CreateFrame("BUTTON", buttonName and (buttonName .. i) or nil, scrollChild, buttonTemplate);
button:SetPoint(point, buttons[i-1], relativePoint, offsetX, offsetY);
tinsert(buttons, button);
end
scrollChild:SetWidth(self:GetWidth())
scrollChild:SetHeight(numButtons * buttonHeight);
HybridScrollFrame_SetVerticalScrollOffset(self, 0);
HybridScrollFrame_UpdateScrollChildRectSafe(self);
self.buttons = buttons;
local scrollBar = HybridScrollFrame_GetScrollBar(self);
if scrollBar then
scrollBar:SetMinMaxValues(0, numButtons * buttonHeight)
scrollBar.buttonHeight = buttonHeight;
scrollBar:SetValueStep(.005);
scrollBar:SetValue(0);
end
end
function HybridScrollFrame_GetButtonIndex(self, button)
return tIndexOf(self.buttons, button);
end
function HybridScrollFrame_GetButtons (self)
return self.buttons;
end
function HybridScrollFrame_SetDoNotHideScrollBar (self, doNotHide)
local scrollBar = HybridScrollFrame_GetScrollBar(self);
if not scrollBar or scrollBar.doNotHide == doNotHide then
return;
end
scrollBar.doNotHide = doNotHide;
HybridScrollFrame_Update(self, self.totalHeight or 0, self.scrollChild:GetHeight());
end
function HybridScrollFrame_ScrollToIndex(self, index, getHeightFunc)
local scrollBar = HybridScrollFrame_GetScrollBar(self);
if not scrollBar then
return;
end
local totalHeight = 0;
local scrollFrameHeight = self:GetHeight();
for i = 1, index do
local entryHeight = getHeightFunc(i);
if i == index then
local offset = 0;
-- we don't need to do anything if the entry is fully displayed with the scroll all the way up
if ( totalHeight + entryHeight > scrollFrameHeight ) then
if ( entryHeight > scrollFrameHeight ) then
-- this entry is larger than the entire scrollframe, put it at the top
offset = totalHeight;
else
-- otherwise place it in the center
local diff = scrollFrameHeight - entryHeight;
offset = totalHeight - diff / 2;
end
-- because of valuestep our positioning might change
-- we'll do the adjustment ourselves to make sure the entry ends up above the center rather than below
local valueStep = scrollBar:GetValueStep();
offset = offset + valueStep - mod(offset, valueStep);
-- but if we ended up moving the entry so high up that its top is not visible, move it back down
if ( offset > totalHeight ) then
offset = offset - valueStep;
end
end
scrollBar:SetValue(offset);
break;
end
totalHeight = totalHeight + entryHeight;
end
end
function HybridScrollBar_Disable(scrollBar)
scrollBar:Disable();
local scrollDownButton = scrollBar.ScrollDownButton or _G[scrollBar:GetName().."ScrollDownButton"];
if scrollDownButton then
scrollDownButton:Disable();
end
local scrollUpButton = scrollBar.ScrollUpButton or _G[scrollBar:GetName().."ScrollUpButton"];
if scrollUpButton then
scrollUpButton:Disable();
end
end
@@ -0,0 +1,220 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
..\FrameXML\UI.xsd">
<Script file="HybridScrollFrame.lua"/>
<Texture name="HybridScrollBarButton" virtual="true">
<TexCoords left="0.25" right="0.75" top="0.25" bottom="0.75"/>
</Texture>
<Slider name="HybridScrollBarBackgroundTemplate" parentKey="scrollBar" virtual="true">
<Size x="20" y="0"/>
<Anchors>
<Anchor point="TOPLEFT" relativePoint="TOPRIGHT" x="0" y="-18"/>
<Anchor point="BOTTOMLEFT" relativePoint="BOTTOMRIGHT" x="0" y="16"/>
</Anchors>
<Layers>
<Layer level="BACKGROUND">
<Texture name="$parentBG" setAllPoints="true" hidden="true" parentKey="trackBG">
<Color r="0" g="0" b="0" a=".85"/>
</Texture>
</Layer>
<Layer level="ARTWORK">
<Texture name="$parentTop" parentKey="ScrollBarTop" file="Interface\PaperDollInfoFrame\UI-Character-ScrollBar">
<Size x="27" y="48"/>
<Anchors>
<Anchor point="TOPLEFT" x="-4" y="17"/>
</Anchors>
<TexCoords left="0" right="0.484375" top="0" bottom=".20"/>
</Texture>
<Texture name="$parentBottom" parentKey="ScrollBarBottom" file="Interface\PaperDollInfoFrame\UI-Character-ScrollBar">
<Size x="27" y="64"/>
<Anchors>
<Anchor point="BOTTOMLEFT" x="-4" y="-15"/>
</Anchors>
<TexCoords left="0.515625" right="1.0" top="0.1440625" bottom="0.4140625"/>
</Texture>
<Texture name="$parentMiddle" parentKey="ScrollBarMiddle" file="Interface\PaperDollInfoFrame\UI-Character-ScrollBar">
<Anchors>
<Anchor point="TOPLEFT" relativeTo="$parentTop" relativePoint="BOTTOMLEFT"/>
<Anchor point="BOTTOMRIGHT" relativeTo="$parentBottom" relativePoint="TOPRIGHT"/>
</Anchors>
<TexCoords left="0" right="0.484375" top="0.1640625" bottom="1"/>
</Texture>
</Layer>
</Layers>
<ThumbTexture name="$parentThumbTexture" file="Interface\Buttons\UI-ScrollBar-Knob" parentKey="thumbTexture">
<Size x="18" y="24"/>
<TexCoords left="0.20" right="0.80" top="0.125" bottom="0.875"/>
</ThumbTexture>
</Slider>
<Slider name="HybridScrollBarTemplate" inherits="HybridScrollBarBackgroundTemplate" virtual="true">
<Frames>
<Button name="$parentScrollUpButton" parentKey="ScrollUpButton" inherits="UIPanelScrollUpButtonTemplate">
<Anchors>
<Anchor point="BOTTOM" relativePoint="TOP" x="0" y="-2"/>
</Anchors>
<Scripts>
<OnLoad function="HybridScrollFrameScrollUp_OnLoad"/>
<OnClick function ="HybridScrollFrameScrollButton_OnClick"/>
</Scripts>
</Button>
<Button name="$parentScrollDownButton" parentKey="ScrollDownButton" inherits="UIPanelScrollDownButtonTemplate">
<Anchors>
<Anchor point="TOP" relativePoint="BOTTOM" x="0" y="2"/>
</Anchors>
<Scripts>
<OnLoad function="HybridScrollFrameScrollDown_OnLoad"/>
<OnClick function="HybridScrollFrameScrollButton_OnClick"/>
</Scripts>
</Button>
</Frames>
<Scripts>
<OnValueChanged function="HybridScrollFrame_OnValueChanged"/>
</Scripts>
</Slider>
<Slider name="HybridScrollBarTrimTemplate" parentKey="scrollBar" virtual="true">
<Size x="20" y="0"/>
<Layers>
<Layer level="BACKGROUND">
<Texture name="$parentBG" setAllPoints="true" hidden="true" parentKey="trackBG">
<Color r="0" g="0" b="0" a=".85"/>
</Texture>
</Layer>
<Layer level="ARTWORK">
<Texture name="$parentTop" parentKey="Top" file="Interface\PaperDollInfoFrame\UI-Character-ScrollBar">
<Size x="24" y="48"/>
<Anchors>
<Anchor point="TOPLEFT" x="-4" y="17"/>
</Anchors>
<TexCoords left="0" right="0.45" top="0" bottom=".20"/>
</Texture>
<Texture name="$parentBottom" parentKey="Bottom" file="Interface\PaperDollInfoFrame\UI-Character-ScrollBar">
<Size x="24" y="64"/>
<Anchors>
<Anchor point="BOTTOMLEFT" x="-4" y="-15"/>
</Anchors>
<TexCoords left="0.515625" right="0.97" top="0.1440625" bottom="0.4140625"/>
</Texture>
<Texture name="$parentMiddle" parentKey="Middle" file="Interface\PaperDollInfoFrame\UI-Character-ScrollBar">
<Anchors>
<Anchor point="TOPLEFT" relativeTo="$parentTop" relativePoint="BOTTOMLEFT"/>
<Anchor point="BOTTOMRIGHT" relativeTo="$parentBottom" relativePoint="TOPRIGHT"/>
</Anchors>
<TexCoords left="0" right="0.45" top="0.1640625" bottom="1"/>
</Texture>
</Layer>
</Layers>
<Frames>
<Button name="$parentScrollUpButton" parentKey="UpButton" inherits="UIPanelScrollUpButtonTemplate">
<Anchors>
<Anchor point="BOTTOM" relativePoint="TOP" x="0" y="-2"/>
</Anchors>
<Scripts>
<OnLoad function="HybridScrollFrameScrollUp_OnLoad"/>
<OnClick function="HybridScrollFrameScrollButton_OnClick"/>
</Scripts>
</Button>
<Button name="$parentScrollDownButton" parentKey="DownButton" inherits="UIPanelScrollDownButtonTemplate">
<Anchors>
<Anchor point="TOP" relativePoint="BOTTOM" x="0" y="2"/>
</Anchors>
<Scripts>
<OnLoad function="HybridScrollFrameScrollDown_OnLoad"/>
<OnClick function="HybridScrollFrameScrollButton_OnClick"/>
</Scripts>
</Button>
</Frames>
<Scripts>
<OnValueChanged function="HybridScrollFrame_OnValueChanged"/>
</Scripts>
<ThumbTexture name="$parentThumbTexture" inherits="HybridScrollBarButton" file="Interface\Buttons\UI-ScrollBar-Knob" parentKey="thumbTexture">
<Size x="18" y="24"/>
<TexCoords left="0.20" right="0.80" top="0.125" bottom="0.875"/>
</ThumbTexture>
</Slider>
<Slider name="MinimalHybridScrollBarTemplate" parentKey="scrollBar" virtual="true">
<Size x="22" y="0"/>
<Layers>
<Layer level="BACKGROUND">
<Texture name="$parentTrack" parentKey="trackBG">
<Anchors>
<Anchor point="TOPLEFT" x="0" y="17"/>
<Anchor point="BOTTOMRIGHT" x="0" y="-17"/>
</Anchors>
<Color r="0" g="0" b="0" a="1"/>
</Texture>
</Layer>
</Layers>
<Frames>
<Button name="$parentScrollUpButton" inherits="UIPanelScrollUpButtonTemplate">
<Anchors>
<Anchor point="TOP" x="0" y="15"/>
</Anchors>
<Scripts>
<OnLoad function="HybridScrollFrameScrollUp_OnLoad"/>
<OnClick function="HybridScrollFrameScrollButton_OnClick"/>
</Scripts>
</Button>
<Button name="$parentScrollDownButton" inherits="UIPanelScrollDownButtonTemplate">
<Anchors>
<Anchor point="BOTTOM" x="0" y="-15"/>
</Anchors>
<Scripts>
<OnLoad function="HybridScrollFrameScrollDown_OnLoad"/>
<OnClick function="HybridScrollFrameScrollButton_OnClick"/>
</Scripts>
</Button>
</Frames>
<Scripts>
<OnValueChanged function="HybridScrollFrame_OnValueChanged"/>
</Scripts>
<ThumbTexture name="$parentThumbTexture" inherits="HybridScrollBarButton" file="Interface\Buttons\UI-ScrollBar-Knob" parentKey="thumbTexture">
<Size x="18" y="24"/>
<TexCoords left="0.20" right="0.80" top="0.125" bottom="0.875"/>
</ThumbTexture>
</Slider>
<ScrollFrame name="HybridScrollFrameTemplate" virtual="true">
<Scripts>
<OnLoad function="HybridScrollFrame_OnLoad"/>
<OnMouseWheel function="HybridScrollFrame_OnMouseWheel"/>
</Scripts>
<ScrollChild>
<Frame name="$parentScrollChild" parentKey="ScrollChild">
<Scripts>
<OnLoad function="HybridScrollFrameScrollChild_OnLoad"/>
</Scripts>
</Frame>
</ScrollChild>
</ScrollFrame>
<ScrollFrame name="BasicHybridScrollFrameTemplate" inherits="HybridScrollFrameTemplate" virtual="true">
<Anchors>
<Anchor point="TOPLEFT"/>
<Anchor point="BOTTOMRIGHT"/>
</Anchors>
<Frames>
<Slider name="$parentScrollBar" parentKey="ScrollBar" inherits="HybridScrollBarTemplate">
<Anchors>
<Anchor point="TOPLEFT" relativePoint="TOPRIGHT" x="0" y="-17"/>
<Anchor point="BOTTOMLEFT" relativePoint="BOTTOMRIGHT" x="0" y="12"/>
</Anchors>
</Slider>
</Frames>
</ScrollFrame>
<!-- This is a scrollframe with no border and a black texture for a track -->
<ScrollFrame name="MinimalHybridScrollFrameTemplate" inherits="HybridScrollFrameTemplate" virtual="true">
<Frames>
<Slider name="$parentScrollBar" inherits="MinimalHybridScrollBarTemplate">
<Anchors>
<Anchor point="TOPLEFT" relativePoint="TOPRIGHT" x="0" y="-17"/>
<Anchor point="BOTTOMLEFT" relativePoint="BOTTOMRIGHT" x="0" y="17"/>
</Anchors>
</Slider>
</Frames>
</ScrollFrame>
</Ui>
@@ -0,0 +1,355 @@
NAVBAR_WIDTHBUFFER = 20;
function NavBar_Initialize(self, template, homeData, homeButton, overflowButton)
self.template = template;
self.freeButtons = {};
self.navList = {};
self.widthBuffer = NAVBAR_WIDTHBUFFER;
local name = self:GetName();
if not self.dropDown then
local dropDownName = name and name.."DropDown" or nil;
self.dropDown = CreateFrame("Frame", dropDownName, self, "UIDropDownMenuTemplate");
UIDropDownMenu_Initialize(self.dropDown, NavBar_DropDown_Initialize, "MENU");
end
if not homeButton then
local homeButtonName = name and name.."HomeButton" or nil;
homeButton = CreateFrame("BUTTON", homeButtonName, self, self.template);
homeButton:SetWidth(homeButton.text:GetStringWidth()+30);
end
homeButton:SetText(homeData.name or HOME);
if not overflowButton then
local overflowButtonName = name and name.."OverflowButton" or nil;
overflowButton = CreateFrame("BUTTON", overflowButtonName, self, self.template);
overflowButton:SetWidth(30);
-- LOOK AT CLICK
end
if not homeButton:GetScript("OnEnter") then
homeButton:SetScript("OnEnter", NavBar_ButtonOnEnter);
end
if not homeButton:GetScript("OnLeave") then
homeButton:SetScript("OnLeave", NavBar_ButtonOnLeave);
end
if ( self.oldStyle ) then
homeButton:RegisterForClicks("LeftButtonUp", "RightButtonUp");
overflowButton:RegisterForClicks("LeftButtonUp", "RightButtonUp");
else
homeButton:RegisterForClicks("LeftButtonUp");
end
overflowButton.listFunc = NavBar_ListOverFlowButtons;
homeButton:ClearAllPoints();
overflowButton:ClearAllPoints();
homeButton:SetPoint("LEFT", self, "LEFT", 0, 0);
overflowButton:SetPoint("LEFT", self, "LEFT", 0, 0);
overflowButton:Hide();
homeButton.oldClick = homeButton:GetScript("OnClick");
homeButton:SetScript("OnClick", NavBar_ButtonOnClick);
overflowButton:SetScript("OnMouseDown", NavBar_ToggleMenu);
self.homeButton = homeButton;
self.overflowButton = overflowButton;
self.navList[#self.navList+1] = homeButton;
homeButton.myclick = homeData.OnClick;
homeButton.listFunc = homeData.listFunc;
homeButton.data = homeData;
homeButton:Show();
end
function NavBar_Reset(self)
for index=2,#self.navList do
self.navList[index]:Hide();
tinsert(self.freeButtons, self.navList[index])
self.navList[index] = nil;
end
NavBar_CheckLength(self);
end
function NavBar_AddButton(self, buttonData)
local navButton = self.freeButtons[#self.freeButtons];
if navButton then
self.freeButtons[#self.freeButtons] = nil;
end
if not navButton then
local name = self:GetName();
local buttonName = name and name.."Button"..(#self.navList+1);
navButton = CreateFrame("BUTTON", buttonName, self, self.template);
navButton.oldClick = navButton:GetScript("OnClick");
navButton:SetScript("OnClick", NavBar_ButtonOnClick);
if ( self.oldStyle ) then
navButton:RegisterForClicks("LeftButtonUp", "RightButtonUp");
else
navButton:RegisterForClicks("LeftButtonUp");
end
if not navButton:GetScript("OnEnter") then
navButton:SetScript("OnEnter", NavBar_ButtonOnEnter);
end
if not navButton:GetScript("OnLeave") then
navButton:SetScript("OnLeave", NavBar_ButtonOnLeave);
end
end
--Set up the button
local navParent = self.navList[#self.navList];
self.navList[#self.navList+1] = navButton;
navButton.navParent = navParent;
navButton:SetText(buttonData.name);
local buttonExtraWidth;
navButton.MenuArrowButton:Hide();
buttonExtraWidth = 30;
navButton.text:SetWidth(self.textMaxWidth or 0);
navButton:SetWidth(navButton.text:GetStringWidth() + buttonExtraWidth);
navButton.myclick = buttonData.OnClick;
navButton.listFunc = buttonData.listFunc;
navButton.id = buttonData.id;
navButton.data = buttonData;
navButton:Show();
NavBar_CheckLength(self);
navButton.MenuArrowButton:SetEnabled(not buttonData.isDisabled)
end
function NavBar_ClearTrailingButtons(list, freeList, button)
for index=#list,1,-1 do
if not list[index] or button == list[index] then
break
end
list[index]:Hide();
tinsert(freeList, list[index])
list[index] = nil;
end
NavBar_CheckLength(button:GetParent());
end
function NavBar_OpenTo(self, id)
local button;
local found = false;
for i=1, #self.navList do
button = self.navList[i];
if (button.id and button.id == id) then
found = true;
break;
end
end
if (found) then
NavBar_ClearTrailingButtons(self.navList, self.freeButtons, button)
end
end
function NavBar_ButtonOnClick(self, button)
local parent = self:GetParent()
CloseDropDownMenus();
if button == "LeftButton" then
NavBar_ClearTrailingButtons(parent.navList, parent.freeButtons, self);
if self.oldClick then
self:oldClick(button);
end
if self.myclick then
self:myclick(button);
end
elseif button == "RightButton" then
NavBar_ToggleMenu(self);
end
end
function NavBar_ButtonOnEnter(self)
if self.text:IsTruncated() then
GameTooltip:SetOwner(self, "ANCHOR_BOTTOMRIGHT");
GameTooltip:AddLine(self.text:GetText(), NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, true);
GameTooltip:Show();
end
end
function NavBar_ButtonOnLeave(self)
if self.text:IsTruncated() then
GameTooltip:Hide();
end
end
function NavBar_CheckLength(self)
local width = 0;
local collapsedWidth;
local maxWidth = self:GetWidth() - self.widthBuffer;
local xoffset;
local lastShown;
local collapsed = false;
for i=#self.navList,1,-1 do
local currentWidth = width;
width = width + self.navList[i]:GetWidth();
if width > maxWidth then
self.navList[i]:Hide();
collapsed = true;
if not collapsedWidth then -- store the width for adding the offset button
collapsedWidth = currentWidth;
end
else
self.navList[i]:Show();
if lastShown then
local lastButton = self.navList[lastShown];
xoffset = self.navList[i].xoffset or 0
lastButton:SetPoint("LEFT", self.navList[i], "RIGHT", xoffset, 0);
self.navList[i]:SetFrameLevel(lastButton:GetFrameLevel()+1);
else
self.navList[i]:SetFrameLevel(self:GetFrameLevel()+1);
end
lastShown = i;
end
if i<#self.navList then
if self.navList[i].selected then
self.navList[i].selected:Hide();
end
self.navList[i]:Enable();
else
if self.navList[i].selected then
self.navList[i].selected:Show();
end
self.navList[i]:SetButtonState("NORMAL");
self.navList[i]:Disable();
end
end
if self.navList[1] then
local frameLevel = self.navList[1]:GetFrameLevel()
if frameLevel >= self.overlay:GetFrameLevel() then
self.overlay:SetFrameLevel(frameLevel + 1)
end
end
if collapsed then
if collapsedWidth + self.overflowButton:GetWidth() > maxWidth then
--No room for the overflow button
self.navList[lastShown]:Hide();
lastShown = lastShown + 1;
end
self.overflowButton:Show();
--There should only ever be no lastShown if a single button is longer than maxWidth by itself.
if ( lastShown ) then
local lastButton = self.navList[lastShown];
--There should only ever be no lastButton when there is lastShown if a single button is less than maxWidth
--but it's width plus the width of the overflow button is longer than maxWidth. In this case the single button
--is hidden to make room for the overflowButton.
if ( lastButton ) then
xoffset = self.overflowButton.xoffset or 0
lastButton:SetPoint("LEFT", self.overflowButton, "RIGHT", xoffset, 0);
self.overflowButton:SetFrameLevel(lastButton:GetFrameLevel()+1);
end
end
else
self.overflowButton:Hide();
end
end
function NavBar_ListOverFlowButtons(self, index)
local navBar = self:GetParent();
local button = navBar.navList[index];
if not button:IsShown() then
return button:GetText(), NavBar_OverflowItemOnClick;
end
end
function NavBar_ToggleMenu(self, button)
if ( self:GetParent().dropDown.buttonOwner ~= self ) then
CloseDropDownMenus();
end
self:GetParent().dropDown.buttonOwner = self;
ToggleDropDownMenu(nil, nil, self:GetParent().dropDown, self, 20, 3);
end
function NavBar_DropDown_Initialize(self, level)
local navButton = self.buttonOwner;
if not navButton or not navButton.listFunc then
return;
end
local info = UIDropDownMenu_CreateInfo();
info.func = NavBar_DropDown_Click;
info.owner = navButton;
info.notCheckable = true;
local index = 1;
local text, func = navButton:listFunc(index);
while text do
info.text = text;
info.arg1 = index;
info.arg2 = func;
UIDropDownMenu_AddButton(info, level);
index = index + 1;
text, func = navButton:listFunc(index);
end
end
function NavBar_DropDown_Click(self, index, func)
local navButton = self.owner;
local navBar = navButton:GetParent();
if func ~= NavBar_OverflowItemOnClick then
NavBar_ClearTrailingButtons(navBar.navList, navBar.freeButtons, navButton);
end
if type(func) == "function" then
func(self, index, navBar);
end
end
function NavBar_OverflowItemOnClick(junk, index, navBar)
local button = navBar.navList[index];
if button then
button:Click();
end
end
function NavBar_ReconsultationSize( self )
self.xoffset = -15
local newWidth = min(128, self.text:GetStringWidth()+50)
local texCoordoffsetX = (newWidth/128)*0.25
self:GetNormalTexture():SetTexCoord(0.70312500-texCoordoffsetX, 0.70312500, 0.00781250, 0.24218750)
self:GetPushedTexture():SetTexCoord(0.70312500-texCoordoffsetX, 0.70312500, 0.25781250, 0.49218750)
self:GetHighlightTexture():SetTexCoord(0.70312500-texCoordoffsetX, 0.71312500, 0.50781250, 0.74218750)
self:SetWidth(newWidth)
end
@@ -0,0 +1,241 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
..\FrameXML\UI.xsd">
<Script file="NavigationBar.lua"/>
<Button name="NavButtonTemplate" motionScriptsWhileDisabled="true" virtual="true">
<Size x="80" y="30"/>
<Layers>
<Layer level="OVERLAY">
<Texture file="Interface\HelpFrame\CS_HelpTextures" parentKey="arrowUp">
<Size x="21" y="30"/>
<Anchors>
<Anchor point="LEFT" relativePoint="RIGHT" x="0" y="0"/>
</Anchors>
<TexCoords left="0.88867188" right="0.92968750" top="0.29687500" bottom="0.53125000"/>
</Texture>
<Texture file="Interface\HelpFrame\CS_HelpTextures" parentKey="arrowDown">
<Size x="21" y="30"/>
<Anchors>
<Anchor point="LEFT" relativePoint="RIGHT" x="0" y="0"/>
</Anchors>
<TexCoords left="0.63281250" right="0.67382813" top="0.75781250" bottom="0.99218750"/>
</Texture>
<Texture file="Interface\HelpFrame\CS_HelpTextures" parentKey="selected" hidden="true">
<Anchors>
<Anchor point="TOPLEFT" x="0" y="0"/>
<Anchor point="BOTTOMRIGHT" x="0" y="0"/>
</Anchors>
<TexCoords left="0.00195313" right="0.25195313" top="0.37500000" bottom="0.64062500"/>
</Texture>
</Layer>
</Layers>
<Frames>
<Button parentKey="MenuArrowButton" hidden="true">
<Size x="27" y="31"/>
<Anchors>
<Anchor point="RIGHT" relativePoint="TOPRIGHT" x="-2" y="-15"/>
</Anchors>
<Layers>
<Layer level="OVERLAY">
<Texture parentKey="Art" file="Interface\Buttons\SquareButtonTextures">
<Size x="12" y="12"/>
<Anchors>
<Anchor point="CENTER" x="0" y="-1"/>
</Anchors>
<TexCoords left="0.45312500" right="0.64062500" bottom="0.01562500" top="0.20312500"/>
</Texture>
</Layer>
</Layers>
<NormalTexture file="Interface\Buttons\UI-SquareButton-Up" parentKey="NormalTexture" alpha="0">
<Size x="32" y="32"/>
<Anchors>
<Anchor point="CENTER"/>
</Anchors>
</NormalTexture>
<PushedTexture file="Interface\Buttons\UI-SquareButton-Down" parentKey="PushedTexture" alpha="0">
<Size x="32" y="32"/>
<Anchors>
<Anchor point="CENTER"/>
</Anchors>
</PushedTexture>
<HighlightTexture file="Interface\Buttons\UI-Common-MouseHilight" alphaMode="ADD">
<Size x="32" y="32"/>
<Anchors>
<Anchor point="CENTER"/>
</Anchors>
</HighlightTexture>
<Scripts>
<OnMouseDown>
if self:IsEnabled() == 1 then
self.Art:SetPoint("CENTER", -1, -2);
end
</OnMouseDown>
<OnMouseUp>
if self:IsEnabled() == 1 then
self.Art:SetPoint("CENTER", 0, -1);
PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON);
NavBar_ToggleMenu(self:GetParent());
end
</OnMouseUp>
<OnEnter>
self.NormalTexture:SetAlpha(1);
self.PushedTexture:SetAlpha(1);
</OnEnter>
<OnLeave>
self.NormalTexture:SetAlpha(0);
self.PushedTexture:SetAlpha(0);
</OnLeave>
<OnEnable>
self.NormalTexture:SetDesaturated(false)
self.PushedTexture:SetDesaturated(false)
self.Art:SetDesaturated(false)
</OnEnable>
<OnDisable>
self.NormalTexture:SetDesaturated(true)
self.PushedTexture:SetDesaturated(true)
self.Art:SetDesaturated(true)
</OnDisable>
</Scripts>
</Button>
</Frames>
<Scripts>
<OnMouseDown>
if self:IsEnabled() == 1 then
self.arrowUp:Hide();
self.arrowDown:Show();
end
</OnMouseDown>
<OnMouseUp>
self.arrowDown:Hide();
self.arrowUp:Show();
</OnMouseUp>
<OnClick>
PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON);
</OnClick>
<OnEnable>
self.arrowDown:Hide();
self.arrowUp:Show();
</OnEnable>
<OnDisable>
self.arrowDown:Hide();
self.arrowUp:Show();
</OnDisable>
</Scripts>
<NormalTexture file="Interface\HelpFrame\CS_HelpTextures_Tile" parentKey="NormalTexture" horizTile="true">
<TexCoords top="0.06250000" bottom="0.12109375"/>
</NormalTexture>
<PushedTexture file="Interface\HelpFrame\CS_HelpTextures_Tile" parentKey="PushedTexture" horizTile="true">
<TexCoords top="0.12500000" bottom="0.18359375"/>
</PushedTexture>
<HighlightTexture file="Interface\HelpFrame\CS_HelpTextures" parentKey="HighlightTexture" alphaMode="ADD">
<TexCoords left="0.00195313" right="0.25195313" top="0.65625000" bottom="0.92187500"/>
</HighlightTexture>
<ButtonText name="$parentText" inherits="GameFontNormal" justifyH="LEFT" parentKey="text">
<Size x="0" y="12"/>
<Anchors>
<Anchor point="LEFT" x="20" y="0"/>
</Anchors>
</ButtonText>
</Button>
<Frame name="NavBarTemplate" parentKey="navBar" virtual="true">
<Size x="300" y="34"/>
<Layers>
<Layer level="BACKGROUND">
<Texture file="Interface\HelpFrame\CS_HelpTextures_Tile" horizTile="true">
<Anchors>
<Anchor point="TOPLEFT" relativePoint="TOPLEFT" x="0" y="0"/>
<Anchor point="BOTTOMRIGHT" relativePoint="BOTTOMRIGHT" x="0" y="0"/>
</Anchors>
<TexCoords top="0.18750000" bottom="0.25390625"/>
</Texture>
</Layer>
</Layers>
<Frames>
<Frame name="$parentOverlay" parentKey="overlay">
<Anchors>
<Anchor point="TOPLEFT" x="0" y="0"/>
<Anchor point="BOTTOMRIGHT" x="0" y="0"/>
</Anchors>
<Layers>
<Layer level="OVERLAY">
<Texture file="Interface\HelpFrame\CS_HelpTextures_Tile" horizTile="true">
<Anchors>
<Anchor point="TOPLEFT" x="0" y="0"/>
<Anchor point="BOTTOMRIGHT" x="0" y="0"/>
</Anchors>
<TexCoords top="0.25781250" bottom="0.32421875"/>
</Texture>
</Layer>
</Layers>
<Scripts>
<OnLoad>
self:SetFrameLevel(50);
</OnLoad>
</Scripts>
</Frame>
<Button name="$parentOverflowButton" parentKey="overflow">
<Size x="44" y="30"/>
<Scripts>
<OnLoad>
self.xoffset = -18
</OnLoad>
<OnClick>
PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON);
</OnClick>
</Scripts>
<NormalTexture file="Interface\HelpFrame\CS_HelpTextures">
<TexCoords left="0.54296875" right="0.62890625" top="0.75781250" bottom="0.99218750"/>
</NormalTexture>
<PushedTexture file="Interface\HelpFrame\CS_HelpTextures">
<TexCoords left="0.45312500" right="0.53906250" top="0.75781250" bottom="0.99218750"/>
</PushedTexture>
<HighlightTexture file="Interface\HelpFrame\CS_HelpTextures" alphaMode="ADD" alpha="0.4">
<TexCoords left="0.54296875" right="0.62890625" top="0.75781250" bottom="0.99218750"/>
</HighlightTexture>
</Button>
<Button name="$parentHomeButton" parentKey="home" text="NAVIGATIONBAR_HOME">
<Size x="128" y="30"/>
<Layers>
<Layer level="OVERLAY">
<Texture name="$parentLeft" file="Interface\Common\ShadowOverlay-Left">
<Size x="30" y="30"/>
<Anchors>
<Anchor point="LEFT" x="0" y="0"/>
</Anchors>
</Texture>
</Layer>
</Layers>
<Scripts>
<OnLoad>
self.xoffset = -15;
local newWidth = min(128, self.text:GetStringWidth()+50)
local texCoordoffsetX = (newWidth/128)*0.25;
self:GetNormalTexture():SetTexCoord(0.70312500-texCoordoffsetX, 0.70312500, 0.00781250, 0.24218750);
self:GetPushedTexture():SetTexCoord(0.70312500-texCoordoffsetX, 0.70312500, 0.25781250, 0.49218750);
self:GetHighlightTexture():SetTexCoord(0.70312500-texCoordoffsetX, 0.71312500, 0.50781250, 0.74218750);
self:SetWidth(newWidth);
</OnLoad>
<OnClick>
PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON);
</OnClick>
</Scripts>
<NormalTexture file="Interface\HelpFrame\CS_HelpTextures">
</NormalTexture>
<PushedTexture file="Interface\HelpFrame\CS_HelpTextures">
</PushedTexture>
<HighlightTexture file="Interface\HelpFrame\CS_HelpTextures" alphaMode="ADD">
</HighlightTexture>
<ButtonText name="$parentText" inherits="GameFontNormal" justifyH="LEFT" parentKey="text">
<Size x="0" y="12"/>
<Anchors>
<Anchor point="LEFT" x="10" y="0"/>
<Anchor point="RIGHT" x="-30" y="0"/>
</Anchors>
</ButtonText>
</Button>
</Frames>
</Frame>
</Ui>
@@ -0,0 +1,422 @@
local pairs = pairs
local ipairs = ipairs
local next = next
local CreateFrame = CreateFrame
ObjectPoolMixin = {};
function ObjectPoolMixin:OnLoad(creationFunc, resetterFunc)
self.creationFunc = creationFunc;
self.resetterFunc = resetterFunc;
self.activeObjects = {};
self.inactiveObjects = {};
self.numActiveObjects = 0;
end
function ObjectPoolMixin:Acquire()
local numInactiveObjects = #self.inactiveObjects;
if numInactiveObjects > 0 then
local obj = self.inactiveObjects[numInactiveObjects];
self.activeObjects[obj] = true;
self.numActiveObjects = self.numActiveObjects + 1;
self.inactiveObjects[numInactiveObjects] = nil;
return obj, false;
end
local newObj = self.creationFunc(self);
if self.resetterFunc and not self.disallowResetIfNew then
self.resetterFunc(self, newObj);
end
self.activeObjects[newObj] = true;
self.numActiveObjects = self.numActiveObjects + 1;
return newObj, true;
end
function ObjectPoolMixin:Release(obj)
if self:IsActive(obj) then
self.inactiveObjects[#self.inactiveObjects + 1] = obj;
self.activeObjects[obj] = nil;
self.numActiveObjects = self.numActiveObjects - 1;
if self.resetterFunc then
self.resetterFunc(self, obj);
end
return true;
end
return false;
end
function ObjectPoolMixin:ReleaseAll()
for obj in pairs(self.activeObjects) do
self:Release(obj);
end
end
function ObjectPoolMixin:SetResetDisallowedIfNew(disallowed)
self.disallowResetIfNew = disallowed;
end
function ObjectPoolMixin:EnumerateActive()
return pairs(self.activeObjects);
end
function ObjectPoolMixin:GetNextActive(current)
return (next(self.activeObjects, current));
end
function ObjectPoolMixin:GetNextInactive(current)
return (next(self.inactiveObjects, current));
end
function ObjectPoolMixin:IsActive(object)
return (self.activeObjects[object] ~= nil);
end
function ObjectPoolMixin:GetNumActive()
return self.numActiveObjects;
end
function ObjectPoolMixin:EnumerateInactive()
return ipairs(self.inactiveObjects);
end
function CreateObjectPool(creationFunc, resetterFunc)
local objectPool = CreateFromMixins(ObjectPoolMixin);
objectPool:OnLoad(creationFunc, resetterFunc);
return objectPool;
end
FramePoolMixin = CreateFromMixins(ObjectPoolMixin);
local pollFrameIndex = 0
local function FramePoolFactory(framePool)
framePool.createdFrames = framePool.createdFrames + 1
pollFrameIndex = pollFrameIndex + 1
local parentName, frameName = framePool.parent and framePool.parent:GetName()
if parentName then
frameName = string.format("%sPoolFrame%s%i_%i", parentName, framePool.frameTemplate or "NoTemplate", framePool.createdFrames, pollFrameIndex)
elseif framePool.frameTemplate then
frameName = string.format("UnnamedPoolFrame%s%i_%i", framePool.frameTemplate, framePool.createdFrames, pollFrameIndex)
else
frameName = string.format("UnnamedPoolFrameNoTemplate%i_%i", framePool.createdFrames, pollFrameIndex)
end
return CreateFrame(framePool.frameType, frameName, framePool.parent, framePool.frameTemplate);
end
local function ForbiddenFramePoolFactory(framePool)
return FramePoolFactory(framePool)
end
function FramePoolMixin:OnLoad(frameType, parent, frameTemplate, resetterFunc, forbidden, frameInitFunc)
if forbidden then
local creationFunc = ForbiddenFramePoolFactory;
if frameInitFunc ~= nil then
creationFunc = function(framePool)
local frame = ForbiddenFramePoolFactory(framePool);
frameInitFunc(frame);
return frame;
end
end
ObjectPoolMixin.OnLoad(self, creationFunc, resetterFunc);
else
local creationFunc = FramePoolFactory;
if frameInitFunc ~= nil then
creationFunc = function(framePool)
local frame = FramePoolFactory(framePool);
frameInitFunc(frame);
return frame;
end
end
ObjectPoolMixin.OnLoad(self, creationFunc, resetterFunc);
end
self.createdFrames = 0;
self.frameType = frameType;
self.parent = parent;
self.frameTemplate = frameTemplate;
end
function FramePoolMixin:GetTemplate()
return self.frameTemplate;
end
function FramePool_Hide(framePool, frame)
frame:Hide();
end
function FramePool_HideAndClearAnchors(framePool, frame)
frame:Hide();
frame:ClearAllPoints();
end
function CreateFramePool(frameType, parent, frameTemplate, resetterFunc, forbidden, frameInitFunc)
local framePool = CreateFromMixins(FramePoolMixin);
framePool:OnLoad(frameType, parent, frameTemplate, resetterFunc or FramePool_HideAndClearAnchors, forbidden, frameInitFunc);
return framePool;
end
TexturePoolMixin = CreateFromMixins(ObjectPoolMixin);
local function TexturePoolFactory(texturePool)
return texturePool.parent:CreateTexture(nil, texturePool.layer, texturePool.textureTemplate, texturePool.subLayer);
end
function TexturePoolMixin:OnLoad(parent, layer, subLayer, textureTemplate, resetterFunc)
ObjectPoolMixin.OnLoad(self, TexturePoolFactory, resetterFunc);
self.parent = parent;
self.layer = layer;
self.subLayer = subLayer;
self.textureTemplate = textureTemplate;
end
TexturePool_Hide = FramePool_Hide;
TexturePool_HideAndClearAnchors = FramePool_HideAndClearAnchors;
function CreateTexturePool(parent, layer, subLayer, textureTemplate, resetterFunc)
local texturePool = CreateFromMixins(TexturePoolMixin);
texturePool:OnLoad(parent, layer, subLayer, textureTemplate, resetterFunc or TexturePool_HideAndClearAnchors);
return texturePool;
end
FontStringPoolMixin = CreateFromMixins(ObjectPoolMixin);
local function FontStringPoolFactory(fontStringPool)
return fontStringPool.parent:CreateFontString(nil, fontStringPool.layer, fontStringPool.fontStringTemplate, fontStringPool.subLayer);
end
function FontStringPoolMixin:OnLoad(parent, layer, subLayer, fontStringTemplate, resetterFunc)
ObjectPoolMixin.OnLoad(self, FontStringPoolFactory, resetterFunc);
self.parent = parent;
self.layer = layer;
self.subLayer = subLayer;
self.fontStringTemplate = fontStringTemplate;
end
FontStringPool_Hide = FramePool_Hide;
FontStringPool_HideAndClearAnchors = FramePool_HideAndClearAnchors;
function CreateFontStringPool(parent, layer, subLayer, fontStringTemplate, resetterFunc)
local fontStringPool = CreateFromMixins(FontStringPoolMixin);
fontStringPool:OnLoad(parent, layer, subLayer, fontStringTemplate, resetterFunc or FontStringPool_HideAndClearAnchors);
return fontStringPool;
end
ActorPoolMixin = CreateFromMixins(ObjectPoolMixin);
local function ActorPoolFactory(actorPool)
return actorPool.parent:CreateActor(nil, actorPool.actorTemplate);
end
function ActorPoolMixin:OnLoad(parent, actorTemplate, resetterFunc)
ObjectPoolMixin.OnLoad(self, ActorPoolFactory, resetterFunc);
self.parent = parent;
self.actorTemplate = actorTemplate;
end
ActorPool_Hide = FramePool_Hide;
function ActorPool_HideAndClearModel(actorPool, actor)
actor:ClearModel();
actor:Hide();
end
function CreateActorPool(parent, actorTemplate, resetterFunc)
local actorPool = CreateFromMixins(ActorPoolMixin);
actorPool:OnLoad(parent, actorTemplate, resetterFunc or ActorPool_HideAndClearModel);
return actorPool;
end
FramePoolCollectionMixin = {};
function CreateFramePoolCollection()
local poolCollection = CreateFromMixins(FramePoolCollectionMixin);
poolCollection:OnLoad();
return poolCollection;
end
function FramePoolCollectionMixin:OnLoad()
self.pools = {};
end
function FramePoolCollectionMixin:GetNumActive()
local numTotalActive = 0;
for _, pool in pairs(self.pools) do
numTotalActive = numTotalActive + pool:GetNumActive();
end
return numTotalActive;
end
-- Returns the pool, and whether or not the pool needed to be created.
function FramePoolCollectionMixin:GetOrCreatePool(frameType, parent, template, resetterFunc, forbidden)
local pool = self:GetPool(template);
if not pool then
return self:CreatePool(frameType, parent, template, resetterFunc, forbidden), true;
end
return pool, false;
end
function FramePoolCollectionMixin:CreatePool(frameType, parent, template, resetterFunc, forbidden, frameInitFunc)
assert(self:GetPool(template) == nil);
local pool = CreateFramePool(frameType, parent, template, resetterFunc, forbidden, frameInitFunc);
self.pools[template] = pool;
return pool;
end
function FramePoolCollectionMixin:GetPool(template)
return self.pools[template];
end
function FramePoolCollectionMixin:Acquire(template)
local pool = self:GetPool(template);
assert(pool);
return pool:Acquire();
end
function FramePoolCollectionMixin:Release(object)
for _, pool in pairs(self.pools) do
if pool:Release(object) then
-- Found it! Just return
return;
end
end
-- Huh, we didn't find that object
assert(false);
end
function FramePoolCollectionMixin:ReleaseAllByTemplate(template)
local pool = self:GetPool(template);
if pool then
pool:ReleaseAll();
end
end
function FramePoolCollectionMixin:ReleaseAll()
for key, pool in pairs(self.pools) do
pool:ReleaseAll();
end
end
function FramePoolCollectionMixin:EnumerateActiveByTemplate(template)
local pool = self:GetPool(template);
if pool then
return pool:EnumerateActive();
end
return nop;
end
function FramePoolCollectionMixin:EnumerateActive()
local currentPoolKey, currentPool = next(self.pools, nil);
local currentObject = nil;
return function()
if currentPool then
currentObject = currentPool:GetNextActive(currentObject);
while not currentObject do
currentPoolKey, currentPool = next(self.pools, currentPoolKey);
if currentPool then
currentObject = currentPool:GetNextActive();
else
break;
end
end
end
return currentObject;
end, nil;
end
function FramePoolCollectionMixin:EnumerateInactiveByTemplate(template)
local pool = self:GetPool(template);
if pool then
return pool:EnumerateInactive();
end
return nop;
end
FixedSizeFramePoolCollectionMixin = CreateFromMixins(FramePoolCollectionMixin);
function CreateFixedSizeFramePoolCollection()
local poolCollection = CreateFromMixins(FixedSizeFramePoolCollectionMixin);
poolCollection:OnLoad();
return poolCollection;
end
function FixedSizeFramePoolCollectionMixin:OnLoad()
FramePoolCollectionMixin.OnLoad(self);
self.sizes = {};
end
function FixedSizeFramePoolCollectionMixin:CreatePool(frameType, parent, template, resetterFunc, forbidden, maxPoolSize, preallocate)
local pool = FramePoolCollectionMixin.CreatePool(self, frameType, parent, template, resetterFunc, forbidden);
if preallocate then
for i = 1, maxPoolSize do
pool:Acquire();
end
pool:ReleaseAll();
end
self.sizes[template] = maxPoolSize;
return pool;
end
function FixedSizeFramePoolCollectionMixin:Acquire(template)
local pool = self:GetPool(template);
assert(pool);
if pool:GetNumActive() < self.sizes[template] then
return pool:Acquire();
end
return nil;
end
FontStringPoolCollectionMixin = CreateFromMixins(FramePoolCollectionMixin);
function CreateFontStringPoolCollection()
local poolCollection = CreateFromMixins(FontStringPoolCollectionMixin);
poolCollection:OnLoad();
return poolCollection;
end
function FontStringPoolCollectionMixin:GetOrCreatePool(parent, layer, subLayer, fontStringTemplate, resetterFunc)
local pool = self:GetPool(fontStringTemplate);
if not pool then
pool = self:CreatePool(parent, layer, subLayer, fontStringTemplate, resetterFunc);
end
return pool;
end
function FontStringPoolCollectionMixin:CreatePool(parent, layer, subLayer, fontStringTemplate, resetterFunc)
assert(self:GetPool(fontStringTemplate) == nil);
local pool = CreateFontStringPool(parent, layer, subLayer, fontStringTemplate, resetterFunc);
self.pools[fontStringTemplate] = pool;
return pool;
end
function FontStringPoolCollectionMixin:CreatePoolIfNeeded(parent, layer, subLayer, fontStringTemplate, resetterFunc)
if not self:GetPool(fontStringTemplate) then
self:CreatePool(parent, layer, subLayer, fontStringTemplate, resetterFunc);
end
end
function FontStringPoolCollectionMixin:Acquire(fontStringTemplate, parent, layer, subLayer, resetterFunc)
local pool = self:GetOrCreatePool(parent, layer, subLayer, fontStringTemplate, resetterFunc);
local newString = pool:Acquire();
if parent then
newString:SetParent(parent);
end
if layer then
newString:SetDrawLayer(layer, subLayer);
end
return newString;
end
@@ -0,0 +1,117 @@
local SetPortraitTexture = SetPortraitTexture
local SetBagPortraitTexture = SetBagPortraitTexture
TitledPanelMixin = {};
function TitledPanelMixin:GetTitleText()
return self.TitleContainer.TitleText;
end
function TitledPanelMixin:SetTitleColor(color)
self:GetTitleText():SetTextColor(color:GetRGBA());
end
function TitledPanelMixin:SetTitle(title)
self:GetTitleText():SetText(title);
end
function TitledPanelMixin:SetTitleFormatted(fmt, ...)
self:GetTitleText():SetFormattedText(fmt, ...);
end
function TitledPanelMixin:SetTitleMaxLinesAndHeight(maxLines, height)
self:GetTitleText():SetMaxLines(maxLines);
self:GetTitleText():SetHeight(height);
end
function TitledPanelMixin:SetTitleOffsets(leftOffset, rightOffset)
self.TitleContainer:SetPoint("TOPLEFT", self, "TOPLEFT", leftOffset or 58, -1);
self.TitleContainer:SetPoint("TOPRIGHT", self, "TOPRIGHT", rightOffset or -24, -1);
end
DefaultPanelMixin = CreateFromMixins(TitledPanelMixin);
PortraitFrameMixin = CreateFromMixins(TitledPanelMixin);
function PortraitFrameMixin:GetPortrait()
return self.portrait;
end
function PortraitFrameMixin:GetTitleText()
return self.TitleText;
end
function PortraitFrameMixin:SetBorder(layoutName)
local layout = NineSliceUtil.GetLayout(layoutName);
NineSliceUtil.ApplyLayout(self.NineSlice, layout);
end
function PortraitFrameMixin:SetPortraitToAsset(texture)
SetPortraitToTexture(self:GetPortrait(), texture);
end
function PortraitFrameMixin:SetPortraitToUnit(unit)
SetPortraitTexture(self:GetPortrait(), unit);
end
function PortraitFrameMixin:SetPortraitToBag(bagID)
SetBagPortraitTexture(self:GetPortrait(), bagID);
end
function PortraitFrameMixin:SetPortraitTextureRaw(texture)
self:GetPortrait():SetTexture(texture);
end
function PortraitFrameMixin:SetPortraitAtlasRaw(atlas, ...)
self:GetPortrait():SetAtlas(atlas, ...);
end
function PortraitFrameMixin:SetPortraitToClassIcon(classFilename)
self:SetPortraitToAsset("Interface/TargetingFrame/UI-Classes-Circles");
local left, right, bottom, top = unpack(CLASS_ICON_TCOORDS[string.upper(classFilename)]);
self:SetPortraitTexCoord(left, right, bottom, top);
end
function PortraitFrameMixin:SetPortraitTexCoord(...)
self:GetPortrait():SetTexCoord(...);
end
function PortraitFrameMixin:SetPortraitShown(shown)
self:GetPortrait():SetShown(shown);
end
function PortraitFrameMixin:SetPortraitTextureSizeAndOffset(size, offsetX, offsetY)
local portrait = self:GetPortrait();
portrait:SetSize(size, size);
portrait:SetPoint("TOPLEFT", self, "TOPLEFT", offsetX, offsetY);
end
do
local function SetFrameLevelInternal(frame, level)
if frame then
-- assertsafe(level < 10000, "Base level needs to be low enough to accomodate the existing layering"); -- TODO: Should become a constant
frame:SetFrameLevel(level);
end
end
function PortraitFrameMixin:SetFrameLevelsFromBaseLevel(baseLevel)
SetFrameLevelInternal(self.NineSlice, baseLevel + 2);
SetFrameLevelInternal(self.PortraitContainer, baseLevel + 1);
SetFrameLevelInternal(self.TitleContainer, baseLevel + 3);
SetFrameLevelInternal(self.CloseButton, baseLevel + 3);
end
end
PortraitFrameFlatBaseMixin = {};
function PortraitFrameFlatBaseMixin:SetBackgroundColor(color)
if self.Bg then
local bg = self.Bg;
color = color or PANEL_BACKGROUND_COLOR;
local r, g, b, a = color:GetRGBA();
bg.BottomLeft:SetVertexColor(r, g, b, a);
bg.BottomRight:SetVertexColor(r, g, b, a);
bg.BottomEdge:SetColorTexture(r, g, b, a);
bg.TopSection:SetColorTexture(r, g, b, a);
end
end
@@ -0,0 +1,660 @@
local function getObjTypeMeta(objType)
local obj = CreateFrame(objType)
obj:Hide()
return getmetatable(obj).__index, obj
end
local FrameMeta, FrameObj = getObjTypeMeta("Frame")
local FontStringMeta = getmetatable(FrameObj:CreateFontString()).__index
local TextureMeta = getmetatable(FrameObj:CreateTexture()).__index
local ButtonMeta = getObjTypeMeta("Button")
local CheckButtonMeta = getObjTypeMeta("CheckButton")
local EditBoxMeta = getObjTypeMeta("EditBox")
local SimpleHTMLMeta = getObjTypeMeta("SimpleHTML")
local SliderMeta = getObjTypeMeta("Slider")
local StatusBarMeta = getObjTypeMeta("StatusBar")
local ScrollFrameMeta = getObjTypeMeta("ScrollFrame")
local MessageFrameMeta = getObjTypeMeta("MessageFrame")
local ScrollingMessageFrameMeta = getObjTypeMeta("ScrollingMessageFrame")
local ModelMeta = getObjTypeMeta("Model")
--local ColorSelectMeta = createAndGetMeta("ColorSelect")
--local MovieFrameMeta = createAndGetMeta("MovieFrame")
local AnimationGroup = FrameObj:CreateAnimationGroup()
local AnimationGroupMeta = getmetatable(AnimationGroup).__index
local AnimationAnimationMeta = getmetatable(AnimationGroup:CreateAnimation("Animation")).__index
local AnimationAlphaMeta = getmetatable(AnimationGroup:CreateAnimation("Alpha")).__index
local AnimationRotationMeta = getmetatable(AnimationGroup:CreateAnimation("Rotation")).__index
local AnimationPathMeta = getmetatable(AnimationGroup:CreateAnimation("Path")).__index
local AnimationScaleMeta = getmetatable(AnimationGroup:CreateAnimation("Scale")).__index
local AnimationTranslationMeta = getmetatable(AnimationGroup:CreateAnimation("Translation")).__index
local GameTooltipMeta, PlayerModelMeta, DressUpModelMeta, TabardModelMeta, ModelFFXMeta
if IsOnGlueScreen() then
ModelFFXMeta = getObjTypeMeta("ModelFFX")
else
GameTooltipMeta = getObjTypeMeta("GameTooltip")
PlayerModelMeta = getObjTypeMeta("PlayerModel")
DressUpModelMeta = getObjTypeMeta("DressUpModel")
TabardModelMeta = getObjTypeMeta("TabardModel")
-- local CooldownMeta = createAndGetMeta("Cooldown")
-- local MinimapMeta = createAndGetMeta("Minimap")
-- local TaxiRouteFrameMeta = createAndGetMeta("TaxiRouteFrame")
-- local QuestPOIFrameMeta = createAndGetMeta("QuestPOIFrame")
-- local WorldFrameMeta = createAndGetMeta("WorldFrame")
end
local function nop() end
local function ScriptRegion_SetShown(self, show)
if show then
self:Show()
else
self:Hide()
end
end
local function ScriptRegion_GetScaledRect(self)
local left, bottom, width, height = self:GetRect()
if left and bottom and width and height then
local scale = self:GetEffectiveScale()
return left * scale, bottom * scale, width * scale, height * scale
end
end
local function ScriptRegion_IsMouseOverEx(self, ignoreVisibility, checkMouseFocus)
if ignoreVisibility or self:IsVisible() then
local l, r, t, b = self:GetHitRectInsets()
return self:IsMouseOver(-t, b, l, -r) and (not checkMouseFocus or self == GetMouseFocus())
end
return false
end
local function ScriptRegionResizing_ClearAndSetPoint(self, ...)
self:ClearAllPoints()
self:SetPoint(...)
end
local function Region_GetEffectiveScale(self)
return self:GetParent():GetEffectiveScale()
end
local function LayoutFrame_SetParentArray(self, arrayName, element, setInSelf)
local parent = not setInSelf and self:GetParent() or self
if not parent[arrayName] then
parent[arrayName] = {}
end
table.insert(parent[arrayName], element or self)
end
local RegisterCustomEvent = RegisterCustomEvent
local UnregisterCustomEvent = UnregisterCustomEvent
local function Frame_RegisterCustomEvent(self, event)
RegisterCustomEvent(self, event)
end
local function Frame_UnregisterCustomEvent(self, event)
UnregisterCustomEvent(self, event)
end
local function FontString_SetDesaturated(self, toggle, color)
if toggle then
self:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b)
else
if type(color) == "table" then
self:SetTextColor(color.r, color.g, color.b)
else
self:SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b)
end
end
end
local SECONDS_PER_DAY = 86400
local function FontString_SetRemainingTime(self, seconds, daysformat)
if type(seconds) ~= "number" then
self:SetText("")
return
end
if daysformat then
if seconds >= SECONDS_PER_DAY then
self:SetFormattedText(D_DAYS_FULL, math.floor(seconds / SECONDS_PER_DAY))
else
self:SetText(date("!%X", seconds))
end
elseif seconds >= SECONDS_PER_DAY then
local days = string.format(DAY_ONELETTER_ABBR_SHORT, math.floor(seconds / SECONDS_PER_DAY))
self:SetFormattedText("%s %s", days, date("!%X", seconds % SECONDS_PER_DAY))
elseif seconds >= 0 then
self:SetText(date("!%X", seconds))
else
self:SetText("")
end
end
local function Texture_SetSubTexCoord(self, left, right, top, bottom)
local ULx, ULy, LLx, LLy, URx, URy, LRx, LRy = self:GetTexCoord()
local leftedge = ULx
local rightedge = URx
local topedge = ULy
local bottomedge = LLy
local width = rightedge - leftedge
local height = bottomedge - topedge
leftedge = ULx + width * left
topedge = ULy + height * top
rightedge = math.max(rightedge * right, ULx)
bottomedge = math.max(bottomedge * bottom, ULy)
ULx = leftedge
ULy = topedge
LLx = leftedge
LLy = bottomedge
URx = rightedge
URy = topedge
LRx = rightedge
LRy = bottomedge
self:SetTexCoord(ULx, ULy, LLx, LLy, URx, URy, LRx, LRy)
end
local ATLAS_FIELD_WIDTH = 1
local ATLAS_FIELD_HEIGHT = 2
local ATLAS_FIELD_LEFT = 3
local ATLAS_FIELD_RIGHT = 4
local ATLAS_FIELD_TOP = 5
local ATLAS_FIELD_BOTTOM = 6
local ATLAS_FIELD_TILESHORIZ = 7
local ATLAS_FIELD_TILESVERT = 8
local ATLAS_FIELD_TEXTUREPATH = 9
local S_ATLAS_STORAGE = S_ATLAS_STORAGE
local function Texture_SetAtlas(self, atlasName, useAtlasSize, filterMode)
if type(self) ~= "table" then
error("Attempt to find 'this' in non-table object (used '.' instead of ':' ?)", 3)
elseif type(atlasName) ~= "string" then
error(string.format("Usage: %s:SetAtlas(\"atlasName\"[, useAtlasSize])", self:GetName() or tostring(self)), 3)
end
local atlas = S_ATLAS_STORAGE[atlasName]
if not atlas then
error(string.format("%s:SetAtlas: Atlas %s does not exist", self:GetName() or tostring(self), atlasName), 3)
end
local success = self:SetTexture(atlas[ATLAS_FIELD_TEXTUREPATH] or "", atlas[ATLAS_FIELD_TILESHORIZ], atlas[ATLAS_FIELD_TILESVERT])
if success then
if useAtlasSize then
self:SetWidth(atlas[ATLAS_FIELD_WIDTH])
self:SetHeight(atlas[ATLAS_FIELD_HEIGHT])
end
self:SetTexCoord(atlas[ATLAS_FIELD_LEFT], atlas[ATLAS_FIELD_RIGHT], atlas[ATLAS_FIELD_TOP], atlas[ATLAS_FIELD_BOTTOM])
self:SetHorizTile(atlas[ATLAS_FIELD_TILESHORIZ])
self:SetVertTile(atlas[ATLAS_FIELD_TILESVERT])
end
return success
end
local function Texture_SetPortrait(self, displayID)
local portrait = strconcat("Interface\\PORTRAITS\\Portrait_model_", tonumber(displayID))
local success = self:SetTexture(portrait)
return success
end
local function Button_SetEnabled(self, enabled)
if enabled then
self:Enable()
else
self:Disable()
end
end
local function Button_SetNormalAtlas(self, atlasName, useAtlasSize, filterMode)
local texture = self:GetNormalTexture()
if not texture then
self:SetNormalTexture("")
texture = self:GetNormalTexture()
end
Texture_SetAtlas(texture, atlasName, useAtlasSize, filterMode)
end
local function Button_SetPushedAtlas(self, atlasName, useAtlasSize, filterMode)
local texture = self:GetPushedTexture()
if not texture then
self:SetPushedTexture("")
texture = self:GetPushedTexture()
end
Texture_SetAtlas(texture, atlasName, useAtlasSize, filterMode)
end
local function Button_SetDisabledAtlas(self, atlasName, useAtlasSize, filterMode)
local texture = self:GetDisabledTexture()
if not texture then
self:SetDisabledTexture("")
texture = self:GetDisabledTexture()
end
Texture_SetAtlas(texture, atlasName, useAtlasSize, filterMode)
end
local function Button_SetHighlightAtlas(self, atlasName, useAtlasSize, filterMode)
local texture = self:GetHighlightTexture()
if not texture then
self:SetHighlightTexture("")
texture = self:GetHighlightTexture()
end
Texture_SetAtlas(texture, atlasName, useAtlasSize, filterMode)
end
local function Button_ClearNormalTexture(self)
self:SetNormalTexture("")
end
local function Button_ClearPushedTexture(self)
self:SetPushedTexture("")
end
local function Button_ClearDisabledTexture(self)
self:SetDisabledTexture("")
end
local function Button_ClearHighlightTexture(self)
self:SetHighlightTexture("")
end
local function CheckButton_SetCheckedAtlas(self, atlasName, useAtlasSize, filterMode)
local texture = self:GetCheckedTexture()
if not texture then
self:SetCheckedTexture("")
texture = self:GetCheckedTexture()
end
Texture_SetAtlas(texture, atlasName, useAtlasSize, filterMode)
end
local function CheckButton_SetDisabledCheckedAtlas(self, atlasName, useAtlasSize, filterMode)
local texture = self:GetDisabledCheckedTexture()
if not texture then
self:SetDisabledCheckedTexture("")
texture = self:GetDisabledCheckedTexture()
end
Texture_SetAtlas(texture, atlasName, useAtlasSize, filterMode)
end
local function CheckButton_ClearCheckedTexture(self)
self:SetCheckedTexture("")
end
local function CheckButton_ClearDisabledCheckedTexture(self)
self:SetDisabledCheckedTexture("")
end
local function EditBox_IsEnabled(self)
return self.__ext_Disabled ~= true
end
local function EditBox_Enabled(self)
if self.__ext_mouseEnabled then
self:EnableMouse(true)
end
if self.__ext_autoFocus then
self:SetAutoFocus(true)
self:SetFocus()
self:HighlightText(0, 0)
end
self.SetFocus = nil
self.__ext_Disabled = nil
self.__ext_autoFocus = nil
self.__ext_mouseEnabled = nil
end
local function EditBox_Disable(self)
if not self.__ext_Disabled then
self.__ext_autoFocus = self:IsAutoFocus() == 1
self.__ext_mouseEnabled = self:IsMouseEnabled() == 1
end
self:SetAutoFocus(false)
self:ClearFocus()
self:EnableMouse(false)
self.SetFocus = nop
self.__ext_Disabled = true
end
local function PlayerModel_UpdateModelEffects(self)
self:ResetAllSpells()
do -- 3D armor
local displayIDs = self:GetDisplayIDs()
if displayIDs then
for index, displayID in ipairs(displayIDs) do
if displayID ~= 0 then
local spellID = ITEMS_WITH_3D[displayID]
if spellID then
self:SetSpell(spellID)
end
end
end
end
end
do -- customizations
if not self.__hideCustomizations then
local guid = self.__unitGUID
if guid and guid == UnitGUID("player") then
local activeCustomizationItems = C_CustomizationsCollection.GetActiveCustomizationItems(1)
if activeCustomizationItems then
for index, customizationItemID in ipairs(activeCustomizationItems) do
local spellID = C_CustomizationsCollection.GetCustomizationSpellByItem(customizationItemID)
if spellID then
if spellID == 320799 then
local SPELL_EFFECTS_GIFT_OF_MOST_PRECIOUS = {313589, 313590, 313591, 313592, 313593, 313594}
spellID = SPELL_EFFECTS_GIFT_OF_MOST_PRECIOUS[math.random(1, #SPELL_EFFECTS_GIFT_OF_MOST_PRECIOUS)]
end
self:SetSpell(spellID)
end
end
end
end
end
end
end
local function PlayerModel_SetUnit(self, unit, isCustomPosition, positionData)
if type(unit) ~= "string" then
error("Usage: SetUnit(\"unit\")", 2)
end
local objectType = self:GetObjectType()
if objectType == "PlayerModel" then
self:SetUnitRaw(unit)
return
end
if isCustomPosition then
if objectType == "TabardModel" then
self:SetPosition(0, 0, 0)
else
self:SetPosition(1, 1, 1)
end
end
self:SetUnitRaw(unit)
self.__hideCustomizations = nil
self.__unitGUID = UnitGUID(unit)
PlayerModel_UpdateModelEffects(self)
if isCustomPosition then
local unitSex = UnitSex(unit) or 2
local _, unitRace = UnitRace(unit)
local positionStorage = positionData or (objectType == "TabardModel" and TABARDMODEL_CAMERA_POSITION or DRESSUPMODEL_CAMERA_POSITION)
local data = positionStorage[string.format("%s%d", unitRace or "Human", unitSex)]
if data then
local positionX, positionY, positionZ, facing = unpack(data, 1, 4)
self.basePositionOverrideX = positionX
self.basePositionOverrideY = positionY
self.basePositionOverrideZ = positionZ
self.basePositionOverrideXasZ = true
self:SetPosition(positionX or 0, positionY or 0, positionZ or 0)
if facing then
self:SetFacing(math.rad(facing))
end
return
end
end
self.basePositionOverrideX = nil
self.basePositionOverrideY = nil
self.basePositionOverrideZ = nil
self.basePositionOverrideXasZ = nil
end
local function PlayerModel_RefreshUnit(self)
self:RefreshUnitRaw()
local objectType = self:GetObjectType()
if objectType == "DressUpModel" or objectType == "TabardModel" then
self.__hideCustomizations = nil
PlayerModel_UpdateModelEffects(self)
end
end
local function DressUpModel_Dress(self)
self:DressRaw()
self.__hideCustomizations = nil
PlayerModel_UpdateModelEffects(self)
end
local function DressUpModel_Undress(self)
self:UndressRaw()
self.__hideCustomizations = true
PlayerModel_UpdateModelEffects(self)
end
local function DressUpModel_TryOn(self, item)
if C_CustomizationsCollection.CanPreviewCustomizationInDressUp(item) then
local spellID, category, subcategory = C_CustomizationsCollection.GetCustomizationSpellByItem(item)
if spellID then
PlayerModel_UpdateModelEffects(self)
for index, activeSpellID in ipairs({self:GetAllSpells()}) do
local isCustomizationSpell, activeSpellCategory, activeSpellSubCategory = C_CustomizationsCollection.IsCustomizationSpell(activeSpellID)
if isCustomizationSpell and category == activeSpellCategory and subcategory == activeSpellSubCategory then
self:ResetSpell(activeSpellID)
break
end
end
if spellID == 320799 then
local SPELL_EFFECTS_GIFT_OF_MOST_PRECIOUS = {313589, 313590, 313591, 313592, 313593, 313594}
spellID = SPELL_EFFECTS_GIFT_OF_MOST_PRECIOUS[math.random(1, #SPELL_EFFECTS_GIFT_OF_MOST_PRECIOUS)]
end
self:SetSpell(spellID)
end
return
end
self:TryOnRaw(item)
PlayerModel_UpdateModelEffects(self)
end
local function Animation_Restart(self)
if self:IsPlaying() then
self:Stop()
end
self:Play()
end
FrameMeta.SetShown = ScriptRegion_SetShown
FrameMeta.GetScaledRect = ScriptRegion_GetScaledRect
FrameMeta.IsMouseOverEx = ScriptRegion_IsMouseOverEx
FrameMeta.ClearAndSetPoint = ScriptRegionResizing_ClearAndSetPoint
FrameMeta.SetParentArray = LayoutFrame_SetParentArray
FrameMeta.RegisterCustomEvent = Frame_RegisterCustomEvent
FrameMeta.UnregisterCustomEvent = Frame_UnregisterCustomEvent
FontStringMeta.SetShown = ScriptRegion_SetShown
FontStringMeta.ClearAndSetPoint = ScriptRegionResizing_ClearAndSetPoint
FontStringMeta.GetEffectiveScale = Region_GetEffectiveScale
FontStringMeta.SetParentArray = LayoutFrame_SetParentArray
FontStringMeta.GetScaledRect = ScriptRegion_GetScaledRect
FontStringMeta.SetDesaturated = FontString_SetDesaturated
FontStringMeta.SetRemainingTime = FontString_SetRemainingTime
TextureMeta.SetShown = ScriptRegion_SetShown
TextureMeta.GetScaledRect = ScriptRegion_GetScaledRect
TextureMeta.ClearAndSetPoint = ScriptRegionResizing_ClearAndSetPoint
TextureMeta.GetEffectiveScale = Region_GetEffectiveScale
TextureMeta.SetParentArray = LayoutFrame_SetParentArray
TextureMeta.SetSubTexCoord = Texture_SetSubTexCoord
TextureMeta.SetAtlas = Texture_SetAtlas
TextureMeta.SetPortrait = Texture_SetPortrait
ButtonMeta.SetShown = ScriptRegion_SetShown
ButtonMeta.GetScaledRect = ScriptRegion_GetScaledRect
ButtonMeta.IsMouseOverEx = ScriptRegion_IsMouseOverEx
ButtonMeta.ClearAndSetPoint = ScriptRegionResizing_ClearAndSetPoint
ButtonMeta.SetParentArray = LayoutFrame_SetParentArray
ButtonMeta.RegisterCustomEvent = Frame_RegisterCustomEvent
ButtonMeta.UnregisterCustomEvent = Frame_UnregisterCustomEvent
ButtonMeta.SetEnabled = Button_SetEnabled
ButtonMeta.SetNormalAtlas = Button_SetNormalAtlas
ButtonMeta.SetPushedAtlas = Button_SetPushedAtlas
ButtonMeta.SetDisabledAtlas = Button_SetDisabledAtlas
ButtonMeta.SetHighlightAtlas = Button_SetHighlightAtlas
ButtonMeta.ClearClearNormalTexture = Button_ClearNormalTexture
ButtonMeta.ClearPushedTexture = Button_ClearPushedTexture
ButtonMeta.ClearDisabledTexture = Button_ClearDisabledTexture
ButtonMeta.ClearHighlightTexture = Button_ClearHighlightTexture
CheckButtonMeta.SetShown = ScriptRegion_SetShown
CheckButtonMeta.IsMouseOverEx = ScriptRegion_IsMouseOverEx
CheckButtonMeta.GetScaledRect = ScriptRegion_GetScaledRect
CheckButtonMeta.ClearAndSetPoint = ScriptRegionResizing_ClearAndSetPoint
CheckButtonMeta.SetParentArray = LayoutFrame_SetParentArray
CheckButtonMeta.RegisterCustomEvent = Frame_RegisterCustomEvent
CheckButtonMeta.UnregisterCustomEvent = Frame_UnregisterCustomEvent
CheckButtonMeta.SetEnabled = Button_SetEnabled
CheckButtonMeta.SetNormalAtlas = Button_SetNormalAtlas
CheckButtonMeta.SetPushedAtlas = Button_SetPushedAtlas
CheckButtonMeta.SetDisabledAtlas = Button_SetDisabledAtlas
CheckButtonMeta.SetHighlightAtlas = Button_SetHighlightAtlas
CheckButtonMeta.SetCheckedAtlas = CheckButton_SetCheckedAtlas
CheckButtonMeta.SetDisabledCheckedAtlas = CheckButton_SetDisabledCheckedAtlas
CheckButtonMeta.ClearClearNormalTexture = Button_ClearNormalTexture
CheckButtonMeta.ClearPushedTexture = Button_ClearPushedTexture
CheckButtonMeta.ClearDisabledTexture = Button_ClearDisabledTexture
CheckButtonMeta.ClearHighlightTexture = Button_ClearHighlightTexture
CheckButtonMeta.ClearDisabledCheckedTexture = CheckButton_ClearCheckedTexture
CheckButtonMeta.ClearDisabledCheckedTexture = CheckButton_ClearDisabledCheckedTexture
EditBoxMeta.SetShown = ScriptRegion_SetShown
EditBoxMeta.GetScaledRect = ScriptRegion_GetScaledRect
EditBoxMeta.ClearAndSetPoint = ScriptRegionResizing_ClearAndSetPoint
EditBoxMeta.RegisterCustomEvent = Frame_RegisterCustomEvent
EditBoxMeta.UnregisterCustomEvent = Frame_UnregisterCustomEvent
EditBoxMeta.SetEnabled = Button_SetEnabled
EditBoxMeta.IsEnabled = EditBox_IsEnabled
EditBoxMeta.Enable = EditBox_Enabled
EditBoxMeta.Disable = EditBox_Disable
SimpleHTMLMeta.SetShown = ScriptRegion_SetShown
SimpleHTMLMeta.GetScaledRect = ScriptRegion_GetScaledRect
SimpleHTMLMeta.ClearAndSetPoint = ScriptRegionResizing_ClearAndSetPoint
SimpleHTMLMeta.SetParentArray = LayoutFrame_SetParentArray
SimpleHTMLMeta.RegisterCustomEvent = Frame_RegisterCustomEvent
SimpleHTMLMeta.UnregisterCustomEvent = Frame_UnregisterCustomEvent
SliderMeta.SetShown = ScriptRegion_SetShown
SliderMeta.GetScaledRect = ScriptRegion_GetScaledRect
SliderMeta.IsMouseOverEx = ScriptRegion_IsMouseOverEx
SliderMeta.ClearAndSetPoint = ScriptRegionResizing_ClearAndSetPoint
SliderMeta.SetParentArray = LayoutFrame_SetParentArray
SliderMeta.RegisterCustomEvent = Frame_RegisterCustomEvent
SliderMeta.UnregisterCustomEvent = Frame_UnregisterCustomEvent
SliderMeta.SetEnabled = Button_SetEnabled
StatusBarMeta.SetShown = ScriptRegion_SetShown
StatusBarMeta.GetScaledRect = ScriptRegion_GetScaledRect
StatusBarMeta.ClearAndSetPoint = ScriptRegionResizing_ClearAndSetPoint
StatusBarMeta.SetParentArray = LayoutFrame_SetParentArray
StatusBarMeta.RegisterCustomEvent = Frame_RegisterCustomEvent
StatusBarMeta.UnregisterCustomEvent = Frame_UnregisterCustomEvent
ScrollFrameMeta.SetShown = ScriptRegion_SetShown
ScrollFrameMeta.GetScaledRect = ScriptRegion_GetScaledRect
ScrollFrameMeta.ClearAndSetPoint = ScriptRegionResizing_ClearAndSetPoint
ScrollFrameMeta.SetParentArray = LayoutFrame_SetParentArray
ScrollFrameMeta.RegisterCustomEvent = Frame_RegisterCustomEvent
ScrollFrameMeta.UnregisterCustomEvent = Frame_UnregisterCustomEvent
MessageFrameMeta.SetShown = ScriptRegion_SetShown
MessageFrameMeta.GetScaledRect = ScriptRegion_GetScaledRect
MessageFrameMeta.ClearAndSetPoint = ScriptRegionResizing_ClearAndSetPoint
MessageFrameMeta.SetParentArray = LayoutFrame_SetParentArray
MessageFrameMeta.RegisterCustomEvent = Frame_RegisterCustomEvent
MessageFrameMeta.UnregisterCustomEvent = Frame_UnregisterCustomEvent
ScrollingMessageFrameMeta.SetShown = ScriptRegion_SetShown
ScrollingMessageFrameMeta.GetScaledRect = ScriptRegion_GetScaledRect
ScrollingMessageFrameMeta.ClearAndSetPoint = ScriptRegionResizing_ClearAndSetPoint
ScrollingMessageFrameMeta.SetParentArray = LayoutFrame_SetParentArray
ScrollingMessageFrameMeta.RegisterCustomEvent = Frame_RegisterCustomEvent
ScrollingMessageFrameMeta.UnregisterCustomEvent = Frame_UnregisterCustomEvent
ModelMeta.SetShown = ScriptRegion_SetShown
ModelMeta.GetScaledRect = ScriptRegion_GetScaledRect
ModelMeta.ClearAndSetPoint = ScriptRegionResizing_ClearAndSetPoint
ModelMeta.RegisterCustomEvent = Frame_RegisterCustomEvent
ModelMeta.UnregisterCustomEvent = Frame_UnregisterCustomEvent
AnimationGroupMeta.Restart = Animation_Restart
AnimationAnimationMeta.Restart = Animation_Restart
AnimationAlphaMeta.Restart = Animation_Restart
AnimationRotationMeta.Restart = Animation_Restart
AnimationPathMeta.Restart = Animation_Restart
AnimationScaleMeta.Restart = Animation_Restart
AnimationTranslationMeta.Restart = Animation_Restart
if IsOnGlueScreen() then
ModelFFXMeta.SetShown = ScriptRegion_SetShown
ModelFFXMeta.RegisterCustomEvent = Frame_RegisterCustomEvent
ModelFFXMeta.UnregisterCustomEvent = Frame_UnregisterCustomEvent
else
GameTooltipMeta.GetScaledRect = ScriptRegion_GetScaledRect
GameTooltipMeta.RegisterCustomEvent = Frame_RegisterCustomEvent
GameTooltipMeta.UnregisterCustomEvent = Frame_UnregisterCustomEvent
PlayerModelMeta.SetShown = ScriptRegion_SetShown
PlayerModelMeta.GetScaledRect = ScriptRegion_GetScaledRect
PlayerModelMeta.ClearAndSetPoint = ScriptRegionResizing_ClearAndSetPoint
PlayerModelMeta.SetParentArray = LayoutFrame_SetParentArray
PlayerModelMeta.RegisterCustomEvent = Frame_RegisterCustomEvent
PlayerModelMeta.UnregisterCustomEvent = Frame_UnregisterCustomEvent
PlayerModelMeta.SetUnitRaw = PlayerModelMeta.SetUnit
PlayerModelMeta.SetUnit = PlayerModel_SetUnit
PlayerModelMeta.RefreshUnitRaw = PlayerModelMeta.RefreshUnit
PlayerModelMeta.RefreshUnit = PlayerModel_RefreshUnit
DressUpModelMeta.SetShown = ScriptRegion_SetShown
DressUpModelMeta.GetScaledRect = ScriptRegion_GetScaledRect
DressUpModelMeta.ClearAndSetPoint = ScriptRegionResizing_ClearAndSetPoint
DressUpModelMeta.SetParentArray = LayoutFrame_SetParentArray
DressUpModelMeta.RegisterCustomEvent = Frame_RegisterCustomEvent
DressUpModelMeta.UnregisterCustomEvent = Frame_UnregisterCustomEvent
DressUpModelMeta.SetUnitRaw = DressUpModelMeta.SetUnit
DressUpModelMeta.SetUnit = PlayerModel_SetUnit
DressUpModelMeta.RefreshUnitRaw = DressUpModelMeta.RefreshUnit
DressUpModelMeta.RefreshUnit = PlayerModel_RefreshUnit
DressUpModelMeta.TryOnRaw = DressUpModelMeta.TryOn
DressUpModelMeta.TryOn = DressUpModel_TryOn
DressUpModelMeta.DressRaw = DressUpModelMeta.Dress
DressUpModelMeta.Dress = DressUpModel_Dress
DressUpModelMeta.UndressRaw = DressUpModelMeta.Undress
DressUpModelMeta.Undress = DressUpModel_Undress
TabardModelMeta.SetShown = ScriptRegion_SetShown
TabardModelMeta.GetScaledRect = ScriptRegion_GetScaledRect
TabardModelMeta.ClearAndSetPoint = ScriptRegionResizing_ClearAndSetPoint
TabardModelMeta.SetParentArray = LayoutFrame_SetParentArray
TabardModelMeta.RegisterCustomEvent = Frame_RegisterCustomEvent
TabardModelMeta.UnregisterCustomEvent = Frame_UnregisterCustomEvent
TabardModelMeta.SetUnitRaw = TabardModelMeta.SetUnit
TabardModelMeta.SetUnit = PlayerModel_SetUnit
TabardModelMeta.RefreshUnitRaw = TabardModelMeta.RefreshUnit
TabardModelMeta.RefreshUnit = PlayerModel_RefreshUnit
TabardModelMeta.SetSpell = function() end
end
@@ -0,0 +1,196 @@
local function SetupTextFont(fontString, fontObject)
if fontString and fontObject then
fontString:SetFontObject(fontObject);
end
end
function SharedTooltip_OnLoad(self)
local style = nil;
local isEmbedded = false;
SharedTooltip_SetBackdropStyle(self, style, isEmbedded);
self:SetClampRectInsets(0, 0, 15, 0);
SetupTextFont(self.TextLeft1, self.textLeft1Font);
SetupTextFont(self.TextRight1, self.textRight1Font);
SetupTextFont(self.TextLeft2, self.textLeft2Font);
SetupTextFont(self.TextRight2, self.textRight2Font);
end
function SharedTooltip_OnHide(self)
self:SetPadding(0, 0, 0, 0);
end
local DEFAULT_TOOLTIP_OFFSET_X = -17;
local DEFAULT_TOOLTIP_OFFSET_Y = 70;
function SharedTooltip_SetDefaultAnchor(tooltip, parent)
tooltip:SetOwner(parent or GetAppropriateTopLevelParent(), "ANCHOR_NONE");
tooltip:SetPoint("BOTTOMRIGHT", GetAppropriateTopLevelParent(), "BOTTOMRIGHT", DEFAULT_TOOLTIP_OFFSET_X, DEFAULT_TOOLTIP_OFFSET_Y);
end
function SharedTooltip_ClearInsertedFrames(self)
if self.insertedFrames then
for i = 1, #self.insertedFrames do
self.insertedFrames[i]:Hide();
end
end
self.insertedFrames = nil;
end
function SharedTooltip_SetBackdropStyle(self, style, embedded)
if embedded or self.IsEmbedded then
self:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b, 0)
self:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b, 0);
else
self:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b, 1);
self:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b, 1);
end
if self.TopOverlay then
if style and style.overlayAtlasTop then
self.TopOverlay:SetAtlas(style.overlayAtlasTop, true);
self.TopOverlay:SetScale(style.overlayAtlasTopScale or 1.0);
self.TopOverlay:SetPoint("CENTER", self, "TOP", style.overlayAtlasTopXOffset or 0, style.overlayAtlasTopYOffset or 0);
self.TopOverlay:Show();
else
self.TopOverlay:Hide();
end
end
if self.BottomOverlay then
if style and style.overlayAtlasBottom then
self.BottomOverlay:SetAtlas(style.overlayAtlasBottom, true);
self.BottomOverlay:SetScale(style.overlayAtlasBottomScale or 1.0);
self.BottomOverlay:SetPoint("CENTER", self, "BOTTOM", style.overlayAtlasBottomXOffset or 0, style.overlayAtlasBottomYOffset or 0);
self.BottomOverlay:Show();
else
self.BottomOverlay:Hide();
end
end
if style and style.padding then
self:SetPadding(style.padding.right, style.padding.bottom, style.padding.left, style.padding.top);
end
end
function GameTooltip_AddBlankLinesToTooltip(tooltip, numLines)
if numLines ~= nil then
for i = 1, numLines do
tooltip:AddLine(" ");
end
end
end
function GameTooltip_AddBlankLineToTooltip(tooltip)
GameTooltip_AddBlankLinesToTooltip(tooltip, 1);
end
function GameTooltip_SetTitle(tooltip, text, overrideColor, wrap)
local titleColor = overrideColor or HIGHLIGHT_FONT_COLOR;
local r, g, b, a = titleColor:GetRGBA();
if wrap == nil then
wrap = 1;
end
tooltip:SetText(text, r, g, b, a, wrap);
end
function GameTooltip_ShowDisabledTooltip(tooltip, owner, text, tooltipAnchor)
tooltip:SetOwner(owner, tooltipAnchor);
local wrap = 1;
GameTooltip_SetTitle(tooltip, text, RED_FONT_COLOR, wrap);
tooltip:Show();
end
function GameTooltip_AddNormalLine(tooltip, text, wrap, leftOffset)
GameTooltip_AddColoredLine(tooltip, text, NORMAL_FONT_COLOR, wrap, leftOffset);
end
function GameTooltip_AddHighlightLine(tooltip, text, wrap, leftOffset)
GameTooltip_AddColoredLine(tooltip, text, HIGHLIGHT_FONT_COLOR, wrap, leftOffset);
end
function GameTooltip_AddInstructionLine(tooltip, text, wrap, leftOffset)
GameTooltip_AddColoredLine(tooltip, text, GREEN_FONT_COLOR, wrap, leftOffset);
end
function GameTooltip_AddErrorLine(tooltip, text, wrap, leftOffset)
GameTooltip_AddColoredLine(tooltip, text, RED_FONT_COLOR, wrap, leftOffset);
end
function GameTooltip_AddDisabledLine(tooltip, text, wrap, leftOffset)
GameTooltip_AddColoredLine(tooltip, text, DISABLED_FONT_COLOR, wrap, leftOffset);
end
function GameTooltip_AddColoredLine(tooltip, text, color, wrap, leftOffset)
local r, g, b = color:GetRGB();
if wrap == nil then
wrap = 1;
end
tooltip:AddLine(text, r, g, b, wrap, leftOffset);
end
function GameTooltip_AddColoredDoubleLine(tooltip, leftText, rightText, leftColor, rightColor, wrap)
local leftR, leftG, leftB = leftColor:GetRGB();
local rightR, rightG, rightB = rightColor:GetRGB();
if wrap == nil then
wrap = 1;
end
tooltip:AddDoubleLine(leftText, rightText, leftR, leftG, leftB, rightR, rightG, rightB, wrap);
end
function GameTooltip_InsertFrame(tooltipFrame, frame, verticalPadding)
verticalPadding = verticalPadding or 0;
local textSpacing = 2;
local textHeight = Round(_G[tooltipFrame:GetName().."TextLeft2"]:GetLineHeight());
local neededHeight = Round(frame:GetHeight() + verticalPadding);
local numLinesNeeded = math.ceil(neededHeight / (textHeight + textSpacing));
local currentLine = tooltipFrame:NumLines();
GameTooltip_AddBlankLinesToTooltip(tooltipFrame, numLinesNeeded);
frame:SetParent(tooltipFrame);
frame:ClearAllPoints();
frame:SetPoint("TOPLEFT", tooltipFrame:GetName().."TextLeft"..(currentLine + 1), "TOPLEFT", 0, -verticalPadding);
if not tooltipFrame.insertedFrames then
tooltipFrame.insertedFrames = { };
end
local frameWidth = frame:GetWidth();
if tooltipFrame:GetMinimumWidth() < frameWidth then
tooltipFrame:SetMinimumWidth(frameWidth);
end
frame:Show();
tinsert(tooltipFrame.insertedFrames, frame);
-- return space taken so inserted frame can resize if needed
return (numLinesNeeded * textHeight) + (numLinesNeeded - 1) * textSpacing;
end
DisabledTooltipButtonMixin = {};
function DisabledTooltipButtonMixin:OnEnter()
if not self:IsEnabled() then
local disabledTooltip, disabledTooltipAnchor = self:GetDisabledTooltip();
if disabledTooltip ~= nil then
GameTooltip_ShowDisabledTooltip(GetAppropriateTooltip(), self, disabledTooltip, disabledTooltipAnchor);
end
end
end
function DisabledTooltipButtonMixin:OnLeave()
local tooltip = GetAppropriateTooltip();
tooltip:Hide();
end
function DisabledTooltipButtonMixin:SetDisabledTooltip(disabledTooltip, disabledTooltipAnchor)
self.disabledTooltip = disabledTooltip;
self.disabledTooltipAnchor = disabledTooltipAnchor;
end
function DisabledTooltipButtonMixin:GetDisabledTooltip()
return self.disabledTooltip, self.disabledTooltipAnchor;
end
function DisabledTooltipButtonMixin:SetDisabledState(disabled, disabledTooltip, disabledTooltipAnchor)
self:SetEnabled(not disabled);
self:SetDisabledTooltip(disabledTooltip, disabledTooltipAnchor);
end
@@ -0,0 +1,191 @@
<Ui xmlns="http://www.blizzard.com/wow/ui/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.blizzard.com/wow/ui/
..\FrameXML\UI.xsd">
<Script file="SharedTooltipTemplates.lua"/>
<FontString name="TooltipTextLeftTemplate" inherits="GameTooltipText" justifyH="LEFT" hidden="true" virtual="true"/>
<FontString name="TooltipTextRightTemplate" inherits="GameTooltipText" justifyH="RIGHT" hidden="true" virtual="true"/>
<Texture name="TooltipTextureTemplate" hidden="true" virtual="true">
<Size x="12" y="12"/>
</Texture>
<GameTooltip name="SharedTooltipTemplate" clampedToScreen="true" frameStrata="TOOLTIP" hidden="true" virtual="true">
<Attributes>
<Attribute name="textLeft1Font" value="GameTooltipHeaderText" type="string"/>
<Attribute name="textRight1Font" value="GameTooltipHeaderText" type="string"/>
<Attribute name="textLeft2Font" value="GameTooltipText" type="string"/>
<Attribute name="textRight2Font" value="GameTooltipText" type="string"/>
<Attribute name="layoutType" value="TooltipDefaultLayout" type="string"/>
</Attributes>
<Backdrop bgFile="Interface\Tooltips\UI-Tooltip-Background" edgeFile="Interface\Tooltips\UI-Tooltip-Border" tile="true">
<EdgeSize>
<AbsValue val="16"/>
</EdgeSize>
<TileSize>
<AbsValue val="16"/>
</TileSize>
<BackgroundInsets>
<AbsInset left="5" right="5" top="5" bottom="5"/>
</BackgroundInsets>
</Backdrop>
<Layers>
<Layer level="OVERLAY">
<Texture parentKey="TopOverlay" hidden="true">
<Anchors>
<Anchor point="CENTER" relativePoint="TOP" />
</Anchors>
</Texture>
<Texture parentKey="BottomOverlay" hidden="true">
<Anchors>
<Anchor point="CENTER" relativePoint="BOTTOM" />
</Anchors>
</Texture>
</Layer>
<Layer level="ARTWORK">
<FontString name="$parentTextLeft1" parentKey="TextLeft1" inherits="TooltipTextLeftTemplate">
<Anchors>
<Anchor point="TOPLEFT" x="10" y="-10"/>
</Anchors>
</FontString>
<FontString name="$parentTextRight1" parentKey="TextRight1" inherits="TooltipTextRightTemplate" justifyH="LEFT">
<Anchors>
<Anchor point="RIGHT" relativeTo="$parentTextLeft1" relativePoint="LEFT" x="40" y="0"/>
</Anchors>
</FontString>
<FontString name="$parentTextLeft2" parentKey="TextLeft2" inherits="TooltipTextLeftTemplate">
<Anchors>
<Anchor point="TOPLEFT" relativeTo="$parentTextLeft1" relativePoint="BOTTOMLEFT" x="0" y="-2"/>
</Anchors>
</FontString>
<FontString name="$parentTextRight2" parentKey="TextRight2" inherits="TooltipTextRightTemplate">
<Anchors>
<Anchor point="RIGHT" relativeTo="$parentTextLeft2" relativePoint="LEFT" x="40" y="0"/>
</Anchors>
</FontString>
<Texture name="$parentTexture1" inherits="TooltipTextureTemplate"/>
<Texture name="$parentTexture2" inherits="TooltipTextureTemplate"/>
<Texture name="$parentTexture3" inherits="TooltipTextureTemplate"/>
<Texture name="$parentTexture4" inherits="TooltipTextureTemplate"/>
<Texture name="$parentTexture5" inherits="TooltipTextureTemplate"/>
<Texture name="$parentTexture6" inherits="TooltipTextureTemplate"/>
<Texture name="$parentTexture7" inherits="TooltipTextureTemplate"/>
<Texture name="$parentTexture8" inherits="TooltipTextureTemplate"/>
<Texture name="$parentTexture9" inherits="TooltipTextureTemplate"/>
<Texture name="$parentTexture10" inherits="TooltipTextureTemplate"/>
<Texture name="$parentTexture11" inherits="TooltipTextureTemplate"/>
<Texture name="$parentTexture12" inherits="TooltipTextureTemplate"/>
<Texture name="$parentTexture13" inherits="TooltipTextureTemplate"/>
<Texture name="$parentTexture14" inherits="TooltipTextureTemplate"/>
<Texture name="$parentTexture15" inherits="TooltipTextureTemplate"/>
<Texture name="$parentTexture16" inherits="TooltipTextureTemplate"/>
<Texture name="$parentTexture17" inherits="TooltipTextureTemplate"/>
<Texture name="$parentTexture18" inherits="TooltipTextureTemplate"/>
<Texture name="$parentTexture19" inherits="TooltipTextureTemplate"/>
<Texture name="$parentTexture20" inherits="TooltipTextureTemplate"/>
<Texture name="$parentTexture21" inherits="TooltipTextureTemplate"/>
<Texture name="$parentTexture22" inherits="TooltipTextureTemplate"/>
<Texture name="$parentTexture23" inherits="TooltipTextureTemplate"/>
<Texture name="$parentTexture24" inherits="TooltipTextureTemplate"/>
<Texture name="$parentTexture25" inherits="TooltipTextureTemplate"/>
<Texture name="$parentTexture26" inherits="TooltipTextureTemplate"/>
<Texture name="$parentTexture27" inherits="TooltipTextureTemplate"/>
<Texture name="$parentTexture28" inherits="TooltipTextureTemplate"/>
<Texture name="$parentTexture29" inherits="TooltipTextureTemplate"/>
<Texture name="$parentTexture30" inherits="TooltipTextureTemplate"/>
</Layer>
</Layers>
<Scripts>
<OnLoad function="SharedTooltip_OnLoad"/>
<OnHide function="SharedTooltip_OnHide"/>
<OnTooltipSetDefaultAnchor function="SharedTooltip_SetDefaultAnchor"/>
<OnTooltipCleared function="SharedTooltip_ClearInsertedFrames"/>
</Scripts>
</GameTooltip>
<GameTooltip name="SharedNoHeaderTooltipTemplate" inherits="SharedTooltipTemplate" virtual="true">
<Attributes>
<Attribute name="textLeft1Font" value="GameTooltipText" type="string"/>
<Attribute name="textRight1Font" value="GameTooltipText" type="string"/>
</Attributes>
</GameTooltip>
<Frame name="TooltipBorderedFrameTemplate" virtual="true">
<Layers>
<Layer level="BACKGROUND">
<Texture parentKey="BorderTopLeft" name="$parentBorderTopLeft" file="Interface\Tooltips\UI-Tooltip-TL">
<Size x="8" y="8"/>
<Anchors>
<Anchor point="TOPLEFT"/>
</Anchors>
</Texture>
<Texture parentKey="BorderTopRight" name="$parentBorderTopRight" file="Interface\Tooltips\UI-Tooltip-TR">
<Size x="8" y="8"/>
<Anchors>
<Anchor point="TOPRIGHT"/>
</Anchors>
</Texture>
<Texture parentKey="BorderBottomRight" name="$parentBorderBottomRight" file="Interface\Tooltips\UI-Tooltip-BR">
<Size x="8" y="8"/>
<Anchors>
<Anchor point="BOTTOMRIGHT"/>
</Anchors>
</Texture>
<Texture parentKey="BorderBottomLeft" name="$parentBorderBottomLeft" file="Interface\Tooltips\UI-Tooltip-BL">
<Size x="8" y="8"/>
<Anchors>
<Anchor point="BOTTOMLEFT"/>
</Anchors>
</Texture>
<Texture parentKey="BorderTop" file="Interface\Tooltips\UI-Tooltip-T">
<Size x="8" y="8"/>
<Anchors>
<Anchor point="TOPLEFT" relativeTo="$parentBorderTopLeft" relativePoint="TOPRIGHT"/>
<Anchor point="TOPRIGHT" relativeTo="$parentBorderTopRight" relativePoint="TOPLEFT"/>
</Anchors>
</Texture>
<Texture parentKey="BorderRight" file="Interface\Tooltips\UI-Tooltip-R">
<Size x="8" y="8"/>
<Anchors>
<Anchor point="TOPRIGHT" relativeTo="$parentBorderTopRight" relativePoint="BOTTOMRIGHT"/>
<Anchor point="BOTTOMRIGHT" relativeTo="$parentBorderBottomRight" relativePoint="TOPRIGHT"/>
</Anchors>
</Texture>
<Texture parentKey="BorderBottom" file="Interface\Tooltips\UI-Tooltip-B">
<Size x="8" y="8"/>
<Anchors>
<Anchor point="BOTTOMLEFT" relativeTo="$parentBorderBottomLeft" relativePoint="BOTTOMRIGHT"/>
<Anchor point="BOTTOMRIGHT" relativeTo="$parentBorderBottomRight" relativePoint="BOTTOMLEFT"/>
</Anchors>
</Texture>
<Texture parentKey="BorderLeft" file="Interface\Tooltips\UI-Tooltip-L">
<Size x="8" y="8"/>
<Anchors>
<Anchor point="TOPLEFT" relativeTo="$parentBorderTopLeft" relativePoint="BOTTOMLEFT"/>
<Anchor point="BOTTOMLEFT" relativeTo="$parentBorderBottomLeft" relativePoint="TOPLEFT"/>
</Anchors>
</Texture>
<Texture parentKey="Background">
<Anchors>
<Anchor point="TOPLEFT" relativeTo="$parentBorderTopLeft" relativePoint="BOTTOMRIGHT"/>
<Anchor point="BOTTOMRIGHT" relativeTo="$parentBorderBottomRight" relativePoint="TOPLEFT"/>
</Anchors>
<Color r="0" g="0" b="0" a="0.8"/>
</Texture>
</Layer>
</Layers>
</Frame>
<Button name="DisabledTooltipButtonTemplate" motionScriptsWhileDisabled="true" virtual="true">
<Scripts>
<OnLoad>
Mixin(self, DisabledTooltipButtonMixin)
</OnLoad>
<OnEnter>
self:OnEnter()
</OnEnter>
<OnLeave>
self:OnLeave()
</OnLeave>
</Scripts>
</Button>
</Ui>
@@ -0,0 +1,365 @@
-- SOUND KITS
SOUNDKIT = {
LOOT_WINDOW_COIN_SOUND = 120,
INTERFACE_SOUND_LOST_TARGET_UNIT = 684,
GS_TITLE_OPTIONS = 778,
GS_TITLE_CREDITS = 790,
GS_TITLE_OPTION_OK = 798,
GS_TITLE_OPTION_EXIT = 799,
GS_LOGIN = 800,
GS_LOGIN_NEW_ACCOUNT = 801,
GS_LOGIN_CHANGE_REALM_OK = 805,
GS_LOGIN_CHANGE_REALM_CANCEL = 807,
GS_CHARACTER_SELECTION_ENTER_WORLD = 809,
GS_CHARACTER_SELECTION_DEL_CHARACTER = 810,
GS_CHARACTER_SELECTION_ACCT_OPTIONS = 811,
GS_CHARACTER_SELECTION_EXIT = 812,
GS_CHARACTER_SELECTION_CREATE_NEW = 813,
GS_CHARACTER_CREATION_CLASS = 814,
GS_CHARACTER_CREATION_LOOK = 817,
GS_CHARACTER_CREATION_CREATE_CHAR = 818,
GS_CHARACTER_CREATION_CANCEL = 819,
IG_MINIMAP_OPEN = 821,
IG_MINIMAP_CLOSE = 822,
IG_MINIMAP_ZOOM_IN = 823,
IG_MINIMAP_ZOOM_OUT = 824,
IG_CHAT_EMOTE_BUTTON = 825,
IG_CHAT_SCROLL_UP = 826,
IG_CHAT_SCROLL_DOWN = 827,
IG_CHAT_BOTTOM = 828,
IG_SPELLBOOK_OPEN = 829,
IG_SPELLBOOK_CLOSE = 830,
IG_ABILITY_OPEN = 834,
IG_ABILITY_CLOSE = 835,
IG_ABILITY_PAGE_TURN = 836,
IG_ABILITY_ICON_DROP = 838,
IG_CHARACTER_INFO_OPEN = 839,
IG_CHARACTER_INFO_CLOSE = 840,
IG_CHARACTER_INFO_TAB = 841,
IG_QUEST_LOG_OPEN = 844,
IG_QUEST_LOG_CLOSE = 845,
IG_QUEST_LOG_ABANDON_QUEST = 846,
IG_MAINMENU_OPEN = 850,
IG_MAINMENU_CLOSE = 851,
IG_MAINMENU_OPTION = 852,
IG_MAINMENU_LOGOUT = 853,
IG_MAINMENU_QUIT = 854,
IG_MAINMENU_CONTINUE = 855,
IG_MAINMENU_OPTION_CHECKBOX_ON = 856,
IG_MAINMENU_OPTION_CHECKBOX_OFF = 857,
IG_MAINMENU_OPTION_FAER_TAB = 858,
IG_INVENTORY_ROTATE_CHARACTER = 861,
IG_BACKPACK_OPEN = 862,
IG_BACKPACK_CLOSE = 863,
IG_BACKPACK_COIN_SELECT = 864,
IG_BACKPACK_COIN_OK = 865,
IG_BACKPACK_COIN_CANCEL = 866,
IG_CHARACTER_NPC_SELECT = 867,
IG_CREATURE_NEUTRAL_SELECT = 871,
IG_CREATURE_AGGRO_SELECT = 873,
IG_QUEST_LIST_OPEN = 875,
IG_QUEST_LIST_CLOSE = 876,
IG_QUEST_LIST_SELECT = 877,
IG_QUEST_LIST_COMPLETE = 878,
IG_QUEST_CANCEL = 879,
IG_PLAYER_INVITE = 880,
MONEY_FRAME_OPEN = 891,
MONEY_FRAME_CLOSE = 892,
U_CHAT_SCROLL_BUTTON = 1115,
PUT_DOWN_SMALL_CHAIN = 1212,
LOOT_WINDOW_OPEN_EMPTY = 1264,
TELL_MESSAGE = 3081,
MAP_PING = 3175,
FISHING_REEL_IN = 3407,
IG_PVP_UPDATE = 4574,
AUCTION_WINDOW_OPEN = 5274,
AUCTION_WINDOW_CLOSE = 5275,
TUTORIAL_POPUP = 7355,
ITEM_REPAIR = 7994,
PVP_ENTER_QUEUE = 8458,
PVP_THROUGH_QUEUE = 8459,
KEY_RING_OPEN = 8938,
KEY_RING_CLOSE = 8939,
RAID_WARNING = 8959,
READY_CHECK = 8960,
GLUESCREEN_INTRO = 9902,
AMB_GLUESCREEN_HUMAN = 9903,
AMB_GLUESCREEN_ORC = 9905,
AMB_GLUESCREEN_TAUREN = 9906,
AMB_GLUESCREEN_DWARF = 9907,
AMB_GLUESCREEN_NIGHTELF = 9908,
AMB_GLUESCREEN_UNDEAD = 9909,
AMB_GLUESCREEN_BLOODELF = 9910,
AMB_GLUESCREEN_DRAENEI = 9911,
JEWEL_CRAFTING_FINALIZE = 10590,
MENU_CREDITS01 = 10763,
MENU_CREDITS02 = 10804,
GUILD_VAULT_OPEN = 12188,
GUILD_VAULT_CLOSE = 12189,
RAID_BOSS_EMOTE_WARNING = 12197,
GUILD_BANK_OPEN_BAG = 12206,
GS_LICH_KING = 12765,
ALARM_CLOCK_WARNING_2 = 12867,
ALARM_CLOCK_WARNING_3 = 12889,
MENU_CREDITS03 = 13822,
ACHIEVEMENT_MENU_OPEN = 13832,
ACHIEVEMENT_MENU_CLOSE = 13833,
BARBERSHOP_HAIRCUT = 13873,
BARBERSHOP_SIT = 14148,
GM_CHAT_WARNING = 15273,
LFG_REWARDS = 17316,
LFG_ROLE_CHECK = 17317,
LFG_DENIED = 17341,
UI_BNET_TOAST = 18019,
ALARM_CLOCK_WARNING_1 = 18871,
AMB_GLUESCREEN_WORGEN = 20169,
AMB_GLUESCREEN_GOBLIN = 20170,
AMB_GLUESCREEN_TROLL = 21136,
AMB_GLUESCREEN_GNOME = 21137,
UI_POWER_AURA_GENERIC = 23287,
UI_REFORGING_REFORGE = 23291,
UI_AUTO_QUEST_COMPLETE = 23404,
GS_CATACLYSM = 23640,
MENU_CREDITS04 = 23812,
UI_BATTLEGROUND_COUNTDOWN_TIMER = 25477,
UI_BATTLEGROUND_COUNTDOWN_FINISHED = 25478,
UI_VOID_STORAGE_UNLOCK = 25711,
UI_VOID_STORAGE_DEPOSIT = 25712,
UI_VOID_STORAGE_WITHDRAW = 25713,
UI_TRANSMOGRIFY_UNDO = 25715,
UI_ETHEREAL_WINDOW_OPEN = 25716,
UI_ETHEREAL_WINDOW_CLOSE = 25717,
UI_TRANSMOGRIFY_REDO = 25738,
UI_VOID_STORAGE_BOTH = 25744,
AMB_GLUESCREEN_PANDAREN = 25848,
MUS_50_HEART_OF_PANDARIA_MAINTITLE = 28509,
UI_PET_BATTLES_TRAP_READY = 28814,
UI_EPICLOOT_TOAST = 31578,
UI_BONUS_LOOT_ROLL_START = 31579,
UI_BONUS_LOOT_ROLL_LOOP = 31580,
UI_BONUS_LOOT_ROLL_END = 31581,
UI_PET_BATTLE_START = 31584,
UI_SCENARIO_ENDING = 31754,
UI_SCENARIO_STAGE_END = 31757,
MENU_CREDITS05 = 32015,
UI_PET_BATTLE_CAMERA_MOVE_IN = 32047,
UI_PET_BATTLE_CAMERA_MOVE_OUT = 32052,
AMB_50_GLUESCREEN_ALLIANCE = 32412,
AMB_50_GLUESCREEN_HORDE = 32413,
AMB_50_GLUESCREEN_PANDAREN_NEUTRAL = 32414,
UI_CHALLENGES_NEW_RECORD = 33338,
MENU_CREDITS06 = 34020,
UI_LOSS_OF_CONTROL_START = 34468,
UI_PET_BATTLES_PVP_THROUGH_QUEUE = 36609,
AMB_GLUESCREEN_DEATHKNIGHT = 37056,
UI_RAID_BOSS_WHISPER_WARNING = 37666,
UI_DIG_SITE_COMPLETION_TOAST = 38326,
UI_IG_STORE_PAGE_NAV_BUTTON = 39511,
UI_IG_STORE_WINDOW_OPEN_BUTTON = 39512,
UI_IG_STORE_WINDOW_CLOSE_BUTTON = 39513,
UI_IG_STORE_CANCEL_BUTTON = 39514,
UI_IG_STORE_BUY_BUTTON = 39515,
UI_IG_STORE_CONFIRM_PURCHASE_BUTTON = 39516,
UI_IG_STORE_PURCHASE_DELIVERED_TOAST_01 = 39517,
MUS_60_MAIN_TITLE = 40169,
UI_GARRISON_MISSION_COMPLETE_ENCOUNTER_FAIL = 43501,
UI_GARRISON_MISSION_COMPLETE_MISSION_SUCCESS = 43502,
UI_GARRISON_MISSION_COMPLETE_MISSION_FAIL_STINGER = 43503,
UI_GARRISON_MISSION_THREAT_COUNTERED = 43505,
UI_GARRISON_MISSION_100_PERCENT_CHANCE_REACHED_NOT_USED = 43507,
UI_QUEST_ROLLING_FORWARD_01 = 43936,
UI_BAG_SORTING_01 = 43937,
UI_TOYBOX_TABS = 43938,
UI_GARRISON_TOAST_INVASION_ALERT = 44292,
UI_GARRISON_TOAST_MISSION_COMPLETE = 44294,
UI_GARRISON_TOAST_BUILDING_COMPLETE = 44295,
UI_GARRISON_TOAST_FOLLOWER_GAINED = 44296,
UI_GARRISON_NAV_TABS = 44297,
UI_GARRISON_GARRISON_REPORT_OPEN = 44298,
UI_GARRISON_GARRISON_REPORT_CLOSE = 44299,
UI_GARRISON_ARCHITECT_TABLE_OPEN = 44300,
UI_GARRISON_ARCHITECT_TABLE_CLOSE = 44301,
UI_GARRISON_ARCHITECT_TABLE_UPGRADE = 44302,
UI_GARRISON_ARCHITECT_TABLE_UPGRADE_CANCEL = 44304,
UI_GARRISON_ARCHITECT_TABLE_UPGRADE_START = 44305,
UI_GARRISON_ARCHITECT_TABLE_PLOT_SELECT = 44306,
UI_GARRISON_ARCHITECT_TABLE_BUILDING_SELECT = 44307,
UI_GARRISON_ARCHITECT_TABLE_BUILDING_PLACEMENT = 44308,
UI_GARRISON_COMMAND_TABLE_OPEN = 44311,
UI_GARRISON_COMMAND_TABLE_CLOSE = 44312,
UI_GARRISON_COMMAND_TABLE_MISSION_CLOSE = 44313,
UI_GARRISON_COMMAND_TABLE_NAV_NEXT = 44314,
UI_GARRISON_COMMAND_TABLE_SELECT_MISSION = 44315,
UI_GARRISON_COMMAND_TABLE_SELECT_FOLLOWER = 44316,
UI_GARRISON_COMMAND_TABLE_FOLLOWER_ABILITY_OPEN = 44317,
UI_GARRISON_COMMAND_TABLE_FOLLOWER_ABILITY_CLOSE = 44318,
UI_GARRISON_COMMAND_TABLE_ASSIGN_FOLLOWER = 44319,
UI_GARRISON_COMMAND_TABLE_UNASSIGN_FOLLOWER = 44320,
UI_GARRISON_COMMAND_TABLE_SLOT_CHAMPION = 72546,
UI_GARRISON_COMMAND_TABLE_SLOT_TROOP = 72547,
UI_GARRISON_COMMAND_TABLE_REDUCED_SUCCESS_CHANCE = 44321,
UI_GARRISON_COMMAND_TABLE_100_SUCCESS = 44322,
UI_GARRISON_COMMAND_TABLE_MISSION_START = 44323,
UI_GARRISON_COMMAND_TABLE_VIEW_MISSION_REPORT = 44324,
UI_GARRISON_COMMAND_TABLE_MISSION_SUCCESS_STINGER = 44330,
UI_GARRISON_COMMAND_TABLE_CHEST_UNLOCK = 44331,
UI_GARRISON_COMMAND_TABLE_CHEST_UNLOCK_GOLD_SUCCESS = 44332,
UI_GARRISON_MONUMENTS_OPEN = 44344,
UI_BONUS_EVENT_SYSTEM_VIGNETTES = 45142,
UI_GARRISON_COMMAND_TABLE_FOLLOWER_LEVEL_UP = 46893,
UI_GARRISON_ARCHITECT_TABLE_BUILDING_PLACEMENT_ERROR = 47355,
UI_GARRISON_MONUMENTS_CLOSE = 47373,
AMB_GLUESCREEN_WARLORDS_OF_DRAENOR = 47544,
MUS_1_0_MAINTITLE_ORIGINAL = 47598,
UI_GROUP_FINDER_RECEIVE_APPLICATION = 47615,
UI_GARRISON_MISSION_ENCOUNTER_ANIMATION_GENERIC = 47704,
UI_GARRISON_START_WORK_ORDER = 47972,
UI_GARRISON_SHIPMENTS_WINDOW_OPEN = 48191,
UI_GARRISON_SHIPMENTS_WINDOW_CLOSE = 48192,
UI_GARRISON_MONUMENTS_NAV = 48942,
UI_RAID_BOSS_DEFEATED = 50111,
UI_PERSONAL_LOOT_BANNER = 50893,
UI_GARRISON_FOLLOWER_LEARN_TRAIT = 51324,
UI_GARRISON_SHIPYARD_PLACE_CARRIER = 51385,
UI_GARRISON_SHIPYARD_PLACE_GALLEON = 51387,
UI_GARRISON_SHIPYARD_PLACE_DREADNOUGHT = 51388,
UI_GARRISON_SHIPYARD_PLACE_SUBMARINE = 51389,
UI_GARRISON_SHIPYARD_PLACE_LANDING_CRAFT = 51390,
UI_GARRISON_SHIPYARD_START_MISSION = 51401,
UI_RAID_LOOT_TOAST_LESSER_ITEM_WON = 51402,
UI_WARFORGED_ITEM_LOOT_TOAST = 51561,
UI_GARRISON_COMMAND_TABLE_INCREASED_SUCCESS_CHANCE = 51570,
UI_GARRISON_SHIPYARD_DECOMISSION_SHIP = 51871,
UI_70_ARTIFACT_FORGE_TRAIT_FIRST_TRAIT = 54126,
UI_70_ARTIFACT_FORGE_RELIC_PLACE = 54128,
UI_70_ARTIFACT_FORGE_APPEARANCE_COLOR_SELECT = 54130,
UI_70_ARTIFACT_FORGE_APPEARANCE_LOCKED = 54131,
UI_70_ARTIFACT_FORGE_APPEARANCE_APPEARANCE_CHANGE = 54132,
UI_70_ARTIFACT_FORGE_TOAST_TRAIT_AVAILABLE = 54133,
UI_70_ARTIFACT_FORGE_APPEARANCE_APPEARANCE_UNLOCK = 54139,
UI_70_ARTIFACT_FORGE_TRAIT_GOLD_TRAIT = 54125,
UI_72_ARTIFACT_FORGE_FINAL_TRAIT_UNLOCKED = 83682,
UI_70_ARTIFACT_FORGE_TRAIT_FINALRANK = 54127,
UI_70_ARTIFACT_FORGE_TRAIT_RANKUP = 54129,
AMB_GLUESCREEN_DEMONHUNTER = 56352,
MUS_70_MAIN_TITLE = 56353,
MENU_CREDITS07 = 56354,
UI_TRANSMOG_ITEM_CLICK = 62538,
UI_TRANSMOG_PAGE_TURN = 62539,
UI_TRANSMOG_GEAR_SLOT_CLICK = 62540,
UI_TRANSMOG_REVERTING_GEAR_SLOT = 62541,
UI_TRANSMOG_APPLY = 62542,
UI_TRANSMOG_CLOSE_WINDOW = 62543,
UI_TRANSMOG_OPEN_WINDOW = 62544,
UI_LEGENDARY_LOOT_TOAST = 63971,
UI_STORE_UNWRAP = 64329,
AMB_GLUESCREEN_LEGION = 71535,
UI_MISSION_200_PERCENT = 72548,
UI_MISSION_MAP_ZOOM = 72549,
UI_70_BOOST_THANKSFORPLAYING_SMALLER = 72978,
UI_70_BOOST_THANKSFORPLAYING = 72977,
UI_WORLDQUEST_START = 73275,
UI_WORLDQUEST_MAP_SELECT = 73276,
UI_WORLDQUEST_COMPLETE = 73277,
UI_ORDERHALL_TALENT_SELECT = 73279,
UI_ORDERHALL_TALENT_READY_TOAST = 73280,
UI_ORDERHALL_TALENT_READY_CHECK = 73281,
UI_ORDERHALL_TALENT_NUKE_FROM_ORBIT = 73282,
UI_ORDERHALL_TALENT_WINDOW_OPEN = 73914,
UI_ORDERHALL_TALENT_WINDOW_CLOSE = 73915,
UI_PROFESSIONS_WINDOW_OPEN = 73917,
UI_PROFESSIONS_WINDOW_CLOSE = 73918,
UI_PROFESSIONS_NEW_RECIPE_LEARNED_TOAST = 73919,
UI_70_CHALLENGE_MODE_SOCKET_PAGE_OPEN = 74421,
UI_70_CHALLENGE_MODE_SOCKET_PAGE_CLOSE = 74423,
UI_70_CHALLENGE_MODE_SOCKET_PAGE_SOCKET = 74431,
UI_70_CHALLENGE_MODE_SOCKET_PAGE_ACTIVATE_BUTTON = 74432,
UI_70_CHALLENGE_MODE_KEYSTONE_UPGRADE = 74437,
UI_70_CHALLENGE_MODE_NEW_RECORD = 74438,
UI_70_CHALLENGE_MODE_SOCKET_PAGE_REMOVE_KEYSTONE = 74525,
UI_70_CHALLENGE_MODE_COMPLETE_NO_UPGRADE = 74526,
UI_MISSION_SUCCESS_CHEERS = 74702,
UI_PVP_HONOR_PRESTIGE_OPEN_WINDOW = 76995,
UI_PVP_HONOR_PRESTIGE_WINDOW_CLOSE = 77002,
UI_PVP_HONOR_PRESTIGE_RANK_UP = 77003,
UI_71_SOCIAL_QUEUEING_TOAST = 79739,
UI_72_ARTIFACT_FORGE_ACTIVATE_FINAL_TIER = 83681,
UI_72_BUILDINGS_CONTRIBUTE_POWER_MENU_CLICK = 84240,
UI_72_BUILDING_CONTRIBUTION_TABLE_OPEN = 84368,
UI_72_BUILDINGS_CONTRIBUTION_TABLE_CLOSE = 84369,
UI_72_BUILDINGS_CONTRIBUTE_RESOURCES = 84378,
UI_72_ARTIFACT_FORGE_FINAL_TRAIT_REFUND_START = 83684,
UI_72_ARTIFACT_FORGE_FINAL_TRAIT_REFUND_LOOP = 83685,
UI_73_ARTIFACT_RELICS_TRAIT_SELECT_AND_REVEAL = 89685,
UI_73_ARTIFACT_RELICS_TRAIT_SELECT_ONLY = 89686,
UI_73_ARTIFACT_RELICS_TRAIT_REVEAL_ONLY = 90080,
PUT_DOWN_GEMS = 1204,
PICK_UP_GEMS = 1221,
UI_73_ARTIFACT_OVERLOADED_HIGHEST = 97301,
UI_73_ARTIFACT_OVERLOADED_HIGH = 97471,
UI_73_ARTIFACT_OVERLOADED_MEDIUM = 97470,
UI_73_ARTIFACT_OVERLOADED_LOW = 97469,
UI_73_ARTIFACT_OVERLOADED_ORB_HIGHEST = 97559,
UI_73_ARTIFACT_OVERLOADED_ORB_HIGH = 97558,
UI_73_ARTIFACT_OVERLOADED_ORB_MEDIUM = 97557,
UI_73_ARTIFACT_OVERLOADED_ORB_LOW = 97556,
UI_73_ARTIFACT_OVERLOADED_ORB_IMPACT_MEDIUM = 97597,
UI_73_ARTIFACT_OVERLOADED_ORB_IMPACT_LOW = 97598,
AMB_GLUESCREEN_VOIDELF = 97324,
AMB_GLUESCREEN_LIGHTFORGEDDRAENEI = 97325,
AMB_GLUESCREEN_NIGHTBORNE = 97326,
AMB_GLUESCREEN_HIGHMOUNTAINTAUREN = 97327,
UI_VOICECHAT_DEAFENOFF = 110990,
UI_VOICECHAT_DEAFENON = 110989,
UI_VOICECHAT_MUTEOFF = 110988,
UI_VOICECHAT_MUTEON = 110987,
UI_VOICECHAT_MUTEOTHEROFF = 111080,
UI_VOICECHAT_MUTEOTHERON = 111081,
UI_VOICECHAT_MEMBERLEAVECHANNEL = 110986,
UI_VOICECHAT_MEMBERJOINCHANNEL = 110985,
UI_VOICECHAT_STOPTALK = 110984,
UI_VOICECHAT_TALKSTART = 110983,
UI_VOICECHAT_LEAVECHANNEL = 110982,
UI_VOICECHAT_JOINCHANNEL = 110981,
AMB_GLUESCREEN_BATTLE_FOR_AZEROTH = 113894,
AMB_GLUESCREEN_MAGHARORC = 113556,
AMB_GLUESCREEN_DARKIRONDWARF = 113557,
MUS_80_MAIN_TITLE = 113559,
MENU_CREDITS08 = 113560,
UI_AZERITE_EMPOWERED_ITEM_LOOT_TOAST = 118238,
UI_80_AZERITEARMOR_SELECTBUFF = 114993,
UI_80_AZERITEARMOR_BUFFAVAILABLE = 116657,
UI_80_AZERITEARMOR_ROTATION_LOOP = 114994,
UI_80_AZERITEARMOR_ROTATIONENDS = 114995,
UI_80_AZERITEARMOR_ROTATIONENDS_FINALTRAIT = 116233,
UI_80_AZERITEARMOR_ROTATIONENDCLICKS = 115314,
UI_80_AZERITEARMOR_ROTATIONSTARTCLICKS = 115358,
UI_80_AZERITEARMOR_FIRSTTIMEFLOURISH = 118264,
UI_80_AZERITEARMOR_REFORGE_ETHEREALWINDOW_OPEN = 114990,
UI_80_AZERITEARMOR_REFORGE_ETHEREALWINDOW_CLOSE = 114991,
UI_80_AZERITEARMOR_REFORGE = 114992,
UI_80_ISLANDS_AZERITECOLLECTION_START = 115003,
UI_80_ISLANDS_AZERITECOLLECTION_LOOP = 115004,
UI_80_ISLANDS_AZERITECOLLECTION_STOP = 115005,
UI_80_SCRAPPING_WINDOW_CLOSE = 115487,
UI_80_SCRAPPING_WINDOW_OPEN = 115488,
UI_WARMODE_ACTIVATE = 118563,
UI_WARMODE_DECTIVATE = 118564,
UI_80_ISLANDS_TABLE_OPEN = 118610,
UI_80_ISLANDS_TABLE_CLOSE = 118611,
UI_80_ISLANDS_TABLE_SELECT_DIFFICULTY = 118612,
UI_80_ISLANDS_TABLE_FIND_GROUP = 118613,
UI_80_ISLANDS_TABLE_FIND_GROUP_PVP = 118668,
UI_80_ISLANDS_TUTORIAL_CLOSE = 119726,
UI_GARRISON_MISSION_COMPLETE_ENCOUNTER_CHANCE = 0, -- missing SoundKit entry!
UI_COUNTDOWN_BAR_STATE_STARTS = 158958,
UI_COUNTDOWN_BAR_STATE_FINISHED = 158959,
UI_COUNTDOWN_MEDIUM_NUMBER_FINISHED = 158960,
UI_COUNTDOWN_TIMER = 191352,
UI_COUNTDOWN_FINISHED = 158566,
};
@@ -0,0 +1,499 @@
local ColumnWidthConstraints = {
Fill = 1, -- Width will be distributed by available space.
Fixed = 2, -- Width is specified when initializing the column.
};
-- Any row or cell is expected to initialize itself in terms of the row data. The dataIndex is provided
-- in case the derived mixin needs to make additional CAPI calls involving it's relative index. The row
-- data may also be needed for a tooltip, so it will be assigned to the row and cells on update.
TableBuilderElementMixin = {};
--Derive
function TableBuilderElementMixin:Init(...)
end
--Derive
function TableBuilderElementMixin:Populate(rowData, dataIndex)
end
TableBuilderCellMixin = CreateFromMixins(TableBuilderElementMixin);
--Derive
function TableBuilderCellMixin:OnLineEnter()
end
--Derive
function TableBuilderCellMixin:OnLineLeave()
end
TableBuilderRowMixin = CreateFromMixins(TableBuilderElementMixin);
--Derive
function TableBuilderRowMixin:OnLineEnter()
end
--Derive
function TableBuilderRowMixin:OnLineLeave()
end
function TableBuilderRowMixin:OnEnter()
self:OnLineEnter();
for i, cell in ipairs(self.cells) do
cell:OnLineEnter();
end
end
function TableBuilderRowMixin:OnLeave()
self:OnLineLeave();
for i, cell in ipairs(self.cells) do
cell:OnLineLeave();
end
end
-- Defines an entire column within the table builder, by default a column's sizing constraints are set to fill.
TableBuilderColumnMixin = {};
function TableBuilderColumnMixin:Init(table)
self.cells = {};
self.table = table;
local fillCoefficient = 1.0;
local padding = 0;
self:SetFillConstraints(fillCoefficient, padding);
end
-- Constructs the header frame with an optional initializer.
function TableBuilderColumnMixin:ConstructHeader(templateType, template, ...)
local frame = self.table:ConstructHeader(templateType, template);
self.headerFrame = frame;
if frame.Init then
frame:Init(...);
end
frame:Show();
end
-- Constructs cells corresponding to each row with an optional initializer.
function TableBuilderColumnMixin:ConstructCells(templateType, template, ...)
local cells = self.table:ConstructCells(templateType, template);
self.cells = cells;
for k, cell in pairs(cells) do
if cell.Init then
cell:Init(...);
end
cell:Show();
end
end
function TableBuilderColumnMixin:GetCellByRowIndex(rowIndex)
return self.cells[rowIndex];
end
function TableBuilderColumnMixin:GetFillCoefficient()
return self.fillCoefficient;
end
function TableBuilderColumnMixin:SetFillCoefficient(fillCoefficient)
self.fillCoefficient = fillCoefficient;
end
function TableBuilderColumnMixin:GetPadding()
return self.padding;
end
function TableBuilderColumnMixin:SetPadding(padding)
self.padding = padding;
end
function TableBuilderColumnMixin:GetCellPadding()
return self.leftCellPadding or 0, self.rightCellPadding or 0;
end
function TableBuilderColumnMixin:SetCellPadding(leftCellPadding, rightCellPadding)
self.leftCellPadding = leftCellPadding;
self.rightCellPadding = rightCellPadding;
end
function TableBuilderColumnMixin:GetHeaderFrame()
return self.headerFrame;
end
function TableBuilderColumnMixin:SetHeaderFrame(headerFrame)
self.headerFrame = headerFrame;
end
function TableBuilderColumnMixin:GetWidthConstraints()
return self.widthConstraints;
end
function TableBuilderColumnMixin:GetFixedWidth()
return self.fixedWidth;
end
-- A header frame for the column is expected to be constructed or assigned prior to calling this.
-- See ConstructHeader() or SetHeaderFrame().
function TableBuilderColumnMixin:ConstrainToHeader(padding)
local header = self:GetHeaderFrame();
assert(header, "ConstrainToHeader() called with a nil header frame. Use ConstructHeader() or assign one with SetHeaderFrame(), or use SetFixedConstraints to have a headerless column.");
self:SetFixedConstraints(header:GetWidth(), padding or 0);
end
function TableBuilderColumnMixin:SetFixedConstraints(fixedWidth, padding)
self.widthConstraints = ColumnWidthConstraints.Fixed;
self.fixedWidth = fixedWidth;
self:SetFillCoefficient(0);
self:SetPadding(padding or 0);
end
function TableBuilderColumnMixin:SetFillConstraints(fillCoefficient, padding)
self.widthConstraints = ColumnWidthConstraints.Fill;
self.fixedWidth = 0;
self:SetFillCoefficient(fillCoefficient);
self:SetPadding(padding or 0);
end
function TableBuilderColumnMixin:SetCalculatedWidth(calculatedWidth)
self.calculatedWidth = calculatedWidth;
end
function TableBuilderColumnMixin:GetCalculatedWidth()
return self.calculatedWidth;
end
function TableBuilderColumnMixin:GetCellWidth()
local leftCellPadding, rightCellPadding = self:GetCellPadding();
return (self.calculatedWidth - leftCellPadding) - rightCellPadding;
end
function TableBuilderColumnMixin:GetFullWidth()
return self:GetCalculatedWidth() + self:GetPadding();
end
function TableBuilderColumnMixin:SetDisplayUnderPreviousHeader(displayUnderPreviousHeader)
self.displayUnderPreviousHeader = displayUnderPreviousHeader;
end
function TableBuilderColumnMixin:GetDisplayUnderPreviousHeader()
return self.displayUnderPreviousHeader;
end
-- Constructs a table of frames within an existing set of row frames. These row frames could originate from
-- a hybrid scroll frame or statically fixed set. To populate the table, assign a data provider (CAPI or lua function)
-- that can retrieve an object by index (number).
TableBuilderMixin = {};
function TableBuilderMixin:Init(rows)
self.columns = {};
self.leftMargin = 0;
self.rightMargin = 0;
self.columnHeaderOverlap = 0;
self.tableWidth = 0;
self.headerPoolCollection = CreateFramePoolCollection();
self:SetRows(rows);
end
function TableBuilderMixin:GetDataProvider()
return self.dataProvider;
end
function TableBuilderMixin:SetDataProvider(dataProvider)
self.dataProvider = dataProvider;
end
function TableBuilderMixin:GetDataProviderData(dataIndex)
local dataProvider = self:GetDataProvider();
return dataProvider and dataProvider(dataIndex) or nil;
end
-- Controls the margins of the left-most and right-most columns within the table.
function TableBuilderMixin:SetTableMargins(leftMargin, rightMargin)
rightMargin = rightMargin or leftMargin; -- Use leftMargin as the default for both.
self.leftMargin = leftMargin;
self.rightMargin = rightMargin;
end
-- Column headers overlap to make a consistent display.
function TableBuilderMixin:SetColumnHeaderOverlap(columnHeaderOverlap)
self.columnHeaderOverlap = columnHeaderOverlap;
end
-- Can be used to set the table width, particularly if no header frames are involved.
function TableBuilderMixin:SetTableWidth(tableWidth)
self.tableWidth = tableWidth;
end
function TableBuilderMixin:GetTableWidth()
return self.tableWidth;
end
function TableBuilderMixin:GetTableMargins()
return self.leftMargin, self.rightMargin;
end
function TableBuilderMixin:GetColumnHeaderOverlap()
return self.columnHeaderOverlap;
end
function TableBuilderMixin:GetColumns()
return self.columns;
end
function TableBuilderMixin:GetHeaderContainer()
return self.headerContainer;
end
function TableBuilderMixin:SetHeaderContainer(headerContainer)
assert(headerContainer, "SetHeaderContainer() with a nil header container. Use ConstructHeader() or assign one with SetHeaderFrame(), or use SetFixedConstraints to have a headerless column.");
self.headerContainer = headerContainer;
self:SetTableWidth(headerContainer:GetWidth());
end
function TableBuilderMixin:ReleaseRowPools()
local rows = self.rows;
if rows then
for k, row in pairs(rows) do
local poolCollection = row.poolCollection;
if poolCollection then
poolCollection:ReleaseAll();
end
end
end
end
function TableBuilderMixin:SetRows(rows)
-- Release any previous rows, though I can't imagine a case where the rows
-- are being exchanged.
self:ReleaseRowPools();
self.rows = rows;
for k, row in pairs(rows) do
if not row.poolCollection then
row.poolCollection = CreateFramePoolCollection();
end
end
end
function TableBuilderMixin:GetHeaderPoolCollection()
return self.headerPoolCollection;
end
function TableBuilderMixin:GetRows()
return self.rows;
end
function TableBuilderMixin:ConstructHeader(templateType, template)
local headerContainer = self:GetHeaderContainer();
assert(headerContainer ~= nil, "A header container must be set with TableBuilderMixin:SetHeaderContainer before adding column headers.")
local headerPoolCollection = self:GetHeaderPoolCollection();
local pool = headerPoolCollection:GetOrCreatePool(templateType, headerContainer, template);
return pool:Acquire(template);
end
function TableBuilderMixin:ConstructCells(templateType, template)
local cells = {};
for k, row in pairs(self:GetRows()) do
local pool = row.poolCollection:GetOrCreatePool(templateType, row, template);
local cell = pool:Acquire(template);
tinsert(cells, cell);
end
return cells;
end
function TableBuilderMixin:Arrange()
local columns = self:GetColumns();
if columns and #columns > 0 then
self:CalculateColumnSpacing();
self:ArrangeHeaders();
self:ArrangeCells();
end
end
function TableBuilderMixin:Reset()
self.columns = {};
self:GetHeaderPoolCollection():ReleaseAll();
self:ReleaseRowPools();
end
function TableBuilderMixin:Populate(offset, count)
local dataProvider = self:GetDataProvider();
local columns = self:GetColumns();
for rowIndex = 1, count do
local dataIndex = rowIndex + offset;
local rowData = dataProvider(dataIndex);
if not rowData then
break;
end
local row = self:GetRowByIndex(rowIndex);
if row then
-- Data is assigned to the rows and elements so they can
-- access it later in tooltips.
row.rowData = rowData;
if row.Populate then
row:Populate(rowData, dataIndex);
end
for columnIndex, p in ipairs(columns) do
local cell = self:GetCellByIndex(rowIndex, columnIndex);
if cell.Populate then
cell.rowData = rowData;
cell:Populate(rowData, dataIndex);
end
end
end
end
end
function TableBuilderMixin:GetCellByIndex(rowIndex, index)
local row = self:GetRowByIndex(rowIndex);
return row.cells[index];
end
function TableBuilderMixin:GetRowByIndex(rowIndex)
return self.rows[rowIndex];
end
function TableBuilderMixin:AddColumn()
local column = CreateAndInitFromMixin(TableBuilderColumnMixin, self);
tinsert(self.columns, column);
return column;
end
function TableBuilderMixin:CalculateColumnSpacing()
-- The arrangement of frames is daisy-chained left to right. The margin on the left side
-- is created by adding the margin to it's anchor offset, and the margin on the right side
-- is created by subtracting space from the remaining fill space.
local columns = self:GetColumns();
local paddingTotal = 0;
local fillCoefficientTotal = 0;
local fixedWidthTotal = 0;
for columnIndex, column in ipairs(columns) do
if column:GetWidthConstraints() == ColumnWidthConstraints.Fill then
fillCoefficientTotal = fillCoefficientTotal + column:GetFillCoefficient();
else
fixedWidthTotal = fixedWidthTotal + column:GetFixedWidth();
end
paddingTotal = paddingTotal + column:GetPadding();
end
local tableWidth = self:GetTableWidth();
local leftMargin, rightMargin = self:GetTableMargins();
local fillWidthTotal = tableWidth - paddingTotal - (leftMargin + rightMargin) - fixedWidthTotal;
for k, column in pairs(columns) do
if fillCoefficientTotal > 0 and column:GetWidthConstraints() == ColumnWidthConstraints.Fill then
local fillRatio = column:GetFillCoefficient() / fillCoefficientTotal;
local width = fillRatio * fillWidthTotal;
column:SetCalculatedWidth(width);
else
local width = column:GetFixedWidth();
column:SetCalculatedWidth(width);
end
end
end
function TableBuilderMixin:ArrangeHorizontally(frame, relativeTo, width, pointTop, pointRelativeTop, pointBottom, pointRelativeBottom, xOffset)
frame:SetPoint(pointTop, relativeTo, pointRelativeTop, xOffset, 0);
frame:SetPoint(pointBottom, relativeTo, pointRelativeBottom, xOffset, 0);
frame:SetWidth(width);
end
function TableBuilderMixin:ArrangeHeaders()
local headerOverlap = self:GetColumnHeaderOverlap();
local leftMargin, rightMargin = self:GetTableMargins();
local columns = self:GetColumns();
-- Any trailing columns without headers should add to the width of the last column with a header.
local numColumns = #columns;
local lastActiveHeaderIndex = numColumns;
local trailingWidth = 0;
for i, column in ipairs(columns) do
if column:GetHeaderFrame() then
trailingWidth = 0;
lastActiveHeaderIndex = i;
else
trailingWidth = trailingWidth + column:GetFullWidth();
end
end
local previousHeader = nil;
local accumulatedWidth = 0;
local columnIndex = 1;
while columnIndex <= numColumns do
local column = columns[columnIndex];
accumulatedWidth = accumulatedWidth + column:GetCalculatedWidth();
local isLastIndex = columnIndex == lastActiveHeaderIndex;
local header = column:GetHeaderFrame();
if header then
if isLastIndex then
accumulatedWidth = accumulatedWidth + trailingWidth;
else
for j = columnIndex + 1, #columns do
local nextColumn = columns[j];
if nextColumn:GetDisplayUnderPreviousHeader() then
columnIndex = columnIndex + 1;
accumulatedWidth = accumulatedWidth + nextColumn:GetFullWidth();
else
break;
end
end
end
if previousHeader == nil then
self:ArrangeHorizontally(header, header:GetParent(), accumulatedWidth, "TOPLEFT", "TOPLEFT", "BOTTOMLEFT", "BOTTOMLEFT", leftMargin);
else
self:ArrangeHorizontally(header, previousHeader, accumulatedWidth + headerOverlap, "TOPLEFT", "TOPRIGHT", "BOTTOMLEFT", "BOTTOMRIGHT", column:GetPadding() - headerOverlap);
end
accumulatedWidth = 0;
previousHeader = header;
end
if isLastIndex then
break;
end
columnIndex = columnIndex + 1;
end
end
function TableBuilderMixin:ArrangeCells()
local columns = self:GetColumns();
local leftMargin, rightMargin = self:GetTableMargins();
for rowIndex, row in ipairs(self:GetRows()) do
local cells = {};
local height = row:GetHeight();
local column = columns[1];
local cell = column:GetCellByRowIndex(rowIndex);
tinsert(cells, cell);
cell:SetHeight(height);
local leftCellPadding, rightCellPadding = column:GetCellPadding();
self:ArrangeHorizontally(cell, row, column:GetCellWidth(), "TOPLEFT", "TOPLEFT", "BOTTOMLEFT", "BOTTOMLEFT", leftMargin + leftCellPadding);
local previousCell = cell;
local previousRightCellPadding = rightCellPadding;
for columnIndex = 2, #columns do
column = columns[columnIndex];
cell = column:GetCellByRowIndex(rowIndex);
tinsert(cells, cell);
cell:SetHeight(height);
leftCellPadding, rightCellPadding = column:GetCellPadding();
self:ArrangeHorizontally(cell, previousCell, column:GetCellWidth(), "TOPLEFT", "TOPRIGHT", "BOTTOMLEFT", "BOTTOMRIGHT", column:GetPadding() + leftCellPadding + previousRightCellPadding);
previousCell = cell;
previousRightCellPadding = rightCellPadding;
end
row.cells = cells;
end
end
-- ... are additional mixins
function CreateTableBuilder(rows, ...)
local tableBuilder = CreateAndInitFromMixin(TableBuilderMixin, rows);
Mixin(tableBuilder, ...);
return tableBuilder;
end
@@ -0,0 +1,697 @@
local tRemove = table.remove;
local tInsert = table.insert;
local tWipe = table.wipe;
TableUtil = {};
TableUtil.Constants =
{
AssociativePriorityTable = true,
ArraylikePriorityTable = false,
IsIndexTable = true,
};
function ipairs_reverse(table)
local function Enumerator(table, index)
index = index - 1;
local value = table[index];
if value ~= nil then
return index, value;
end
end
return Enumerator, table, #table + 1;
end
function CreateTableEnumerator(tbl, minIndex, maxIndex)
minIndex = minIndex and (minIndex - 1) or 0;
maxIndex = maxIndex or math.huge;
local function Enumerator(tbl, index)
index = index + 1;
if index <= maxIndex then
local value = tbl[index];
if value ~= nil then
return index, value;
end
end
end
return Enumerator, tbl, minIndex;
end
function CreateTableReverseEnumerator(tbl, minIndex, maxIndex)
minIndex = minIndex or 1;
maxIndex = (maxIndex or #tbl) + 1;
local function Enumerator(tbl, index)
index = index - 1;
if index >= minIndex then
local value = tbl[index];
if value ~= nil then
return index, value;
end
end
end
return Enumerator, tbl, maxIndex;
end
function tCount(t)
if type(t) ~= "table" then
return 0
end
local size = 0
for _ in pairs(t) do
size = size + 1
end
return size
end
function tDeleteItem(tbl, item)
local size = #tbl;
local index = size;
while index > 0 do
if item == tbl[index] then
tRemove(tbl, index);
end
index = index - 1;
end
return size - #tbl;
end
function tIndexOf(tbl, item)
for i, v in ipairs(tbl) do
if item == v then
return i;
end
end
end
function tContains(tbl, item)
local index = 1;
while tbl[index] do
if ( item == tbl[index] ) then
return 1;
end
index = index + 1;
end
return nil;
end
function tContainsValue(tbl, item)
for k, v in pairs(tbl) do
if item == v then
return true;
end
end
return false;
end
function TableUtil.ContainsAllKeys(lhsTable, rhsTable)
for key, _ in pairs(lhsTable) do
if rhsTable[key] == nil then
return false;
end
end
-- Check for any keys that are in rhsTable and not lhsTable.
for key, _ in pairs(rhsTable) do
if lhsTable[key] == nil then
return false;
end
end
return true;
end
function TableUtil.CompareValuesAsKeys(lhsTable, rhsTable, valueToKeyOp)
local lhsKeys = CopyTransformedValuesAsKeys(lhsTable, valueToKeyOp);
local rhsKeys = CopyTransformedValuesAsKeys(rhsTable, valueToKeyOp);
return TableUtil.ContainsAllKeys(lhsKeys, rhsKeys)
end
-- This is a deep compare on the values of the table (based on depth) but not a deep comparison
-- of the keys, as this would be an expensive check and won't be necessary in most cases.
function tCompare(lhsTable, rhsTable, depth)
depth = depth or 1;
for key, value in pairs(lhsTable) do
if type(value) == "table" then
local rhsValue = rhsTable[key];
if type(rhsValue) ~= "table" then
return false;
end
if depth > 1 then
if not tCompare(value, rhsValue, depth - 1) then
return false;
end
end
elseif value ~= rhsTable[key] then
return false;
end
end
-- Check for any keys that are in rhsTable and not lhsTable.
for key, value in pairs(rhsTable) do
if lhsTable[key] == nil then
return false;
end
end
return true;
end
function tInvert(tbl)
local inverted = {};
for k, v in pairs(tbl) do
inverted[v] = k;
end
return inverted;
end
function TableUtil.TrySet(tbl, key)
if not tbl[key] then
tbl[key] = true;
return true;
end
return false;
end
function TableUtil.CopyUnique(tbl, isIndexTable)
local found = {};
local function FilterPredicate(value)
return TableUtil.TrySet(found, value);
end
return tFilter(tbl, FilterPredicate, isIndexTable);
end
function TableUtil.CopyUniqueByPredicate(tbl, isIndexTable, unaryPredicate)
local found = {};
local function FilterPredicate(value)
return TableUtil.TrySet(found, unaryPredicate(value));
end
return tFilter(tbl, FilterPredicate, isIndexTable);
end
function tFilter(tbl, pred, isIndexTable)
local out = {};
if (isIndexTable) then
local currentIndex = 1;
for i, v in ipairs(tbl) do
if (pred(v)) then
out[currentIndex] = v;
currentIndex = currentIndex + 1;
end
end
else
for k, v in pairs(tbl) do
if (pred(v)) then
out[k] = v;
end
end
end
return out;
end
function tAppendAll(table, addedArray)
for i, element in ipairs(addedArray) do
tinsert(table, element);
end
end
function tInsertUnique(tbl, item)
if not tContains(tbl, item) then
table.insert(tbl, item);
return #tbl;
end
return nil;
end
function tUnorderedRemove(tbl, index)
if index ~= #tbl then
tbl[index] = tbl[#tbl];
end
tRemove(tbl);
end
function CopyTable(settings, shallow)
local copy = {};
for k, v in pairs(settings) do
if type(v) == "table" and not shallow then
copy[k] = CopyTable(v);
else
copy[k] = v;
end
end
return copy;
end
function MergeTable(destination, source)
for k, v in pairs(source) do
destination[k] = v;
end
end
-- Useful if there are external references to a table but we want to set
-- that table's key-value pairs to be exactly the same as another table's key-value pairs.
function SetTablePairsToTable(destination, source)
tWipe(destination);
MergeTable(destination, source);
end
function Accumulate(tbl)
local count = 0;
for k, v in pairs(tbl) do
count = count + v;
end
return count;
end
function AccumulateOp(tbl, op)
local count = 0;
for k, v in pairs(tbl) do
count = count + op(v);
end
return count;
end
function TableUtil.Execute(tbl, op)
for k, v in pairs(tbl) do
op(v);
end
end
function TableUtil.ExecuteUntil(tbl, op)
for k, v in pairs(tbl) do
local operationResult = op(v);
if operationResult then
return operationResult;
end
end
return nil;
end
function TableUtil.Transform(tbl, op)
local result = {};
for k, v in pairs(tbl) do
table.insert(result, op(v));
end
return result;
end
function ContainsIf(tbl, pred)
for k, v in pairs(tbl) do
if (pred(v)) then
return true;
end
end
return false;
end
function FindInTableIf(tbl, pred)
for k, v in pairs(tbl) do
if (pred(v)) then
return k, v;
end
end
return nil;
end
function FindValueInTableIf(tbl, pred)
local _, value = FindInTableIf(tbl, pred);
return value;
end
local function FindSortedIndexImplementation(tbl, searchComparison, startIndex, rangeStart, rangeEnd)
local comparisonResult = searchComparison(tbl[startIndex]);
if comparisonResult == 0 then
return startIndex;
end
if comparisonResult > 0 then
if startIndex >= rangeEnd then
return startIndex + 1;
end
rangeStart = startIndex + 1;
return FindSortedIndexImplementation(tbl, searchComparison, startIndex + math.ceil((rangeEnd - startIndex) / 2), rangeStart, rangeEnd);
end
-- comparisonResult < 0
if startIndex <= rangeStart then
return startIndex;
end
rangeEnd = startIndex - 1;
return FindSortedIndexImplementation(tbl, searchComparison, math.floor(startIndex / 2), rangeStart, rangeEnd);
end
function FindSortedIndex(tbl, searchComparison)
local numTable = #tbl;
local startingIndex = math.ceil(numTable / 2);
if startingIndex == 0 then
return 1;
end
return FindSortedIndexImplementation(tbl, searchComparison, startingIndex, 1, numTable);
end
function TableIsEmpty(tbl)
return next(tbl) == nil;
end
function TableHasAnyEntries(tbl)
return next(tbl) ~= nil;
end
function CopyValuesAsKeys(tbl)
local output = {};
for k, v in ipairs(tbl) do
output[v] = v;
end
return output;
end
function CopyTransformedValuesAsKeys(tbl, transformOp)
local output = {};
for _, v in ipairs(tbl) do
output[transformOp(v)] = v;
end
return output;
end
-- Addresses the problem where nil values within a varargs list are not preserved when constructing
-- a table, resulting a table with a smaller size than expected. Should be paired with a call to
-- SafeUnpack when unpacking the table.
function SafePack(...)
local tbl = { ... };
tbl.n = select("#", ...);
return tbl;
end
-- Upacks a table that was constructed using SafePack.
function SafeUnpack(tbl, startIndex)
return unpack(tbl, startIndex or 1, tbl.n);
end
-- Returns the length of a table, accounting for the possibility of a table constructed using SafePack.
function SafeLength(tbl)
if not tbl then
return 0;
end
local operatorCount = #tbl;
local safePackCount = tbl.n;
if safePackCount and operatorCount ~= safePackCount then
return safePackCount;
end
return operatorCount;
end
function GetOrCreateTableEntry(table, key, defaultValue)
local currentValue = table[key];
local isNewValue = (currentValue == nil);
if isNewValue then
if defaultValue ~= nil then
currentValue = defaultValue;
else
currentValue = {};
end
table[key] = currentValue;
end
return currentValue, isNewValue;
end
function GetOrCreateTableEntryByCallback(table, key, callback)
local currentValue = table[key];
local isNewValue = (currentValue == nil);
if isNewValue then
currentValue = callback(key);
table[key] = currentValue;
end
return currentValue, isNewValue;
end
function GetRandomArrayEntry(array)
return array[math.random(1, #array)];
end
function GetRandomTableValue(tbl)
local value;
local n = 0;
for k, v in pairs(tbl) do
n = n + 1;
local r = math.random();
if r <= (1 / n) then
value = v;
end
end
return value;
end
function GetKeysArray(tbl)
local keysArray = {};
for key in pairs(tbl) do
tInsert(keysArray, key);
end
return keysArray;
end
function GetValuesArray(tbl)
local valuesArray = {};
for key, value in pairs(tbl) do
tInsert(valuesArray, value);
end
return valuesArray;
end
function GetPairsArray(tbl)
local pairsArray = {};
for key, value in pairs(tbl) do
tInsert(pairsArray, { key = key, value = value, });
end
return pairsArray;
end
function SwapTableEntries(lhsTable, rhsTable, key)
local lhsValue = lhsTable[key];
lhsTable[key] = rhsTable[key];
rhsTable[key] = lhsValue;
end
function GetKeysArraySortedByValue(tbl)
local keysArray = GetKeysArray(tbl);
table.sort(keysArray, function(a, b)
return tbl[a] < tbl[b];
end);
return keysArray;
end
function TableUtil.OperateOnKeys(tbl, operation)
for key, value in pairs(tbl) do
operation(key);
end
end
function TableUtil.GetTableValueListFromEnumeration(tableKey, ...)
local values = {};
for enumerationKey, tbl in ... do
table.insert(values, tbl[tableKey]);
end
return values;
end
function TableUtil.GetHighestNumericalValueInTable(table)
local highestValue = nil;
for key, value in pairs(table) do
if type(value) == "number" and (not highestValue or value > highestValue) then
highestValue = value;
end
end
return highestValue;
end
--[[
This utility creates and returns a table of elements that are sorted by value "priority".
Arguments:
comparator - comparator(A, B) returns whether A has higher priority than B
isAssociative - whether the table should be associative (true) or array-like (false). Only values have priorities for associative tables, not keys.
Return usage:
t[k]/t:Get(k) - returns the value stored with key/index k
t[k] = v (Associative only) - stores the value v at key k, sorting accordingly
t:Insert(v) (Array-like only) - inserts the value v, sorting accordingly
t:Remove(k) - removes the element at key/index k
t:Iterate(cb) - calls function cb on each key/index value pair in sorted priority order. !!WARNING!! This must be used instead of pairs(t)/ipairs(t)
t:GetTop() - returns the highest priority element
t:Pop() - returns and removes the highest priority element
t:GetBottom() - returns the lowest priority element
t:Size() - returns the number of stored elements. !!WARNING!! This must be used instead of #t
t:Clear() - removes all elements
--]]
function TableUtil.CreatePriorityTable(comparator, isAssociative)
local sortedArray = {};
local ShiftPositionMap;
local keyToPosMap;
if isAssociative then
keyToPosMap = {};
ShiftPositionMap = function(position, shiftUp)
local mod = shiftUp and 1 or -1;
for k, p in pairs(keyToPosMap) do
if p >= position then
keyToPosMap[k] = p + mod;
end
end
end
end
local function SortedInsert(k, v)
if isAssociative then
local prevPos = keyToPosMap[k];
if prevPos then
tRemove(sortedArray, prevPos);
local shiftUp = false;
ShiftPositionMap(prevPos, shiftUp);
end
end
local top = (#sortedArray > 0) and (#sortedArray + 1) or 1;
local bottom = 1;
while top ~= bottom do
local mid = math.floor((top - bottom) / 2) + bottom;
if not comparator(v, sortedArray[mid]) then
bottom = mid + 1;
else
top = mid;
end
end
local idx = bottom;
tInsert(sortedArray, idx, v);
if isAssociative then
local shiftUp = true;
ShiftPositionMap(idx, shiftUp);
keyToPosMap[k] = idx;
end
end
local t = {};
function t:Get(k)
local key = isAssociative and keyToPosMap[k] or k;
return sortedArray[key];
end
if not isAssociative then
function t:Insert(v)
SortedInsert(nil, v)
end
end
function t:Remove(k)
local key = isAssociative and keyToPosMap[k] or k;
tRemove(sortedArray, key);
if isAssociative then
keyToPosMap[k] = nil;
local shiftUp = false;
ShiftPositionMap(key, shiftUp);
end
end
function t:GetTop()
return #sortedArray > 0 and sortedArray[1];
end
function t:GetBottom()
return #sortedArray > 0 and sortedArray[#sortedArray];
end
function t:Pop()
if t:Size() == 0 then
return nil;
end
local top = t:GetTop();
local removalKey = isAssociative and tInvert(keyToPosMap)[1] or 1;
t:Remove(removalKey);
return top;
end
function t:Iterate(callback)
local posToKeyMap = isAssociative and tInvert(keyToPosMap) or nil;
for pos, v in ipairs(sortedArray) do
local key = isAssociative and posToKeyMap[pos] or pos;
local done = callback(key, v);
if done then
return;
end
end
end
function t:Size()
return #sortedArray;
end
function t:Clear()
sortedArray = {};
if isAssociative then
keyToPosMap = {};
end
end
local mt =
{
__index = function(t, k)
return t:Get(k);
end,
};
if isAssociative then
mt.__newindex = function(t, k, v)
if v ~= nil then
SortedInsert(k, v);
else
t:Remove(k);
end
end
else
mt.__newindex = function(t, k, v)
error("Attempted to assign a value to an array-like priority queue index. Use Insert()/Remove() instead.")
end
end
setmetatable(t, mt);
return t;
end
function DeepMergeTable(destination, source)
for k, v in pairs(source) do
if type(v) == "table" then
if type(destination[k]) == "table" then
DeepMergeTable(destination[k], v)
else
destination[k] = CopyTable(v)
end
else
destination[k] = v
end
end
end
@@ -0,0 +1,850 @@
local ADVENTURE_TYPE = {
PRIMARY = 1,
SECONDARY = 2,
}
local ADVENTURE_CATEGORY = {
DEV = 0,
NOVICE_TIPS = 1,
WINTERGRASP = 2,
CATEGORY_BOSSES = 3,
SPEC_INFO = 4,
QUEST_DAILY_CRYSTALS = 5,
BATTLE_PASS_QUEST_DAILY = 6,
QUEST_RENEGADE = 7,
QUEST_SIRUS = 8,
SEASONAL_EVENT = 9,
QUEST_WEEKLY_PVE = 10,
BRAWL = 11,
BATTLE_PASS_QUEST_WEEKLY = 12,
RAID_NEWEST_NORMAL = 13,
RAID_NEWEST_HEROIC = 14,
WEEKEND_EVENT = 15,
QUEST_DAILY_ISLAND = 16,
ZONE_QUEST = 17,
TUTORIAL_COINS = 100,
MISC = 128,
}
local ADVENTURE_CATEGORY_PRIORITY = {
[ADVENTURE_CATEGORY.DEV] = 0,
[ADVENTURE_CATEGORY.NOVICE_TIPS] = 1,
[ADVENTURE_CATEGORY.WINTERGRASP] = 1,
[ADVENTURE_CATEGORY.CATEGORY_BOSSES] = 1,
[ADVENTURE_CATEGORY.SPEC_INFO] = 3,
[ADVENTURE_CATEGORY.QUEST_DAILY_CRYSTALS] = 1,
[ADVENTURE_CATEGORY.BATTLE_PASS_QUEST_DAILY] = 2,
[ADVENTURE_CATEGORY.QUEST_RENEGADE] = 2,
[ADVENTURE_CATEGORY.QUEST_SIRUS] = 2,
[ADVENTURE_CATEGORY.SEASONAL_EVENT] = 2,
[ADVENTURE_CATEGORY.QUEST_WEEKLY_PVE] = 2,
[ADVENTURE_CATEGORY.BRAWL] = 2,
[ADVENTURE_CATEGORY.BATTLE_PASS_QUEST_WEEKLY] = 5,
[ADVENTURE_CATEGORY.RAID_NEWEST_NORMAL] = 2,
[ADVENTURE_CATEGORY.RAID_NEWEST_HEROIC] = 2,
[ADVENTURE_CATEGORY.WEEKEND_EVENT] = 4,
[ADVENTURE_CATEGORY.QUEST_DAILY_ISLAND] = 5,
[ADVENTURE_CATEGORY.ZONE_QUEST] = 5,
[ADVENTURE_CATEGORY.TUTORIAL_COINS] = 6,
[ADVENTURE_CATEGORY.MISC] = 5,
}
local CONDITION_CHECK = {
PLAYER_IN_GM_MODE = 0,
PLAYER_FACTION = 1,
PLAYER_LEVEL = 2,
PLAYER_HAS_BUFF = 3,
PLAYER_HAS_DEBUFF = 4,
PLAYER_HAS_ITEM = 5,
PLAYER_SPELL_KNOWN = 6,
PET_SPELL_KNOWN = 7,
REALM_STAGE = 8,
REALM_DUNGEON_ACTUAL = 9,
REALM_GAME_EVENT_ACTIVE = 10,
PLAYER_QUEST_COMPLETE = 11,
PLAYER_ACHIEVEMENT_COMPLETE = 12,
PLAYER_BATTLEPASS_DAILY_COUNT = 13,
PLAYER_BATTLEPASS_WEEKLY_COUNT = 14,
REALM_WINTERGRASP_REGISTRATION_ACTIVE = 15,
REALM_BRAWL_ACTIVE = 16,
PLAYER_LFG_DUNGEON_JOINABLE = 17,
PLAYER_LFG_MINIGAME_JOINABLE = 18,
PLAYER_CUSTOM_VALUE = 19,
PLAYER_HAS_QUEST_IN_QUESTLOG = 20,
PLAYER_TALENT_GROUPS_COUNT = 21,
REALM_ID = 22,
PLAYER_IN_CHALLENGE_MODE = 23,
}
local CONDITION_OPERATOR = {
COMP_TYPE_EQ = 0,
COMP_TYPE_HIGH = 1,
COMP_TYPE_LOW = 2,
COMP_TYPE_HIGH_EQ = 3,
COMP_TYPE_LOW_EQ = 4,
}
local ACTION_BUTTON_TYPE = {
NONE = 0,
QUEST_START = 1,
UI_PVP_ARENA_RATING = 2,
UI_PVP_HONOR_RANDOM = 3,
UI_PVP_HONOR_WINTERGRASP = 4,
UI_PVP_HONOR_BRAWL = 5,
UI_PVE_LFG_DUNGEON_RANDOM = 6,
UI_PVE_LFG_DUNGEON_ID = 7,
UI_PVE_LFG_MINIGAME_ID = 8,
UI_EJ_DUNGEON_ID = 9,
UI_BATTLEPASS_QUESTS = 10,
UI_HEAD_HUNTING = 11,
}
local error = error
local ipairs = ipairs
local pairs = pairs
local select = select
local tonumber = tonumber
local type = type
local mathmax, mathmin, mathrandom = math.max, math.min, math.random
local strconcat, strformat, strgsub = strconcat, string.format, string.gsub
local tinsert, tsort, twipe, tCompare = table.insert, table.sort, table.wipe, tCompare
local CanQueueForWintergrasp = CanQueueForWintergrasp
local GetAchievementInfo = GetAchievementInfo
local GetFramerate = GetFramerate
local GetItemCount = GetItemCount
local GetQuestLinkByID = GetQuestLinkByID
local GetSpellInfo = GetSpellInfo
local GetTitleForQuestID = GetTitleForQuestID
local IsLFGDungeonJoinable = IsLFGDungeonJoinable
local IsQuestCompleted = IsQuestCompleted
local IsQuestDataCached = IsQuestDataCached
local IsSpellKnown = IsSpellKnown
local QueryQuestStart = QueryQuestStart
local UnitFactionGroup = UnitFactionGroup
local UnitLevel = UnitLevel
local debugprofilestop = debugprofilestop
local FireCustomClientEvent = FireCustomClientEvent
local GetCurrentBrawlID = C_PvP.GetCurrentBrawlID
local IsGameEventActive = IsGameEventActive
local IsGMAccount = IsGMAccount
local IsInterfaceDevClient = IsInterfaceDevClient
--local RequestQuestCacheByID = RequestQuestCacheByID
local AJ_ACTION_TEXT_JOIN_BATTLE = AJ_ACTION_TEXT_JOIN_BATTLE
local AJ_ACTION_TEXT_JOIN_GROUP = AJ_ACTION_TEXT_JOIN_GROUP
local AJ_ACTION_TEXT_OPEN_EJ = AJ_ACTION_TEXT_OPEN_EJ
local AJ_ACTION_TEXT_SHOW_QUEST = AJ_ACTION_TEXT_SHOW_QUEST
local AJ_ACTION_TEXT_START_HUNT = AJ_ACTION_TEXT_START_HUNT
local AJ_ACTION_TEXT_START_QUEST = AJ_ACTION_TEXT_START_QUEST
local AJ_PRIMARY_REWARD_TEXT = AJ_PRIMARY_REWARD_TEXT
local UNKNOWN = UNKNOWN
local COLOR_PATTERN = strformat("^|cff%s|H", string.rep("[0-9A-Fa-f]", 6))
local QUESTION_MARK_ICON = strgsub(QUESTION_MARK_ICON, "%.BLP$", "")
local NUM_SECONDARY_SUGGESTIONS = 2
local MAX_INT = 2^32/2-1
local PRIVATE = {
DIRTY = true,
FRAMETIME_TARGET = 1 / 55,
FRAMETIME_AVAILABLE = 8,
FRAMETIME_RESERVE = 4,
REGISTRY = {},
SUGGESTIONS = {},
PRIMARY_OFFSET_INDEX = 1,
}
PRIVATE.eventHandler = CreateFrame("Frame")
PRIVATE.eventHandler:Hide()
PRIVATE.eventHandler:SetScript("OnUpdate", function(self, elapsed)
local frametimeStep = PRIVATE.FRAMETIME_TARGET - elapsed
if frametimeStep ~= 0 then
frametimeStep = frametimeStep * 1000
PRIVATE.FRAMETIME_AVAILABLE = mathmax(5, PRIVATE.FRAMETIME_AVAILABLE + frametimeStep)
end
if PRIVATE.BUILD_COROUTINE then
PRIVATE.BUILD_COROUTINE_TIMESTAMP = debugprofilestop()
local status, result, progress = coroutine.resume(PRIVATE.BUILD_COROUTINE)
if not status then
PRIVATE.BUILD_COROUTINE = nil
self:Hide()
error(result, 2)
elseif not result then
if PRIVATE.BUILD_COROUTINE_DEBUG then print("AJ_BUILD_COROUTINE", progress) end
else
PRIVATE.BUILD_COROUTINE = nil
self:Hide()
end
else
self:Hide()
end
end)
PRIVATE.Initialize = function()
if PRIVATE.initialized then
return
end
PRIVATE.initialized = true
_G.ADVENTURE_TYPE = nil
_G.ADVENTURE_CATEGORY = nil
_G.ADVENTURE_CATEGORY_PRIORITY = nil
_G.CONDITION_CHECK = nil
_G.ACTION_BUTTON_TYPE = nil
local ADVENTURE_REGISTRY = _G.ADVENTURE_REGISTRY or {}
if not IsInterfaceDevClient() then
_G.ADVENTURE_REGISTRY = nil
end
for _, adventureType in pairs(ADVENTURE_TYPE) do
PRIVATE.REGISTRY[adventureType] = {}
end
for index, entry in ipairs(ADVENTURE_REGISTRY) do
if not entry.rngPriority then
entry.rngPriority = mathrandom(1, MAX_INT)
end
if entry.content then
entry.content = strgsub(entry.content, "\\n", "\n")
end
tinsert(PRIVATE.REGISTRY[entry.type], entry)
end
for adventureType, registry in pairs(PRIVATE.REGISTRY) do
tsort(registry, PRIVATE.SortEntries)
end
end
PRIVATE.SortEntries = function(a, b)
if ADVENTURE_CATEGORY_PRIORITY[a.category] ~= ADVENTURE_CATEGORY_PRIORITY[b.category] then
return ADVENTURE_CATEGORY_PRIORITY[a.category] < ADVENTURE_CATEGORY_PRIORITY[b.category]
elseif a.rngPriority ~= b.rngPriority then
return a.rngPriority < b.rngPriority
elseif a.id ~= b.id then
return a.id < b.id
end
return false
end
PRIVATE.IsMinigameAvailable = function(minigameID)
for index = 1, C_MiniGames.GetNumGames() do
if C_MiniGames.GetGameIDFromIndex(index) == minigameID then
return true
end
end
return false
end
PRIVATE.ApplyConditionOperator = function(operator, conditionValue, value)
if operator == CONDITION_OPERATOR.COMP_TYPE_EQ then
return value == conditionValue
elseif operator == CONDITION_OPERATOR.COMP_TYPE_HIGH then
return value > conditionValue
elseif operator == CONDITION_OPERATOR.COMP_TYPE_LOW then
return value < conditionValue
elseif operator == CONDITION_OPERATOR.COMP_TYPE_HIGH_EQ then
return value >= conditionValue
elseif operator == CONDITION_OPERATOR.COMP_TYPE_LOW_EQ then
return value <= conditionValue
else
return false
end
end
PRIVATE.CheckCondition = function(entry, conditionType, conditionValue, operator, invert)
local isComplete = false
if conditionType == CONDITION_CHECK.PLAYER_QUEST_COMPLETE then
isComplete = IsQuestCompleted(conditionValue)
elseif conditionType == CONDITION_CHECK.PLAYER_HAS_QUEST_IN_QUESTLOG then
isComplete = GetQuestLogIndexByID(conditionValue) ~= nil
elseif conditionType == CONDITION_CHECK.PLAYER_ACHIEVEMENT_COMPLETE then
isComplete = select(4, GetAchievementInfo(conditionValue))
elseif conditionType == CONDITION_CHECK.PLAYER_BATTLEPASS_DAILY_COUNT then
isComplete = PRIVATE.ApplyConditionOperator(operator or CONDITION_OPERATOR.COMP_TYPE_HIGH_EQ, conditionValue, C_BattlePass.GetNumQuests(Enum.BattlePass.QuestType.Daily))
elseif conditionType == CONDITION_CHECK.PLAYER_BATTLEPASS_WEEKLY_COUNT then
isComplete = PRIVATE.ApplyConditionOperator(operator or CONDITION_OPERATOR.COMP_TYPE_HIGH_EQ, conditionValue, C_BattlePass.GetNumQuests(Enum.BattlePass.QuestType.Weekly))
elseif conditionType == CONDITION_CHECK.REALM_STAGE then
isComplete = PRIVATE.ApplyConditionOperator(operator or CONDITION_OPERATOR.COMP_TYPE_HIGH_EQ, conditionValue, C_Service.GetRealmStage())
elseif conditionType == CONDITION_CHECK.PLAYER_LEVEL then
isComplete = PRIVATE.ApplyConditionOperator(operator or CONDITION_OPERATOR.COMP_TYPE_HIGH_EQ, conditionValue, UnitLevel("player"))
elseif conditionType == CONDITION_CHECK.PLAYER_FACTION then
isComplete = PRIVATE.ApplyConditionOperator(operator or CONDITION_OPERATOR.COMP_TYPE_EQ, conditionValue, SERVER_PLAYER_FACTION_GROUP[UnitFactionGroup("player")])
elseif conditionType == CONDITION_CHECK.PLAYER_CUSTOM_VALUE then
isComplete = PRIVATE.ApplyConditionOperator(operator or CONDITION_OPERATOR.COMP_TYPE_HIGH, 0, C_Service.GetCustomValue(conditionValue) or 0)
elseif conditionType == CONDITION_CHECK.PLAYER_TALENT_GROUPS_COUNT then
isComplete = PRIVATE.ApplyConditionOperator(operator or CONDITION_OPERATOR.COMP_TYPE_HIGH, conditionValue, C_Talent.GetNumTalentGroups() or 1)
elseif conditionType == CONDITION_CHECK.PLAYER_HAS_ITEM then
isComplete = GetItemCount(conditionValue) > 0
elseif conditionType == CONDITION_CHECK.PLAYER_HAS_BUFF then
isComplete = C_Unit.FindAuraBySpell("player", conditionValue, "HELPFUL") ~= nil
elseif conditionType == CONDITION_CHECK.PLAYER_HAS_DEBUFF then
isComplete = C_Unit.FindAuraBySpell("player", conditionValue, "HARMFUL") ~= nil
elseif conditionType == CONDITION_CHECK.PLAYER_SPELL_KNOWN then
isComplete = IsSpellKnown(conditionValue, false)
elseif conditionType == CONDITION_CHECK.PET_SPELL_KNOWN then
isComplete = IsSpellKnown(conditionValue, true)
elseif conditionType == CONDITION_CHECK.REALM_ID then
isComplete = C_Service.GetRealmID() == conditionValue
elseif conditionType == CONDITION_CHECK.REALM_GAME_EVENT_ACTIVE then
isComplete = IsGameEventActive(conditionValue)
elseif conditionType == CONDITION_CHECK.REALM_BRAWL_ACTIVE then
isComplete = GetCurrentBrawlID() == conditionValue
elseif conditionType == CONDITION_CHECK.REALM_WINTERGRASP_REGISTRATION_ACTIVE then
isComplete = CanQueueForWintergrasp() ~= nil
elseif conditionType == CONDITION_CHECK.PLAYER_LFG_DUNGEON_JOINABLE then
isComplete = conditionValue ~= 0 and IsLFGDungeonJoinable(conditionValue)
elseif conditionType == CONDITION_CHECK.PLAYER_LFG_MINIGAME_JOINABLE then
isComplete = conditionValue ~= 0 and PRIVATE.IsMinigameAvailable(conditionValue)
elseif conditionType == CONDITION_CHECK.REALM_DUNGEON_ACTUAL then
isComplete = C_EncounterJournal.IsActualInstance(conditionValue, entry.ej_difficultyID)
elseif conditionType == CONDITION_CHECK.PLAYER_IN_CHALLENGE_MODE then
isComplete = (C_Hardcore.GetActiveChallengeID() or 0) == conditionValue
elseif conditionType == CONDITION_CHECK.PLAYER_IN_GM_MODE then
isComplete = C_Service.IsInGMMode()
else -- unhandled condition
return false
end
if (not invert and isComplete)
or (invert and not isComplete)
then
return true
end
return false
end
PRIVATE.CheckConditions = function(entry)
for index, condition in ipairs(entry.conditions) do
local isComplete = PRIVATE.CheckCondition(entry, condition.type, condition.value, condition.operator, condition.invert)
if not isComplete then
--[[
if condition.altID then
if type(condition.altID) == "table" then
for idIndex, conditionAltID in ipairs(condition.altID) do
isComplete = PRIVATE.CheckCondition(entry, condition.type, conditionAltID, condition.operator, condition.invert)
if isComplete then
break
end
end
else
isComplete = PRIVATE.CheckCondition(entry, condition.type, condition.altID, condition.operator, condition.invert)
end
if not isComplete then
return false
end
else
return false
end
--]]
return false
end
end
return true
end
PRIVATE.UpdateSuggestionsCoroutine = function(isLevelUp)
local oldIDs = PRIVATE.GetUniqueSuggestionIDs()
local numEntries = 0
local processedEntries = 0
for adventureType, registry in ipairs(PRIVATE.REGISTRY) do
numEntries = numEntries + #registry
end
do -- Build Suggestions
twipe(PRIVATE.SUGGESTIONS)
local numPrimary = 0
local numSecondary = 0
for adventureType, registry in ipairs(PRIVATE.REGISTRY) do
local isPrimary = adventureType == ADVENTURE_TYPE.PRIMARY
PRIVATE.SUGGESTIONS[adventureType] = {}
for index, entry in ipairs(registry) do
processedEntries = processedEntries + 1
if PRIVATE.CheckConditions(entry) then
if isPrimary then
numPrimary = numPrimary + 1
tinsert(PRIVATE.SUGGESTIONS[adventureType], entry)
else
if numSecondary >= NUM_SECONDARY_SUGGESTIONS or numPrimary == 0 then
numPrimary = numPrimary + 1
tinsert(PRIVATE.SUGGESTIONS[ADVENTURE_TYPE.PRIMARY], entry)
else
numSecondary = numSecondary + 1
tinsert(PRIVATE.SUGGESTIONS[adventureType], entry)
end
end
end
if (debugprofilestop() - PRIVATE.BUILD_COROUTINE_TIMESTAMP) > PRIVATE.FRAMETIME_BUDGET then
coroutine.yield(false, processedEntries / numEntries)
end
end
end
end
local newIDs = PRIVATE.GetUniqueSuggestionIDs()
local newAdventureNotice = tCompare(oldIDs, newIDs, 2)
local offsetFound
do -- try to select previously displayed primary suggestion
if PRIVATE.PRIMARY_OFFSET_ID then
local suggestion, offsetIndex = PRIVATE.GetSuggestionEntryByID(ADVENTURE_TYPE.PRIMARY, PRIVATE.PRIMARY_OFFSET_ID)
if suggestion then
PRIVATE.PRIMARY_OFFSET_INDEX = offsetIndex
PRIVATE.PRIMARY_OFFSET_ID = suggestion.id
offsetFound = true
end
end
if not offsetFound then
local suggestion = PRIVATE.GetSuggestionEntry(ADVENTURE_TYPE.PRIMARY, 1)
if suggestion then
PRIVATE.PRIMARY_OFFSET_ID = suggestion.id
else
PRIVATE.PRIMARY_OFFSET_ID = nil
end
PRIVATE.PRIMARY_OFFSET_INDEX = 1
end
end
FireCustomClientEvent("AJ_REFRESH_DISPLAY", newAdventureNotice)
return true, 1
end
PRIVATE.UpdateSuggestions = function(isLevelUp)
if PRIVATE.BUILD_COROUTINE then
return
end
local framerate = GetFramerate()
PRIVATE.FRAMETIME_TARGET = framerate > 63 and (1 / 60) or (1 / 55)
PRIVATE.FRAMETIME_BUDGET = 1000 / framerate - PRIVATE.FRAMETIME_RESERVE
PRIVATE.BUILD_COROUTINE = coroutine.create(PRIVATE.UpdateSuggestionsCoroutine)
PRIVATE.BUILD_COROUTINE_TIMESTAMP = debugprofilestop()
local status, result, progress = coroutine.resume(PRIVATE.BUILD_COROUTINE, isLevelUp)
if not status then
PRIVATE.BUILD_COROUTINE = nil
PRIVATE.eventHandler:Hide()
error(result, 2)
end
if coroutine.status(PRIVATE.BUILD_COROUTINE) == "dead" then
PRIVATE.BUILD_COROUTINE = nil
else
if PRIVATE.BUILD_COROUTINE_DEBUG then print("AJ_BUILD_COROUTINE", progress) end
PRIVATE.eventHandler:Show()
end
end
PRIVATE.GetNumPrimarySuggestions = function()
if PRIVATE.SUGGESTIONS[ADVENTURE_TYPE.PRIMARY] then
return #PRIVATE.SUGGESTIONS[ADVENTURE_TYPE.PRIMARY]
end
return 0
end
PRIVATE.GetNumSecondarySuggestions = function()
if PRIVATE.SUGGESTIONS[ADVENTURE_TYPE.SECONDARY] then
return #PRIVATE.SUGGESTIONS[ADVENTURE_TYPE.SECONDARY]
end
return 0
end
PRIVATE.GetButtonText = function(suggestion)
if suggestion.actionType == ACTION_BUTTON_TYPE.NONE then
-- skip
elseif suggestion.actionType == ACTION_BUTTON_TYPE.QUEST_START then
return AJ_ACTION_TEXT_START_QUEST
elseif suggestion.actionType == ACTION_BUTTON_TYPE.UI_PVP_ARENA_RATING
or suggestion.actionType == ACTION_BUTTON_TYPE.UI_PVP_HONOR_RANDOM
or suggestion.actionType == ACTION_BUTTON_TYPE.UI_PVP_HONOR_WINTERGRASP
or suggestion.actionType == ACTION_BUTTON_TYPE.UI_PVP_HONOR_BRAWL
then
return AJ_ACTION_TEXT_JOIN_BATTLE
elseif suggestion.actionType == ACTION_BUTTON_TYPE.UI_PVE_LFG_DUNGEON_RANDOM
or suggestion.actionType == ACTION_BUTTON_TYPE.UI_PVE_LFG_DUNGEON_ID
or suggestion.actionType == ACTION_BUTTON_TYPE.UI_PVE_LFG_MINIGAME_ID
then
return AJ_ACTION_TEXT_JOIN_GROUP
elseif suggestion.actionType == ACTION_BUTTON_TYPE.UI_EJ_DUNGEON_ID then
return AJ_ACTION_TEXT_OPEN_EJ
elseif suggestion.actionType == ACTION_BUTTON_TYPE.UI_BATTLEPASS_QUESTS then
return AJ_ACTION_TEXT_SHOW_QUEST
elseif suggestion.actionType == ACTION_BUTTON_TYPE.UI_HEAD_HUNTING then
return AJ_ACTION_TEXT_START_HUNT
end
end
local ACTION_TARGET_VIEW = {
[ACTION_BUTTON_TYPE.UI_PVP_ARENA_RATING] = "pvp-arena-rating",
[ACTION_BUTTON_TYPE.UI_PVP_HONOR_RANDOM] = "pvp-honor-random",
[ACTION_BUTTON_TYPE.UI_PVP_HONOR_WINTERGRASP] = "pvp-honor-wintergrasp",
[ACTION_BUTTON_TYPE.UI_PVP_HONOR_BRAWL] = "pvp-honor-brawl",
[ACTION_BUTTON_TYPE.UI_PVE_LFG_DUNGEON_RANDOM] = "pve-lfg-dungeon",
[ACTION_BUTTON_TYPE.UI_PVE_LFG_DUNGEON_ID] = "pve-lfg-dungeon",
[ACTION_BUTTON_TYPE.UI_PVE_LFG_MINIGAME_ID] = "pve-lfg-minigame",
}
PRIVATE.ActivateEntry = function(suggestion)
if suggestion.actionType == ACTION_BUTTON_TYPE.NONE then
-- skip
elseif suggestion.actionType == ACTION_BUTTON_TYPE.QUEST_START then
local questID = suggestion.actionParam
if questID then
QueryQuestStart(questID, Enum.QueryQuestStartSource.Suggestion, suggestion.id)
-- FireCustomClientEvent("AJ_QUEST_LOG_OPEN", questID or 0, uiMapID or 0)
else
GMError(string.format("[Suggestion::ActivateEntry] no quest id to start [suggestionID=%d]", suggestion.id))
end
elseif suggestion.actionType == ACTION_BUTTON_TYPE.UI_PVP_ARENA_RATING
or suggestion.actionType == ACTION_BUTTON_TYPE.UI_PVP_HONOR_RANDOM
or suggestion.actionType == ACTION_BUTTON_TYPE.UI_PVP_HONOR_WINTERGRASP
or suggestion.actionType == ACTION_BUTTON_TYPE.UI_PVP_HONOR_BRAWL
then
local desiredViewType = ACTION_TARGET_VIEW[suggestion.actionType]
FireCustomClientEvent("AJ_ACTION_PVP_LFG", desiredViewType)
elseif suggestion.actionType == ACTION_BUTTON_TYPE.UI_PVE_LFG_DUNGEON_RANDOM then
for i, lfgDungeonID in ipairs({258, 259, 261}) do
if IsLFGDungeonJoinable(lfgDungeonID) then
local desiredViewType = ACTION_TARGET_VIEW[suggestion.actionType]
FireCustomClientEvent("AJ_ACTION_PVE_LFG", desiredViewType, lfgDungeonID)
return
end
end
elseif suggestion.actionType == ACTION_BUTTON_TYPE.UI_PVE_LFG_DUNGEON_ID then
local desiredViewType = ACTION_TARGET_VIEW[suggestion.actionType]
local lfgDungeonID = suggestion.actionParam or 0
if IsLFGDungeonJoinable(lfgDungeonID) then
FireCustomClientEvent("AJ_ACTION_PVE_LFG", desiredViewType, lfgDungeonID)
end
elseif suggestion.actionType == ACTION_BUTTON_TYPE.UI_PVE_LFG_MINIGAME_ID then
local desiredViewType = ACTION_TARGET_VIEW[suggestion.actionType]
local minigameID = suggestion.actionParam or 0
FireCustomClientEvent("AJ_ACTION_PVE_LFG", desiredViewType, minigameID)
elseif suggestion.actionType == ACTION_BUTTON_TYPE.UI_EJ_DUNGEON_ID then
local dungeonID = suggestion.actionParam or 0
local difficultyID = suggestion.actionParam2 or -1
FireCustomClientEvent("AJ_ACTION_EJ_DUNGEON", dungeonID, difficultyID)
elseif suggestion.actionType == ACTION_BUTTON_TYPE.UI_BATTLEPASS_QUESTS then
local showQuestTab = true
FireCustomClientEvent("AJ_ACTION_BATTLE_PASS", showQuestTab)
elseif suggestion.actionType == ACTION_BUTTON_TYPE.UI_HEAD_HUNTING then
FireCustomClientEvent("AJ_ACTION_HEAD_HUNTING")
end
end
PRIVATE.GetSuggestionEntry = function(suggestionType, index)
if PRIVATE.SUGGESTIONS[suggestionType] then
return PRIVATE.SUGGESTIONS[suggestionType][index]
end
end
PRIVATE.GetSuggestionEntryByID = function(suggestionType, id)
if PRIVATE.SUGGESTIONS[suggestionType] then
for index, suggestion in ipairs(PRIVATE.SUGGESTIONS[suggestionType]) do
if suggestion.id == id then
return suggestion, index
end
end
end
end
PRIVATE.OnItemLoaded = function()
FireCustomClientEvent("AJ_REWARD_DATA_RECEIVED")
end
PRIVATE.OnItemLoadedContent = function()
FireCustomClientEvent("AJ_REFRESH_DISPLAY", false)
end
PRIVATE.OnQuestLoadedContent = function(questID)
FireCustomClientEvent("AJ_REFRESH_DISPLAY", false)
end
PRIVATE.GetQuestLink = function(questID)
questID = tonumber(questID)
if IsQuestDataCached(questID) then
local questLink = GetQuestLinkByID(questID)
if questLink then
questLink = strgsub(questLink, COLOR_PATTERN, "|cff8B0000|H")
return questLink
end
else
RequestQuestCacheByID(questID, PRIVATE.OnQuestLoadedContent)
end
local name = GetTitleForQuestID(questID)
if not name then
name = IsGMAccount() and strformat("%s (quest:%s)", UNKNOWN, questID) or UNKNOWN
end
return strformat("|cff8B0000|Hquest:%d:-1|h[%s]|h|r", questID, name)
end
PRIVATE.GetItemLink = function(itemID)
itemID = tonumber(itemID)
local name, link = C_Item.GetItemInfo(itemID, nil, PRIVATE.OnItemLoadedContent, true)
if not link then
name = IsGMAccount() and strformat("%s (item:%s)", UNKNOWN, itemID) or UNKNOWN
return strformat("|cffffffff[%s]|r", name)
end
return link
end
PRIVATE.GetSpellLink = function(spellID)
spellID = tonumber(spellID)
local name = GetSpellInfo(spellID)
if not name then
name = IsGMAccount() and strformat("%s (spell:%s)", UNKNOWN, spellID) or UNKNOWN
return strformat("|cffffffff[%s]|r", name)
end
return strformat("|cff000080|Hspell:%d|h[%s]|h|r", spellID, name)
end
PRIVATE.GetSuggestionInfo = function(suggestionType, index)
local suggestion = PRIVATE.GetSuggestionEntry(suggestionType, index)
if suggestion then
local description = suggestion.content
if description then
description = strgsub(description, "{quest:(%d+)}", PRIVATE.GetQuestLink)
description = strgsub(description, "{item:(%d+)}", PRIVATE.GetItemLink)
description = strgsub(description, "{spell:(%d+)}", PRIVATE.GetSpellLink)
end
return {
title = suggestion.title,
description = description,
buttonText = PRIVATE.GetButtonText(suggestion),
iconPath = suggestion.icon and strconcat([[Interface\Icons\]], suggestion.icon) or QUESTION_MARK_ICON,
ej_instanceID = suggestion.ej_instanceID,
difficultyID = suggestion.ej_difficultyID or 1,
expansionLevel = suggestion.ej_expansionLevel,
isRandomDungeon = suggestion.ej_isRandomDungeon,
hideDifficulty = suggestion.ej_showDifficulty ~= 1,
}
end
end
PRIVATE.GetSuggestionByIndex = function(suggestionIndex)
if suggestionIndex <= 1 then
return PRIVATE.GetSuggestionEntry(ADVENTURE_TYPE.PRIMARY, PRIVATE.PRIMARY_OFFSET_INDEX)
else
return PRIVATE.GetSuggestionEntry(ADVENTURE_TYPE.SECONDARY, suggestionIndex - 1)
end
end
PRIVATE.GetReward = function(suggestion)
if not suggestion then
return
end
local numRewards = #suggestion.rewards
if numRewards > 0 then
if numRewards == 1 and suggestion.rewardDesc then
local itemName, itemLink, itemRarity, iLevel, itemMinLevel, itemType, itemSubType, itemStackCount, itemEquipLoc, itemTexture, vendorPrice = C_Item.GetItemInfo(suggestion.rewards[1], nil, PRIVATE.OnItemLoaded, true)
local rewardDesc = type(suggestion.rewardDesc) == "string" and suggestion.rewardDesc or AJ_PRIMARY_REWARD_TEXT
return {
isRewardTable = false,
rewardDesc = rewardDesc,
itemLink = itemLink,
itemIcon = itemTexture,
itemQuantity = 1,
}
else
local rewards = {}
for index, itemID in ipairs(suggestion.rewards) do
local itemName, itemLink, itemRarity, iLevel, itemMinLevel, itemType, itemSubType, itemStackCount, itemEquipLoc, itemTexture, vendorPrice = C_Item.GetItemInfo(suggestion.rewards[index], nil, PRIVATE.OnItemLoaded, true)
if itemLink then
tinsert(rewards, {
itemLink = itemLink,
itemIcon = itemTexture,
itemQuantity = 1,
})
end
end
if #rewards > 0 then
rewards.isRewardList = true
return rewards
end
end
elseif false then -- currency item
return {
isRewardTable = false,
rewardDesc = AJ_PRIMARY_REWARD_TEXT,
currencyIcon = nil,
currencyQuantity = nil,
currencyIcon = nil,
}
else
local minItemLevel = suggestion.reward_minItemLevel
local maxItemLevel = suggestion.reward_maxItemLevel
local itemLevel = suggestion.reward_itemLevel
if itemLevel or minItemLevel or maxItemLevel then
if itemLevel then
minItemLevel = nil
maxItemLevel = nil
elseif not minItemLevel or not maxItemLevel then
minItemLevel = nil
maxItemLevel = nil
itemLevel = minItemLevel or maxItemLevel
end
return {
isRewardTable = true,
itemLevel = itemLevel,
minItemLevel = minItemLevel,
maxItemLevel = maxItemLevel,
}
end
end
end
PRIVATE.GetUniqueSuggestionIDs = function()
local suggestionIDs = {}
for adventureType, registry in ipairs(PRIVATE.REGISTRY) do
suggestionIDs[adventureType] = {}
for index, entry in ipairs(registry) do
suggestionIDs[adventureType][entry.id] = true
end
end
return suggestionIDs
end
do
if IsInterfaceDevClient() then
PRIVATE.BUILD_COROUTINE_DEBUG = true
PRIVATE_AJ = PRIVATE
end
PRIVATE.Initialize()
end
C_AdventureJournal = {}
function C_AdventureJournal.ReloadData()
if IsInterfaceDevClient() then
if _G.ADVENTURE_REGISTRY and PRIVATE.initialized then
PRIVATE.initialized = nil
twipe(PRIVATE.REGISTRY)
PRIVATE.Initialize()
end
end
end
function C_AdventureJournal.CanBeShown()
return true
end
function C_AdventureJournal.UpdateSuggestions(isLevelUp)
PRIVATE.UpdateSuggestions(not not isLevelUp)
end
function C_AdventureJournal.SetPrimaryOffset(offset)
if type(offset) ~= "number" then
error(strformat("bad argument #1 to 'C_AdventureJournal.SetPrimaryOffset' (number expected, got %s)", offset ~= nil and type(offset) or "no value"), 2)
end
offset = offset + 1
if offset < 1 or offset > PRIVATE.GetNumPrimarySuggestions() then
error(strformat("bad argument #1 to 'C_AdventureJournal.SetPrimaryOffset' (index %s out of range [1 - %s])", offset, PRIVATE.GetNumPrimarySuggestions()), 2)
end
if offset == PRIVATE.PRIMARY_OFFSET_INDEX then
return
end
local suggestion = PRIVATE.GetSuggestionEntry(ADVENTURE_TYPE.PRIMARY, offset)
if suggestion then
PRIVATE.PRIMARY_OFFSET_INDEX = offset
PRIVATE.PRIMARY_OFFSET_ID = suggestion.id
FireCustomClientEvent("AJ_REFRESH_DISPLAY", false)
end
end
function C_AdventureJournal.GetPrimaryOffset()
return PRIVATE.PRIMARY_OFFSET_INDEX - 1
end
function C_AdventureJournal.GetNumAvailableSuggestions()
return PRIVATE.GetNumPrimarySuggestions()
end
function C_AdventureJournal.GetSuggestions(suggestionTable)
if type(suggestionTable) ~= "table" then
error(strformat("bad argument #1 to 'C_AdventureJournal.GetSuggestions' (table expected, got %s)", suggestionTable ~= nil and type(suggestionTable) or "no value"), 2)
end
twipe(suggestionTable)
if PRIVATE.GetNumPrimarySuggestions() > 0 then
local suggestion = PRIVATE.GetSuggestionInfo(ADVENTURE_TYPE.PRIMARY, PRIVATE.PRIMARY_OFFSET_INDEX)
if suggestion then
tinsert(suggestionTable, suggestion)
end
end
for index = 1, mathmin(NUM_SECONDARY_SUGGESTIONS, PRIVATE.GetNumSecondarySuggestions()) do
local suggestion = PRIVATE.GetSuggestionInfo(ADVENTURE_TYPE.SECONDARY, index)
if suggestion then
tinsert(suggestionTable, suggestion)
end
end
end
function C_AdventureJournal.GetReward(suggestionIndex)
if type(suggestionIndex) ~= "number" then
error(strformat("bad argument #1 to 'C_AdventureJournal.GetReward' (number expected, got %s)", suggestionIndex ~= nil and type(suggestionIndex) or "no value"), 2)
elseif suggestionIndex < 1 or suggestionIndex > NUM_SECONDARY_SUGGESTIONS + 1 then
error(strformat("bad argument #1 to 'C_AdventureJournal.GetReward' (index %s out of range [1 - %s])", suggestionIndex, NUM_SECONDARY_SUGGESTIONS + 1), 2)
end
return PRIVATE.GetReward(PRIVATE.GetSuggestionByIndex(suggestionIndex))
end
function C_AdventureJournal.ActivateEntry(suggestionIndex)
if type(suggestionIndex) ~= "number" then
error(strformat("bad argument #1 to 'C_AdventureJournal.ActivateEntry' (number expected, got %s)", suggestionIndex ~= nil and type(suggestionIndex) or "no value"), 2)
elseif suggestionIndex < 1 or suggestionIndex > NUM_SECONDARY_SUGGESTIONS + 1 then
error(strformat("bad argument #1 to 'C_AdventureJournal.ActivateEntry' (index %s out of range [1 - %s])", suggestionIndex, NUM_SECONDARY_SUGGESTIONS + 1), 2)
end
local suggestion = PRIVATE.GetSuggestionByIndex(suggestionIndex)
if suggestion then
PRIVATE.ActivateEntry(suggestion)
end
end
@@ -9,3 +9,34 @@
## X-Hidden: 1 ## X-Hidden: 1
MoonWellClient.lua MoonWellClient.lua
EncounterJournal\SharedXML\ClientDataGenerated\Generated_ItemsCache1.lua
EncounterJournal\SharedXML\ClientDataGenerated\Generated_ItemsCache2.lua
EncounterJournal\SharedXML\ClientDataGenerated\Generated_ItemsCache3.lua
EncounterJournal\EncounterJournalCompat.lua
EncounterJournal\SharedXML\Pools.lua
EncounterJournal\SharedXML\TableUtil.lua
EncounterJournal\SharedXML\SoundKitConstants.lua
EncounterJournal\EncounterJournalData.lua
EncounterJournal\Generated_EncounterJournal.lua
EncounterJournal\EncounterJournalTierFilter.lua
EncounterJournal\EncounterJournalTierSnapshot.lua
EncounterJournal\GlobalStrings.lua
EncounterJournal\Utils\C_EncounterJournal.lua
EncounterJournal\Utils\C_AdventureJournal.lua
EncounterJournal\EncounterJournalInit.lua
EncounterJournal\EncounterJournalFrameMethods.lua
EncounterJournal\EncounterJournalFonts.xml
EncounterJournal\SharedXML\SharedTooltipTemplates.xml
EncounterJournal\SharedXML\TableBuilder.lua
EncounterJournal\SharedXML\EventHandler.lua
EncounterJournal\SharedXML\SharedUIPanelTemplates.xml
EncounterJournal\SharedXML\SharedUIPanelPKBTTemplates.xml
EncounterJournal\SharedXML\HybridScrollFrame.xml
EncounterJournal\SharedXML\NavigationBar.xml
EncounterJournal\Custom_EncounterJournal\Custom_EncounterJournal.lua
EncounterJournal\Custom_EncounterJournal\Custom_EncounterJournal.xml
EncounterJournal\Custom_EncounterJournal\Custom_LootJournalItems.xml
EncounterJournal\Custom_EncounterJournal\Custom_ItemBrowser.xml
EncounterJournal\EncounterJournalScrollFix.lua
EncounterJournal\EncounterJournalDungeonMode.lua
EncounterJournal\EncounterJournalOpen.lua

Some files were not shown because too many files have changed in this diff Show More