--[[ | 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/ --]] -- generic panels that are applicable anywhere -- used for prominent text entries DEFINE_BASECLASS("DTextEntry") local PANEL = {} AccessorFunc(PANEL, "backgroundColor", "BackgroundColor") function PANEL:Init() self:SetPaintBackground(false) self:SetTextColor(color_white) self.backgroundColor = Color(255, 255, 255, 25) end function PANEL:SetFont(font) surface.SetFont(font) local _, height = surface.GetTextSize("W@") self:SetTall(height) BaseClass.SetFont(self, font) end function PANEL:Paint(width, height) derma.SkinFunc("DrawImportantBackground", 0, 0, width, height, self.backgroundColor) BaseClass.Paint(self, width, height) end vgui.Register("ixTextEntry", PANEL, "DTextEntry") -- similar to a frame, but is mainly used for grouping panels together in a list PANEL = {} AccessorFunc(PANEL, "text", "Text", FORCE_STRING) AccessorFunc(PANEL, "color", "Color") function PANEL:Init() self.text = "" self.paddingTop = SScaleMin(32 / 3) local skin = self:GetSkin() if (skin and skin.fontCategoryBlur) then surface.SetFont("TitlesFontNoClamp") self.paddingTop = select(2, surface.GetTextSize("W@")) + SScaleMin(6 / 3) end self:DockPadding(SScaleMin(1 / 3), self.paddingTop, SScaleMin(1 / 3), SScaleMin(1 / 3)) end function PANEL:SizeToContents() local height = self.paddingTop + SScaleMin(1 / 3) for _, v in ipairs(self:GetChildren()) do if (IsValid(v) and v:IsVisible()) then local _, top, _, bottom = v:GetDockMargin() height = height + v:GetTall() + top + bottom end end self:SetTall(height) end function PANEL:Paint(width, height) text = self.text or "" color = self.color or ix.config.Get("color") surface.SetFont("TitlesFontNoClamp") local textHeight = select(2, surface.GetTextSize(text)) + SScaleMin(6 / 3) local width, height = self:GetSize() surface.SetDrawColor(0, 0, 0, 100) surface.DrawRect(0, textHeight, width, height - textHeight) surface.SetDrawColor(Color(0, 0, 0, 0)) surface.DrawRect(0, 0, width, textHeight) surface.SetFont("TitlesFontNoClamp") surface.SetTextColor(color_white) surface.SetTextPos(0, SScaleMin(1 / 3)) surface.DrawText(text) return SScaleMin(1 / 3), textHeight, SScaleMin(1 / 3), SScaleMin(1 / 3) end vgui.Register("ixCategoryPanel", PANEL, "EditablePanel") -- segmented progress bar PANEL = {} AccessorFunc(PANEL, "font", "Font", FORCE_STRING) AccessorFunc(PANEL, "barColor", "BarColor") AccessorFunc(PANEL, "textColor", "TextColor") AccessorFunc(PANEL, "progress", "Progress", FORCE_NUMBER) AccessorFunc(PANEL, "padding", "Padding", FORCE_NUMBER) AccessorFunc(PANEL, "animationTime", "AnimationTime", FORCE_NUMBER) AccessorFunc(PANEL, "easingType", "EasingType", FORCE_STRING) function PANEL:Init() self.segments = {} self.padding = ScrH() * 0.01 self.fraction = 0 self.animationTime = 0.5 self.easingType = "outQuint" self.progress = 0 end function PANEL:AddSegment(text) local id = #self.segments + 1 if (text:utf8sub(1, 1) == "@") then text = L(text:utf8sub(2)) end self.segments[id] = text return id end function PANEL:AddSegments(...) local segments = {...} for i = 1, #segments do self:AddSegment(segments[i]) end end function PANEL:GetSegments() return self.segments end function PANEL:SetProgress(segment) self.progress = math.Clamp(segment, 0, #self.segments) self:CreateAnimation(self.animationTime, { target = {fraction = self.progress / #self.segments}, easing = self.easingType }) end function PANEL:IncrementProgress(amount) self:SetProgress(self.progress + (amount or 1)) end function PANEL:DecrementProgress(amount) self:SetProgress(self.progress - (amount or 1)) end function PANEL:GetFraction() return self.fraction end function PANEL:SizeToContents() self:SetTall(draw.GetFontHeight(self.font or self:GetSkin().fontSegmentedProgress) + self.padding) end function PANEL:Paint(width, height) derma.SkinFunc("PaintSegmentedProgressBackground", self, width, height) if (#self.segments > 0) then derma.SkinFunc("PaintSegmentedProgress", self, width, height) end end vgui.Register("ixSegmentedProgress", PANEL, "Panel") -- list of labelled information PANEL = {} AccessorFunc(PANEL, "labelColor", "LabelColor") AccessorFunc(PANEL, "textColor", "TextColor") AccessorFunc(PANEL, "list", "List") AccessorFunc(PANEL, "minWidth", "MinimumWidth", FORCE_NUMBER) function PANEL:Init() self.label = self:Add("DLabel") self.label:SetFont("TitlesFontNoClamp") self.label:SetExpensiveShadow(1) self.label:SetTextColor(color_white) self.label:SetText("Label") self.label:SetContentAlignment(5) self.label:Dock(LEFT) self.label:DockMargin(0, 0, SScaleMin(4 / 3), 0) self.label:SizeToContents() self.label.Paint = function(this, width, height) derma.SkinFunc("PaintListRow", this, width, height) end self.text = self:Add("DLabel") self.text:SetFont("TitlesFontNoBoldNoClamp") self.text:SetTextColor(color_white) self.text:SetText("Text") self.text:SetTextInset(SScaleMin(8 / 3), 0) self.text:Dock(FILL) self.text:DockMargin(SScaleMin(4 / 3), 0, 0, 0) self.text:SizeToContents() self.text.Paint = function(this, width, height) derma.SkinFunc("PaintListRow", this, width, height) end self:DockMargin(0, 0, 0, SScaleMin(8 / 3)) self.list = {} self.minWidth = SScaleMin(100 / 3) end function PANEL:SetRightPanel(panel) self.text:Remove() self.text = self:Add(panel) self.text:Dock(FILL) self.text:DockMargin(SScaleMin(8 / 3), SScaleMin(4 / 3), SScaleMin(4 / 3), SScaleMin(4 / 3)) self.text:SizeToContents() end function PANEL:SetList(list, bNoAdd) if (!bNoAdd) then list[#list + 1] = self end self.list = list end function PANEL:UpdateLabelWidths() local maxWidth = self.label:GetWide() for i = 1, #self.list do maxWidth = math.max(self.list[i]:GetLabelWidth(), maxWidth) end maxWidth = math.max(self.minWidth, maxWidth) for i = 1, #self.list do self.list[i]:SetLabelWidth(maxWidth) end end function PANEL:SetLabelColor(color) self.label:SetTextColor(color) end function PANEL:SetTextColor(color) self.text:SetTextColor(color) end function PANEL:SetLabelText(text) self.label:SetText(text) self.label:SizeToContents() self:UpdateLabelWidths() end function PANEL:SetText(text) self.text:SetText(text) self.text:SizeToContents() end function PANEL:SetLabelWidth(width) self.label:SetWide(width) end function PANEL:GetLabelWidth(bWithoutMargin) if (!bWithoutMargin) then return self.label:GetWide() end local left, _, right, _ = self.label:GetDockMargin() return self.label:GetWide() + left + right end function PANEL:SizeToContents() self:SetTall(math.max(self.label:GetTall(), self.text:GetTall()) + SScaleMin(8 / 3)) end vgui.Register("ixListRow", PANEL, "Panel") -- alternative checkbox PANEL = {} AccessorFunc(PANEL, "bChecked", "Checked", FORCE_BOOL) AccessorFunc(PANEL, "animationTime", "AnimationTime", FORCE_NUMBER) AccessorFunc(PANEL, "labelPadding", "LabelPadding", FORCE_NUMBER) PANEL.GetValue = PANEL.GetChecked function PANEL:Init() self:SetMouseInputEnabled(true) self:SetCursor("hand") self.labelPadding = SScaleMin(8 / 3) self.animationOffset = 0 self.animationTime = 0.5 self.bChecked = false surface.SetFont("TitlesFontNoBoldNoClamp") self:SetWide(math.max(surface.GetTextSize(L("yes")), surface.GetTextSize(L("no"))) + self.labelPadding) end -- can be overidden to change audio params function PANEL:GetAudioFeedback() return "weapons/ar2/ar2_empty.wav", 75, self.bChecked and 150 or 125, 0.25 end function PANEL:EmitFeedback() LocalPlayer():EmitSound(self:GetAudioFeedback()) end function PANEL:SetChecked(bChecked, bInstant) self.bChecked = tobool(bChecked) self:CreateAnimation(bInstant and 0 or self.animationTime, { index = 1, target = { animationOffset = bChecked and 1 or 0 }, easing = "outElastic" }) if (!bInstant) then self:EmitFeedback() end end function PANEL:OnMousePressed(code) if (code == MOUSE_LEFT) then self:SetChecked(!self.bChecked) self:DoClick() end end function PANEL:DoClick() end function PANEL:Paint(width, height) surface.SetDrawColor(derma.GetColor("DarkerBackground", self)) surface.DrawRect(0, 0, width, height) local offset = self.animationOffset surface.SetFont("TitlesFontNoBoldNoClamp") local text = L("no"):utf8upper() local textWidth, textHeight = surface.GetTextSize(text) local y = offset * -textHeight surface.SetTextColor(250, 60, 60, 255) surface.SetTextPos(width * 0.5 - textWidth * 0.5, y + height * 0.5 - textHeight * 0.5) surface.DrawText(text) text = L("yes"):utf8upper() y = y + textHeight textWidth, textHeight = surface.GetTextSize(text) surface.SetTextColor(30, 250, 30, 255) surface.SetTextPos(width * 0.5 - textWidth * 0.5, y + height * 0.5 - textHeight * 0.5) surface.DrawText(text) end vgui.Register("ixCheckBox", PANEL, "EditablePanel") -- alternative num slider PANEL = {} AccessorFunc(PANEL, "labelPadding", "LabelPadding", FORCE_NUMBER) function PANEL:Init() self.labelPadding = SScaleMin(8 / 3) surface.SetFont("TitlesFontNoBoldNoClamp") local totalWidth = surface.GetTextSize("999") -- start off with 3 digit width self.label = self:Add("DLabel") self.label:Dock(RIGHT) self.label:SetWide(totalWidth + self.labelPadding) self.label:SetContentAlignment(5) self.label:SetFont("TitlesFontNoBoldNoClamp") self.label.Paint = function(panel, width, height) surface.SetDrawColor(derma.GetColor("DarkerBackground", self)) surface.DrawRect(0, 0, width, height) end self.label.SizeToContents = function(panel) surface.SetFont(panel:GetFont()) local textWidth = surface.GetTextSize(panel:GetText()) if (textWidth > totalWidth) then panel:SetWide(textWidth + self.labelPadding) elseif (panel:GetWide() > totalWidth + self.labelPadding) then panel:SetWide(totalWidth + self.labelPadding) end end self.slider = self:Add("ixSlider") self.slider:Dock(FILL) self.slider:DockMargin(0, 0, SScaleMin(4 / 3), 0) self.slider.OnValueChanged = function(panel) self:OnValueChanged() end self.slider.OnValueUpdated = function(panel) self.label:SetText(tostring(panel:GetValue())) self.label:SizeToContents() self:OnValueUpdated() end end function PANEL:GetLabel() return self.label end function PANEL:GetSlider() return self.slider end function PANEL:SetValue(value, bNoNotify) value = tonumber(value) or self.slider:GetMin() self.slider:SetValue(value, bNoNotify) self.label:SetText(tostring(self.slider:GetValue())) self.label:SizeToContents() end function PANEL:GetValue() return self.slider:GetValue() end function PANEL:GetFraction() return self.slider:GetFraction() end function PANEL:GetVisualFraction() return self.slider:GetVisualFraction() end function PANEL:SetMin(value) self.slider:SetMin(value) end function PANEL:SetMax(value) self.slider:SetMax(value) end function PANEL:GetMin() return self.slider:GetMin() end function PANEL:GetMax() return self.slider:GetMax() end function PANEL:SetDecimals(value) self.slider:SetDecimals(value) end function PANEL:GetDecimals() return self.slider:GetDecimals() end -- called when changed by user function PANEL:OnValueChanged() end -- called when changed while dragging bar function PANEL:OnValueUpdated() end vgui.Register("ixNumSlider", PANEL, "Panel") -- alternative slider PANEL = {} AccessorFunc(PANEL, "bDragging", "Dragging", FORCE_BOOL) AccessorFunc(PANEL, "min", "Min", FORCE_NUMBER) AccessorFunc(PANEL, "max", "Max", FORCE_NUMBER) AccessorFunc(PANEL, "decimals", "Decimals", FORCE_NUMBER) function PANEL:Init() self.min = 0 self.max = 10 self.value = 0 self.visualValue = 0 self.decimals = 0 self:SetCursor("hand") end function PANEL:SetValue(value, bNoNotify) self.value = math.Clamp(math.Round(tonumber(value) or self.min, self.decimals), self.min, self.max) self:ValueUpdated(bNoNotify) if (!bNoNotify) then self:OnValueChanged() end end function PANEL:GetValue() return self.value end function PANEL:GetFraction() return math.Remap(self.value, self.min, self.max, 0, 1) end function PANEL:GetVisualFraction() return math.Remap(self.visualValue, self.min, self.max, 0, 1) end function PANEL:OnMousePressed(key) if (key == MOUSE_LEFT) then self.bDragging = true self:MouseCapture(true) self:OnCursorMoved(self:CursorPos()) end end function PANEL:OnMouseReleased(key) if (self.bDragging) then self:OnValueChanged() end self.bDragging = false self:MouseCapture(false) end function PANEL:OnCursorMoved(x, y) if (!self.bDragging) then return end x = math.Clamp(x, 0, self:GetWide()) local oldValue = self.value self.value = math.Clamp(math.Round( math.Remap(x / self:GetWide(), 0, 1, self.min, self.max), self.decimals ), self.min, self.max) self:CreateAnimation(0.5, { index = 1, target = {visualValue = self.value}, easing = "outQuint" }) if (self.value != oldValue) then self:ValueUpdated() end end function PANEL:OnValueChanged() end function PANEL:ValueUpdated(bNoNotify) self:CreateAnimation(bNoNotify and 0 or 0.5, { index = 1, target = {visualValue = self.value}, easing = "outQuint" }) if (!bNoNotify) then self:OnValueUpdated() end end function PANEL:OnValueUpdated() end function PANEL:Paint(width, height) derma.SkinFunc("PaintHelixSlider", self, width, height) end vgui.Register("ixSlider", PANEL, "EditablePanel") -- label with custom kerning PANEL = {} AccessorFunc(PANEL, "text", "Text", FORCE_STRING) AccessorFunc(PANEL, "color", "TextColor") AccessorFunc(PANEL, "kerning", "Kerning", FORCE_NUMBER) -- in px AccessorFunc(PANEL, "font", "Font", FORCE_STRING) AccessorFunc(PANEL, "bCentered", "Centered", FORCE_BOOL) AccessorFunc(PANEL, "bDrawShadow", "ExpensiveShadow") function PANEL:Init() self.text = "" self.color = color_white self.kerning = 2 self.font = "DermaDefault" self.bCentered = false self.shadowDistance = 0 self.color = color_black end function PANEL:SetText(text) self.text = tostring(text) self:GetContentSize(true) end function PANEL:SetExpensiveShadow(distance, color) -- we'll retain similar naming to the DLabel shadow self.shadowDistance = distance or 1 self.shadowColor = ix.util.DimColor(self.color, 0.5) end function PANEL:Paint(width, height) surface.SetFont(self.font) local x = self.bCentered and (width * 0.5 - self:GetContentSize() * 0.5) or 0 for i = 1, #self.text do local character = self.text[i] local textWidth, _ = surface.GetTextSize(character) local kerning = i == 1 and 0 or self.kerning local shadowDistance = self.shadowDistance -- shadow if (self.shadowDistance > 0) then surface.SetTextColor(self.shadowColor) surface.SetTextPos(x + kerning + shadowDistance, shadowDistance) surface.DrawText(character) end -- character surface.SetTextColor(self.color) surface.SetTextPos(x + kerning, 0) surface.DrawText(character) x = x + textWidth + kerning end end function PANEL:GetContentSize(bCalculate) if (bCalculate or !self.contentSize) then local width = 0 surface.SetFont(self.font) for i = 1, #self.text do local textWidth, _ = surface.GetTextSize(self.text[i]) width = width + textWidth + self.kerning end self.contentSize = {width, draw.GetFontHeight(self.font)} end return self.contentSize[1], self.contentSize[2] end function PANEL:SizeToContents() self:SetSize(self:GetContentSize(true)) end vgui.Register("ixKLabel", PANEL, "Panel") -- text entry with icon DEFINE_BASECLASS("ixTextEntry") PANEL = {} AccessorFunc(PANEL, "icon", "Icon", FORCE_STRING) AccessorFunc(PANEL, "iconColor", "IconColor") function PANEL:Init() self:SetIcon("V") self:SetFont("ixSmallTitleFont") self.iconColor = Color(200, 200, 200, 160) end function PANEL:SetIcon(newIcon) surface.SetFont("ixSmallTitleIcons") self.iconWidth, self.iconHeight = surface.GetTextSize(newIcon) self.icon = newIcon self:DockMargin(self.iconWidth + 2, 0, 0, 8) end function PANEL:Paint(width, height) BaseClass.Paint(self, width, height) -- there's no inset for text entries so we'll have to get creative DisableClipping(true) surface.SetDrawColor(self:GetBackgroundColor()) surface.DrawRect(-self.iconWidth - 2, 0, self.iconWidth + 2, height) surface.SetFont("ixSmallTitleIcons") surface.SetTextColor(self.iconColor) surface.SetTextPos(-self.iconWidth, 0) surface.DrawText("V") DisableClipping(false) end vgui.Register("ixIconTextEntry", PANEL, "ixTextEntry")