annotate Config.lua @ 35:69d03f8e293e

- separated layout and data logic between Frame.lua and Update.lua - solved disappearing tracker mystery
author Nenue
date Sun, 17 Apr 2016 11:07:48 -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