Compare commits

...

2 commits

6 changed files with 222 additions and 255 deletions

View file

@ -33,7 +33,6 @@ local surface_SetDrawColor = surface.SetDrawColor
local surface_SetMaterial = surface.SetMaterial local surface_SetMaterial = surface.SetMaterial
cbox.chatbox = cbox.chatbox or {} cbox.chatbox = cbox.chatbox or {}
cbox.chatbox.tabs = cbox.chatbox.tabs or {}
cbox.chatbox.panels = cbox.chatbox.panels or {} cbox.chatbox.panels = cbox.chatbox.panels or {}
cbox.chatbox.modes = cbox.chatbox.modes or {} cbox.chatbox.modes = cbox.chatbox.modes or {}
@ -44,6 +43,9 @@ local CHATBOX_FADE = CreateClientConVar("cbox_chatbox_fade", "1", true, false, "
local CHATBOX_MODE1 = CreateClientConVar("cbox_chatbox_mode1", "say", true, false, "Default mode when pressing messagemode") local CHATBOX_MODE1 = CreateClientConVar("cbox_chatbox_mode1", "say", true, false, "Default mode when pressing messagemode")
local CHATBOX_MODE2 = CreateClientConVar("cbox_chatbox_mode2", "say_team", true, false, "Default mode when pressing messagemode2") local CHATBOX_MODE2 = CreateClientConVar("cbox_chatbox_mode2", "say_team", true, false, "Default mode when pressing messagemode2")
local INPUT_TEXT_COLOR = Color(221, 221, 221)
local INPUT_HIGHLIGHT_COLOR = Color(192, 28, 0, 140)
---@param height number ---@param height number
---@return number ---@return number
local function _ScreenScaleH(height) local function _ScreenScaleH(height)
@ -59,19 +61,6 @@ local function GetDefaultBounds()
return ScreenScaleH(10), ScreenScaleH(275), ScreenScaleH(320), ScreenScaleH(120) return ScreenScaleH(10), ScreenScaleH(275), ScreenScaleH(320), ScreenScaleH(120)
end end
---Add a new chatbox tab
---@param key string Internal unique name
---@param name string Display name
---@param icon string Path to icon
---@param callback fun(): Panel What to do when the tab is created
function cbox.chatbox.AddTab(key, name, icon, callback)
cbox.chatbox.tabs[key] = {
name = name,
icon = icon,
callback = callback,
}
end
---Add a new chatbox send mode ---Add a new chatbox send mode
---@param key string Internal unique name ---@param key string Internal unique name
---@param name string Display name ---@param name string Display name
@ -148,13 +137,12 @@ local function CreateChatbox()
frame:SetDeleteOnClose(false) frame:SetDeleteOnClose(false)
frame:SetSizable(true) frame:SetSizable(true)
frame:SetScreenLock(true) frame:SetScreenLock(true)
frame:DockPadding(8, 8, 8, 8) frame:DockPadding(16, 20, 16, 12)
local dx, dy, dw, dh = GetDefaultBounds() local dx, dy, dw, dh = GetDefaultBounds()
-- TODO: make this configurable frame:SetMinWidth(math.min(256, dw))
frame:SetMinWidth(dw) frame:SetMinHeight(math.min(128, dh))
frame:SetMinHeight(dh)
local x = frame:GetCookie("pos_x", dx) local x = frame:GetCookie("pos_x", dx)
local y = frame:GetCookie("pos_y", dy) local y = frame:GetCookie("pos_y", dy)
@ -213,6 +201,53 @@ local function CreateChatbox()
end end
end end
function frame:OnMousePressed(button)
local screenX, screenY = self:LocalToScreen( 0, 0 )
if self.m_bSizable and gui.MouseX() > (screenX + self:GetWide() - 20) and gui.MouseY() > (screenY + self:GetTall() - 20) then
self.Sizing = {gui.MouseX() - self:GetWide(), gui.MouseY() - self:GetTall()}
self:MouseCapture(true)
return
end
if self:GetDraggable() and gui.MouseY() < (screenY + 16) then
if button == MOUSE_LEFT then
self.Dragging = {gui.MouseX() - self.x, gui.MouseY() - self.y}
self:MouseCapture(true)
elseif button == MOUSE_RIGHT then
local menu = DermaMenu()
local settings = menu:AddOption("Settings", function() end)
settings:SetIcon("icon16/cog.png")
local metrics = menu:AddOption("Reset Metrics", function()
RunConsoleCommand("cbox_chatbox_reset_metrics")
if IsValid(cbox.chatbox.panels.input) then
cbox.chatbox.panels.input:RequestFocus()
end
end)
metrics:SetIcon("icon16/arrow_out.png")
menu:AddSpacer()
local reload = menu:AddOption("Reload Chatbox", function()
RunConsoleCommand((input.IsKeyDown(KEY_LSHIFT) or input.IsKeyDown(KEY_RSHIFT)) and "_cbox_chatbox_fullreload" or "cbox_chatbox_reload")
end)
reload:SetIcon("icon16/arrow_refresh.png")
menu:AddSpacer()
local close = menu:AddOption("Close", function()
cbox.chatbox.Close()
end)
close:SetIcon("icon16/cross.png")
menu:Open()
end
return
end
end
function frame:Paint(w, h) function frame:Paint(w, h)
local alpha = CHATBOX_ALPHA:GetInt() local alpha = CHATBOX_ALPHA:GetInt()
@ -279,61 +314,127 @@ local function CreateChatbox()
cbox.chatbox.panels.frame = frame cbox.chatbox.panels.frame = frame
local tabs = vgui.Create("DPropertySheet", frame, "cbox.chatbox.tabs") local wrapper = vgui.Create("EditablePanel", frame)
tabs:Dock(FILL) wrapper:Dock(FILL)
tabs:SetPadding(0)
function tabs:Paint(w, h) end -- TODO: custom richtext panel
local history = vgui.Create("RichText", wrapper)
function tabs:OnActiveTabChanged( old, new ) history:Dock(FILL)
if new:GetPanel().cbox_id == "\1chat" then function history:Paint(w, h)
cbox.chatbox.panels.input:RequestFocus() surface_SetDrawColor(0, 0, 0, 128)
surface_DrawRect(0, 0, w, h)
end end
cbox.chatbox.panels.history = history
function history:PerformLayout()
-- TODO: configurable font
history:SetFontInternal("ChatFont")
end end
cbox.chatbox.panels.tabs = tabs local input_wrapper = vgui.Create("EditablePanel", wrapper)
input_wrapper:SetHeight(20)
input_wrapper:DockMargin(0, 8, 0, 0)
input_wrapper:Dock(BOTTOM)
for id, tab in next, cbox.chatbox.tabs do local input = vgui.Create("DTextEntry", input_wrapper)
local function catch(err) input:DockMargin(4, 0, 0, 0)
cbox.utils.RealmError(("Failed to create tab %q:"):format(id), err) input:Dock(FILL)
input:SetFont("ChatFont")
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 end
local ok, ret = xpcall(tab.callback, catch) local mode_switch = vgui.Create("DButton", input_wrapper)
if not ok then continue end mode_switch:SetTextColor(INPUT_TEXT_COLOR)
if not ispanel(ret) then mode_switch:Dock(LEFT)
cbox.utils.RealmError(("Got non-panel for tab %q!"):format(id)) cbox.chatbox.panels.mode_switch = mode_switch
continue
function mode_switch:UpdateMode(mode)
local mode_data = cbox.chatbox.modes[mode]
if not mode_data then
self.current_mode = "say"
mode_data = cbox.chatbox.modes.say
end end
local sheet = tabs:AddSheet(tab.name, ret, tab.icon) self.current_mode = mode
sheet.Panel.cbox_id = id self:SetText(mode_data.name .. ":")
end
function sheet.Tab:ApplySchemeSettings() function mode_switch:Paint(w, h)
surface_SetDrawColor(0, 0, 0, 128)
surface_DrawRect(0, 0, w, h)
end
function mode_switch:ApplySchemeSettings()
local ExtraInset = 8 local ExtraInset = 8
if self.Image then self:SetTextInset(ExtraInset, 0)
ExtraInset = ExtraInset + self.Image:GetWide()
end
self:SetTextInset(ExtraInset, 2)
local w, h = self:GetContentSize() local w, h = self:GetContentSize()
h = self:GetTabHeight()
self:SetSize(w + 8, h) self:SetSize(w + 8, 20)
DLabel.ApplySchemeSettings(self) DLabel.ApplySchemeSettings(self)
end end
-- TODO: configurable font mode_switch:SetFont("ChatFont")
sheet.Tab:SetFont("ChatFont") mode_switch:UpdateMode("say")
function sheet.Tab:Paint(w, h) function mode_switch:NextMode()
if self:IsActive() then local keys = table.GetKeys(cbox.chatbox.modes)
surface_SetDrawColor(0, 0, 0, 128) table.sort(keys)
surface_DrawRect(0, 0, w, 20)
else local _, next_mode = next(keys, table.KeyFromValue(keys, self.current_mode))
surface_SetDrawColor(0, 0, 0, 64) if not next_mode then next_mode = keys[1] end
surface_DrawRect(0, 2, w, 18)
self:UpdateMode(next_mode)
end end
function mode_switch:DoClick()
self:NextMode()
end
function mode_switch:DoRightClick()
local menu = DermaMenu()
for mode, data in next, cbox.chatbox.modes do
menu:AddOption(data.name, function()
self:UpdateMode(mode)
end)
end
menu:Open()
end
function input:OnKeyCodeTyped(key)
--[[if key == KEY_ESCAPE then
cbox.chatbox.Close()
gui.HideGameUI()
else--]]
if key == KEY_BACKQUOTE then
gui.HideGameUI()
elseif key == KEY_ENTER then
local text = self:GetText():Trim()
if text ~= "" then
cbox.chatbox.modes[mode_switch.current_mode].callback(text)
end
cbox.chatbox.Close()
elseif key == KEY_TAB then
if #self:GetText() == 0 then
mode_switch:NextMode()
else
local tab_text = hook.Run("OnChatTab", self:GetText())
self:SetText(tab_text)
end
timer.Simple(0, function()
self:RequestFocus()
self:SetCaretPos(self:GetText():len())
end)
else
hook.Run("ChatTextChanged", self:GetText())
end end
end end
end end
@ -341,12 +442,6 @@ end
local function Init() local function Init()
include("cbox/cl_modes.lua") include("cbox/cl_modes.lua")
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
if not IsValid(cbox.chatbox.panels.frame) then if not IsValid(cbox.chatbox.panels.frame) then
CreateChatbox() CreateChatbox()
end end
@ -359,6 +454,7 @@ local function Init()
end end
if bind ~= "messagemode" and bind ~= "messagemode2" then return end if bind ~= "messagemode" and bind ~= "messagemode2" then return end
if not pressed then return end if not pressed then return end
if input.IsKeyDown(KEY_LALT) or input.IsKeyDown(KEY_RALT) then return end
cbox.chatbox.Open(bind == "messagemode2") cbox.chatbox.Open(bind == "messagemode2")
@ -395,7 +491,7 @@ function cbox.chatbox.Open(alt)
frame:MakePopup() frame:MakePopup()
end end
if not IsValid(cbox.chatbox.panels.input) or not IsValid(cbox.chatbox.panels.tabs) then if not IsValid(cbox.chatbox.panels.input) or not IsValid(cbox.chatbox.panels.history) then
-- attempt to reinit -- attempt to reinit
if IsValid(frame) then if IsValid(frame) then
frame:Remove() frame:Remove()
@ -403,8 +499,8 @@ function cbox.chatbox.Open(alt)
Init() Init()
end end
if not IsValid(cbox.chatbox.panels.input) or not IsValid(cbox.chatbox.panels.tabs) then if not IsValid(cbox.chatbox.panels.input) or not IsValid(cbox.chatbox.panels.history) then
cbox.utils.RealmError("Input or tabs aren't valid, chat tab failed to load, bailing!") cbox.utils.RealmError("Input or history aren't valid, chat failed to load, bailing!")
if IsValid(frame) then if IsValid(frame) then
frame:Remove() frame:Remove()
end end
@ -412,20 +508,20 @@ function cbox.chatbox.Open(alt)
return return
end end
for _, tab in ipairs(cbox.chatbox.panels.tabs:GetItems()) do
if tab.Panel.cbox_id == "\1chat" and cbox.chatbox.panels.tabs:GetActiveTab() ~= tab.Tab then
cbox.chatbox.panels.tabs:SetActiveTab(tab.Tab)
end
end
cbox.chatbox.panels.input:RequestFocus() cbox.chatbox.panels.input:RequestFocus()
if IsValid(cbox.chatbox.panels.mode_switch) then if IsValid(cbox.chatbox.panels.mode_switch) then
if alt then local mode1 = CHATBOX_MODE1:GetString()
cbox.chatbox.panels.mode_switch:UpdateMode(CHATBOX_MODE2:GetString()) local mode2 = CHATBOX_MODE2:GetString()
else
cbox.chatbox.panels.mode_switch:UpdateMode(CHATBOX_MODE1:GetString()) if not cbox.chatbox.modes[mode1] then
mode1 = "say"
end end
if not cbox.chatbox.modes[mode2] then
mode2 = "say_team"
end
cbox.chatbox.panels.mode_switch:UpdateMode(alt and mode2 or mode1)
end end
hook.Run("StartChat") hook.Run("StartChat")
@ -457,10 +553,47 @@ end
hook.Add("Initialize", "cbox.chatbox", Init) hook.Add("Initialize", "cbox.chatbox", Init)
hook.Add("OnChatAddText", "cbox.chatbox.history", function(args)
local history = cbox.chatbox.panels.history
for _, arg in ipairs(args) do
if IsColor(arg) then
history:InsertColorChange(arg.r, arg.g, arg.b, 255)
elseif isstring(arg) then
history:AppendText(arg)
elseif isentity(arg) then
if IsValid(arg) and arg:IsPlayer() then
local col = hook.Run("GetTeamColor", arg)
history:InsertColorChange(col.r, col.g, col.b, 255)
history:AppendText(arg:Name())
else
history:InsertColorChange(160, 160, 160, 255)
history:AppendText("???")
end
end
end
history:AppendText("\n")
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_reset_metrics", function()
if IsValid(cbox.chatbox.panels.frame) then
local frame = cbox.chatbox.panels.frame
local dx, dy, dw, dh = GetDefaultBounds()
frame:SetCookie("pos_x", dx)
frame:SetCookie("pos_y", dy)
frame:SetCookie("width", dw)
frame:SetCookie("height", dh)
frame:SetPos(dx, dy)
frame:SetSize(dw, dh)
end
end, nil, "Resets the metrics (size and position) of the chatbox")
concommand.Add("_cbox_chatbox_fullreload", function() concommand.Add("_cbox_chatbox_fullreload", function()
if IsValid(cbox.chatbox.panels.frame) then if IsValid(cbox.chatbox.panels.frame) then
cbox.chatbox.panels.frame:Remove() cbox.chatbox.panels.frame:Remove()

View file

@ -7,6 +7,13 @@ cbox.chatbox.AddMode("say_team", "Team", function(text)
end) end)
cbox.chatbox.AddMode("cmd", "Console", function(text) cbox.chatbox.AddMode("cmd", "Console", function(text)
cbox.utils.RealmPrint(Format("Running command %q", text))
if IsConCommandBlocked(text) then
LocalPlayer():ChatPrint("Tried to run blocked command.")
return
end
local function catch(err) local function catch(err)
LocalPlayer():ChatPrint("Failed to run command: " .. err) LocalPlayer():ChatPrint("Failed to run command: " .. err)
end end

View file

@ -8,11 +8,6 @@ if SERVER then
AddCSLuaFile("cbox/cl_hooks.lua") AddCSLuaFile("cbox/cl_hooks.lua")
AddCSLuaFile("cbox/cl_chatbox.lua") AddCSLuaFile("cbox/cl_chatbox.lua")
AddCSLuaFile("cbox/cl_modes.lua") AddCSLuaFile("cbox/cl_modes.lua")
local tab_files = file.Find("cbox/tabs/*", "LUA")
for _, name in ipairs(tab_files) do
AddCSLuaFile("cbox/tabs/" .. name)
end
elseif CLIENT then elseif CLIENT then
include("cbox/cl_hooks.lua") include("cbox/cl_hooks.lua")
include("cbox/cl_chatbox.lua") include("cbox/cl_chatbox.lua")

View file

@ -14,8 +14,8 @@ local color_black = Color(0, 0, 0)
local utils = {} local utils = {}
utils.colors = { utils.colors = {
BRAND = Color(132, 206, 181), BRAND = Color(132, 206, 181),
CLIENT = Color(143, 218, 230), CLIENT = Color(230, 218, 112),
SERVER = Color(230, 218, 112), SERVER = Color(143, 218, 230),
SHARED = Color(93, 200, 92 ), SHARED = Color(93, 200, 92 ),
ERROR = Color(255, 90, 90 ), ERROR = Color(255, 90, 90 ),
} }

View file

@ -1,154 +0,0 @@
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()
local wrapper = vgui.Create("EditablePanel")
-- TODO: custom richtext panel
local history = vgui.Create("RichText", wrapper)
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
function history:PerformLayout()
-- TODO: configurable font
history:SetFontInternal("ChatFont")
end
local input_wrapper = vgui.Create("EditablePanel", wrapper)
input_wrapper:SetHeight(20)
input_wrapper:DockMargin(0, 8, 0, 0)
input_wrapper:Dock(BOTTOM)
local input = vgui.Create("DTextEntry", input_wrapper)
input:DockMargin(4, 0, 0, 0)
input:Dock(FILL)
input:SetFont("ChatFont")
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)
mode_switch:SetTextColor(INPUT_TEXT_COLOR)
mode_switch:Dock(LEFT)
cbox.chatbox.panels.mode_switch = mode_switch
function mode_switch:UpdateMode(mode)
local mode_data = cbox.chatbox.modes[mode]
if not mode_data then
self.current_mode = "say"
mode_data = cbox.chatbox.modes.say
end
self.current_mode = mode
self:SetText(mode_data.name)
end
function mode_switch:Paint(w, h)
surface_SetDrawColor(0, 0, 0, 128)
surface_DrawRect(0, 0, w, h)
end
function mode_switch:ApplySchemeSettings()
local ExtraInset = 8
self:SetTextInset(ExtraInset, 0)
local w, h = self:GetContentSize()
self:SetSize(w + 8, 20)
DLabel.ApplySchemeSettings(self)
end
mode_switch:SetFont("ChatFont")
mode_switch:UpdateMode("say")
function mode_switch:NextMode()
local keys = table.GetKeys(cbox.chatbox.modes)
table.sort(keys)
local _, next_mode = next(keys, table.KeyFromValue(keys, self.current_mode))
if not next_mode then next_mode = keys[1] end
self:UpdateMode(next_mode)
end
function mode_switch:DoClick()
self:NextMode()
end
function mode_switch:DoRightClick()
local menu = DermaMenu()
for mode, data in SortedPairs(cbox.chatbox.modes) do
menu:AddOption(data.name, function()
self:UpdateMode(mode)
end)
end
menu:Open()
end
function input:OnKeyCodeTyped(key)
--[[if key == KEY_ESCAPE then
cbox.chatbox.Close()
gui.HideGameUI()
else--]]
if key == KEY_BACKQUOTE then
gui.HideGameUI()
elseif key == KEY_ENTER then
local text = self:GetText():Trim()
if text ~= "" then
cbox.chatbox.modes[mode_switch.current_mode].callback(text)
end
cbox.chatbox.Close()
elseif key == KEY_TAB then
if #self:GetText() == 0 then
mode_switch:NextMode()
else
-- TODO: autocomplete
end
timer.Simple(0, function() self:RequestFocus() end)
else
hook.Run("ChatTextChanged", self:GetText())
end
end
return wrapper
end)
hook.Add("OnChatAddText", "cbox.chatbox.history", function(args)
local history = cbox.chatbox.panels.history
for _, arg in ipairs(args) do
if IsColor(arg) then
history:InsertColorChange(arg.r, arg.g, arg.b, 255)
elseif isstring(arg) then
history:AppendText(arg)
elseif isentity(arg) then
if IsValid(arg) and arg:IsPlayer() then
local col = hook.Run("GetTeamColor", arg)
history:InsertColorChange(col.r, col.g, col.b, 255)
history:AppendText(arg:Name())
else
history:InsertColorChange(160, 160, 160, 255)
history:AppendText("???")
end
end
end
history:AppendText("\n")
end)

View file

@ -1,14 +0,0 @@
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)