annotate Config.lua @ 37:e84d645c8ab8

- revised the tracker update function to build its complete data list up front and use the values as points of comparison for determining possible out of place blocks, which will be iterated over afterward to remove what wasn't re-used - also entailed revising the exact role of global event handlers and function hooks, limiting their directions of communication so one doesn't end up calling the other multiple or inifinity times - schema handling polish
author Nenue
date Mon, 18 Apr 2016 07:56:23 -0400
parents 66b927b46776
children
rev   line source
Nenue@0 1 --- All the control GUI stuff, including chat command functions
Nenue@0 2 -- @file-author@
Nenue@0 3 -- @project-revision@ @project-hash@
Nenue@0 4 -- @file-revision@ @file-hash@
Nenue@0 5 -- Created: 3/12/2016 12:49 AM
Nenue@0 6 local B, _G = select(2,...).frame, _G
Nenue@0 7 local M = B:RegisterModule("Options")
Nenue@0 8 local tostring, tonumber, floor, format = tostring, tonumber, floor, string.format
Nenue@0 9 local unpack, select, pairs, ipairs, type, wipe = unpack, select, pairs, ipairs, type, table.wipe
Nenue@0 10 local CreateFrame, IsControlKeyDown = _G.CreateFrame, _G.IsControlKeyDown
Nenue@0 11 local max = math.max
Nenue@0 12 local OpacitySliderFrame, ColorPickerFrame = _G.OpacitySliderFrame, _G.ColorPickerFrame
Nenue@0 13 local print = B.print('Cfgl')
Nenue@0 14 local function round(number, decimals)
Nenue@0 15 if floor(number) == number then
Nenue@0 16 return ('%d'):format(number)
Nenue@0 17 end
Nenue@0 18
Nenue@0 19 return (("%%.%df"):format(decimals)):format(number)
Nenue@0 20 end
Nenue@0 21
Nenue@24 22 M.defaults = {
Nenue@24 23 enable = true
Nenue@24 24 }
Nenue@24 25
Nenue@0 26 --- STATE VARIABLES
Nenue@0 27 local configInit
Nenue@0 28 --- Dummies for addon table upvalues
Nenue@0 29 local configFrames = {} -- actual frame objects
Nenue@0 30 local displays = B.displays -- anchor objects dummy
Nenue@0 31
Nenue@0 32
Nenue@0 33 --- Returns a value retreival function and the current value stored in config
Nenue@0 34 -- @paramsig value, previousValue = configInteger(key)
Nenue@0 35 -- @param key Name of the config field being represented.
Nenue@0 36 local defaultGroup = 'BuffButton'
Nenue@0 37 local configInteger = function(group, key)
Nenue@0 38 return function(self ,display)
Nenue@0 39 return floor(tonumber(self:GetValue()) + 0.5)
Nenue@0 40 end, (B.Conf[group ..key] or B.Conf[defaultGroup..key])
Nenue@0 41 end
Nenue@0 42 local configPercent = function(group, key)
Nenue@0 43 return function(self, display)
Nenue@0 44 local value = self:GetValue()
Nenue@0 45 if display then
Nenue@0 46 return tostring(floor(value*100+0.5))..' %'
Nenue@0 47 else
Nenue@0 48 return floor((value*100+0.5))/100
Nenue@0 49 end
Nenue@0 50 end, (B.Conf[group ..key] or B.Conf[defaultGroup..key])
Nenue@0 51 end
Nenue@0 52 local configColor = function(group, key)
Nenue@0 53 -- table for config, color value list for text
Nenue@0 54 return function(self, display)
Nenue@0 55 if display then
Nenue@0 56 return "|cFFFF4444" .. round(self.rgba[1], 1) .. "|r, |cFF44FF44" .. round(self.rgba[2], 1) .. "|r, |cFF4488FF" ..
Nenue@0 57 round(self.rgba[3], 1) .. "|r, " .. round(self.rgba[4], 1)
Nenue@0 58 else
Nenue@0 59 return self.rgba
Nenue@0 60 end
Nenue@0 61 end, (B.Conf[group ..key] or B.Conf[defaultGroup..key])
Nenue@0 62 end
Nenue@0 63 local configCheck = function(group, key)
Nenue@0 64 return function(self) return self:GetChecked() end, B.Conf[group ..key] or B.Conf[defaultGroup..key]
Nenue@0 65 end
Nenue@0 66 -- initializes the corresponding type of config field
Nenue@0 67 local frameTypeConv = {
Nenue@0 68 Color = 'Button',
Nenue@0 69 Font = 'Frame',
Nenue@0 70 }
Nenue@0 71 local configTypeParams = {
Nenue@0 72 Slider = function(frame, optionInfo)
Nenue@0 73 frame:SetMinMaxValues(optionInfo[5], optionInfo[6])
Nenue@0 74 frame:SetValueStep(optionInfo[7])
Nenue@0 75 frame:SetStepsPerPage(optionInfo[8])
Nenue@0 76 print(frame.OptName, '\n {', optionInfo[5], optionInfo[6], optionInfo[7], optionInfo[8], '}')
Nenue@0 77 end,
Nenue@0 78 CheckButton = function(frame, optionInfo)
Nenue@0 79 frame.SetValue = function(self, ...)
Nenue@0 80 self:SetChecked(...)
Nenue@0 81 B.Conf[self.OptName] = self:GetChecked()
Nenue@0 82 print(self.OptTab)
Nenue@0 83 B.UpdateAll()
Nenue@0 84 end
Nenue@0 85 frame:SetScript("OnClick",function(self)
Nenue@0 86 B.Conf[self.OptName] = self:GetChecked()
Nenue@0 87 print(B.Conf[self.OptName], self:GetChecked())
Nenue@0 88 B.UpdateAll()
Nenue@0 89 end)
Nenue@0 90 end,
Nenue@0 91 Color = function(frame, optionInfo)
Nenue@0 92 frame.rgba = { frame.current:GetVertexColor() }
Nenue@0 93 local colorPickerCallback = function(restore)
Nenue@0 94 local newR, newG, newB, newA
Nenue@0 95 if restore then
Nenue@0 96 newR, newG, newB, newA = unpack(restore)
Nenue@0 97 else
Nenue@0 98 newA, newR, newG, newB = OpacitySliderFrame:GetValue(), ColorPickerFrame:GetColorRGB()
Nenue@0 99 print('not cancel', newA, newR, newB, newG)
Nenue@0 100 end
Nenue@0 101 frame:SetValue({newR, newG, newB, newA})
Nenue@0 102 B.UpdateBuffs(frame.OptTab)
Nenue@0 103 end
Nenue@0 104 frame:SetScript("OnClick", function(self)
Nenue@0 105 print('got a click')
Nenue@0 106 local r, g, b, a = frame.current:GetVertexColor()
Nenue@0 107 ColorPickerFrame:SetColorRGB(r, g, b)
Nenue@0 108 ColorPickerFrame.hasOpacity = (a ~= nil)
Nenue@0 109 ColorPickerFrame.opacity = a
Nenue@0 110 ColorPickerFrame.previousValues = {r,g,b,a}
Nenue@0 111 ColorPickerFrame.func, ColorPickerFrame.opacityFunc, ColorPickerFrame.cancelFunc =
Nenue@0 112 colorPickerCallback, colorPickerCallback,colorPickerCallback
Nenue@0 113 ColorPickerFrame:Hide()
Nenue@0 114 ColorPickerFrame:Show()
Nenue@0 115 end)
Nenue@0 116 frame.SetValue = function(self, rgba)
Nenue@0 117 print(rgba)
Nenue@0 118 frame.rgba = rgba
Nenue@0 119 B.Conf[self.OptName] = rgba
Nenue@0 120 frame.current:SetVertexColor(unpack(rgba))
Nenue@0 121 frame.fieldvalue:SetText(frame.OptValue(frame, true))
Nenue@0 122 end
Nenue@0 123 end
Nenue@0 124 }
Nenue@0 125 --- configDialog
Nenue@0 126 -- @usage tinsert(configDialog, {prefix, row, [...] })
Nenue@0 127 -- Each top level member defines a group of config value handlers, structured as an iterative table where the
Nenue@0 128 -- first member is a key prefix, the second member is an integer row value, and all following members are treated
Nenue@0 129 -- as a widget resource, defined initially as a complete sub-table, which can be re-used further down by passing
Nenue@0 130 -- the string literal widget suffix.
Nenue@0 131 -- widget table: ... {'suffix', 'description', valueCallback, 'template', [widget parameters]}
Nenue@0 132 -- widget copy: ... 'suffix', ...
Nenue@0 133 local configDialog = {
Nenue@0 134 {'BuffButton', 1,
Nenue@0 135
Nenue@0 136 {'Max', 'Max', configInteger, 'Slider',
Nenue@0 137 1, _G.BUFF_MAX_DISPLAY, 1, 1}, -- valueMin, valueMax, valueStep, stepsPerPage
Nenue@0 138 {'PerRow', 'Per Row', configInteger, 'Slider',
Nenue@0 139 1, _G.BUFF_MAX_DISPLAY, 1, 1}, -- valueMin, valueMax, valueStep, stepsPerPage,
Nenue@0 140 {'Size', 'Icon Size', configInteger, 'Slider',
Nenue@0 141 1, 256, 1, 1},
Nenue@0 142 {'Spacing', 'Icon Spacing', configInteger, 'Slider',
Nenue@0 143 1, 50, 1, 1},
Nenue@0 144 {'DurationSize', 'Duration Text Height', configInteger, 'Slider',
Nenue@0 145 1, 72, 1, 1},
Nenue@0 146 {'Zoom', 'Icon Zoom', configInteger, 'Slider',
Nenue@0 147 0, 100, 1, 1},
Nenue@0 148 {'Border', 'Border', configInteger, 'Slider',
Nenue@0 149 1, 16, 1, 1},
Nenue@0 150 {'Color', 'Default Border', configColor, 'Color'},
Nenue@0 151 {'RaidColor', 'RaidBuff Border', configColor, 'Color'},
Nenue@0 152 {'PlayerColor', 'Player Buffs', configColor, 'Color'},
Nenue@0 153 {'BossColor', 'Encounter Buffs', configColor, 'Color'},
Nenue@0 154 {'ShowSelfCast', 'Show name for self-casts', configCheck, 'CheckButton'}
Nenue@0 155 },
Nenue@0 156 { 'DebuffButton', 1,
Nenue@0 157 {'Max', 'Max', configInteger, 'Slider',
Nenue@0 158 1, _G.DEBUFF_MAX_DISPLAY, 1, 1 }
Nenue@0 159 ,
Nenue@0 160 {'PerRow', 'Per Row', configInteger, 'Slider',
Nenue@0 161 1, _G.DEBUFF_MAX_DISPLAY, 1, 1 },
Nenue@0 162 'Size', 'Spacing', 'DurationSize', 'Zoom', 'Border',
Nenue@0 163 'Color', 'RaidColor', 'PlayerColor', 'BossColor',
Nenue@0 164 },
Nenue@0 165 { 'TempEnchant', 1,
Nenue@0 166 {'Max', 'Max', configInteger, 'Slider',
Nenue@0 167 1, _G.NUM_TEMP_ENCHANT_FRAMES, 1, 1 },
Nenue@0 168 {'PerRow', 'Per Row', configInteger, 'Slider',
Nenue@0 169 1, _G.NUM_TEMP_ENCHANT_FRAMES, 1, 1},
Nenue@0 170 'Size', 'Spacing', 'DurationSize', 'Zoom', 'Border',
Nenue@0 171 'Color', 'RaidColor', 'PlayerColor', 'BossColor',
Nenue@0 172 },
Nenue@0 173 { 'ConsolidatedBuff', 2,
Nenue@0 174 {'Position', 'Slot Position', configInteger, 'Slider',
Nenue@0 175 1, _G.BUFF_MAX_DISPLAY, 1, 1 }
Nenue@0 176
Nenue@0 177 },
Nenue@0 178 { 'ConsolidatedBuff', 2,
Nenue@0 179 'Size'
Nenue@0 180 },
Nenue@0 181 { 'Raid', 3,
Nenue@0 182 {'ShowMissing', 'Verbose missing raid buffs', configCheck, 'CheckButton'}
Nenue@0 183 }
Nenue@0 184 }
Nenue@0 185
Nenue@0 186
Nenue@0 187
Nenue@0 188
Nenue@0 189 local configFrame
Nenue@0 190 local optionTemplates = {}
Nenue@0 191 local configPadding, configSpacing = 3, 3
Nenue@0 192
Nenue@0 193 --- Walks the structure table to generate a pretty config panel
Nenue@0 194 local InitConfig = function()
Nenue@0 195 configInit = true
Nenue@0 196 local configWidth = B:GetWidth()
Nenue@0 197 local optionWidth = (configWidth - configPadding) / 3 - configSpacing
Nenue@0 198 local configHeight = 0
Nenue@0 199 local bottom_extent = 0
Nenue@0 200 local clusterHeight = 0
Nenue@0 201 local clusterOffset = 0
Nenue@0 202 local lastCluster
Nenue@0 203 local cluster = 1
Nenue@0 204 local col = 0
Nenue@0 205 for t, taboptions in ipairs(configDialog) do
Nenue@0 206 local group = taboptions[1]
Nenue@0 207 cluster = taboptions[2]
Nenue@0 208 col = col + 1
Nenue@0 209
Nenue@0 210
Nenue@0 211 if not configFrames[t] then
Nenue@0 212 configFrames[t] = {}
Nenue@0 213 end
Nenue@0 214
Nenue@0 215
Nenue@0 216 if cluster ~= lastCluster then
Nenue@0 217 configHeight = configHeight + clusterHeight
Nenue@0 218 print('|cFFFF8800## new cluster|r, advancing offset from', clusterOffset, 'to', clusterOffset + clusterHeight)
Nenue@0 219 clusterOffset = clusterOffset + clusterHeight
Nenue@0 220 col = 1
Nenue@0 221 clusterHeight = 0
Nenue@0 222 lastCluster = cluster
Nenue@0 223 end
Nenue@0 224
Nenue@0 225 print('processing tab', group)
Nenue@0 226 local row = 0
Nenue@0 227 for i = 3, #taboptions do
Nenue@0 228 row = row + 1
Nenue@0 229 local optionInfo = taboptions[i]
Nenue@0 230 if type(optionInfo) == 'string' then
Nenue@0 231 optionInfo = optionTemplates[optionInfo]
Nenue@0 232 end
Nenue@0 233 local key, fieldname, valueFuncGenerator, configType = unpack(optionInfo)
Nenue@0 234
Nenue@0 235 if not optionTemplates[key] then
Nenue@0 236 optionTemplates[key] = optionInfo
Nenue@0 237 end
Nenue@0 238
Nenue@0 239 local fullkey = group .. key
Nenue@0 240 print(fullkey, fieldname)
Nenue@0 241
Nenue@0 242 if not configFrames[t][row] then
Nenue@0 243 print('building frame', t, group, row)
Nenue@0 244 local frameTemplate = 'VeneerConfig'..configType
Nenue@0 245 local frameType = frameTypeConv[configType] or configType
Nenue@0 246 configFrames[t][row] = CreateFrame(frameType, fullkey, B, frameTemplate)
Nenue@0 247 local f = configFrames[t][row]
Nenue@0 248 f.OptKey = key
Nenue@0 249 f.OptTab = group
Nenue@0 250 f.OptName = fullkey
Nenue@0 251 local valueFunc, initialValue = valueFuncGenerator(group, key)
Nenue@0 252 print(' value getter', fullkey,'->', valueFunc,initialValue)
Nenue@0 253 configTypeParams[configType](f, optionInfo)
Nenue@0 254 f.OptValue = valueFunc
Nenue@0 255
Nenue@0 256 --- Enclosing these to
Nenue@0 257 -- a) make the panel easy to bring up externally
Nenue@0 258 -- b) limit gameplay risk from config frame errors
Nenue@0 259 -- c) milk the iterator scope for all its worth
Nenue@0 260 f.OnChange = function(self)
Nenue@0 261
Nenue@0 262 -- holding control; mirror this setting in other categories
Nenue@0 263 if IsControlKeyDown() and not (configInit) then
Nenue@0 264 configInit = true
Nenue@0 265 for optTab, opts in pairs(configFrames) do
Nenue@0 266 for _, opt in ipairs(opts) do
Nenue@0 267 if opt.OptKey == key then
Nenue@0 268 if optTab ~= group then
Nenue@0 269 print('mapping to', optTab, opt.OptKey)
Nenue@0 270 opt:SetValue(self:GetValue())
Nenue@0 271 end
Nenue@0 272
Nenue@0 273 end
Nenue@0 274 end
Nenue@0 275 end
Nenue@0 276 configInit = nil
Nenue@0 277 end
Nenue@0 278 local newValue = valueFunc(self)
Nenue@0 279 if newValue ~= B.Conf[fullkey] then
Nenue@0 280 print(newValue, fullkey)
Nenue@0 281 f.fieldvalue:SetText(valueFunc(self, true))
Nenue@0 282 B.Conf[fullkey] = valueFunc(self)
Nenue@0 283 -- prepare to update
Nenue@0 284 wipe(B.drawn[f.OptTab])
Nenue@0 285 B.UpdateBuffs(self.OptTab)
Nenue@0 286 B.UpdateConfigLayers()
Nenue@0 287 end
Nenue@0 288
Nenue@0 289 end
Nenue@0 290
Nenue@0 291 f:SetValue(initialValue)
Nenue@0 292 local yBuffer = configPadding
Nenue@0 293 if f.fieldname then
Nenue@0 294 f.fieldname:SetText(fieldname)
Nenue@0 295 yBuffer = yBuffer + f.fieldname:GetHeight()
Nenue@0 296 end
Nenue@0 297 if f.fieldvalue then
Nenue@0 298 f.fieldvalue:SetText(f:OptValue(true))
Nenue@0 299 end
Nenue@0 300
Nenue@0 301 local point, relative, x, y = 'TOPLEFT', 'BOTTOMLEFT', 0, -3
Nenue@0 302
Nenue@0 303 local base
Nenue@0 304 if (row == 1) then
Nenue@0 305 bottom_extent = 0
Nenue@0 306 base = B.header
Nenue@0 307 x = (col-1) * (optionWidth+configSpacing)
Nenue@0 308 y = -configPadding
Nenue@0 309 else
Nenue@0 310 base = configFrames[t][row-1]
Nenue@0 311 end
Nenue@0 312
Nenue@0 313 print('|cFFFF0088'..cluster..'|r |cFF00FF00'.. row..'|r', col, base:GetName(), x, y - clusterOffset)
Nenue@0 314
Nenue@0 315 if frameType ~= 'CheckButton' then
Nenue@0 316 f:SetWidth(optionWidth)
Nenue@0 317 end
Nenue@0 318
Nenue@0 319 f:SetPoint(point, base, relative, x, y-yBuffer-clusterOffset)
Nenue@0 320 --print('creating', frameType, fieldname)
Nenue@0 321 f:Show()
Nenue@0 322
Nenue@0 323 bottom_extent = bottom_extent + f:GetHeight() + yBuffer + configSpacing
Nenue@0 324
Nenue@0 325
Nenue@0 326
Nenue@0 327 clusterHeight = max(clusterHeight, bottom_extent)
Nenue@0 328 --print('y', floor(yBuffer+0.5), 'f:H', floor(f:GetHeight()+0.5), 'hTally', floor(bottom_extent+0.5), 'hMax', floor(configHeight+0.5))
Nenue@0 329 end
Nenue@0 330 end
Nenue@0 331 end
Nenue@0 332
Nenue@0 333 -- grab the last cluster
Nenue@0 334 if lastCluster == cluster then
Nenue@0 335 print('|cFF00FF00##scooping up last cluster info')
Nenue@0 336 configHeight = configHeight + clusterHeight
Nenue@0 337 end
Nenue@0 338
Nenue@0 339 if not B.configFramesCreated then
Nenue@0 340 B.configFramesCreated = true
Nenue@0 341 B:SetHeight(B.header:GetStringHeight() + configSpacing*3 + configHeight)
Nenue@0 342 end
Nenue@0 343 if configInit then configInit = nil end
Nenue@0 344 end
Nenue@0 345
Nenue@0 346 M.Command = function(enable, editbox)
Nenue@0 347 displays = B.displays
Nenue@0 348 if type(enable) == 'boolean' then
Nenue@0 349 B.Conf.ConfigMode = enable
Nenue@0 350 else
Nenue@0 351 B.Conf.ConfigMode = (B.Conf.ConfigMode == false) and true or false
Nenue@0 352 end
Nenue@0 353
Nenue@0 354 print('/BUFF', B.Conf.ConfigMode, type(B.Conf.ConfigMode))
Nenue@0 355 if B.Conf.ConfigMode then
Nenue@0 356 if not B.configFramesCreated then
Nenue@0 357 InitConfig()
Nenue@0 358 end
Nenue@0 359 print('Veneer config')
Nenue@0 360 B:Show()
Nenue@0 361 else
Nenue@0 362 B:Hide()
Nenue@0 363 end
Nenue@0 364 B.UpdateAll()
Nenue@0 365 B.UpdateConfigLayers()
Nenue@0 366 end
Nenue@0 367
Nenue@0 368 B.Close = function ()
Nenue@0 369 M.Command()
Nenue@0 370 end
Nenue@0 371
Nenue@0 372 B.ToggleGuides = function(_, self)
Nenue@0 373 B.Conf.GuidesMode = (not B.Conf.GuidesMode)
Nenue@0 374 if B.Conf.GuidesMode then
Nenue@0 375 self:GetNormalTexture():SetTexture(0.94, 0.21, 0.21, 1)
Nenue@0 376 else
Nenue@0 377 self:GetNormalTexture():SetTexture(0, 0, 0, 1)
Nenue@0 378 end
Nenue@0 379
Nenue@0 380 B.UpdateConfigLayers()
Nenue@0 381 end
Nenue@0 382
Nenue@0 383 M.OnEnable = function()
Nenue@24 384 print('|cFFFF0088config module', B.Conf.ConfigMode)
Nenue@0 385 M.Command(B.Conf.ConfigMode)
Nenue@0 386 end
Nenue@0 387
Nenue@0 388 M.OnInitialize = function()
Nenue@0 389 DEFAULT_CHAT_FRAME:AddMessage("|cFF22D822Veneer|r")
Nenue@0 390 SLASH_BUFFALO1, SLASH_BUFFALO2 = "/buffalo", "/buff"
Nenue@0 391 SlashCmdList.BUFFALO = M.Command
Nenue@0 392
Nenue@0 393 end