|
|
|
|
--[[
|
|
|
|
|
CompositeButtons are intrinsic buttons that create pseudo-buttons from the
|
|
|
|
|
textures in the ARTWORK layer of a button. Its aim is to solve the problem
|
|
|
|
|
of list buttons being encumbered by too many overlaying buttons and all the
|
|
|
|
|
different textures, script handlers and special handling it creates.
|
|
|
|
|
|
|
|
|
|
For example, the old (4.8.9) RematchTeamListButtonTemplate had a separate
|
|
|
|
|
button for notes, preferences, win record, 3 pets and a separate frame for
|
|
|
|
|
the favorites star (so highlight textures would appear below it). The pet
|
|
|
|
|
buttons had multiple layers of textures too. This represented 7 different
|
|
|
|
|
elements that intercept mouse events and three times as many layers of
|
|
|
|
|
textures with their own separate highlights and handling.
|
|
|
|
|
|
|
|
|
|
The new team list button template has no overlaying buttons. Everything
|
|
|
|
|
clickable is a texture in the ARTWORK layer of the button. When the mouse
|
|
|
|
|
moves over one of these textures, it's highlighted by a single reticle
|
|
|
|
|
duplicating the texture with an ADD blend mode, causing the texture to
|
|
|
|
|
brighten. OnClicks, OnEnters and OnLeaves are defined to the texture as if
|
|
|
|
|
it was a button.
|
|
|
|
|
|
|
|
|
|
To use:
|
|
|
|
|
1. Create a widget of type RematchCompositeButton
|
|
|
|
|
2. Add textures to the ARTWORK drawlayer (they will automatically gain
|
|
|
|
|
highlight behavior but will not intercept clicks)
|
|
|
|
|
3. Things that shouldn't be clicked should be in other layers
|
|
|
|
|
4. If they must be in ARTWORK and remain uninteractive:
|
|
|
|
|
texture.ignoreComposite = true
|
|
|
|
|
5. To set script handlers:
|
|
|
|
|
button:SetTextureScript(texture,"OnClick",func)
|
|
|
|
|
Supported handlers: "OnClick", "OnEnter", "OnLeave"
|
|
|
|
|
6. In the parent button's OnClick, check for button:HasFocus() to tell
|
|
|
|
|
if the button has focus but not an active texture. Clicks will go
|
|
|
|
|
through the textures to the underlying button; use HasFocus() to ignore.
|
|
|
|
|
]]
|
|
|
|
|
|
|
|
|
|
RematchCompositeButton = {} -- this is just a namespace for use bY XML
|
|
|
|
|
|
|
|
|
|
local allButtons = {} -- indexed by button, every created composite button
|
|
|
|
|
local onClicks = {} -- indexed by texture, function to run when a texture clicked
|
|
|
|
|
local onEnters = {} -- indexed by texture, function to run when mouse enters a texture
|
|
|
|
|
local onLeaves = {} -- indexed by texture, function to run when mouse leaves a texture
|
|
|
|
|
|
|
|
|
|
-- only one button can have focus and one texture in a button can share focus
|
|
|
|
|
local focusedButton = nil -- button that the mouse is currently over
|
|
|
|
|
local focusedTexture = nil -- texture within the above button that mouse is over
|
|
|
|
|
|
|
|
|
|
local reticle = CreateFrame("Frame", "RematchCompositeButtonReticle", UIParent)
|
|
|
|
|
|
|
|
|
|
-- method to add a script handler to a texture assigned to each button:
|
|
|
|
|
-- button:SetTextureScript(button.Icon,"OnClick",function() end)
|
|
|
|
|
local function setTextureScript(self, texture, handler, func)
|
|
|
|
|
if handler=="OnClick" then
|
|
|
|
|
onClicks[texture] = func -- note: self will be parent button, not texture
|
|
|
|
|
elseif handler=="OnEnter" then
|
|
|
|
|
onEnters[texture] = func
|
|
|
|
|
elseif handler=="OnLeave" then
|
|
|
|
|
onLeaves[texture] = func
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- method to return true if the mouse is over the button but not any active textures
|
|
|
|
|
local function hasFocus(self)
|
|
|
|
|
return focusedButton==self and not focusedTexture
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- when a button is created, add it and its textures to allButtons
|
|
|
|
|
-- (this assumes buttons are created in XML fully formed when OnLoad happens. for
|
|
|
|
|
-- buttons created with CreateFrame, call this after all textures are created.)
|
|
|
|
|
function RematchCompositeButton:OnPreLoad()
|
|
|
|
|
allButtons[self] = {}
|
|
|
|
|
-- add textures in the ARTWORK layer to the new allButtons entry
|
|
|
|
|
local index = 1
|
|
|
|
|
for _,child in ipairs({self:GetRegions()}) do
|
|
|
|
|
if child:GetObjectType()=="Texture" and child:GetDrawLayer()=="ARTWORK" and not child.ignoreComposite then
|
|
|
|
|
allButtons[self][index] = child
|
|
|
|
|
index = index + 1
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
self:RegisterForClicks("AnyUp") -- all buttons accept any mouse button
|
|
|
|
|
-- assign methods to the button
|
|
|
|
|
self.SetTextureScript = setTextureScript
|
|
|
|
|
self.HasFocus = hasFocus
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- onenter starts up reticle monitoring for texture interaction
|
|
|
|
|
function RematchCompositeButton:OnPreEnter()
|
|
|
|
|
focusedButton = self -- set focus to this button
|
|
|
|
|
focusedTexture = nil
|
|
|
|
|
reticle:SetParent(self)
|
|
|
|
|
reticle:SetFrameLevel(self:GetFrameLevel())
|
|
|
|
|
reticle.Overlay:Hide()
|
|
|
|
|
reticle:Show() -- start up reticle if it's not started
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- onleave stops reticle monitoring
|
|
|
|
|
function RematchCompositeButton:OnPreLeave()
|
|
|
|
|
-- if texture has focus, run its OnLeave if applicable
|
|
|
|
|
if focusedButton and focusedTexture and onLeaves[focusedTexture] then
|
|
|
|
|
onLeaves[focusedTexture](focusedTexture)
|
|
|
|
|
end
|
|
|
|
|
focusedButton = nil -- drop focus from this button
|
|
|
|
|
focusedTexture = nil
|
|
|
|
|
reticle:Hide() -- hide reticle
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- on a MouseDown, the overlay is hidden to show the normal texture underneath
|
|
|
|
|
-- this has the effect of making the texture look a bit darker
|
|
|
|
|
function RematchCompositeButton:OnPreMouseDown()
|
|
|
|
|
if focusedTexture then
|
|
|
|
|
reticle.Overlay:Hide()
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- on a MouseDown, then overlay is shown again, making the texture lighter
|
|
|
|
|
function RematchCompositeButton:OnPreMouseUp()
|
|
|
|
|
if focusedTexture then
|
|
|
|
|
reticle.Overlay:Show()
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- on a click of the button, run the texture's OnClick if defined
|
|
|
|
|
function RematchCompositeButton:OnPreClick(button)
|
|
|
|
|
if focusedButton==self and focusedTexture and onClicks[focusedTexture] then
|
|
|
|
|
onClicks[focusedTexture](focusedTexture,button)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- when a button hides that has ownership of the reticle, the reticle hides too.
|
|
|
|
|
-- make sure the texture's OnLeave runs too
|
|
|
|
|
function RematchCompositeButton:OnPreHide()
|
|
|
|
|
if focusedButton==self and focusedTexture and onLeaves[focusedTexture] then
|
|
|
|
|
onLeaves[focusedTexture](focusedTexture)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- the reticle is a frame that's on screen while the mouse is over a composite
|
|
|
|
|
-- button. it watches for the mouse moving over a texture, sets focusedTexture
|
|
|
|
|
-- and highlights the texture.
|
|
|
|
|
reticle:SetSize(32,32)
|
|
|
|
|
reticle.Overlay = reticle:CreateTexture(nil,"OVERLAY")
|
|
|
|
|
reticle.Overlay:SetAlpha(0.75)
|
|
|
|
|
reticle.Overlay:SetBlendMode("ADD")
|
|
|
|
|
reticle:EnableMouse(false)
|
|
|
|
|
reticle:SetScript("OnUpdate",function(self,elapsed)
|
|
|
|
|
if focusedButton and allButtons[focusedButton] then
|
|
|
|
|
for _,texture in ipairs(allButtons[focusedButton]) do
|
|
|
|
|
if MouseIsOver(texture) and texture:IsVisible() then
|
|
|
|
|
if focusedTexture ~= texture then
|
|
|
|
|
-- if leaving another texture, do its OnLeave first if needed
|
|
|
|
|
if focusedTexture and onLeaves[focusedTexture] then
|
|
|
|
|
onLeaves[focusedTexture](focusedTexture)
|
|
|
|
|
end
|
|
|
|
|
focusedTexture = texture
|
|
|
|
|
-- position reticle over the texture
|
|
|
|
|
self.Overlay:SetPoint("TOPLEFT", texture, "TOPLEFT")
|
|
|
|
|
self.Overlay:SetPoint("BOTTOMRIGHT", texture, "BOTTOMRIGHT")
|
|
|
|
|
local drawLayer,textureSubLevel = texture:GetDrawLayer()
|
|
|
|
|
self.Overlay:SetDrawLayer(drawLayer,textureSubLevel+1)
|
|
|
|
|
-- copy the texture to make it lighten the existing one
|
|
|
|
|
self.Overlay:SetTexture(texture:GetTexture())
|
|
|
|
|
self.Overlay:SetTexCoord(texture:GetTexCoord())
|
|
|
|
|
self.Overlay:SetVertexColor(0.75,0.75,0.75,1)
|
|
|
|
|
self.Overlay:SetDesaturated(true)
|
|
|
|
|
-- show reticle
|
|
|
|
|
self.Overlay:Show()
|
|
|
|
|
-- finally do an OnEnter of the focused texture
|
|
|
|
|
if onEnters[texture] then
|
|
|
|
|
onEnters[texture](texture)
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
-- check if texture has changed and update if so
|
|
|
|
|
local currentTexture = texture:GetTexture()
|
|
|
|
|
if self.Overlay:GetTexture()~=currentTexture then
|
|
|
|
|
self.Overlay:SetTexture(currentTexture)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
-- if we reached here mouse is not over texture
|
|
|
|
|
-- first do any OnLeave of the focused texture if one exists
|
|
|
|
|
if focusedTexture and onLeaves[focusedTexture] then
|
|
|
|
|
onLeaves[focusedTexture](focusedTexture)
|
|
|
|
|
end
|
|
|
|
|
focusedTexture = nil
|
|
|
|
|
-- then hide the overlay
|
|
|
|
|
self.Overlay:ClearAllPoints()
|
|
|
|
|
self.Overlay:Hide()
|
|
|
|
|
end
|
|
|
|
|
end)
|