mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-16 21:33:46 +03:00
389 lines
8.5 KiB
Lua
389 lines
8.5 KiB
Lua
--[[
|
|
| This file was obtained through the combined efforts
|
|
| of Madbluntz & Plymouth Antiquarian Society.
|
|
|
|
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
|
| Maloy, DrPepper10 @ RIP, Atle!
|
|
|
|
|
| Visit for more: https://plymouth.thetwilightzone.ru/
|
|
--]]
|
|
|
|
local sui = sui
|
|
|
|
local surface = surface
|
|
local utf8 = sui.utf8
|
|
local draw = draw
|
|
local math = math
|
|
|
|
local IsValid = IsValid
|
|
local tostring = tostring
|
|
local tonumber = tonumber
|
|
|
|
local SUI, NAME = CURRENT_SUI, CURRENT_SUI.name
|
|
|
|
local GetColor = SUI.GetColor
|
|
local TEXT_ENTRY_FONT = SUI.CreateFont("TextEntry", "Roboto Regular", 16)
|
|
|
|
local Panel = {}
|
|
|
|
sui.scaling_functions(Panel)
|
|
|
|
AccessorFunc(Panel, "m_FontName", "Font", FORCE_STRING)
|
|
AccessorFunc(Panel, "m_Editable", "Editable", FORCE_BOOL)
|
|
AccessorFunc(Panel, "m_Placeholder", "Placeholder", FORCE_STRING)
|
|
AccessorFunc(Panel, "m_MaxChars", "MaxChars", FORCE_NUMBER)
|
|
AccessorFunc(Panel, "m_Numeric", "Numeric", FORCE_BOOL)
|
|
AccessorFunc(Panel, "m_NoBar", "NoBar", FORCE_BOOL)
|
|
AccessorFunc(Panel, "m_BarColor", "BarColor")
|
|
AccessorFunc(Panel, "m_Background", "Background")
|
|
AccessorFunc(Panel, "m_Radius", "Radius")
|
|
AccessorFunc(Panel, "m_NoEnter", "NoEnter")
|
|
|
|
Panel:SetRadius(3)
|
|
|
|
function Panel:Init()
|
|
self:ScaleInit()
|
|
|
|
self:SetupTransition("TextEntryReady", 0.9, function()
|
|
return self:IsEditing() or self:GetBarColor() ~= nil
|
|
end)
|
|
|
|
self:SetUpdateOnType(true)
|
|
self:SetCursor("beam")
|
|
self:SetFont(TEXT_ENTRY_FONT)
|
|
self:SetPlaceholder("Placeholder text")
|
|
|
|
self:SetSize(200, 22)
|
|
|
|
self.allowed_numeric_characters = "1234567890.-"
|
|
|
|
self.history = {}
|
|
self.history_pos = 1
|
|
self.can_use_history = true
|
|
|
|
self:OnScaleChange()
|
|
end
|
|
|
|
function Panel:SetCaretPos(pos)
|
|
DTextEntry.SetCaretPos(self, math.Clamp(pos, 0, utf8.len(self:GetText())))
|
|
end
|
|
|
|
function Panel:SetValue(value)
|
|
self:SetText(value)
|
|
self:OnValueChange(value)
|
|
end
|
|
|
|
function Panel:AllowInput(ch)
|
|
if self:CheckNumeric(ch) then return true end
|
|
|
|
if sui.wspace_chs[ch] or sui.cntrl_chs[ch] then
|
|
return true
|
|
end
|
|
|
|
local max_chars = self:GetMaxChars()
|
|
if max_chars and #self:GetText() >= max_chars then
|
|
surface.PlaySound("resource/warning.wav")
|
|
return true
|
|
end
|
|
end
|
|
|
|
function Panel:AddValue(v, i, j)
|
|
local original_text = self:GetText()
|
|
|
|
local start
|
|
if i then
|
|
start = original_text:sub(1, i)
|
|
else
|
|
start = utf8.sub(original_text, 1, self:GetCaretPos())
|
|
end
|
|
|
|
local text = start .. v
|
|
local caret_pos = utf8.len(text)
|
|
|
|
local _end
|
|
if j then
|
|
_end = original_text:sub(j)
|
|
else
|
|
_end = utf8.sub(original_text, utf8.len(start) + 1)
|
|
end
|
|
text = text .. _end
|
|
|
|
local max_chars = self:GetMaxChars()
|
|
if max_chars then
|
|
text = text:sub(1, max_chars)
|
|
end
|
|
|
|
self:SetValue(text)
|
|
self:SetCaretPos(caret_pos)
|
|
end
|
|
|
|
function Panel:OnKeyCodeTyped(code)
|
|
if self.no_down then
|
|
self.no_down = nil
|
|
return
|
|
end
|
|
|
|
if code == KEY_UP or code == KEY_DOWN then
|
|
if not self:UpdateFromHistory(code) then
|
|
return true
|
|
end
|
|
|
|
local lines, caret_line = self:GetNumLines()
|
|
|
|
if lines == 1 then
|
|
return true
|
|
end
|
|
|
|
--
|
|
-- this fixes a weird issue
|
|
-- make the text entry has at least 2 lines, go up then go down, you won't be able to go up again
|
|
--
|
|
if code == KEY_DOWN and lines == caret_line + 1 then
|
|
self.no_down = true
|
|
gui.InternalKeyCodeTyped(KEY_DOWN)
|
|
end
|
|
end
|
|
|
|
self:OnKeyCode(code)
|
|
|
|
if code == KEY_ENTER then
|
|
if IsValid(self.Menu) then
|
|
self.Menu:Remove()
|
|
end
|
|
|
|
if not self:GetNoEnter() then
|
|
self:FocusNext()
|
|
self:OnEnter()
|
|
end
|
|
end
|
|
end
|
|
|
|
function Panel:DisallowFloats(disallow)
|
|
if not isbool(disallow) then
|
|
disallow = true
|
|
end
|
|
|
|
if disallow then
|
|
self.allowed_numeric_characters = self.allowed_numeric_characters:gsub("%.", "", 1)
|
|
elseif not self.allowed_numeric_characters:find(".", 1, true) then
|
|
self.allowed_numeric_characters = self.allowed_numeric_characters .. "."
|
|
end
|
|
end
|
|
|
|
function Panel:DisallowNegative(disallow)
|
|
if not isbool(disallow) then
|
|
disallow = true
|
|
end
|
|
|
|
if disallow then
|
|
self.allowed_numeric_characters = self.allowed_numeric_characters:gsub("%-", "", 1)
|
|
elseif not self.allowed_numeric_characters:find("-", 1, true) then
|
|
self.allowed_numeric_characters = self.allowed_numeric_characters .. "-"
|
|
end
|
|
end
|
|
|
|
function Panel:CheckNumeric(value)
|
|
if not self:GetNumeric() then return false end
|
|
|
|
if not self.allowed_numeric_characters:find(value, 1, true) then
|
|
return true
|
|
end
|
|
|
|
local new_value = ""
|
|
local current_value = tostring(self:GetText())
|
|
|
|
local caret_pos = self:GetCaretPos()
|
|
for i = 0, #current_value do
|
|
new_value = new_value .. current_value:sub(i, i)
|
|
if i == caret_pos then
|
|
new_value = new_value .. value
|
|
end
|
|
end
|
|
|
|
if #current_value ~= 0 and not tonumber(new_value) then
|
|
return true
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
function Panel:AddHistory(txt)
|
|
if not txt or txt == "" then return end
|
|
local history = self.history
|
|
if history[#history] ~= txt then
|
|
table.insert(history, txt)
|
|
end
|
|
end
|
|
|
|
function Panel:UpdateFromHistory(code)
|
|
if not self.can_use_history then return end
|
|
|
|
local lines, caret_line = self:GetNumLines()
|
|
|
|
if code == KEY_UP then
|
|
if caret_line > 1 then return true end -- enable the caret to move up and down
|
|
|
|
if self.history_pos <= 1 then return end
|
|
|
|
self.history_pos = self.history_pos - 1
|
|
elseif code == KEY_DOWN then
|
|
if caret_line ~= lines then return true end
|
|
|
|
if self.history_pos >= #self.history then
|
|
self:SetValue("")
|
|
self:SetCaretPos(0)
|
|
self.history_pos = #self.history + 1
|
|
return
|
|
end
|
|
|
|
self.history_pos = self.history_pos + 1
|
|
end
|
|
|
|
local text = self.history[self.history_pos]
|
|
if not text then return end
|
|
|
|
self:SetValue(text)
|
|
self:SetCaretPos(utf8.len(text))
|
|
end
|
|
|
|
function Panel:OnTextChanged()
|
|
self.history_pos = #self.history + 1
|
|
|
|
local text = self:GetText()
|
|
|
|
self.can_use_history = text == "" and true or false
|
|
|
|
if self:GetUpdateOnType() then
|
|
self:UpdateConvarValue()
|
|
self:OnValueChange(text)
|
|
end
|
|
|
|
self:OnChange()
|
|
end
|
|
|
|
function Panel:OnScaleChange()
|
|
self:InvalidateLayout()
|
|
self:InvalidateLayout(true)
|
|
end
|
|
|
|
function Panel:Paint(w, h)
|
|
self:RoundedBox("Background", self:GetRadius(), 0, 0, w, h, GetColor("text_entry_bg") or self:GetBackground())
|
|
|
|
local text_entry_3 = GetColor("text_entry_3")
|
|
|
|
if self:GetText() == "" then
|
|
local old_text = self:GetText()
|
|
self:SetText(self:GetPlaceholder())
|
|
self:DrawTextEntryText(GetColor("text_entry_2"), text_entry_3, text_entry_3)
|
|
self:SetText(old_text)
|
|
else
|
|
self:DrawTextEntryText(GetColor("text_entry"), text_entry_3, text_entry_3)
|
|
end
|
|
|
|
if not self:GetNoBar() then
|
|
local bar_color = self:GetBarColor()
|
|
|
|
self:RoundedBox("Bar1", 0, 0, h - 1, w, 1, GetColor("text_entry_bar_color"))
|
|
|
|
local bar = math.Round(w * self.TextEntryReady)
|
|
if bar > 0 then
|
|
self:RoundedBox("Bar2", 0, (w / 2) - (bar / 2), h - 1, bar, 1, bar_color or text_entry_3)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- https://github.com/ValveSoftware/source-sdk-2013/blob/0d8dceea4310fde5706b3ce1c70609d72a38efdf/mp/src/vgui2/vgui_controls/TextEntry.cpp#L969
|
|
function Panel:GetNumLines(wide)
|
|
local num_lines = 1
|
|
|
|
wide = wide or self:GetWide() - 2
|
|
|
|
local vbar = self:GetChildren()[1]
|
|
if vbar then
|
|
wide = wide - vbar:GetWide()
|
|
end
|
|
|
|
local char_width
|
|
local x = 3
|
|
|
|
local word_start_index = 1
|
|
local word_start_len
|
|
local word_length = 0
|
|
local has_word = false
|
|
local just_started_new_line = true
|
|
local word_started_on_new_line = true
|
|
|
|
local start_char = 1
|
|
|
|
surface.SetFont(self:GetFont())
|
|
|
|
local i = start_char
|
|
local text, n = utf8.force(self:GetText())
|
|
local caret_line = 0
|
|
local caret_pos = self:GetCaretPos()
|
|
local caret_i = 1
|
|
while i <= n do
|
|
local ch_len = utf8.char_bytes(text:byte(i))
|
|
local ch = text:sub(i, i + ch_len - 1)
|
|
|
|
if ch ~= " " then
|
|
if not has_word then
|
|
word_start_index = i
|
|
word_start_len = ch_len
|
|
has_word = true
|
|
word_started_on_new_line = just_started_new_line
|
|
word_length = 0
|
|
end
|
|
else
|
|
has_word = false
|
|
end
|
|
|
|
char_width = surface.GetTextSize(ch)
|
|
just_started_new_line = false
|
|
|
|
if (x + char_width) >= wide then
|
|
x = 3
|
|
|
|
just_started_new_line = true
|
|
has_word = false
|
|
|
|
if word_started_on_new_line then
|
|
num_lines = num_lines + 1
|
|
else
|
|
num_lines = num_lines + 1
|
|
i = (word_start_index + word_start_len) - ch_len
|
|
end
|
|
|
|
word_length = 0
|
|
end
|
|
|
|
x = x + char_width
|
|
word_length = word_length + char_width
|
|
|
|
if caret_i == caret_pos then
|
|
caret_line = num_lines
|
|
end
|
|
|
|
i = i + ch_len
|
|
caret_i = caret_i + 1
|
|
end
|
|
|
|
return num_lines, caret_line
|
|
end
|
|
|
|
function Panel:SetCheck(func, col)
|
|
function self:OnValueChange(text)
|
|
if func(text) == false then
|
|
self.valid = false
|
|
self:SetBarColor(GetColor("close_hover"))
|
|
self:SetNoEnter(true)
|
|
else
|
|
self.valid = true
|
|
self:SetBarColor(col)
|
|
self:SetNoEnter(false)
|
|
end
|
|
end
|
|
self:SetValue(self:GetText())
|
|
end
|
|
|
|
sui.register("TextEntry", Panel, "DTextEntry") |