gmod-addons/addons/screenshot_editor/lua/vgui/dscreenshoteditor.lua

564 lines
17 KiB
Lua

local PANEL = {}
local BLUR_MATERIAL = Material("pp/blurscreen")
local BUTTON_COLOR_NORMAL = Color(50, 50, 50, 200)
local BUTTON_COLOR_HOVER = Color(70, 70, 70, 200)
local BUTTON_COLOR_DOWN = Color(90, 90, 90, 200)
local BUTTON_COLOR_DISABLED = Color(30, 30, 30, 200)
local BUTTON_PAINT = function(panel, w, h)
local col = BUTTON_COLOR_NORMAL
if panel.Depressed then
col = BUTTON_COLOR_DOWN
elseif panel:IsHovered() then
col = BUTTON_COLOR_HOVER
end
draw.RoundedBox(8, 0, 0, w, h, col)
end
local BUTTON_COLOR_OUTLINE = Color(0, 0, 0)
local BUTTON_COLOR_OUTLINE_FLASH = Color(0, 0, 0)
local BUTTON_PAINT_OUTLINE = function(panel, w, h)
local col = BUTTON_COLOR_NORMAL
local outlineCol = BUTTON_COLOR_OUTLINE
if panel.Depressed then
col = BUTTON_COLOR_DOWN
elseif panel:IsHovered() then
col = BUTTON_COLOR_HOVER
end
if not panel:IsEnabled() then
col = BUTTON_COLOR_DISABLED
local curBright = math.Remap(math.sin(SysTime() * 5), -1, 1, 50, 80)
BUTTON_COLOR_OUTLINE_FLASH.r = curBright
BUTTON_COLOR_OUTLINE_FLASH.g = curBright
BUTTON_COLOR_OUTLINE_FLASH.b = curBright
outlineCol = BUTTON_COLOR_OUTLINE_FLASH
end
draw.RoundedBox(8, 0, 0, w, h, outlineCol)
draw.RoundedBox(6, 2, 2, w - 4, h - 4, col)
end
surface.CreateFont("ScreenshotEditorLabel", {
font = "Roboto",
size = 16,
weight = 500,
antialias = true,
})
surface.CreateFont("ScreenshotEditorProcessing", {
font = "Roboto",
size = 32,
weight = 500,
antialias = true,
})
surface.CreateFont("ScreenshotEditorArrow", {
font = "Consolas",
size = 24,
weight = 500,
antialias = true
})
function PANEL:Init()
local FILTER_DATA = screenshot_editor.GetFilters()
local FRAME_DATA = screenshot_editor.GetFrames()
local width, height = ScrW(), ScrH()
self:SetSize(width, height)
self:DockPadding(16, 16, 16, 16)
self.CurrentScreenshot = Material("lights/white")
self.CurrentFilter = 0
self.CurrentFrame = 0
self.ShowEditedScreenshots = true
self.SearchFilter = ""
local toggleButtonSize = 32
local controlsBase = vgui.Create("DPanel", self)
controlsBase:SetSize(width * 0.225, height)
controlsBase:AlignLeft(0)
controlsBase:DockPadding(8, 8, 8, 8)
controlsBase.Paint = function(panel, w, h)
w = w - (toggleButtonSize + 16)
-- Blur
render.SetScissorRect(panel:GetX(), 0, w + panel:GetX(), h, true)
local x, y = panel:LocalToScreen(0, 0)
surface.SetDrawColor(255, 255, 255, 255)
surface.SetMaterial(BLUR_MATERIAL)
for i = 0.33, 1, 0.33 do
BLUR_MATERIAL:SetFloat("$blur", 8 * i)
BLUR_MATERIAL:Recompute()
render.UpdateScreenEffectTexture()
surface.DrawTexturedRect(-x, -y, ScrW(), ScrH())
end
render.SetScissorRect(0, 0, 0, 0, false)
-- Darken BG
surface.SetDrawColor(0, 0, 0, 200)
surface.DrawRect(0, 0, w, h)
end
self.ControlsBase = controlsBase
local toggleButtonMargin = (height - 16 - 32) / 2
local toggleControlsButton = vgui.Create("DButton", controlsBase)
toggleControlsButton:DockMargin(16, toggleButtonMargin, 0, toggleButtonMargin)
toggleControlsButton:Dock(RIGHT)
toggleControlsButton:SetFont("ScreenshotEditorArrow")
toggleControlsButton:SetText("<")
toggleControlsButton:SetWide(32)
toggleControlsButton:SetTextColor(color_white)
toggleControlsButton:SetTooltip("Hide Controls Menu")
toggleControlsButton.IsHidden = false
toggleControlsButton.Paint = BUTTON_PAINT
toggleControlsButton.DoClick = function(panel)
panel.IsHidden = not panel.IsHidden
local xPos = panel.IsHidden and -self.ControlsBase:GetWide() + (toggleButtonSize + 16) or 0
self.ControlsBase:MoveTo(xPos, 0, 0.5, 0, 0.5)
panel:SetText(panel.IsHidden and ">" or "<")
panel:SetTooltip(panel.IsHidden and "Show Controls Menu" or "Hide Controls Menu")
end
--[[
Filter control
]]
local filterTall = 48
local filterPadding = 4
local filterBase = vgui.Create("DPanel", controlsBase)
filterBase:Dock(TOP)
filterBase:DockMargin(0, 0, 0, 8)
filterBase:SetTall(filterTall)
filterBase:DockPadding(filterPadding, filterPadding, filterPadding, filterPadding)
filterBase.Paint = function(panel, w, h)
draw.RoundedBox(8, 0, 0, w, h, Color(0, 0, 0, 240))
end
local filterButtonLeft = vgui.Create("DButton", filterBase)
filterButtonLeft:DockMargin(0, 0, 8, 0)
filterButtonLeft:Dock(LEFT)
filterButtonLeft:SetWide(filterTall - (filterPadding * 2))
filterButtonLeft:SetFont("ScreenshotEditorArrow")
filterButtonLeft:SetText("<")
filterButtonLeft:SetTextColor(color_white)
filterButtonLeft.Paint = BUTTON_PAINT
filterButtonLeft.DoClick = function(panel)
local newFilterIndex = (self.CurrentFilter - 1) % #FILTER_DATA
self:SelectFilter(newFilterIndex)
end
local filterButtonRight = vgui.Create("DButton", filterBase)
filterButtonRight:DockMargin(8, 0, 0, 0)
filterButtonRight:Dock(RIGHT)
filterButtonRight:SetWide(filterTall - (filterPadding * 2))
filterButtonRight:SetFont("ScreenshotEditorArrow")
filterButtonRight:SetText(">")
filterButtonRight:SetTextColor(color_white)
filterButtonRight.Paint = BUTTON_PAINT
filterButtonRight.DoClick = function(panel)
local newFilterIndex = (self.CurrentFilter + 1) % #FILTER_DATA
self:SelectFilter(newFilterIndex)
end
local currentFilterName = vgui.Create("DLabel", filterBase)
currentFilterName:SetFont("ScreenshotEditorLabel")
currentFilterName:SetText("Current Filter: None")
currentFilterName:Dock(FILL)
currentFilterName:SetContentAlignment(5)
currentFilterName:SetMouseInputEnabled(true)
currentFilterName:SetCursor("hand")
currentFilterName.DoClick = function()
local dMenu = DermaMenu()
for index, filterEntryData in ipairs(screenshot_editor.GetFilters()) do
dMenu:AddOption(filterEntryData.FilterName, function()
self:SelectFilter(index - 1)
end)
end
dMenu:Open()
end
self.CurrentFilterLabel = currentFilterName
--[[
Frame control
]]
local frameBase = vgui.Create("DPanel", controlsBase)
frameBase:Dock(TOP)
frameBase:DockMargin(0, 0, 0, 8)
frameBase:SetTall(filterTall)
frameBase:DockPadding(filterPadding, filterPadding, filterPadding, filterPadding)
frameBase.Paint = function(panel, w, h)
draw.RoundedBox(8, 0, 0, w, h, Color(0, 0, 0, 240))
end
local frameButtonLeft = vgui.Create("DButton", frameBase)
frameButtonLeft:DockMargin(0, 0, 8, 0)
frameButtonLeft:Dock(LEFT)
frameButtonLeft:SetWide(filterTall - (filterPadding * 2))
frameButtonLeft:SetFont("ScreenshotEditorArrow")
frameButtonLeft:SetText("<")
frameButtonLeft:SetTextColor(color_white)
frameButtonLeft.Paint = BUTTON_PAINT
frameButtonLeft.DoClick = function(panel)
local newFrameIndex = (self.CurrentFrame - 1) % #FRAME_DATA
self:SelectFrame(newFrameIndex)
end
local frameButtonRight = vgui.Create("DButton", frameBase)
frameButtonRight:DockMargin(8, 0, 0, 0)
frameButtonRight:Dock(RIGHT)
frameButtonRight:SetWide(filterTall - (filterPadding * 2))
frameButtonRight:SetFont("ScreenshotEditorArrow")
frameButtonRight:SetText(">")
frameButtonRight:SetTextColor(color_white)
frameButtonRight.Paint = BUTTON_PAINT
frameButtonRight.DoClick = function(panel)
local newFrameIndex = (self.CurrentFrame + 1) % #FRAME_DATA
self:SelectFrame(newFrameIndex)
end
local currentFrameName = vgui.Create("DLabel", frameBase)
currentFrameName:SetFont("ScreenshotEditorLabel")
currentFrameName:SetText("Current Frame: None")
currentFrameName:Dock(FILL)
currentFrameName:SetContentAlignment(5)
currentFrameName:SetMouseInputEnabled(true)
currentFrameName:SetCursor("hand")
currentFrameName.DoClick = function()
local dMenu = DermaMenu()
for index, frameEntryData in ipairs(screenshot_editor.GetFrames()) do
dMenu:AddOption(frameEntryData.FrameName, function()
self:SelectFrame(index - 1)
end)
end
dMenu:Open()
end
self.CurrentFrameLabel = currentFrameName
--[[
List filters
]]
local showEditedScreenshots = vgui.Create("DCheckBoxLabel", controlsBase)
showEditedScreenshots:DockMargin(0, 0, 0, 8)
showEditedScreenshots:Dock(TOP)
showEditedScreenshots:SetText("Show Edited Screenshots")
showEditedScreenshots:SetValue(true)
showEditedScreenshots.OnChange = function(panel, isChecked)
self.ShowEditedScreenshots = isChecked
self:FilterScreenshotsList()
end
local searchFilter = vgui.Create("DTextEntry", controlsBase)
searchFilter:DockMargin(0, 0, 0, 8)
searchFilter:Dock(TOP)
searchFilter:SetPlaceholderText("Search...")
searchFilter:SetUpdateOnType(true)
searchFilter.OnValueChange = function(panel, text)
self.SearchFilter = text
self:FilterScreenshotsList()
end
--[[
Save & close buttons
]]
local closeButton = vgui.Create("DButton", controlsBase)
closeButton:Dock(BOTTOM)
closeButton:SetTall(32)
closeButton:SetText("Close")
closeButton:SetTextColor(color_white)
closeButton.Paint = BUTTON_PAINT_OUTLINE
closeButton.DoClick = function()
self:Remove()
end
local saveButton = vgui.Create("DButton", controlsBase)
saveButton:Dock(BOTTOM)
saveButton:DockMargin(0, 0, 0, 8)
saveButton:SetTall(32)
saveButton:SetText("Save")
saveButton:SetTextColor(color_white)
saveButton.Paint = BUTTON_PAINT_OUTLINE
saveButton.DoClick = function(panel)
local fileName = game.GetMap() .. "_" .. os.time() .. "_" .. FrameNumber() .. "_edit"
RunConsoleCommand("jpeg", fileName, "100")
timer.Simple(FrameTime(), function()
if IsValid(panel) then
panel:SetText("Screenshot saved!")
end
end)
timer.Simple(3, function()
if IsValid(panel) then
panel:SetText("Save")
end
end)
end
--[[
Refresh screenshots button
]]
local refreshScreenshotsButton = vgui.Create("DButton", controlsBase)
refreshScreenshotsButton:Dock(BOTTOM)
refreshScreenshotsButton:DockMargin(0, 0, 0, 8)
refreshScreenshotsButton:SetTall(32)
refreshScreenshotsButton:SetText("Refresh Screenshots List")
refreshScreenshotsButton:SetTextColor(color_white)
refreshScreenshotsButton.Paint = BUTTON_PAINT_OUTLINE
refreshScreenshotsButton.DoClick = function(panel)
local fcScroll = self.FileScroll
if not IsValid(fcScroll) then return end
panel:SetText("Refreshing Screenshots...")
panel:SetEnabled(false)
fcScroll:Clear()
local processingLabel = vgui.Create("DLabel", fcScroll)
processingLabel:Dock(TOP)
processingLabel:SetText("Processing...")
processingLabel:SetFont("ScreenshotEditorProcessing")
processingLabel:SizeToContentsX()
processingLabel:SetTall(128)
processingLabel:SetContentAlignment(5)
if not screenshot_editor.IsProcessingScreenshots() then
screenshot_editor.ProcessScreenshots()
end
hook.Add("ScreenshotEditorProcessingFinished", "ScreenshotEditorRefreshScreenshots", function()
if IsValid(fcScroll) then
fcScroll:Clear()
end
if IsValid(self) then
self:AddScreenshotsToList()
end
if IsValid(panel) then
panel:SetText("Refresh Screenshots List")
panel:SetEnabled(true)
end
end)
end
--[[
File chooser control
]]
local fcScroll = vgui.Create("DScrollPanel", controlsBase)
fcScroll:DockMargin(0, 0, 0, 8)
fcScroll:Dock(FILL)
--fcScroll:SetTall(height * 0.5)
fcScroll.OnItemSelected = function(panel, item)
panel.VBar:Stop()
panel.VBar:AnimateTo(item:GetY(), 0.3, 0, 0.4)
self.CurrentScreenshot = Material("../screenshots/" .. item.FileName, "smooth")
end
self.FileScroll = fcScroll
controlsBase:SetRenderInScreenshots(false)
self:SetKeyboardInputEnabled(true)
self:Center()
self:MakePopup()
-- In case screenshots are still being processed
if screenshot_editor.IsProcessingScreenshots() then
refreshScreenshotsButton:DoClick()
else
self:AddScreenshotsToList()
end
end
function PANEL:SelectFilter(index)
self.CurrentFilter = index
local filterData = screenshot_editor.GetFilter(self.CurrentFilter + 1)
self.CurrentFilterLabel:SetText("Current Filter: " .. filterData.FilterName)
end
function PANEL:SelectFrame(index)
self.CurrentFrame = index
local frameData = screenshot_editor.GetFrame(self.CurrentFrame + 1)
self.CurrentFrameLabel:SetText("Current Frame: " .. frameData.FrameName)
end
-- Add screenshots to the DListView
function PANEL:AddScreenshotsToList()
local fileScroll = self.FileScroll
if not IsValid(fileScroll) then return end
fileScroll:Clear()
for fileName, fileTime in pairs(screenshot_editor.GetScreenshots()) do
fileName = fileName:Replace("screenshots/", "")
local fileEntry = self.FileScroll:Add("DScreenshotFileEntry")
fileEntry:DockMargin(0, 0, 4, 4)
fileEntry:Dock(TOP)
fileEntry:SetWide(self.ControlsBase:GetWide() - 16)
fileEntry:SetFileName(fileName)
fileEntry:SetDateCreated(fileTime)
fileEntry.LayoutPanel = self.FileScroll
end
local fileEntries = self.FileScroll:GetCanvas():GetChildren()
table.sort(fileEntries, function(a, b)
return (a.FileDateCreated or 0) > (b.FileDateCreated or 0)
end)
for index, fileEntry in ipairs(fileEntries) do
if fileEntry:GetName() ~= "DScreenshotFileEntry" then continue end
if index == 1 then
fileEntry:OnMouseReleased(MOUSE_LEFT)
end
fileEntry:SetZPos(index)
end
self:FilterScreenshotsList()
end
function PANEL:FilterScreenshotsList()
local showEdited = self.ShowEditedScreenshots
local fileScrollCanvas = self.FileScroll:GetCanvas()
for _, child in ipairs(fileScrollCanvas:GetChildren()) do
if child:GetName() ~= "DScreenshotFileEntry" then continue end
local fileName = string.StripExtension(child.FileName)
local shouldShow = true
if fileName:EndsWith("_edit") then
shouldShow = shouldShow and showEdited
end
local searchMatched = string.find(fileName:lower(), self.SearchFilter:lower(), nil, true)
shouldShow = shouldShow and searchMatched
child:SetVisible(shouldShow)
end
fileScrollCanvas:InvalidateLayout()
end
function PANEL:PaintScreenshot(width, height)
surface.SetDrawColor(255, 255, 255, 255)
surface.SetMaterial(self.CurrentScreenshot)
surface.DrawTexturedRect(0, 0, width, height)
local currentFilterData = screenshot_editor.GetFilter(self.CurrentFilter + 1)
if currentFilterData and currentFilterData.FilterCallback then
currentFilterData.FilterCallback(width, height, self.CurrentScreenshot)
end
local currentFrameData = screenshot_editor.GetFrame(self.CurrentFrame + 1)
if currentFrameData then
if not currentFrameData.Material then
currentFrameData.Material = Material(currentFrameData.MaterialPath, "smooth mips")
end
render.PushFilterMin(TEXFILTER.ANISOTROPIC)
render.PushFilterMag(TEXFILTER.ANISOTROPIC)
local frameMat = currentFrameData.Material
surface.SetMaterial(frameMat)
surface.DrawTexturedRect(0, 0, width, height)
render.PopFilterMin()
render.PopFilterMag()
end
end
function PANEL:Paint(width, height)
surface.SetDrawColor(20, 20, 20, 255)
surface.DrawRect(0, 0, width, height)
self:PaintScreenshot(width, height)
end
function PANEL:OnKeyCodePressed(keyCode)
local pressedUpKey = (keyCode == KEY_W) or (keyCode == KEY_UP)
local pressedDownKey = (keyCode == KEY_S) or (keyCode == KEY_DOWN)
if pressedUpKey or pressedDownKey then
local selectedLine = 1
local fileEntries = self.FileScroll:GetCanvas():GetChildren()
for index, line in ipairs(fileEntries) do
if line.Targeted then
selectedLine = index
break
end
end
local lineIdToSelect = selectedLine
-- Bit of a weird workaround to deal with entries that aren't visible
for i = selectedLine + (pressedUpKey and -1 or 1), (pressedUpKey and 0 or #fileEntries), (pressedUpKey and -1 or 1) do
local iLine = fileEntries[i]
if IsValid(iLine) and iLine:IsVisible() then
lineIdToSelect = i
break
end
end
if selectedLine ~= lineIdToSelect then
local lineToSelect = fileEntries[lineIdToSelect]
if IsValid(lineToSelect) then
lineToSelect:OnMouseReleased(MOUSE_LEFT)
end
end
end
end
derma.DefineControl("DScreenshotEditor", "Screenshot Editor", PANEL, "EditablePanel")