Compare commits

...

2 commits

3 changed files with 266 additions and 40 deletions

View file

@ -1,12 +1,32 @@
local DisableClipping = DisableClipping
local ScrW = ScrW local ScrW = ScrW
local ScrH = ScrH local ScrH = ScrH
local Color = Color
local STENCIL_EQUAL = STENCIL_EQUAL
local STENCIL_KEEP = STENCIL_KEEP
local STENCIL_NEVER = STENCIL_NEVER
local STENCIL_REPLACE = STENCIL_REPLACE
local draw = draw
local math = math
local render = render local render = render
local string = string
local surface = surface local surface = surface
local draw_NoTexture = draw.NoTexture
local math_rad = math.rad
local math_sin = math.sin
local math_cos = math.cos
local render_ClearStencil = render.ClearStencil
local render_SetStencilCompareFunction = render.SetStencilCompareFunction
local render_SetStencilEnable = render.SetStencilEnable
local render_SetStencilFailOperation = render.SetStencilFailOperation
local render_SetStencilPassOperation = render.SetStencilPassOperation
local render_SetStencilReferenceValue = render.SetStencilReferenceValue
local render_SetStencilTestMask = render.SetStencilTestMask
local render_SetStencilWriteMask = render.SetStencilWriteMask
local render_SetStencilZFailOperation = render.SetStencilZFailOperation
local render_UpdateScreenEffectTexture = render.UpdateScreenEffectTexture local render_UpdateScreenEffectTexture = render.UpdateScreenEffectTexture
local surface_DrawPoly = surface.DrawPoly
local surface_DrawRect = surface.DrawRect local surface_DrawRect = surface.DrawRect
local surface_DrawTexturedRect = surface.DrawTexturedRect local surface_DrawTexturedRect = surface.DrawTexturedRect
local surface_SetDrawColor = surface.SetDrawColor local surface_SetDrawColor = surface.SetDrawColor
@ -16,10 +36,10 @@ cbox.chatbox = cbox.chatbox or {}
cbox.chatbox.tabs = cbox.chatbox.tabs or {} cbox.chatbox.tabs = cbox.chatbox.tabs or {}
cbox.chatbox.panels = cbox.chatbox.panels or {} cbox.chatbox.panels = cbox.chatbox.panels or {}
local CHATBOX_COLOR = CreateClientConVar("cbox_chatbox_color", "160 160 160", true, false, "Chatbox background color") local CHATBOX_COLOR = CreateClientConVar("cbox_chatbox_color", "160 160 160", true, false, "Chatbox background color")
local CHATBOX_ALPHA = CreateClientConVar("cbox_chatbox_alpha", "128", true, false, "Chatbox background alpha") local CHATBOX_ALPHA = CreateClientConVar("cbox_chatbox_alpha", "128", true, false, "Chatbox background alpha")
local CHATBOX_BLUR = CreateClientConVar("cbox_chatbox_blur", "0", true, false, "Chatbox background is blurred") local CHATBOX_BLUR = CreateClientConVar("cbox_chatbox_blur", "0", true, false, "Chatbox background is blurred")
local CHATBOX_FADE = CreateClientConVar("cbox_chatbox_fade", "1", true, false, "Chatbox fades in and out")
---@param height number ---@param height number
---@return number ---@return number
@ -51,6 +71,55 @@ end
local MATERIAL_BLUR = Material("pp/blurscreen") local MATERIAL_BLUR = Material("pp/blurscreen")
local function add_rounded_poly(poly, x, y, rad, seg, offset)
offset = offset or 0
for i = 0, seg do
local r = math_rad(((i + offset) / seg) * -90)
poly[#poly + 1] = {
x = x + math_sin(r) * rad,
y = y + math_cos(r) * rad,
u = math_sin(r) / 2 + 0.5,
v = math_cos(r) / 2 + 0.5,
}
end
end
local function RoundedBoxPoly(x, y, w, h, rad, seg)
local poly = {}
add_rounded_poly(poly, x + rad, y + rad, rad, seg, seg)
poly[#poly + 1] = {
x = x + (w - rad),
y = y,
u = 0.5,
v = 0.5,
}
add_rounded_poly(poly, x + (w - rad), y + rad, rad, seg, seg * 2)
poly[#poly + 1] = {
x = x + w,
y = y + (h - rad),
u = 0.5,
v = 0.5,
}
add_rounded_poly(poly, x + (w - rad), y + (h - rad), rad, seg, seg * 3)
poly[#poly + 1] = {
x = x + rad,
y = y + h,
u = 0.5,
v = 0.5,
}
add_rounded_poly(poly, x + rad, y + (h - rad), rad, seg)
surface_DrawPoly(poly)
end
local function CreateChatbox() local function CreateChatbox()
if IsValid(cbox.chatbox.panels.frame) then if IsValid(cbox.chatbox.panels.frame) then
cbox.chatbox.panels.frame:Remove() cbox.chatbox.panels.frame:Remove()
@ -61,15 +130,85 @@ local function CreateChatbox()
frame:SetDeleteOnClose(false) frame:SetDeleteOnClose(false)
frame:SetSizable(true) frame:SetSizable(true)
frame:SetScreenLock(true) frame:SetScreenLock(true)
frame:DockPadding(4, 4, 4, 4) frame:DockPadding(8, 8, 8, 8)
frame.btnMinim:SetVisible(false) local dx, dy, dw, dh = GetDefaultBounds()
frame.btnMaxim:SetVisible(false)
frame.lblTitle:SetVisible(false) -- TODO: make this configurable
frame:SetMinWidth(dw)
frame:SetMinWidth(dh)
-- TODO: save resizing/moving
frame:SetPos(dx, dy)
frame:SetSize(dw, dh)
frame:SetVisible(false)
function frame:PerformLayout() end
frame.btnClose:Remove()
frame.btnMinim:Remove()
frame.btnMaxim:Remove()
frame.lblTitle:Remove()
function frame:CrossFade(anim, delta, out)
if anim.Finished then
if out then
self:Close()
else
self:MakePopup()
end
end
if anim.Started then
if out then
self:SetAlpha(255)
else
self:SetAlpha(0)
end
end
self:SetAlpha(out and 255 * (1 - delta) or 255 * delta)
end
frame.animFade = Derma_Anim("Fade", frame, frame.CrossFade)
frame.oldThink = frame.Think
function frame:Think()
self:oldThink()
self.animFade:Run()
-- TODO: save position and size
end
function frame:Paint(w, h) function frame:Paint(w, h)
local alpha = CHATBOX_ALPHA:GetInt() local alpha = CHATBOX_ALPHA:GetInt()
-- Reset everything to known good
render_SetStencilWriteMask( 0xFF )
render_SetStencilTestMask( 0xFF )
render_SetStencilReferenceValue( 0 )
render_SetStencilPassOperation( STENCIL_KEEP )
render_SetStencilZFailOperation( STENCIL_KEEP )
render_ClearStencil()
-- Enable stencils
render_SetStencilEnable( true )
-- Set everything up everything draws to the stencil buffer instead of the screen
render_SetStencilReferenceValue( 1 )
render_SetStencilCompareFunction( STENCIL_NEVER )
render_SetStencilFailOperation( STENCIL_REPLACE )
draw_NoTexture()
surface_SetDrawColor(255, 255, 255)
RoundedBoxPoly(0, 0, w, h, 8, 24)
-- Only draw things that are in the stencil buffer
render_SetStencilCompareFunction( STENCIL_EQUAL )
render_SetStencilFailOperation( STENCIL_KEEP )
if CHATBOX_BLUR:GetBool() and alpha ~= 255 then if CHATBOX_BLUR:GetBool() and alpha ~= 255 then
local x, y = self:LocalToScreen(0, 0) local x, y = self:LocalToScreen(0, 0)
@ -84,32 +223,26 @@ local function CreateChatbox()
end end
end end
local color = string.Explode(" ", CHATBOX_COLOR:GetString()) local r, g, b = CHATBOX_COLOR:GetString():match("(%d+) (%d+) (%d+)")
surface_SetDrawColor(tonumber(color[1]), tonumber(color[2]), tonumber(color[3]), alpha) surface_SetDrawColor(r, g, b, alpha)
surface_DrawRect(0, 0, w, h) surface_DrawRect(0, 0, w, h)
-- Let everything render normally again
render_SetStencilEnable(false)
end end
local dx, dy, dw, dh = GetDefaultBounds()
-- TODO: make this configurable
frame:SetMinWidth(dw)
frame:SetMinWidth(dh)
-- TODO: save resizing/moving
frame:SetPos(dx, dy)
frame:SetSize(dw, dh)
frame:SetVisible(false)
cbox.chatbox.panels.frame = frame cbox.chatbox.panels.frame = frame
local tabs = vgui.Create("DPropertySheet", frame, "cbox.chatbox.tabs") local tabs = vgui.Create("DPropertySheet", frame, "cbox.chatbox.tabs")
tabs:Dock(FILL) tabs:Dock(FILL)
tabs:SetPadding(0) tabs:SetPadding(0)
function tabs:Paint(w, h) function tabs:Paint(w, h) end
surface_SetDrawColor(0, 0, 0, 72)
surface_DrawRect(0, 20, w, h - 20) function tabs:OnActiveTabChanged( old, new )
if new:GetPanel().cbox_id == "\1chat" then
cbox.chatbox.panels.input:RequestFocus()
end
end end
for id, tab in next, cbox.chatbox.tabs do for id, tab in next, cbox.chatbox.tabs do
@ -124,27 +257,68 @@ local function CreateChatbox()
continue continue
end end
tabs:AddSheet(tab.name, ret, tab.icon) local sheet = tabs:AddSheet(tab.name, ret, tab.icon)
sheet.Panel.cbox_id = id
end
end end
frame.btnClose:SetZPos(99) local function Init()
local tab_files = file.Find("cbox/tabs/*", "LUA")
for _, name in ipairs(tab_files) do
cbox.utils.RealmPrint("Loading chatbox tab:", name)
include("cbox/tabs/" .. name)
end end
if not IsValid(cbox.chatbox.panels.frame) then if not IsValid(cbox.chatbox.panels.frame) then
CreateChatbox() CreateChatbox()
end end
hook.Add("PlayerBindPress", "cbox.chatbox", function(ply, bind, pressed)
if bind ~= "messagemode" and bind ~= "messagemode2" then return end
if not pressed then return end
cbox.chatbox.Open(bind == "messagemode2")
return true
end)
end
---Opens the chatbox ---Opens the chatbox
---@param alt? boolean Was this request to open made by messagemode2 (team chat) ---@param alt? boolean Was this request to open made by messagemode2 (team chat)
function cbox.chatbox.Open(alt) function cbox.chatbox.Open(alt)
alt = alt ~= nil and alt or false alt = alt ~= nil and alt or false
if not IsValid(cbox.chatbox.panels.frame) then local frame = cbox.chatbox.panels.frame
if not IsValid(frame) then
CreateChatbox() CreateChatbox()
end end
cbox.chatbox.panels.frame:SetVisible(true) frame:SetVisible(true)
cbox.chatbox.panels.frame:MakePopup()
if frame.animFade and CHATBOX_FADE:GetBool() then
frame.animFade:Start(0.1, false)
else
frame:MakePopup()
end
if not IsValid(cbox.chatbox.panels.input) then
-- attempt to reinit
if IsValid(frame) then
frame:Remove()
end
Init()
end
if not IsValid(cbox.chatbox.panels.input) then
cbox.utils.RealmError("Input isn't valid, chat tab failed to load, bailing!")
if IsValid(frame) then
frame:Remove()
end
hook.Remove("PlayerBindPress", "cbox.chatbox")
return
end
cbox.chatbox.panels.input:RequestFocus() cbox.chatbox.panels.input:RequestFocus()
hook.Run("StartChat") hook.Run("StartChat")
@ -152,7 +326,13 @@ end
---Closes the chatbox ---Closes the chatbox
function cbox.chatbox.Close() function cbox.chatbox.Close()
cbox.chatbox.panels.frame:Close() local frame = cbox.chatbox.panels.frame
if frame.animFade and CHATBOX_FADE:GetBool() then
frame.animFade:Start(0.1, true)
else
frame:Close()
end
hook.Run("FinishChat") hook.Run("FinishChat")
@ -160,14 +340,15 @@ function cbox.chatbox.Close()
hook.Run("ChatTextChanged", "") hook.Run("ChatTextChanged", "")
end end
hook.Add("PlayerBindPress", "cbox.chatbox", function(ply, bind, pressed) hook.Add("Initialize", "cbox.chatbox", Init)
if bind ~= "messagemode" and bind ~= "messagemode2" then return end
cbox.chatbox.Open(bind == "messagemode2")
return true
end)
concommand.Add("cbox_chatbox_reload", function() concommand.Add("cbox_chatbox_reload", function()
CreateChatbox() CreateChatbox()
end, nil, "Reloads the chatbox") end, nil, "Reloads the chatbox")
concommand.Add("_cbox_chatbox_fullreload", function()
if IsValid(cbox.chatbox.panels.frame) then
cbox.chatbox.panels.frame:Remove()
end
Init()
end, nil, "Fully reinitializes the chatbox, use only in extreme breakage.")

View file

@ -1,9 +1,23 @@
local Color = Color
local surface = surface
local surface_DrawRect = surface.DrawRect
local surface_SetDrawColor = surface.SetDrawColor
local INPUT_TEXT_COLOR = Color(221, 221, 221)
local INPUT_HIGHLIGHT_COLOR = Color(192, 28, 0, 140)
cbox.chatbox.AddTab("\1chat", "Chat", "icon16/comments.png", function() cbox.chatbox.AddTab("\1chat", "Chat", "icon16/comments.png", function()
local wrapper = vgui.Create("EditablePanel") local wrapper = vgui.Create("EditablePanel")
-- TODO: custom richtext panel -- TODO: custom richtext panel
local history = vgui.Create("RichText", wrapper) local history = vgui.Create("RichText", wrapper)
history:Dock(FILL) history:Dock(FILL)
function history:Paint(w, h)
surface_SetDrawColor(0, 0, 0, 128)
surface_DrawRect(0, 0, w, h)
end
cbox.chatbox.panels.history = history cbox.chatbox.panels.history = history
function history:PerformLayout() function history:PerformLayout()
@ -13,18 +27,35 @@ cbox.chatbox.AddTab("\1chat", "Chat", "icon16/comments.png", function()
local input_wrapper = vgui.Create("EditablePanel", wrapper) local input_wrapper = vgui.Create("EditablePanel", wrapper)
input_wrapper:SetHeight(20) input_wrapper:SetHeight(20)
input_wrapper:DockMargin(0, 8, 0, 0)
input_wrapper:Dock(BOTTOM) input_wrapper:Dock(BOTTOM)
local input = vgui.Create("DTextEntry", input_wrapper) local input = vgui.Create("DTextEntry", input_wrapper)
input:DockMargin(4, 0, 0, 0)
input:Dock(FILL) input:Dock(FILL)
input:SetFont("ChatFont")
cbox.chatbox.panels.input = input cbox.chatbox.panels.input = input
function input:Paint(w, h)
surface_SetDrawColor(0, 0, 0, 128)
surface_DrawRect(0, 0, w, h)
self:DrawTextEntryText(INPUT_TEXT_COLOR, INPUT_HIGHLIGHT_COLOR, INPUT_TEXT_COLOR)
end
local mode_switch = vgui.Create("DButton", input_wrapper) local mode_switch = vgui.Create("DButton", input_wrapper)
mode_switch:SetFont("ChatFont")
mode_switch:SetTextColor(INPUT_TEXT_COLOR)
mode_switch:SetText("Say") mode_switch:SetText("Say")
mode_switch:SizeToContents() mode_switch:SizeToContents()
mode_switch:Dock(LEFT) mode_switch:Dock(LEFT)
cbox.chatbox.panels.mode_switch = mode_switch cbox.chatbox.panels.mode_switch = mode_switch
function mode_switch:Paint(w, h)
surface_SetDrawColor(0, 0, 0, 128)
surface_DrawRect(0, 0, w, h)
end
function mode_switch:DoClick() function mode_switch:DoClick()
-- TODO -- TODO
end end

View file

@ -0,0 +1,14 @@
local surface = surface
local surface_DrawRect = surface.DrawRect
local surface_SetDrawColor = surface.SetDrawColor
cbox.chatbox.AddTab("zzzzzzzsettings", "Settings", "icon16/cog.png", function()
local wrapper = vgui.Create("EditablePanel")
function wrapper:Paint(w, h)
surface_SetDrawColor(0, 0, 0, 128)
surface_DrawRect(0, 0, w, h)
end
return wrapper
end)