| 
flickerstreak@201
 | 
     1 local addonName, addonTable = ...
 | 
| 
flickerstreak@205
 | 
     2 local pcall = pcall
 | 
| 
flickerstreak@205
 | 
     3 local pairs = pairs
 | 
| 
flickerstreak@205
 | 
     4 local type = type
 | 
| 
flickerstreak@205
 | 
     5 local geterrorhandler = geterrorhandler
 | 
| 
flickerstreak@184
 | 
     6 local LKB = LibStub("LibKeyBound-1.0")
 | 
| 
flickerstreak@33
 | 
     7 local L = LibStub("AceLocale-3.0"):GetLocale("ReAction")
 | 
| 
flickerstreak@33
 | 
     8 
 | 
| 
flickerstreak@205
 | 
     9 ------ Utility ------
 | 
| 
flickerstreak@205
 | 
    10 local tcopy
 | 
| 
flickerstreak@28
 | 
    11 do
 | 
| 
flickerstreak@205
 | 
    12   function tcopy(x)
 | 
| 
flickerstreak@28
 | 
    13     if type(x) ~= "table" then
 | 
| 
flickerstreak@28
 | 
    14       return x
 | 
| 
flickerstreak@28
 | 
    15     end
 | 
| 
flickerstreak@28
 | 
    16     local r = {}
 | 
| 
flickerstreak@28
 | 
    17     for k,v in pairs(x) do
 | 
| 
flickerstreak@205
 | 
    18       r[k] = tcopy(v)
 | 
| 
flickerstreak@28
 | 
    19     end
 | 
| 
flickerstreak@28
 | 
    20     return r
 | 
| 
flickerstreak@28
 | 
    21   end
 | 
| 
flickerstreak@28
 | 
    22 end
 | 
| 
flickerstreak@28
 | 
    23 
 | 
| 
flickerstreak@205
 | 
    24 ------ Core ------
 | 
| 
flickerstreak@205
 | 
    25 local ReAction = LibStub("AceAddon-3.0"):NewAddon( "ReAction",
 | 
| 
flickerstreak@205
 | 
    26   "AceEvent-3.0"
 | 
| 
flickerstreak@205
 | 
    27 )
 | 
| 
flickerstreak@205
 | 
    28 addonTable.ReAction = ReAction
 | 
| 
flickerstreak@205
 | 
    29 ReAction.version = "1.1"
 | 
| 
flickerstreak@205
 | 
    30 ReAction.L = L
 | 
| 
flickerstreak@205
 | 
    31 ReAction.LKB = LKB
 | 
| 
flickerstreak@28
 | 
    32 
 | 
| 
flickerstreak@205
 | 
    33 
 | 
| 
flickerstreak@205
 | 
    34 ------ Handlers ------
 | 
| 
flickerstreak@28
 | 
    35 function ReAction:OnInitialize()
 | 
| 
flickerstreak@28
 | 
    36   self.db = LibStub("AceDB-3.0"):New("ReAction_DB", 
 | 
| 
flickerstreak@28
 | 
    37     { 
 | 
| 
flickerstreak@28
 | 
    38       profile = {
 | 
| 
flickerstreak@28
 | 
    39         bars = { },
 | 
| 
flickerstreak@184
 | 
    40         defaultBar = { },
 | 
| 
flickerstreak@28
 | 
    41       }
 | 
| 
flickerstreak@111
 | 
    42     },
 | 
| 
flickerstreak@182
 | 
    43     true -- use global 'Default' (locale-specific)
 | 
| 
flickerstreak@28
 | 
    44   )
 | 
| 
flickerstreak@205
 | 
    45 
 | 
| 
flickerstreak@205
 | 
    46   self.bars = { }
 | 
| 
flickerstreak@205
 | 
    47   self.defaultBarConfig = { }
 | 
| 
flickerstreak@205
 | 
    48 
 | 
| 
flickerstreak@205
 | 
    49   self.callbacks = LibStub("CallbackHandler-1.0"):New(self)
 | 
| 
flickerstreak@184
 | 
    50   LKB.RegisterCallback(self,"LIBKEYBOUND_ENABLED")
 | 
| 
flickerstreak@184
 | 
    51   LKB.RegisterCallback(self,"LIBKEYBOUND_DISABLED")
 | 
| 
flickerstreak@207
 | 
    52   LKB.RegisterCallback(self, "LIBKEYBOUND_MODE_COLOR_CHANGED","LIBKEYBOUND_ENABLED")
 | 
| 
flickerstreak@182
 | 
    53   self:RegisterEvent("PLAYER_REGEN_DISABLED")
 | 
| 
flickerstreak@182
 | 
    54   self:InitializeOptions()
 | 
| 
flickerstreak@28
 | 
    55 end
 | 
| 
flickerstreak@28
 | 
    56 
 | 
| 
flickerstreak@28
 | 
    57 function ReAction:OnEnable()
 | 
| 
flickerstreak@205
 | 
    58   self:InitializeBars()
 | 
| 
flickerstreak@28
 | 
    59 end
 | 
| 
flickerstreak@28
 | 
    60 
 | 
| 
flickerstreak@28
 | 
    61 function ReAction:OnDisable()
 | 
| 
flickerstreak@205
 | 
    62   self:TearDownBars()
 | 
| 
flickerstreak@28
 | 
    63 end
 | 
| 
flickerstreak@28
 | 
    64 
 | 
| 
flickerstreak@33
 | 
    65 function ReAction:PLAYER_REGEN_DISABLED()
 | 
| 
flickerstreak@205
 | 
    66   if self.configMode == true then
 | 
| 
flickerstreak@63
 | 
    67     self:UserError(L["ReAction config mode disabled during combat."])
 | 
| 
flickerstreak@33
 | 
    68     self:SetConfigMode(false)
 | 
| 
flickerstreak@88
 | 
    69     self:SetKeybindMode(false)
 | 
| 
flickerstreak@185
 | 
    70     self:CloseEditor()
 | 
| 
flickerstreak@33
 | 
    71   end
 | 
| 
flickerstreak@33
 | 
    72 end
 | 
| 
flickerstreak@33
 | 
    73 
 | 
| 
flickerstreak@88
 | 
    74 function ReAction:LIBKEYBOUND_ENABLED( evt )
 | 
| 
flickerstreak@88
 | 
    75   self:SetKeybindMode(true)
 | 
| 
flickerstreak@88
 | 
    76 end
 | 
| 
flickerstreak@88
 | 
    77 
 | 
| 
flickerstreak@88
 | 
    78 function ReAction:LIBKEYBOUND_DISABLED( evt )
 | 
| 
flickerstreak@88
 | 
    79   return self:SetKeybindMode(false)
 | 
| 
flickerstreak@88
 | 
    80 end
 | 
| 
flickerstreak@88
 | 
    81 
 | 
| 
flickerstreak@33
 | 
    82 
 | 
| 
flickerstreak@205
 | 
    83 ------ Methods ------
 | 
| 
flickerstreak@77
 | 
    84 
 | 
| 
flickerstreak@61
 | 
    85 function ReAction:UserError(msg)
 | 
| 
flickerstreak@61
 | 
    86   UIErrorsFrame:AddMessage(msg)
 | 
| 
flickerstreak@61
 | 
    87 end
 | 
| 
flickerstreak@61
 | 
    88 
 | 
| 
flickerstreak@205
 | 
    89 function ReAction:GetBar(arg)
 | 
| 
flickerstreak@205
 | 
    90   if type(arg) == "string" then
 | 
| 
flickerstreak@205
 | 
    91     return self.bars[arg], arg
 | 
| 
flickerstreak@205
 | 
    92   elseif type(arg) == "table" then -- reverse lookup
 | 
| 
flickerstreak@205
 | 
    93     for name, bar in pairs(self.bars) do
 | 
| 
flickerstreak@205
 | 
    94       if arg == bar then
 | 
| 
flickerstreak@205
 | 
    95         return bar, name
 | 
| 
flickerstreak@205
 | 
    96       end
 | 
| 
flickerstreak@205
 | 
    97     end
 | 
| 
flickerstreak@205
 | 
    98   else
 | 
| 
flickerstreak@205
 | 
    99     error("ReAction:GetBar() requires either a name or a bar table arg")
 | 
| 
flickerstreak@205
 | 
   100   end
 | 
| 
flickerstreak@184
 | 
   101 end
 | 
| 
flickerstreak@184
 | 
   102 
 | 
| 
flickerstreak@205
 | 
   103 function ReAction:IterateBars()
 | 
| 
flickerstreak@205
 | 
   104   return pairs(self.bars)
 | 
| 
flickerstreak@205
 | 
   105 end
 | 
| 
flickerstreak@184
 | 
   106 
 | 
| 
flickerstreak@63
 | 
   107 -- usage:
 | 
| 
flickerstreak@91
 | 
   108 --  (1) ReAction:CreateBar(name, [cfgTable])
 | 
| 
flickerstreak@63
 | 
   109 --  (2) ReAction:CreateBar(name, "barType", [nRows], [nCols], [btnSize], [btnSpacing])
 | 
| 
flickerstreak@91
 | 
   110 function ReAction:CreateBar(name, config, ...)
 | 
| 
flickerstreak@91
 | 
   111   local profile = self.db.profile
 | 
| 
flickerstreak@91
 | 
   112 
 | 
| 
flickerstreak@127
 | 
   113   if name then
 | 
| 
flickerstreak@205
 | 
   114     if self.bars[name] then
 | 
| 
flickerstreak@127
 | 
   115       self:UserError(format(L["ReAction: name '%s' already in use"],name))
 | 
| 
flickerstreak@127
 | 
   116       return nil
 | 
| 
flickerstreak@127
 | 
   117     end
 | 
| 
flickerstreak@127
 | 
   118   else
 | 
| 
flickerstreak@91
 | 
   119     local prefix = L["Bar "]
 | 
| 
flickerstreak@91
 | 
   120     local i = 1
 | 
| 
flickerstreak@91
 | 
   121     repeat
 | 
| 
flickerstreak@91
 | 
   122       name = prefix..i
 | 
| 
flickerstreak@91
 | 
   123       i = i + 1
 | 
| 
flickerstreak@205
 | 
   124     until self.bars[name] == nil
 | 
| 
flickerstreak@91
 | 
   125   end
 | 
| 
flickerstreak@91
 | 
   126 
 | 
| 
flickerstreak@91
 | 
   127   if type(config) == "string" then
 | 
| 
flickerstreak@205
 | 
   128     config = self.defaultBarConfig[config]
 | 
| 
flickerstreak@48
 | 
   129     if not config then
 | 
| 
flickerstreak@91
 | 
   130       error(("ReAction:CreateBar() - unknown bar type '%s'"):format(tostring(select(1,...))))
 | 
| 
flickerstreak@48
 | 
   131     end
 | 
| 
flickerstreak@205
 | 
   132     config = tcopy(config)
 | 
| 
flickerstreak@91
 | 
   133     config.btnRows    = select(1,...) or config.btnRows    or 1
 | 
| 
flickerstreak@91
 | 
   134     config.btnColumns = select(2,...) or config.btnColumns or 12
 | 
| 
flickerstreak@91
 | 
   135     config.btnWidth   = select(3,...) or config.btnWidth   or 36
 | 
| 
flickerstreak@91
 | 
   136     config.btnHeight  = select(3,...) or config.btnHeight  or 36
 | 
| 
flickerstreak@91
 | 
   137     config.spacing    = select(4,...) or config.spacing    or 3
 | 
| 
flickerstreak@48
 | 
   138     config.width      = config.width or config.btnColumns*(config.btnWidth + config.spacing) + 1
 | 
| 
flickerstreak@48
 | 
   139     config.height     = config.height or config.btnRows*(config.btnHeight + config.spacing) + 1
 | 
| 
flickerstreak@81
 | 
   140     config.anchor     = config.anchor or "UIParent"
 | 
| 
flickerstreak@81
 | 
   141     config.point      = config.point or "BOTTOM"
 | 
| 
flickerstreak@81
 | 
   142     config.relpoint   = config.relpoint or "BOTTOM"
 | 
| 
flickerstreak@48
 | 
   143     config.y          = config.y or 200
 | 
| 
flickerstreak@48
 | 
   144     config.x          = config.x or 0
 | 
| 
flickerstreak@48
 | 
   145   end
 | 
| 
flickerstreak@205
 | 
   146   config = config or profile.bars[name] or tcopy(profile.defaultBar)
 | 
| 
flickerstreak@91
 | 
   147 
 | 
| 
flickerstreak@91
 | 
   148   profile.bars[name] = config
 | 
| 
flickerstreak@91
 | 
   149   local bar = self.Bar:New( name, config )  -- ReAction.Bar defined in Bar.lua
 | 
| 
flickerstreak@205
 | 
   150   self.bars[name] = bar
 | 
| 
flickerstreak@205
 | 
   151   self.callbacks:Fire("OnCreateBar", bar, name)
 | 
| 
flickerstreak@205
 | 
   152   if self.configMode then
 | 
| 
flickerstreak@33
 | 
   153     bar:ShowControls(true)
 | 
| 
flickerstreak@33
 | 
   154   end
 | 
| 
flickerstreak@33
 | 
   155 
 | 
| 
flickerstreak@28
 | 
   156   return bar
 | 
| 
flickerstreak@28
 | 
   157 end
 | 
| 
flickerstreak@28
 | 
   158 
 | 
| 
flickerstreak@205
 | 
   159 function ReAction:DestroyBar(x)
 | 
| 
flickerstreak@205
 | 
   160   local bar, name = self:GetBar(x)
 | 
| 
flickerstreak@63
 | 
   161   if bar and name then
 | 
| 
flickerstreak@205
 | 
   162     self.bars[name] = nil
 | 
| 
flickerstreak@205
 | 
   163     self.callbacks:Fire("OnDestroyBar", bar, name)
 | 
| 
flickerstreak@205
 | 
   164     bar:Destroy()
 | 
| 
flickerstreak@28
 | 
   165   end
 | 
| 
flickerstreak@28
 | 
   166 end
 | 
| 
flickerstreak@28
 | 
   167 
 | 
| 
flickerstreak@205
 | 
   168 function ReAction:RefreshBar(x)
 | 
| 
flickerstreak@205
 | 
   169   local bar, name = self:GetBar(x)
 | 
| 
flickerstreak@205
 | 
   170   if bar and name then
 | 
| 
flickerstreak@205
 | 
   171     self.callbacks:Fire("OnRefreshBar", bar, name)
 | 
| 
flickerstreak@205
 | 
   172   end
 | 
| 
flickerstreak@63
 | 
   173 end
 | 
| 
flickerstreak@63
 | 
   174 
 | 
| 
flickerstreak@205
 | 
   175 function ReAction:InitializeBars()
 | 
| 
flickerstreak@205
 | 
   176   if not self.barsInitialized then
 | 
| 
flickerstreak@205
 | 
   177     for name, config in pairs(self.db.profile.bars) do
 | 
| 
flickerstreak@205
 | 
   178       if config then
 | 
| 
flickerstreak@205
 | 
   179         self:CreateBar(name, config)
 | 
| 
flickerstreak@205
 | 
   180       end
 | 
| 
flickerstreak@205
 | 
   181     end
 | 
| 
flickerstreak@205
 | 
   182     -- re-anchor and refresh in case anchor order does not match init order
 | 
| 
flickerstreak@205
 | 
   183     for name, bar in pairs(self.bars) do
 | 
| 
flickerstreak@205
 | 
   184       bar:ApplyAnchor()
 | 
| 
flickerstreak@205
 | 
   185       self.callbacks:Fire("OnRefreshBar", bar, name)
 | 
| 
flickerstreak@205
 | 
   186     end
 | 
| 
flickerstreak@205
 | 
   187     self.barsInitialized = true
 | 
| 
flickerstreak@205
 | 
   188   end
 | 
| 
flickerstreak@205
 | 
   189 end
 | 
| 
flickerstreak@205
 | 
   190 
 | 
| 
flickerstreak@205
 | 
   191 function ReAction:TearDownBars()
 | 
| 
flickerstreak@205
 | 
   192   for name, bar in pairs(self.bars) do
 | 
| 
flickerstreak@205
 | 
   193     if bar then
 | 
| 
flickerstreak@205
 | 
   194       self.bars[name] = DestroyBar(bar)
 | 
| 
flickerstreak@205
 | 
   195     end
 | 
| 
flickerstreak@205
 | 
   196   end
 | 
| 
flickerstreak@205
 | 
   197   self.barsInitialized = false
 | 
| 
flickerstreak@205
 | 
   198 end
 | 
| 
flickerstreak@205
 | 
   199 
 | 
| 
flickerstreak@205
 | 
   200 function ReAction:RebuildAll()
 | 
| 
flickerstreak@205
 | 
   201   self:TearDownBars()
 | 
| 
flickerstreak@205
 | 
   202   self:InitializeBars()
 | 
| 
flickerstreak@28
 | 
   203 end
 | 
| 
flickerstreak@28
 | 
   204 
 | 
| 
flickerstreak@28
 | 
   205 function ReAction:RenameBar(x, newname)
 | 
| 
flickerstreak@205
 | 
   206   local bar, name = self:GetBar(x)
 | 
| 
flickerstreak@63
 | 
   207   if type(newname) ~= "string" then
 | 
| 
flickerstreak@63
 | 
   208     error("ReAction:RenameBar() - second argument must be a string")
 | 
| 
flickerstreak@63
 | 
   209   end
 | 
| 
flickerstreak@63
 | 
   210   if bar and name and #newname > 0 then
 | 
| 
flickerstreak@127
 | 
   211     if newname == name then
 | 
| 
flickerstreak@127
 | 
   212       return
 | 
| 
flickerstreak@127
 | 
   213     end
 | 
| 
flickerstreak@205
 | 
   214     if self.bars[newname] then
 | 
| 
flickerstreak@127
 | 
   215       self:UserError(format(L["ReAction: name '%s' already in use"],newname))
 | 
| 
flickerstreak@47
 | 
   216     else
 | 
| 
flickerstreak@205
 | 
   217       self.bars[newname], self.bars[name] = self.bars[name], nil
 | 
| 
flickerstreak@47
 | 
   218       bar:SetName(newname or "")
 | 
| 
flickerstreak@47
 | 
   219       local cfg = self.db.profile.bars
 | 
| 
flickerstreak@47
 | 
   220       cfg[newname], cfg[name] = cfg[name], nil
 | 
| 
flickerstreak@205
 | 
   221       self.callbacks:Fire("OnRenameBar", bar, name, newname)
 | 
| 
flickerstreak@28
 | 
   222     end
 | 
| 
flickerstreak@28
 | 
   223   end
 | 
| 
flickerstreak@28
 | 
   224 end
 | 
| 
flickerstreak@28
 | 
   225 
 | 
| 
flickerstreak@205
 | 
   226 function ReAction:EraseBar(x)
 | 
| 
flickerstreak@205
 | 
   227   local bar, name = self:GetBar(x)
 | 
| 
flickerstreak@63
 | 
   228   if bar and name then
 | 
| 
flickerstreak@205
 | 
   229     self.callbacks:Fire("OnEraseBar", bar, name)
 | 
| 
flickerstreak@205
 | 
   230     DestroyBar(bar)
 | 
| 
flickerstreak@205
 | 
   231     self.db.profile.bars[name] = nil
 | 
| 
flickerstreak@63
 | 
   232   end
 | 
| 
flickerstreak@63
 | 
   233 end
 | 
| 
flickerstreak@63
 | 
   234 
 | 
| 
flickerstreak@53
 | 
   235 function ReAction:RegisterBarType( name, config, isDefaultChoice )
 | 
| 
flickerstreak@205
 | 
   236   self.defaultBarConfig[name] = config
 | 
| 
flickerstreak@48
 | 
   237   if isDefaultChoice then
 | 
| 
flickerstreak@205
 | 
   238     self.defaultBarConfigChoice = name
 | 
| 
flickerstreak@48
 | 
   239   end
 | 
| 
flickerstreak@185
 | 
   240   self:RefreshEditor()
 | 
| 
flickerstreak@48
 | 
   241 end
 | 
| 
flickerstreak@48
 | 
   242 
 | 
| 
flickerstreak@53
 | 
   243 function ReAction:UnregisterBarType( name )
 | 
| 
flickerstreak@205
 | 
   244   self.defaultBarConfig[name] = nil
 | 
| 
flickerstreak@205
 | 
   245   if self.defaultBarConfigChoice == name then
 | 
| 
flickerstreak@205
 | 
   246     self.defaultBarConfigChoice = nil
 | 
| 
flickerstreak@48
 | 
   247   end
 | 
| 
flickerstreak@185
 | 
   248   self:RefreshEditor()
 | 
| 
flickerstreak@48
 | 
   249 end
 | 
| 
flickerstreak@48
 | 
   250 
 | 
| 
flickerstreak@63
 | 
   251 function ReAction:IterateBarTypes()
 | 
| 
flickerstreak@205
 | 
   252   return pairs(self.defaultBarConfig)
 | 
| 
flickerstreak@63
 | 
   253 end
 | 
| 
flickerstreak@63
 | 
   254 
 | 
| 
flickerstreak@63
 | 
   255 function ReAction:GetBarTypeConfig(name)
 | 
| 
flickerstreak@63
 | 
   256   if name then
 | 
| 
flickerstreak@205
 | 
   257     return self.defaultBarConfig[name]
 | 
| 
flickerstreak@63
 | 
   258   end
 | 
| 
flickerstreak@63
 | 
   259 end
 | 
| 
flickerstreak@63
 | 
   260 
 | 
| 
flickerstreak@63
 | 
   261 function ReAction:GetBarTypeOptions( fill )
 | 
| 
flickerstreak@63
 | 
   262   fill = fill or { }
 | 
| 
flickerstreak@63
 | 
   263   for k in self:IterateBarTypes() do
 | 
| 
flickerstreak@63
 | 
   264     fill[k] = k
 | 
| 
flickerstreak@63
 | 
   265   end
 | 
| 
flickerstreak@63
 | 
   266   return fill
 | 
| 
flickerstreak@63
 | 
   267 end
 | 
| 
flickerstreak@63
 | 
   268 
 | 
| 
flickerstreak@63
 | 
   269 function ReAction:GetDefaultBarType()
 | 
| 
flickerstreak@205
 | 
   270   return self.defaultBarConfigChoice
 | 
| 
flickerstreak@63
 | 
   271 end
 | 
| 
flickerstreak@63
 | 
   272 
 | 
| 
flickerstreak@33
 | 
   273 function ReAction:SetConfigMode( mode )
 | 
| 
flickerstreak@205
 | 
   274   if mode ~= self.configMode then
 | 
| 
flickerstreak@207
 | 
   275     if mode then
 | 
| 
flickerstreak@207
 | 
   276       self:SetKeybindMode(false)
 | 
| 
flickerstreak@207
 | 
   277     end
 | 
| 
flickerstreak@205
 | 
   278     self.configMode = mode
 | 
| 
flickerstreak@205
 | 
   279     self.callbacks:Fire("OnConfigModeChanged", mode)
 | 
| 
flickerstreak@77
 | 
   280   end
 | 
| 
flickerstreak@63
 | 
   281 end
 | 
| 
flickerstreak@63
 | 
   282 
 | 
| 
flickerstreak@63
 | 
   283 function ReAction:GetConfigMode()
 | 
| 
flickerstreak@205
 | 
   284   return self.configMode
 | 
| 
flickerstreak@33
 | 
   285 end
 | 
| 
flickerstreak@38
 | 
   286 
 | 
| 
flickerstreak@88
 | 
   287 function ReAction:SetKeybindMode( mode )
 | 
| 
flickerstreak@205
 | 
   288   if mode ~= self.kbMode then
 | 
| 
flickerstreak@88
 | 
   289     if mode then
 | 
| 
flickerstreak@207
 | 
   290       self:SetConfigMode(false)
 | 
| 
flickerstreak@184
 | 
   291       LKB:Activate()
 | 
| 
flickerstreak@88
 | 
   292     else
 | 
| 
flickerstreak@184
 | 
   293       LKB:Deactivate()
 | 
| 
flickerstreak@88
 | 
   294     end
 | 
| 
flickerstreak@207
 | 
   295     for _, bar in self:IterateBars() do
 | 
| 
flickerstreak@207
 | 
   296       bar:SetKeybindMode(mode)
 | 
| 
flickerstreak@207
 | 
   297     end
 | 
| 
flickerstreak@205
 | 
   298     self.kbMode = LKB:IsShown() or false
 | 
| 
flickerstreak@88
 | 
   299   end
 | 
| 
flickerstreak@88
 | 
   300 end
 | 
| 
flickerstreak@88
 | 
   301 
 | 
| 
flickerstreak@88
 | 
   302 function ReAction:GetKeybindMode( mode )
 | 
| 
flickerstreak@205
 | 
   303   return self.kbMode
 | 
| 
flickerstreak@88
 | 
   304 end
 |