--[[ ThemePrefsRows: you give it the choices, values, and params, and it'll generate the rest; quirky behavior to be outlined below. Documentation will be provided once this system is stabilized. v0.5.2: Dec. 28, 2010. Throw an error for default/value type mismatches. v0.5.1: Dec. 27, 2010. Fix Choices not necessarily being strings. v0.5.0: Dec. 15, 2010. Initial version. Not very well tested. vyhd wrote this for sm-ssc --]] -- unless overridden, these parameters will be used for the OptionsRow local DefaultParams = { LayoutType = "ShowAllInRow", SelectType = "SelectOne", OneChoiceForAllPlayers = true, ExportOnChange = false, EnabledForPlayers = nil, ReloadRowMessages = nil, -- takes a function(self, list, pn); -- if not used, we use the default LoadSelections = nil, SaveSelections = nil, } -- local alias to simplify error reporting local function GetString( name ) return THEME:GetString( "ThemePrefsRows", name ) end local function DefaultLoad( pref, default, choices, values ) return function(self, list, pn) local val = ThemePrefs.Get( pref ) -- if our current value is here, set focus to that for i=1, #choices do if values[i] == val then list[i] = true return end end -- try the default value for i=1, #choices do if values[i] == default then list[i] = true return end end -- set to the first value and output a warning Warn( GetString("NoDefaultInValues"):format(pref) ) list[1] = true end end local function DefaultSave( pref, choices, values ) local msg = "ThemePrefChanged" local params = { Name = pref } return function(self, list, pn) for i=1, #choices do if list[i] then ThemePrefs.Set( pref, values[i] ) MESSAGEMAN:Broadcast( msg, params ) break end end end end -- This function checks for mismatches between the default value and the -- values table passed to the ThemePrefRow, e.g. it will return false if -- you have a boolean default and an integer value. I'm somewhat stricter -- about types than Lua is because I don't like the unpredictability and -- complexity of coercing values transparently in a bunch of places. local function TypesMatch( Values, Default ) local DefaultType = type(Default) for i, value in ipairs(Values) do local ValueType = type(value) if ValueType ~= DefaultType then Warn( GetString("TypeMismatch"):format(DefaultType, i, ValueType) ) return false end end return true end local function CreateThemePrefRow( pref, tbl ) -- can't make an option handler without options if not tbl.Choices then return nil end local Choices = tbl.Choices local Default = tbl.Default local Values = tbl.Values and tbl.Values or Choices local Params = tbl.Params and tbl.Params or { } -- if the choices aren't strings, make them strings now for i, str in ipairs(Choices) do Choices[i] = tostring( Choices[i] ) end -- check to see that Values and Choices have the same length if #Choices ~= #Values then Warn( GetString("ChoicesSizeMismatch") ) return nil end -- check to see that everything in Values matches the type of Default if not TypesMatch( Values, Default ) then return nil end -- set the name and choices here; we'll do the rest below local Handler = { Name = pref, Choices = Choices } -- add all the keys in DefaultParams, get the value from -- Params if it exists and DefaultParams otherwise -- (note that we explicitly check for nil, due to bools.) for k, _ in pairs(DefaultParams) do Handler[k] = Params[k] ~= nil and Params[k] or DefaultParams[k] end -- if we don't have LoadSelections and SaveSelections, make them if not Handler.LoadSelections then Handler.LoadSelections = DefaultLoad( pref, Default, Choices, Values ) end if not Handler.SaveSelections then Handler.SaveSelections = DefaultSave( pref, Choices, Values ) end return Handler end -- All OptionsRows for preferences are stuck in this table, accessible -- through GetRow('name') in the namespace or ThemePrefRow('name') in -- the global namespace. (I like to keep pollution to a minimum.) local Rows = { } ThemePrefsRows = { IsInitted = false, Init = function( prefs ) for pref, tbl in pairs(prefs) do Rows[pref] = CreateThemePrefRow( pref, tbl ) end end, GetRow = function( pref ) Trace( ("GetRow(%s), type %s"):format(pref, type(Rows[pref])) ) return Rows[pref] end, } -- Global namespace alias ThemePrefRow = ThemePrefsRows.GetRow -- UGLY: declare this here, even though it's in the previous namespace, -- so we can have one call to initialize both systems (ThemePrefsRow is -- declared after ThemePrefs, so it can't actually be in that file...) ThemePrefs.InitAll = function( prefs ) Trace( "ThemePrefs.InitAll( prefs )" ) ThemePrefs.Init( prefs, true ) ThemePrefsRows.Init( prefs ) end