Thread Tools Display Modes
12/05/14, 07:42 PM   #1
circonian
AddOn Author - Click to view addons
Join Date: May 2014
Posts: 613
ZO_PlayerInventoryTabs - m_buttonData.control vs m_button

What is the difference between these. I originally thought they were supposed to be the same thing. Am I wrong?
Lua Code:
  1. ZO_PlayerInventoryTabs.m_object.m_clickedButton.m_button
  2. -- and
  3. ZO_PlayerInventoryTabs.m_object.m_clickedButton.m_buttonData.control

Just to give you an idea while reading this, this is what the table looks like:
Lua Code:
  1. ZO_PlayerInventoryTabs = {
  2.    -- contains stuff and --
  3.    m_object = {
  4.       -- contains stuff and --
  5.       m_clickedButton = {
  6.          -- contains stuff and --
  7.          m_button = <button control>,
  8.          m_buttonData = {
  9.             -- contains stuff and --
  10.             control = <button control>,
  11.          }
  12.       }
  13.    }
  14. }


When your in the backpack they always seem to be the same. If you open the mail, for example, they are no longer the same. The buttons are numbered differently in the mail than they are in the backpack even though its still ZO_PlayerInventoryTabs.
This seems to be because the mail window does not have a quest tab.

When you set a callback for the buttons like:
Lua Code:
  1. local function InvTabSwitch(_tButtonData)
  2.    -- do stuff --
  3. end
  4.  
  5. local function HookBankButtons()
  6.     local tButtons = ZO_PlayerBankTabs.m_object.m_buttons
  7.    
  8.     for k,v in pairs(tButtons) do
  9.         local tButtonData = v[1].m_object.m_buttonData
  10.         local hCallback = tButtonData.callback
  11.        
  12.         -- Make the SubMenu bar for this button & store it in tButtonData
  13.         local menuBar = MakeMenuBar(v[1])
  14.         tButtonData.FilterIt_SubMenu = menuBar
  15.        
  16.         tButtonData.callback = function(...)   
  17.                 InvTabSwitch(...)                      
  18.                 hCallback(...)
  19.             end    
  20.     end
  21. end

It passes m_buttonData to the callback. In the backpack it works fine, since m_buttonData.control & m_button are the same. When the callback is passed m_buttonData it contains control which is the button you pushed...but

When the mail is open because the m_buttonData.control & m_button are not the same and it causes a problem.
Your callback is still passed m_buttonData, but it only contains control which is not the button you pushed. It is the last button you pushed, which I believe is a mere coincidence due to the way the buttons get numbered and the fact that there is no quest tab in the mail window.

So what is supposed to be the difference between m_buttonData.control & m_button.
Why does the backpack pass the callback function the m_buttonData.control for the button that is pushed, but when the mail is open it passes in the wrong m_buttonData.control. Is it just a bug?

So I figured I could just do this to grab m_button which "seems" to be the real button that was pushed.
Lua Code:
  1. -- m_buttonData passed to callback
  2. local menuBar = m_buttonData.control:GetParent()
  3. local actualClickedButton = menuBar.m_object.m_clickedButton.m_button

But it leaves me wondering since I don't really know the difference between:
Lua Code:
  1. ZO_PlayerInventoryTabs.m_object.m_clickedButton.m_button
  2. -- and
  3. ZO_PlayerInventoryTabs.m_object.m_clickedButton.m_buttonData.control
Is this going to cause me more problems somewhere else?

Last edited by circonian : 12/05/14 at 09:21 PM.
  Reply With Quote
12/05/14, 09:08 PM   #2
The Real Daenerys
 
The Real Daenerys's Avatar
Join Date: Dec 2014
Posts: 1
nice work!
  Reply With Quote
12/05/14, 09:17 PM   #3
circonian
AddOn Author - Click to view addons
Join Date: May 2014
Posts: 613
Originally Posted by circonian View Post
Is this going to cause me more problems somewhere else?
Apparently the answer to that question is yes...

Another side effect of this is that it seems that you can't save a reference to the last button pushed.

If you try to save a reference to, lets say the Armor inventory tab button control, when you open the mail that reference now points to the Weapons button !!!

Last edited by circonian : 12/05/14 at 09:23 PM.
  Reply With Quote
12/05/14, 09:25 PM   #4
merlight
AddOn Author - Click to view addons
Join Date: Jul 2014
Posts: 671
Just going through the code and writing down findings... ... ... Ok now that I got through it, you can skip down to the bad button
I'll leave the whole journey here, may be useful another day.

The v[1] from tButtons in your iteration is a control created from ZO_MenuBarButtonTemplate1 by default, but different windows override it with their own template (hopefully always derived from the default). The default template's OnInitialized handler calls ZO_MenuBarButtonTemplate_OnInitialized(self). There it creates an instance of class MenuBarButton:

Lua Code:
  1. function ZO_MenuBarButtonTemplate_OnInitialized(self)
  2.     self.m_object = MenuBarButton:New(self)
  3. end
  4.  
  5. function MenuBarButton:Initialize(button)
  6.     self.m_button = button
  7.     ...
  8. end
  9.  
  10. function MenuBarButton:SetData(owner, buttonData)
  11.     self.m_buttonData = buttonData
  12.    ...
  13. end

So you can get the object from the control, and the control from the object:
Lua Code:
  1. local buttonControl = v[1]
  2. -- this should always be true
  3. assert(buttonControl == buttonControl.m_object.m_button)

m_clickedButton is an instance of MenuBarButton


*** bad button ***

It's quite unfortunate the callback only gets buttonData as the argument. buttonData.control is not coming from the MenuBarButton class, it is set in local function InitializeInventoryFilters(inventory) (ingame/inventory/inventory.lua), i.e. once when the buttons are created. But later, in ZO_InventoryManager:ApplyBackpackLayout, the buttons are released, and some of them acquired from the pool again, but .control is not re-assigned. And that is the problem - buttonData remains the same, but gets attached to a different button control.

It's a bug in ZO_InventoryManager:ApplyBackpackLayout in the loop containing ZO_MenuBar_AddButton calls. Since MenuBarButton class is only accessible via metatables of existing buttons, the simplest fix will probably be replacing ZO_MenuBar_AddButton:
Lua Code:
  1. function ZO_MenuBar_AddButton(self, buttonData)
  2.     local button = self.m_object:AddButton(buttonData)
  3.     buttonData.control = button
  4.     return button
  5. end
  Reply With Quote
12/05/14, 09:34 PM   #5
Garkin
 
Garkin's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2014
Posts: 832
This is a little offtopic, but all button data is stored in tabFilters table, so it would be easier to work with this table:
Lua Code:
  1. local function InvTabSwitch(_tButtonData)
  2.     -- do stuff --
  3. end
  4.      
  5. local function HookBankButtons()
  6.     local inventory = PLAYER_INVENTORY:GetDisplayInventoryTable(INVENTORY_BANK)
  7.     local tabFilters = inventory.tabFilters
  8.        
  9.     for k,tButtonData in pairs(tabFilters) do
  10.         local hCallback = tButtonData.callback
  11.            
  12.         -- Make the SubMenu bar for this button & store it in tButtonData
  13.         local button = inventory.filterBar:ButtonObjectForDescriptor(tButtonData.descriptor)
  14.         local menuBar = MakeMenuBar(button.m_button)
  15.         tButtonData.FilterIt_SubMenu = menuBar
  16.  
  17.         tButtonData.callback = function(...)
  18.                 InvTabSwitch(...)                      
  19.                 hCallback(...)
  20.             end    
  21.     end
  22. end

EDIT: As merlight has explained, "buttonData.control" is not supported by MenuBar / MenuBarButton class and it is not correctly updated by inventory manager. So, I have updated code to get button from descriptor.

Last edited by Garkin : 12/05/14 at 11:41 PM.
  Reply With Quote
12/05/14, 10:45 PM   #6
circonian
AddOn Author - Click to view addons
Join Date: May 2014
Posts: 613
Originally Posted by merlight View Post
Just going through the code and writing down findings... ... ... Ok now that I got through it, you can skip down to the bad button
I'll leave the whole journey here, may be useful another day.
Awesome explanation, thanks !
  Reply With Quote
12/06/14, 03:57 PM   #7
circonian
AddOn Author - Click to view addons
Join Date: May 2014
Posts: 613
Originally Posted by Garkin View Post
This is a little offtopic, but all button data is stored in tabFilters table, so it would be easier to work with this table:
Lua Code:
  1. local function InvTabSwitch(_tButtonData)
  2.     -- do stuff --
  3. end
  4.      
  5. local function HookBankButtons()
  6.     local inventory = PLAYER_INVENTORY:GetDisplayInventoryTable(INVENTORY_BANK)
  7.     local tabFilters = inventory.tabFilters
  8.        
  9.     for k,tButtonData in pairs(tabFilters) do
  10.         local hCallback = tButtonData.callback
  11.            
  12.         -- Make the SubMenu bar for this button & store it in tButtonData
  13.         local button = inventory.filterBar:ButtonObjectForDescriptor(tButtonData.descriptor)
  14.         local menuBar = MakeMenuBar(button.m_button)
  15.         tButtonData.FilterIt_SubMenu = menuBar
  16.  
  17.         tButtonData.callback = function(...)
  18.                 InvTabSwitch(...)                      
  19.                 hCallback(...)
  20.             end    
  21.     end
  22. end

EDIT: As merlight has explained, "buttonData.control" is not supported by MenuBar / MenuBarButton class and it is not correctly updated by inventory manager. So, I have updated code to get button from descriptor.
Ah nice, i tried to find a way to get the button from descriptor but couldn't find a way. Thanks for the info!
  Reply With Quote

ESOUI » Developer Discussions » General Authoring Discussion » ZO_PlayerInventoryTabs - m_buttonData.control vs m_button

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