267 lines
9.5 KiB
Lua
267 lines
9.5 KiB
Lua
-- ------------------------------------------------------------------------------ --
|
|
-- TradeSkillMaster --
|
|
-- https://tradeskillmaster.com --
|
|
-- All Rights Reserved - Detailed license information included with addon. --
|
|
-- ------------------------------------------------------------------------------ --
|
|
|
|
--- Slider UI Element Class.
|
|
-- A slider allows for selecting a numerical range. It is a subclass of the @{Element} class.
|
|
-- @classmod Slider
|
|
|
|
local _, TSM = ...
|
|
local Math = TSM.Include("Util.Math")
|
|
local NineSlice = TSM.Include("Util.NineSlice")
|
|
local ScriptWrapper = TSM.Include("Util.ScriptWrapper")
|
|
local Theme = TSM.Include("Util.Theme")
|
|
local Slider = TSM.Include("LibTSMClass").DefineClass("Slider", TSM.UI.Element)
|
|
local UIElements = TSM.Include("UI.UIElements")
|
|
UIElements.Register(Slider)
|
|
TSM.UI.Slider = Slider
|
|
local private = {}
|
|
local THUMB_WIDTH = 8
|
|
local INPUT_WIDTH = 50
|
|
local INPUT_AREA_SPACE = 128
|
|
|
|
|
|
|
|
-- ============================================================================
|
|
-- Public Class Methods
|
|
-- ============================================================================
|
|
|
|
function Slider.__init(self)
|
|
local frame = UIElements.CreateFrame(self, "Frame")
|
|
frame:EnableMouse(true)
|
|
ScriptWrapper.Set(frame, "OnMouseDown", private.FrameOnMouseDown, self)
|
|
ScriptWrapper.Set(frame, "OnMouseUp", private.FrameOnMouseUp, self)
|
|
ScriptWrapper.Set(frame, "OnUpdate", private.FrameOnUpdate, self)
|
|
|
|
self.__super:__init(frame)
|
|
|
|
-- create the textures
|
|
frame.barTexture = frame:CreateTexture(nil, "BACKGROUND", nil, 1)
|
|
frame.activeBarTexture = frame:CreateTexture(nil, "BACKGROUND", nil, 2)
|
|
frame.thumbTextureLeft = frame:CreateTexture(nil, "ARTWORK")
|
|
frame.thumbTextureRight = frame:CreateTexture(nil, "ARTWORK")
|
|
|
|
frame.inputLeft = CreateFrame("EditBox", nil, frame, nil)
|
|
frame.inputLeft:SetJustifyH("CENTER")
|
|
frame.inputLeft:SetWidth(INPUT_WIDTH)
|
|
frame.inputLeft:SetHeight(24)
|
|
frame.inputLeft:SetAutoFocus(false)
|
|
frame.inputLeft:SetNumeric(true)
|
|
ScriptWrapper.Set(frame.inputLeft, "OnEscapePressed", private.InputOnEscapePressed)
|
|
ScriptWrapper.Set(frame.inputLeft, "OnEnterPressed", private.LeftInputOnEnterPressed, self)
|
|
|
|
|
|
frame.dash = UIElements.CreateFontString(self, frame)
|
|
frame.dash:SetJustifyH("CENTER")
|
|
frame.dash:SetJustifyV("MIDDLE")
|
|
frame.dash:SetWidth(12)
|
|
|
|
frame.inputRight = CreateFrame("EditBox", nil, frame, nil)
|
|
frame.inputRight:SetJustifyH("CENTER")
|
|
frame.inputRight:SetWidth(INPUT_WIDTH)
|
|
frame.inputRight:SetHeight(24)
|
|
frame.inputRight:SetNumeric(true)
|
|
frame.inputRight:SetAutoFocus(false)
|
|
ScriptWrapper.Set(frame.inputRight, "OnEscapePressed", private.InputOnEscapePressed)
|
|
ScriptWrapper.Set(frame.inputRight, "OnEnterPressed", private.RightInputOnEnterPressed, self)
|
|
|
|
self._inputLeftNineSlice = NineSlice.New(frame.inputLeft)
|
|
self._inputRightNineSlice = NineSlice.New(frame.inputRight)
|
|
self._leftValue = nil
|
|
self._rightValue = nil
|
|
self._minValue = nil
|
|
self._maxValue = nil
|
|
self._dragging = nil
|
|
end
|
|
|
|
function Slider.Release(self)
|
|
self._leftValue = nil
|
|
self._rightValue = nil
|
|
self._minValue = nil
|
|
self._maxValue = nil
|
|
self._dragging = nil
|
|
self.__super:Release()
|
|
end
|
|
|
|
--- Set the extends of the possible range.
|
|
-- @tparam Slider self The slider object
|
|
-- @tparam number minValue The minimum value
|
|
-- @tparam number maxValue The maxmimum value
|
|
-- @treturn Slider The slider object
|
|
function Slider.SetRange(self, minValue, maxValue)
|
|
self._minValue = minValue
|
|
self._maxValue = maxValue
|
|
self._leftValue = minValue
|
|
self._rightValue = maxValue
|
|
return self
|
|
end
|
|
|
|
--- Sets the current value.
|
|
-- @tparam Slider self The slider object
|
|
-- @tparam number leftValue The lower end of the range
|
|
-- @tparam number rightValue The upper end of the range
|
|
-- @treturn Slider The slider object
|
|
function Slider.SetValue(self, leftValue, rightValue)
|
|
assert(leftValue < rightValue and leftValue >= self._minValue and rightValue <= self._maxValue)
|
|
self._leftValue = leftValue
|
|
self._rightValue = rightValue
|
|
return self
|
|
end
|
|
|
|
--- Gets the current value
|
|
-- @tparam Slider self The slider object
|
|
-- @treturn number The lower end of the range
|
|
-- @treturn number The upper end of the range
|
|
function Slider.GetValue(self)
|
|
return self._leftValue, self._rightValue
|
|
end
|
|
|
|
function Slider.Draw(self)
|
|
self.__super:Draw()
|
|
local frame = self:_GetBaseFrame()
|
|
|
|
local inputColor = Theme.GetColor("ACTIVE_BG")
|
|
self._inputLeftNineSlice:SetStyle("rounded")
|
|
self._inputRightNineSlice:SetStyle("rounded")
|
|
self._inputLeftNineSlice:SetVertexColor(inputColor:GetFractionalRGBA())
|
|
self._inputRightNineSlice:SetVertexColor(inputColor:GetFractionalRGBA())
|
|
|
|
local sliderHeight = self:_GetDimension("HEIGHT") / 2
|
|
local width = self:_GetDimension("WIDTH") - INPUT_AREA_SPACE
|
|
local leftPos = Math.Scale(self._leftValue, self._minValue, self._maxValue, 0, width - THUMB_WIDTH)
|
|
local rightPos = Math.Scale(self._rightValue, self._minValue, self._maxValue, 0, width - THUMB_WIDTH)
|
|
local fontPath, fontHeight = Theme.GetFont("BODY_BODY1"):GetWowFont()
|
|
local textColor = Theme.GetColor("TEXT")
|
|
|
|
-- wow renders the font slightly bigger than the designs would indicate, so subtract one from the font height
|
|
frame.inputRight:SetFont(fontPath, fontHeight)
|
|
frame.inputRight:SetTextColor(textColor:GetFractionalRGBA())
|
|
frame.inputRight:SetPoint("RIGHT", 0)
|
|
frame.inputRight:SetNumber(self._rightValue)
|
|
|
|
frame.dash:SetFont(fontPath, fontHeight)
|
|
frame.dash:SetTextColor(textColor:GetFractionalRGBA())
|
|
frame.dash:SetText("-")
|
|
frame.dash:SetPoint("RIGHT", frame.inputRight, "LEFT", 0, 0)
|
|
|
|
-- wow renders the font slightly bigger than the designs would indicate, so subtract one from the font height
|
|
frame.inputLeft:SetFont(fontPath, fontHeight)
|
|
frame.inputLeft:SetTextColor(textColor:GetFractionalRGBA())
|
|
frame.inputLeft:SetPoint("RIGHT", frame.dash, "LEFT", 0)
|
|
frame.inputLeft:SetNumber(self._leftValue)
|
|
|
|
frame.barTexture:ClearAllPoints()
|
|
frame.barTexture:SetPoint("LEFT", 0, 0)
|
|
frame.barTexture:SetPoint("RIGHT", frame.inputLeft, "LEFT", -16, 0)
|
|
frame.barTexture:SetHeight(sliderHeight / 3)
|
|
frame.barTexture:SetColorTexture(Theme.GetColor("FRAME_BG"):GetFractionalRGBA())
|
|
|
|
TSM.UI.TexturePacks.SetTextureAndSize(frame.thumbTextureLeft, "iconPack.14x14/Circle")
|
|
frame.thumbTextureLeft:SetPoint("LEFT", frame.barTexture, leftPos, 0)
|
|
|
|
TSM.UI.TexturePacks.SetTextureAndSize(frame.thumbTextureRight, "iconPack.14x14/Circle")
|
|
frame.thumbTextureRight:SetPoint("LEFT", frame.barTexture, rightPos, 0)
|
|
|
|
frame.activeBarTexture:SetPoint("LEFT", frame.thumbTextureLeft, "CENTER")
|
|
frame.activeBarTexture:SetPoint("RIGHT", frame.thumbTextureRight, "CENTER")
|
|
frame.activeBarTexture:SetHeight(sliderHeight / 3)
|
|
frame.activeBarTexture:SetColorTexture(Theme.GetColor("TEXT"):GetFractionalRGBA())
|
|
end
|
|
|
|
|
|
|
|
-- ============================================================================
|
|
-- Private Class Methods
|
|
-- ============================================================================
|
|
|
|
function Slider._GetCursorPositionValue(self)
|
|
local frame = self:_GetBaseFrame()
|
|
local x = GetCursorPosition() / frame:GetEffectiveScale()
|
|
local left = frame:GetLeft() + THUMB_WIDTH / 2
|
|
local right = frame:GetRight() - THUMB_WIDTH - INPUT_AREA_SPACE * 2 / 2
|
|
x = min(max(x, left), right)
|
|
local value = Math.Scale(x, left, right, self._minValue, self._maxValue)
|
|
return min(max(Math.Round(value), self._minValue), self._maxValue)
|
|
end
|
|
|
|
function Slider._UpdateLeftValue(self, value)
|
|
local newValue = max(min(value, self._rightValue), self._minValue)
|
|
if newValue == self._leftValue then
|
|
return
|
|
end
|
|
self._leftValue = newValue
|
|
self:Draw()
|
|
end
|
|
|
|
function Slider._UpdateRightValue(self, value)
|
|
local newValue = min(max(value, self._leftValue), self._maxValue)
|
|
if newValue == self._rightValue then
|
|
return
|
|
end
|
|
self._rightValue = newValue
|
|
self:Draw()
|
|
end
|
|
|
|
|
|
|
|
-- ============================================================================
|
|
-- Local Script Handlers
|
|
-- ============================================================================
|
|
|
|
function private.InputOnEscapePressed(input)
|
|
input:ClearFocus()
|
|
end
|
|
|
|
function private.LeftInputOnEnterPressed(self)
|
|
local input = self:_GetBaseFrame().inputLeft
|
|
self:_UpdateLeftValue(input:GetNumber())
|
|
end
|
|
|
|
function private.RightInputOnEnterPressed(self)
|
|
local input = self:_GetBaseFrame().inputRight
|
|
self:_UpdateRightValue(input:GetNumber())
|
|
end
|
|
|
|
function private.FrameOnMouseDown(self)
|
|
local frame = self:_GetBaseFrame()
|
|
frame.inputLeft:ClearFocus()
|
|
frame.inputRight:ClearFocus()
|
|
local value = self:_GetCursorPositionValue()
|
|
local leftDiff = abs(value - self._leftValue)
|
|
local rightDiff = abs(value - self._rightValue)
|
|
if value < self._leftValue then
|
|
-- clicked to the left of the left thumb, so drag that
|
|
self._dragging = "left"
|
|
elseif value > self._rightValue then
|
|
-- clicked to the right of the right thumb, so drag that
|
|
self._dragging = "right"
|
|
elseif self._leftValue == self._rightValue then
|
|
-- just ignore this click since they clicked on both thumbs
|
|
elseif leftDiff < rightDiff then
|
|
-- clicked closer to the left thumb, so drag that
|
|
self._dragging = "left"
|
|
else
|
|
-- clicked closer to the right thumb (or right in the middle), so drag that
|
|
self._dragging = "right"
|
|
end
|
|
end
|
|
|
|
function private.FrameOnMouseUp(self)
|
|
self._dragging = nil
|
|
end
|
|
|
|
function private.FrameOnUpdate(self)
|
|
if not self._dragging then
|
|
return
|
|
end
|
|
if self._dragging == "left" then
|
|
self:_UpdateLeftValue(self:_GetCursorPositionValue())
|
|
elseif self._dragging == "right" then
|
|
self:_UpdateRightValue(self:_GetCursorPositionValue())
|
|
else
|
|
error("Unexpected dragging: "..tostring(self._dragging))
|
|
end
|
|
end
|