WoWInterface

WoWInterface (https://www.wowinterface.com/forums/index.php)
-   Lua/XML Help (https://www.wowinterface.com/forums/forumdisplay.php?f=16)
-   -   Same background for multiple frames? (https://www.wowinterface.com/forums/showthread.php?t=54158)

Ravenevar 08-08-16 01:09 AM

Same background for multiple frames?
 
Hi there,

I've been using the same code to place the same background on different frames in my UI. It works fine but I'd like to figure out a more efficient way.

For example, on my PlayerFrame (courtesy of LynMinimap) I might have the following code:

Code:

        local bg = CreateFrame('Frame', nil, PlayerFrame)
        bg:SetPoint('TOPLEFT', PlayerFrame, 0, -26)
        bg:SetPoint('BOTTOMRIGHT', PlayerFrame, 0, 26)
        bg:SetBackdrop({
                bgFile = [[Interface/Buttons/WHITE8X8]],
                tiled = false,
                insets = {left = -3, right = -2, top = -3, bottom = -3}
        })
        bg:SetBackdropColor(0, 0, 0, 1)
        bg:SetFrameLevel(0)
       
        local trans = CreateFrame('Frame', nil, PlayerFrame)
        trans:SetBackdrop({
                        bgFile = [[Interface\Tooltips\UI-Tooltip-Background]],
                        tiled = false,
                        insets = {left = -6, right = -5, top = -6, bottom = -6}
        })
        trans:SetPoint('TOPLEFT', PlayerFrame, 0, -26)
        trans:SetPoint('BOTTOMRIGHT', PlayerFrame, 0, 26)
        trans:SetFrameLevel(0)
        trans:SetFrameStrata('BACKGROUND')
        trans:SetBackdropColor(0, 0, 0, 0.6)

Now I want to use this same background for my TargetFrame. Currently I have just copy/pasted the above code and replaced PlayerFrame with TargetFrame and it works, but now I have double the code. Is there a way I can do it more efficiently? Looking at other addons I have tried using "for _,frame in next" and "for index,value in ipairs" but I can't seem to make them work.

Any help is greatly appreciated!

myrroddin 08-08-16 01:56 AM

Create a wrapper function that passes a variable, in this case, your intended frame. You can also combine lines 2 & 3.
Code:

local player_frame = MyAddOn:SkinFrame(PlayerFrame)
local target_frame = MyAddOn:SkinFrame(TargetFrame)

function MyAddOn:SkinFrame(frame)
    local bg = CreateFrame('Frame', nil, frame)
    bg:SetPoint('TOPLEFT', frame, "BOTTOMRIGHT", 0, -26)
    -- do the rest of your code here
    return frame -- returns your skinned frame
end


Vlad 08-08-16 01:57 AM

You are already on the right track, spotting the fact the code is the same except in a very few locations. So fixing this shouldn't be hard. We first wrap this in a function, then we give that function an argument we call "parentFrame", then we can easily call the same code as many times as we like, and just provide it with a new frame to work with and do the exact operations.

Code:

local function SkinFrame(parentFrame)
        local bg = CreateFrame('Frame', nil, parentFrame)
        bg:SetPoint('TOPLEFT', parentFrame, 0, -26)
        bg:SetPoint('BOTTOMRIGHT', parentFrame, 0, 26)
        bg:SetBackdrop({
                bgFile = [[Interface/Buttons/WHITE8X8]],
                tiled = false,
                insets = {left = -3, right = -2, top = -3, bottom = -3}
        })
        bg:SetBackdropColor(0, 0, 0, 1)
        bg:SetFrameLevel(0)

        local trans = CreateFrame('Frame', nil, parentFrame)
        trans:SetBackdrop({
                bgFile = [[Interface\Tooltips\UI-Tooltip-Background]],
                tiled = false,
                insets = {left = -6, right = -5, top = -6, bottom = -6}
        })
        trans:SetPoint('TOPLEFT', parentFrame, 0, -26)
        trans:SetPoint('BOTTOMRIGHT', parentFrame, 0, 26)
        trans:SetFrameLevel(0)
        trans:SetFrameStrata('BACKGROUND')
        trans:SetBackdropColor(0, 0, 0, 0.6)
end

SkinFrame(PlayerFrame)
SkinFrame(TargetFrame)

There is a final form of optimization we can do, though not a big thing considering it's ONLY used two times. Larger addons, let's say a raid frame with 80 potential units on screen, we could look at the two tables used in bg:SetBackdrop() and trans:SetBackdrop() and considering it's the same table used each time, we could make it so we just reuse the same table from memory, since the function creates a new table each time it is called.

Code:

local BG_BACKDROP = {
        bgFile = [[Interface/Buttons/WHITE8X8]],
        tiled = false,
        insets = {left = -3, right = -2, top = -3, bottom = -3}
}

local TRANS_BACKDROP = {
        bgFile = [[Interface\Tooltips\UI-Tooltip-Background]],
        tiled = false,
        insets = {left = -6, right = -5, top = -6, bottom = -6}
}

local function SkinFrame(parentFrame)
        -- <snip>
        bg:SetBackdrop(BG_BACKDROP)
        -- <snip>
        trans:SetBackdrop(TRANS_BACKDROP)
        -- <snip>
end

myrroddin was quicker and replied while I was typing this out, but I'll hit the post button regardless.

myrroddin 08-08-16 02:00 AM

Vlad, no worries. I didn't even think about reusing the texture look up more effieciently. Good catch!

Ravenevar 08-08-16 04:24 AM

Wow, thanks for the quick replies! Tried it and it works perfectly! And now I see how you guys did it, it makes perfect sense. Thanks so much!

However, I noticed that when two of the "trans" backdrops overlap, the alpha doubles and becomes darker. Is there anyway to avoid this? Let them blend smoothly?

Lastly, a side question, is there an easy way to show frames that are normally not shown, say if I wanted to put the same background on my party frames and wanted to see what it looks like? I'm no longer at my computer atm, but would it just be a case of PartyFrame1:Show() kind of deal?

Thanks again!

Vlad 08-08-16 04:46 AM

Quote:

Originally Posted by Ravenevar (Post 317618)
However, I noticed that when two of the "trans" backdrops overlap, the alpha doubles and becomes darker. Is there anyway to avoid this? Let them blend smoothly?

I don't want to say it's impossible, but I haven't seen any of my addons do something like this either.

Quote:

Originally Posted by Ravenevar (Post 317618)
Lastly, a side question, is there an easy way to show frames that are normally not shown, say if I wanted to put the same background on my party frames and wanted to see what it looks like? I'm no longer at my computer atm, but would it just be a case of PartyFrame1:Show() kind of deal?

Yes. I recommend taking a look at:
http://wowprogramming.com/docs
http://wowprogramming.com/docs/widgets/VisibleRegion

Widgets are basically special tables Blizzard created with their own metatables, often inheriting methods from parent widgets, there is a graph on the site above to illustrate the relations. Note that stuff like "PlayerFrame" are defined in the FrameXML of the game, you can find the sources online here:
https://www.townlong-yak.com/framexml/beta
https://www.townlong-yak.com/framexm...yerFrame.xml#7

You either have the widgets defined/created in the XML files, or you can find lua calling CreateFrame and specifying a widget type to create.
http://wow.gamepedia.com/API_CreateFrame

When modifying the default interface, I recommend first looking the code up and see how it works, usually you want to modify it at certain times, like events or specific function calls, and you can hooksecurefunc/HookScript accordingly and do your own stuff right after Blizzards code does its own thing. It can get a bit tricky with secure frames, if you manage to taint it, secure functions will stop working, like targeting when it comes to unit frames.

Anyway that went far out of scope of the questions you asked. Sorry.

Phanx 08-08-16 11:55 AM

Quote:

Originally Posted by Ravenevar (Post 317618)
Lastly, a side question, is there an easy way to show frames that are normally not shown, say if I wanted to put the same background on my party frames and wanted to see what it looks like? I'm no longer at my computer atm, but would it just be a case of PartyFrame1:Show() kind of deal?

For unit frames specifically, just calling :Show() on it will make it appear for about 1 frame, and then it will disappear again, because unit frames are automatically shown or hidden based on whether or not the unit they are assigned to show currently exists.

To work around this, you can temporarily set the frame to show the player unit:

Code:

PartyMemberFrame1.unit = "player"
PartyMemberFrame1:SetAttribute("unit", "player")

Just remember to re-set the unit back to the original one when you're done testing (or just reload the UI).

Here's a small addon that provides a /fakeunits command to toggle the unit on a bunch of Blizzard unit frames:

Code:

local frames = {
    "PetFrame",
    "PartyMemberFrame1",
    "PartyMemberFrame2",
    "PartyMemberFrame3",
    "PartyMemberFrame4",
    "Boss1TargetFrame",
    "Boss2TargetFrame",
    "Boss3TargetFrame",
    "Boss4TargetFrame",
    "ArenaEnemyFrame1",
    "ArenaEnemyFrame2",
    "ArenaEnemyFrame3",
    "ArenaEnemyFrame4",
}

local inFakeMode
function ToggleFakeUnits()
    if InCombatLockdown() then
        return print("Can't change frame units in combat.")
    end
    for i = 1, #frames do
        local f = _G[frames[i]]
        if inFakeMode then
            f.unit = f.__realunit
            f.__realunit = nil
            f:SetAttribute("unit", f.unit)
        else
            f.__realunit = f.unit
            f.unit = "player"
            f:SetAttribute("player")
        end
    end
    inFakeMode = not inFakeMode
end

SLASH_TOGGLEFAKEUNITS1 = "/fakeunits"
SlashCmdList.TOGGLEFAKEUNITS = ToggleFakeUnits

local ef = CreateFrame("Frame")
ef:RegisterEvent("PLAYER_REGEN_DISABLED")
ef:SetScript("OnEvent", function()
    if inFakeMode and UnitAffectingCombat("player") then
        ToggleFakeUnits()
    end
end)



All times are GMT -6. The time now is 04:33 AM.

vBulletin © 2024, Jelsoft Enterprises Ltd
© 2004 - 2022 MMOUI