352 lines
11 KiB
Lua
352 lines
11 KiB
Lua
-- ------------------------------------------------------------------------------ --
|
|
-- TradeSkillMaster --
|
|
-- https://tradeskillmaster.com --
|
|
-- All Rights Reserved - Detailed license information included with addon. --
|
|
-- ------------------------------------------------------------------------------ --
|
|
|
|
--- Input UI Element Class.
|
|
-- The input element allows the user to enter text. It is a subclass of the @{BaseInput} class.
|
|
-- @classmod Input
|
|
|
|
local _, TSM = ...
|
|
local Theme = TSM.Include("Util.Theme")
|
|
local ScriptWrapper = TSM.Include("Util.ScriptWrapper")
|
|
local ItemLinked = TSM.Include("Service.ItemLinked")
|
|
local UIElements = TSM.Include("UI.UIElements")
|
|
local Input = TSM.Include("LibTSMClass").DefineClass("Input", TSM.UI.BaseInput)
|
|
UIElements.Register(Input)
|
|
TSM.UI.Input = Input
|
|
local private = {}
|
|
local PADDING_LEFT = 8
|
|
local PADDING_RIGHT = 8
|
|
local PADDING_TOP_BOTTOM = 4
|
|
|
|
|
|
|
|
-- ============================================================================
|
|
-- Public Class Methods
|
|
-- ============================================================================
|
|
|
|
function Input.__init(self)
|
|
local frame = UIElements.CreateFrame(self, "EditBox")
|
|
self._editBox = frame
|
|
self.__super:__init(frame)
|
|
|
|
self._hintText = UIElements.CreateFontString(self, frame)
|
|
self._hintText:SetFont(Theme.GetFont("BODY_BODY3"):GetWowFont())
|
|
self._hintText:SetJustifyH("LEFT")
|
|
self._hintText:SetJustifyV("MIDDLE")
|
|
self._hintText:SetPoint("TOPLEFT", PADDING_LEFT, 0)
|
|
self._hintText:SetPoint("BOTTOMRIGHT", -PADDING_RIGHT, 0)
|
|
|
|
self._icon = frame:CreateTexture(nil, "ARTWORK")
|
|
self._icon:SetPoint("RIGHT", -PADDING_RIGHT / 2, 0)
|
|
|
|
self._clearBtn = CreateFrame("Button", nil, frame)
|
|
self._clearBtn:SetAllPoints(self._icon)
|
|
ScriptWrapper.Set(self._clearBtn, "OnClick", private.ClearBtnOnClick, self)
|
|
|
|
self._subIcon = frame:CreateTexture(nil, "ARTWORK")
|
|
self._subIcon:SetPoint("LEFT", PADDING_LEFT / 2, 0)
|
|
TSM.UI.TexturePacks.SetTextureAndSize(self._subIcon, "iconPack.14x14/Subtract/Default")
|
|
|
|
self._subBtn = CreateFrame("Button", nil, frame)
|
|
self._subBtn:SetAllPoints(self._subIcon)
|
|
ScriptWrapper.Set(self._subBtn, "OnClick", private.SubBtnOnClick, self)
|
|
ScriptWrapper.SetPropagate(self._subBtn, "OnEnter")
|
|
ScriptWrapper.SetPropagate(self._subBtn, "OnLeave")
|
|
|
|
self._addIcon = frame:CreateTexture(nil, "ARTWORK")
|
|
self._addIcon:SetPoint("RIGHT", -PADDING_RIGHT / 2, 0)
|
|
TSM.UI.TexturePacks.SetTextureAndSize(self._addIcon, "iconPack.14x14/Add/Default")
|
|
|
|
self._addBtn = CreateFrame("Button", nil, frame)
|
|
self._addBtn:SetAllPoints(self._addIcon)
|
|
ScriptWrapper.Set(self._addBtn, "OnClick", private.AddBtnOnClick, self)
|
|
ScriptWrapper.SetPropagate(self._addBtn, "OnEnter")
|
|
ScriptWrapper.SetPropagate(self._addBtn, "OnLeave")
|
|
|
|
ScriptWrapper.Set(frame, "OnEnter", private.OnEnter, self)
|
|
ScriptWrapper.Set(frame, "OnLeave", private.OnLeave, self)
|
|
|
|
local function ItemLinkedCallback(name, link)
|
|
if self._allowItemInsert == nil or not self:IsVisible() or not self:HasFocus() then
|
|
return
|
|
end
|
|
if self._allowItemInsert == true then
|
|
self._editBox:Insert(link)
|
|
else
|
|
self._editBox:Insert(name)
|
|
end
|
|
return true
|
|
end
|
|
ItemLinked.RegisterCallback(ItemLinkedCallback, -1)
|
|
|
|
self._clearEnabled = false
|
|
self._subAddEnabled = false
|
|
self._iconTexture = nil
|
|
self._autoComplete = nil
|
|
self._allowItemInsert = nil
|
|
self._lostFocusOnButton = false
|
|
end
|
|
|
|
function Input.Release(self)
|
|
self._clearEnabled = false
|
|
self._subAddEnabled = false
|
|
self._iconTexture = nil
|
|
self._autoComplete = nil
|
|
self._allowItemInsert = nil
|
|
self._lostFocusOnButton = false
|
|
self._hintText:SetText("")
|
|
self.__super:Release()
|
|
end
|
|
|
|
--- Sets the horizontal justification of the hint text.
|
|
-- @tparam Input self The input object
|
|
-- @tparam string justifyH The horizontal justification (either "LEFT", "CENTER" or "RIGHT")
|
|
-- @treturn Input The input object
|
|
function Input.SetHintJustifyH(self, justifyH)
|
|
assert(justifyH == "LEFT" or justifyH == "CENTER" or justifyH == "RIGHT")
|
|
self._hintText:SetJustifyH(justifyH)
|
|
return self
|
|
end
|
|
|
|
--- Sets the vertical justification of the hint text.
|
|
-- @tparam Input self The input object
|
|
-- @tparam string justifyV The vertical justification (either "TOP", "MIDDLE" or "BOTTOM")
|
|
-- @treturn Input The input object
|
|
function Input.SetHintJustifyV(self, justifyV)
|
|
assert(justifyV == "TOP" or justifyV == "MIDDLE" or justifyV == "BOTTOM")
|
|
self._hintText:SetJustifyV(justifyV)
|
|
return self
|
|
end
|
|
|
|
--- Sets the auto complete table.
|
|
-- @tparam Input self The input object
|
|
-- @tparam table tbl A list of strings to auto-complete to
|
|
-- @treturn Input The input object
|
|
function Input.SetAutoComplete(self, tbl)
|
|
assert(type(tbl) == "table")
|
|
self._autoComplete = tbl
|
|
return self
|
|
end
|
|
|
|
--- Sets the hint text.
|
|
-- The hint text is shown when there's no other text in the input.
|
|
-- @tparam Input self The input object
|
|
-- @tparam string text The hint text
|
|
-- @treturn Input The input object
|
|
function Input.SetHintText(self, text)
|
|
self._hintText:SetText(text)
|
|
return self
|
|
end
|
|
|
|
--- Sets whether or not the clear button is enabled.
|
|
-- @tparam Input self The input object
|
|
-- @tparam boolean enabled Whether or not the clear button is enabled
|
|
-- @treturn Input The input object
|
|
function Input.SetClearButtonEnabled(self, enabled)
|
|
assert(type(enabled) == "boolean")
|
|
assert(not self._subAddEnabled)
|
|
self._clearEnabled = enabled
|
|
return self
|
|
end
|
|
|
|
--- Sets whether or not the sub/add buttons are enabled.
|
|
-- @tparam Input self The input object
|
|
-- @tparam boolean enabled Whether or not the sub/add buttons are enabled
|
|
-- @treturn Input The input object
|
|
function Input.SetSubAddEnabled(self, enabled)
|
|
assert(type(enabled) == "boolean")
|
|
assert(not self._clearEnabled and not self._iconTexture)
|
|
self._subAddEnabled = enabled
|
|
return self
|
|
end
|
|
|
|
--- Sets the icon texture.
|
|
-- @tparam Input self The input object
|
|
-- @tparam[opt=nil] string iconTexture The texture string to use for the icon texture
|
|
-- @treturn Input The input object
|
|
function Input.SetIconTexture(self, iconTexture)
|
|
assert(iconTexture == nil or TSM.UI.TexturePacks.IsValid(iconTexture))
|
|
assert(not self._subAddEnabled)
|
|
self._iconTexture = iconTexture
|
|
return self
|
|
end
|
|
|
|
--- Allows inserting an item into the input by linking it while the input has focus.
|
|
-- @tparam Input self The input object
|
|
-- @tparam[opt=false] boolean insertLink Insert the link instead of the item name
|
|
-- @treturn Input The input object
|
|
function Input.AllowItemInsert(self, insertLink)
|
|
assert(insertLink == true or insertLink == false or insertLink == nil)
|
|
self._allowItemInsert = insertLink or false
|
|
return self
|
|
end
|
|
|
|
function Input.Draw(self)
|
|
self.__super:Draw()
|
|
self:_UpdateIconsForValue(self._value)
|
|
end
|
|
|
|
|
|
|
|
-- ============================================================================
|
|
-- Private Class Methods
|
|
-- ============================================================================
|
|
|
|
function Input._GetHintTextColor(self)
|
|
local color = Theme.GetColor(self._disabled and "PRIMARY_BG_ALT" or self._backgroundColor)
|
|
if color:IsLight() then
|
|
return self:_GetTextColor("+HOVER")
|
|
else
|
|
return self:_GetTextColor("-HOVER")
|
|
end
|
|
end
|
|
|
|
function Input._UpdateIconsForValue(self, value)
|
|
local frame = self:_GetBaseFrame()
|
|
local leftPadding, rightPadding = PADDING_LEFT, PADDING_RIGHT
|
|
|
|
-- set the hint text
|
|
if value == "" and self._hintText:GetText() ~= "" then
|
|
self._hintText:SetFont(Theme.GetFont(self._font):GetWowFont())
|
|
self._hintText:SetTextColor(self:_GetHintTextColor():GetFractionalRGBA())
|
|
self._hintText:Show()
|
|
else
|
|
self._hintText:Hide()
|
|
end
|
|
|
|
local showSubAdd = self._subAddEnabled and (frame:IsMouseOver() or frame:HasFocus())
|
|
if showSubAdd then
|
|
self._subIcon:Show()
|
|
self._subBtn:Show()
|
|
self._addIcon:Show()
|
|
self._addBtn:Show()
|
|
else
|
|
self._subIcon:Hide()
|
|
self._subBtn:Hide()
|
|
self._addIcon:Hide()
|
|
self._addBtn:Hide()
|
|
end
|
|
|
|
-- set the icon
|
|
local iconTexture = nil
|
|
if self._clearEnabled and value ~= "" then
|
|
self._clearBtn:Show()
|
|
iconTexture = TSM.UI.TexturePacks.GetColoredKey("iconPack.18x18/Close/Default", self:_GetTextColor())
|
|
else
|
|
self._clearBtn:Hide()
|
|
iconTexture = not frame:HasFocus() and self._iconTexture and TSM.UI.TexturePacks.GetColoredKey(self._iconTexture, self:_GetTextColor()) or nil
|
|
end
|
|
if iconTexture then
|
|
assert(not showSubAdd)
|
|
self._icon:Show()
|
|
TSM.UI.TexturePacks.SetTextureAndSize(self._icon, iconTexture)
|
|
rightPadding = rightPadding + TSM.UI.TexturePacks.GetWidth(iconTexture)
|
|
else
|
|
self._icon:Hide()
|
|
end
|
|
frame:SetTextInsets(leftPadding, rightPadding, PADDING_TOP_BOTTOM, PADDING_TOP_BOTTOM)
|
|
-- for some reason the text insets don't take effect right away, so on the next frame, we call GetTextInsets() which seems to fix things
|
|
ScriptWrapper.Set(frame, "OnUpdate", private.OnUpdate, self)
|
|
end
|
|
|
|
function Input._OnTextChanged(self, value)
|
|
self:_UpdateIconsForValue(value)
|
|
end
|
|
|
|
function Input._ShouldKeepFocus(self)
|
|
if not IsMouseButtonDown("LeftButton") then
|
|
return false
|
|
end
|
|
if self._clearBtn:IsVisible() and self._clearBtn:IsMouseOver() then
|
|
return true
|
|
elseif self._subBtn:IsVisible() and self._subBtn:IsMouseOver() then
|
|
return true
|
|
elseif self._addBtn:IsVisible() and self._addBtn:IsMouseOver() then
|
|
return true
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
|
|
|
|
|
|
-- ============================================================================
|
|
-- Private Class Methods
|
|
-- ============================================================================
|
|
|
|
function Input._OnChar(self, c)
|
|
self.__super:_OnChar(c)
|
|
if not self._autoComplete then
|
|
return
|
|
end
|
|
local frame = self:_GetBaseFrame()
|
|
local text = frame:GetText()
|
|
local match = nil
|
|
for _, k in ipairs(self._autoComplete) do
|
|
local start, ending = strfind(strlower(k), strlower(text), 1, true)
|
|
if start == 1 and ending and ending == #text then
|
|
match = k
|
|
break
|
|
end
|
|
end
|
|
if match and not IsControlKeyDown() then
|
|
local compStart = #text
|
|
frame:SetText(match)
|
|
self:HighlightText(compStart, #match)
|
|
frame:GetScript("OnTextChanged")(frame, true)
|
|
end
|
|
end
|
|
|
|
|
|
|
|
-- ============================================================================
|
|
-- Local Script Handlers
|
|
-- ============================================================================
|
|
|
|
function private.OnUpdate(self)
|
|
local frame = self:_GetBaseFrame()
|
|
ScriptWrapper.Clear(frame, "OnUpdate")
|
|
frame:GetTextInsets()
|
|
end
|
|
|
|
function private.ClearBtnOnClick(self)
|
|
assert(self:_SetValueHelper(""))
|
|
self._escValue = ""
|
|
self._editBox:SetText(self._value)
|
|
self:Draw()
|
|
end
|
|
|
|
function private.SubBtnOnClick(self)
|
|
local minVal = self._validateContext and strsplit(":", self._validateContext)
|
|
local value = tostring(max(tonumber(self:GetValue()) - (IsShiftKeyDown() and 10 or 1), minVal or -math.huge))
|
|
if self:_SetValueHelper(value) then
|
|
self._escValue = self._value
|
|
self:_GetBaseFrame():SetText(value)
|
|
self:_UpdateIconsForValue(value)
|
|
end
|
|
end
|
|
|
|
function private.AddBtnOnClick(self)
|
|
local _, maxVal = nil, nil
|
|
if self._validateContext then
|
|
_, maxVal = strsplit(":", self._validateContext)
|
|
end
|
|
local value = tostring(min(tonumber(self:GetValue()) + (IsShiftKeyDown() and 10 or 1), maxVal or math.huge))
|
|
if self:_SetValueHelper(value) then
|
|
self._escValue = self._value
|
|
self:_GetBaseFrame():SetText(value)
|
|
self:_UpdateIconsForValue(value)
|
|
end
|
|
end
|
|
|
|
function private.OnEnter(self)
|
|
self:_UpdateIconsForValue(self._value)
|
|
end
|
|
|
|
function private.OnLeave(self)
|
|
self:_UpdateIconsForValue(self._value)
|
|
end
|