WoWInterface

WoWInterface (https://www.wowinterface.com/forums/index.php)
-   Lua/XML Help (https://www.wowinterface.com/forums/forumdisplay.php?f=16)
-   -   Finding Frames of other Addons and overwriting their position (https://www.wowinterface.com/forums/showthread.php?t=57218)

Lybrial 06-22-19 06:36 AM

Finding Frames of other Addons and overwriting their position
 
Hi,

Im using several AddOns and some of them do not allow to anchor to certain frames.
So what I really would like to do is to be able to find those frames and to overwrite them.
Yet I could not find any way to do this. At first I would need to find frames by its name:

Code:

local children = { UIParent:GetChildren() }

for _, child in ipairs(children) do
    print("child: " .. child:GetName());
end

--> Does not work

Code:

local frame = EnumerateFrames();

while frame do
    print("child: " .. frame:GetName());

    frame = EnumerateFrames(frame));
end

--> Also does not work

Is there no way to iterate over all frames and to find the frame I need by its name?

Fizzlemizz 06-22-19 06:56 AM

If the frame does have a name, you should be able to type /fstack in-game and mouse over the frame. Type /fstack again to turn it off.

You might also want to install FrameStackGlobalizer

Lybrial 06-22-19 07:00 AM

Hi,

this is not what I need. I mean it is what I need to find the names BUT
I need to get a frame by its name in luca code. Not ingame. I need something like:

Code:

local frame = FindFrameByName("Grid2LayoutFrame"); -- example
frame:SetPoint("CENTER", myFrame, "CENTER, 0, 0);


Xrystal 06-22-19 07:22 AM

This code you showed, will work but it will error out if that particular child doesn't have a name
Code:

local children = { UIParent:GetChildren() }

for _, child in ipairs(children) do
    print("child: " .. child:GetName());
end

Change it to the following and see what output you get then.
Code:

local children = { UIParent:GetChildren() }

for _, child in ipairs(children) do
    local name = child:GetName()
    if name then print(name) else print("Not Named") end
end

You could then expand that as a recursive function to repeat the process for every frame... then instead of printing the name out, simply create a table of frames with a name containing the frame handle ... then you can use that table for a search by name tool.

I've not needed to do this myself but theoretically it is sound.

Lybrial 06-22-19 07:41 AM

Hi, thx for your quick reply.

Yes, the code works. But it only prints out 223 children of 398

Code:

print("amount children: " .. UIParent:GetNumChildren());
       
local children = { UIParent:GetChildren() };
       
for key, child in ipairs(children) do
        local name = child:GetName() or child:GetDebugName();
                       
        if name then
                print(key .. ": " .. name);
        else
                print(key .. ": " .. "Not Named");
        end
end

I know the names of some frames. "Grid2LayoutFrame" frame for
example is a child of UIParent. Thats what im getting with /framestack.
But this frame is not appearing in the list of frames im printing.

Btw. Not Named is never printed out. Its erroring out after 223 items.

Fizzlemizz 06-22-19 08:35 AM

Are you getting an error for trying to access a forbidden object?

Lybrial 06-22-19 08:43 AM

No, no error. Its just silently crashing. The code after the loop is also not continuing.

Code:

print("amount children: " .. UIParent:GetNumChildren());
       
local children = { UIParent:GetChildren() };
       
for key, child in ipairs(children) do
        local name = child:GetName() or child:GetDebugName();
                       
        if name then
                print(key .. ": " .. name);
        else
                print(key .. ": " .. "Not Named");
        end
end

print("done");

So in thise case after child number 223 it is silently erroring out and the done
is never getting printed.

Fizzlemizz 06-22-19 08:49 AM

Do you have BugGrabber and BugSack installed?

It shouldn't be that silent.

Fizzlemizz 06-22-19 08:53 AM

I think you need to be a bit more specific about what you are trying to anchor too or start your child search at Grid2LayoutFrame.

Lybrial 06-22-19 09:03 AM

You are right, with BugSack I get an error:

Code:

1x Lybrial_Anchors\init.lua:90: Attempt to access forbidden object from code tainted by an AddOn
[C]: in function `GetName'
Lybrial_Anchors\init.lua:90: in function <Lybrial_Anchors\init.lua:78>
[C]: ?
...aceMasque\Libs\AceAddon-3.0\AceAddon-3.0-12.lua:70: in function <...aceMasque\Libs\AceAddon-3.0\AceAddon-3.0.lua:65>
...aceMasque\Libs\AceAddon-3.0\AceAddon-3.0-12.lua:527: in function `EnableAddon'
...aceMasque\Libs\AceAddon-3.0\AceAddon-3.0-12.lua:540: in function `EnableAddon'
...aceMasque\Libs\AceAddon-3.0\AceAddon-3.0-12.lua:620: in function <...aceMasque\Libs\AceAddon-3.0\AceAddon-3.0.lua:605>
[C]: in function `LoadAddOn'
FrameXML\UIParent.lua:446: in function `UIParentLoadAddOn'
FrameXML\UIParent.lua:565: in function `TimeManager_LoadUI'
FrameXML\UIParent.lua:1192: in function <FrameXML\UIParent.lua:1090>

And to be specific with what I want to achieve:

I have created WeakAuras which are anchored to the personal player resource nameplate.
So when the nameplate moves my WeakAuras move too. I want to do this for other AddOns
too. Raven for example supports this functionality out of the box. In the options frame I can
choose an anchor. Other AddOns like Grid2 or Hekili are not providing such a functionality.

That is why I wanted to implement a small Addon which picks up the frames of some predefined
AddOns and overwrites their anchor and position on the screen.

So for example I have the Grid2LayoutFrame which is the root frame of Grid2 and a child
of UIParent. So my Idea was to iterate over all frames of the UIParent to get the
Grid2LayoutFrame and to be able to modify its attributes.

Without iterating the children of UIParent and comparing the frame names I do not see
any possiblity to access the frames that I need.

Fizzlemizz 06-22-19 10:01 AM

Grid2LayoutFrame is the name of the frame. You don't have to "find" it.

Code:

/run print(Grid2LayoutFrame)
For clarity, for any frame that has been given a name, that name (and associated frame) is stored as a global

If you are creating names from strings build from the name you can locate them in the global table
Code:

/run print(_G["Grid2LayoutFrame"])

Lybrial 06-22-19 10:06 AM

Holy moly you are right.
That makes stuff a lot easier. Thank you!

Fizzlemizz 06-22-19 10:14 AM

Makes /fstack look a whole lot more useful ;)

Xrystal 06-22-19 10:21 AM

Rofl Fizzle .. I actually do it that way but for some reason didn't equate why I do it to why he does but I do it for the same reason... I think the loop exanple confused me .. yes, lets go with that rofl.

MooreaTv 06-23-19 09:14 PM

Not what the OP wanted which is solved (as named frames are global)

But what if you want to see all frames, or rather all frames you are allowed to see,
how would one skip over the forbidden one and get the loop above to not fail in the middle?

Fizzlemizz 06-23-19 09:33 PM

IsForbidden

MooreaTv 06-24-19 03:50 AM

Thanks Fizzlemizz!

Lybrial 06-26-19 12:16 PM

I was able to anchor my frames perfectly to the player resource bar:

Code:

        if (self.anchorFrame) then
                return;
        end
       
        self.anchorFrame = CreateFrame("Frame", "LybrialUIAnchor", UIParent);
        self.anchorFrame:Hide();
        self.anchorFrame.attachedVisibleFrames = {};
        self.anchorFrame:RegisterEvent("NAME_PLATE_UNIT_ADDED");
        self.anchorFrame:RegisterEvent("NAME_PLATE_UNIT_REMOVED");                       
        self.anchorFrame.Attach = function(self, frame, frameTopLeft, frameBottomRight)
                self:SetParent(frame);
                self:ClearAllPoints();
                self:SetPoint("TOPLEFT", frameTopLeft, "TOPLEFT", 0, 0);
                self:SetPoint("BOTTOMRIGHT", frameBottomRight, "BOTTOMRIGHT", 0, 0);
                self:Show();
        end
        self.anchorFrame.Detach = function(self, frame)
                self:ClearAllPoints();
                self:Hide();
        end
        self.anchorFrame.eventHandler = function(self, event, nameplate)
                if (event == "NAME_PLATE_UNIT_ADDED") then
                        if (UnitIsUnit(nameplate, "player")) then
                                local frame = C_NamePlate.GetNamePlateForUnit("player");
                               
                                if (frame) then
                                        if (frame.kui and frame.kui.bg and frame.kui:IsShown()) then
                                                LybrialAnchors.anchorFrame:Attach(frame.kui, KuiNameplatesPlayerAnchor, KuiNameplatesPlayerAnchor);
                                        elseif (ElvUIPlayerNamePlateAnchor) then
                                                LybrialAnchors.anchorFrame:Attach(ElvUIPlayerNamePlateAnchor, ElvUIPlayerNamePlateAnchor, ElvUIPlayerNamePlateAnchor);
                                        else
                                                LybrialAnchors.anchorFrame:Attach(frame, frame.UnitFrame.healthBar, NamePlateDriverFrame.classNamePlatePowerBar);
                                        end
                                       
                                        LybrialAnchors.anchorFrame:Show();
                                        LybrialAnchors:OnUpdate();
                                else
                                        LybrialAnchors.anchorFrame:Detach();
                                        LybrialAnchors.anchorFrame:Hide();
                                        LybrialAnchors:OnUpdate();
                                end
                        end
                elseif (event == "NAME_PLATE_UNIT_REMOVED") then
                        if (UnitIsUnit(nameplate, "player")) then
                                LybrialAnchors.anchorFrame:Detach();
                                LybrialAnchors.anchorFrame:Hide();
                                LybrialAnchors:OnUpdate();
                        end
                end
        end
        self.anchorFrame:SetScript("OnEvent", self.anchorFrame.eventHandler);

To anchor raven to my frame I do this:

Code:

function Raven:SetupFrames()
        if (self.isLoaded and self.db.profile.enabled) then
                table.foreach(self.frames, function(key, value)
                        local frame = _G[value];
                       
                        if (frame) then
                                frame:ClearAllPoints();
                               
                                if (value == "RavenBarGroupShort_Buffs") then
                                        frame:SetPoint("CENTER", LybrialAnchors.anchorFrame, "CENTER", -215, -59);
                                elseif (value == "RavenBarGroupDebuffs") then
                                        frame:SetPoint("CENTER", LybrialAnchors.anchorFrame, "CENTER", -215, -134);
                                elseif (value == "RavenBarGroupZiel") then
                                        frame:SetPoint("CENTER", LybrialAnchors.anchorFrame, "CENTER", 217, -59);
                                elseif (value == "RavenBarGroupCooldowns") then
                                        frame:SetPoint("CENTER", LybrialAnchors.anchorFrame, "CENTER", 0, -224);
                                end
                        end
                end);
        end
end

But here we are now at Patch 8.2 and as expected:

Code:

7x Raven\Nest.lua:918: Action[FrameMeasurement] failed because[Can't measure restricted regions]: attempted from: RavenBarGroupDebuffs:GetLeft().
[C]: in function `GetLeft'
Raven\Nest.lua:918: in function `Nest_GetAnchorPoint'
Raven\Bars.lua:677: in function `UpdatePositions'
Raven\Bars.lua:2099: in function `UpdateBars'
Raven\Main.lua:1109: in function `Update'
Raven\Main.lua:820: in function <Raven\Main.lua:816>

Locals:
(*temporary) = RavenBarGroupDebuffs {
 0 = <userdata>
}

Is there any way around this?

Lybrial 06-26-19 11:21 PM

So nameplates are "restricted frames now" so if I would attach raven
to nameplates I would not be able to call functions like GetCenter(),
GetLeft() etc on nameplates frame, right? But that is not what im
doing here. Im creating another frame, an "anchorFrame" and
attach this frame to the nameplates. Raven is then getting attached
to the anchorFrame.

The error says that raven was not able to call GetLeft() etc. on
that anchor frame.

So is a child frame of a restricted frame automatically restricted too?
Hell that would suck :D

Fizzlemizz 06-26-19 11:39 PM

Yes. Being able to attach an "unrestricted intermediary" frame wold defeat the purpose of restricting nameplates in the first place.


All times are GMT -6. The time now is 02:45 PM.

vBulletin © 2020, Jelsoft Enterprises Ltd
© 2004 - 2020 MMOUI