comparison Editor.lua @ 257:920d17851a93 stable

Merge 1.1 beta 4 to stable
author Flick
date Tue, 12 Apr 2011 16:06:31 -0700
parents f255cd69e890
children d7a7ef367faf
comparison
equal deleted inserted replaced
210:b2b105747466 257:920d17851a93
1 local addonName, addonTable = ... 1 local addonName, addonTable = ...
2 local ReAction = addonTable.ReAction 2 local ReAction = addonTable.ReAction
3 local L = ReAction.L 3 local L = ReAction.L
4 local _G = _G 4 local _G = _G
5 local wipe = wipe 5 local wipe = wipe
6 local format = string.format
7 local InCombatLockdown = InCombatLockdown
8 local tfetch = addonTable.tfetch
9 local tbuild = addonTable.tbuild
6 10
7 local AceConfigReg = LibStub("AceConfigRegistry-3.0") 11 local AceConfigReg = LibStub("AceConfigRegistry-3.0")
8 local AceConfigDialog = LibStub("AceConfigDialog-3.0") 12 local AceConfigDialog = LibStub("AceConfigDialog-3.0")
9 13
10 14
11 local pointTable = { 15 local pointTable = {
16 NONE = " ",
12 CENTER = L["Center"], 17 CENTER = L["Center"],
13 LEFT = L["Left"], 18 LEFT = L["Left"],
14 RIGHT = L["Right"], 19 RIGHT = L["Right"],
15 TOP = L["Top"], 20 TOP = L["Top"],
16 BOTTOM = L["Bottom"], 21 BOTTOM = L["Bottom"],
18 TOPRIGHT = L["Top Right"], 23 TOPRIGHT = L["Top Right"],
19 BOTTOMLEFT = L["Bottom Left"], 24 BOTTOMLEFT = L["Bottom Left"],
20 BOTTOMRIGHT = L["Bottom Right"], 25 BOTTOMRIGHT = L["Bottom Right"],
21 } 26 }
22 27
23 local Editor = { } 28 local Editor = {
29 buttonHandlers = { }
30 }
24 31
25 function Editor:New() 32 function Editor:New()
26 -- create new self 33 -- create new self
27 self = setmetatable( { }, { __index = self } ) 34 self = setmetatable( { }, { __index = self } )
28 35
88 type = { 95 type = {
89 type = "select", 96 type = "select",
90 name = L["Button Type"], 97 name = L["Button Type"],
91 get = function() return self.tmp.barType or ReAction:GetDefaultBarType() or "" end, 98 get = function() return self.tmp.barType or ReAction:GetDefaultBarType() or "" end,
92 set = function(info, val) 99 set = function(info, val)
93 local c = ReAction:GetBarTypeConfig(val) 100 local c = ReAction:GetDefaultBarConfig(val)
94 self.tmp.barType = val 101 self.tmp.barType = val
95 self.tmp.barSize = c.defaultButtonSize or self.tmp.barSize 102 self.tmp.barSize = c.btnWidth or self.tmp.barSize
96 self.tmp.barRows = c.defaultBarRows or self.tmp.barRows 103 self.tmp.barRows = c.btnRows or self.tmp.barRows
97 self.tmp.barCols = c.defaultBarCols or self.tmp.barCols 104 self.tmp.barCols = c.btnColumns or self.tmp.barCols
98 self.tmp.barSpacing = c.defaultBarSpacing or self.tmp.barSpacing 105 self.tmp.barSpacing = c.spacing or self.tmp.barSpacing
99 end, 106 end,
100 values = "GetBarTypes", 107 values = "GetBarTypes",
101 order = 3, 108 order = 3,
102 }, 109 },
103 go = { 110 go = {
171 AceConfigReg:RegisterOptionsTable(self.configID, self.options) 178 AceConfigReg:RegisterOptionsTable(self.configID, self.options)
172 AceConfigDialog:SetDefaultSize(self.configID, 700, 540) 179 AceConfigDialog:SetDefaultSize(self.configID, 700, 540)
173 180
174 ReAction.RegisterCallback(self,"OnCreateBar") 181 ReAction.RegisterCallback(self,"OnCreateBar")
175 ReAction.RegisterCallback(self,"OnDestroyBar") 182 ReAction.RegisterCallback(self,"OnDestroyBar")
176 ReAction.RegisterCallback(self,"OnEraseBar")
177 ReAction.RegisterCallback(self,"OnRenameBar") 183 ReAction.RegisterCallback(self,"OnRenameBar")
178 184
179 for name, bar in ReAction:IterateBars() do 185 self:RefreshBarOptions()
180 self:CreateBarTree(bar)
181 end
182 186
183 return self 187 return self
184 end 188 end
185 189
186 190
201 205
202 function Editor:Refresh() 206 function Editor:Refresh()
203 AceConfigReg:NotifyChange(self.configID) 207 AceConfigReg:NotifyChange(self.configID)
204 end 208 end
205 209
206 function Editor:CreateBarTree(bar) 210 function Editor:UpdateBarOptions(bar)
207 local name = bar:GetName() 211 local name = bar:GetName()
208 -- AceConfig doesn't allow spaces, etc, in arg key names, and they must be 212 local key = self.barOptMap[name]
209 -- unique strings. So generate a unique key (it can be whatever) for the bar
210 local args = self.options.args 213 local args = self.options.args
211 local key 214
212 local i = 1 215 if not key then
213 repeat 216 -- AceConfig doesn't allow spaces, etc, in arg key names, and they must be
214 key = ("bar%s"):format(i) 217 -- unique strings. So generate a unique key (it can be whatever) for the bar
215 i = i+1 218 local i = 1
216 until args[key] == nil 219 repeat
217 self.barOptMap[name] = key 220 key = ("bar%s"):format(i)
218 args[key] = { 221 i = i+1
219 type = "group", 222 until args[key] == nil
220 name = name, 223 self.barOptMap[name] = key
221 childGroups = "tab", 224
222 order = i+100, 225 args[key] = {
223 args = { 226 type = "group",
224 general = { 227 name = name,
225 type = "group", 228 childGroups = "tab",
226 name = L["General"], 229 order = i+100,
227 order = 1, 230 args = {
228 args = { 231 general = {
229 name = { 232 type = "group",
230 type = "input", 233 name = L["General"],
231 name = L["Rename Bar"], 234 order = 1,
232 get = function() return bar:GetName() end, 235 args = {
233 set = function(info, value) return ReAction:RenameBar(bar, value) end, 236 name = {
234 order = 1, 237 type = "input",
235 }, 238 name = L["Rename Bar"],
236 delete = { 239 get = function() return bar:GetName() end,
237 type = "execute", 240 set = function(info, value) return ReAction:RenameBar(bar, value) end,
238 name = L["Delete Bar"], 241 order = 1,
239 desc = function() return bar:GetName() end, 242 },
240 confirm = true, 243 delete = {
241 func = function() ReAction:EraseBar(bar) end, 244 type = "execute",
242 order = 2 245 name = L["Delete Bar"],
243 }, 246 desc = function() return bar:GetName() end,
244 anchor = { 247 confirm = true,
245 type = "group", 248 func = function() ReAction:EraseBar(bar) end,
246 name = L["Anchor"], 249 order = 2
247 inline = true, 250 },
248 args = { 251 anchor = {
249 frame = { 252 type = "group",
250 type = "input", 253 name = L["Anchor"],
251 name = L["Frame"], 254 inline = true,
252 desc = L["The frame that the bar is anchored to"], 255 args = {
253 get = function() local _, f = bar:GetAnchor(); return f end, 256 frame = {
254 set = function(info, val) bar:SetAnchor(nil,val) end, 257 type = "input",
255 validate = function(info, name) 258 name = L["Frame"],
256 if name then 259 desc = L["The frame that the bar is anchored to"],
257 local f = ReAction:GetBar(name) 260 get = function() local _, f = bar:GetAnchor(); return f end,
258 if f then 261 set = function(info, val) bar:SetAnchor(nil,val) end,
259 return true 262 validate = function(info, name)
260 else 263 if name then
261 f = _G[name] 264 local f = ReAction:GetBar(name)
262 if f and type(f) == "table" and f.IsObjectType and f:IsObjectType("Frame") then 265 if f then
263 local _, explicit = f:IsProtected() 266 return true
264 return explicit 267 else
268 f = _G[name]
269 if f and type(f) == "table" and f.IsObjectType and f:IsObjectType("Frame") then
270 local _, explicit = f:IsProtected()
271 return explicit
272 end
265 end 273 end
266 end 274 end
267 end 275 return false
268 return false 276 end,
269 end, 277 width = "double",
270 width = "double", 278 order = 1
271 order = 1 279 },
280 point = {
281 type = "select",
282 name = L["Point"],
283 desc = L["Anchor point on the bar frame"],
284 style = "dropdown",
285 get = function() return bar:GetAnchor() end,
286 set = function(info, val) bar:SetAnchor(val) end,
287 values = pointTable,
288 order = 2,
289 },
290 relativePoint = {
291 type = "select",
292 name = L["Relative Point"],
293 desc = L["Anchor point on the target frame"],
294 style = "dropdown",
295 get = function() local p,f,r = bar:GetAnchor(); return r end,
296 set = function(info, val) bar:SetAnchor(nil,nil,val) end,
297 values = pointTable,
298 order = 3,
299 },
300 x = {
301 type = "input",
302 pattern = "\-?%d+",
303 name = L["X offset"],
304 get = function() local p,f,r,x = bar:GetAnchor(); return ("%d"):format(x) end,
305 set = function(info,val) bar:SetAnchor(nil,nil,nil,val) end,
306 order = 4
307 },
308 y = {
309 type = "input",
310 pattern = "\-?%d+",
311 name = L["Y offset"],
312 get = function() local p,f,r,x,y = bar:GetAnchor(); return ("%d"):format(y) end,
313 set = function(info,val) bar:SetAnchor(nil,nil,nil,nil,val) end,
314 order = 5
315 },
272 }, 316 },
273 point = { 317 order = 3
274 type = "select",
275 name = L["Point"],
276 desc = L["Anchor point on the bar frame"],
277 style = "dropdown",
278 get = function() return bar:GetAnchor() end,
279 set = function(info, val) bar:SetAnchor(val) end,
280 values = pointTable,
281 order = 2,
282 },
283 relativePoint = {
284 type = "select",
285 name = L["Relative Point"],
286 desc = L["Anchor point on the target frame"],
287 style = "dropdown",
288 get = function() local p,f,r = bar:GetAnchor(); return r end,
289 set = function(info, val) bar:SetAnchor(nil,nil,val) end,
290 values = pointTable,
291 order = 3,
292 },
293 x = {
294 type = "input",
295 pattern = "\-?%d+",
296 name = L["X offset"],
297 get = function() local p,f,r,x = bar:GetAnchor(); return ("%d"):format(x) end,
298 set = function(info,val) bar:SetAnchor(nil,nil,nil,val) end,
299 order = 4
300 },
301 y = {
302 type = "input",
303 pattern = "\-?%d+",
304 name = L["Y offset"],
305 get = function() local p,f,r,x,y = bar:GetAnchor(); return ("%d"):format(y) end,
306 set = function(info,val) bar:SetAnchor(nil,nil,nil,nil,val) end,
307 order = 5
308 },
309 }, 318 },
310 order = 3 319 alpha = {
320 type = "range",
321 name = L["Transparency"],
322 get = function() return bar:GetAlpha() end,
323 set = function(info, val) bar:SetAlpha(val) end,
324 min = 0,
325 max = 1,
326 isPercent = true,
327 step = 0.01,
328 bigStep = 0.05,
329 order = 4,
330 },
311 }, 331 },
312 alpha = { 332 },
313 type = "range", 333 buttonOpts = self:CreateButtonOptions(bar),
314 name = L["Transparency"], 334 stateOpts = self:CreateStateOptions(bar)
315 get = function() return bar:GetAlpha() end, 335 }
316 set = function(info, val) bar:SetAlpha(val) end,
317 min = 0,
318 max = 1,
319 isPercent = true,
320 step = 0.01,
321 bigStep = 0.05,
322 order = 4,
323 },
324 },
325 },
326 } 336 }
327 } 337 end
328 self:RefreshBarOptions() 338
339 end
340
341 function Editor:CreateButtonOptions(bar)
342 local buttonClass = bar:GetButtonClass()
343 local classID = buttonClass:GetButtonTypeID()
344 local handler = self.buttonHandlers[classID]
345
346 if handler then
347 local h = handler:New(bar)
348 return h:GetOptions()
349 end
329 end 350 end
330 351
331 function Editor:RefreshBarOptions() 352 function Editor:RefreshBarOptions()
332 for name, key in pairs(self.barOptMap) do 353 for name, key in pairs(self.barOptMap) do
333 local bar = ReAction:GetBar(name) 354 if not ReAction:GetBar(name) then
334 if bar and key and self.options.args[key] then 355 self.barOptMap[name] = nil
335 self.options.args[key].plugins = self:GenerateBarOptionsTable(bar) 356 self.options.args[key] = nil
336 end 357 end
337 end 358 end
338 AceConfigReg:NotifyChange(self.configID) 359 for name, bar in ReAction:IterateBars() do
360 self:UpdateBarOptions(bar)
361 end
362 self:Refresh()
339 end 363 end
340 364
341 function Editor:OnCreateBar(evt, bar) 365 function Editor:OnCreateBar(evt, bar)
342 if not self.tmp.creating then 366 self:UpdateBarOptions(bar)
343 -- a bit of hack to work around OnCreateBar event handler ordering 367 self:Refresh()
344 self:CreateBarTree(bar)
345 end
346 end 368 end
347 369
348 function Editor:OnDestroyBar(evt, bar, name) 370 function Editor:OnDestroyBar(evt, bar, name)
349 local key = self.barOptMap[name] 371 local key = self.barOptMap[name]
350 if key then 372 if key then
351 self.options.args[key] = nil 373 self.barOptMap[name] = nil
352 end
353 self:Refresh()
354 end
355
356 function Editor:OnEraseBar(evt, name)
357 local key = self.barOptMap[name]
358 self.barOptMap[name] = nil
359 if key then
360 self.options.args[key] = nil 374 self.options.args[key] = nil
361 self:Refresh() 375 self:Refresh()
362 end 376 end
363 end 377 end
364 378
365 function Editor:OnRenameBar(evt, bar, oldname, newname) 379 function Editor:OnRenameBar(evt, bar, oldname, newname)
366 local key = self.barOptMap[oldname] 380 local key = self.barOptMap[oldname]
367 self.barOptMap[oldname], self.barOptMap[newname] = nil, key
368 if key then 381 if key then
382 self.barOptMap[oldname], self.barOptMap[newname] = nil, key
369 self.options.args[key].name = newname 383 self.options.args[key].name = newname
370 self:Refresh() 384 self:Refresh()
371 end 385 end
372 end 386 end
373 387
377 return ReAction:GetBarTypeOptions(_scratch) 391 return ReAction:GetBarTypeOptions(_scratch)
378 end 392 end
379 393
380 function Editor:CreateBar() 394 function Editor:CreateBar()
381 if self.tmp.barName and self.tmp.barName ~= "" then 395 if self.tmp.barName and self.tmp.barName ~= "" then
382 self.tmp.creating = true
383 local bar = ReAction:CreateBar(self.tmp.barName, self.tmp.barType or ReAction:GetDefaultBarType(), self.tmp.barRows, self.tmp.barCols, self.tmp.barSize, self.tmp.barSpacing) 396 local bar = ReAction:CreateBar(self.tmp.barName, self.tmp.barType or ReAction:GetDefaultBarType(), self.tmp.barRows, self.tmp.barCols, self.tmp.barSize, self.tmp.barSpacing)
384 if bar then 397 if bar then
385 self:CreateBarTree(bar)
386 AceConfigDialog:SelectGroup(self.configID, self.barOptMap[self.tmp.barName]) 398 AceConfigDialog:SelectGroup(self.configID, self.barOptMap[self.tmp.barName])
387 self.tmp.barName = nil 399 self.tmp.barName = nil
388 end 400 end
389 self.tmp.creating = false 401 end
390 end 402 end
391 end 403
392 404 -------------------------------
393 function Editor:GenerateBarOptionsTable( bar ) 405 ---- Action button handler ----
394 local opts = { } 406 -------------------------------
395 if not ReAction.barOptionGenerators then 407
396 return 408 do
397 end 409 local ActionHandler = {
398 410 buttonClass = ReAction.Button.Action,
399 for module, func in pairs(ReAction.barOptionGenerators) do 411 options = {
400 local success, r 412 hideEmpty = {
401 if type(func) == "string" then 413 name = L["Hide Empty Buttons"],
402 success, r = pcall(module[func], module, bar) 414 order = 1,
403 else 415 type = "toggle",
404 success, r = pcall(func, bar) 416 width = "double",
405 end 417 get = "GetHideEmpty",
406 if success then 418 set = "SetHideEmpty",
407 if r then 419 },
408 opts[module:GetName()] = { [module:GetName()] = r } 420 lockButtons = {
421 name = L["Lock Buttons"],
422 desc = L["Prevents picking up/dragging actions (use SHIFT to override this behavior)"],
423 order = 2,
424 type = "toggle",
425 get = "GetLockButtons",
426 set = "SetLockButtons",
427 },
428 lockOnlyCombat = {
429 name = L["Only in Combat"],
430 desc = L["Only lock the buttons when in combat"],
431 order = 3,
432 type = "toggle",
433 disabled = "LockButtonsCombatDisabled",
434 get = "GetLockButtonsCombat",
435 set = "SetLockButtonsCombat",
436 },
437 pages = {
438 name = L["# Pages"],
439 desc = L["Use the Dynamic State tab to specify page transitions"],
440 order = 4,
441 type = "range",
442 min = 1,
443 max = 10,
444 step = 1,
445 get = "GetNumPages",
446 set = "SetNumPages",
447 },
448 mindcontrol = {
449 name = L["Mind Control Support"],
450 desc = L["When possessing a target (e.g. via Mind Control), map the first 12 buttons of this bar to the possessed target's actions."],
451 order = 5,
452 type = "toggle",
453 width = "double",
454 set = "SetMindControl",
455 get = "GetMindControl",
456 },
457 vehicle = {
458 name = L["Vehicle Support"],
459 desc = L["When on a vehicle, map the first 6 buttons of this bar to the vehicle actions. The vehicle-exit button is mapped to the 7th button. Pitch controls are not supported."],
460 order = 6,
461 type = "toggle",
462 width = "double",
463 get = "GetVehicle",
464 set = "SetVehicle",
465 },
466 actions = {
467 name = L["Edit Action IDs"],
468 order = 7,
469 type = "group",
470 inline = true,
471 args = {
472 method = {
473 name = L["Assign"],
474 order = 1,
475 type = "select",
476 width = "double",
477 values = { [0] = L["Choose Method..."],
478 [1] = L["Individually"],
479 [2] = L["All at Once"], },
480 get = "GetActionEditMethod",
481 set = "SetActionEditMethod",
482 },
483 rowSelect = {
484 name = L["Row"],
485 desc = L["Rows are numbered top to bottom"],
486 order = 2,
487 type = "select",
488 width = "half",
489 hidden = "IsButtonSelectHidden",
490 values = "GetRowList",
491 get = "GetSelectedRow",
492 set = "SetSelectedRow",
493 },
494 colSelect = {
495 name = L["Col"],
496 desc = L["Columns are numbered left to right"],
497 order = 3,
498 type = "select",
499 width = "half",
500 hidden = "IsButtonSelectHidden",
501 values = "GetColumnList",
502 get = "GetSelectedColumn",
503 set = "SetSelectedColumn",
504 },
505 pageSelect = {
506 name = L["Page"],
507 order = 4,
508 type = "select",
509 width = "half",
510 hidden = "IsPageSelectHidden",
511 values = "GetPageList",
512 get = "GetSelectedPage",
513 set = "SetSelectedPage",
514 },
515 single = {
516 name = L["Action ID"],
517 usage = L["Specify ID 1-120"],
518 order = 5,
519 type = "input",
520 width = "half",
521 hidden = "IsButtonSelectHidden",
522 get = "GetActionID",
523 set = "SetActionID",
524 validate = "ValidateActionID",
525 },
526 multi = {
527 name = L["ID List"],
528 usage = L["Specify a comma-separated list of IDs for each button in the bar (in order). Separate multiple pages with semicolons (;)"],
529 order = 6,
530 type = "input",
531 multiline = true,
532 width = "double",
533 hidden = "IsMultiIDHidden",
534 get = "GetMultiID",
535 set = "SetMultiID",
536 validate = "ValidateMultiID",
537 },
538 },
539 },
540 }
541 }
542
543 Editor.buttonHandlers[ActionHandler.buttonClass:GetButtonTypeID()] = ActionHandler
544
545 local meta = { __index = ActionHandler }
546
547 function ActionHandler:New( bar )
548 return setmetatable(
549 {
550 bar = bar,
551 config = bar:GetConfig(),
552 },
553 meta)
554 end
555
556 function ActionHandler:Refresh()
557 self.buttonClass:SetupBar(self.bar)
558 end
559
560 function ActionHandler:UpdateButtonLock()
561 self.buttonClass:SetButtonLock(self.bar, self.config.lockButtons, self.config.lockButtonsCombat)
562 end
563
564 function ActionHandler:GetLastButton()
565 return self.bar:GetButton(self.bar:GetNumButtons())
566 end
567
568 -- options handlers
569 function ActionHandler:GetOptions()
570 return {
571 type = "group",
572 name = L["Action Buttons"],
573 handler = self,
574 order = 2,
575 args = self.options
576 }
577 end
578
579 function ActionHandler:SetHideEmpty(info, value)
580 if value ~= self.config.hideEmpty then
581 self.config.hideEmpty = value
582 for _, b in self.bar:IterateButtons() do
583 b:ShowGrid(not value)
409 end 584 end
410 else 585 end
411 geterrorhandler()(r) 586 end
412 end 587
413 end 588 function ActionHandler:GetHideEmpty()
414 return opts 589 return self.config.hideEmpty
415 end 590 end
416 591
592 function ActionHandler:GetLockButtons()
593 return self.config.lockButtons
594 end
595
596 function ActionHandler:SetLockButtons(info, value)
597 self.config.lockButtons = value
598 self:UpdateButtonLock()
599 end
600
601 function ActionHandler:GetLockButtonsCombat()
602 return self.config.lockButtonsCombat
603 end
604
605 function ActionHandler:SetLockButtonsCombat(info, value)
606 self.config.lockButtonsCombat = value
607 self:UpdateButtonLock()
608 end
609
610 function ActionHandler:LockButtonsCombatDisabled()
611 return not self.config.lockButtons
612 end
613
614 function ActionHandler:GetNumPages()
615 return self.config.nPages
616 end
617
618 function ActionHandler:SetNumPages(info, value)
619 self.config.nPages = value
620 self:Refresh()
621 end
622
623 function ActionHandler:GetMindControl()
624 return self.config.mindcontrol
625 end
626
627 function ActionHandler:SetMindControl(info, value)
628 self.config.mindcontrol = value
629 self:Refresh()
630 end
631
632 function ActionHandler:GetVehicle()
633 return self.config.vehicle
634 end
635
636 function ActionHandler:SetVehicle(info, value)
637 self.config.vehicle = value
638 self:Refresh()
639 end
640
641 function ActionHandler:GetActionEditMethod()
642 return self.editMethod or 0
643 end
644
645 function ActionHandler:SetActionEditMethod(info, value)
646 self.editMethod = value
647 end
648
649 function ActionHandler:IsButtonSelectHidden()
650 return self.editMethod ~= 1
651 end
652
653 function ActionHandler:GetRowList()
654 local r,c = self.bar:GetButtonGrid()
655 if self.rowList == nil or #self.rowList ~= r then
656 local list = { }
657 for i = 1, r do
658 table.insert(list,i)
659 end
660 self.rowList = list
661 end
662 return self.rowList
663 end
664
665 function ActionHandler:GetSelectedRow()
666 local r, c = self.bar:GetButtonGrid()
667 local row = self.selectedRow or 1
668 if row > r then
669 row = 1
670 end
671 self.selectedRow = row
672 return row
673 end
674
675 function ActionHandler:SetSelectedRow(info, value)
676 self.selectedRow = value
677 end
678
679 function ActionHandler:GetColumnList()
680 local r,c = self.bar:GetButtonGrid()
681 if self.columnList == nil or #self.columnList ~= c then
682 local list = { }
683 for i = 1, c do
684 table.insert(list,i)
685 end
686 self.columnList = list
687 end
688 return self.columnList
689 end
690
691 function ActionHandler:GetSelectedColumn()
692 local r, c = self.bar:GetButtonGrid()
693 local col = self.selectedColumn or 1
694 if col > c then
695 col = 1
696 end
697 self.selectedColumn = col
698 return col
699 end
700
701 function ActionHandler:SetSelectedColumn(info, value)
702 self.selectedColumn = value
703 end
704
705 function ActionHandler:IsPageSelectHidden()
706 return self.editMethod ~= 1 or (self.config.nPages or 1) < 2
707 end
708
709 function ActionHandler:GetPageList()
710 local n = self.config.nPages or 1
711 if self.pageList == nil or #self.pageList ~= n then
712 local p = { }
713 for i = 1, n do
714 table.insert(p,i)
715 end
716 self.pageList = p
717 end
718 return self.pageList
719 end
720
721 function ActionHandler:GetSelectedPage()
722 local p = self.selectedPage or 1
723 if p > (self.config.nPages or 1) then
724 p = 1
725 end
726 self.selectedPage = p
727 return p
728 end
729
730 function ActionHandler:SetSelectedPage(info, value)
731 self.selectedPage = value
732 end
733
734 function ActionHandler:GetActionID()
735 local row = self.selectedRow or 1
736 local col = self.selectedColumn or 1
737 local r, c = self.bar:GetButtonGrid()
738 local n = (row-1) * c + col
739 local btn = self.bar:GetButton(n)
740 if btn then
741 return tostring(btn:GetActionID(self.selectedPage or 1))
742 end
743 end
744
745 function ActionHandler:SetActionID(info, value)
746 local row = self.selectedRow or 1
747 local col = self.selectedColumn or 1
748 local r, c = self.bar:GetButtonGrid()
749 local n = (row-1) * c + col
750 local btn = self.bar:GetButton(n)
751 if btn then
752 btn:SetActionID(tonumber(value), self.selectedPage or 1)
753 end
754 end
755
756 function ActionHandler:ValidateActionID(info, value)
757 value = tonumber(value)
758 if value == nil or value < 1 or value > 120 then
759 return L["Specify ID 1-120"]
760 end
761 return true
762 end
763
764 function ActionHandler:IsMultiIDHidden()
765 return self.editMethod ~= 2
766 end
767
768 function ActionHandler:GetMultiID()
769 local p = { }
770 for i = 1, self.config.nPages or 1 do
771 local b = { }
772 for _, btn in self.bar:IterateButtons() do
773 table.insert(b, btn:GetActionID(i))
774 end
775 table.insert(p, table.concat(b,","))
776 end
777 return table.concat(p,";\n")
778 end
779
780
781 local function ParseMultiID(nBtns, nPages, s)
782 if s:match("[^%d%s,;]") then
783 return nil
784 end
785 local p = { }
786 for list in s:gmatch("[^;]+") do
787 local pattern = ("^%s?$"):format(("%s*(%d+)%s*,"):rep(nBtns))
788 local ids = { list:match(pattern) }
789 if #ids ~= nBtns then
790 return nil
791 end
792 table.insert(p,ids)
793 end
794 if #p ~= nPages then
795 return nil
796 end
797 return p
798 end
799
800 function ActionHandler:SetMultiID(info, value)
801 local p = ParseMultiID(self.bar:GetNumButtons(), self.config.nPages or 1, value)
802 for page, b in ipairs(p) do
803 for button, id in ipairs(b) do
804 self.bar:GetButton(button):SetActionID(id, page)
805 end
806 end
807 end
808
809 function ActionHandler:ValidateMultiID(info, value)
810 local bad = L["Invalid action ID list string"]
811 if value == nil or ParseMultiID(self.bar:GetNumButtons(), self.config.nPages or 1, value) == nil then
812 return bad
813 end
814 return true
815 end
816 end
817
818
819 ----------------------------------
820 ---- PetAction button handler ----
821 ----------------------------------
822
823 do
824 local PetHandler = {
825 buttonClass = ReAction.Button.PetAction,
826 }
827
828 Editor.buttonHandlers[PetHandler.buttonClass:GetButtonTypeID()] = PetHandler
829
830 local meta = { __index = PetHandler }
831
832 function PetHandler:New(bar)
833 return setmetatable(
834 {
835 bar = bar,
836 config = bar.config
837 }, meta)
838 end
839
840 function PetHandler:GetLockButtons()
841 return self.config.lockButtons
842 end
843
844 function PetHandler:SetLockButtons(info, value)
845 self.config.lockButtons = value
846 self.buttonClass:UpdateButtonLock(self.bar)
847 end
848
849 function PetHandler:GetLockButtonsCombat()
850 return self.config.lockButtonsCombat
851 end
852
853 function PetHandler:SetLockButtonsCombat(info, value)
854 self.config.lockButtonsCombat = value
855 self.buttonClass:UpdateButtonLock(self.bar)
856 end
857
858 function PetHandler:LockButtonsCombatDisabled()
859 return not self.config.lockButtons
860 end
861
862 function PetHandler:GetOptions()
863 return {
864 type = "group",
865 name = L["Pet Buttons"],
866 handler = self,
867 order = 2,
868 args = {
869 lockButtons = {
870 name = L["Lock Buttons"],
871 desc = L["Prevents picking up/dragging actions (use SHIFT to override this behavior)"],
872 order = 2,
873 type = "toggle",
874 get = "GetLockButtons",
875 set = "SetLockButtons",
876 },
877 lockOnlyCombat = {
878 name = L["Only in Combat"],
879 desc = L["Only lock the buttons when in combat"],
880 order = 3,
881 type = "toggle",
882 disabled = "LockButtonsCombatDisabled",
883 get = "GetLockButtonsCombat",
884 set = "SetLockButtonsCombat",
885 },
886 }
887 }
888 end
889 end
890
891
892 -------------------------------------
893 ---- Vehicle Exit button handler ----
894 -------------------------------------
895
896 do
897 local VExitHandler = {
898 buttonClass = ReAction.Button.VehicleExit,
899 }
900
901 Editor.buttonHandlers[VExitHandler.buttonClass:GetButtonTypeID()] = VExitHandler
902
903 local meta = { __index = VExitHandler }
904
905 function VExitHandler:New(bar)
906 return setmetatable(
907 {
908 bar = bar,
909 }, meta)
910 end
911
912 function VExitHandler:GetConfig()
913 return self.bar:GetConfig()
914 end
915
916 function VExitHandler:GetPassengerOnly()
917 return not self:GetConfig().withControls
918 end
919
920 function VExitHandler:SetPassengerOnly(info, value)
921 self:GetConfig().withControls = not value
922 self.buttonClass:UpdateRegistration(self.bar)
923 end
924
925
926 function VExitHandler:GetOptions()
927 return {
928 type = "group",
929 name = L["Exit Vehicle"],
930 handler = self,
931 args = {
932 passengerOnly = {
933 name = L["Show only when passenger"],
934 desc = L["Only show the button when riding as a passenger in a vehicle (no vehicle controls)"],
935 order = 2,
936 width = "double",
937 type = "toggle",
938 get = "GetPassengerOnly",
939 set = "SetPassengerOnly",
940 },
941 }
942 }
943 end
944 end
945
946
947 ------------------------------
948 --- Dynamic State options ----
949 ------------------------------
950 do
951 local ApplyStates = ReAction.Bar.ApplyStates
952 local CleanupStates = ReAction.Bar.CleanupStates
953 local SetProperty = ReAction.Bar.SetStateProperty
954 local GetProperty = ReAction.Bar.GetStateProperty
955
956 -- pre-sorted by the order they should appear in
957 local rules = {
958 -- rule fields
959 { "stance", { {battle = L["Battle Stance"]}, {defensive = L["Defensive Stance"]}, {berserker = L["Berserker Stance"]} } },
960 { "form", { {caster = L["Caster Form"]}, {bear = L["Bear Form"]}, {cat = L["Cat Form"]}, {tree = L["Tree of Life"]}, {moonkin = L["Moonkin Form"]} } },
961 { "stealth", { {stealth = L["Stealth"]}, {nostealth = L["No Stealth"]}, {shadowdance = L["Shadow Dance"]} } },
962 { "shadow", { {shadowform = L["Shadowform"]}, {noshadowform = L["No Shadowform"]} } },
963 { "demon", { {demon = L["Demon Form"]}, {nodemon = L["No Demon Form"]} } },
964 { "pet", { {pet = L["With Pet"]}, {nopet = L["Without Pet"]} } },
965 { "target", { {harm = L["Hostile Target"]}, {help = L["Friendly Target"]}, {notarget = L["No Target"]} } },
966 { "focus", { {focusharm = L["Hostile Focus"]}, {focushelp = L["Friendly Focus"]}, {nofocus = L["No Focus"]} } },
967 { "possess", { {possess = L["Mind Control"]} } },
968 { "vehicle", { {vehicle = L["In a Vehicle"]} } },
969 { "group", { {raid = L["Raid"]}, {party = L["Party"]}, {solo = L["Solo"]} } },
970 { "combat", { {combat = L["In Combat"]}, {nocombat = L["Out of Combat"]} } },
971 }
972
973 local ruleSelect = { }
974 local ruleMap = { }
975 local optionMap = setmetatable({},{__mode="k"})
976
977
978 -- unpack rules table into ruleSelect and ruleMap
979 for _, c in ipairs(rules) do
980 local rule, fields = unpack(c)
981 for _, field in ipairs(fields) do
982 local key, label = next(field)
983 table.insert(ruleSelect, label)
984 table.insert(ruleMap, key)
985 end
986 end
987
988 local stateOptions = {
989 ordering = {
990 name = L["Info"],
991 order = 1,
992 type = "group",
993 args = {
994 delete = {
995 name = L["Delete this State"],
996 order = -1,
997 type = "execute",
998 func = "DeleteState",
999 },
1000 rename = {
1001 name = L["Name"],
1002 order = 1,
1003 type = "input",
1004 get = "GetName",
1005 set = "SetStateName",
1006 pattern = "^%w*$",
1007 usage = L["State names must be alphanumeric without spaces"],
1008 },
1009 ordering = {
1010 name = L["Evaluation Order"],
1011 desc = L["State transitions are evaluated in the order listed:\nMove a state up or down to change the order"],
1012 order = 2,
1013 type = "group",
1014 inline = true,
1015 args = {
1016 up = {
1017 name = L["Up"],
1018 order = 1,
1019 type = "execute",
1020 width = "half",
1021 func = "MoveStateUp",
1022 },
1023 down = {
1024 name = L["Down"],
1025 order = 2,
1026 type = "execute",
1027 width = "half",
1028 func = "MoveStateDown",
1029 }
1030 }
1031 }
1032 }
1033 },
1034 properties = {
1035 name = L["Properties"],
1036 order = 2,
1037 type = "group",
1038 args = {
1039 desc = {
1040 name = L["Set the properties for the bar when in this state"],
1041 order = 1,
1042 type = "description"
1043 },
1044 page = {
1045 name = L["Show Page #"],
1046 order = 11,
1047 type = "select",
1048 width = "half",
1049 disabled = "IsPageDisabled",
1050 hidden = "IsPageHidden",
1051 values = "GetPageValues",
1052 set = "SetProp",
1053 get = "GetPage",
1054 },
1055 hide = {
1056 name = L["Hide Bar"],
1057 order = 90,
1058 type = "toggle",
1059 set = "SetProp",
1060 get = "GetProp",
1061 },
1062 --[[ BROKEN
1063 keybindState = {
1064 name = L["Override Keybinds"],
1065 desc = L["Set this state to maintain its own set of keybinds which override the defaults when active"],
1066 order = 91,
1067 type = "toggle",
1068 set = "SetProp",
1069 get = "GetProp",
1070 }, ]]
1071 position = {
1072 name = L["Position"],
1073 order = 92,
1074 type = "group",
1075 inline = true,
1076 args = {
1077 anchorEnable = {
1078 name = L["Reposition"],
1079 order = 1,
1080 type = "toggle",
1081 set = "SetProp",
1082 get = "GetProp",
1083 },
1084 anchorFrame = {
1085 name = L["Anchor Frame"],
1086 order = 2,
1087 type = "select",
1088 values = "GetAnchorFrames",
1089 set = "SetAnchorFrame",
1090 get = "GetAnchorFrame",
1091 disabled = "GetAnchorDisabled",
1092 hidden = "GetAnchorDisabled",
1093 },
1094 anchorPoint = {
1095 name = L["Point"],
1096 order = 3,
1097 type = "select",
1098 values = pointTable,
1099 set = "SetAnchorPointProp",
1100 get = "GetAnchorPointProp",
1101 disabled = "GetAnchorDisabled",
1102 hidden = "GetAnchorDisabled",
1103 },
1104 anchorRelPoint = {
1105 name = L["Relative Point"],
1106 order = 4,
1107 type = "select",
1108 values = pointTable,
1109 set = "SetAnchorPointProp",
1110 get = "GetAnchorPointProp",
1111 disabled = "GetAnchorDisabled",
1112 hidden = "GetAnchorDisabled",
1113 },
1114 anchorX = {
1115 name = L["X Offset"],
1116 order = 5,
1117 type = "range",
1118 min = -100,
1119 max = 100,
1120 step = 1,
1121 set = "SetProp",
1122 get = "GetProp",
1123 disabled = "GetAnchorDisabled",
1124 hidden = "GetAnchorDisabled",
1125 },
1126 anchorY = {
1127 name = L["Y Offset"],
1128 order = 6,
1129 type = "range",
1130 min = -100,
1131 max = 100,
1132 step = 1,
1133 set = "SetProp",
1134 get = "GetProp",
1135 disabled = "GetAnchorDisabled",
1136 hidden = "GetAnchorDisabled",
1137 },
1138 },
1139 },
1140 scale = {
1141 name = L["Scale"],
1142 order = 93,
1143 type = "group",
1144 inline = true,
1145 args = {
1146 enableScale = {
1147 name = L["Set New Scale"],
1148 order = 1,
1149 type = "toggle",
1150 set = "SetProp",
1151 get = "GetProp",
1152 },
1153 scale = {
1154 name = L["Scale"],
1155 order = 2,
1156 type = "range",
1157 min = 0.25,
1158 max = 2.5,
1159 step = 0.05,
1160 isPercent = true,
1161 set = "SetProp",
1162 get = "GetScale",
1163 disabled = "GetScaleDisabled",
1164 hidden = "GetScaleDisabled",
1165 },
1166 },
1167 },
1168 alpha = {
1169 name = L["Transparency"],
1170 order = 94,
1171 type = "group",
1172 inline = true,
1173 args = {
1174 enableAlpha = {
1175 name = L["Set Transparency"],
1176 order = 1,
1177 type = "toggle",
1178 set = "SetProp",
1179 get = "GetProp",
1180 },
1181 alpha = {
1182 name = L["Transparency"],
1183 order = 2,
1184 type = "range",
1185 min = 0,
1186 max = 1,
1187 step = 0.01,
1188 bigStep = 0.05,
1189 isPercent = true,
1190 set = "SetProp",
1191 get = "GetAlpha",
1192 disabled = "GetAlphaDisabled",
1193 hidden = "GetAlphaDisabled",
1194 },
1195 },
1196 },
1197 },
1198 plugins = { }
1199 },
1200 rules = {
1201 name = L["Rule"],
1202 order = 3,
1203 type = "group",
1204 args = {
1205 mode = {
1206 name = L["Select this state"],
1207 order = 2,
1208 type = "select",
1209 style = "radio",
1210 values = {
1211 default = L["by default"],
1212 any = L["when ANY of these"],
1213 all = L["when ALL of these"],
1214 custom = L["via custom rule"],
1215 keybind = L["via keybinding"],
1216 },
1217 set = "SetType",
1218 get = "GetType",
1219 },
1220 clear = {
1221 name = L["Clear All"],
1222 order = 3,
1223 type = "execute",
1224 hidden = "GetClearAllDisabled",
1225 disabled = "GetClearAllDisabled",
1226 func = "ClearAllConditions",
1227 },
1228 inputs = {
1229 name = L["Conditions"],
1230 order = 4,
1231 type = "multiselect",
1232 hidden = "GetConditionsDisabled",
1233 disabled = "GetConditionsDisabled",
1234 values = ruleSelect,
1235 set = "SetCondition",
1236 get = "GetCondition",
1237 },
1238 custom = {
1239 name = L["Custom Rule"],
1240 order = 5,
1241 type = "input",
1242 multiline = true,
1243 hidden = "GetCustomDisabled",
1244 disabled = "GetCustomDisabled",
1245 desc = L["Syntax like macro rules: see preset rules for examples"],
1246 set = "SetCustomRule",
1247 get = "GetCustomRule",
1248 validate = "ValidateCustomRule",
1249 },
1250 keybind = {
1251 name = L["Keybinding"],
1252 order = 6,
1253 inline = true,
1254 hidden = "GetKeybindDisabled",
1255 disabled = "GetKeybindDisabled",
1256 type = "group",
1257 args = {
1258 desc = {
1259 name = L["Invoking a state keybind toggles an override of all other transition rules."],
1260 order = 1,
1261 type = "description",
1262 },
1263 keybind = {
1264 name = L["State Hotkey"],
1265 desc = L["Define an override toggle keybind"],
1266 order = 2,
1267 type = "keybinding",
1268 set = "SetKeybind",
1269 get = "GetKeybind",
1270 },
1271 },
1272 },
1273 },
1274 },
1275 }
1276
1277 local StateHandler = { }
1278 local meta = { __index = StateHandler }
1279
1280 function StateHandler:New( bar, opts )
1281 local self = setmetatable(
1282 {
1283 bar = bar
1284 },
1285 meta )
1286
1287 function self:GetName()
1288 return opts.name
1289 end
1290
1291 function self:SetName(name)
1292 opts.name = name
1293 end
1294
1295 function self:GetOrder()
1296 return opts.order
1297 end
1298
1299 -- get reference to states table: even if the bar
1300 -- name changes the states table ref won't
1301 self.states = tbuild(bar:GetConfig(), "states")
1302 self.state = tbuild(self.states, opts.name)
1303
1304 opts.order = self:GetRuleField("order")
1305 if opts.order == nil then
1306 -- add after the highest
1307 opts.order = 100
1308 for _, state in pairs(self.states) do
1309 local x = tonumber(tfetch(state, "rule", "order"))
1310 if x and x >= opts.order then
1311 opts.order = x + 1
1312 end
1313 end
1314 self:SetRuleField("order",opts.order)
1315 end
1316
1317 return self
1318 end
1319
1320 -- helper methods
1321
1322 function StateHandler:SetRuleField( key, value, ... )
1323 tbuild(self.state, "rule", ...)[key] = value
1324 end
1325
1326 function StateHandler:GetRuleField( ... )
1327 return tfetch(self.state, "rule", ...)
1328 end
1329
1330 function StateHandler:FixAll( setkey )
1331 -- if multiple selections in the same group are chosen when 'all' is selected,
1332 -- keep only one of them. If changing the mode, the first in the fields list will
1333 -- be chosen arbitrarily. Otherwise, if selecting a new checkbox from the field-set,
1334 -- it will be retained.
1335 local notified = false
1336 if self:GetRuleField("type") == "all" then
1337 for _, c in ipairs(rules) do
1338 local rule, fields = unpack(c)
1339 local once = false
1340 if setkey then
1341 for idx, field in ipairs(fields) do
1342 if next(field) == setkey then
1343 once = true
1344 end
1345 end
1346 end
1347 for idx, field in ipairs(fields) do
1348 local key = next(field)
1349 if self:GetRuleField("values",key) then
1350 if once and key ~= setkey then
1351 self:SetRuleField(key,false,"values")
1352 if not setkey and not notified then
1353 ReAction:UserError(L["Warning: one or more incompatible rules were turned off"])
1354 notified = true
1355 end
1356 end
1357 once = true
1358 end
1359 end
1360 end
1361 end
1362 end
1363
1364 function StateHandler:GetNeighbors()
1365 local before, after
1366 for k, v in pairs(self.states) do
1367 local o = tonumber(tfetch(v, "rule", "order"))
1368 if o and k ~= self:GetName() then
1369 local obefore = tfetch(self.states,before,"rule","order")
1370 local oafter = tfetch(self.states,after,"rule","order")
1371 if o < self:GetOrder() and (not obefore or obefore < o) then
1372 before = k
1373 end
1374 if o > self:GetOrder() and (not oafter or oafter > o) then
1375 after = k
1376 end
1377 end
1378 end
1379 return before, after
1380 end
1381
1382 function StateHandler:SwapOrder( a, b )
1383 -- do options table
1384 local args = optionMap[self.bar].args
1385 args[a].order, args[b].order = args[b].order, args[a].order
1386 -- do profile
1387 a = tbuild(self.states, a, "rule")
1388 b = tbuild(self.states, b, "rule")
1389 a.order, b.order = b.order, a.order
1390 end
1391
1392 -- handler methods
1393
1394 function StateHandler:GetProp( info )
1395 -- gets property of the same name as the options arg
1396 return GetProperty(self.bar, self:GetName(), info[#info])
1397 end
1398
1399 function StateHandler:SetProp( info, value )
1400 -- sets property of the same name as the options arg
1401 SetProperty(self.bar, self:GetName(), info[#info], value)
1402 end
1403
1404 function StateHandler:DeleteState()
1405 if self.states[self:GetName()] then
1406 self.states[self:GetName()] = nil
1407 ApplyStates(self.bar)
1408 end
1409 optionMap[self.bar].args[self:GetName()] = nil
1410 end
1411
1412 function StateHandler:SetStateName(info, value)
1413 -- check for existing state name
1414 if self.states[value] then
1415 ReAction:UserError(format(L["State named '%s' already exists"],value))
1416 return
1417 end
1418 local args = optionMap[self.bar].args
1419 local name = self:GetName()
1420 self.states[value], args[value], self.states[name], args[name] = self.states[name], args[name], nil, nil
1421 self:SetName(value)
1422 ApplyStates(self.bar)
1423 ReAction:ShowEditor(self.bar, moduleID, value)
1424 end
1425
1426 function StateHandler:MoveStateUp()
1427 local before, after = self:GetNeighbors()
1428 if before then
1429 self:SwapOrder(before, self:GetName())
1430 ApplyStates(self.bar)
1431 end
1432 end
1433
1434 function StateHandler:MoveStateDown()
1435 local before, after = self:GetNeighbors()
1436 if after then
1437 self:SwapOrder(self:GetName(), after)
1438 ApplyStates(self.bar)
1439 end
1440 end
1441
1442 function StateHandler:GetAnchorDisabled()
1443 return not GetProperty(self.bar, self:GetName(), "anchorEnable")
1444 end
1445
1446 function StateHandler:IsPageDisabled()
1447 local n = self.bar:GetConfig().nPages or 1
1448 return not (n > 1)
1449 end
1450
1451 function StateHandler:IsPageHidden()
1452 return not self.bar:GetConfig().nPages
1453 end
1454
1455 function StateHandler:GetPageValues()
1456 if not self._pagevalues then
1457 self._pagevalues = { }
1458 end
1459 local n = self.bar:GetConfig().nPages
1460 -- cache the results
1461 if self._npages ~= n then
1462 self._npages = n
1463 wipe(self._pagevalues)
1464 for i = 1, n do
1465 self._pagevalues["page"..i] = i
1466 end
1467 end
1468 return self._pagevalues
1469 end
1470
1471 function StateHandler:GetPage(info)
1472 return self:GetProp(info) or 1
1473 end
1474
1475 function StateHandler:GetAnchorFrames(info)
1476 self._anchorframes = self._anchorframes or { }
1477 table.wipe(self._anchorframes)
1478
1479 table.insert(self._anchorframes, "UIParent")
1480 for name, bar in ReAction:IterateBars() do
1481 table.insert(self._anchorframes, bar:GetFrame():GetName())
1482 end
1483 return self._anchorframes
1484 end
1485
1486 function StateHandler:GetAnchorFrame(info)
1487 local value = self:GetProp(info)
1488 for k,v in pairs(self._anchorframes) do
1489 if v == value then
1490 return k
1491 end
1492 end
1493 end
1494
1495 function StateHandler:SetAnchorFrame(info, value)
1496 local f = _G[self._anchorframes[value]]
1497 if f then
1498 self.bar:SetFrameRef("anchor-"..self:GetName(), f)
1499 self:SetProp(info, f:GetName())
1500 end
1501 end
1502
1503 function StateHandler:SetAnchorPointProp(info, value)
1504 self:SetProp(info, value ~= "NONE" and value or nil)
1505 end
1506
1507 function StateHandler:GetAnchorPointProp(info)
1508 return self:GetProp(info) or "NONE"
1509 end
1510
1511 function StateHandler:GetScale(info)
1512 return self:GetProp(info) or 1.0
1513 end
1514
1515 function StateHandler:GetScaleDisabled()
1516 return not GetProperty(self.bar, self:GetName(), "enableScale")
1517 end
1518
1519 function StateHandler:GetAlpha(info)
1520 return self:GetProp(info) or 1.0
1521 end
1522
1523 function StateHandler:GetAlphaDisabled()
1524 return not GetProperty(self.bar, self:GetName(), "enableAlpha")
1525 end
1526
1527 function StateHandler:SetType(info, value)
1528 self:SetRuleField("type", value)
1529 self:FixAll()
1530 ApplyStates(self.bar)
1531 end
1532
1533 function StateHandler:GetType()
1534 return self:GetRuleField("type")
1535 end
1536
1537 function StateHandler:GetClearAllDisabled()
1538 local t = self:GetRuleField("type")
1539 return not( t == "any" or t == "all" or t == "custom")
1540 end
1541
1542 function StateHandler:ClearAllConditions()
1543 local t = self:GetRuleField("type")
1544 if t == "custom" then
1545 self:SetRuleField("custom","")
1546 elseif t == "any" or t == "all" then
1547 self:SetRuleField("values", {})
1548 end
1549 ApplyStates(self.bar)
1550 end
1551
1552 function StateHandler:GetConditionsDisabled()
1553 local t = self:GetRuleField("type")
1554 return not( t == "any" or t == "all")
1555 end
1556
1557 function StateHandler:SetCondition(info, key, value)
1558 self:SetRuleField(ruleMap[key], value or nil, "values")
1559 if value then
1560 self:FixAll(ruleMap[key])
1561 end
1562 ApplyStates(self.bar)
1563 end
1564
1565 function StateHandler:GetCondition(info, key)
1566 return self:GetRuleField("values", ruleMap[key]) or false
1567 end
1568
1569 function StateHandler:GetCustomDisabled()
1570 return self:GetRuleField("type") ~= "custom"
1571 end
1572
1573 function StateHandler:SetCustomRule(info, value)
1574 self:SetRuleField("custom",value)
1575 ApplyStates(self.bar)
1576 end
1577
1578 function StateHandler:GetCustomRule()
1579 return self:GetRuleField("custom") or ""
1580 end
1581
1582 function StateHandler:ValidateCustomRule(info, value)
1583 local s = value:gsub("%s","") -- remove all spaces
1584 -- unfortunately %b and captures don't support the '+' notation, or this would be considerably simpler
1585 repeat
1586 if s == "" then
1587 return true
1588 end
1589 local c, r = s:match("(%b[])(.*)")
1590 if c == nil and s and #s > 0 then
1591 return format(L["Invalid custom rule '%s': each clause must appear within [brackets]"],value or "")
1592 end
1593 s = r
1594 until c == nil
1595 return true
1596 end
1597
1598 function StateHandler:GetKeybindDisabled()
1599 return self:GetRuleField("type") ~= "keybind"
1600 end
1601
1602 function StateHandler:GetKeybind()
1603 return self:GetRuleField("keybind")
1604 end
1605
1606 function StateHandler:SetKeybind(info, value)
1607 if value and #value == 0 then
1608 value = nil
1609 end
1610 self:SetRuleField("keybind",value)
1611 ApplyStates(self.bar)
1612 end
1613
1614 local function CreateStateOptions(bar, name)
1615 local opts = {
1616 type = "group",
1617 name = name,
1618 childGroups = "tab",
1619 args = stateOptions
1620 }
1621
1622 opts.handler = StateHandler:New(bar,opts)
1623
1624 return opts
1625 end
1626
1627 function Editor:CreateStateOptions(bar)
1628 local private = { }
1629 local states = tbuild(bar:GetConfig(), "states")
1630 local options = {
1631 name = L["Dynamic State"],
1632 type = "group",
1633 order = -1,
1634 childGroups = "tree",
1635 disabled = InCombatLockdown,
1636 args = {
1637 __desc__ = {
1638 name = L["States are evaluated in the order they are listed"],
1639 order = 1,
1640 type = "description",
1641 },
1642 __new__ = {
1643 name = L["New State..."],
1644 order = 2,
1645 type = "group",
1646 args = {
1647 name = {
1648 name = L["State Name"],
1649 desc = L["Set a name for the new state"],
1650 order = 1,
1651 type = "input",
1652 get = function() return private.newstatename or "" end,
1653 set = function(info,value) private.newstatename = value end,
1654 pattern = "^%w*$",
1655 usage = L["State names must be alphanumeric without spaces"],
1656 },
1657 create = {
1658 name = L["Create State"],
1659 order = 2,
1660 type = "execute",
1661 func = function ()
1662 local name = private.newstatename
1663 if states[name] then
1664 ReAction:UserError(format(L["State named '%s' already exists"],name))
1665 else
1666 -- TODO: select default state options and pass as final argument
1667 states[name] = { }
1668 optionMap[bar].args[name] = CreateStateOptions(bar,name)
1669 ReAction:ShowEditor(bar, moduleID, name)
1670 private.newstatename = ""
1671 end
1672 end,
1673 disabled = function()
1674 local name = private.newstatename or ""
1675 return #name == 0 or name:find("%W")
1676 end,
1677 }
1678 }
1679 }
1680 }
1681 }
1682 for name, config in pairs(states) do
1683 options.args[name] = CreateStateOptions(bar,name)
1684 end
1685 optionMap[bar] = options
1686 return options
1687 end
1688 end
417 1689
418 1690
419 ---- Export to ReAction ---- 1691 ---- Export to ReAction ----
420 function ReAction:ShowEditor(bar, ...) 1692 function ReAction:ShowEditor(bar, ...)
421 if InCombatLockdown() then 1693 if InCombatLockdown() then
437 if self.editor then 1709 if self.editor then
438 self.editor:RefreshBarOptions() 1710 self.editor:RefreshBarOptions()
439 end 1711 end
440 end 1712 end
441 1713
442 function ReAction:RegisterBarOptionGenerator( module, func )
443 if not module or type(module) ~= "table" then -- doesn't need to be a proper module, strictly
444 error("ReAction:RegisterBarOptionGenerator() : Invalid module")
445 end
446 if type(func) == "string" then
447 if not module[func] then
448 error(("ReAction:RegisterBarOptionGenerator() : Invalid method '%s'"):format(func))
449 end
450 elseif func and type(func) ~= "function" then
451 error("ReAction:RegisterBarOptionGenerator() : Invalid function")
452 end
453 self.barOptionGenerators = self.barOptionGenerators or { }
454 self.barOptionGenerators[module] = func
455
456 if self.editor then
457 self.editor:RefreshBarOptions()
458 end
459 end
460