Files

431 lines
15 KiB
Lua

local E, L, V, P, G = unpack(ElvUI)
local MF = E:NewModule("Enhanced_ModelFrames", "AceHook-3.0", "AceEvent-3.0")
local S = E:GetModule("Skins")
local _G = _G
local max, min = math.max, math.min
local PI = math.pi
local GetCVar = GetCVar
local GetCursorPosition = GetCursorPosition
local Model_RotateLeft = Model_RotateLeft
local Model_RotateRight = Model_RotateRight
local ROTATIONS_PER_SECOND = ROTATIONS_PER_SECOND
local modelFrames = {
"DressUpModel",
"PetStableModel"
}
local modelSettings = {
["HumanMale"] = {panMaxLeft = -0.4, panMaxRight = 0.4, panMaxTop = 1.2, panMaxBottom = -0.3, panValue = 38},
["HumanFemale"] = {panMaxLeft = -0.3, panMaxRight = 0.3, panMaxTop = 1.2, panMaxBottom = -0.2, panValue = 45},
["DwarfMale"] = {panMaxLeft = -0.4, panMaxRight = 0.6, panMaxTop = 0.9, panMaxBottom = -0.2, panValue = 44},
["DwarfFemale"] = {panMaxLeft = -0.3, panMaxRight = 0.3, panMaxTop = 0.9, panMaxBottom = -0.2, panValue = 47},
["NightElfMale"] = {panMaxLeft = -0.5, panMaxRight = 0.5, panMaxTop = 1.5, panMaxBottom = -0.4, panValue = 30},
["NightElfFemale"] = {panMaxLeft = -0.4, panMaxRight = 0.4, panMaxTop = 1.4, panMaxBottom = -0.4, panValue = 33},
["GnomeMale"] = {panMaxLeft = -0.3, panMaxRight = 0.3, panMaxTop = 0.5, panMaxBottom = -0.2, panValue = 52},
["GnomeFemale"] = {panMaxLeft = -0.3, panMaxRight = 0.3, panMaxTop = 0.5, panMaxBottom = -0.2, panValue = 60},
["DraeneiMale"] = {panMaxLeft = -0.6, panMaxRight = 0.6, panMaxTop = 1.4, panMaxBottom = -0.4, panValue = 28},
["DraeneiFemale"] = {panMaxLeft = -0.3, panMaxRight = 0.3, panMaxTop = 1.4, panMaxBottom = -0.3, panValue = 31},
["OrcMale"] = {panMaxLeft = -0.7, panMaxRight = 0.8, panMaxTop = 1.2, panMaxBottom = -0.3, panValue = 30},
["OrcFemale"] = {panMaxLeft = -0.4, panMaxRight = 0.3, panMaxTop = 1.2, panMaxBottom = -0.3, panValue = 37},
["ScourgeMale"] = {panMaxLeft = -0.4, panMaxRight = 0.4, panMaxTop = 1.1, panMaxBottom = -0.3, panValue = 35},
["ScourgeFemale"] = {panMaxLeft = -0.3, panMaxRight = 0.4, panMaxTop = 1.1, panMaxBottom = -0.3, panValue = 36},
["TaurenMale"] = {panMaxLeft = -0.7, panMaxRight = 0.9, panMaxTop = 1.1, panMaxBottom = -0.5, panValue = 31},
["TaurenFemale"] = {panMaxLeft = -0.5, panMaxRight = 0.6, panMaxTop = 1.3, panMaxBottom = -0.4, panValue = 32},
["TrollMale"] = {panMaxLeft = -0.5, panMaxRight = 0.6, panMaxTop = 1.3, panMaxBottom = -0.4, panValue = 27},
["TrollFemale"] = {panMaxLeft = -0.4, panMaxRight = 0.4, panMaxTop = 1.5, panMaxBottom = -0.4, panValue = 31},
["BloodElfMale"] = {panMaxLeft = -0.5, panMaxRight = 0.4, panMaxTop = 1.3, panMaxBottom = -0.3, panValue = 36},
["BloodElfFemale"] = {panMaxLeft = -0.3, panMaxRight = 0.2, panMaxTop = 1.2, panMaxBottom = -0.3, panValue = 38},
}
local playerRaceSex
do
local _
_, playerRaceSex = UnitRace("player")
if UnitSex("player") == 2 then
playerRaceSex = playerRaceSex.."Male"
else
playerRaceSex = playerRaceSex.."Female"
end
end
function MF:ModelControlButton(model)
model:Size(18, 18)
model.icon = model:CreateTexture("$parentIcon", "ARTWORK")
model.icon:SetInside()
model.icon:SetTexture("Interface\\AddOns\\ElvUI_Enhanced\\Media\\Textures\\UI-ModelControlPanel")
model.icon:SetTexCoord(0.01562500, 0.26562500, 0.00781250, 0.13281250)
model:SetScript("OnMouseDown", function(self) MF:ModelControlButton_OnMouseDown(self) end)
model:SetScript("OnMouseUp", function(self) MF:ModelControlButton_OnMouseUp(self) end)
model:SetScript("OnEnter", function(self)
UIFrameFadeIn(self:GetParent(), 0.2, self:GetParent():GetAlpha(), 1)
if GetCVar("UberTooltips") == "1" then
GameTooltip:SetOwner(self, "ANCHOR_TOPLEFT")
GameTooltip:SetText(self.tooltip, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b)
if self.tooltipText then
GameTooltip:AddLine(self.tooltipText, nil, nil, nil, 1, 1)
end
GameTooltip:Show()
end
end)
model:SetScript("OnLeave", function(self)
UIFrameFadeOut(self:GetParent(), 0.2, self:GetParent():GetAlpha(), 0.5)
GameTooltip:Hide()
end)
end
function MF:ModelWithControls(model)
model.controlFrame = CreateFrame("Frame", "$parentControlFrame", model)
model.controlFrame:Point("TOP", 0, -2)
model.controlFrame:SetAlpha(0.5)
model.controlFrame:Hide()
local zoomInButton = CreateFrame("Button", "$parentZoomInButton", model.controlFrame)
self:ModelControlButton(zoomInButton)
zoomInButton:Point("LEFT", 2, 0)
zoomInButton:RegisterForClicks("AnyUp")
zoomInButton.icon:SetTexCoord(0.57812500, 0.82812500, 0.14843750, 0.27343750)
zoomInButton.tooltip = L["Zoom In"]
zoomInButton.tooltipText = L["Mouse Wheel Up"]
zoomInButton:SetScript("OnMouseDown", function(self)
MF:Model_OnMouseWheel(self:GetParent():GetParent(), 1)
end)
local zoomOutButton = CreateFrame("Button", "$parentZoomOutButton", model.controlFrame)
self:ModelControlButton(zoomOutButton)
zoomOutButton:Point("LEFT", 2, 0)
zoomOutButton:RegisterForClicks("AnyUp")
zoomOutButton.icon:SetTexCoord(0.29687500, 0.54687500, 0.00781250, 0.13281250)
zoomOutButton.tooltip = L["Zoom Out"]
zoomOutButton.tooltipText = L["Mouse Wheel Down"]
zoomOutButton:SetScript("OnMouseDown", function(self)
MF:Model_OnMouseWheel(self:GetParent():GetParent(), -1)
end)
local panButton = CreateFrame("Button", "$parentPanButton", model.controlFrame)
self:ModelControlButton(panButton)
panButton:Point("LEFT", 2, 0)
panButton:RegisterForClicks("AnyUp")
panButton.icon:SetTexCoord(0.29687500, 0.54687500, 0.28906250, 0.41406250)
panButton.tooltip = L["Drag"]
panButton.tooltipText = L["Right-click on character and drag to move it within the window."]
panButton:SetScript("OnMouseDown", function(self)
MF:ModelControlButton_OnMouseDown(self)
MF:Model_StartPanning(self:GetParent():GetParent(), true)
end)
panButton:SetScript("OnMouseUp", function(self)
MF:Model_StopPanning(model)
MF:ModelControlButton_OnMouseUp(self)
if not model:IsMouseOver() and not model.controlFrame:IsMouseOver() then
model.controlFrame:Hide()
end
end)
local rotateLeftButton = CreateFrame("Button", "$parentRotateLeftButton", model.controlFrame)
self:ModelControlButton(rotateLeftButton)
rotateLeftButton:RegisterForClicks("AnyUp")
rotateLeftButton.icon:SetTexCoord(0.01562500, 0.26562500, 0.28906250, 0.41406250)
rotateLeftButton.tooltip = L["Rotate Left"]
rotateLeftButton.tooltipText = L["Left-click on character and drag to rotate."]
rotateLeftButton:SetScript("OnClick", function(self)
Model_RotateLeft(self:GetParent():GetParent())
end)
model.controlFrame.rotateLeftButton = rotateLeftButton
local rotateRightButton = CreateFrame("Button", "$parentRotateRightButton", model.controlFrame)
self:ModelControlButton(rotateRightButton)
rotateRightButton:RegisterForClicks("AnyUp")
rotateRightButton.icon:SetTexCoord(0.57812500, 0.82812500, 0.28906250, 0.41406250)
rotateRightButton.tooltip = L["Rotate Right"]
rotateRightButton.tooltipText = L["Left-click on character and drag to rotate."]
rotateRightButton:SetScript("OnClick", function(self)
Model_RotateRight(self:GetParent():GetParent())
end)
model.controlFrame.rotateRightButton = rotateRightButton
local rotateResetButton = CreateFrame("Button", "$parentrotateResetButton", model.controlFrame)
self:ModelControlButton(rotateResetButton)
rotateResetButton:RegisterForClicks("AnyUp")
rotateResetButton.tooltip = L["Reset Position"]
rotateResetButton:SetScript("OnClick", function(self)
MF:Model_Reset(self:GetParent():GetParent())
end)
if E.private.skins.blizzard.enable then
model.controlFrame:Size(123, 23)
S:HandleButton(zoomInButton)
S:HandleButton(zoomOutButton)
zoomOutButton:Point("LEFT", "$parentZoomInButton", "RIGHT", 2, 0)
S:HandleButton(panButton)
panButton:Point("LEFT", "$parentZoomOutButton", "RIGHT", 2, 0)
S:HandleButton(rotateLeftButton)
rotateLeftButton:Point("LEFT", "$parentPanButton", "RIGHT", 2, 0)
S:HandleButton(rotateRightButton)
rotateRightButton:Point("LEFT", "$parentRotateLeftButton", "RIGHT", 2, 0)
S:HandleButton(rotateResetButton)
rotateResetButton:Point("LEFT", "$parentRotateRightButton", "RIGHT", 2, 0)
else
model.controlFrame:Size(114, 23)
zoomOutButton:SetPoint("LEFT", "$parentZoomInButton", "RIGHT")
panButton:SetPoint("LEFT", "$parentZoomOutButton", "RIGHT")
rotateLeftButton:SetPoint("LEFT", "$parentPanButton", "RIGHT")
rotateRightButton:SetPoint("LEFT", "$parentRotateLeftButton", "RIGHT")
rotateResetButton:SetPoint("LEFT", "$parentRotateRightButton", "RIGHT")
end
model.controlFrame:SetScript("OnHide", function(self)
if self.buttonDown then
MF:ModelControlButton_OnMouseUp(self.buttonDown)
end
end)
self:HookScript(model, "OnUpdate", "Model_OnUpdate")
model:SetScript("OnMouseWheel", function(self, delta)
MF:Model_OnMouseWheel(self, delta)
end)
model:SetScript("OnMouseUp", function(self, button)
if button == "RightButton" and self.panning then
MF:Model_StopPanning(self)
elseif self.mouseDown then
MF:Model_OnMouseUp(self, button)
end
end)
model:SetScript("OnMouseDown", function(self, button)
if button == "RightButton" and not self.mouseDown then
MF:Model_StartPanning(self)
else
MF:Model_OnMouseDown(self, button)
end
end)
model:SetScript("OnEnter", function(self)
self.controlFrame:Show()
end)
model:SetScript("OnLeave", function(self)
if not self.controlFrame:IsMouseOver() and not ModelPanningFrame:IsShown() then
self.controlFrame:Hide()
end
end)
model:SetScript("OnHide", function(self)
if self.panning then
MF:Model_StopPanning(self)
end
self.mouseDown = false
self.controlFrame:Hide()
MF:Model_Reset(self)
end)
end
function MF:Model_OnMouseWheel(model, delta, maxZoom, minZoom)
maxZoom = maxZoom or 2.8
minZoom = minZoom or 0
local zoomLevel = model.zoomLevel or minZoom
zoomLevel = zoomLevel + delta * 0.5
zoomLevel = min(zoomLevel, maxZoom)
zoomLevel = max(zoomLevel, minZoom)
local _, y, z = model:GetPosition()
model:SetPosition(zoomLevel, y, z)
model.zoomLevel = zoomLevel
end
function MF:Model_OnMouseDown(model, button)
if not button or button == "LeftButton" then
model.mouseDown = true
model.rotationCursorStart = GetCursorPosition()
end
end
function MF:Model_OnMouseUp(model, button)
if not button or button == "LeftButton" then
model.mouseDown = false
end
end
function MF:Model_OnUpdate(frame, elapsedTime, rotationsPerSecond)
if not rotationsPerSecond then
rotationsPerSecond = ROTATIONS_PER_SECOND
end
if frame.mouseDown then
if frame.rotationCursorStart then
local cursorX = GetCursorPosition()
local diff = (cursorX - frame.rotationCursorStart) * 0.010
frame.rotationCursorStart = cursorX
frame.rotation = frame.rotation + diff
if frame.rotation < 0 then
frame.rotation = frame.rotation + (2 * PI)
end
if frame.rotation > (2 * PI) then
frame.rotation = frame.rotation - (2 * PI)
end
frame:SetRotation(frame.rotation, false)
end
elseif frame.panning then
local modelScale = frame:GetModelScale()
local cursorX, cursorY = GetCursorPosition()
local scale = UIParent:GetEffectiveScale()
ModelPanningFrame:Point("BOTTOMLEFT", cursorX / scale - 16, cursorY / scale - 16) -- half the texture size to center it on the cursor
-- settings
local settings = modelSettings[playerRaceSex]
local zoom = 1 + (frame.zoomLevel or 0)
-- Panning should require roughly the same mouse movement regardless of zoom level so the model moves at the same rate as the cursor
-- This formula more or less works for all zoom levels, found via trial and error
local transformationRatio = settings.panValue * 2 ^ (zoom * 1.25) * scale / modelScale
local dx = (cursorX - frame.cursorX) / transformationRatio
local dy = (cursorY - frame.cursorY) / transformationRatio
local cameraY = frame.cameraY + dx
local cameraZ = frame.cameraZ + dy
-- bounds
scale = scale * modelScale
local maxCameraY = settings.panMaxRight * zoom * scale
cameraY = min(cameraY, maxCameraY)
local minCameraY = settings.panMaxLeft * zoom * scale
cameraY = max(cameraY, minCameraY)
local maxCameraZ = settings.panMaxTop * zoom * scale
cameraZ = min(cameraZ, maxCameraZ)
local minCameraZ = settings.panMaxBottom * zoom * scale
cameraZ = max(cameraZ, minCameraZ)
frame:SetPosition(frame.cameraX, cameraY, cameraZ)
end
local leftButton, rightButton
if frame.controlFrame then
leftButton = frame.controlFrame.rotateLeftButton
rightButton = frame.controlFrame.rotateRightButton
else
leftButton = frame:GetName() and _G[frame:GetName().."RotateLeftButton"]
rightButton = frame:GetName() and _G[frame:GetName().."RotateRightButton"]
end
if leftButton and leftButton:GetButtonState() == "PUSHED" then
frame.rotation = frame.rotation + (elapsedTime * 2 * PI * rotationsPerSecond)
if frame.rotation < 0 then
frame.rotation = frame.rotation + (2 * PI)
end
elseif rightButton and rightButton:GetButtonState() == "PUSHED" then
frame.rotation = frame.rotation - (elapsedTime * 2 * PI * rotationsPerSecond)
if frame.rotation > (2 * PI) then
frame.rotation = frame.rotation - (2 * PI)
end
end
frame:SetRotation(frame.rotation)
end
function MF:Model_Reset(model)
model.rotation = 0.61
model:SetRotation(model.rotation)
model.zoomLevel = 0
model:SetPosition(0, 0, 0)
end
function MF:Model_StartPanning(model, usePanningFrame)
if usePanningFrame then
ModelPanningFrame.model = model
ModelPanningFrame:Show()
end
model.panning = true
local cameraX, cameraY, cameraZ = model:GetPosition()
model.cameraX = cameraX
model.cameraY = cameraY
model.cameraZ = cameraZ
local cursorX, cursorY = GetCursorPosition()
model.cursorX = cursorX
model.cursorY = cursorY
end
function MF:Model_StopPanning(model)
model.panning = false
ModelPanningFrame:Hide()
end
function MF:ModelControlButton_OnMouseDown(model)
model.icon:Point("CENTER", 1, -1)
model:GetParent().buttonDown = model
end
function MF:ModelControlButton_OnMouseUp(model)
model.icon:SetPoint("CENTER")
model:GetParent().buttonDown = nil
end
function MF:ADDON_LOADED(event, addon)
if addon == "Blizzard_InspectUI" then
InspectModelFrame:EnableMouse(true)
InspectModelFrame:EnableMouseWheel(true)
InspectModelRotateLeftButton:Kill()
InspectModelRotateRightButton:Kill()
self:ModelWithControls(InspectModelFrame)
elseif addon == "Blizzard_AuctionUI" then
AuctionDressUpModel:EnableMouse(true)
AuctionDressUpModel:EnableMouseWheel(true)
AuctionDressUpModelRotateLeftButton:Kill()
AuctionDressUpModelRotateRightButton:Kill()
self:ModelWithControls(AuctionDressUpModel)
end
end
function MF:Initialize()
for i = 1, #modelFrames do
local model = _G[modelFrames[i]]
model:EnableMouse(true)
model:EnableMouseWheel(true)
_G[modelFrames[i].."RotateLeftButton"]:Kill()
_G[modelFrames[i].."RotateRightButton"]:Kill()
self:ModelWithControls(model)
end
local modelPanning = CreateFrame("Frame", "ModelPanningFrame", UIParent)
modelPanning:SetFrameStrata("DIALOG")
modelPanning:Hide()
modelPanning:Size(32, 32)
modelPanning.texture = modelPanning:CreateTexture(nil, "ARTWORK")
modelPanning.texture:SetTexture("Interface\\AddOns\\ElvUI_Enhanced\\Media\\Textures\\UI-Cursor-Move")
modelPanning.texture:SetAllPoints()
self:RegisterEvent("ADDON_LOADED")
end
local function InitializeCallback()
MF:Initialize()
end
E:RegisterModule(MF:GetName(), InitializeCallback)