local _, T = ... local XU, ScrollBar, iSB, type = T.exUI, {}, {}, type local assert, getWidgetData, newWidgetData, setWidgetData, AddObjectMethods, CallObjectScript = XU:GetImpl() local HOLD_ACTION_DELAY, PAGE_DELAY, STEPPER_REPEAT_DELAY = 0.15, 0.25, 0.4 local MIN_ANIMATION_FRAMERATE, ANIMATION_TARGET_DURATION = 45, 0.2 local MODERN_UI = C_Texture.GetAtlasInfo("minimal-scrollbar-thumb-top") ~= nil -- LEGACY[1.14.3] local ScrollBarData, scrollBarProps = {}, { api=ScrollBar, scripts={"OnMinMaxChanged", "OnValueChanged"}, val=0, min=0, max=100, win=10, step=1, stepsPerPage=1, enabled=true, } AddObjectMethods({"ScrollBar"}, scrollBarProps) -- Public ScrollBar Widget API function ScrollBar:GetValue() local d = assert(getWidgetData(self, ScrollBarData), "Invalid object type") return d.val end function ScrollBar:SetValue(value) local d = assert(getWidgetData(self, ScrollBarData), "Invalid object type") assert(type(value) == "number", 'Syntax: ScrollBar:SetValue(value)') if d.val ~= value then iSB.SetValue(d, value, false, true) end end function ScrollBar:GetMinMaxValues() local d = assert(getWidgetData(self, ScrollBarData), "Invalid object type") return d.min, d.max end function ScrollBar:SetMinMaxValues(minValue, maxValue) local d = assert(getWidgetData(self, ScrollBarData), "Invalid object type") assert(type(minValue) == 'number' and type(maxValue) == 'number', 'Syntax: ScrollBar:SetMinMaxValues(minValue, maxValue)') if minValue == d.min and maxValue == d.max then return end d.min, d.max, d.ThumbSize = minValue, maxValue < minValue and minValue or maxValue iSB.SetValue(d, d.val, false) iSB.SetInteractionState(d, "NONE") iSB.UpdateThumbSizeAndPosition(d) CallObjectScript(d.self, "OnMinMaxChanged", minValue, maxValue) end function ScrollBar:GetWindowRange() local d = assert(getWidgetData(self, ScrollBarData), "Invalid object type") return d.win end function ScrollBar:SetWindowRange(range) local d = assert(getWidgetData(self, ScrollBarData), "Invalid object type") if d.win == range then return end assert(type(range) == 'number' and range >= 0, 'Syntax: ScrollBar:SetWindowRange(range)') d.win = range iSB.UpdateThumbPosition(d) iSB.SetInteractionState(d, "NONE") end function ScrollBar:GetValueStep() local d = assert(getWidgetData(self, ScrollBarData), "Invalid object type") return d.step end function ScrollBar:SetValueStep(step) local d = assert(getWidgetData(self, ScrollBarData), "Invalid object type") assert(type(step) == "number" and step >= 0, 'Syntax: ScrollBar:SetValueStep(step)') d.step = step end function ScrollBar:GetStepsPerPage() local d = assert(getWidgetData(self, ScrollBarData), "Invalid object type") return d.stepsPerPage end function ScrollBar:SetStepsPerPage(steps) local d = assert(getWidgetData(self, ScrollBarData), "Invalid object type") assert(type(steps) == "number" and steps >= 1, 'Syntax: ScrollBar:SetStepsPerPage(stepsPerPage)') d.stepsPerPage = steps end function ScrollBar:GetStepperButtonsShown() local d = assert(getWidgetData(self, ScrollBarData), "Invalid object type") return d.StepUp:IsShown() end function ScrollBar:SetStepperButtonsShown(shown) local d = assert(getWidgetData(self, ScrollBarData), "Invalid object type") d.StepUp:SetShown(shown) d.StepDown:SetShown(shown) local shownGap = MODERN_UI and 20 or 18 d.Track:SetPoint("TOP", 0, shown and -shownGap or -1) d.Track:SetPoint("BOTTOM", 0, shown and shownGap or 1) iSB.SetInteractionState(d, "NONE") iSB.UpdateTrackTextures(d) iSB.UpdateThumbSizeAndPosition(d) end function ScrollBar:Step(delta, allowAnimation) local d = assert(getWidgetData(self, ScrollBarData), "Invalid object type") assert(type(delta) == "number" and (allowAnimation == nil or type(allowAnimation) == "boolean"), 'Syntax: ScrollBar:Step(delta[, allowAnimation])') iSB.Step(d, delta, false, allowAnimation) end function ScrollBar:IsValueAtRest() local d = assert(getWidgetData(self, ScrollBarData), "Invalid object type") return d.animTarget == nil and d.interactionState ~= "THUMB_DRAG" end function ScrollBar:IsEnabled() local d = assert(getWidgetData(self, ScrollBarData), "Invalid object type") return d.enabled end function ScrollBar:SetEnabled(enabled) local d = assert(getWidgetData(self, ScrollBarData), "Invalid object type") enabled = not not enabled if d.enabled ~= enabled then d.enabled = enabled iSB.SetInteractionState(d, "NONE") end end function ScrollBar:Enable() return ScrollBar.SetEnabled(self, true) end function ScrollBar:Disable() return ScrollBar.SetEnabled(self, false) end function iSB.NotifyValueChanged(d, isInternalChange, onlyOnRestStart) local isAtRest = d.animTarget == nil and d.interactionState ~= "THUMB_DRAG" local wasNotAtRest = onlyOnRestStart and d.lastValueChangeNotAtRest d.lastValueChangeNotAtRest = not isAtRest if not onlyOnRestStart or (wasNotAtRest and isAtRest) then CallObjectScript(d.self, "OnValueChanged", d.val, isInternalChange) end end function iSB.SetInteractionState(d, state) local val, enabled = d.val, d.enabled d.interactionState = state d.ThumbTexN:SetShown(state ~= "THUMB_DRAG") d.ThumbTexP:SetShown(state == "THUMB_DRAG") d.Thumb:EnableMouseMotion(enabled and state ~= "THUMB_DRAG") if d.mouseDown and state ~= "THUMB_DRAG" and state ~= "TRACK_HELD" then d.mouseDown, d.mouseDownX, d.mouseDownY, d.mouseDownS, d.mouseDownV, d.mouseDownOnThumb = nil d.Track:SetScript("OnUpdate", nil) end if d.stepperHeld == d.StepUp and state ~= "STEP_UP_HELD" or d.stepperHeld == d.StepDown and state ~= "STEP_DOWN_HELD" then d.stepperHeldTime, d.stepperHeld = nil end d.StepUpH:SetShown(state ~= "STEP_UP_HELD") d.StepDownH:SetShown(state ~= "STEP_DOWN_HELD") d.StepUp:SetEnabled(enabled and val > d.min) d.StepDown:SetEnabled(enabled and val < d.max) if state ~= "ANIMATING_VALUE" and state ~= "STEP_UP_HELD" and state ~= "STEP_DOWN_HELD" then d.animStart, d.animTarget, d.animEnd, d.animDur = nil end iSB.NotifyValueChanged(d, true, true) end function iSB.SetValue(d, candValue, isInternalChange, visualUpdate, allowInteraction) local vlo, vhi, enabled = d.min, d.max, d.enabled local ov, nv = d.val, candValue < vlo and vlo or candValue > vhi and vhi or candValue d.StepUp:SetEnabled(enabled and nv > vlo) d.StepDown:SetEnabled(enabled and nv < vhi) d.val = nv if visualUpdate then iSB.UpdateThumbPosition(d) end if nv ~= ov then if visualUpdate and not allowInteraction then iSB.SetInteractionState(d, "NONE") end iSB.NotifyValueChanged(d, isInternalChange) return true end end function iSB.UpdateThumbPosition(d) local om = d.ThumbOffsetMul if not om then return iSB.UpdateThumbSizeAndPosition(d) end d.Thumb:SetPoint("TOP", 0, (d.val - d.min)*om) end function iSB.UpdateThumbSizeAndPosition(d) local vrange, urange = d.max - d.min, d.Track:GetHeight() d.Thumb:SetShown(vrange > 0) if vrange <= 0 then return end local tsz = math.max(18, d.win / (vrange + d.win) * urange) local om = (tsz-urange)/vrange if d.ThumbSize == tsz and d.ThumbOffsetMul == om then return end d.ThumbSize, d.ThumbOffsetMul = tsz, om d.Thumb:SetHeight(tsz) iSB.UpdateThumbTextures(d, tsz) iSB.UpdateThumbPosition(d) end function iSB.PerformTrackPageStep(d, isFirstStep) local thumb, _mouseX, mouseY = d.Thumb, GetCursorPosition() local dsign, delta, nv = mouseY/thumb:GetEffectiveScale() >= thumb:GetTop() and -1 or 1 if isFirstStep or dsign == d.mouseDownS then d.mouseDownS, delta = dsign, (d.step > 0 and d.step or 1)*(d.stepsPerPage > 0 and d.stepsPerPage or 1) nv = iSB.AdjustValueToStep(d, d.val + dsign * delta, dsign) return iSB.SetValue(d, nv, true, true, true) end end function iSB:OnTrackUpdate() local d, now = getWidgetData(self, ScrollBarData), GetTime() if not (d.mouseDown and d.ThumbOffsetMul) then return end local downElapsed = now - d.mouseDown local doNothing = downElapsed < HOLD_ACTION_DELAY if doNothing and d.mouseDownOnThumb then local _mx, my = GetCursorPosition() doNothing = (my-d.mouseDownY)^2 < 5 end if doNothing then elseif d.mouseDownOnThumb then local ts, _mx, my = self:GetEffectiveScale(), GetCursorPosition() local dm = (d.mouseDownY-my)/ts local nv = dm^2 > 0.5 and d.mouseDownV-dm/d.ThumbOffsetMul or d.mouseDownV iSB.SetValue(d, nv, true, true, true) elseif not iSB.IsCursorOverThumb(d) and iSB.PerformTrackPageStep(d, false) then d.mouseDown = GetTime() + PAGE_DELAY - HOLD_ACTION_DELAY end end function iSB:OnTrackMouseDown(button) local d = button == "LeftButton" and getWidgetData(self, ScrollBarData) if not (d.enabled and d.min < d.max) then return end d.mouseDown, d.mouseDownOnThumb = GetTime(), iSB.IsCursorOverThumb(d) d.mouseDownV, d.mouseDownX, d.mouseDownY = d.val, GetCursorPosition() iSB.SetInteractionState(d, d.mouseDownOnThumb and "THUMB_DRAG" or "TRACK_HELD") if not d.mouseDownOnThumb then iSB.PerformTrackPageStep(d, true) end d.Track:SetScript("OnUpdate", iSB.OnTrackUpdate) end function iSB:OnTrackMouseUp(button) local d = button == "LeftButton" and getWidgetData(self, ScrollBarData) if d.mouseDown then iSB.SetInteractionState(d, "NONE") end end function iSB:OnShow() local d = getWidgetData(self, ScrollBarData) iSB.SetInteractionState(d, "NONE") d.ThumbSize = nil iSB.UpdateThumbSizeAndPosition(d) end function iSB.Step(d, delta, isInternalChange, allowAnimation) local dsign, dstep = delta < 0 and -1 or delta > 0 and 1 or 0, d.step local delta, at = delta * (dstep > 0 and dstep or 1), allowAnimation and d.animTarget local sval = at and (delta == 0 or ((at - d.val) < 0) == (delta < 0)) and at or d.val local nv = iSB.AdjustValueToStep(d, sval + delta, dsign) if allowAnimation then iSB.SetValueAnimated(d, nv, isInternalChange, ANIMATION_TARGET_DURATION) else iSB.SetValue(d, nv, isInternalChange, true, true) end end function iSB.AdjustValueToStep(d, candValue, dsign) local dstep, lo, hi = d.step, d.min, d.max local fv = dstep > 0 and candValue % dstep or 0 dsign = dsign == 0 and (fv > 0.5 and 1 or -1) or dsign if fv > 0 then candValue = candValue - fv + (fv+fv > dstep and dstep or 0) end return candValue < lo and lo or candValue > hi and hi or candValue end function iSB.AnimateValue(d) local sv, tv, et, ad, now = d.animStart, d.animTarget, d.animEnd, d.animDur, GetTime() if not (d and sv and tv and et and ad) then elseif et <= now then d.animStart, d.animTarget, d.animEnd, d.animDur = nil iSB.SetValue(d, tv, true, true, true) else local p = 1-(et-now)/ad p = p*p*(3-2*p) iSB.SetValue(d, sv + (tv-sv)*p, true, true, true) return true end end function iSB:OnValueAnimationUpdate() local d = getWidgetData(self, ScrollBarData) if d and not iSB.AnimateValue(d) then d.animStart, d.animTarget, d.animEnd, d.animDur = nil self:SetScript("OnUpdate", nil) if d.interactionState == "ANIMATING_VALUE" then iSB.SetInteractionState(d, "NONE") else iSB.NotifyValueChanged(d, true, true) end end end function iSB.SetValueAnimated(d, nv, isInternalChange, targetDuration) local at = d.animTarget if at == nv then return elseif nv == d.val then d.animStart, d.animDur, d.animTarget, d.animEnd = nil return elseif GetFramerate() < MIN_ANIMATION_FRAMERATE and not at then return iSB.SetValue(d, nv, isInternalChange, true, true) end local et, ad, sv, now = d.animEnd, d.animDur, d.val, GetTime() local r0, r1 = et and (at-d.animStart), nv - sv if et == nil or et <= now or (r0 < 0) ~= (r1 < 0) or r1 == 0 then d.animStart, d.animDur = at or sv, targetDuration else r0, r1 = r0 < 0 and -r0 or r0, r1 < 0 and -r1 or r1 local p = 1-(et-now)/ad local s = r1*(36/144*r1-p*(1-p)*r0) local x1 = s > 0 and 0.5 - s^0.5/r1 or 0.25 local p1 = x1*x1*(3-x1-x1) local d1 = p1*(nv-sv)/(1-p1) d.animStart, d.animDur = sv-d1, targetDuration/(1-x1) end d.animTarget, d.animEnd = nv, now+targetDuration d.Track:SetScript("OnUpdate", iSB.OnValueAnimationUpdate) end function iSB:OnStepButtonDown(button) local d = button == "LeftButton" and getWidgetData(self, ScrollBarData) local isUpStep = d and self == d.StepUp if not d or (d.val == (isUpStep and d.min or d.max)) then return end iSB.Step(d, isUpStep and -1 or 1, true, true) d.stepperHeldTime, d.stepperHeld = GetTime() + STEPPER_REPEAT_DELAY, self iSB.SetInteractionState(d, isUpStep and "STEP_UP_HELD" or "STEP_DOWN_HELD") self:SetScript("OnUpdate", iSB.OnStepButtonHeld) PlaySound(SOUNDKIT.U_CHAT_SCROLL_BUTTON) end function iSB:OnStepButtonHeld() local d = getWidgetData(self:GetParent(), ScrollBarData) if not d then elseif d.stepperHeld ~= self then self:SetScript("OnUpdate", nil) elseif d.stepperHeldTime < GetTime() then iSB.OnStepButtonDown(self, "LeftButton") end end function iSB:OnStepButtonUp(button) local d = button == "LeftButton" and getWidgetData(self, ScrollBarData) if not d then return end self:SetScript("OnUpdate", nil) if d.stepperHeld == self then d.stepperHeldTime, d.stepperHeld = nil end if d.interactionState == (self == d.StepUp and "STEP_UP_HELD" or "STEP_DOWN_HELD") then iSB.SetInteractionState(d, d.animTarget and "ANIMATING_VALUE" or "NONE") end end function iSB.IsCursorOverThumb(d) local l, r, t, b = d.Thumb:GetHitRectInsets() return d.Thumb:IsMouseOver(-t, b, l, -r) end function iSB.UpdateTrackTextures(d) local bg = d.TrackBG bg[1]:SetAtlas("minimal-scrollbar-track-top", true) bg[2]:SetAtlas("!minimal-scrollbar-track-middle", true) bg[3]:SetAtlas("minimal-scrollbar-track-bottom", true) end function iSB.UpdateThumbTextures(d, tsz) local n, h, p, m = d.ThumbTexN, d.ThumbTexH, d.ThumbTexP, d.ThumbTexM tsz = tsz or d.Thumb:GetHeight() local b = tsz < 32 and "minimal-scrollbar-small-thumb-bottom" or "minimal-scrollbar-thumb-bottom" n[1]:SetAtlas("minimal-scrollbar-thumb-top", true) n[2]:SetAtlas("minimal-scrollbar-thumb-middle", true) n[3]:SetAtlas(b, true) h[1]:SetAtlas("minimal-scrollbar-thumb-top-over", true) h[2]:SetAtlas("minimal-scrollbar-thumb-middle-over", true) h[3]:SetAtlas(b.."-over", true) p[1]:SetAtlas("minimal-scrollbar-thumb-top-down", true) p[2]:SetAtlas("minimal-scrollbar-thumb-middle-down", true) p[3]:SetAtlas(b.."-down", true) m:SetTexCoord(0,1, 0, tsz < 715 and tsz/715 or 1) end function iSB:UpdateStepButtonTextures(variant) local normal, hover, pushed if variant == "TOP" then normal, hover, pushed = "minimal-scrollbar-arrow-top", "minimal-scrollbar-arrow-top-over", "minimal-scrollbar-arrow-top-down" elseif variant == "BOTTOM" then normal, hover, pushed = "minimal-scrollbar-arrow-bottom", "minimal-scrollbar-arrow-bottom-over", "minimal-scrollbar-arrow-bottom-down" else error('invalid variant') end self:GetNormalTexture():SetAtlas(normal, true) self:GetHighlightTexture():SetAtlas(hover, true) self:GetPushedTexture():SetAtlas(pushed, true) local dt = self:GetDisabledTexture() dt:SetAtlas(normal, true) dt:SetDesaturated(true) dt:SetVertexColor(0.5, 0.5, 0.5) end if not MODERN_UI then function iSB.UpdateTrackTextures(d) local bg, showStepper = d.TrackBG, d.StepUp:IsShown() local t, m, b = bg[1], bg[2], bg[3] local ct, cb = showStepper and 0 or 20, showStepper and 0 or 21 t:SetTexture("Interface/PaperDollInfoFrame/UI-Character-ScrollBar") t:SetTexCoord(2/64, 29/64, ct/256, 32/256) t:SetSize(22, 22/27*(32-ct)) m:SetTexture("Interface/PaperDollInfoFrame/UI-Character-ScrollBar") m:SetTexCoord(2/64, 29/64, 28/256, 1) b:SetTexture("Interface/PaperDollInfoFrame/UI-Character-ScrollBar") b:SetTexCoord(35/64, 62/64, 228/256, (255-cb)/256) b:SetSize(22, 22/27*(27-cb)) end function iSB.UpdateThumbTextures(d, tsz) local n, p = d.ThumbTexN, d.ThumbTexP tsz = tsz or d.Thumb:GetHeight() n[1]:SetAtlas("UI-ScrollBar-Knob-EndCap-Top", true) n[2]:SetAtlas("UI-ScrollBar-Knob-Center", true) n[3]:SetAtlas("UI-ScrollBar-Knob-EndCap-Bottom", true) p[1]:SetAtlas("UI-ScrollBar-Knob-EndCap-Top", true) p[2]:SetAtlas("UI-ScrollBar-Knob-Center", true) p[3]:SetAtlas("UI-ScrollBar-Knob-EndCap-Bottom", true) d.ThumbTexM:SetTexCoord(0, 1, 0, tsz < 1022 and tsz/1022 or 1) end function iSB:UpdateStepButtonTextures(variant) local normal, hover, pushed, disabled if variant == "TOP" then normal, hover, pushed, disabled = "Interface/Buttons/UI-ScrollBar-ScrollUpButton-Up", "Interface/Buttons/UI-ScrollBar-ScrollUpButton-Highlight", "Interface/Buttons/UI-ScrollBar-ScrollUpButton-Down", "Interface/Buttons/UI-ScrollBar-ScrollUpButton-Disabled" elseif variant == "BOTTOM" then normal, hover, pushed, disabled = "Interface/Buttons/UI-ScrollBar-ScrollDownButton-Up", "Interface/Buttons/UI-ScrollBar-ScrollDownButton-Highlight", "Interface/Buttons/UI-ScrollBar-ScrollDownButton-Down", "Interface/Buttons/UI-ScrollBar-ScrollDownButton-Disabled" else error('invalid variant') end self:SetNormalTexture(normal) self:SetHighlightTexture(hover) self:SetPushedTexture(pushed) self:SetDisabledTexture(disabled) self:GetNormalTexture():SetTexCoord(0.20, 0.80, 0.25, 0.75) self:GetHighlightTexture():SetTexCoord(0.20, 0.80, 0.25, 0.75) self:GetPushedTexture():SetTexCoord(0.20, 0.80, 0.25, 0.75) self:GetDisabledTexture():SetTexCoord(0.20, 0.80, 0.25, 0.75) self:GetHighlightTexture():SetBlendMode("ADD") self:SetSize(18, 16) end end local function createTexTrio(parent, layer, startGap, endGap, xShift, yShift) local oy, ox, a,b,c = yShift or 0, xShift or 0 for i=1,3 do c, b, a = parent:CreateTexture(nil, layer, nil, i == 2 and -1 or 0), c, b end a:SetPoint("TOP", ox, oy) c:SetPoint("BOTTOM", ox, oy) if startGap then b:SetPoint("TOP", ox, oy - startGap) b:SetPoint("BOTTOM", ox, oy + (endGap or startGap)) else b:SetPoint("TOPLEFT", a, "BOTTOMLEFT") b:SetPoint("BOTTOMRIGHT", c, "TOPRIGHT", 0, endGap and -endGap or 0) end return XU:Create("ObjectGroup", a,b,c) end local function createStepButton(parent, d, ...) local t = CreateFrame("Button", nil, parent) t:SetSize(16, 16) t:SetScript("OnMouseDown", iSB.OnStepButtonDown) t:SetScript("OnMouseUp", iSB.OnStepButtonUp) setWidgetData(t, ScrollBarData, d) t:SetPoint(...) t:SetNormalTexture('') t:SetHighlightTexture('') t:SetPushedTexture('') t:SetDisabledTexture('') local a,b,c,d = t:GetNormalTexture(), t:GetHighlightTexture(), t:GetPushedTexture(), t:GetDisabledTexture() if MODERN_UI then b:SetBlendMode('BLEND') for i=1,4 do a:ClearAllPoints() a:SetPoint("CENTER") a:SetShown(i < 3) a,b,c,d=b,c,d,a end end return t, b end local function noop() end local function CreateScrollBar(name, parent, outerTemplate, id) local f, d, t = CreateFrame("Frame", name, parent, outerTemplate, id) d = newWidgetData(f, ScrollBarData, scrollBarProps) f:SetWidth(20) t = CreateFrame("Frame", nil, f) t:SetWidth(MODERN_UI and 10 or 20) t:SetPoint("TOP", 0, MODERN_UI and -20 or -18) t:SetPoint("BOTTOM", 0, MODERN_UI and 20 or 18) t:SetScript("OnMouseDown", iSB.OnTrackMouseDown) t:SetScript("OnMouseUp", iSB.OnTrackMouseUp) t:SetScript("OnShow", iSB.OnShow) t:SetScript("OnSizeChanged", iSB.OnShow) setWidgetData(t, ScrollBarData, d) t, d.Track = CreateFrame("Frame", nil, t), t t:SetPoint("TOP", 0, -50) t:SetSize(MODERN_UI and 8 or 16, 20) if t.EnableMouseMotion == nil then -- LEGACY[1.14.3] t.EnableMouseMotion = noop end t:EnableMouseMotion(true) d.Thumb = t local sp, sx = MODERN_UI and 8 or 10, not MODERN_UI and 0.5 or 0 d.ThumbTexN = createTexTrio(t, "BACKGROUND", sp, sp, sx) d.ThumbTexH = createTexTrio(t, "HIGHLIGHT", sp, sp, sx) d.ThumbTexP = createTexTrio(t, "BACKGROUND", sp, sp, sx) d.ThumbTexM = XU:Create("ObjectGroup", d.ThumbTexN[2], d.ThumbTexH[2], d.ThumbTexP[2]) d.ThumbTexP:SetShown(false) local etw = (d.Track:GetWidth()-t:GetWidth())/2 d.Thumb:SetHitRectInsets(-etw, -etw, 0, 0) d.StepUp, d.StepUpH = createStepButton(f, d, "TOP", 0, MODERN_UI and -2 or -1) d.StepDown, d.StepDownH = createStepButton(f, d, "BOTTOM", 0, MODERN_UI and 2 or 1) iSB.UpdateStepButtonTextures(d.StepUp, "TOP") iSB.UpdateStepButtonTextures(d.StepDown, "BOTTOM") d.TrackBG = createTexTrio(d.Track, "BACKGROUND", nil, nil, nil, 1) if MODERN_UI then d.StepUp:GetPushedTexture():SetPoint("CENTER", 0, 2) d.StepDown:GetPushedTexture():SetPoint("CENTER", 0, -2) else local g, bg, t, b = d.Track:CreateTexture(nil, "BACKGROUND", nil, -2), d.TrackBG t, b, bg[4] = bg[1], bg[3], g g:SetColorTexture(0,0,0,0.35) g:SetPoint("TOPLEFT", t, 2, -1) g:SetPoint("BOTTOMRIGHT", b, -2, 1) b:SetPoint("BOTTOM", d.StepDown, 0, -1) t:SetPoint("TOP", d.StepUp, 0, 1) d.ThumbTexN:SetWidth(17) d.ThumbTexP:SetWidth(17) end iSB.UpdateTrackTextures(d) iSB.UpdateThumbTextures(d) return f end XU:RegisterFactory("ScrollBar", CreateScrollBar)