Mercurial > wow > reaction
comparison State.lua @ 79:a45255f5d0c2
- Converted State options to use static options table + metatable handler
- Fixed bug with FixAll()
- Added external property handler registration
- Removed pages handler (to be migrated to ReAction_Action)
| author | Flick <flickerstreak@gmail.com> |
|---|---|
| date | Tue, 24 Jun 2008 23:39:43 +0000 |
| parents | da8ba8783924 |
| children | 42ec2938d65a |
comparison
equal
deleted
inserted
replaced
| 78:502cdb5666e2 | 79:a45255f5d0c2 |
|---|---|
| 51 end) | 51 end) |
| 52 return r | 52 return r |
| 53 end | 53 end |
| 54 | 54 |
| 55 | 55 |
| 56 local InitRules, ApplyStates, SetProperty, GetProperty | 56 local InitRules, ApplyStates, SetProperty, GetProperty, RegisterProperty |
| 57 | 57 |
| 58 -- PRIVATE -- | 58 -- PRIVATE -- |
| 59 do | 59 do |
| 60 -- As far as I can tell the macro clauses are NOT locale-specific. | 60 -- As far as I can tell the macro clauses are NOT locale-specific. |
| 61 local ruleformats = { | 61 local ruleformats = { |
| 140 local ofskey = ofskeys[ckey] | 140 local ofskey = ofskeys[ckey] |
| 141 local default = select(barofsidx[ckey], bar:GetAnchor()) | 141 local default = select(barofsidx[ckey], bar:GetAnchor()) |
| 142 bar:SetStateAttribute(format("headofs%s",ofskeys[ckey]), map, default) | 142 bar:SetStateAttribute(format("headofs%s",ofskeys[ckey]), map, default) |
| 143 end | 143 end |
| 144 | 144 |
| 145 -- the name of the function maps to the name of the config element | 145 -- the table key name for each function maps to the name of the config element |
| 146 local propertyFuncs = { | 146 local propertyFuncs = { |
| 147 hide = function( bar, states ) | 147 hide = function( bar, states ) |
| 148 local hs = { } | 148 local hs = { } |
| 149 for state, config in pairs(states) do | 149 for state, config in pairs(states) do |
| 150 if config.hide then | 150 if config.hide then |
| 151 table.insert(hs, state) | 151 table.insert(hs, state) |
| 152 end | 152 end |
| 153 end | 153 end |
| 154 bar:SetStateAttribute("hidestates", nil, table.concat(hs,","), true) -- pass to buttons | 154 bar:SetStateAttribute("hidestates", nil, table.concat(hs,","), true) -- pass to buttons |
| 155 end, | |
| 156 | |
| 157 page = function( bar, states ) | |
| 158 local map = { } | |
| 159 for state, config in pairs(states) do | |
| 160 if config.page then | |
| 161 map[state] = format("page%d",config.page) | |
| 162 end | |
| 163 end | |
| 164 bar:SetStateAttribute("statebutton", map) | |
| 165 end, | 155 end, |
| 166 | 156 |
| 167 keybindstate = function( bar, states ) | 157 keybindstate = function( bar, states ) |
| 168 local map = { } | 158 local map = { } |
| 169 for state, config in pairs(states) do | 159 for state, config in pairs(states) do |
| 211 local states = tbuild(module.db.profile.bars, bar:GetName(), "states") | 201 local states = tbuild(module.db.profile.bars, bar:GetName(), "states") |
| 212 tbuild(states, state)[propname] = value | 202 tbuild(states, state)[propname] = value |
| 213 local f = propertyFuncs[propname] | 203 local f = propertyFuncs[propname] |
| 214 if f then | 204 if f then |
| 215 f(bar, states) | 205 f(bar, states) |
| 206 end | |
| 207 end | |
| 208 | |
| 209 function RegisterProperty( propname, f ) | |
| 210 propertyFuncs[propname] = f | |
| 211 for bar in ReAction:IterateBars() do | |
| 212 local states = tfetch(module.db.profile.bars, bar:GetName(), "states") | |
| 213 if states then | |
| 214 f(bar,states) | |
| 215 end | |
| 216 end | 216 end |
| 217 end | 217 end |
| 218 | 218 |
| 219 | 219 |
| 220 | 220 |
| 377 local bars = self.db.profile.bars | 377 local bars = self.db.profile.bars |
| 378 bars[newname], bars[oldname] = bars[oldname], nil | 378 bars[newname], bars[oldname] = bars[oldname], nil |
| 379 end | 379 end |
| 380 | 380 |
| 381 function module:OnConfigModeChanged(event, mode) | 381 function module:OnConfigModeChanged(event, mode) |
| 382 -- TODO: unregister all state drivers (temporarily) and hidestates | 382 -- nothing to do (yet) |
| 383 end | 383 end |
| 384 | 384 |
| 385 | 385 |
| 386 | 386 |
| 387 -- Options -- | 387 -- Options -- |
| 388 | 388 |
| 389 local CreateBarOptions | 389 local CreateBarOptions, RegisterPropertyOptions |
| 390 do | 390 do |
| 391 local playerClass = select(2, UnitClass("player")) | |
| 391 local function ClassCheck(...) | 392 local function ClassCheck(...) |
| 392 for i = 1, select('#',...) do | 393 for i = 1, select('#',...) do |
| 393 local _, c = UnitClass("player") | 394 if playerClass == select(i,...) then |
| 394 if c == select(i,...) then | |
| 395 return false | 395 return false |
| 396 end | 396 end |
| 397 end | 397 end |
| 398 return true | 398 return true |
| 399 end | 399 end |
| 440 table.insert(ruleMap, key) | 440 table.insert(ruleMap, key) |
| 441 end | 441 end |
| 442 end | 442 end |
| 443 end | 443 end |
| 444 | 444 |
| 445 local stateOptions = { | |
| 446 ordering = { | |
| 447 name = L["Info"], | |
| 448 order = 1, | |
| 449 type = "group", | |
| 450 args = { | |
| 451 delete = { | |
| 452 name = L["Delete this State"], | |
| 453 order = -1, | |
| 454 type = "execute", | |
| 455 func = "DeleteState", | |
| 456 }, | |
| 457 rename = { | |
| 458 name = L["Name"], | |
| 459 order = 1, | |
| 460 type = "input", | |
| 461 get = "GetName", | |
| 462 set = "SetStateName", | |
| 463 pattern = "^%w*$", | |
| 464 usage = L["State names must be alphanumeric without spaces"], | |
| 465 }, | |
| 466 ordering = { | |
| 467 name = L["Evaluation Order"], | |
| 468 desc = L["State transitions are evaluated in the order listed:\nMove a state up or down to change the order"], | |
| 469 order = 2, | |
| 470 type = "group", | |
| 471 inline = true, | |
| 472 args = { | |
| 473 up = { | |
| 474 name = L["Up"], | |
| 475 order = 1, | |
| 476 type = "execute", | |
| 477 width = "half", | |
| 478 func = "MoveStateUp", | |
| 479 }, | |
| 480 down = { | |
| 481 name = L["Down"], | |
| 482 order = 2, | |
| 483 type = "execute", | |
| 484 width = "half", | |
| 485 func = "MoveStateDown", | |
| 486 } | |
| 487 } | |
| 488 } | |
| 489 } | |
| 490 }, | |
| 491 properties = { | |
| 492 name = L["Properties"], | |
| 493 order = 2, | |
| 494 type = "group", | |
| 495 args = { | |
| 496 desc = { | |
| 497 name = L["Set the properties for the bar when in this state"], | |
| 498 order = 1, | |
| 499 type = "description" | |
| 500 }, | |
| 501 hide = { | |
| 502 name = L["Hide Bar"], | |
| 503 order = 91, | |
| 504 type = "toggle", | |
| 505 set = "SetProp", | |
| 506 get = "GetProp", | |
| 507 }, | |
| 508 keybindstate = { | |
| 509 name = L["Override Keybinds"], | |
| 510 desc = L["Set this state to maintain its own set of keybinds which override the defaults when active"], | |
| 511 order = 92, | |
| 512 type = "toggle", | |
| 513 set = "SetProp", | |
| 514 get = "GetProp", | |
| 515 }, | |
| 516 position = { | |
| 517 name = L["Position"], | |
| 518 order = 93, | |
| 519 type = "group", | |
| 520 inline = true, | |
| 521 args = { | |
| 522 enableAnchor = { | |
| 523 name = L["Set New Position"], | |
| 524 order = 1, | |
| 525 type = "toggle", | |
| 526 set = "SetProp", | |
| 527 get = "GetProp", | |
| 528 }, | |
| 529 anchorPoint = { | |
| 530 name = L["Point"], | |
| 531 order = 2, | |
| 532 type = "select", | |
| 533 values = pointTable, | |
| 534 set = "SetAnchorPointProp", | |
| 535 get = "GetAnchorPointProp", | |
| 536 disabled = "GetAnchorDisabled", | |
| 537 hidden = "GetAnchorDisabled", | |
| 538 }, | |
| 539 anchorRelPoint = { | |
| 540 name = L["Relative Point"], | |
| 541 order = 3, | |
| 542 type = "select", | |
| 543 values = pointTable, | |
| 544 set = "SetAnchorPointProp", | |
| 545 get = "GetAnchorPointProp", | |
| 546 disabled = "GetAnchorDisabled", | |
| 547 hidden = "GetAnchorDisabled", | |
| 548 }, | |
| 549 anchorX = { | |
| 550 name = L["X Offset"], | |
| 551 order = 4, | |
| 552 type = "range", | |
| 553 min = -100, | |
| 554 max = 100, | |
| 555 step = 1, | |
| 556 set = "SetProp", | |
| 557 get = "GetProp", | |
| 558 disabled = "GetAnchorDisabled", | |
| 559 hidden = "GetAnchorDisabled", | |
| 560 }, | |
| 561 anchorY = { | |
| 562 name = L["Y Offset"], | |
| 563 order = 5, | |
| 564 type = "range", | |
| 565 min = -100, | |
| 566 max = 100, | |
| 567 step = 1, | |
| 568 set = "SetProp", | |
| 569 get = "GetProp", | |
| 570 disabled = "GetAnchorDisabled", | |
| 571 hidden = "GetAnchorDisabled", | |
| 572 }, | |
| 573 }, | |
| 574 }, | |
| 575 scale = { | |
| 576 name = L["Scale"], | |
| 577 order = 94, | |
| 578 type = "group", | |
| 579 inline = true, | |
| 580 args = { | |
| 581 enableScale = { | |
| 582 name = L["Set New Scale"], | |
| 583 order = 1, | |
| 584 type = "toggle", | |
| 585 set = "SetProp", | |
| 586 get = "GetProp", | |
| 587 }, | |
| 588 scale = { | |
| 589 name = L["Scale"], | |
| 590 order = 2, | |
| 591 type = "range", | |
| 592 min = 0.1, | |
| 593 max = 2.5, | |
| 594 step = 0.05, | |
| 595 isPercent = true, | |
| 596 set = "SetProp", | |
| 597 get = "GetProp", | |
| 598 disabled = "GetScaleDisabled", | |
| 599 hidden = "GetScaleDisabled", | |
| 600 }, | |
| 601 }, | |
| 602 }, | |
| 603 }, | |
| 604 plugins = { } | |
| 605 }, | |
| 606 rules = { | |
| 607 name = L["Rule"], | |
| 608 order = 3, | |
| 609 type = "group", | |
| 610 args = { | |
| 611 mode = { | |
| 612 name = L["Select this state"], | |
| 613 order = 2, | |
| 614 type = "select", | |
| 615 style = "radio", | |
| 616 values = { | |
| 617 default = L["by default"], | |
| 618 any = L["when ANY of these"], | |
| 619 all = L["when ALL of these"], | |
| 620 custom = L["via custom rule"], | |
| 621 keybind = L["via keybinding"], | |
| 622 }, | |
| 623 set = "SetType", | |
| 624 get = "GetType", | |
| 625 }, | |
| 626 clear = { | |
| 627 name = L["Clear All"], | |
| 628 order = 3, | |
| 629 type = "execute", | |
| 630 hidden = "GetClearAllDisabled", | |
| 631 disabled = "GetClearAllDisabled", | |
| 632 func = "ClearAllConditions", | |
| 633 }, | |
| 634 inputs = { | |
| 635 name = L["Conditions"], | |
| 636 order = 4, | |
| 637 type = "multiselect", | |
| 638 hidden = "GetConditionsDisabled", | |
| 639 disabled = "GetConditionsDisabled", | |
| 640 values = ruleSelect, | |
| 641 set = "SetCondition", | |
| 642 get = "GetCondition", | |
| 643 }, | |
| 644 custom = { | |
| 645 name = L["Custom Rule"], | |
| 646 order = 5, | |
| 647 type = "input", | |
| 648 multiline = true, | |
| 649 hidden = "GetCustomDisabled", | |
| 650 disabled = "GetCustomDisabled", | |
| 651 desc = L["Syntax like macro rules: see preset rules for examples"], | |
| 652 set = "SetCustomRule", | |
| 653 get = "GetCustomRule", | |
| 654 validate = "ValidateCustomRule", | |
| 655 }, | |
| 656 keybind = { | |
| 657 name = L["Keybinding"], | |
| 658 order = 6, | |
| 659 inline = true, | |
| 660 hidden = "GetKeybindDisabled", | |
| 661 disabled = "GetKeybindDisabled", | |
| 662 type = "group", | |
| 663 args = { | |
| 664 desc = { | |
| 665 name = L["Invoking a state keybind toggles an override of all other transition rules."], | |
| 666 order = 1, | |
| 667 type = "description", | |
| 668 }, | |
| 669 keybind = { | |
| 670 name = L["State Hotkey"], | |
| 671 desc = L["Define an override toggle keybind"], | |
| 672 order = 2, | |
| 673 type = "keybinding", | |
| 674 set = "SetKeybind", | |
| 675 get = "GetKeybind", | |
| 676 }, | |
| 677 }, | |
| 678 }, | |
| 679 }, | |
| 680 }, | |
| 681 } | |
| 682 | |
| 683 local StateHandler = { } | |
| 684 | |
| 685 function StateHandler:New( bar, opts ) | |
| 686 local self = setmetatable({ bar = bar }, { __index = StateHandler }) | |
| 687 | |
| 688 function self:GetName() | |
| 689 return opts.name | |
| 690 end | |
| 691 | |
| 692 function self:SetName(name) | |
| 693 opts.name = name | |
| 694 end | |
| 695 | |
| 696 function self:GetOrder() | |
| 697 return opts.order | |
| 698 end | |
| 699 | |
| 700 -- get reference to states table: even if the bar | |
| 701 -- name changes the states table ref won't | |
| 702 self.states = tbuild(module.db.profile.bars, bar:GetName(), "states") | |
| 703 | |
| 704 tbuild(self.states, opts.name) | |
| 705 | |
| 706 opts.order = self:GetRule("order") | |
| 707 if opts.order == nil then | |
| 708 -- add after the highest | |
| 709 opts.order = 100 | |
| 710 for _, state in pairs(self.states) do | |
| 711 local x = tonumber(tfetch(state, "rule", "order")) | |
| 712 if x and x >= opts.order then | |
| 713 opts.order = x + 1 | |
| 714 end | |
| 715 end | |
| 716 self:SetRule("order",opts.order) | |
| 717 end | |
| 718 | |
| 719 return self | |
| 720 end | |
| 721 | |
| 722 -- helper methods | |
| 723 | |
| 724 function StateHandler:SetRule( key, value, ... ) | |
| 725 tbuild(self.states, self:GetName(), "rule", ...)[key] = value | |
| 726 end | |
| 727 | |
| 728 function StateHandler:GetRule( ... ) | |
| 729 return tfetch(self.states, self:GetName(), "rule", ...) | |
| 730 end | |
| 731 | |
| 732 function StateHandler:FixAll( setkey ) | |
| 733 -- if multiple selections in the same group are chosen when 'all' is selected, | |
| 734 -- keep only one of them. If changing the mode, the first in the fields list will | |
| 735 -- be chosen arbitrarily. Otherwise, if selecting a new checkbox from the field-set, | |
| 736 -- it will be retained. | |
| 737 local notified = false | |
| 738 if self:GetRule("type") == "all" then | |
| 739 for _, c in ipairs(rules) do | |
| 740 local rule, hidden, fields = unpack(c) | |
| 741 local once = false | |
| 742 if setkey then | |
| 743 for idx, field in ipairs(fields) do | |
| 744 if next(field) == setkey then | |
| 745 once = true | |
| 746 end | |
| 747 end | |
| 748 end | |
| 749 for idx, field in ipairs(fields) do | |
| 750 local key = next(field) | |
| 751 if self:GetRule("values",key) then | |
| 752 if once and key ~= setkey then | |
| 753 self:SetRule(key,false,"values") | |
| 754 if not setkey and not notified then | |
| 755 ReAction:UserError(L["Warning: one or more incompatible rules were turned off"]) | |
| 756 notified = true | |
| 757 end | |
| 758 end | |
| 759 once = true | |
| 760 end | |
| 761 end | |
| 762 end | |
| 763 end | |
| 764 end | |
| 765 | |
| 766 function StateHandler:GetNeighbors() | |
| 767 local before, after | |
| 768 for k, v in pairs(self.states) do | |
| 769 local o = tonumber(tfetch(v, "rule", "order")) | |
| 770 if o and k ~= self:GetName() then | |
| 771 local obefore = tfetch(self.states,before,"rule","order") | |
| 772 local oafter = tfetch(self.states,after,"rule","order") | |
| 773 if o < self:GetOrder() and (not obefore or obefore < o) then | |
| 774 before = k | |
| 775 end | |
| 776 if o > self:GetOrder() and (not oafter or oafter > o) then | |
| 777 after = k | |
| 778 end | |
| 779 end | |
| 780 end | |
| 781 return before, after | |
| 782 end | |
| 783 | |
| 784 function StateHandler:SwapOrder( a, b ) | |
| 785 -- do options table | |
| 786 local args = optionMap[self.bar].args | |
| 787 args[a].order, args[b].order = args[b].order, args[a].order | |
| 788 -- do profile | |
| 789 a = tbuild(self.states, a, "rule") | |
| 790 b = tbuild(self.states, b, "rule") | |
| 791 a.order, b.order = b.order, a.order | |
| 792 end | |
| 793 | |
| 794 -- handler methods | |
| 795 | |
| 796 function StateHandler:GetProp( info ) | |
| 797 -- gets property of the same name as the options arg | |
| 798 return GetProperty(self.bar, self:GetName(), info[#info]) | |
| 799 end | |
| 800 | |
| 801 function StateHandler:SetProp( info, value ) | |
| 802 -- sets property of the same name as the options arg | |
| 803 SetProperty(self.bar, self:GetName(), info[#info], value) | |
| 804 end | |
| 805 | |
| 806 function StateHandler:DeleteState() | |
| 807 if self.states[self:GetName()] then | |
| 808 self.states[self:GetName()] = nil | |
| 809 ApplyStates(self.bar) | |
| 810 end | |
| 811 optionMap[self.bar].args[self:GetName()] = nil | |
| 812 end | |
| 813 | |
| 814 function StateHandler:SetStateName(info, value) | |
| 815 -- check for existing state name | |
| 816 if self.states[value] then | |
| 817 ReAction:UserError(format(L["State named '%s' already exists"],value)) | |
| 818 return | |
| 819 end | |
| 820 local args = optionMap[self.bar].args | |
| 821 local name = self:GetName() | |
| 822 self.states[value], args[value], self.states[name], args[name] = self.states[name], args[name], nil, nil | |
| 823 self:SetName(value) | |
| 824 ApplyStates(self.bar) | |
| 825 end | |
| 826 | |
| 827 function StateHandler:MoveStateUp() | |
| 828 local before, after = self:GetNeighbors() | |
| 829 if before then | |
| 830 self:SwapOrder(before, self:GetName()) | |
| 831 ApplyStates(self.bar) | |
| 832 end | |
| 833 end | |
| 834 | |
| 835 function StateHandler:MoveStateDown() | |
| 836 local before, after = self:GetNeighbors() | |
| 837 if after then | |
| 838 self:SwapOrder(self:GetName(), after) | |
| 839 ApplyStates(self.bar) | |
| 840 end | |
| 841 end | |
| 842 | |
| 843 function StateHandler:GetAnchorDisabled() | |
| 844 return not GetProperty(self.bar, self:GetName(), "enableAnchor") | |
| 845 end | |
| 846 | |
| 847 function StateHandler:SetAnchorPointProp(info, value) | |
| 848 self:SetProp(info, value ~= "NONE" and value or nil) | |
| 849 end | |
| 850 | |
| 851 function StateHandler:GetAnchorPointProp(info) | |
| 852 return self:GetProp(info) or "NONE" | |
| 853 end | |
| 854 | |
| 855 function StateHandler:GetScaleDisabled() | |
| 856 return not GetProperty(self.bar, self:GetName(), "enableScale") | |
| 857 end | |
| 858 | |
| 859 function StateHandler:SetType(info, value) | |
| 860 self:SetRule("type", value) | |
| 861 self:FixAll() | |
| 862 ApplyStates(self.bar) | |
| 863 end | |
| 864 | |
| 865 function StateHandler:GetType() | |
| 866 return self:GetRule("type") | |
| 867 end | |
| 868 | |
| 869 function StateHandler:GetClearAllDisabled() | |
| 870 local t = self:GetRule("type") | |
| 871 return not( t == "any" or t == "all" or t == "custom") | |
| 872 end | |
| 873 | |
| 874 function StateHandler:ClearAllConditions() | |
| 875 local t = self:GetRule("type") | |
| 876 if t == "custom" then | |
| 877 self:SetRule("custom","") | |
| 878 elseif t == "any" or t == "all" then | |
| 879 self:SetRule("values", {}) | |
| 880 end | |
| 881 ApplyStates(self.bar) | |
| 882 end | |
| 883 | |
| 884 function StateHandler:GetConditionsDisabled() | |
| 885 local t = self:GetRule("type") | |
| 886 return not( t == "any" or t == "all") | |
| 887 end | |
| 888 | |
| 889 function StateHandler:SetCondition(info, key, value) | |
| 890 self:SetRule(ruleMap[key], value or nil, "values") | |
| 891 if value then | |
| 892 self:FixAll(ruleMap[key]) | |
| 893 end | |
| 894 ApplyStates(self.bar) | |
| 895 end | |
| 896 | |
| 897 function StateHandler:GetCondition(info, key) | |
| 898 return self:GetRule("values", ruleMap[key]) or false | |
| 899 end | |
| 900 | |
| 901 function StateHandler:GetCustomDisabled() | |
| 902 return self:GetRule("type") ~= "custom" | |
| 903 end | |
| 904 | |
| 905 function StateHandler:SetCustomRule(info, value) | |
| 906 self:SetRule("custom",value) | |
| 907 ApplyStates(self.bar) | |
| 908 end | |
| 909 | |
| 910 function StateHandler:GetCustomRule() | |
| 911 return self:GetRule("custom") or "" | |
| 912 end | |
| 913 | |
| 914 function StateHandler:ValidateCustomRule(info, value) | |
| 915 local s = value:gsub("%s","") -- remove all spaces | |
| 916 -- unfortunately %b and captures don't support the '+' notation, or this would be considerably simpler | |
| 917 repeat | |
| 918 if s == "" then | |
| 919 return true | |
| 920 end | |
| 921 local c, r = s:match("(%b[])(.*)") | |
| 922 if c == nil and s and #s > 0 then | |
| 923 return format(L["Invalid custom rule '%s': each clause must appear within [brackets]"],value or "") | |
| 924 end | |
| 925 s = r | |
| 926 until c == nil | |
| 927 return true | |
| 928 end | |
| 929 | |
| 930 function StateHandler:GetKeybindDisabled() | |
| 931 return self:GetRule("type") ~= "keybind" | |
| 932 end | |
| 933 | |
| 934 function StateHandler:GetKeybind() | |
| 935 return self:GetRule("keybind") | |
| 936 end | |
| 937 | |
| 938 function StateHandler:SetKeybind(info, value) | |
| 939 if value and #value == 0 then | |
| 940 value = nil | |
| 941 end | |
| 942 self:SetRule("keybind",value) | |
| 943 ApplyStates(self.bar) | |
| 944 end | |
| 945 | |
| 445 local function CreateStateOptions(bar, name) | 946 local function CreateStateOptions(bar, name) |
| 446 local opts = { | 947 local opts = { |
| 447 type = "group", | 948 type = "group", |
| 448 name = name, | 949 name = name, |
| 449 childGroups = "tab", | 950 childGroups = "tab", |
| 951 args = stateOptions | |
| 450 } | 952 } |
| 451 | 953 |
| 452 local states = tbuild(module.db.profile.bars, bar:GetName(), "states") | 954 opts.handler = StateHandler:New(bar,opts) |
| 453 | 955 |
| 454 local function update() | |
| 455 ApplyStates(bar) | |
| 456 end | |
| 457 | |
| 458 local function setrule( key, value, ... ) | |
| 459 tbuild(states, opts.name, "rule", ...)[key] = value | |
| 460 end | |
| 461 | |
| 462 local function getrule( ... ) | |
| 463 return tfetch(states, opts.name, "rule", ...) | |
| 464 end | |
| 465 | |
| 466 local function setprop(info, value) | |
| 467 SetProperty(bar, opts.name, info[#info], value) | |
| 468 end | |
| 469 | |
| 470 local function getprop(info) | |
| 471 return GetProperty(bar, opts.name, info[#info]) | |
| 472 end | |
| 473 | |
| 474 local function fixall(setkey) | |
| 475 -- if multiple selections in the same group are chosen when 'all' is selected, | |
| 476 -- keep only one of them. If changing the mode, the first in the fields list will | |
| 477 -- be chosen arbitrarily. Otherwise, if selecting a new checkbox from the field-set, | |
| 478 -- it will be retained. | |
| 479 local notified = false | |
| 480 for _, c in ipairs(rules) do | |
| 481 local rule, hidden, fields = unpack(c) | |
| 482 local found = false | |
| 483 for key in ipairs(fields) do | |
| 484 if getrule("values",key) then | |
| 485 if (found or setkey) and key ~= setkey then | |
| 486 setrule(key,false,"values") | |
| 487 if not setkey and not notified then | |
| 488 ReAction:UserError(L["Warning: one or more incompatible rules were turned off"]) | |
| 489 notified = true | |
| 490 end | |
| 491 end | |
| 492 found = true | |
| 493 end | |
| 494 end | |
| 495 end | |
| 496 end | |
| 497 | |
| 498 local function getNeighbors() | |
| 499 local before, after | |
| 500 for k, v in pairs(states) do | |
| 501 local o = tonumber(tfetch(v, "rule", "order")) | |
| 502 if o and k ~= opts.name then | |
| 503 local obefore = tfetch(states,before,"rule","order") | |
| 504 local oafter = tfetch(states,after,"rule","order") | |
| 505 if o < opts.order and (not obefore or obefore < o) then | |
| 506 before = k | |
| 507 end | |
| 508 if o > opts.order and (not oafter or oafter > o) then | |
| 509 after = k | |
| 510 end | |
| 511 end | |
| 512 end | |
| 513 return before, after | |
| 514 end | |
| 515 | |
| 516 local function swapOrder( a, b ) | |
| 517 -- do options table | |
| 518 local args = optionMap[bar].args | |
| 519 args[a].order, args[b].order = args[b].order, args[a].order | |
| 520 -- do profile | |
| 521 a = tbuild(states, a, "rule") | |
| 522 b = tbuild(states, b, "rule") | |
| 523 a.order, b.order = b.order, a.order | |
| 524 end | |
| 525 | |
| 526 local function anchordisable() | |
| 527 return not GetProperty(bar, opts.name, "enableAnchor") | |
| 528 end | |
| 529 | |
| 530 tbuild(states, name) | |
| 531 | |
| 532 opts.order = getrule("order") | |
| 533 if opts.order == nil then | |
| 534 -- add after the highest | |
| 535 opts.order = 100 | |
| 536 for _, state in pairs(states) do | |
| 537 local x = tonumber(tfetch(state, "rule", "order")) | |
| 538 if x and x >= opts.order then | |
| 539 opts.order = x + 1 | |
| 540 end | |
| 541 end | |
| 542 setrule("order",opts.order) | |
| 543 end | |
| 544 | |
| 545 opts.args = { | |
| 546 ordering = { | |
| 547 name = L["Info"], | |
| 548 order = 1, | |
| 549 type = "group", | |
| 550 args = { | |
| 551 delete = { | |
| 552 name = L["Delete this State"], | |
| 553 order = -1, | |
| 554 type = "execute", | |
| 555 func = function(info) | |
| 556 if states[opts.name] then | |
| 557 states[opts.name] = nil | |
| 558 ApplyStates(bar) | |
| 559 end | |
| 560 optionMap[bar].args[opts.name] = nil | |
| 561 end, | |
| 562 }, | |
| 563 rename = { | |
| 564 name = L["Name"], | |
| 565 order = 1, | |
| 566 type = "input", | |
| 567 get = function() return opts.name end, | |
| 568 set = function(info, value) | |
| 569 -- check for existing state name | |
| 570 if states[value] then | |
| 571 format(L["State named '%s' already exists"],value) | |
| 572 end | |
| 573 local args = optionMap[bar].args | |
| 574 states[value], args[value], states[opts.name], args[opts.name] = states[opts.name], args[opts.name], nil, nil | |
| 575 opts.name = value | |
| 576 update() | |
| 577 end, | |
| 578 pattern = "^%w*$", | |
| 579 usage = L["State names must be alphanumeric without spaces"], | |
| 580 }, | |
| 581 ordering = { | |
| 582 name = L["Evaluation Order"], | |
| 583 desc = L["State transitions are evaluated in the order listed:\nMove a state up or down to change the order"], | |
| 584 order = 2, | |
| 585 type = "group", | |
| 586 inline = true, | |
| 587 args = { | |
| 588 up = { | |
| 589 name = L["Up"], | |
| 590 order = 1, | |
| 591 type = "execute", | |
| 592 width = "half", | |
| 593 func = function() | |
| 594 local before, after = getNeighbors() | |
| 595 if before then | |
| 596 swapOrder(before, opts.name) | |
| 597 update() | |
| 598 end | |
| 599 end, | |
| 600 }, | |
| 601 down = { | |
| 602 name = L["Down"], | |
| 603 order = 2, | |
| 604 type = "execute", | |
| 605 width = "half", | |
| 606 func = function() | |
| 607 local before, after = getNeighbors() | |
| 608 if after then | |
| 609 swapOrder(opts.name, after) | |
| 610 update() | |
| 611 end | |
| 612 end, | |
| 613 } | |
| 614 } | |
| 615 } | |
| 616 } | |
| 617 }, | |
| 618 properties = { | |
| 619 name = L["Properties"], | |
| 620 order = 2, | |
| 621 type = "group", | |
| 622 args = { | |
| 623 desc = { | |
| 624 name = L["Set the properties for the bar when in this state"], | |
| 625 order = 1, | |
| 626 type = "description" | |
| 627 }, | |
| 628 hide = { | |
| 629 name = L["Hide Bar"], | |
| 630 order = 2, | |
| 631 type = "toggle", | |
| 632 set = setprop, | |
| 633 get = getprop, | |
| 634 }, | |
| 635 page = { | |
| 636 name = L["Show Page #"], | |
| 637 order = 3, | |
| 638 type = "select", | |
| 639 disabled = function() | |
| 640 --return bar:GetNumPages() < 2 | |
| 641 return true | |
| 642 end, | |
| 643 hidden = function() | |
| 644 --return bar:GetNumPages() < 2 | |
| 645 return true | |
| 646 end, | |
| 647 values = function() | |
| 648 -- use off-by-one ordering to put (none) first in the list | |
| 649 local pages = { [1] = L["(none)"] } | |
| 650 --for i = 1, bar:GetNumPages() do | |
| 651 -- pages[i+1] = i | |
| 652 --end | |
| 653 return pages | |
| 654 end, | |
| 655 set = function(info, value) | |
| 656 value = value - 1 | |
| 657 setprop(info, value > 0 and value or nil) | |
| 658 end, | |
| 659 get = function(info) | |
| 660 return getprop(info) or L["(none)"] | |
| 661 end, | |
| 662 }, | |
| 663 keybindstate = { | |
| 664 name = L["Override Keybinds"], | |
| 665 desc = L["Set this state to maintain its own set of keybinds which override the defaults when active"], | |
| 666 order = 4, | |
| 667 type = "toggle", | |
| 668 set = setprop, | |
| 669 get = getprop, | |
| 670 }, | |
| 671 position = { | |
| 672 name = L["Position"], | |
| 673 order = 5, | |
| 674 type = "group", | |
| 675 inline = true, | |
| 676 args = { | |
| 677 enableAnchor = { | |
| 678 name = L["Set New Position"], | |
| 679 order = 1, | |
| 680 type = "toggle", | |
| 681 set = setprop, | |
| 682 get = getprop, | |
| 683 }, | |
| 684 anchorPoint = { | |
| 685 name = L["Point"], | |
| 686 order = 2, | |
| 687 type = "select", | |
| 688 values = pointTable, | |
| 689 set = function(info, value) setprop(info, value ~= "NONE" and value or nil) end, | |
| 690 get = function(info) return getprop(info) or "NONE" end, | |
| 691 disabled = anchordisable, | |
| 692 hidden = anchordisable, | |
| 693 }, | |
| 694 anchorRelPoint = { | |
| 695 name = L["Relative Point"], | |
| 696 order = 3, | |
| 697 type = "select", | |
| 698 values = pointTable, | |
| 699 set = function(info, value) setprop(info, value ~= "NONE" and value or nil) end, | |
| 700 get = function(info) return getprop(info) or "NONE" end, | |
| 701 disabled = anchordisable, | |
| 702 hidden = anchordisable, | |
| 703 }, | |
| 704 anchorX = { | |
| 705 name = L["X Offset"], | |
| 706 order = 4, | |
| 707 type = "range", | |
| 708 min = -100, | |
| 709 max = 100, | |
| 710 step = 1, | |
| 711 set = setprop, | |
| 712 get = getprop, | |
| 713 disabled = anchordisable, | |
| 714 hidden = anchordisable, | |
| 715 }, | |
| 716 anchorY = { | |
| 717 name = L["Y Offset"], | |
| 718 order = 5, | |
| 719 type = "range", | |
| 720 min = -100, | |
| 721 max = 100, | |
| 722 step = 1, | |
| 723 set = setprop, | |
| 724 get = getprop, | |
| 725 disabled = anchordisable, | |
| 726 hidden = anchordisable, | |
| 727 }, | |
| 728 }, | |
| 729 }, | |
| 730 scale = { | |
| 731 name = L["Scale"], | |
| 732 order = 6, | |
| 733 type = "group", | |
| 734 inline = true, | |
| 735 args = { | |
| 736 enableScale = { | |
| 737 name = L["Set New Scale"], | |
| 738 order = 1, | |
| 739 type = "toggle", | |
| 740 set = setprop, | |
| 741 get = getprop, | |
| 742 }, | |
| 743 scale = { | |
| 744 name = L["Scale"], | |
| 745 order = 2, | |
| 746 type = "range", | |
| 747 min = 0.1, | |
| 748 max = 2.5, | |
| 749 step = 0.05, | |
| 750 isPercent = true, | |
| 751 set = setprop, | |
| 752 get = function(info) return getprop(info) or 1 end, | |
| 753 disabled = function() return not GetProperty(bar, opts.name, "enableScale") end, | |
| 754 hidden = function() return not GetProperty(bar, opts.name, "enableScale") end, | |
| 755 }, | |
| 756 }, | |
| 757 }, | |
| 758 }, | |
| 759 }, | |
| 760 rules = { | |
| 761 name = L["Rule"], | |
| 762 order = 3, | |
| 763 type = "group", | |
| 764 args = { | |
| 765 mode = { | |
| 766 name = L["Select this state"], | |
| 767 order = 2, | |
| 768 type = "select", | |
| 769 style = "radio", | |
| 770 values = { | |
| 771 default = L["by default"], | |
| 772 any = L["when ANY of these"], | |
| 773 all = L["when ALL of these"], | |
| 774 custom = L["via custom rule"], | |
| 775 keybind = L["via keybinding"], | |
| 776 }, | |
| 777 set = function( info, value ) | |
| 778 setrule("type", value) | |
| 779 fixall() | |
| 780 update() | |
| 781 end, | |
| 782 get = function( info ) | |
| 783 return getrule("type") | |
| 784 end, | |
| 785 }, | |
| 786 clear = { | |
| 787 name = L["Clear All"], | |
| 788 order = 3, | |
| 789 type = "execute", | |
| 790 hidden = function() | |
| 791 local t = getrule("type") | |
| 792 return t ~= "any" and t ~= "all" | |
| 793 end, | |
| 794 disabled = function() | |
| 795 local t = getrule("type") | |
| 796 return t ~= "any" and t ~= "all" | |
| 797 end, | |
| 798 func = function() | |
| 799 local type = getrule("type") | |
| 800 if type == "custom" then | |
| 801 setrule("custom","") | |
| 802 elseif type == "any" or type == "all" then | |
| 803 setrule("values", {}) | |
| 804 end | |
| 805 update() | |
| 806 end, | |
| 807 }, | |
| 808 inputs = { | |
| 809 name = L["Conditions"], | |
| 810 order = 4, | |
| 811 type = "multiselect", | |
| 812 hidden = function() | |
| 813 local t = getrule("type") | |
| 814 return t ~= "any" and t ~= "all" | |
| 815 end, | |
| 816 disabled = function() | |
| 817 local t = getrule("type") | |
| 818 return t ~= "any" and t ~= "all" | |
| 819 end, | |
| 820 values = ruleSelect, | |
| 821 set = function(info, key, value ) | |
| 822 setrule(ruleMap[key], value or nil, "values") | |
| 823 if value then | |
| 824 fixall(ruleMap[key]) | |
| 825 end | |
| 826 update() | |
| 827 end, | |
| 828 get = function(info, key) | |
| 829 return getrule("values", ruleMap[key]) or false | |
| 830 end, | |
| 831 }, | |
| 832 custom = { | |
| 833 name = L["Custom Rule"], | |
| 834 order = 5, | |
| 835 type = "input", | |
| 836 multiline = true, | |
| 837 hidden = function() | |
| 838 return getrule("type") ~= "custom" | |
| 839 end, | |
| 840 disabled = function() | |
| 841 return getrule("type") ~= "custom" | |
| 842 end, | |
| 843 desc = L["Syntax like macro rules: see preset rules for examples"], | |
| 844 set = function(info, value) | |
| 845 setrule("custom",value) | |
| 846 update() | |
| 847 end, | |
| 848 get = function(info) | |
| 849 return getrule("custom") or "" | |
| 850 end, | |
| 851 validate = function (info, rule) | |
| 852 local s = rule:gsub("%s","") -- remove all spaces | |
| 853 -- unfortunately %b and captures don't support the '+' notation, or this would be considerably simpler | |
| 854 repeat | |
| 855 if s == "" then | |
| 856 return true | |
| 857 end | |
| 858 local c, r = s:match("(%b[])(.*)") | |
| 859 if c == nil and s and #s > 0 then | |
| 860 return format(L["Invalid custom rule '%s': each clause must appear within [brackets]"],rule) | |
| 861 end | |
| 862 s = r | |
| 863 until c == nil | |
| 864 return true | |
| 865 end, | |
| 866 }, | |
| 867 keybind = { | |
| 868 name = L["Keybinding"], | |
| 869 order = 6, | |
| 870 inline = true, | |
| 871 hidden = function() return getrule("type") ~= "keybind" end, | |
| 872 disabled = function() return getrule("type") ~= "keybind" end, | |
| 873 type = "group", | |
| 874 args = { | |
| 875 desc = { | |
| 876 name = L["Invoking a state keybind toggles an override of all other transition rules."], | |
| 877 order = 1, | |
| 878 type = "description", | |
| 879 }, | |
| 880 keybind = { | |
| 881 name = L["State Hotkey"], | |
| 882 desc = L["Define an override toggle keybind"], | |
| 883 order = 2, | |
| 884 type = "keybinding", | |
| 885 set = function(info, value) | |
| 886 if value and #value == 0 then | |
| 887 value = nil | |
| 888 end | |
| 889 setrule("keybind",value) | |
| 890 update() | |
| 891 end, | |
| 892 get = function() return getrule("keybind") end, | |
| 893 }, | |
| 894 }, | |
| 895 }, | |
| 896 }, | |
| 897 }, | |
| 898 } | |
| 899 return opts | 956 return opts |
| 900 end | 957 end |
| 901 | 958 |
| 902 | 959 |
| 903 CreateBarOptions = function(bar) | 960 function RegisterPropertyOptions( field, options, handler ) |
| 961 stateOptions.properties.plugins[field] = options | |
| 962 if handler then | |
| 963 for k,v in pairs(handler) do | |
| 964 StateHandler[k] = v | |
| 965 end | |
| 966 end | |
| 967 end | |
| 968 | |
| 969 | |
| 970 function module:GetBarOptions(bar) | |
| 904 local private = { } | 971 local private = { } |
| 905 local states = tbuild(module.db.profile.bars, bar:GetName(), "states") | 972 local states = tbuild(module.db.profile.bars, bar:GetName(), "states") |
| 906 local options = { | 973 local options = { |
| 907 name = L["Dynamic State"], | 974 name = L["Dynamic State"], |
| 908 type = "group", | 975 type = "group", |
| 952 } | 1019 } |
| 953 } | 1020 } |
| 954 } | 1021 } |
| 955 } | 1022 } |
| 956 } | 1023 } |
| 957 local states = tfetch(module.db.profile.bars, bar:GetName(), "states") | 1024 for name, config in pairs(states) do |
| 958 if states then | 1025 options.args[name] = CreateStateOptions(bar,name) |
| 959 for name, config in pairs(states) do | |
| 960 options.args[name] = CreateStateOptions(bar,name) | |
| 961 end | |
| 962 end | 1026 end |
| 963 optionMap[bar] = options | 1027 optionMap[bar] = options |
| 964 return options | 1028 return options |
| 965 end | 1029 end |
| 966 end | 1030 end |
| 967 | 1031 |
| 968 function module:GetBarOptions(bar) | 1032 -- Module API -- |
| 969 return CreateBarOptions(bar) | 1033 |
| 970 end | 1034 -- Pass in a property field-name, an implementation function, a static options table, and an |
| 1035 -- optional options handler method-table | |
| 1036 -- | |
| 1037 -- propertyImplFunc prototype: | |
| 1038 -- propertyImplFunc( bar, stateTable ) | |
| 1039 -- where stateTable is a { ["statename"] = { state config } } table. | |
| 1040 -- | |
| 1041 -- The options table is static, i.e. not bar-specific and should only reference handler method | |
| 1042 -- strings (either existing ones or those added via optHandler). The existing options are ordered | |
| 1043 -- 91-100. Order #1 is reserved for the heading. | |
| 1044 -- | |
| 1045 -- The contents of optHandler, if provided, will be added to the existing StateHandler metatable. | |
| 1046 -- See above, for existing API. In particular see the properties set up in the New method: self.bar, | |
| 1047 -- self.states, and self:GetName(), and the generic property handlers self:GetProp() and self:SetProp(). | |
| 1048 -- | |
| 1049 function module:RegisterStateProperty( field, propertyImplFunc, options, optHandler ) | |
| 1050 RegisterProperty(field, propertyImplFunc) | |
| 1051 RegisterPropertyOptions(field, options, optHandler) | |
| 1052 end | |
| 1053 |
