Quantcast
How to add a thin border to a frame? - WoWInterface
Thread Tools Display Modes
12-07-20, 01:55 AM   #1
Zax
A Flamescale Wyrmkin
AddOn Author - Click to view addons
Join Date: Aug 2006
Posts: 107
How to add a thin border to a frame?

Hello,

Is there a simple way to draw/add a thin border to a frame, without any .tga file?
Something like CSS attribute border: 1px solid #00ff00

I tried with Backdrop's edgeFile with some built-in texture files but the result is not accurate (the border is not well drawn), at least with small frames like buttons.

My final goal is to write a function like .addBorder(frame, borderWidth, borderColor)
  Reply With Quote
12-07-20, 12:03 PM   #2
Xrystal
nUI Maintainer
 
Xrystal's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Feb 2006
Posts: 5,638
Look at one of the preset backdrop examples that are used with the built in frames.
https://www.townlong-yak.com/framexml/live/Backdrop.lua

You may have to look at the inset value as well.

Find a blizzard frame that does something similar to what you want to do and see which of the backdrops they have set up for it. And then go from there.
__________________
  Reply With Quote
12-08-20, 06:17 AM   #3
Zax
A Flamescale Wyrmkin
AddOn Author - Click to view addons
Join Date: Aug 2006
Posts: 107
Very interesting link, Xrystal.
Thank you.
  Reply With Quote
12-12-20, 02:11 AM   #4
Walkerbo
A Flamescale Wyrmkin
 
Walkerbo's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2010
Posts: 127
Just to piggyback onto Xrystal; here is a small sample of frame templates.

Options box template has the finest line, so that may be a great place to start..
__________________
"As someone once told me, frames are just special types of tables, and tables are special types of pointers."
Fizzlemizz
  Reply With Quote
12-12-20, 12:35 PM   #5
Zax
A Flamescale Wyrmkin
AddOn Author - Click to view addons
Join Date: Aug 2006
Posts: 107
Nice
Thank you.
  Reply With Quote
12-12-20, 02:27 PM   #6
Kanegasi
A Molten Giant
 
Kanegasi's Avatar
AddOn Author - Click to view addons
Join Date: Apr 2007
Posts: 565
If you want something simple and direct, this is what I use to add a 1pixel black border around my chat frame with a single pixel missing at the corners:

Lua Code:
  1. local frame = frameYouWantToAddBordersTo
  2.  
  3. local frameborder=CreateFrame("frame",nil,frame)
  4. frameborder:SetAllPoints(frame)
  5. frameborder:SetFrameStrata("BACKGROUND")
  6. frameborder:SetFrameLevel(1)
  7. frameborder.left=frameborder:CreateTexture(nil,"BORDER")
  8. frameborder.left:SetPoint("BOTTOMLEFT",frameborder,"BOTTOMLEFT",-2,-1)
  9. frameborder.left:SetPoint("TOPRIGHT",frameborder,"TOPLEFT",-1,1)
  10. frameborder.left:SetColorTexture(0,0,0,1)
  11. frameborder.right=frameborder:CreateTexture(nil,"BORDER")
  12. frameborder.right:SetPoint("BOTTOMLEFT",frameborder,"BOTTOMRIGHT",1,-1)
  13. frameborder.right:SetPoint("TOPRIGHT",frameborder,"TOPRIGHT",2,1)
  14. frameborder.right:SetColorTexture(0,0,0,1)
  15. frameborder.top=frameborder:CreateTexture(nil,"BORDER")
  16. frameborder.top:SetPoint("BOTTOMLEFT",frameborder,"TOPLEFT",-1,1)
  17. frameborder.top:SetPoint("TOPRIGHT",frameborder,"TOPRIGHT",1,2)
  18. frameborder.top:SetColorTexture(0,0,0,1)
  19. frameborder.bottom=frameborder:CreateTexture(nil,"BORDER")
  20. frameborder.bottom:SetPoint("BOTTOMLEFT",frameborder,"BOTTOMLEFT",-1,-1)
  21. frameborder.bottom:SetPoint("TOPRIGHT",frameborder,"BOTTOMRIGHT",1,-2)
  22. frameborder.bottom:SetColorTexture(0,0,0,1)

A blank "background" container with four black textures anchored to the four corners. With the way this lays out, these lines rest right on the edges of the parent frame, leaving the blank corners clear from the parent frame's own background. Attached is a screenshot of my chatframes. I repeat this code for each chatframe separately.
Attached Thumbnails
Click image for larger version

Name:	Untitled.png
Views:	164
Size:	194.5 KB
ID:	9551  
  Reply With Quote
12-14-20, 02:22 AM   #7
Zax
A Flamescale Wyrmkin
AddOn Author - Click to view addons
Join Date: Aug 2006
Posts: 107
Interesting trick! Thank you Kanegasi.

I tried this, but the result is sometime not very accurate:
Code:
-- params
local borderColor = {1, 1, 1}
local borderWidth = 1
--
if (not frame.SetBackdrop) then Mixin(frame, BackdropTemplateMixin) end
frame.backdrop = {
	edgeFile = "Interface\\Buttons\\WHITE8x8",
	tileEdge = false,
	edgeSize = borderWidth,
	insets = {left = borderWidth, right = borderWidth, top = borderWidth, bottom = borderWidth},
}
frame:SetBackdrop(frame.backdrop)
frame:SetBackdropBorderColor(borderColor[1], borderColor[2], borderColor[3], 1)
  Reply With Quote
12-14-20, 03:52 AM   #8
runamonk
A Theradrim Guardian
 
runamonk's Avatar
AddOn Author - Click to view addons
Join Date: Dec 2007
Posts: 61
The code you tested is correct; I'm guessing you've run into what I've run into and sometimes it's a pixel bigger or smaller than it should be in some places while in others it's perfect?
  Reply With Quote
12-14-20, 07:45 AM   #9
Zax
A Flamescale Wyrmkin
AddOn Author - Click to view addons
Join Date: Aug 2006
Posts: 107
Originally Posted by runamonk View Post
sometimes it's a pixel bigger or smaller than it should be in some places while in others it's perfect?
Yes, that's what happen with a 1px border width: some borders are sometimes drawn with 2px.
  Reply With Quote
12-14-20, 09:40 AM   #10
runamonk
A Theradrim Guardian
 
runamonk's Avatar
AddOn Author - Click to view addons
Join Date: Dec 2007
Posts: 61
I have the same issue. I draw lots of boxes (bags/items in the bags) and even with changing the scaling I could never get it draw everything perfect. Super annoying.
  Reply With Quote
12-14-20, 03:54 PM   #11
jeffy162
A Pyroguard Emberseer
 
jeffy162's Avatar
AddOn Author - Click to view addons
Join Date: May 2009
Posts: 2,364
DISCLAIMERB: I might not use the correct terms, but, this has happened to me also.

I had this issue with one of my laptops - turned out that it was just not "pixel perfect", only I didn't know that until I got a new laptop and everything (all of the borders and such) were perfect. I don't think that is your problem, though. It's my understanding that WoW's parent company has fixed that particular problem. But, I could always be wrong.

In my defense I must tell you that I'm 67 years of age and live in an assisted living facility, and I haven't played WoW in four and a half years and I don't believe I ever will again.
__________________
Ahhhh, the vagueries of the aging mind. Wait.... What was I saying?


Carbonite <----- GitHub main module (Maps ONLY) download link. The other modules are also available on GitHub.
Carbonite-CLASSIC<----- GitHub link to Carbonite Classic. Thanks to ircdirk for this!
  Reply With Quote
12-14-20, 04:06 PM   #12
Fizzlemizz
I did that?
 
Fizzlemizz's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Dec 2011
Posts: 1,418
Something else to try:
Lua Code:
  1. local function CreateBorder(self)
  2.     if not self.borders then
  3.         self.borders = {}
  4.         for i=1, 4 do
  5.             self.borders[i] = self:CreateLine(nil, "BACKGROUND", nil, 0)
  6.             local l = self.borders[i]
  7.             l:SetThickness(1)
  8.             l:SetColorTexture(1, 1, 0, 1)
  9.             if i==1 then
  10.                 l:SetStartPoint("TOPLEFT")
  11.                 l:SetEndPoint("TOPRIGHT")
  12.             elseif i==2 then
  13.                 l:SetStartPoint("TOPRIGHT")
  14.                 l:SetEndPoint("BOTTOMRIGHT")
  15.             elseif i==3 then
  16.                 l:SetStartPoint("BOTTOMRIGHT")
  17.                 l:SetEndPoint("BOTTOMLEFT")
  18.             else
  19.                 l:SetStartPoint("BOTTOMLEFT")
  20.                 l:SetEndPoint("TOPLEFT")
  21.             end
  22.         end
  23.     end
  24. end
  25.  
  26. local f = CreateFrame("Frame")
  27. f:SetSize(40, 40)
  28. f:SetPoint("CENTER")
  29. f.bg = f:CreateTexture()
  30. f.bg:SetAllPoints()
  31. f.bg:SetTexture("Interface/BUTTONS/WHITE8X8")
  32. f.bg:SetVertexColor(0, 0, 0)
  33. f:SetResizable(true)
  34. f:EnableMouse(true)
  35. f:RegisterForDrag("LeftButton")
  36. f:SetScript("OnDragStart", function(self)
  37.     self:StartSizing("BOTTOMRIGHT")
  38. end)
  39. f:SetScript("OnDragStop", function(self)
  40.     self:StopMovingOrSizing()
  41. end)
  42.  
  43. CreateBorder(f)

It's along the same lines as Kanegasi's solution.
__________________
Fizzlemizz
Maintainer of Discord Unit Frames and Discord Art.
Author of FauxMazzle, FauxMazzleHUD and Move Pad Plus.

Last edited by Fizzlemizz : 12-14-20 at 05:11 PM.
  Reply With Quote
12-15-20, 02:32 AM   #13
Zax
A Flamescale Wyrmkin
AddOn Author - Click to view addons
Join Date: Aug 2006
Posts: 107
Maybe it should be intensively tested but Fizzlemizz's solution seems perfect

Though, I don't understand why corners are rounded (it's obvious with thickness > 1)

Last edited by Zax : 12-15-20 at 02:40 AM.
  Reply With Quote
12-15-20, 02:10 PM   #14
Kanegasi
A Molten Giant
 
Kanegasi's Avatar
AddOn Author - Click to view addons
Join Date: Apr 2007
Posts: 565
If you're using the backdrop method, the API behind that is called "NineSlice". This is a method of creating resizeable textured frames of nine pieces, consisting of four static corners, four repeatable edge textures, and a repeatable background. The corners are rounded because they are separate textures, the roundness not noticeable at really tiny sizes.
  Reply With Quote
12-16-20, 03:03 AM   #15
Zax
A Flamescale Wyrmkin
AddOn Author - Click to view addons
Join Date: Aug 2006
Posts: 107
Considring Fizzlemizz's script, is there a way to modify border color of an existing border, previously created with his script?

Lua Code:
  1. local function CreateBorder(self)
  2.     if not self.borders then
  3.         self.borders = {}
  4.         for i=1, 4 do
  5.             self.borders[i] = self:CreateLine(nil, "BACKGROUND", nil, 0)
  6.             local l = self.borders[i]
  7.             l:SetThickness(1)
  8.             l:SetColorTexture(1, 1, 0, 1)
  9.             if i==1 then
  10.                 l:SetStartPoint("TOPLEFT")
  11.                 l:SetEndPoint("TOPRIGHT")
  12.             elseif i==2 then
  13.                 l:SetStartPoint("TOPRIGHT")
  14.                 l:SetEndPoint("BOTTOMRIGHT")
  15.             elseif i==3 then
  16.                 l:SetStartPoint("BOTTOMRIGHT")
  17.                 l:SetEndPoint("BOTTOMLEFT")
  18.             else
  19.                 l:SetStartPoint("BOTTOMLEFT")
  20.                 l:SetEndPoint("TOPLEFT")
  21.             end
  22.         end
  23.     end
  24. end
  25.  
  26. local f = CreateFrame("Frame")
  27. f:SetSize(40, 40)
  28. f:SetPoint("CENTER")
  29. f.bg = f:CreateTexture()
  30. f.bg:SetAllPoints()
  31. f.bg:SetTexture("Interface/BUTTONS/WHITE8X8")
  32. f.bg:SetVertexColor(0, 0, 0)
  33. f:SetResizable(true)
  34. f:EnableMouse(true)
  35. f:RegisterForDrag("LeftButton")
  36. f:SetScript("OnDragStart", function(self)
  37.     self:StartSizing("BOTTOMRIGHT")
  38. end)
  39. f:SetScript("OnDragStop", function(self)
  40.     self:StopMovingOrSizing()
  41. end)
  42.  
  43. CreateBorder(f)
  Reply With Quote
12-16-20, 07:51 AM   #16
Kanegasi
A Molten Giant
 
Kanegasi's Avatar
AddOn Author - Click to view addons
Join Date: Apr 2007
Posts: 565
The textures are stored as indexes in the borders key of the parent frame. If you were to do ZaxBorders=CreateFrame("frame") instead of local f=CreateFrame("frame"), you can change the colors like so:

Lua Code:
  1. for i=1,4 do
  2.     ZaxBorders.borders[i]:SetColorTexture(r,g,b,a)
  3. end

Also, the way the code is currently ordered, 1 is top, 2 is right, 3 is bottom, and 4 is left. You can change the color of, say, just the bottom with this:

ZaxBorders.borders[3]:SetColorTexture(r,g,b,a)
  Reply With Quote
12-16-20, 09:52 AM   #17
Fizzlemizz
I did that?
 
Fizzlemizz's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Dec 2011
Posts: 1,418
Again, the same as Kanegasi but slightly different in order to bake the border colouring into your created frames:

Lua Code:
  1. local function ColorBorders(self, r, g, b, a)
  2.     for i=1, 4 do
  3.         self.borders[i]:SetColorTexture(r, g, b, a and a or 1)
  4.     end    
  5. end
  6.  
  7. local function CreateBorderFrame(name, thickness)
  8.     local f = CreateFrame("Frame", name)
  9.     f:SetSize(40, 40)
  10.     f.bg = f:CreateTexture()
  11.     f.bg:SetAllPoints()
  12.     f.bg:SetTexture("Interface/BUTTONS/WHITE8X8")
  13.     f.bg:SetVertexColor(0, 0, 0)
  14.     f:SetResizable(true)
  15.     f:EnableMouse(true)
  16.     f:RegisterForDrag("LeftButton")
  17.     f:SetScript("OnDragStart", function(self)
  18.         self:StartSizing("BOTTOMRIGHT")
  19.     end)
  20.     f:SetScript("OnDragStop", function(self)
  21.         self:StopMovingOrSizing()
  22.     end)
  23.     f.SetBorderColor = ColorBorders
  24.     f.borders = {}
  25.     local offset = (thickness/2)
  26.     for i=1, 4 do
  27.         f.borders[i] = f:CreateLine(nil, "BACKGROUND", nil, 0)
  28.         local l = f.borders[i]
  29.         l:SetThickness(thickness)
  30.         l:SetColorTexture(1, 1, 0, 1)
  31.         if i==1 then
  32.             l:SetStartPoint("TOPLEFT", -offset, 0)
  33.             l:SetEndPoint("TOPRIGHT", offset, 0)
  34.         elseif i==2 then
  35.             l:SetStartPoint("TOPRIGHT", 0, offset)
  36.             l:SetEndPoint("BOTTOMRIGHT", 0, -offset)
  37.         elseif i==3 then
  38.             l:SetStartPoint("BOTTOMRIGHT", offset, 0)
  39.             l:SetEndPoint("BOTTOMLEFT", -offset, 0)
  40.         else
  41.             l:SetStartPoint("BOTTOMLEFT", 0, -offset)
  42.             l:SetEndPoint("TOPLEFT", 0, offset)
  43.         end
  44.     end
  45.     return f
  46. end
  47.  
  48. local f = CreateBorderFrame("ZaxFrame1", 1)
  49. f:SetPoint("RIGHT", UIParent, "CENTER", -20, 0)
  50. f = CreateBorderFrame("ZaxFrame2", 18)
  51. f:SetPoint("LEFT", UIParent, "CENTER", 20, 0)
  52. ZaxFrame2:SetBorderColor(0.2, 0.5, 0.8)
__________________
Fizzlemizz
Maintainer of Discord Unit Frames and Discord Art.
Author of FauxMazzle, FauxMazzleHUD and Move Pad Plus.

Last edited by Fizzlemizz : 12-16-20 at 09:57 AM.
  Reply With Quote
12-16-20, 10:17 AM   #18
Zax
A Flamescale Wyrmkin
AddOn Author - Click to view addons
Join Date: Aug 2006
Posts: 107
Great
Thank you very much Fizzlemizz and Kanegasi for your scripts, and also for your time and patience.
  Reply With Quote
12-19-20, 02:19 AM   #19
Spyro
A Fallenroot Satyr
 
Spyro's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2011
Posts: 23
Originally Posted by Kanegasi View Post
If you're using the backdrop method, the API behind that is called "NineSlice". This is a method of creating resizeable textured frames of nine pieces, consisting of four static corners, four repeatable edge textures, and a repeatable background. The corners are rounded because they are separate textures, the roundness not noticeable at really tiny sizes.
Didn't know the backdrop borders have parentkeys.

Do the corners have parentkeys too?

Currently I'm accesing them with GetRegions() lol.
  Reply With Quote
12-19-20, 07:26 AM   #20
Vrul
A Scalebane Royal Guard
 
Vrul's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2007
Posts: 404
Originally Posted by Spyro View Post
Didn't know the backdrop borders have parentkeys.

Do the corners have parentkeys too?

Currently I'm accesing them with GetRegions() lol.
These are the default names:
TopLeftCorner
TopRightCorner
BottomLeftCorner
BottomRightCorner
TopEdge
BottomEdge
LeftEdge
RightEdge
Center

However, the pieces are accessed via:
Lua Code:
  1. local function GetNineSlicePiece(container, pieceName)
  2.     if container.GetNineSlicePiece then
  3.         local piece = container:GetNineSlicePiece(pieceName);
  4.         if piece then
  5.             return piece, true;
  6.         end
  7.     end
  8.  
  9.     local piece = container[pieceName];
  10.     if piece then
  11.         return piece, true;
  12.     else
  13.         piece = container:CreateTexture()
  14.         container[pieceName] = piece;
  15.         return piece, false;
  16.     end
  17. end

The only two places I found using GetNineSlicePiece were for Blizzard_BFAMissionUI and Blizzard_CovenantMissionUI which had keys:
TopLeftCorner
TopRightCorner
BotLeftCorner
BotRightCorner
TopBorder
BottomBorder
LeftBorder
RightBorder
  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » How to add a thin border to a frame?

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