You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

302 lines
9.5 KiB

local sqrt = math.sqrt;
local pow = math.pow;
local floor = math.floor;
local function outQuart(t, b, e, d)
t = t / d - 1;
return (b - e) * (pow(t, 4) - 1) + b
end
local GetCursorPosition = GetCursorPosition;
local TEXTURE_PATH_PREFIX = "Interface\\AddOns\\Narcissus\\Art\\Modules\\PhotoMode\\ModelControl\\";
local CAP_OFFSET = 48;
local MAX_OFFSET = 12;
local curveK = MAX_OFFSET/CAP_OFFSET^2;
local ThumbResetter = CreateFrame("Frame");
ThumbResetter.t= 0;
ThumbResetter.duration = 0.5;
ThumbResetter:Hide();
ThumbResetter:SetScript("OnUpdate", function(self, elapsed)
self.t = self.t + elapsed;
local offsetX = outQuart(self.t, self.fromX, self.toX, self.duration);
local alpha = outQuart(self.t, self.fromAlpha, 0, self.duration);
if self.t >= self.duration then
offsetX = self.toX;
alpha = 0;
self:Hide();
end
self.object:SetPoint("CENTER", self.widget, "LEFT", offsetX, 0);
self.fluid:SetAlpha(alpha);
end);
function ThumbResetter:ResetThumb(widget)
if self:IsShown() then
--self.object:SetPoint("CENTER", self.widget, "LEFT", self.toX, 0);
--self.Fluid:SetAlpha(0);
self:Hide();
end
local Thumb = widget.OverlayFrame.Thumb;
local _, _, _, fromX = Thumb:GetPoint();
local barWidth = widget:GetWidth();
local toX, duration;
if fromX < 0 then
toX = 0;
duration = sqrt(-fromX/MAX_OFFSET)
elseif fromX > barWidth then
toX = barWidth;
duration = sqrt((fromX - barWidth )/MAX_OFFSET);
end
if duration and duration > 0 then
self.duration = 0.65*duration;
self.widget = widget;
self.object = Thumb;
self.fluid = widget.Fluid;
self.fromAlpha = widget.Fluid:GetAlpha();
self.fromX = fromX;
self.toX = toX;
self.t = 0;
self:Show();
end
end
local function GetCapDiff(x)
local r = (CAP_OFFSET - x) + CAP_OFFSET;
local y = 0;
local ratio = 0;
if x >= 0 then
if x > CAP_OFFSET then
x = CAP_OFFSET;
end
y = curveK * (CAP_OFFSET^2 - (x - CAP_OFFSET)^2);
ratio = y / MAX_OFFSET;
elseif x < 0 then
if x < -CAP_OFFSET then
x = -CAP_OFFSET;
end
y = curveK * (-CAP_OFFSET^2 + (x + CAP_OFFSET)^2);
ratio = -y / MAX_OFFSET;
end
return y, ratio
end
local function CreateMarks(widget, visualRange, maxRange, gap)
if not widget.marks then
widget.marks = {};
end
local barWidth = widget:GetWidth();
widget.visualRange = visualRange;
widget.maxRange = maxRange;
widget.maxOffset = barWidth * (maxRange / visualRange - 1);
local valuePerX = visualRange / barWidth;
widget.valuePerX = valuePerX;
local visualGap = gap / valuePerX;
local mark;
local numMark = floor(maxRange/gap);
for i = 1, numMark do
mark = widget.marks[i];
if not mark then
mark = CreateFrame("Frame", nil, widget.ClipFrame, "NarciSliderMarkerTemplate");
tinsert(widget.marks, mark);
end
mark:Show();
mark:ClearAllPoints();
mark:SetPoint("CENTER", widget.Reference, "LEFT", i * visualGap, 0);
if i ~= numMark then
mark.Label:SetText(i * gap);
end
end
for i = numMark + 1, #widget.marks do
widget.marks[i]:Hide();
end
end
NarciUncappedSliderMixin = {};
function NarciUncappedSliderMixin:OnLoad()
if self.iconName then
self.Icon:SetTexture(TEXTURE_PATH_PREFIX.."Icon".. self.iconName);
end
self.isDragging = false;
self.barOffset = 0;
CreateMarks(self, 2000, 10000, 1000);
self.isInBound = false;
self.Fluid:SetVertexColor(0.82, 0, 0);
end
function NarciUncappedSliderMixin:OnEnter()
self.OverlayFrame.ThumbHighlight:Show();
end
function NarciUncappedSliderMixin:OnLeave()
if not self.isDragging then
self.OverlayFrame.ThumbHighlight:Hide();
end
end
function NarciUncappedSliderMixin:OnMouseDown(button)
self.isDragging = true;
self.scale = self:GetEffectiveScale();
self.capLeft = self:GetLeft();
self.capRight = self:GetRight();
self:SetScript("OnUpdate", function(self, elapsed)
local diff = self:UpdateThumbPosition();
self.barOffset = self.barOffset + diff * 12 * elapsed;
if self.barOffset < 0 then
self.barOffset = 0;
if self.isInBound then
self.isInBound = false;
self.Fluid:SetVertexColor(0.82, 0, 0);
end
elseif self.barOffset > self.maxOffset then
self.barOffset = self.maxOffset;
if self.isInBound then
self.isInBound = false;
self.Fluid:SetVertexColor(0.82, 0, 0);
end
else
if not self.isInBound then
self.isInBound = true;
self.Fluid:SetVertexColor(0.25, 0.78, 0.92);
end
end
self:UpdateEffectiveOffset();
end)
end
function NarciUncappedSliderMixin:OnMouseUp()
self.isDragging = false;
self:SetScript("OnUpdate", nil);
if not self:IsMouseOver() then
self:OnLeave();
end
ThumbResetter:ResetThumb(self);
end
function NarciUncappedSliderMixin:UpdateThumbPosition()
local cursorX, _ = GetCursorPosition() / self.scale;
local diff = 0;
local fluidAlpha;
if cursorX > self.capRight then
diff = cursorX - self.capRight;
cursorX = self.capRight;
elseif cursorX < self.capLeft then
diff = cursorX - self.capLeft;
cursorX = self.capLeft;
end
--Damping
if diff == 0 then
self.isMovingRight = false;
self.isMovingLeft = false;
fluidAlpha = 0;
else
diff, fluidAlpha = GetCapDiff(diff);
if diff > 0 then
if not self.isMovingRight then
self.isMovingRight = true;
self.isMovingLeft = false;
self.Fluid:ClearAllPoints();
self.Fluid:SetPoint("RIGHT", self.OverlayFrame.Thumb, "CENTER", 0, 0);
self.Fluid:SetTexCoord(0.25, 0, 0.5, 0.5625);
end
else
if not self.isMovingLeft then
self.isMovingLeft = true;
self.isMovingRight = false;
self.Fluid:ClearAllPoints();
self.Fluid:SetPoint("LEFT", self.OverlayFrame.Thumb, "CENTER", 0, 0);
self.Fluid:SetTexCoord(0, 0.25, 0.5, 0.5625);
end
end
end
local thumbOffset = cursorX - self.capLeft;
self.thumbOffset = thumbOffset;
local offset = thumbOffset + diff;
self.OverlayFrame.Thumb:SetPoint("CENTER", self, "LEFT", offset, 0);
self.Fluid:SetAlpha(sqrt(fluidAlpha));
return diff
end
function NarciUncappedSliderMixin:UpdateEffectiveOffset(forcedRefresh)
self.Reference:SetPoint("CENTER", self, "LEFT", -self.barOffset, 0);
local alpha = (10 - self.barOffset)/10;
if alpha < 0 then
alpha = 0;
end
self.Hedge:SetAlpha(alpha);
self.Icon:SetAlpha(alpha);
local effectiveValue = floor( (self.barOffset + self.thumbOffset)* self.valuePerX + 0.5);
if effectiveValue ~= self.effectiveValue or forcedRefresh then
self.effectiveValue = effectiveValue;
self.OverlayFrame.ValueText:SetText(effectiveValue);
if self.onValueChangedFunc then
self.onValueChangedFunc(effectiveValue);
end
if self.barOffset < 10 then
local alpha = self.barOffset/10;
self.ZeroButton:SetAlpha(alpha);
if alpha < 0.05 then
self.ZeroButton:Hide();
self.showZeroButton = false;
end
else
self.ZeroButton:Show();
if not self.showZeroButton then
self.showZeroButton = true;
self.ZeroButton.flyIn:Play();
end
end
end
end
function NarciUncappedSliderMixin:SetValue(value, forcedRefresh)
local maxRange = self.maxRange;
if value > maxRange then
value = maxRange;
elseif value < 0 then
value = 0;
end
local thumbOffset;
local visualRange = self.visualRange;
local barWidth = self:GetWidth();
if value > visualRange then
if value > (maxRange - visualRange) then
thumbOffset = barWidth * (visualRange - maxRange + value) / visualRange;
else
thumbOffset = barWidth / 2;
end
elseif value < visualRange then
thumbOffset = barWidth * value / visualRange;
else
thumbOffset = barWidth * value / (3 * visualRange);
end
self.barOffset = value / self.valuePerX - thumbOffset;
self.thumbOffset = thumbOffset;
self:UpdateEffectiveOffset(forcedRefresh);
self.OverlayFrame.Thumb:SetPoint("CENTER", self, "LEFT", thumbOffset, 0);
self.Fluid:SetAlpha(0);
--print(self.effectiveValue)
end
function NarciUncappedSliderMixin:ResetValueVisual()
self.OverlayFrame.Thumb:SetPoint("CENTER", self, "LEFT", 0, 0);
self.Fluid:SetAlpha(0);
self.thumbOffset = 0;
self.barOffset = 0;
self.ZeroButton:Hide();
self.showZeroButton = false;
self.effectiveValue = 0;
self.Hedge:SetAlpha(1);
self.Icon:SetAlpha(1);
self.Reference:SetPoint("CENTER", self, "LEFT", 0, 0);
end