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
cbox.chatbox = cbox.chatbox or {}
cbox.chatbox.tabs = cbox.chatbox.tabs or {}
cbox.chatbox.panels = cbox.chatbox.panels 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_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
---@return number
local function _ScreenScaleH(height)
@ -59,19 +61,6 @@ local function GetDefaultBounds()
return ScreenScaleH(10), ScreenScaleH(275), ScreenScaleH(320), ScreenScaleH(120)
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
---@param key string Internal unique name
---@param name string Display name
@ -148,13 +137,12 @@ local function CreateChatbox()
frame:SetDeleteOnClose(false)
frame:SetSizable(true)
frame:SetScreenLock(true)
frame:DockPadding(8, 8, 8, 8)
frame:DockPadding(16, 20, 16, 12)
local dx, dy, dw, dh = GetDefaultBounds()
-- TODO: make this configurable
frame:SetMinWidth(dw)
frame:SetMinHeight(dh)
frame:SetMinWidth(math.min(256, dw))
frame:SetMinHeight(math.min(128, dh))
local x = frame:GetCookie("pos_x", dx)
local y = frame:GetCookie("pos_y", dy)
@ -213,6 +201,53 @@ local function CreateChatbox()
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)
local alpha = CHATBOX_ALPHA:GetInt()
@ -279,61 +314,127 @@ local function CreateChatbox()
cbox.chatbox.panels.frame = frame
local tabs = vgui.Create("DPropertySheet", frame, "cbox.chatbox.tabs")
tabs:Dock(FILL)
tabs:SetPadding(0)
local wrapper = vgui.Create("EditablePanel", frame)
wrapper:Dock(FILL)
function tabs:Paint(w, h) end
function tabs:OnActiveTabChanged( old, new )
if new:GetPanel().cbox_id == "\1chat" then
cbox.chatbox.panels.input:RequestFocus()
-- 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
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 function catch(err)
cbox.utils.RealmError(("Failed to create tab %q:"):format(id), err)
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 ok, ret = xpcall(tab.callback, catch)
if not ok then continue end
if not ispanel(ret) then
cbox.utils.RealmError(("Got non-panel for tab %q!"):format(id))
continue
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
local sheet = tabs:AddSheet(tab.name, ret, tab.icon)
sheet.Panel.cbox_id = id
self.current_mode = mode
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
if self.Image then
ExtraInset = ExtraInset + self.Image:GetWide()
end
self:SetTextInset(ExtraInset, 2)
self:SetTextInset(ExtraInset, 0)
local w, h = self:GetContentSize()
h = self:GetTabHeight()
self:SetSize(w + 8, h)
self:SetSize(w + 8, 20)
DLabel.ApplySchemeSettings(self)
end
-- TODO: configurable font
sheet.Tab:SetFont("ChatFont")
mode_switch:SetFont("ChatFont")
mode_switch:UpdateMode("say")
function sheet.Tab:Paint(w, h)
if self:IsActive() then
surface_SetDrawColor(0, 0, 0, 128)
surface_DrawRect(0, 0, w, 20)
else
surface_SetDrawColor(0, 0, 0, 64)
surface_DrawRect(0, 2, w, 18)
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 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
@ -341,12 +442,6 @@ end
local function Init()
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
CreateChatbox()
end
@ -359,6 +454,7 @@ local function Init()
end
if bind ~= "messagemode" and bind ~= "messagemode2" 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")
@ -395,7 +491,7 @@ function cbox.chatbox.Open(alt)
frame:MakePopup()
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
if IsValid(frame) then
frame:Remove()
@ -403,8 +499,8 @@ function cbox.chatbox.Open(alt)
Init()
end
if not IsValid(cbox.chatbox.panels.input) or not IsValid(cbox.chatbox.panels.tabs) then
cbox.utils.RealmError("Input or tabs aren't valid, chat tab failed to load, bailing!")
if not IsValid(cbox.chatbox.panels.input) or not IsValid(cbox.chatbox.panels.history) then
cbox.utils.RealmError("Input or history aren't valid, chat failed to load, bailing!")
if IsValid(frame) then
frame:Remove()
end
@ -412,20 +508,20 @@ function cbox.chatbox.Open(alt)
return
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()
if IsValid(cbox.chatbox.panels.mode_switch) then
if alt then
cbox.chatbox.panels.mode_switch:UpdateMode(CHATBOX_MODE2:GetString())
else
cbox.chatbox.panels.mode_switch:UpdateMode(CHATBOX_MODE1:GetString())
local mode1 = CHATBOX_MODE1:GetString()
local mode2 = CHATBOX_MODE2:GetString()
if not cbox.chatbox.modes[mode1] then
mode1 = "say"
end
if not cbox.chatbox.modes[mode2] then
mode2 = "say_team"
end
cbox.chatbox.panels.mode_switch:UpdateMode(alt and mode2 or mode1)
end
hook.Run("StartChat")
@ -457,10 +553,47 @@ end
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()
CreateChatbox()
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()
if IsValid(cbox.chatbox.panels.frame) then
cbox.chatbox.panels.frame:Remove()

View file

@ -7,6 +7,13 @@ cbox.chatbox.AddMode("say_team", "Team", function(text)
end)
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)
LocalPlayer():ChatPrint("Failed to run command: " .. err)
end

View file

@ -8,11 +8,6 @@ if SERVER then
AddCSLuaFile("cbox/cl_hooks.lua")
AddCSLuaFile("cbox/cl_chatbox.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
include("cbox/cl_hooks.lua")
include("cbox/cl_chatbox.lua")

View file

@ -14,8 +14,8 @@ local color_black = Color(0, 0, 0)
local utils = {}
utils.colors = {
BRAND = Color(132, 206, 181),
CLIENT = Color(143, 218, 230),
SERVER = Color(230, 218, 112),
CLIENT = Color(230, 218, 112),
SERVER = Color(143, 218, 230),
SHARED = Color(93, 200, 92 ),
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)