Quantcast Why frame never attaches to UIParent? - WoWInterface
Thread Tools Display Modes
07-17-19, 01:16 PM   #1
Lybrial
A Theradrim Guardian
AddOn Compiler - Click to view compilations
Join Date: Jan 2010
Posts: 61
Why frame never attaches to UIParent?

Hi,

I have the following code:

Lua Code:
  1. function LybrialAnchors:SetupFrames()
  2.     if (not self.anchorFrame) then
  3.         self.anchorFrame = CreateFrame("Frame", "LybrialUIAnchor");
  4.         self.anchorFrame:RegisterEvent("NAME_PLATE_UNIT_ADDED");
  5.         self.anchorFrame:RegisterEvent("NAME_PLATE_UNIT_REMOVED");
  6.         self.anchorFrame.Attach = function(self, frame, frameTopLeft, frameBottomRight)
  7.             print("attach: " .. self:GetName());
  8.  
  9.             self:SetParent(frame);
  10.             self:ClearAllPoints();
  11.             self:SetPoint("TOPLEFT", frameTopLeft, "TOPLEFT", 0, 0);
  12.             self:SetPoint("BOTTOMRIGHT", frameBottomRight, "BOTTOMRIGHT", 0, 0);
  13.  
  14.             LybrialAnchors:OnUpdate();
  15.         end
  16.         self.anchorFrame.Detach = function(self)
  17.             print("detach: " .. self:GetName());
  18.  
  19.             self:SetParent(UIParent);
  20.             self:ClearAllPoints();
  21.             self:SetPoint("CENTER", UIParent, "CENTER", 0, -150);
  22.  
  23.             LybrialAnchors:OnUpdate();
  24.         end
  25.         self.anchorFrame.eventHandler = function(_, event, nameplate)
  26.             if (event == "NAME_PLATE_UNIT_ADDED") then
  27.                 if (UnitIsUnit(nameplate, "player")) then
  28.                     if (InCombatLockdown() or C_PetBattles.IsInBattle()) then
  29.                         LybrialAnchors.anchorFrame:Detach();
  30.                     else
  31.                         local frame = C_NamePlate.GetNamePlateForUnit("player");
  32.  
  33.                         if (frame) then
  34.                             LybrialAnchors.anchorFrame:Attach(frame, frame.UnitFrame.healthBar, NamePlateDriverFrame.classNamePlatePowerBar);
  35.                         else
  36.                             LybrialAnchors.anchorFrame:Detach();
  37.                         end
  38.                     end
  39.                 end
  40.             elseif (event == "NAME_PLATE_UNIT_REMOVED") then
  41.                 if (UnitIsUnit(nameplate, "player")) then
  42.                     LybrialAnchors.anchorFrame:Detach();
  43.                 end
  44.             end
  45.         end
  46.  
  47.         self.anchorFrame:SetScript("OnEvent", self.anchorFrame.eventHandler);
  48.     end
  49. end

What it should do:

It should create a frame and attach that frame to the UIParent by default.
But when the player nameplate is getting added AND when im not in combat
the frame should get attached to the personal player resources.

What it does:

It never attaches to the UI Parent. When im in combat and I hide and show the UI
again the print method tells me that the "Detach" was called but still the frame is
getting anchored to the nameplate. I dont get how this is possible. It is always
attaching to the nameplate even though the print method tells me the "Detach"
method is getting called.

Anyone an idea why this is happening?

Last edited by Lybrial : 07-17-19 at 11:29 PM.
  Reply With Quote
07-18-19, 10:40 AM   #2
aallkkaa
A Black Drake
 
aallkkaa's Avatar
AddOn Author - Click to view addons
Join Date: Jun 2017
Posts: 89
I haven't tested this but ...
Shouldn't it be:
Code:
print("attach: " .. (self.anchorFrame:GetParent()):GetName());
and
Code:
print("detach: " .. (self.anchorFrame:GetParent()):GetName());
?
  Reply With Quote
07-18-19, 10:51 AM   #3
Lybrial
A Theradrim Guardian
AddOn Compiler - Click to view compilations
Join Date: Jan 2010
Posts: 61
Name doesnt matter. I just wanted to make sure that "Detach" is getting called.
But yes, If I would want to output the parent frame you would be right.

Code:
print("detach: " .. (self:GetParent()):GetName())
To varify that the right code is called I used your print: Its correct.

Still all frames are still attached to nameplate and not UIParent.

Last edited by Lybrial : 07-18-19 at 10:57 AM.
  Reply With Quote
07-18-19, 11:23 AM   #4
aallkkaa
A Black Drake
 
aallkkaa's Avatar
AddOn Author - Click to view addons
Join Date: Jun 2017
Posts: 89
Oh, right, I see your point now.

Still, on a second look at your code, you are passing self as argument to self.anchorFrame.Attach(self) and to self.anchorFrame.Detach(self). You then call frame methods on self that I believe you want to be called on self.anchorFrame instead.
I'm unsure about this, but that may be the problem. If I'm right, the easy fix would be to use self.anchorFrame as prefix to :SetParent, etc.
  Reply With Quote
07-18-19, 11:38 AM   #5
Lybrial
A Theradrim Guardian
AddOn Compiler - Click to view compilations
Join Date: Jan 2010
Posts: 61
In this case self is the anchorFrame

Look what happens if I add some outputs to Detach function:

Lua Code:
  1. self.anchorFrame.Detach = function(self)
  2.             print("Detach called");
  3.  
  4.             self:SetParent(UIParent);
  5.             self:ClearAllPoints();
  6.             self:SetPoint("CENTER", UIParent, "CENTER", 0, -150);
  7.  
  8.             print("attached to: " .. self:GetParent():GetName());
  9.  
  10.             LybrialAnchors:OnUpdate();
  11.         end

output:

Code:
Detach called
attached to: NamePlate1
How does that make sense? I set parent to UIParent and he is still attached to NamePlate1

Last edited by Lybrial : 07-18-19 at 11:45 AM.
  Reply With Quote
07-18-19, 03:23 PM   #6
aallkkaa
A Black Drake
 
aallkkaa's Avatar
AddOn Author - Click to view addons
Join Date: Jun 2017
Posts: 89
You are right and I would agree the output of your prints does not make sense.
That is actually why I went ahead and guessed at the possibility that the use of the reserved word "self" as a parent table to the frame itself might be causing a problem. In other words, I understood the logic of your use of "self" and it is correct AFAIK, but there have been times where the WoW API seems to contradict Lua logic (maybe I just don't get it but... recently I got a C_Stack_Overflow on a semi-personal addon of mine (and I couldn't figure out why); come Blizzard's latest hotfixes and the error was gone!).

Getting back to your case, have you tried :SetParent(nil) before setting a new parent? I know, should not be needed, but...
  Reply With Quote
07-18-19, 05:05 PM   #7
jeruku
A Chromatic Dragonspawn
 
jeruku's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2010
Posts: 196
To my knowledge one of the more recent updates included a change to anchoring, including Nameplates. With it came the change that you can only anchor children of a Nameplate to the plate itself or one of its other children.

Blue post summary:
We added new restricted frames system that affects frame anchoring:
  • Frames that are anchored to a restricted frame can only have their other anchors set to frames within that same anchor hierarchy
  • Added new API in the Line API: Line:ClearAllPoints();
    • This will clear the anchors on a line and must be called to clear the restricted flag off of the frame.
  • New restricted frames include:
    • Nameplates

The following APIs are now blocked from being called on restricted frames:
  • GetCenter()
  • GetLeft()
  • GetRight()
  • GetTop()
  • GetBottom()
  • GetRect()
  • GetScaledRect()
  • GetBoundsRect()
__________________
"I have not failed, I simply found 10,000 ways that did not work." - Thomas Edison
  Reply With Quote
07-19-19, 01:48 AM   #8
Lybrial
A Theradrim Guardian
AddOn Compiler - Click to view compilations
Join Date: Jan 2010
Posts: 61
And that happens even if you clearAllPoints() Oo
God I hate these 8.2 changes, seriously....
  Reply With Quote
07-19-19, 03:53 AM   #9
aallkkaa
A Black Drake
 
aallkkaa's Avatar
AddOn Author - Click to view addons
Join Date: Jun 2017
Posts: 89
And in the light of jeruku's post, I winged up an addon with your (slightly edited) code and my previous suggestion does work. I.e.:
Lua Code:
  1. print("Detach called");
  2.  
  3. self:SetParent(nil);
  4. self:SetParent(UIParent);
  5. self:ClearAllPoints();
  6. self:SetPoint("CENTER", UIParent, "CENTER", 0, -150);
  7.  
  8. print("attached to: " .. self:GetParent():GetName());
Output:
Code:
Detach called
attached to: UIParent

Furthermore, :GetPoint should be added to the list jeruku quoted under "The following APIs are now blocked from being called on restricted frames:" If you add thiese two lines to the end of the snippet above:
Lua Code:
  1. local point, anchor, anchorTo, x, y = self:GetPoint(1);
  2. print("at point #1: " .. point.. ", ".. anchor:GetName().. ", ".. anchorTo.. ", ".. x.. ", ".. y);
The output is:
Code:
Detach called
attached to: UIParent
at point #1: CENTER, UIParent, CENTER, 0, -150
But, if you add that same code to your :Attach method, you get an error:
Code:
Message: Interface\AddOns\alkaTestLyabral\alkaTestLyabral.lua:22: Action[FrameMeasurement] failed because[Can't measure restricted regions]: attempted from: LybrialUIAnchor:GetPoint().
Time: Fri Jul 19 10:47:09 2019
Count: 1
Stack: Interface\AddOns\alkaTestLyabral\alkaTestLyabral.lua:22: Action[FrameMeasurement] failed because[Can't measure restricted regions]: attempted from: LybrialUIAnchor:GetPoint().
[C]: in function `GetPoint'
Interface\AddOns\alkaTestLyabral\alkaTestLyabral.lua:22: in function `Attach'
Interface\AddOns\alkaTestLyabral\alkaTestLyabral.lua:64: in function <Interface\AddOns\alkaTestLyabral\alkaTestLyabral.lua:55>

Locals: (*temporary) = LybrialUIAnchor {
 0 = <userdata>
 Attach = <function> defined @Interface\AddOns\alkaTestLyabral\alkaTestLyabral.lua:12
 Detach = <function> defined @Interface\AddOns\alkaTestLyabral\alkaTestLyabral.lua:32
 TestTexture = <unnamed> {
 }
 eventHandler = <function> defined @Interface\AddOns\alkaTestLyabral\alkaTestLyabral.lua:55
}
(*temporary) = 1

Finally, I also created a texture on the frame. And it's weird.
The texture reportedly attaches correctly to the frame, wich on Detach is reportedly positioned at "CENTER, UIParent, CENTER, 0, -150".
Code:
Lua Code:
  1. print("Detach called");
  2. print("attached to: " .. self:GetParent():GetName());
  3. local point, anchor, anchorTo, x, y = self:GetPoint(1);
  4. print("at point #1: " .. point.. ", ".. anchor:GetName().. ", ".. anchorTo.. ", ".. x.. ", ".. y);
  5. local point, anchor, anchorTo, x, y = self.TestTexture:GetPoint(1);
  6. print("Texture at point #1: " .. point.. ", ".. anchor:GetName().. ", ".. anchorTo.. ", ".. x.. ", ".. y);
Output:
Code:
Detach called
attached to: UIParent
at point #1: CENTER, UIParent, CENTER, 0, -150
Texture at point #1: TOPLEFT, LybrialUIAnchor, TOPLEFT, 0, 0
BUT the texture is always drawn at the position the player's nameplate was last drawn at (on :Attach), never resetting to "CENTER, UIParent, CENTER, 0, -150" (as set and reportedly done on : Dettach).
I'm actually rather unfamiliar with working with textures, so I may be missing something.

For reference, here's the full code I ran:
Lua Code:
  1. local LybrialAnchors = {};
  2.  
  3. function LybrialAnchors:SetupFrames()
  4.     if (not self.anchorFrame) then
  5.         self.anchorFrame = CreateFrame("Frame", "LybrialUIAnchor");
  6.  
  7.         self.anchorFrame.TestTexture = self.anchorFrame:CreateTexture(NIL, "ARTWORK");
  8.         self.anchorFrame.TestTexture:SetColorTexture(1, 1, 1, 1);
  9.  
  10.         self.anchorFrame:RegisterEvent("NAME_PLATE_UNIT_ADDED");
  11.         self.anchorFrame:RegisterEvent("NAME_PLATE_UNIT_REMOVED");
  12.         self.anchorFrame.Attach = function(self, frame, frameTopLeft, frameBottomRight)
  13.             print("Attach called");
  14.  
  15.             self:SetParent(frame);
  16.             self:ClearAllPoints();
  17.             self:SetPoint("TOPLEFT", frameTopLeft, "TOPLEFT", 0, 0);
  18.             self:SetPoint("BOTTOMRIGHT", frameBottomRight, "BOTTOMRIGHT", 0, 0);
  19.  
  20.             print("attached to: " .. self:GetParent():GetName());
  21.             -- NB: The following line will error (cannot get measurements from restricted frame
  22.             -- local point, anchor, anchorTo, x, y = self:GetPoint(1);
  23.             -- print("at point #1: " .. point.. ", ".. anchor:GetName().. ", ".. anchorTo.. ", ".. x.. ", ".. y);
  24.  
  25.             -- LybrialAnchors:OnUpdate();
  26.             self.TestTexture:ClearAllPoints();
  27.             self.TestTexture:SetAllPoints();
  28.             -- NB: The following line will error (cannot get measurements from restricted frame)
  29.             -- local point, anchor, anchorTo, x, y = self.TestTexture:GetPoint(1);
  30.             -- print("Texture at point #1: " .. point.. ", ".. anchor:GetName().. ", ".. anchorTo.. ", ".. x.. ", ".. y);
  31.         end
  32.         self.anchorFrame.Detach = function(self)
  33.             print("Detach called");
  34.  
  35.             self:SetParent(nil);
  36.             self:SetParent(UIParent);
  37.             self:ClearAllPoints();
  38.             self:SetPoint("CENTER", UIParent, "CENTER", 0, -150);
  39.  
  40.             print("attached to: " .. self:GetParent():GetName());
  41.             -- NB: The following line will NOT error
  42.             local point, anchor, anchorTo, x, y = self:GetPoint(1);
  43.             print("at point #1: " .. point.. ", ".. anchor:GetName().. ", ".. anchorTo.. ", ".. x.. ", ".. y);
  44.  
  45.             -- LybrialAnchors:OnUpdate();
  46.             -- NB: The following line will error (cannot set a Texture's parent to nil)
  47.             -- self.TestTexture:SetParent(nil);
  48.             -- self.TestTexture:SetParent(self);
  49.             self.TestTexture:ClearAllPoints();
  50.             self.TestTexture:SetAllPoints();
  51.             -- NB: The following line will NOT error
  52.             local point, anchor, anchorTo, x, y = self.TestTexture:GetPoint(1);
  53.             print("Texture at point #1: " .. point.. ", ".. anchor:GetName().. ", ".. anchorTo.. ", ".. x.. ", ".. y);
  54.         end
  55.         self.anchorFrame.eventHandler = function(_, event, nameplate)
  56.             if (event == "NAME_PLATE_UNIT_ADDED") then
  57.                 if (UnitIsUnit(nameplate, "player")) then
  58.                     if (InCombatLockdown() or C_PetBattles.IsInBattle()) then
  59.                         LybrialAnchors.anchorFrame:Detach();
  60.                     else
  61.                         local frame = C_NamePlate.GetNamePlateForUnit("player");
  62.  
  63.                         if (frame) then
  64.                             LybrialAnchors.anchorFrame:Attach(frame, frame.UnitFrame.healthBar, NamePlateDriverFrame.classNamePlatePowerBar);
  65.                         else
  66.                             LybrialAnchors.anchorFrame:Detach();
  67.                         end
  68.                     end
  69.                 end
  70.             elseif (event == "NAME_PLATE_UNIT_REMOVED") then
  71.                 if (UnitIsUnit(nameplate, "player")) then
  72.                     LybrialAnchors.anchorFrame:Detach();
  73.                 end
  74.             end
  75.         end
  76.  
  77.         self.anchorFrame:SetScript("OnEvent", self.anchorFrame.eventHandler);
  78.     end
  79. end
  80.    
  81. LybrialAnchors:SetupFrames()

I'll be going back to my own nerve-wrecking projects now. But if anyone has any more insight on any of this, I'd be curious.

And... happy coding, Lybrial!
  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » Why frame never attaches to UIParent?

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off