Thread Tools Display Modes
01-27-10, 05:37 AM   #1
nightcracker
A Molten Giant
 
nightcracker's Avatar
AddOn Author - Click to view addons
Join Date: Sep 2009
Posts: 716
LibCoreAPI

Hi all!
I'm making a library to add some more functions to the WoW API and widget API. Mainly to make your life easier, and to shorten up your code. I'm asking YOU what you want added in it, so post here! This is what I have currently(I will be editing this post):
lua Code:
  1. local metatables = {}
  2. local dummy = function() end
  3.  
  4. for key, val in pairs(_G) do
  5.     if type(val)=="table" and val.GetObjectType then
  6.         obj = val:GetObjectType()
  7.         if not metatables[obj] then
  8.             metatables[obj] = getmetatable(val).__index
  9.         end
  10.     end
  11. end
  12.  
  13. local function destroy(self)
  14.     self.Show = dummy
  15.     self:Hide()
  16.     if self.UnregisterAllEvents then
  17.         self:UnregisterAllEvents()
  18.     end
  19. end
  20.  
  21. local function fireevent(self, event, ...)
  22.     local handler = self:GetScript("OnEvent")
  23.     if handler then
  24.         handler(self, event, ...)
  25.         return true
  26.     end
  27.     return false
  28. end
  29.  
  30. local function fire(self, script, ...)
  31.     local handler = self:GetScript(script)
  32.     if handler then
  33.         handler(self, ...)
  34.         return true
  35.     end
  36.     return false
  37. end
  38.  
  39. local function lock(self)
  40.     self.ClearAllPoints = dummy
  41.     self.SetPoint = dummy
  42.     self.SetAllPoints = dummy
  43. end
  44.  
  45. local function unlock(self)
  46.     self.ClearAllPoints = nil
  47.     self.SetPoint = nil
  48.     self.SetAllPoints = nil
  49. end
  50.  
  51. local function setsize(self, w, h)
  52.     self:SetWidth(w)
  53.     self:SetHeight(h or w)
  54. end
  55.  
  56. local function getclassbycolor(r, g, b)
  57.     r, g, b = floor(r*100+.5)/100, floor(g*100+.5)/100, floor(b*100+.5)/100
  58.     for class, color in pairs(RAID_CLASS_COLORS) do
  59.         if color.r==r and color.g==g and color.b==b then
  60.             return class
  61.         end
  62.     end
  63.     return false
  64. end
  65.  
  66. local function getsize(self)
  67.     return self:GetWidth(), self:GetHeight()
  68. end
  69.  
  70. local function setclassicon(self, class)
  71.     self:SetTexture("Interface\\WorldStateFrame\\Icons-Classes")
  72.     if class then
  73.         local classcoords = CLASS_BUTTONS[class]
  74.         if classcoords then
  75.             self:SetTexCoord(unpack(classcoords))
  76.             return true
  77.         else
  78.             self:SetTexCoord(.5, .75, .5, .75)
  79.             return false
  80.         end
  81.     end
  82.     return false
  83. end
  84.  
  85. local function islocked(self)
  86.     if self.ClearAllPoints==dummy and self.SetPoint==dummy and self.SetAllPoints==dummy then
  87.         return true
  88.     end
  89.     return false
  90. end
  91.  
  92. local function isdestroyed(self)
  93.     if self.Show==dummy and not self:IsShown() then
  94.         return true
  95.     end
  96.     return false
  97. end
  98.  
  99. local function toggle(self)
  100.     if self:IsShown() then
  101.         self:Hide()
  102.         return false
  103.     end
  104.     self:Show()
  105.     return true
  106. end
  107.  
  108. local function setshown(self, show)
  109.     if show then
  110.         self:Show()
  111.     else
  112.         self:Hide()
  113.     end
  114. end
  115.  
  116. for key, val in pairs(metatables) do
  117.     if val.Hide then -- Region object
  118.         val.Destroy = destroy
  119.         val.IsDestroyed = isdestroyed
  120.         val.SetSize = setsize
  121.         val.GetSize = getsize
  122.         val.Lock = lock
  123.         val.Unlock = unlock
  124.         val.IsLocked = islocked
  125.         val.Toggle = toggle
  126.         val.SetShown = setshown
  127.     end
  128.     if val.RegisterEvent then -- Frame object
  129.         val.FireEvent = fireevent
  130.     end
  131.     if val.GetScript then -- Any object with scripts
  132.         val.Fire = fire
  133.     end
  134.     if val.SetTexture then -- Texture object
  135.         val.SetClassIcon = setclassicon
  136.     end
  137. end
  138.  
  139. GetClassByColor = getclassbycolor

This adds the following API functions:
Code:
GetClassByColor(red, green, blue)
Returns the class associated with the color.
And the following API Widget functions:
Code:
Region:Destroy()
Permanently hides the region and unregisters events if associated.

Region:IsDestroyed()
Returns true if the region is destroyed, otherwise false.

Region:Lock()
Blocks all attempts of moving this region until it's unlocked.

Region:Unlock()
Unlocks the frame from the above function.

Region:IsLocked()
Returns true if the region is locked, otherwise false.

Region:SetSize(width, [height])
Sets the width and height of this region, if only one parameter is given both width and height will be set to the same value. Example: Region:SetSize(10, 15) sets the width to 10 and height to 15 while Region:SetSize(15) sets the width and height to 15.

Region:GetSize()
Returns the width and height of the region. Example: local width, height = Region:GetSize()

Region:Toggle()
Hides the region if shown, shows the region if hidden. Returns true if the region is now shown, false if the region is now hidden.

Region:SetShown(show)
If show is a true value(any value except nil and false) then the region is shown, else the region is hidden.

Frame:FireEvent(event, ...)
Fires the event handler of the frame with the parameter "event" as the event, and ... the parameters. The ... variable means there could be as many parameters as you want. You must not give the "self" variable in the parameters(this is done automaticly). Returns true if the handler has been executed, false if not.

Frame:Fire(script, ...)
Fires the event handler of the frame for the script "script" with parameters "...". For example, Frame:Fire("OnUpdate", 2) will run the OnUpdate handler for the frame as if 2 seconds have elapsed. Don't give the "self" variable in the parameters, this is done automaticly. Returns true if the handler has been executed, false if not.

Texture:SetClassIcon(class)
Set's the texture of this texture object to the class icon of the parameter given. The class parameter MUST be in the english version capitalized, not the localized version! If an invalid class is given the texture will be set to transparent. Example: Texture:SetClassIcon("WARRIOR") will set the texture of the object to the class icon of a warrior. No textures except blizzard's have been used for this function. Returns true if the class icon was found and set, false if not.
__________________
Three things are certain,
Death, taxes and site not found,
You, victim of one.

Last edited by nightcracker : 01-27-10 at 08:45 AM.
  Reply With Quote
01-27-10, 05:52 AM   #2
nightcracker
A Molten Giant
 
nightcracker's Avatar
AddOn Author - Click to view addons
Join Date: Sep 2009
Posts: 716
Woops, this should be in Pre-Beta Interfaces/Scripts, can someone move it please?
__________________
Three things are certain,
Death, taxes and site not found,
You, victim of one.
  Reply With Quote
01-27-10, 06:37 AM   #3
xConStruct
A Chromatic Dragonspawn
 
xConStruct's Avatar
AddOn Author - Click to view addons
Join Date: May 2008
Posts: 199
Code:
Region:SetShown(shown)
    if shown then
        self:Show()
    else
       self:Hide()
    end
end
This often bothered me

And I would suggest to make getter-functions for your new Set() ones:
- destroyed = Region:IsDestroyed()
- locked = Region:IsLocked()
- width, height = Region:GetSize()

And try to provide return values as often as possible to show if it was successful or not.
- success = Frame:FireEvent()
- success = Frame:Fire()
- success = Texture:SetClassIcon()
__________________
« Website | GitHub »

Oh hai!

Last edited by xConStruct : 01-27-10 at 06:40 AM. Reason: dry-coding, you know :/
  Reply With Quote
01-27-10, 06:45 AM   #4
nightcracker
A Molten Giant
 
nightcracker's Avatar
AddOn Author - Click to view addons
Join Date: Sep 2009
Posts: 716
Originally Posted by Cargor View Post
Code:
Region:SetShown(shown)
    if shown then
        self:Show()
    else
       self:Hide()
    end
end
This often bothered me

And I would suggest to make getter-functions for your new Set() ones:
- destroyed = Region:IsDestroyed()
- locked = Region:IsLocked()
- width, height = Region:GetSize()

And try to provide return values as often as possible to show if it was successful or not.
- success = Frame:FireEvent()
- success = Frame:Fire()
- success = Texture:SetClassIcon()
Nice to see some interest, adding those! Also I'm adding a :Toggle() script.

EDIT: Added!
__________________
Three things are certain,
Death, taxes and site not found,
You, victim of one.

Last edited by nightcracker : 01-27-10 at 07:16 AM.
  Reply With Quote
01-27-10, 07:24 AM   #5
nightcracker
A Molten Giant
 
nightcracker's Avatar
AddOn Author - Click to view addons
Join Date: Sep 2009
Posts: 716
Should I loop _G like this for gathering all metatables, or should I run this once, write the names down, and always use these(subject to changes/deletion of frames by blizzard)?

lua Code:
  1. local metatables = {}
  2. for key, val in pairs(_G) do
  3.     if type(val)=="table" and val.GetObjectType then
  4.         obj = val:GetObjectType()
  5.         if not metatables[obj] then
  6.             metatables[obj] = getmetatable(val).__index
  7.         end
  8.     end
  9. end
__________________
Three things are certain,
Death, taxes and site not found,
You, victim of one.
  Reply With Quote
01-27-10, 08:07 AM   #6
Slakah
A Molten Giant
 
Slakah's Avatar
AddOn Author - Click to view addons
Join Date: Aug 2007
Posts: 863
Originally Posted by nightcracker View Post
Should I loop _G like this for gathering all metatables, or should I run this once, write the names down, and always use these(subject to changes/deletion of frames by blizzard)?

lua Code:
  1. local metatables = {}
  2. for key, val in pairs(_G) do
  3.     if type(val)=="table" and val.GetObjectType then
  4.         obj = val:GetObjectType()
  5.         if not metatables[obj] then
  6.             metatables[obj] = getmetatable(val).__index
  7.         end
  8.     end
  9. end
You don't need to at all, all frames of the same type share the same metatable so muck about with one and you'll muck about with all of them (although there might be some frames which don't i.e. the ChatFrames)

But really imo a library shouldn't add methods to addons frames which don't use it.

Last edited by Slakah : 01-27-10 at 08:17 AM.
  Reply With Quote
01-28-10, 06:54 AM   #7
nightcracker
A Molten Giant
 
nightcracker's Avatar
AddOn Author - Click to view addons
Join Date: Sep 2009
Posts: 716
Originally Posted by Slakah View Post
I never suggested that frames of different types have the same metatable:


Anyway looping through a few frame types would be a lot easier than going through _G.
Finally the answer :P

Originally Posted by nightcracker View Post
Should I loop _G like this for gathering all metatables, or should I run this once, write the names down, and always use these(subject to changes/deletion of frames by blizzard)?

lua Code:
  1. local metatables = {}
  2. for key, val in pairs(_G) do
  3.     if type(val)=="table" and val.GetObjectType then
  4.         obj = val:GetObjectType()
  5.         if not metatables[obj] then
  6.             metatables[obj] = getmetatable(val).__index
  7.         end
  8.     end
  9. end
__________________
Three things are certain,
Death, taxes and site not found,
You, victim of one.
  Reply With Quote
01-28-10, 02:58 PM   #8
Mikord
A Theradrim Guardian
AddOn Author - Click to view addons
Join Date: Jul 2006
Posts: 61
I really wish addon authors would stop mucking about with the global environment. It's never a good idea. I've had to fix several "bugs" that are due to this type of stuff and frankly, it is frustrating.

You asked for an example earlier. Here is some example code that I've seen in a legitimate addon before that your changes would break:

Lua Code:
  1. local frame=CreateFrame("Frame")
  2.  
  3. '...
  4.  
  5. if someEventHasHappened then frame.Fire = true end
  6.  
  7. ' ...Later in the code
  8.  
  9. ' Check if some event should be fired
  10. if frame.Fire then DoSomethingUseful() end

Because you've added a Fire entry that would be detected via the metatable, the check would always pass regardless and you've just hosed this code. It would have to be changed to use rawget. Making others code around you is not very responsible.

Also, what if I were to come behind you, decide to be clever too and create a metatable of my own with some functions *I* think are useful? In the process I blow away your metatables to use my own. Now every addon that makes use of your extensions will break.

I hope you can see why modifying the global environment is just a bad idea. Please don't do it.


Edit:

I see haste beat me to it above. Using LibStub with a specialized CreateFrame call is a much better approach.

Everybody using the global CreateFrame is unaffected as it should be and those who want to use your extensions have an easy way to do so.

Last edited by Mikord : 01-28-10 at 03:54 PM.
  Reply With Quote
01-28-10, 06:58 PM   #9
Saiket
A Chromatic Dragonspawn
 
Saiket's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2008
Posts: 154
Feels like I'm forum muted.
  Reply With Quote
01-29-10, 12:39 AM   #10
nightcracker
A Molten Giant
 
nightcracker's Avatar
AddOn Author - Click to view addons
Join Date: Sep 2009
Posts: 716
My new system(which is immume to frame.Fire):
lua Code:
  1. local version = 1.0
  2.  
  3. local metatables, registered = {}, {}
  4. local noop = function() end
  5.  
  6. if LibCoreAPI then if LibCoreAPI.version<version then registered=LibCoreAPI.RegisteredAddons else return end end
  7.  
  8. for key, val in pairs(_G) do
  9.     if type(val)=="table" and val.GetObjectType then
  10.         obj = val:GetObjectType()
  11.         if not metatables[obj] then
  12.             metatables[obj] = getmetatable(val).__index
  13.         end
  14.     end
  15. end
  16.  
  17. local function registeraddon()
  18.     registered[gsub(debugstack(2), ".*\\(.+)\\.+", "%1")] = true
  19. end
  20.  
  21. local function destroy(self)
  22.     self.Show = noop
  23.     self:Hide()
  24.     if self.UnregisterAllEvents then
  25.         self:UnregisterAllEvents()
  26.     end
  27. end
  28.  
  29. local function fireevent(self, event, ...)
  30.     local handler = self:GetScript("OnEvent")
  31.     if handler then
  32.         handler(self, event, ...)
  33.         return true
  34.     end
  35.     return false
  36. end
  37.  
  38. local function fire(self, script, ...)
  39.     local handler = self:GetScript(script)
  40.     if handler then
  41.         handler(self, ...)
  42.         return true
  43.     end
  44.     return false
  45. end
  46.  
  47. local function lock(self)
  48.     self.ClearAllPoints = noop
  49.     self.SetPoint = noop
  50.     self.SetAllPoints = noop
  51. end
  52.  
  53. local function unlock(self)
  54.     self.ClearAllPoints = nil
  55.     self.SetPoint = nil
  56.     self.SetAllPoints = nil
  57. end
  58.  
  59. local function setsize(self, w, h)
  60.     self:SetWidth(w)
  61.     self:SetHeight(h or w)
  62. end
  63.  
  64. local function getclassbycolor(r, g, b)
  65.     r, g, b = floor(r*100+.5)/100, floor(g*100+.5)/100, floor(b*100+.5)/100
  66.     for class, color in pairs(RAID_CLASS_COLORS) do
  67.         if color.r==r and color.g==g and color.b==b then
  68.             return class
  69.         end
  70.     end
  71.     return false
  72. end
  73.  
  74. local function getsize(self)
  75.     return self:GetWidth(), self:GetHeight()
  76. end
  77.  
  78. local function setclassicon(self, class)
  79.     self:SetTexture("Interface\\WorldStateFrame\\Icons-Classes")
  80.     if class then
  81.         local classcoords = CLASS_BUTTONS[class]
  82.         if classcoords then
  83.             self:SetTexCoord(unpack(classcoords))
  84.             return true
  85.         else
  86.             self:SetTexCoord(.5, .75, .5, .75)
  87.             return false
  88.         end
  89.     end
  90.     return false
  91. end
  92.  
  93. local function islocked(self)
  94.     if self.ClearAllPoints==noop and self.SetPoint==noop and self.SetAllPoints==noop then
  95.         return true
  96.     end
  97.     return false
  98. end
  99.  
  100. local function isdestroyed(self)
  101.     if self.Show==noop and not self:IsShown() then
  102.         return true
  103.     end
  104.     return false
  105. end
  106.  
  107. local function toggle(self)
  108.     if self:IsShown() then
  109.         self:Hide()
  110.         return false
  111.     end
  112.     self:Show()
  113.     return true
  114. end
  115.  
  116. local function setshown(self, show)
  117.     if show then
  118.         self:Show()
  119.     else
  120.         self:Hide()
  121.     end
  122. end
  123.  
  124. local methods = {
  125.     Destroy = destroy,
  126.     IsDestroyed = isdestroyed,
  127.     SetSize = setsize,
  128.     GetSize = getsize,
  129.     Lock = lock,
  130.     Unlock = unlock,
  131.     IsLocked = islocked,
  132.     Toggle = toggle,
  133.     SetShown = setshown,
  134.     FireEvent = fireevent,
  135.     Fire = fire,
  136.     SetClassIcon = setclassicon,
  137. }
  138.  
  139. local dependencies = {
  140.     Destroy = "Hide",
  141.     IsDestroyed = "Hide",
  142.     SetSize = "Hide",
  143.     GetSize = "Hide",
  144.     Lock = "Hide",
  145.     Unlock = "Hide",
  146.     IsLocked = "Hide",
  147.     Toggle = "Hide",
  148.     SetShown = "Hide",
  149.     FireEvent = "RegisterEvent",
  150.     Fire = "GetScript",
  151.     SetClassIcon = "SetTexture",
  152. }
  153.  
  154. local mt = {
  155.     __index = function(tab, func)
  156.         return registered[gsub(debugstack(2), ".*\\(.+)\\.+", "%1")] and methods[func] or nil
  157.     end
  158. }
  159.  
  160. for key, val in pairs(metatables) do
  161.     setmetatable(val, mt)
  162. end
  163.  
  164. LibCoreAPI = {
  165.     GetClassByColor = getclassbycolor,
  166.     Metatables = metatables,
  167.     RegisteredAddons = registered,
  168.     version = version,
  169. }
  170.  
  171. setmetatable(LibCoreAPI, {
  172.     __call = registeraddon,
  173. })

If an addon calls LibCoreAPI() then it get's whitelisted and frameestroy() will return the correct function. If it's not whitelisted then frame.Fire will return an not found error.
__________________
Three things are certain,
Death, taxes and site not found,
You, victim of one.
  Reply With Quote
01-29-10, 12:56 PM   #11
nightcracker
A Molten Giant
 
nightcracker's Avatar
AddOn Author - Click to view addons
Join Date: Sep 2009
Posts: 716
OK, I screwed the metatables, if I use the above method then it taints the secure functions. LibStub it is!

The first uploaded BETA: http://www.wowinterface.com/download...reAPIBETA.html
__________________
Three things are certain,
Death, taxes and site not found,
You, victim of one.
  Reply With Quote

WoWInterface » AddOns, Compilations, Macros » Alpha/Beta AddOns and Compilations » LibCoreAPI


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