Thread Tools Display Modes
06-08-17, 04:11 AM   #1
Layback_
An Onyxian Warder
Join Date: Feb 2016
Posts: 358
Having an issue with edge of backdrop being disappeared when frame's size changes

Hi all,

I should have gone to 'Graphics Help' forum rather than here, 'Lua/XML Help', but I guess this is more like a Lua related issue.

So, I've created a generic Template function for my frames like the following:

Lua Code:
  1. function CustomFunc:SetTemplate(whatType, anchor)
  2.     local anchor = anchor or self;
  3.     local backdrop = LSM:Fetch("background", "backdrop");
  4.     local fer12 = LSM:Fetch("border", "fer12");
  5.  
  6.     local template = CreateFrame("Frame", anchor:GetName() .. "Template", self);
  7.     template:SetFrameLevel(self:GetFrameLevel());
  8.  
  9.     if whatType == 1 then -- Extend
  10.         template:SetPoint("TOPLEFT", anchor, "TOPLEFT", -1, 1);
  11.         template:SetPoint("BOTTOMRIGHT", anchor, "BOTTOMRIGHT", 1, -1);
  12.     elseif whatType == 2 then -- Shrink
  13.         template:SetPoint("TOPLEFT", anchor, "TOPLEFT", 1, -1);
  14.         template:SetPoint("BOTTOMRIGHT", anchor, "BOTTOMRIGHT", -1, 1);
  15.     else -- Default
  16.         template:SetAllPoints(anchor);
  17.     end
  18.  
  19.     template:SetBackdrop({
  20.         bgFile = backdrop,
  21.         edgeFile = fer12,
  22.         edgeSize = 2,
  23.     });
  24.     template:SetBackdropColor(0.1, 0.1, 0.1);
  25.     template:SetBackdropBorderColor(0.7, 0.7, 0.7);
  26.  
  27.     anchor.template = template;
  28. end

Then I applied this to frame and resized the that frame.

Lua Code:
  1. bar = CreateFrame("StatusBar", "TestBar", UIParent);
  2. bar:SetPoint("CENTER");
  3. bar:SetSize(46, 10);
  4. bar:SetTemplate(1);
  5.  
  6. bar:SetWidth(55); -- Modify width

Since the template frame's size varies based on its anchor points, I thought this would work fine, but as you can see the image below, left & right borders are gone once I changed the width of parent frame, bar.
(Well, they are definitely there, but is not rendered(?) properly)



I also attempted to change those regions' draw layer, but that didn't solve the problem

Could anyone please help me out regarding this?

Thank you!

*EDIT: Applying insets to backdrop didn't do the trick as well.

Code:
insets = {
	left = 1,
	right = 1,
	top = 1,
	bottom = 1,
},

**EDIT: Here I've attached those texture files!
Attached Files
File Type: tga fer12.tga (8.0 KB, 130 views)
File Type: blp backdrop.BLP (1.3 KB, 137 views)

Last edited by Layback_ : 06-08-17 at 04:19 AM.
  Reply With Quote
06-08-17, 08:58 AM   #2
MunkDev
A Scalebane Royal Guard
 
MunkDev's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2015
Posts: 431
This happens because you're trying to fit a square peg into a round hole. Your edge file is being drawn on fractioned pixels, meaning the calculations by the UI engine are uneven to the point where your frame's edges end up in between pixels to be drawn on screen.

Normally, this aliasing effect isn't that big a of a deal if you're using larger edge textures, but when you're down to 2 px borders, it matters how large your frame is and where it's placed on screen. This function can eliminate one such case, by forcing your frame to only allow even numbers for width and height:

Lua Code:
  1. -- Force the frame to redraw on even pixels.
  2. function frame:OnSizeChanged(width, height)
  3.     width, height = floor(width + 0.5), floor(height + 0.5)
  4.     self:SetSize(width - (width % 2), height - (height % 2))
  5. end
  6.  
  7. frame:SetScript('OnSizeChanged', frame.OnSizeChanged)

Note that this might cause an infinite loop since the size is set from within the handler that responds to size changes, but find a way to bake this function into your frame.

The other case in which this happens is placing a frame so that its size causes one of the border to not fit perfectly onto a pixel. This can be fixed by the same approach as the function I just posted, but operating on the x and y offsets of your frame:GetPoint() values.
__________________

Last edited by MunkDev : 06-08-17 at 09:05 AM.
  Reply With Quote
06-08-17, 09:07 AM   #3
Gethe
RealUI Developer
 
Gethe's Avatar
Premium Member
Featured
Join Date: Sep 2008
Posts: 942
It's because you have it anchored to the center. When you resized the frame, the left and right borders were no longer on complete pixels so they didn't get rendered properly.

If you want to keep it anchored in the center you have to resize it by increments of 2
__________________
Knowledge = Power; Be OP

  Reply With Quote
06-08-17, 01:17 PM   #4
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
Originally Posted by MunkDev View Post
This happens because you're trying to fit a square peg into a round hole. Your edge file is being drawn on fractioned pixels, meaning the calculations by the UI engine are uneven to the point where your frame's edges end up in between pixels to be drawn on screen.

Normally, this aliasing effect isn't that big a of a deal if you're using larger edge textures, but when you're down to 2 px borders, it matters how large your frame is and where it's placed on screen. This function can eliminate one such case, by forcing your frame to only allow even numbers for width and height:

Lua Code:
  1. -- Force the frame to redraw on even pixels.
  2. function frame:OnSizeChanged(width, height)
  3.     width, height = floor(width + 0.5), floor(height + 0.5)
  4.     self:SetSize(width - (width % 2), height - (height % 2))
  5. end
  6.  
  7. frame:SetScript('OnSizeChanged', frame.OnSizeChanged)

Note that this might cause an infinite loop since the size is set from within the handler that responds to size changes, but find a way to bake this function into your frame.

The other case in which this happens is placing a frame so that its size causes one of the border to not fit perfectly onto a pixel. This can be fixed by the same approach as the function I just posted, but operating on the x and y offsets of your frame:GetPoint() values.
This is not enough by default, you also have to be sure that the frame is not on fraction pixels by itself too:

Lua Code:
  1. local left, bottom = self:GetLeft(), self:GetBottom()
  2.  
  3. local x = math.round(left)
  4. local y = math.round(-UIParent:GetHeight() + bottom + self:GetHeight())
  5.  
  6. self:ClearAllPoints()
  7. self:SetPoint("TopLeft", UIParent, "TopLeft", x, y)

And if the frame is move complex or ancored to another frame than things get even more complicated. I've managed to do pixel perfect scaling but it's well complicated as hell.
  Reply With Quote
06-08-17, 11:09 PM   #5
Layback_
An Onyxian Warder
Join Date: Feb 2016
Posts: 358
mmmmmmmmmmmmmmmm....

That seems complex than I thought.

Maybe I should avoid using border textures until I get confident with it.
(For now, I'll just use a backdrop texture as my borders)

Thank you all !

Last edited by Layback_ : 06-09-17 at 04:45 AM.
  Reply With Quote
06-09-17, 03:39 AM   #6
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
I can give you an example code how to properly do it, after i drunk my covfefe.
  Reply With Quote
06-09-17, 04:45 AM   #7
Layback_
An Onyxian Warder
Join Date: Feb 2016
Posts: 358
Originally Posted by Resike View Post
I can give you an example code how to properly do it, after i drunk my covfefe.
That would be AWESOME !
  Reply With Quote
06-09-17, 05:02 AM   #8
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
Lua Code:
  1. math.round = function(self)
  2.     return math.floor(self + 0.5)
  3. end
  4.  
  5. local frame = CreateFrame("Frame", "TestFrame", UIParent)
  6. frame:SetSize(400, 200)
  7. frame:SetPoint("TOPLEFT", UIParent, "TOPLEFT", (UIParent:GetWidth() / 2) - (frame:GetWidth() / 2), (-UIParent:GetHeight() / 2) + (frame:GetHeight() / 2))
  8. frame:SetClampedToScreen(true)
  9.  
  10. frame.backdrop = {
  11.     bgFile = "Interface\\Buttons\\WHITE8X8",
  12.     edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
  13.     tile = true,
  14.     tileSize = 16,
  15.     edgeSize = 14,
  16.     insets = {left = 3, right = 3, top = 3, bottom = 3},
  17. }
  18.  
  19. frame:SetBackdrop(frame.backdrop)
  20. frame:SetBackdropColor(0.0, 0.0, 0.0, 0.5)
  21. frame:SetBackdropBorderColor(0.3, 0.3, 0.3, 1.0)
  22.  
  23. -- Hooks
  24. hooksecurefunc(frame, "SetPoint", function(self)
  25.     if self.moving then
  26.         return
  27.     end
  28.  
  29.     self.moving = true
  30.     self:SetMovable(true)
  31.  
  32.     local left, bottom = self:GetLeft(), self:GetBottom()
  33.  
  34.     if left and bottom then
  35.         local x = math.round(left)
  36.         local y = math.round(-UIParent:GetHeight() + bottom + self:GetHeight())
  37.  
  38.         self:ClearAllPoints()
  39.         self:SetPoint("TOPLEFT", UIParent, "TOPLEFT", x, y)
  40.     end
  41.  
  42.     self:SetMovable(false)
  43.     self.moving = nil
  44. end)
  45.  
  46. hooksecurefunc(frame, "StopMovingOrSizing", function(self)
  47.     self:SetMovable(true)
  48.  
  49.     local left, bottom = self:GetLeft(), self:GetBottom()
  50.  
  51.     if left and bottom then
  52.         local x = math.round(left)
  53.         local y = math.round(-UIParent:GetHeight() + bottom + self:GetHeight())
  54.  
  55.         self:ClearAllPoints()
  56.         self:SetPoint("TOPLEFT", UIParent, "TOPLEFT", x, y)
  57.     end
  58.  
  59.     self:SetMovable(false)
  60. end)
  61.  
  62. frame:HookScript("OnSizeChanged", function(self)
  63.     self:SetSize(math.round(self:GetWidth()), math.round(self:GetHeight()))
  64. end)
  65.  
  66. -- Moving and Resizing functions
  67. frame:EnableMouse(true)
  68. --frame:SetMaxResize(800, 400)
  69. frame:SetMinResize(40, 40)
  70.  
  71. frame:SetScript("OnMouseDown", function(self, button)
  72.     if button == "LeftButton" then
  73.         self:SetMovable(true)
  74.         self:StartMoving()
  75.     end
  76. end)
  77. frame:SetScript("OnMouseUp", function(self, button)
  78.     if button == "LeftButton" then
  79.         self:StopMovingOrSizing()
  80.         self:SetMovable(false)
  81.  
  82.         local left, bottom = self:GetLeft(), self:GetBottom()
  83.  
  84.         if left and bottom then
  85.             local x = math.round(left)
  86.             local y = math.round(-UIParent:GetHeight() + bottom + self:GetHeight())
  87.  
  88.             self:ClearAllPoints()
  89.             self:SetPoint("TOPLEFT", UIParent, "TOPLEFT", x, y)
  90.         end
  91.     end
  92. end)
  93.  
  94. frame.br = CreateFrame("Frame", nil, frame)
  95. frame.br:SetPoint("TOPLEFT", frame, "BOTTOMRIGHT", -15, 15)
  96. frame.br:SetSize(12, 12)
  97. frame.br:EnableMouse(true)
  98.  
  99. frame.br.texture = frame.br:CreateTexture(nil, "OVERLAY")
  100. frame.br.texture:SetPoint("TOPLEFT", frame.br, "TOPLEFT", 0, 0)
  101. frame.br.texture:SetSize(12, 12)
  102. frame.br.texture:SetTexture("Interface\\ChatFrame\\UI-ChatIM-SizeGrabber-Up")
  103.  
  104. frame.br:SetScript("OnEnter", function(self)
  105.     frame.br.texture:SetTexture("Interface\\ChatFrame\\UI-ChatIM-SizeGrabber-Highlight")
  106. end)
  107. frame.br:SetScript("OnLeave", function(self)
  108.     frame.br.texture:SetTexture("Interface\\ChatFrame\\UI-ChatIM-SizeGrabber-Up")
  109. end)
  110.  
  111. frame.br:SetScript("OnMouseDown", function(self, button)
  112.     if button == "LeftButton" then
  113.         frame.br.texture:SetTexture("Interface\\ChatFrame\\UI-ChatIM-SizeGrabber-Down")
  114.  
  115.         frame:SetResizable(true)
  116.         frame:StartSizing("BottomRight")
  117.     end
  118. end)
  119. frame.br:SetScript("OnMouseUp", function(self, button)
  120.     frame:StopMovingOrSizing()
  121.     frame:SetResizable(false)
  122.  
  123.     frame.br.texture:SetTexture("Interface\\ChatFrame\\UI-ChatIM-SizeGrabber-Up")
  124. end)

This frame can be moved/resized on the fly, and it keeps it's pixel perfection sizes on all of it's elements all the time, even after any (SetSize|SetWidth|SetHeight|SetPoint) calls.
  Reply With Quote
06-09-17, 06:35 AM   #9
Layback_
An Onyxian Warder
Join Date: Feb 2016
Posts: 358
Originally Posted by Resike View Post
This frame can be moved/resized on the fly, and it keeps it's pixel perfection sizes on all of it's elements all the time, even after any (SetSize|SetWidth|SetHeight|SetPoint) calls.
WOW!!

So the core of part of the example would be:

Lua Code:
  1. local left, bottom = self:GetLeft(), self:GetBottom()
  2.  
  3. if left and bottom then
  4.     local x = math.round(left)
  5.     local y = math.round(-UIParent:GetHeight() + bottom + self:GetHeight())
  6.  
  7.     self:ClearAllPoints()
  8.     self:SetPoint("TOPLEFT", UIParent, "TOPLEFT", x, y)
  9. end

as you've explained on previous comment.

What if the parent of such frame is not UIParent, but another frame?

Would L#5 and L#8 still be same? or should I change UIParent to another parent frame that we create?

+

I've been digging codes out of ElvUI and it also has some variables and functions about pixel perfect.

Would that be a relevant info here? If so, do you have any clues regarding what it actually does?

Last edited by Layback_ : 06-09-17 at 07:03 AM.
  Reply With Quote
06-09-17, 09:49 AM   #10
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
You can however thats a bit more complex, since you can never know if the relative frame is not positioned on fraction pixels, for that you have to get the relative frames (GetLeft|GetBottom|GetTop|GetRight) based on anchor points and substract those values from the actual frame's (GetLeft|GetBottom|GetTop|GetRight), and it even gets more complicated since every different anchor points need different calculations, however i have a function for that already, called GetRelativePoint:

Lua Code:
  1. math.round = function(self)
  2.     return math.floor(self + 0.5)
  3. end
  4.  
  5. local function GetRelativePoint(points, frame)
  6.     if not points then
  7.         points = {"BOTTOMLEFT", UIParent, "BOTTOMLEFT"}
  8.     end
  9.  
  10.     local rel = points[2]
  11.     if not rel then
  12.         rel = UIParent
  13.     end
  14.  
  15.     if type(rel) == "string" then
  16.         rel = _G[rel]
  17.     end
  18.  
  19.     if not rel then
  20.         return
  21.     end
  22.  
  23.     local point = string.upper(points[1])
  24.     local relPoint = string.upper(points[3])
  25.     local rX, rY, pX, pY
  26.  
  27.     if rel:GetLeft() then
  28.         if relPoint == "TOPRIGHT" then
  29.             rY = rel:GetTop()
  30.             rX = rel:GetRight()
  31.         elseif relPoint == "TOPLEFT" then
  32.             rY = rel:GetTop()
  33.             rX = rel:GetLeft()
  34.         elseif relPoint == "TOP" then
  35.             rY = rel:GetTop()
  36.             rX = (rel:GetRight() + rel:GetLeft()) / 2
  37.         elseif relPoint == "BOTTOMRIGHT" then
  38.             rY = rel:GetBottom()
  39.             rX = rel:GetRight()
  40.         elseif relPoint == "BOTTOMLEFT" then
  41.             rY = rel:GetBottom()
  42.             rX = rel:GetLeft()
  43.         elseif relPoint == "BOTTOM" then
  44.             rY = rel:GetBottom()
  45.             rX = (rel:GetRight() + rel:GetLeft()) / 2
  46.         elseif relPoint == "CENTER" then
  47.             rY = (rel:GetTop() + rel:GetBottom()) / 2
  48.             rX = (rel:GetRight() + rel:GetLeft()) / 2
  49.         elseif relPoint == "LEFT" then
  50.             rY = (rel:GetTop() + rel:GetBottom()) / 2
  51.             rX = rel:GetLeft()
  52.         elseif relPoint == "RIGHT" then
  53.             rY = (rel:GetTop() + rel:GetBottom()) / 2
  54.             rX = rel:GetRight()
  55.         else
  56.             return
  57.         end
  58.         if rel.GetEffectiveScale then
  59.             rY = rY * rel:GetEffectiveScale()
  60.             rX = rX * rel:GetEffectiveScale()
  61.         else
  62.             rY = rY * UIParent:GetEffectiveScale()
  63.             rX = rX * UIParent:GetEffectiveScale()
  64.         end
  65.     end
  66.  
  67.     if frame:GetLeft() then
  68.         if point == "TOPRIGHT" then
  69.             pY = frame:GetTop()
  70.             pX = frame:GetRight()
  71.         elseif point == "TOPLEFT" then
  72.             pY = frame:GetTop()
  73.             pX = frame:GetLeft()
  74.         elseif point == "TOP" then
  75.             pY = frame:GetTop()
  76.             pX = (frame:GetRight() + frame:GetLeft()) / 2
  77.         elseif point == "BOTTOMRIGHT" then
  78.             pY = frame:GetBottom()
  79.             pX = frame:GetRight()
  80.         elseif point == "BOTTOMLEFT" then
  81.             pY = frame:GetBottom()
  82.             pX = frame:GetLeft()
  83.         elseif point == "BOTTOM" then
  84.             pY = frame:GetBottom()
  85.             pX = (frame:GetRight() + frame:GetLeft()) / 2
  86.         elseif point == "CENTER" then
  87.             pY = (frame:GetTop() + frame:GetBottom()) / 2
  88.             pX = (frame:GetRight() + frame:GetLeft()) / 2
  89.         elseif point == "LEFT" then
  90.             pY = (frame:GetTop() + frame:GetBottom()) / 2
  91.             pX = frame:GetLeft()
  92.         elseif point == "RIGHT" then
  93.             pY = (frame:GetTop() + frame:GetBottom()) / 2
  94.             pX = frame:GetRight()
  95.         else
  96.             return
  97.         end
  98.         if frame.GetEffectiveScale then
  99.             pY = pY * frame:GetEffectiveScale()
  100.             pX = pX * frame:GetEffectiveScale()
  101.         else
  102.             pY = pY * UIParent:GetEffectiveScale()
  103.             pX = pX * UIParent:GetEffectiveScale()
  104.         end
  105.     end
  106.  
  107.     if rY and rX and pY and pX then
  108.         rX = pX - rX
  109.         rY = pY - rY
  110.         if frame.GetEffectiveScale then
  111.             rY = rY / frame:GetEffectiveScale()
  112.             rX = rX / frame:GetEffectiveScale()
  113.         else
  114.             rY = rY / UIParent:GetEffectiveScale()
  115.             rX = rX / UIParent:GetEffectiveScale()
  116.         end
  117.     else
  118.         rX = 0
  119.         rY = 0
  120.     end
  121.  
  122.     --print(point, rel:GetName(), relPoint, rX, rY)
  123.     return {point, rel:GetName(), relPoint, rX, rY}
  124. end
  125.  
  126. local frame = CreateFrame("Frame", "TestFrame", UIParent)
  127. frame:SetSize(400, 200)
  128. frame:SetPoint("TOPLEFT", PlayerFrame, "BOTTOMLEFT", 0, -50)
  129. frame:SetClampedToScreen(true)
  130.  
  131. frame.backdrop = {
  132.     bgFile = "Interface\\Buttons\\WHITE8X8",
  133.     edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
  134.     tile = true,
  135.     tileSize = 16,
  136.     edgeSize = 14,
  137.     insets = {left = 3, right = 3, top = 3, bottom = 3},
  138. }
  139.  
  140. frame:SetBackdrop(frame.backdrop)
  141. frame:SetBackdropColor(0.0, 0.0, 0.0, 0.5)
  142. frame:SetBackdropBorderColor(0.3, 0.3, 0.3, 1.0)
  143.  
  144. -- Frame Hooks
  145. hooksecurefunc(frame, "SetPoint", function(self)
  146.     if self.moving then
  147.         return
  148.     end
  149.  
  150.     self.moving = true
  151.     self:SetMovable(true)
  152.  
  153.     print("SetPoint")
  154.  
  155.     local point, relativeTo, relativePoint, xOffset, yOffset = self:GetPoint(1)
  156.  
  157.     local pos = GetRelativePoint({"TOPLEFT", PlayerFrame, "BOTTOMLEFT"}, self)
  158.  
  159.     local x = math.round(pos[4])
  160.     local y = math.round(pos[5])
  161.  
  162.     self:ClearAllPoints()
  163.     self:SetPoint("TOPLEFT", PlayerFrame, "BOTTOMLEFT", x, y)
  164.  
  165.     self:SetMovable(false)
  166.     self.moving = nil
  167. end)
  168.  
  169. hooksecurefunc(frame, "StopMovingOrSizing", function(self)
  170.     self:SetMovable(true)
  171.  
  172.     print("StopMovingOrSizing")
  173.  
  174.     local point, relativeTo, relativePoint, xOffset, yOffset = self:GetPoint(1)
  175.  
  176.     local pos = GetRelativePoint({"TOPLEFT", PlayerFrame, "BOTTOMLEFT"}, self)
  177.  
  178.     local x = math.round(pos[4])
  179.     local y = math.round(pos[5])
  180.  
  181.     self:ClearAllPoints()
  182.     self:SetPoint("TOPLEFT", PlayerFrame, "BOTTOMLEFT", x, y)
  183.  
  184.     self:SetMovable(false)
  185. end)
  186.  
  187. frame:HookScript("OnSizeChanged", function(self)
  188.     self:SetSize(math.round(self:GetWidth()), math.round(self:GetHeight()))
  189. end)
  190.  
  191. -- Parent Hooks
  192. local point, relativeTo, relativePoint, xOffset, yOffset = frame:GetPoint(1)
  193.  
  194. hooksecurefunc(relativeTo, "SetPoint", function(self)
  195.     if self.moving then
  196.         return
  197.     end
  198.  
  199.     self.moving = true
  200.     self:SetMovable(true)
  201.  
  202.     print("Parent: SetPoint")
  203.  
  204.     local point, relativeTo, relativePoint, xOffset, yOffset = self:GetPoint(1)
  205.  
  206.     local pos = GetRelativePoint({"TOPLEFT", PlayerFrame, "BOTTOMLEFT"}, self)
  207.  
  208.     local x = math.round(pos[4])
  209.     local y = math.round(pos[5])
  210.  
  211.     self:ClearAllPoints()
  212.     self:SetPoint("TOPLEFT", PlayerFrame, "BOTTOMLEFT", x, y)
  213.  
  214.     self:SetMovable(false)
  215.     self.moving = nil
  216. end)
  217.  
  218. hooksecurefunc(relativeTo, "StopMovingOrSizing", function(self)
  219.     self:SetMovable(true)
  220.  
  221.     print("Parent: StopMovingOrSizing")
  222.  
  223.     local point, relativeTo, relativePoint, xOffset, yOffset = self:GetPoint(1)
  224.  
  225.     local pos = GetRelativePoint({"TOPLEFT", PlayerFrame, "BOTTOMLEFT"}, self)
  226.  
  227.     local x = math.round(pos[4])
  228.     local y = math.round(pos[5])
  229.  
  230.     self:ClearAllPoints()
  231.     self:SetPoint("TOPLEFT", PlayerFrame, "BOTTOMLEFT", x, y)
  232.  
  233.     self:SetMovable(false)
  234. end)
  235.  
  236. relativeTo:HookScript("OnSizeChanged", function(self)
  237.     local point, relativeTo, relativePoint, xOffset, yOffset = self:GetPoint(1)
  238.  
  239.     local pos = GetRelativePoint({"TOPLEFT", PlayerFrame, "BOTTOMLEFT"}, self)
  240.  
  241.     local x = math.round(pos[4])
  242.     local y = math.round(pos[5])
  243.  
  244.     self:ClearAllPoints()
  245.     self:SetPoint("TOPLEFT", PlayerFrame, "BOTTOMLEFT", x, y)
  246. end)
  247.  
  248. -- Moving and Resizing functions
  249. frame:EnableMouse(true)
  250. --frame:SetMaxResize(800, 400)
  251. frame:SetMinResize(40, 40)
  252.  
  253. frame:SetScript("OnMouseDown", function(self, button)
  254.     if button == "LeftButton" then
  255.         self:SetMovable(true)
  256.         self:StartMoving()
  257.     end
  258. end)
  259. frame:SetScript("OnMouseUp", function(self, button)
  260.     if button == "LeftButton" then
  261.         self:StopMovingOrSizing()
  262.         self:SetMovable(false)
  263.  
  264.         local point, relativeTo, relativePoint, xOffset, yOffset = self:GetPoint(1)
  265.  
  266.         local pos = GetRelativePoint({"TOPLEFT", PlayerFrame, "BOTTOMLEFT"}, self)
  267.  
  268.         local x = math.round(pos[4])
  269.         local y = math.round(pos[5])
  270.  
  271.         self:ClearAllPoints()
  272.         self:SetPoint("TOPLEFT", PlayerFrame, "BOTTOMLEFT", x, y)
  273.     end
  274. end)
  275.  
  276. frame.br = CreateFrame("Frame", nil, frame)
  277. frame.br:SetPoint("TOPLEFT", frame, "BOTTOMRIGHT", -15, 15)
  278. frame.br:SetSize(12, 12)
  279. frame.br:EnableMouse(true)
  280.  
  281. frame.br.texture = frame.br:CreateTexture(nil, "OVERLAY")
  282. frame.br.texture:SetPoint("TOPLEFT", frame.br, "TOPLEFT", 0, 0)
  283. frame.br.texture:SetSize(12, 12)
  284. frame.br.texture:SetTexture("Interface\\ChatFrame\\UI-ChatIM-SizeGrabber-Up")
  285.  
  286. frame.br:SetScript("OnEnter", function(self)
  287.     frame.br.texture:SetTexture("Interface\\ChatFrame\\UI-ChatIM-SizeGrabber-Highlight")
  288. end)
  289. frame.br:SetScript("OnLeave", function(self)
  290.     frame.br.texture:SetTexture("Interface\\ChatFrame\\UI-ChatIM-SizeGrabber-Up")
  291. end)
  292.  
  293. frame.br:SetScript("OnMouseDown", function(self, button)
  294.     if button == "LeftButton" then
  295.         frame.br.texture:SetTexture("Interface\\ChatFrame\\UI-ChatIM-SizeGrabber-Down")
  296.  
  297.         frame:SetResizable(true)
  298.         frame:StartSizing("BottomRight")
  299.     end
  300. end)
  301. frame.br:SetScript("OnMouseUp", function(self, button)
  302.     frame:StopMovingOrSizing()
  303.     frame:SetResizable(false)
  304.  
  305.     frame.br.texture:SetTexture("Interface\\ChatFrame\\UI-ChatIM-SizeGrabber-Up")
  306. end)


This time the frame is anchored to the PlayerFrame, every time you move the PlayerFrame the frame moves with it, if you position the PlayerFrame on fraction of pixes it does not matter for the frame, the frame still will be positioned pixel perfectly every time. You can also move the frame related to the player frame and it will also keep the pixel perfection that way, and also every time to resize/rescale the PlayerFrame or resize the frame itself. HOWEVER it won't keep the pixel perfection if you scale the frame itself, thats requires even more work.

I don't think ElvUI has pixel perfection, at least not a "perfect" pixel perfection. They just using a hack to set you UI scale on a number which only makes the frames pixel perfect on a 1.0 scaling, however every other scale value will be still be ugly (mostly for frames with edges).

The perfect pixel perfect scaling/resizing on any value is a lot more harder to achieve, i have such a function for my frames, however it only works on frames that you know well and you build in a proper way, it can't be generalised to work on every frame easily.

Last edited by Resike : 06-09-17 at 01:36 PM.
  Reply With Quote
06-09-17, 06:59 PM   #11
Layback_
An Onyxian Warder
Join Date: Feb 2016
Posts: 358
Originally Posted by Resike View Post
You can however thats a bit more complex, since you can never know if the relative frame is not positioned on fraction pixels, for that you have to get the relative frames (GetLeft|GetBottom|GetTop|GetRight) based on anchor points and substract those values from the actual frame's (GetLeft|GetBottom|GetTop|GetRight), and it even gets more complicated since every different anchor points need different calculations, however i have a function for that already, called GetRelativePoint:

This time the frame is anchored to the PlayerFrame, every time you move the PlayerFrame the frame moves with it, if you position the PlayerFrame on fraction of pixes it does not matter for the frame, the frame still will be positioned pixel perfectly every time. You can also move the frame related to the player frame and it will also keep the pixel perfection that way, and also every time to resize/rescale the PlayerFrame or resize the frame itself. HOWEVER it won't keep the pixel perfection if you scale the frame itself, thats requires even more work.
Whoa... That's definitely more complicated than I thought.

I gotta look through it!

Originally Posted by Resike View Post
I don't think ElvUI has pixel perfection, at least not a "perfect" pixel perfection. They just using a hack to set you UI scale on a number which only makes the frames pixel perfect on a 1.0 scaling, however every other scale value will be still be ugly (mostly for frames with edges).

The perfect pixel perfect scaling/resizing on any value is a lot more harder to achieve, i have such a function for my frames, however it only works on frames that you know well and you build in a proper way, it can't be generalised to work on every frame easily.
Hm... I see.

It seems like I've underestimated pixel perfection...

Yep, it is absolutely an horror...

Anyways, thank you so much for such a detailed explanation!
  Reply With Quote
06-10-17, 11:01 PM   #12
Gethe
RealUI Developer
 
Gethe's Avatar
Premium Member
Featured
Join Date: Sep 2008
Posts: 942
The solution I prefer for RealUI is to simply anchor frames corner-to-corner. This way you always know that it's being placed on a full pixel. (this is assuming the UI scale is pixel perfect)
__________________
Knowledge = Power; Be OP

  Reply With Quote
06-10-17, 11:42 PM   #13
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
Originally Posted by Gethe View Post
The solution I prefer for RealUI is to simply anchor frames corner-to-corner. This way you always know that it's being placed on a full pixel. (this is assuming the UI scale is pixel perfect)
But my solution works on every resolution every UIScale ratio and every scale value.

Last edited by Resike : 06-11-17 at 12:09 AM.
  Reply With Quote
06-11-17, 05:36 AM   #14
Banknorris
A Chromatic Dragonspawn
 
Banknorris's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2014
Posts: 153
Originally Posted by Resike View Post
at least not a "perfect" pixel perfection.
Originally Posted by Resike View Post
But my solution works on every resolution every UIScale ratio and every scale value.
ICD10 F42.8 detected
__________________
"In this world nothing can be said to be certain, except that fractional reserve banking is a Ponzi scheme and that you won't believe it." - Mandrill
  Reply With Quote
06-11-17, 09:24 AM   #15
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
Originally Posted by Banknorris View Post
ICD10 F42.8 detected
Well you don't have to have OCD for that (maybe just a little one :P), i just wanted a complete solution.
Lets say you have an unit frame with 204 pixel width, if the user want to scale that not a single scale value scales the width to an even number between 0.80 and 1.20 scale (which would be the most common values if you want the make your frames a bit bigger or smaller), and even if you find a scale value that would fit for the width, thats sure won't fit for the frame's heigth.

I'll make a detailed post about my solution later when i'm exam free.
  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » Having an issue with edge of backdrop being disappeared when frame's size changes

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