Thread Tools Display Modes
07-27-14, 08:00 AM   #1
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
Custom Scripts

I'm not very experience in callbacks, but is it possible to create a custom scripts for a frame which will get triggered just like the "OnShow"/"OnHide" ones but i manage what will trigger them?
  Reply With Quote
07-27-14, 09:58 AM   #2
Malakahh
An Aku'mai Servant
AddOn Author - Click to view addons
Join Date: Jun 2009
Posts: 30
If I understand you correctly, you're looking to create custom events?
  Reply With Quote
07-27-14, 10:12 AM   #3
zork
A Pyroguard Emberseer
 
zork's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2008
Posts: 1,740
Well. The only events you can rely on are the events provided by the API.

If there is no event in the API that is triggering whatever you need to ask for you can fall back to an OnUpdate script checking stuff every now and then.

And there is :HookScript. http://www.wowwiki.com/API_Frame_HookScript
__________________
| Simple is beautiful.
| WoWI AddOns | GitHub | Zork (WoW)

"I wonder what the non-pathetic people are doing tonight?" - Rajesh Koothrappali (The Big Bang Theory)
  Reply With Quote
07-27-14, 11:54 AM   #4
Dridzt
A Pyroguard Emberseer
 
Dridzt's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2005
Posts: 1,360
You can fire custom events using AceEvent-3.0 or even simpler with Callbackhandler-1.0
  Reply With Quote
07-27-14, 02:33 PM   #5
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
I have a total custom dropdown, each time the user changes it's value, i would like to update it's propesions, however there are more dropdowns created by the same template, so i need something like the OnValueChanged script for sliders.

The only workaround i managed to pull out, is to hide/show a totally irrelevant invisible frame and listen it's OnShow/OnHide. But it's sounds like a pretty dumb solution.

Last edited by Resike : 07-27-14 at 02:59 PM.
  Reply With Quote
07-27-14, 07:39 PM   #6
kurapica.igas
A Chromatic Dragonspawn
Join Date: Aug 2011
Posts: 152
Well, if you only need one event handler for one frame's event, it's simple to do it , just add one method to your frame, like :

Lua Code:
  1. ------------------------------
  2. -- Template part
  3. ------------------------------
  4. local function Fire(self, event, ...)
  5.     return type(self[event]) == "function" and self[event](self, ...)
  6. end
  7.  
  8. local function OnClick(self)
  9.     return self.Parent:Fire("OnValueChanged", self:GetID())
  10. end
  11.  
  12. function CreateDropDownMenu( ... )
  13.     local menu = CreateFrame("Frame", ...)
  14.  
  15.     -- Give it a new method
  16.     menu.Fire = Fire
  17.  
  18.     -- Create menu buttons
  19.     for i = 1, 10 do
  20.         local btn = CreateFrame("Button", nil, menu)
  21.         btn:SetID(i)
  22.         btn.Parent = menu
  23.  
  24.         btn:SetScript("OnClick", OnClick)
  25.     end
  26.  
  27.     return menu
  28. end
  29.  
  30. ------------------------------
  31. -- Test part
  32. ------------------------------
  33. local menu = CreateDropDownMenu()
  34.  
  35. function menu:OnValueChanged(value)
  36.     -- action
  37. end

Last edited by kurapica.igas : 07-27-14 at 07:50 PM.
  Reply With Quote
07-27-14, 08:32 PM   #7
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
Originally Posted by Resike View Post
I have a total custom dropdown, each time the user changes it's value, i would like to update it's propesions, however there are more dropdowns created by the same template, so i need something like the OnValueChanged script for sliders.
This seems pretty straightforward... without seeing your code (sigh) it's impossible to give you a specific solution, but I assume your template already has some way to detect when the user clicks on an item in the menu and call some function (eg. to update a value in your settings table) so why can't you just update whatever you want to update (I'm not sure what you meant there where you wrote "propesions") in that function?
__________________
Retired author of too many addons.
Message me if you're interested in taking over one of my addons.
Don’t message me about addon bugs or programming questions.
  Reply With Quote
07-28-14, 04:33 AM   #8
zork
A Pyroguard Emberseer
 
zork's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2008
Posts: 1,740
@Resike
Here is what I do on my dropdowns.
Lua Code:
  1. local dropdownMenu = createBasicDropDownMenu(parent, addon.."PanelHealthOrbFillingTexture", "Choose texture", db.getListFillingTexture, 196)
  2.     dropdownMenu.click = function(self)
  3.       UIDropDownMenu_SetSelectedValue(dropdownMenu, self.value)
  4.       --save value
  5.       panel.saveHealthOrbFillingTexture(self.value)
  6.       --update orb view
  7.       panel.updateHealthOrbFillingTexture()
  8.     end

https://code.google.com/p/rothui/sou.../panel.lua#292

A dropdown item has the "func" attribute. It is called oncllick. I set that to my click handler. So basically what I do in my template function is this.
Lua Code:
  1. if not self.info.hasArrow then
  2.   self.info.func = self.click or nil
  3. end
  4. UIDropDownMenu_AddButton(self.info, level)
__________________
| Simple is beautiful.
| WoWI AddOns | GitHub | Zork (WoW)

"I wonder what the non-pathetic people are doing tonight?" - Rajesh Koothrappali (The Big Bang Theory)

Last edited by zork : 07-28-14 at 04:48 AM.
  Reply With Quote
07-28-14, 06:04 AM   #9
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
Originally Posted by kurapica.igas View Post
Well, if you only need one event handler for one frame's event, it's simple to do it , just add one method to your frame, like :

Lua Code:
  1. ------------------------------
  2. -- Template part
  3. ------------------------------
  4. local function Fire(self, event, ...)
  5.     return type(self[event]) == "function" and self[event](self, ...)
  6. end
  7.  
  8. local function OnClick(self)
  9.     return self.Parent:Fire("OnValueChanged", self:GetID())
  10. end
  11.  
  12. function CreateDropDownMenu( ... )
  13.     local menu = CreateFrame("Frame", ...)
  14.  
  15.     -- Give it a new method
  16.     menu.Fire = Fire
  17.  
  18.     -- Create menu buttons
  19.     for i = 1, 10 do
  20.         local btn = CreateFrame("Button", nil, menu)
  21.         btn:SetID(i)
  22.         btn.Parent = menu
  23.  
  24.         btn:SetScript("OnClick", OnClick)
  25.     end
  26.  
  27.     return menu
  28. end
  29.  
  30. ------------------------------
  31. -- Test part
  32. ------------------------------
  33. local menu = CreateDropDownMenu()
  34.  
  35. function menu:OnValueChanged(value)
  36.     -- action
  37. end
I think this is what i need. Thanks.
  Reply With Quote
07-28-14, 06:11 AM   #10
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
My code looks like this, and i would like to replace the "OnHide" part:

Lua Code:
  1. local function CreateDropDown(frame, parent, list)
  2.     frame = CreateFrame("Button", nil, parent)
  3.     frame:SetWidth(200)
  4.     frame:SetHeight(26)
  5.     frame:SetBackdrop({
  6.         bgFile = "Interface\\Buttons\\White8X8",
  7.         edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
  8.         tile = true,
  9.         tileSize = 16,
  10.         edgeSize = 14,
  11.         insets = {left = 2, right = 2, top = 2, bottom = 2}
  12.     })
  13.     frame:SetBackdropColor(0, 0, 0, 1)
  14.     frame:SetBackdropBorderColor(0.3, 0.3, 0.3, 1.0)
  15.     frame:SetHitRectInsets(0, 0, 0, 0)
  16.     frame:SetScript("OnEnter", function(self)
  17.         self:SetBackdropBorderColor(0.5, 0.5, 0.5, 1.0)
  18.     end)
  19.     frame:SetScript("OnLeave", function(self)
  20.         self:SetBackdropBorderColor(0.3, 0.3, 0.3, 1.0)
  21.     end)
  22.     frame:SetScript("OnShow", function(self)
  23.         frame.Menu:Hide()
  24.     end)
  25.     frame.List = list
  26.     frame.Menu = CreateFrame("Frame", nil, frame)
  27.     frame.Menu:SetPoint("TopLeft", frame, "BottomLeft", 0, 2)
  28.     frame.Menu:SetWidth(frame:GetWidth())
  29.     frame.Menu:SetHeight(20 * #frame.List + 10)
  30.     frame.Menu:SetBackdrop({
  31.         bgFile = "Interface\\Buttons\\White8X8",
  32.         edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
  33.         tile = true,
  34.         tileSize = 16,
  35.         edgeSize = 14,
  36.         insets = {left = 2, right = 2, top = 2, bottom = 2}
  37.     })
  38.     frame.Menu:SetBackdropColor(0, 0, 0, 1)
  39.     frame.Menu:SetBackdropBorderColor(0.3, 0.3, 0.3, 1.0)
  40.     frame.Menu:SetScript("OnEnter", function(self)
  41.         self:SetBackdropBorderColor(0.5, 0.5, 0.5, 1.0)
  42.     end)
  43.     frame.Menu:SetScript("OnLeave", function(self)
  44.         self:SetBackdropBorderColor(0.3, 0.3, 0.3, 1.0)
  45.     end)
  46.     frame.Menu:SetScript("OnShow", function(self)
  47.         CloseDropDownMenus()
  48.         --[[frame:SetNormalTexture("Interface\\ChatFrame\\UI-ChatIcon-ScrollUp-Up")
  49.         frame:SetDisabledTexture("Interface\\ChatFrame\\UI-ChatIcon-ScrollUp-Disabled")
  50.         frame:SetPushedTexture("Interface\\ChatFrame\\UI-ChatIcon-ScrollUp-Down")]]
  51.     end)
  52.     --[[frame.Menu:SetScript("OnHide", function(self, button)
  53.         frame:SetNormalTexture("Interface\\ChatFrame\\UI-ChatIcon-ScrollDown-Up")
  54.         frame:SetDisabledTexture("Interface\\ChatFrame\\UI-ChatIcon-ScrollDown-Disabled")
  55.         frame:SetPushedTexture("Interface\\ChatFrame\\UI-ChatIcon-ScrollDown-Down")
  56.     end)]]
  57.     frame.Menu:Hide()
  58.     for i = 1, #frame.List do
  59.         frame.Menu[i] = CreateFrame("CheckButton", nil, frame.Menu)
  60.         if not frame.List.LastChild then
  61.             frame.Menu[i]:SetPoint("TopLeft", frame.Menu, "TopLeft", 5, -5)
  62.         else
  63.             frame.Menu[i]:SetPoint("TopLeft", frame.List.LastChild, "BottomLeft", 0, 0)
  64.         end
  65.         frame.Menu[i]:SetSize(20, 20)
  66.         frame.Menu[i]:SetHitRectInsets(0, -frame:GetWidth() + 10 + frame.Menu[i]:GetWidth(), 0, 0)
  67.         frame.Menu[i]:SetNormalFontObject(GameFontHighlightSmall)
  68.         frame.Menu[i]:SetDisabledFontObject(GameFontHighlightSmall)
  69.         frame.Menu[i]:SetHighlightFontObject(GameFontHighlightSmall)
  70.         frame.Menu[i]:SetNormalTexture("Interface\\Buttons\\UI-CheckBox-Up")
  71.         --frame.Menu[i]:GetNormalTexture():SetSize(20, 20)
  72.         --frame.Menu[i]:GetNormalTexture():ClearAllPoints()
  73.         --frame.Menu[i]:GetNormalTexture():SetPoint("TOPLEFT", 0, 0)
  74.         frame.Menu[i]:SetCheckedTexture("Interface\\Buttons\\UI-Common-MouseHilight")
  75.         frame.Menu[i]:SetHighlightTexture("Interface\\Buttons\\UI-CheckBox-Highlight")
  76.         --frame.Menu[i]:GetCheckedTexture():SetSize(20, 20)
  77.         --frame.Menu[i]:GetCheckedTexture():ClearAllPoints()
  78.         --frame.Menu[i]:GetCheckedTexture():SetPoint("TOPLEFT", 0, 0)
  79.         frame.Menu[i].Text = frame.Menu[i]:CreateFontString(nil, "Overlay")
  80.         frame.Menu[i].Text:SetJustifyH("Left")
  81.         frame.Menu[i].Text:SetJustifyV("Middle")
  82.         frame.Menu[i].Text:SetWordWrap(false)
  83.         frame.Menu[i].Text:SetPoint("Left", frame.Menu[i], "Right", 5, 0)
  84.         --frame.Menu[i].Text:SetVertexColor(1, 1, 1)
  85.         frame.Menu[i]:SetFontString(frame.Menu[i].Text)
  86.         frame.Menu[i].Text:SetText(frame.List[i])
  87.         frame.List.LastChild = frame.Menu[i]
  88.         frame.Menu[i]:SetScript("OnEnter", function(self)
  89.             frame.Menu:SetBackdropBorderColor(0.5, 0.5, 0.5, 1.0)
  90.             self.Text:SetVertexColor(1, 0.82, 0)
  91.         end)
  92.         frame.Menu[i]:SetScript("OnLeave", function(self)
  93.             frame.Menu:SetBackdropBorderColor(0.3, 0.3, 0.3, 1.0)
  94.             self.Text:SetVertexColor(1, 1, 1)
  95.         end)
  96.         frame.Menu[i]:SetScript("OnClick", function(self, button)
  97.             if button == "LeftButton" then
  98.                 for j = 1, #frame.Menu do
  99.                     local k = frame.Menu[j]
  100.                     if k ~= self then
  101.                         k:SetChecked(false)
  102.                     else
  103.                         if not self:GetChecked() then
  104.                             self:SetChecked(true)
  105.                         end
  106.                     end
  107.                 end
  108.                 frame.selected = frame.List[i]
  109.                 frame.Text:SetText(frame.selected)
  110.                 frame.Menu:Hide()
  111.             end
  112.         end)
  113.     end
  114.     frame.Title = frame:CreateFontString(nil, "Overlay")
  115.     frame.Title:SetFontObject(GameFontNormal)
  116.     frame.Title:SetJustifyV("Middle")
  117.     frame.Title:SetJustifyH("Left")
  118.     frame.Title:SetWordWrap(false)
  119.     frame.Title:SetSize(100, 20)
  120.     frame.Title:SetPoint("BottomLeft", frame, "TopLeft", 3, 0)
  121.     frame.Title:SetPoint("BottomRight", frame, "TopRight", -3, 0)
  122.     frame.Text = frame:CreateFontString(nil, "Overlay")
  123.     frame.Text:SetFontObject(GameFontHighlightSmall)
  124.     frame.Text:SetJustifyH("Left")
  125.     frame.Text:SetJustifyV("Middle")
  126.     frame.Text:SetWordWrap(false)
  127.     frame.Text:SetPoint("TOPLEFT", 8, -2)
  128.     frame.Text:SetPoint("BottomRight", -28, 2)
  129.     frame:SetFontString(frame.Text)
  130.     local t = frame:CreateTexture(nil, "Artwork")
  131.     t:SetTexture("Interface\\ChatFrame\\UI-ChatIcon-ScrollDown-Up")
  132.     t:SetPoint("TopRight")
  133.     t:SetPoint("BottomRight")
  134.     t:SetSize(26, 26)
  135.     frame:SetNormalTexture(t)
  136.     local t = frame:CreateTexture(nil, "Artwork")
  137.     t:SetTexture("Interface\\ChatFrame\\UI-ChatIcon-ScrollDown-Disabled")
  138.     t:SetPoint("TopRight")
  139.     t:SetPoint("BottomRight")
  140.     t:SetSize(26, 26)
  141.     frame:SetDisabledTexture(t)
  142.     local t = frame:CreateTexture(nil, "Artwork")
  143.     t:SetTexture("Interface\\ChatFrame\\UI-ChatIcon-ScrollDown-Down")
  144.     t:SetPoint("TopRight")
  145.     t:SetPoint("BottomRight")
  146.     t:SetSize(26, 26)
  147.     frame:SetPushedTexture(t)
  148.     local t = frame:CreateTexture(nil, "Artwork")
  149.     t:SetTexture("Interface\\ChatFrame\\UI-ChatIcon-BlinkHilight")
  150.     t:SetBlendMode("ADD")
  151.     t:SetPoint("TopRight")
  152.     t:SetPoint("BottomRight")
  153.     t:SetSize(26, 26)
  154.     frame:SetHighlightTexture(t)
  155.     frame:SetScript("OnClick", function(self, button)
  156.         if button == "LeftButton" then
  157.             if frame.Menu:IsShown() then
  158.                 frame.Menu:Hide()
  159.             else
  160.                 frame.Menu:Show()
  161.             end
  162.         end
  163.     end)
  164.     function frame:GetSelected()
  165.         return frame.selected
  166.     end
  167.     function frame:SetSelected(value)
  168.         frame.selected = value
  169.         for i = 1, #frame.List do
  170.             if frame.List[i] == value then
  171.                 frame.Menu[i]:SetChecked(true)
  172.             else
  173.                 frame.Menu[i]:SetChecked(false)
  174.             end
  175.         end
  176.         frame.Text:SetText(value)
  177.     end
  178.     return frame
  179. end
  180.  
  181. local list = {
  182.     [1] = "First",
  183.     [2] = "Second",
  184.     [3] = "Third"
  185. }
  186.  
  187. local dropdown = CreateDropDown(dropdown, UIParent, list)
  188. dropdown:SetSelected("First")
  189. dropdown:SetPoint("Center", UIParent, "Center", 0, 0)
  190. dropdown.Title:SetText("Title")
  191. dropdown.Menu:SetScript("OnHide", function(self)
  192.     -- Save Value
  193.     print(dropdown:GetSelected())
  194. end)
  Reply With Quote
08-02-14, 04:59 AM   #11
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
So what do you guys thing about it? It easy to use, no taints, very compact and goes easy on the resources too.



https://github.com/Resike/MoveAnythi...s/DropDown.lua

I need to come up with a better idea about the :RefreshList() tho.

Last edited by Resike : 08-02-14 at 05:02 AM.
  Reply With Quote
08-02-14, 10:40 PM   #12
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
Well:
Code:
function DropDown:CreateDropDown(frame, parent, list)
    frame = CreateFrame("Button", nil, parent)
Whatever you're passing in as the first argument here is immediately overwritten; I'd suggest not bothering passing anything, and just do this instead:
Code:
function DropDown:CreateDropDown(parent, list)
    local frame = CreateFrame("Button", nil, parent)
But the main problems I see are that

1) You're creating a lot of duplicate copies of all your script handler functions. If you have 5 dropdowns that each have 10 list items, you've created 200 functions, plus another 30 functions every time you call your RefreshList function, where you only needed to create 16 total functions regardless of the number of dropdowns or items. Define each of those functions once, outside of the CreateDropDown function, and then refer to them inside, just like you did with your Fire function.

2) If you have a dropdown with 10 list items, then you're creating 10 frames when you create the dropdown, then another 10 frames every time you call RefreshList. You should be reusing those frames instead.

Also, there is absolutely no benefit to upvaluing any of these things:
Code:
local table = table
local type = type

local CloseDropDownMenus = CloseDropDownMenus
local CreateFrame = CreateFrame
local GameFontHighlight = GameFontHighlight
local GameFontHighlightSmall = GameFontHighlightSmall
local GameFontNormal = GameFontNormal
If you're ever calling any of those functions, or referring to any of those objects, so frequently that an upvalue is doing anything other than cluttering up your code, you're doing something seriously wrong; in your case, you're not using any of them with any frequency at all, so it's just clutter.

----------

I don't really feel like rewriting your code for you right now, but you may find something useful in here:
https://github.com/phanx/PhanxConfig...ngDropdown.lua
__________________
Retired author of too many addons.
Message me if you're interested in taking over one of my addons.
Don’t message me about addon bugs or programming questions.
  Reply With Quote
08-03-14, 03:10 AM   #13
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
Originally Posted by Phanx View Post
Well:
Code:
function DropDown:CreateDropDown(frame, parent, list)
    frame = CreateFrame("Button", nil, parent)
Whatever you're passing in as the first argument here is immediately overwritten; I'd suggest not bothering passing anything, and just do this instead:
Code:
function DropDown:CreateDropDown(parent, list)
    local frame = CreateFrame("Button", nil, parent)
To be honest this is my first try to create a template like this, so ofc it's not perfect. I'll fix this one for sure.

Originally Posted by Phanx View Post
But the main problems I see are that

1) You're creating a lot of duplicate copies of all your script handler functions. If you have 5 dropdowns that each have 10 list items, you've created 200 functions, plus another 30 functions every time you call your RefreshList function, where you only needed to create 16 total functions regardless of the number of dropdowns or items. Define each of those functions once, outside of the CreateDropDown function, and then refer to them inside, just like you did with your Fire function.

2) If you have a dropdown with 10 list items, then you're creating 10 frames when you create the dropdown, then another 10 frames every time you call RefreshList. You should be reusing those frames instead.
I know this is just a temporarly solution for now, the issue is i would like to keep the list sorted mostly, and i couldn't come up with a solution about how can i insert a button where it belongs allphabetically each time you add a new list item.

Last edited by Resike : 08-03-14 at 03:36 AM.
  Reply With Quote
08-04-14, 03:28 AM   #14
p3lim
A Pyroguard Emberseer
 
p3lim's Avatar
AddOn Author - Click to view addons
Join Date: Feb 2007
Posts: 1,710
Originally Posted by Resike View Post
I know this is just a temporarly solution for now, the issue is i would like to keep the list sorted mostly, and i couldn't come up with a solution about how can i insert a button where it belongs allphabetically each time you add a new list item.
Code:
buttons = {
  {name = 'one', callback = function() end, ...},
  {name = 'two', callback = function() end, ...}
}

table.sort(buttons, function(a, b)
  return a.name > b.name
end)

Last edited by p3lim : 08-04-14 at 09:34 AM.
  Reply With Quote
08-04-14, 04:06 AM   #15
Torhal
A Pyroguard Emberseer
 
Torhal's Avatar
AddOn Author - Click to view addons
Join Date: Aug 2008
Posts: 1,196
The sort func should be returning the result of the comparison, though.
__________________
Whenever someone says "pls" because it's shorter than "please", I say "no" because it's shorter than "yes".

Author of NPCScan and many other AddOns.
  Reply With Quote
08-04-14, 09:34 AM   #16
p3lim
A Pyroguard Emberseer
 
p3lim's Avatar
AddOn Author - Click to view addons
Join Date: Feb 2007
Posts: 1,710
Originally Posted by Torhal View Post
The sort func should be returning the result of the comparison, though.
Yeah, forgot about that part. :]
  Reply With Quote
08-04-14, 02:01 PM   #17
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
Originally Posted by p3lim View Post
Code:
buttons = {
  {name = 'one', callback = function() end, ...},
  {name = 'two', callback = function() end, ...}
}

table.sort(buttons, function(a, b)
  return a.name > b.name
end)
The issue is not really with the sorting part, more likely the hassle that comes with the inserting. (Repositioning, reindexing, copying the tables around.) Recreating the whole thing seemed easier.
  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » Custom Scripts

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