WoWInterface

WoWInterface (https://www.wowinterface.com/forums/index.php)
-   Lua/XML Help (https://www.wowinterface.com/forums/forumdisplay.php?f=16)
-   -   Custom Scripts (https://www.wowinterface.com/forums/showthread.php?t=49537)

Resike 07-27-14 08:00 AM

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?

Malakahh 07-27-14 09:58 AM

If I understand you correctly, you're looking to create custom events?

zork 07-27-14 10:12 AM

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

Dridzt 07-27-14 11:54 AM

You can fire custom events using AceEvent-3.0 or even simpler with Callbackhandler-1.0

Resike 07-27-14 02:33 PM

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.

kurapica.igas 07-27-14 07:39 PM

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

Phanx 07-27-14 08:32 PM

Quote:

Originally Posted by Resike (Post 294440)
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?

zork 07-28-14 04:33 AM

@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)

Resike 07-28-14 06:04 AM

Quote:

Originally Posted by kurapica.igas (Post 294446)
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.

Resike 07-28-14 06:11 AM

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)

Resike 08-02-14 04:59 AM

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.

Phanx 08-02-14 10:40 PM

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

Resike 08-03-14 03:10 AM

Quote:

Originally Posted by Phanx (Post 294648)
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.

Quote:

Originally Posted by Phanx (Post 294648)
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.

p3lim 08-04-14 03:28 AM

Quote:

Originally Posted by Resike (Post 294656)
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)


Torhal 08-04-14 04:06 AM

The sort func should be returning the result of the comparison, though. :D

p3lim 08-04-14 09:34 AM

Quote:

Originally Posted by Torhal (Post 294682)
The sort func should be returning the result of the comparison, though. :D

Yeah, forgot about that part. :]

Resike 08-04-14 02:01 PM

Quote:

Originally Posted by p3lim (Post 294681)
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.


All times are GMT -6. The time now is 05:07 PM.

vBulletin © 2024, Jelsoft Enterprises Ltd
© 2004 - 2022 MMOUI