view classes/ActionButton.lua @ 167:eab7e7642dd6

Rewrote MultiCastButton to show prior to learning a summon ability, cleaned up implementation. NOTE: a typo fix will invalidate any existing keybindings to totem buttons.
author Flick <flickerstreak@gmail.com>
date Tue, 19 Oct 2010 16:49:40 +0000
parents 5257073138e8
children 8cc187143acd
line wrap: on
line source
local ReAction = ReAction
local L = ReAction.L
local _G = _G
local CreateFrame = CreateFrame
local format = string.format
local IsUsableAction = IsUsableAction
local IsEquippedAction = IsEquippedAction
local IsConsumableAction = IsConsumableAction
local IsStackableAction = IsStackableAction
local GetActionText = GetActionText
local GetCVar = GetCVar
local GameTooltip_SetDefaultAnchor = GameTooltip_SetDefaultAnchor
local IsCurrentAction = IsCurrentAction
local IsAutoRepeatAction = IsAutoRepeatAction
local IsUsableAction = IsUsableAction
local IsAttackAction = IsAttackAction
local CooldownFrame_SetTimer = CooldownFrame_SetTimer
local GetActionCooldown = GetActionCooldown
local GetActionTexture = GetActionTexture
local ATTACK_BUTTON_FLASH_TIME = ATTACK_BUTTON_FLASH_TIME
local TOOLTIP_UPDATE_TIME = TOOLTIP_UPDATE_TIME
local IsActionInRange = IsActionInRange
local InCombatLockdown = InCombatLockdown
local HasAction = HasAction

ReAction:UpdateRevision("$Revision: 154 $")

--
-- Secure snippets
-- These are run within the context of the bar's sandbox, as the
-- buttons themselves do not have their own sandbox.
--
local _onstate_mc = -- function(self, stateid, newstate)
[[
  local oldMcVehicleState = mcVehicleState
  mcVehicleState = newstate
  control:ChildUpdate()
  if oldMcVehicleState == "vehicle" or mcVehicleState == "vehicle" then
    control:ChildUpdate("vehicle")
  end
]]

local _childupdate = -- function(self, snippetid, message)
[[
  local action = nil
  if (doVehicle and mcVehicleState == "vehicle") or
     (doMindControl and mcVehicleState == "mc") then
    local idx = self:GetAttribute("bar-idx")
    local maxN = (doVehicle and mcVehicleState == "vehicle") and 7 or 12
    if idx and idx <= maxN then
      action = 120 + idx
    else
      action = 0
    end
  elseif state and settings[state] and settings[state].page then
    action = self:GetAttribute("action-"..settings[state].page) 
  end
  if action == nil then
    action = self:GetAttribute("default-action")
  end

  self:SetAttribute("action",action)

  if not self:GetAttribute("showgrid") then
    local hasaction = (action > 120) or self:GetAttribute("hasaction-"..action)
    local tempShow = self:GetAttribute("showgrid-temp")
    local evtShow = self:GetAttribute("showgrid-event")
    if tempShow then tempShow = (tempShow > 0) end
    if evtShow then evtShow = (evtShow > 0) end

    if tempShow or evtShow or hasaction then
      self:Show()
    else
      self:Hide()
    end
  end
]]

local _childupdate_vehicleExit =  -- function(self, snippetid, message)
[[
  local show = (mcVehicleState == "vehicle")
  if show and doVehicle then
    self:SetAttribute("type","macro")
    self:Show()
  else
    self:SetAttribute("type","action")
  end
  control:CallMethod("ShowVehicleExit",show)
]]

local _childupdate_showgrid = -- function(self, snippetid, message)
[[
  self:SetAttribute("showgrid-event",message)
  if not self:GetAttribute("showgrid") then
    local count = message + (self:GetAttribute("showgrid-temp") or 0)
    if count <= 0 then
      local action = self:GetAttribute("action")
      local hasaction = (action > 120) or self:GetAttribute("hasaction-"..action)
      if hasaction then
        self:Show()
      else
        self:Hide()
      end
    else
      self:Show()
    end
  end
]]

local _onDragStart = -- function(self, button, kind, value, ...)
[[
  if lockButtons and (PlayerInCombat() or not lockButtonsCombat) and not IsModifiedClick("PICKUPACTION") then
    return kind, value, ...
  else
    -- don't make any assumptions about hiding on grid show here, as we don't know if the 
    -- drag gets cancelled later. 
    return "action", self:GetAttribute("action")
  end
]]

local _onReceiveDrag = -- function(self, button, kind, value, ...)
[[
  if kind ~= "spell" and kind ~= "item" and kind ~= "macro" then
    return kind, value, ...
  end
  self:SetAttribute("hasaction-"..self:GetAttribute("action"),true)
  return "action", self:GetAttribute("action")
]]

--
-- private
--
local eventList = {
  "PLAYER_REGEN_ENABLED",
  "PLAYER_ENTERING_WORLD",
  "ACTIONBAR_PAGE_CHANGED",
  "ACTIONBAR_SLOT_CHANGED",
  "UPDATE_BINDINGS",
  "ACTIONBAR_UPDATE_STATE",
  "ACTIONBAR_UPDATE_USABLE",
  "ACTIONBAR_UPDATE_COOLDOWN",
  "UNIT_INVENTORY_CHANGED",
  "LEARNED_SPELL_IN_TAB",
  "UPDATE_INVENTORY_ALERTS",
  "PLAYER_TARGET_CHANGED",
  "TRADE_SKILL_SHOW",
  "TRADE_SKILL_CLOSE",
  "PLAYER_ENTER_COMBAT",
  "PLAYER_LEAVE_COMBAT",
  "START_AUTOREPEAT_SPELL",
  "STOP_AUTOREPEAT_SPELL",
  "UNIT_ENTERED_VEHICLE",
  "UNIT_EXITED_VEHICLE",
  "COMPANION_UPDATE",
}

--
-- Action Button class
--
local Super = ReAction.Button
local Action = setmetatable( { }, { __index = Super } )
ReAction.Button.Action = Action

function Action:New( idx, barConfig, bar, idHint )
  local name = format("ReAction_%s_Action_%d",bar:GetName(),idx)
 
  self = Super.New(self, name, barConfig.buttons[idx], bar, idx, "SecureActionButtonTemplate, ActionButtonTemplate" )
  self.barConfig = barConfig

  local f = self:GetFrame()
  local barFrame = bar:GetFrame()
  local config = self:GetConfig()

  self.rangeTimer = TOOLTIP_UPDATE_TIME

  -- set up the base action ID
  self:SetActionIDPool("action",120)
  config.actionID = self:AcquireActionID(config.actionID, idHint)
  self.nPages = 1

  -- attribute setup
  f:SetAttribute("type","action")
  f:SetAttribute("checkselfcast", true)
  f:SetAttribute("checkfocuscast", true)
  f:SetAttribute("action", config.actionID)
  f:SetAttribute("default-action", config.actionID)
  f:SetAttribute("bar-idx",idx)
  f:SetAttribute("showgrid-temp",0)
  f:SetAttribute("showgrid-event",0)
  f:SetAttribute("showgrid",not self:GetBarConfig().hideEmpty)

  -- non secure scripts
  f:SetScript("OnEvent", function(frame, ...) self:OnEvent(...) end)
  f:SetScript("OnEnter", function(frame) self:OnEnter() end)
  f:SetScript("OnLeave", function(frame) self:OnLeave() end)
  f:SetScript("OnAttributeChanged", function(frame, attr, value) self:OnAttributeChanged(attr, value) end)
  f:SetScript("PostClick", function(frame, ...) self:PostClick(...) end)
  f:SetScript("OnUpdate", function(frame, elapsed) self:OnUpdate(elapsed) end)
  f:SetScript("OnDragStart", function(frame) self:OnDragStart() end)
  f:SetScript("OnReceiveDrag", function(frame) self:OnReceiveDrag() end)

  -- event registration
  f:EnableMouse(true)
  f:RegisterForDrag("LeftButton", "RightButton")
  f:RegisterForClicks("AnyUp")
  for _, evt in pairs(eventList) do
    f:RegisterEvent(evt)
  end

  -- secure handlers
  f:SetAttribute("_childupdate", _childupdate)
  f:SetAttribute("_childupdate-showgrid",_childupdate_showgrid)
  barFrame:WrapScript(f, "OnDragStart", _onDragStart)
  barFrame:WrapScript(f, "OnReceiveDrag", _onReceiveDrag)

  -- attach to skinner
  bar:SkinButton(self)

  -- initial display
  if ReAction:GetConfigMode() then
    self:ShowGridTemp(true)
  end

  self:Refresh()

  return self
end

function Action:Destroy()
  local f = self:GetFrame()
  local c = self:GetConfig()

  f:SetAttribute("_childupdate-vehicle",nil)
  f:SetAttribute("action",c.actionID) -- so that Super.Destroy releases the right one

  if c.pageactions and #c.pageactions > 1 then
    for i = 2, #c.pageactions do 
      self:ReleaseActionID(c.pageactions[i])
      self:ReleaseActionID(id)
    end
  end
  
  Super.Destroy(self)
end

function Action:GetBarConfig()
  -- this is the per-bar Action module config structure,
  -- not the config structure of the bar itself
  return self.barConfig
end

function Action:Refresh()
  Super.Refresh(self)
  self:RefreshHasActionAttributes()
  self:RefreshPages()
  self:InstallVehicle()
  self:ShowGrid(not self:GetBarConfig().hideEmpty)
  self:UpdateAction()
end

function Action:InstallVehicle()
  local f = self:GetFrame()
  if self.idx == 7 and self:GetBarConfig().vehicle then
    if not self.vehicleInstalled then
      self.vehicleInstalled = true
      -- install vehicle-exit button on 7th button (only)
      f:SetAttribute("_childupdate-vehicle", _childupdate_vehicleExit)
      f:SetAttribute("macrotext","/run VehicleExit()")
      self:GetBar():GetFrame().ShowVehicleExit = function(bar,show)
        self:ShowVehicleExit(show)
      end
    end
    -- setscale blows away tex coords
    self:UpdateIcon()
  elseif self.vehicleInstalled then
    self.vehicleInstalled = false
    f:SetAttribute("_childupdate-vehicle",nil)
    f:SetAttribute("macrotext",nil)
  end
end

function Action:ShowGrid( show )
  if not InCombatLockdown() then
    self.frame:SetAttribute("showgrid", show)
    self:UpdateShowGrid()
  end
end

function Action:ShowGridTemp( show )
  -- This function only modifies the show-grid when out
  -- of combat, and is ignored by the secure handler. Use 
  -- it for configuration modes.
  if not InCombatLockdown() then
    local count = self.showGridTempCount or 0
    if show then
      count = count + 1
    else
      count = count - 1
    end
    if count < 0 then count = 0 end
    self.showGridTempCount = count
    self:GetFrame():SetAttribute("showgrid-temp",count)
    self:UpdateShowGrid()
  end
end

function Action:UpdateAll()
  self:UpdateActionIDLabel(ReAction:GetConfigMode())
  self:UpdateHotkey()
  self:UpdateShowGrid()
  self:UpdateIcon()
  self:UpdateBorder()
  self:UpdateMacroText()
  self:UpdateCount()
  self:UpdateTooltip()
  self:UpdateCheckedState()
  self:UpdateUsable()
  self:UpdateCooldown()
  self:UpdateFlash()
end

function Action:UpdateAction()
  local action = self:GetActionID()
  if action ~= self.actionID then
    self.actionID = action
    self:UpdateAll()
  end
end

function Action:RefreshHasActionAttributes()
  -- check if each action has an action or not, and flag an attribute
  -- so that the showgrid secure handler can make decisions accordingly
  local f = self:GetFrame()
  local attr = "hasaction-"..self.config.actionID
  local hasAction = HasAction(self.config.actionID)
  if f:GetAttribute(attr) ~= hasAction then
    f:SetAttribute(attr,hasAction) -- avoid setting attribute and triggering script handler unnecessarily
  end
  if self.config.pageactions then
    for i = 1, self.nPages do
      attr = "hasaction-"..self.config.pageactions[i]
      hasAction = HasAction(self.config.pageactions[i])
      if f:GetAttribute(attr) ~= hasAction then
        f:SetAttribute(attr,hasAction)
      end
    end
  end
end

function Action:UpdateShowGrid()
  -- this is a little bit complicated because there's no
  -- secure access to HasAction.
  if InCombatLockdown() then
    self.showgridPending = true  -- handle after combat
  else
    self.showgridPending = false
    self:RefreshHasActionAttributes()

    -- the following is an out-of-combat show/hide to supplement the secure
    -- handling and clean up after it when it guesses
    local f = self:GetFrame()
    local count = (f:GetAttribute("showgrid-event") or 0) +
                  (self.showGridTempCount or 0) +
                  (f:GetAttribute("showgrid") and 1 or 0)

    if count <= 0 and not HasAction(self.actionID) then
      if f:IsShown() then
        f:Hide()
      end
    elseif not f:IsShown() then
      f:Show()
    end
  end
end

function Action:UpdateIcon()
  local texture, tLeft, tRight, tTop, tBottom = self:GetIconTexture()
  local icon = self.frames.icon
  local hotkey = self.frames.hotkey
  local f = self:GetFrame()
  
  if self.vehicleExitMode then
    texture = "Interface\\Vehicles\\UI-Vehicles-Button-Exit-Up"
    icon:SetTexCoord(0.140625, 0.859375, 0.140625, 0.859375)
    icon:SetVertexColor(1,1,1)
  else
    icon:SetTexCoord(0,1,0,1)
  end

  if texture then
    icon:SetTexture(texture)
    if tLeft then
      icon:SetTexCoord(tLeft,tRight,tTop,tBottom)
    end
    icon:Show()
    self.rangeTimer = -1
    f:SetNormalTexture("Interface\\Buttons\\UI-Quickslot2")
  else
    icon:Hide()
    self.frames.cooldown:Hide()
    self.rangeTimer = nil
    f:SetNormalTexture("Interface\\Buttons\\UI-Quickslot")
  end
end

function Action:GetIconTexture()
  return GetActionTexture(self.actionID)
end

function Action:UpdateBorder()
  local action = self.actionID
  if ReAction:GetKeybindMode() then
    self:UpdateKeybindModeDisplay(true)
  elseif IsEquippedAction(action) then
    self.frames.border:SetVertexColor(0, 1.0, 0, 0.35)
    self.frames.border:Show()
  else
    self.frames.border:Hide()
  end
end

function Action:UpdateMacroText()
  local action = self.actionID
  if not IsConsumableAction(action) and not IsStackableAction(action) then
    self.frames.name:SetText(GetActionText(action))
  else
    self.frames.name:SetText("")
  end
end

function Action:UpdateCount()
  local action = self.actionID
  if IsConsumableAction(action) or IsStackableAction(action) then
    self.frames.count:SetText(GetActionCount(action))
  else
    self.frames.count:SetText("")
  end
end

function Action:UpdateTooltip()
  local f = self:GetFrame()
  if GameTooltip:GetOwner() == f then
    self:SetTooltip()
  end
end

function Action:SetTooltip()
  local f = self:GetFrame()
  if GetCVar("UberTooltips") == "1" then
    GameTooltip_SetDefaultAnchor(GameTooltip, f)
  else
    GameTooltip:SetOwner(f,"ANCHOR_RIGHT")
  end
  GameTooltip:SetAction(self.actionID)
end

function Action:UpdateCheckedState()
  local action = self.actionID
  if IsCurrentAction(action) or IsAutoRepeatAction(action) then
    self:GetFrame():SetChecked(1)
  else
    self:GetFrame():SetChecked(0)
  end
end

function Action:UpdateUsable()
  local isUsable, notEnoughMana = self:GetUsable()
  local noRange = self:GetInRange()

  isUsable = self.vehicleExitMode or (isUsable and not noRange)

  if isUsable then
    if self.usableStatus ~= "usable" then
      self.frames.icon:SetVertexColor(1.0, 1.0, 1.0)
      self.frames.normalTexture:SetVertexColor(1.0, 1.0, 1.0)
      self.usableStatus = "usable"
    end
  elseif noRange then
    if self.usableStatus ~= "norange" then
      self.frames.icon:SetVertexColor(1.0,0.1,0.1)
      self.frames.normalTexture:SetVertexColor(1.0, 1.0, 1.0)
      self.usableStatus = "norange"
    end
  elseif notEnoughMana then
    if self.usableStatus ~= "oom" then
      self.frames.icon:SetVertexColor(0.5, 0.5, 1.0)
      self.frames.normalTexture:SetVertexColor(0.5, 0.5, 1.0)
      self.usableStatus = "oom"
    end
  else
    if self.usableStatus ~= "unusable" then
      self.frames.icon:SetVertexColor(0.4, 0.4, 0.4)
      self.frames.normalTexture:SetVertexColor(1.0, 1.0, 1.0)
      self.usableStatus = "unusable"
    end
  end
end

function Action:GetUsable()
  return IsUsableAction(self.actionID)
end

function Action:GetInRange()
  return IsActionInRange(self.actionID) == 0
end

function Action:UpdateCooldown()
  CooldownFrame_SetTimer(self.frames.cooldown, self:GetCooldown())
end

function Action:GetCooldown()
  return GetActionCooldown(self.actionID)
end

function Action:UpdateFlash()
  local action = self.actionID
  self:SetFlash( (IsAttackAction(action) and IsCurrentAction(action)) or IsAutoRepeatAction(action) )
end

function Action:SetFlash(flash)
  if self.flashing ~= flash then
    self.flashing = flash
    self.flashtime = 0
    if not flash then
      self.frames.flash:Hide()
    end
    self:UpdateCheckedState()
  end
end

function Action:RunFlash(elapsed)
  if self.flashing then
    local flashtime = self.flashtime - elapsed
    self.flashtime = flashtime
    if flashtime <= 0 then
      local overtime = -flashtime
      if overtime >= ATTACK_BUTTON_FLASH_TIME then
        overtime = 0
      end
      flashtime = ATTACK_BUTTON_FLASH_TIME - overtime
      local flash = self.frames.flash
      if flash:IsShown() then
        flash:Hide()
      else
        flash:Show()
      end
    end
  end
end

function Action:RunRangeFinder(elapsed)
  local rangeTimer = self.rangeTimer
  if rangeTimer then
    rangeTimer = rangeTimer - elapsed
    self.rangeTimer = rangeTimer
    if rangeTimer <= 0 then
      self:UpdateUsable()
      self.rangeTimer = TOOLTIP_UPDATE_TIME
    end
  end
end

function Action:GetActionID(page)
  if page == nil then
    -- get the effective ID
    return self:GetFrame():GetAttribute("action")
  else
    if page == 1 then
      return self.config.actionID
    else
      return self.config.pageactions and self.config.pageactions[page] or self.config.actionID
    end
  end
end

function Action:SetActionID( id, page )
  id = tonumber(id)
  page = tonumber(page)
  if id == nil or id < 1 or id > 120 then
    ReAction:UserError(L["Action ID range is 1-120"])
    return
  end
  if page and page ~= 1 then
    if not self.config.pageactions then
      self.config.pageactions = { }
    end
    self:ReleaseActionID(self.config.pageactions[page])
    self.config.pageactions[page] = id
    self:AcquireActionID(self.config.pageactions[page])
    self.frame:SetAttribute("action-page"..page,id)
  else
    self:ReleaseActionID(self.config.actionID)
    self.config.actionID = id
    self:AcquireActionID(self.config.actionID)
    self.frame:SetAttribute("action",id)
    self.frame:SetAttribute("default-action",id)
    if self.config.pageactions then
      self.config.pageactions[1] = id
      self.frame:SetAttribute("action-page1",id)
    end
  end
end

function Action:RefreshPages( force )
  local nPages = self:GetBarConfig().nPages
  if nPages and (nPages ~= self.nPages or force) then
    local f = self:GetFrame()
    local c = self.config.pageactions
    if nPages > 1 and not c then
      c = { }
      self.config.pageactions = c
    end
    for i = 1, nPages do
      if i > 1 then
        c[i] = self:AcquireActionID(c[i], self.config.actionID + (i-1)*self.bar:GetNumButtons())
      else
        c[i] = self.config.actionID  -- page 1 is the same as the base actionID
      end
      f:SetAttribute("action-page"..i,c[i])
    end
    for i = nPages+1, #c do
      self:ReleaseActionID(c[i])
      c[i] = nil
      f:SetAttribute("action-page"..i,nil)
    end
    self.nPages = nPages
  end
end

function Action.SetupBarHeader( bar, config ) -- call this as a static method
  local f = bar:GetFrame()
  f:SetAttribute("mindcontrol",config.mindcontrol)
  f:SetAttribute("vehicle",config.vehicle)
  f:Execute(
    [[
    doMindControl = self:GetAttribute("mindcontrol")
    doVehicle = self:GetAttribute("vehicle")
    control:ChildUpdate()
    ]])

  f:SetAttribute("_onstate-mc", _onstate_mc)
  RegisterStateDriver(f, "mc", "[vehicleui] vehicle; [bonusbar:5] mc; none")

  f:SetAttribute("lockbuttons",config.lockButtons)
  f:SetAttribute("lockbuttonscombat",config.lockButtonsCombat)
  f:Execute(
    [[
      lockButtons = self:GetAttribute("lockbuttons")
      lockButtonsCombat = self:GetAttribute("lockbuttonscombat")
    ]])
end


function Action.SetButtonLock( bar, lock, lockCombat ) -- call this as a static method
  local f = bar:GetFrame()
  f:SetAttribute("lockbuttons",lock)
  f:SetAttribute("lockbuttonscombat",lockCombat)
  f:Execute(
    [[
      lockButtons = self:GetAttribute("lockbuttons")
      lockButtonsCombat = self:GetAttribute("lockbuttonscombat")
    ]])
end


function Action:ShowVehicleExit(show)
  self.vehicleExitMode = show and self:GetBarConfig().vehicle
  self:UpdateIcon()
end

function Action:OnEnter( )
  self:SetTooltip()
end

function Action:OnLeave( )
  GameTooltip:Hide()
end

function Action:OnAttributeChanged( attr, value )
  if attr ~= "statehidden" then
    self:UpdateAction()
  end
end

function Action:PostClick( )
  self:UpdateCheckedState()
end

function Action:OnUpdate( elapsed )
  self:RunFlash(elapsed)
  self:RunRangeFinder(elapsed)
end

function Action:OnDragStart()
  self:UpdateCheckedState()
  self:UpdateFlash()
end

function Action:OnReceiveDrag()
  self:UpdateCheckedState()
  self:UpdateFlash()
end

function Action:OnEvent(event, ...)
  if self[event] then
    self[event](self, event, ...)
  end
end

function Action:ACTIONBAR_SLOT_CHANGED(event, action)
  if action == 0 or action == self.actionID then
    self:UpdateAll()
  end
end

function Action:PLAYER_ENTERING_WORLD()
  self:UpdateAction()
end

function Action:ACTIONBAR_PAGE_CHANGED()
  self:UpdateAction()
end

function Action:UPDATE_BONUS_ACTIONBAR()
  self:UpdateAction()
end

function Action:UPDATE_BINDINGS()
  self:UpdateHotkey()
end

function Action:PLAYER_TARGET_CHANGED()
  self.rangeTimer = -1
end

function Action:ACTIONBAR_UPDATE_STATE()
  self:UpdateCheckedState()
end

function Action:TRADE_SKILL_SHOW()
  self:UpdateCheckedState()
end
Action.TRADE_SKILL_CLOSE = Action.TRADE_SKILL_CLOSE

function Action:UNIT_ENTERED_VEHICLE(event,unit)
  if unit == "player" then
    self:UpdateCheckedState()
  end
end
Action.UNIT_EXITED_VEHICLE = Action.UNIT_ENTERED_VEHICLE

function Action:COMPANION_UPDATE(event,unit)
  if unit == "mount" then
    self:UpdateCheckedState()
  end
end

function Action:ACTIONBAR_UPDATE_USABLE()
  self:UpdateUsable()
end

function Action:ACTIONBAR_UPDATE_COOLDOWN()
  self:UpdateCooldown()
end

function Action:PLAYER_ENTER_COMBAT()
  if IsAttackAction(self.actionID) then
    self:SetFlash(true)
  end
end

function Action:PLAYER_LEAVE_COMBAT()
  if IsAttackAction(self.actionID) then
    self:SetFlash(false)
  end
end

function Action:START_AUTOREPEAT_SPELL()
  if IsAutoRepeatAction(self.actionID) then
    self:SetFlash(true)
  end
end

function Action:STOP_AUTOREPEAT_SPELL()
  if not IsAttackAction(self.actionID) then
    self:SetFlash(false)
  end
end

function Action:PLAYER_REGEN_ENABLED()
  if self.showgridPending then
    self:UpdateShowGrid()
  end
end

function Action:UNIT_INVENTORY_CHANGED(unit)
  if unit == "player" then
    self:UpdateTooltip()
  end
end

function Action:LEARNED_SPELL_IN_TAB()
  self:UpdateTooltip()
end