--[[ | 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 PANEL = {} local strAllowedNumericCharacters = "1234567890.-" AccessorFunc( PANEL, "m_bAllowEnter", "EnterAllowed", FORCE_BOOL ) AccessorFunc( PANEL, "m_bUpdateOnType", "UpdateOnType", FORCE_BOOL ) -- Update the convar as we type AccessorFunc( PANEL, "m_bNumeric", "Numeric", FORCE_BOOL ) AccessorFunc( PANEL, "m_bHistory", "HistoryEnabled", FORCE_BOOL ) AccessorFunc( PANEL, "m_bDisableTabbing", "TabbingDisabled", FORCE_BOOL ) AccessorFunc( PANEL, "m_FontName", "Font" ) AccessorFunc( PANEL, "m_bBorder", "DrawBorder" ) AccessorFunc( PANEL, "m_bBackground", "PaintBackground" ) AccessorFunc( PANEL, "m_bBackground", "DrawBackground" ) -- Deprecated AccessorFunc( PANEL, "m_colText", "TextColor" ) AccessorFunc( PANEL, "m_colHighlight", "HighlightColor" ) AccessorFunc( PANEL, "m_colCursor", "CursorColor" ) AccessorFunc( PANEL, "m_colPlaceholder", "PlaceholderColor" ) AccessorFunc( PANEL, "m_txtPlaceholder", "PlaceholderText" ) Derma_Install_Convar_Functions( PANEL ) function PANEL:Init() self:SetHistoryEnabled( false ) self.History = {} self.HistoryPos = 0 -- -- We're going to draw these ourselves in -- the skin system - so disable them here. -- This will leave it only drawing text. -- self:SetPaintBorderEnabled( false ) self:SetPaintBackgroundEnabled( false ) -- -- These are Lua side commands -- Defined above using AccessorFunc -- self:SetDrawBorder( true ) self:SetPaintBackground( true ) self:SetEnterAllowed( true ) self:SetUpdateOnType( false ) self:SetNumeric( false ) self:SetAllowNonAsciiCharacters( true ) -- Nicer default height self:SetTall( 20 ) -- Clear keyboard focus when we click away self.m_bLoseFocusOnClickAway = true -- Beam Me Up Scotty self:SetCursor( "beam" ) self:SetFont( "DermaDefault" ) end function PANEL:IsEditing() return self == vgui.GetKeyboardFocus() end function PANEL:OnKeyCodeTyped( code ) self:OnKeyCode( code ) if ( code == KEY_ENTER && !self:IsMultiline() && self:GetEnterAllowed() ) then if ( IsValid( self.Menu ) ) then self.Menu:Remove() end self:FocusNext() self:OnEnter( self:GetText() ) self.HistoryPos = 0 end if ( self.m_bHistory || IsValid( self.Menu ) ) then if ( code == KEY_UP ) then self.HistoryPos = self.HistoryPos - 1 self:UpdateFromHistory() end if ( code == KEY_DOWN || code == KEY_TAB ) then self.HistoryPos = self.HistoryPos + 1 self:UpdateFromHistory() end end end function PANEL:OnKeyCode( code ) end function PANEL:ApplySchemeSettings() self:SetFontInternal( self.m_FontName ) derma.SkinHook( "Scheme", "TextEntry", self ) end function PANEL:GetTextColor() return self.m_colText || self:GetSkin().colTextEntryText end function PANEL:GetPlaceholderColor() return self.m_colPlaceholder || self:GetSkin().colTextEntryTextPlaceholder end function PANEL:GetHighlightColor() return self.m_colHighlight || self:GetSkin().colTextEntryTextHighlight end function PANEL:GetCursorColor() return self.m_colCursor || self:GetSkin().colTextEntryTextCursor end function PANEL:UpdateFromHistory() if ( IsValid( self.Menu ) ) then return self:UpdateFromMenu() end local pos = self.HistoryPos -- Is the Pos within bounds? if ( pos < 0 ) then pos = #self.History end if ( pos > #self.History ) then pos = 0 end local text = self.History[ pos ] if ( !text ) then text = "" end self:SetText( text ) self:SetCaretPos( utf8.len( text ) ) self:OnTextChanged() self.HistoryPos = pos end function PANEL:UpdateFromMenu() local pos = self.HistoryPos local num = self.Menu:ChildCount() self.Menu:ClearHighlights() if ( pos < 0 ) then pos = num end if ( pos > num ) then pos = 0 end local item = self.Menu:GetChild( pos ) if ( !item ) then self:SetText( "" ) self.HistoryPos = pos return end self.Menu:HighlightItem( item ) local txt = item:GetText() self:SetText( txt ) self:SetCaretPos( utf8.len( txt ) ) self:OnTextChanged( true ) self.HistoryPos = pos end function PANEL:OnTextChanged( noMenuRemoval ) self.HistoryPos = 0 if ( self:GetUpdateOnType() ) then self:UpdateConvarValue() self:OnValueChange( self:GetText() ) end if ( IsValid( self.Menu ) && !noMenuRemoval ) then self.Menu:Remove() end local tab = self:GetAutoComplete( self:GetText() ) if ( tab ) then self:OpenAutoComplete( tab ) end self:OnChange() end function PANEL:OnChange() end function PANEL:OpenAutoComplete( tab ) if ( !tab ) then return end if ( #tab == 0 ) then return end self.Menu = DermaMenu() for k, v in pairs( tab ) do self.Menu:AddOption( v, function() self:SetText( v ) self:SetCaretPos( utf8.len( v ) ) self:RequestFocus() end ) end local x, y = self:LocalToScreen( 0, self:GetTall() ) self.Menu:SetMinimumWidth( self:GetWide() ) self.Menu:Open( x, y, true, self ) self.Menu:SetPos( x, y ) self.Menu:SetMaxHeight( ( ScrH() - y ) - 10 ) end function PANEL:Think() self:ConVarStringThink() end function PANEL:OnRemove() if ( IsValid( self.Menu ) ) then self.Menu:Remove() end end function PANEL:OnEnter( val ) -- For override self:UpdateConvarValue() self:OnValueChange( self:GetText() ) end function PANEL:UpdateConvarValue() -- This only kicks into action if this variable has -- a ConVar associated with it. self:ConVarChanged( self:GetValue() ) end function PANEL:Paint( w, h ) derma.SkinHook( "Paint", "TextEntry", self, w, h ) return false end function PANEL:PerformLayout() derma.SkinHook( "Layout", "TextEntry", self ) end function PANEL:SetValue( strValue ) -- Don't update if we're typing into it! -- I'm sure a lot of people will want to reverse this behaviour :( if ( vgui.GetKeyboardFocus() == self ) then return end local CaretPos = self:GetCaretPos() self:SetText( strValue ) self:OnValueChange( strValue ) self:SetCaretPos( CaretPos ) end function PANEL:OnValueChange( strValue ) -- For Override end function PANEL:CheckNumeric( strValue ) -- Not purely numeric, don't run the check if ( !self:GetNumeric() ) then return false end -- God I hope numbers look the same in every language if ( !string.find( strAllowedNumericCharacters, strValue, 1, true ) ) then -- Noisy Error? return true end return false end function PANEL:SetDisabled( bDisabled ) self:SetEnabled( !bDisabled ) end function PANEL:GetDisabled( bDisabled ) return !self:IsEnabled() end function PANEL:AllowInput( strValue ) -- This is layed out like this so you can easily override and -- either keep or remove this numeric check. if ( self:CheckNumeric( strValue ) ) then return true end end function PANEL:SetEditable( b ) self:SetKeyboardInputEnabled( b ) self:SetMouseInputEnabled( b ) end function PANEL:OnGetFocus() -- -- These hooks are here for the sake of things like the spawn menu -- which don't have key focus until you click on one of the text areas. -- -- If you make a control for the spawnmenu that requires keyboard input -- You should have these 3 functions in your panel, so it can handle it. -- hook.Run( "OnTextEntryGetFocus", self ) end function PANEL:OnLoseFocus() self:UpdateConvarValue() hook.Call( "OnTextEntryLoseFocus", nil, self ) end function PANEL:OnMousePressed( mcode ) if ( mcode == MOUSE_LEFT ) then self:OnGetFocus() end end function PANEL:AddHistory( txt ) if ( !txt || txt == "" ) then return end table.RemoveByValue( self.History, txt ) table.insert( self.History, txt ) end function PANEL:GetAutoComplete( txt ) -- for override. Return a table of strings. end function PANEL:GetInt() local num = tonumber( self:GetText() ) if ( !num ) then return nil end return math.Round( num ) end function PANEL:GetFloat() return tonumber( self:GetText() ) end function PANEL:GenerateExample( ClassName, PropertySheet, Width, Height ) local ctrl = vgui.Create( ClassName ) ctrl:SetText( "Edit Me!" ) ctrl:SetWide( 150 ) ctrl.OnEnter = function( slf ) Derma_Message( "You Typed: " .. slf:GetValue() ) end PropertySheet:AddSheet( ClassName, ctrl, nil, true, true ) end derma.DefineControl( "DTextEntry", "A simple TextEntry control", PANEL, "TextEntry" ) --[[--------------------------------------------------------- Clear the focus when we click away from us.. -----------------------------------------------------------]] function TextEntryLoseFocus( panel, mcode ) local pnl = vgui.GetKeyboardFocus() if ( !pnl ) then return end if ( pnl == panel ) then return end if ( !pnl.m_bLoseFocusOnClickAway ) then return end -- We gotta find the EdtiablePanel parent and call KillFocus on it -- We do it from the panel clicked, not the KB focus, which is necessary for DTextEntry autocomplete to not break local prnt = panel while ( IsValid( prnt ) ) do if ( prnt:GetClassName() == "EditablePanel" || prnt:GetClassName() == "LuaEditablePanel" ) then prnt:KillFocus() return end prnt = prnt:GetParent() end end hook.Add( "VGUIMousePressed", "TextEntryLoseFocus", TextEntryLoseFocus )