Thread Tools Display Modes
01/25/16, 02:35 AM   #1
Terrillyn
AddOn Author - Click to view addons
Join Date: Jan 2016
Posts: 24
Having issues creating an account-wide settings toggle

Hi, I'm having trouble create an 'account-wide settings' toggle for one of my addons, well actually I've got it working but its causing weird behavior with the colorpicker controls and some of the other controls, and I'm hoping someone can help me figure out what I'm doing wrong, here is some scippets of how I'm accomplishing the accountwide toggle:

When my addon loads here is how I load the settings:
Lua Code:
  1. SimpleXPBar.accountwide_settings = ZO_SavedVars:NewAccountWide("SimpleXPBar_Settings", "1", nil, { isAccountWide = false }, 'SimpleXPBar.AccountWide')
  2. SimpleXPBar.AWSV = ZO_SavedVars:NewAccountWide("SimpleXPBar_Settings", "1", nil, SimpleXPBar.default_settings)
  3. SimpleXPBar.CharSV = ZO_SavedVars:New("SimpleXPBar_Settings", "1", nil, SimpleXPBar.default_settings)
  4.    
  5. if SimpleXPBar.accountwide_settings.isAccountWide then
  6.     ZO_DeepTableCopy(SimpleXPBar.AWSV, SimpleXPBar.CharSV)
  7.     SimpleXPBar.CurSV = SimpleXPBar.AWSV
  8. else
  9.     SimpleXPBar.CurSV = SimpleXPBar.CharSV
  10. end

and here is how my 'Account-Wide' toggle is setup (using libaddonmenu):
Lua Code:
  1. {
  2.     type = "checkbox",
  3.     name = "Use Account-Wide settings",
  4.     getFunc = function()
  5.         return SimpleXPBar.accountwide_settings.isAccountWide
  6.     end,
  7.     setFunc = function(val)
  8.         SimpleXPBar.accountwide_settings.isAccountWide = val
  9.         if SimpleXPBar.accountwide_settings.isAccountWide then
  10.             ZO_DeepTableCopy(SimpleXPBar.AWSV, SimpleXPBar.CharSV)
  11.             SimpleXPBar.CurSV = SimpleXPBar.AWSV
  12.         else
  13.             ZO_DeepTableCopy(SimpleXPBar.CharSV, SimpleXPBar.AWSV)
  14.             SimpleXPBar.CurSV = SimpleXPBar.CharSV
  15.         end
  16.     end,
  17. },

Just for reference here is how the Colorpicker is setup:
Lua Code:
  1. {
  2.     type = "colorpicker",
  3.     name = "Color",
  4.     width = "full",
  5.     getFunc = function()
  6.         return SimpleXPBar.CurSV.textbar.color.r, SimpleXPBar.CurSV.textbar.color.b, SimpleXPBar.CurSV.textbar.color.g, SimpleXPBar.CurSV.textbar.color.a
  7.     end,
  8.     setFunc = function(r, g, b, a)
  9.         SimpleXPBar.CurSV.textbar.color.r = r
  10.         SimpleXPBar.CurSV.textbar.color.b = b
  11.         SimpleXPBar.CurSV.textbar.color.g = g
  12.         SimpleXPBar.CurSV.textbar.color.a = a
  13.         SimpleXPBar:UpdateControls()
  14.     end,
  15. },

I'm using SimpleXPBar.CurSV to reference my settings through-out the rest of the code, and the issue I'm having with the colorpicker is that it keeps flipping back and forth between 2 different color settings everytime I click it, I have a feeling this has to do with how lua is referencing the object but I cant figure what its doing in this case. I've already searched around the forums and google trying to find some sample of how to create a accountwide toggle correctly but I ended up looking at how Destinations and MasterMerchant do it and trying something similar.

Any suggestions on a better way of implementing this or a fix would be appreciated.
  Reply With Quote
01/25/16, 04:52 AM   #2
coolmodi
AddOn Author - Click to view addons
Join Date: Mar 2015
Posts: 47
What I see at the first glance is this

Lua Code:
  1. if SimpleXPBar.accountwide_settings.isAccountWide then
  2.     ZO_DeepTableCopy(SimpleXPBar.AWSV, SimpleXPBar.CharSV)
  3.     SimpleXPBar.CurSV = SimpleXPBar.AWSV
  4. else
  5.     SimpleXPBar.CurSV = SimpleXPBar.CharSV
  6. end

Doesn't that mean you use AWSV to save new changes but copy the data from CharSV (that didn't change) over that every time you reload UI? That would reset it to whatever is in CharSV. But maybe ZO_DeepTableCopy is the other way round, don't know.

Edit: Either way I think it has to be the ZO_DeepTableCopy function, my solution was pretty much the same, just without copying tables around (why would you do that anyways?).

Lua Code:
  1. function GroupDamage:RestoreData()
  2.     self.savedVariablesAw = ZO_SavedVars:NewAccountWide("GroupDamageSavedVariables", defaultVarsVer, nil, defaults)
  3.     self.savedVariablesChar = ZO_SavedVars:New("GroupDamageSavedVariables", defaultVarsVer, nil, defaults)
  4.     self.svars = self.savedVariablesChar
  5.     if self.savedVariablesAw.accountWide then
  6.         self.svars = self.savedVariablesAw
  7.     end
  8. end
  9.  
  10. --the AW checkbox
  11. {
  12.             type = "checkbox",
  13.             name = GetString(SI_GROUPDAMAGE_MENU_ACCWIDESETTINGS),
  14.             getFunc = function() return self.savedVariablesAw.accountWide end,
  15.             setFunc = function() self.savedVariablesAw.accountWide = not self.savedVariablesAw.accountWide ReloadUI() end,
  16.             warning = GetString(SI_GROUPDAMAGE_MENU_RELOADWARN)
  17.         },
  18.  
  19. --a colorpicker, you can use tables for the colors and then unpack(table) to make it alot shorter and easier to use ;)
  20. {
  21.             type = "colorpicker",
  22.             name = GetString(SI_GROUPDAMAGE_MENU_BARSCOLOR),
  23.             getFunc = function() return unpack(self.svars.panelBarsColor) end,
  24.             setFunc = function(r,g,b,a)
  25.                 self.svars.panelBarsColor = {r,g,b,a}
  26.                 self:ResetPanelControls()
  27.             end,
  28.         },

Last edited by coolmodi : 01/25/16 at 05:26 AM.
  Reply With Quote
01/25/16, 06:20 AM   #3
Terrillyn
AddOn Author - Click to view addons
Join Date: Jan 2016
Posts: 24
Originally Posted by coolmodi View Post
Doesn't that mean you use AWSV to save new changes but copy the data from CharSV (that didn't change) over that every time you reload UI? That would reset it to whatever is in CharSV. But maybe ZO_DeepTableCopy is the other way round, don't know.
the prototype is ZO_DeepTableCopy(source, dest); I have SimpleXPBar.CharSV get overwritten if accountwide is chosen so that the individual characters will have there settings overwritten, this was intended to mitigate the issue of [when you uncheck the accountwide setting you have to redo all the changes you made on each character], though I may just add a button to push current settings to all characters for this purpose.

Originally Posted by coolmodi View Post
Edit: Either way I think it has to be the ZO_DeepTableCopy function, my solution was pretty much the same, just without copying tables around (why would you do that anyways?).

Lua Code:
  1. function GroupDamage:RestoreData()
  2.     self.savedVariablesAw = ZO_SavedVars:NewAccountWide("GroupDamageSavedVariables", defaultVarsVer, nil, defaults)
  3.     self.savedVariablesChar = ZO_SavedVars:New("GroupDamageSavedVariables", defaultVarsVer, nil, defaults)
  4.     self.svars = self.savedVariablesChar
  5.     if self.savedVariablesAw.accountWide then
  6.         self.svars = self.savedVariablesAw
  7.     end
  8. end
  9.  
  10. --the AW checkbox
  11. {
  12.             type = "checkbox",
  13.             name = GetString(SI_GROUPDAMAGE_MENU_ACCWIDESETTINGS),
  14.             getFunc = function() return self.savedVariablesAw.accountWide end,
  15.             setFunc = function() self.savedVariablesAw.accountWide = not self.savedVariablesAw.accountWide ReloadUI() end,
  16.             warning = GetString(SI_GROUPDAMAGE_MENU_RELOADWARN)
  17.         },
  18.  
  19. --a colorpicker, you can use tables for the colors and then unpack(table) to make it alot shorter and easier to use ;)
  20. {
  21.             type = "colorpicker",
  22.             name = GetString(SI_GROUPDAMAGE_MENU_BARSCOLOR),
  23.             getFunc = function() return unpack(self.svars.panelBarsColor) end,
  24.             setFunc = function(r,g,b,a)
  25.                 self.svars.panelBarsColor = {r,g,b,a}
  26.                 self:ResetPanelControls()
  27.             end,
  28.         },
I'll try it like yours, without the deepcopy, I'm still not entirely sure how shallow copying works in Lua yet; I like that trick with using unpack, I wasn't aware of that function. Thanks.
  Reply With Quote
01/25/16, 06:45 AM   #4
coolmodi
AddOn Author - Click to view addons
Join Date: Mar 2015
Posts: 47
I'm pretty much still a noob in programming, but as I understand it LUA will always reference tables, but "copy" other values.

Lua Code:
  1. x = "asfaf"
  2. y = {"af","sdgsd"}
  3.  
  4. z = x --z will be "asfaf"
  5. w = y --w is only a reference to the table

There's also something called metatables that can change the behavior of tables, ZO_DeepTableCopy ignores them, maybe that messes something up. In GroupDamage I used a custom deepcopy function because I didn't know the ZOS one existed and only because of that even stumbled over this topic. Maybe that's worth a try?

Lua Code:
  1. local function deepcopy(orig)
  2.     local orig_type = type(orig)
  3.     local copy
  4.     if orig_type == 'table' then
  5.         copy = {}
  6.         for orig_key, orig_value in next, orig, nil do
  7.             copy[deepcopy(orig_key)] = deepcopy(orig_value)
  8.         end
  9.         setmetatable(copy, deepcopy(getmetatable(orig)))
  10.     else -- number, string, boolean, etc
  11.         copy = orig
  12.     end
  13.     return copy
  14. end

But again, I'm really no pro here, and maybe the error is somewhat completely different that we both just don't see
  Reply With Quote
01/25/16, 07:55 AM   #5
sirinsidiator
 
sirinsidiator's Avatar
AddOn Author - Click to view addons
Join Date: Apr 2014
Posts: 1,578
While reloading the UI when you toggle the checkbox may solve the problem, it makes for a horrible user experience. Especially when there are multiple settings that each want to reload the ui for themselves, so please use it only as a last resort when there is absolutely no other way to get around it and even then, consider adding a reload ui button instead of automatically reloading it. This advice is also meant for other authors that use forced UI reloads.

As for your problem, I think there are three issues.

1) When you replace the currently used variables in your set function you also need to inform LAM that something changed, so that it can render the changes in its controls.
This can be done by firing the "LAM-RefreshPanel" callback:
Lua Code:
  1. CALLBACK_MANAGER:FireCallbacks("LAM-RefreshPanel", panel)
Where panel is the value that gets returned by RegisterAddonPanel.

2) ZO_SavedVars is a highly complex object. I am not sure if ZO_DeepTableCopy is enough to replace the values correctly. I don't personally use ZO_SavedVars, so correct me if I am wrong, but I think the right way to accomplish what you want is to just create a new ZO_SavedVars object and pass the values that need to be copied as defaults.

3) LAM may call setFunc more often than necessary (not 100% sure, but it might happen), so you should check if something changed before doing your copy routine.

With all of these things considered, it should look something like this:
Lua Code:
  1. {
  2.         type = "checkbox",
  3.         name = "Use Account-Wide settings",
  4.         getFunc = function()
  5.             return SimpleXPBar.accountwide_settings.isAccountWide
  6.         end,
  7.         setFunc = function(val)
  8.             if SimpleXPBar.accountwide_settings.isAccountWide == val then return end
  9.             SimpleXPBar.accountwide_settings.isAccountWide = val
  10.             if SimpleXPBar.accountwide_settings.isAccountWide then
  11.                 SimpleXPBar.AWSV = ZO_SavedVars:NewAccountWide("SimpleXPBar_Settings", "1", nil, SimpleXPBar.CharSV)
  12.                 SimpleXPBar.CurSV = SimpleXPBar.AWSV
  13.             else
  14.                 SimpleXPBar.CharSV = ZO_SavedVars:New("SimpleXPBar_Settings", "1", nil, SimpleXPBar.AWSV)
  15.                 SimpleXPBar.CurSV = SimpleXPBar.CharSV
  16.             end
  17.             CALLBACK_MANAGER:FireCallbacks("LAM-RefreshPanel", panel)
  18.         end,
  19.     },
  Reply With Quote
01/25/16, 08:42 AM   #6
coolmodi
AddOn Author - Click to view addons
Join Date: Mar 2015
Posts: 47
Originally Posted by sirinsidiator View Post
2) ZO_SavedVars is a highly complex object. I am not sure if ZO_DeepTableCopy is enough to replace the values correctly. I don't personally use ZO_SavedVars, so correct me if I am wrong, but I think the right way to accomplish what you want is to just create a new ZO_SavedVars object and pass the values that need to be copied as defaults.
He wants to copy the settings between the character specific vars and the account wide ones. Creating a new object with the other's settings as default won't work as the values are already set. Default values are only used if the setting doesn't exist in the saved vars already. He could increase the version everytime to force it to overwrite it with the defaults though, but that may not be the best option I think

He should just make a function himself that sets all settings to the ones from the other SV and doesn't change the tables. That way it would work for sure.

And yes, the reload in my code there isn't needed, I could just change the reference and it should work fine.

Last edited by coolmodi : 01/25/16 at 08:46 AM.
  Reply With Quote
01/25/16, 07:05 PM   #7
merlight
AddOn Author - Click to view addons
Join Date: Jul 2014
Posts: 671
Originally Posted by coolmodi View Post
There's also something called metatables that can change the behavior of tables, ZO_DeepTableCopy ignores them, ...
Actualy it doesn't ignore them: http://esodata.uesp.net/100013/src/l...s.lua.html#163
  Reply With Quote
01/25/16, 08:22 PM   #8
Terrillyn
AddOn Author - Click to view addons
Join Date: Jan 2016
Posts: 24
Well I spoke too soon, it wouldn't let me set accountwide settings when I did that, seems nothing I try lets me copy over another table, aside from writing a large function to manually copy over all the vars.
For now I'll just keep character and account settings in separate SavedVars, this means the user should enable the Account-Wide toggle before making any changes.

checkbox
Lua Code:
  1. setFunc = function(val)
  2.     if val then
  3.         SimpleXPBar.CurSV = SimpleXPBar.AWSV
  4.     else
  5.         SimpleXPBar.CurSV = SimpleXPBar.CharSV
  6.     end
  7.     SimpleXPBar.AWSV.general.account_wide = val
  8.     SimpleXPBar:UpdateStats()
  9.     SimpleXPBar:UpdateValues()
  10. end,

At playerload
Lua Code:
  1. SimpleXPBar.AWSV = ZO_SavedVars:New("SimpleXPBar_Settings", "1", nil, SimpleXPBar.default_settings, nil, nil, '$' .. SimpleXPBar.name)
  2. SimpleXPBar.CharSV = ZO_SavedVars:New("SimpleXPBar_Settings", "1", nil, SimpleXPBar.default_settings)
  3.  
  4. if SimpleXPBar.AWSV.general.account_wide then
  5.     SimpleXPBar.CurSV = SimpleXPBar.AWSV
  6. else
  7.     SimpleXPBar.CurSV = SimpleXPBar.CharSV
  8. end
  Reply With Quote

ESOUI » Developer Discussions » Lua/XML Help » Having issues creating an account-wide settings toggle


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