383 lines
9.7 KiB
Lua
383 lines
9.7 KiB
Lua
|
gmpanel.actions = gmpanel.actions or {}
|
|||
|
gmpanel.actions.available = gmpanel.actions.available or {}
|
|||
|
gmpanel.actions.added = gmpanel.actions.added or {}
|
|||
|
|
|||
|
pcall(function()
|
|||
|
local f = file.Read('gmpanel_actions.dat')
|
|||
|
if f then gmpanel.actions.added = pon.decode(f) or {} end
|
|||
|
end)
|
|||
|
|
|||
|
local pan, pAvailable, settings, active, right
|
|||
|
|
|||
|
local colors = CFG.skinColors
|
|||
|
local function addedLinePaint(self, w, h)
|
|||
|
local off, off2 = 0, 0
|
|||
|
if IsValid(settings) and settings.editUid == self.uid then
|
|||
|
draw.RoundedBox(4, 0, 0, w, h, colors.g)
|
|||
|
off, off2 = 1, 2
|
|||
|
end
|
|||
|
if self.sel then
|
|||
|
draw.RoundedBox(4, off, off, w - off2, h - off2, Color(170,119,102))
|
|||
|
elseif self.id % 2 == 1 then
|
|||
|
draw.RoundedBox(4, off, off, w - off2, h - off2, Color(0,0,0, 35))
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
local function addedLineSelect(self)
|
|||
|
for _,v in ipairs(active:GetChildren()) do
|
|||
|
v.sel = nil
|
|||
|
end
|
|||
|
self.sel = true
|
|||
|
end
|
|||
|
|
|||
|
local function onModified(self)
|
|||
|
local byUid = {}
|
|||
|
for _,v in ipairs(gmpanel.actions.added) do
|
|||
|
byUid[v.uid] = v
|
|||
|
end
|
|||
|
gmpanel.actions.added = {}
|
|||
|
for _,v in ipairs(self:GetChildren()) do
|
|||
|
gmpanel.actions.added[#gmpanel.actions.added + 1] = byUid[v.uid]
|
|||
|
v.sel = v.uid == settings.editUid or nil
|
|||
|
end
|
|||
|
gmpanel.actions.save()
|
|||
|
end
|
|||
|
|
|||
|
local function addedLineClick(self, mcode)
|
|||
|
|
|||
|
if isfunction(self.oldMP) then self:oldMP(mcode) end
|
|||
|
if mcode ~= MOUSE_RIGHT then return end
|
|||
|
|
|||
|
self:Select()
|
|||
|
|
|||
|
local saved = gmpanel.actions.added[self.id]
|
|||
|
if not saved then return end
|
|||
|
|
|||
|
local menu = DermaMenu()
|
|||
|
|
|||
|
menu:AddOption('Экспортировать', function()
|
|||
|
local data = table.Copy(saved)
|
|||
|
data.uid = nil
|
|||
|
SetClipboardText(pon.encode(data))
|
|||
|
octolib.notify.show('Код действия скопирован в буфер обмена')
|
|||
|
end):SetIcon(octolib.icons.silk16('page_go'))
|
|||
|
|
|||
|
menu:AddOption('Редактировать', function()
|
|||
|
|
|||
|
if not IsValid(settings) then return end
|
|||
|
|
|||
|
local action = gmpanel.actions.available[saved.id]
|
|||
|
if not action then return end
|
|||
|
|
|||
|
pAvailable.dirty = true
|
|||
|
pAvailable:ClearSelection()
|
|||
|
for _,v in ipairs(pAvailable:GetLines()) do
|
|||
|
if v.id == saved.id then
|
|||
|
pAvailable:SelectItem(v)
|
|||
|
break
|
|||
|
end
|
|||
|
end
|
|||
|
pAvailable.dirty = nil
|
|||
|
|
|||
|
settings:Clear()
|
|||
|
action.openSettings(settings, saved)
|
|||
|
settings.editUid = self.uid
|
|||
|
gmpanel.actions.insertButtons(saved.id, saved)
|
|||
|
|
|||
|
end):SetIcon('octoteam/icons-16/pencil.png')
|
|||
|
|
|||
|
menu:AddOption('Удалить', function()
|
|||
|
gmpanel.actions.editAction(self.uid)
|
|||
|
end):SetIcon('octoteam/icons-16/cross.png')
|
|||
|
menu:Open()
|
|||
|
|
|||
|
end
|
|||
|
|
|||
|
local function rebuildAdded()
|
|||
|
if not IsValid(pan) then return end
|
|||
|
if IsValid(right) then right:Remove() end
|
|||
|
right = pan:Add('DPanel')
|
|||
|
right:Dock(RIGHT)
|
|||
|
right:SetWide(150)
|
|||
|
right:SetPaintBackground(false)
|
|||
|
active = octolib.label(right, 'Заготовленные действия')
|
|||
|
active:DockMargin(0, 0, 0, 5)
|
|||
|
active:SetContentAlignment(5)
|
|||
|
|
|||
|
active = right:Add('DScrollPanel')
|
|||
|
active:Dock(FILL)
|
|||
|
active:DockMargin(5, 0, 0, 0)
|
|||
|
active = active:Add('DListLayout')
|
|||
|
active:Dock(FILL)
|
|||
|
active:MakeDroppable('gmpanel.actions.added')
|
|||
|
|
|||
|
function active:AddPanel(i, data)
|
|||
|
local cont = self:Add('DPanel')
|
|||
|
cont:SetTall(20)
|
|||
|
cont.Paint = addedLinePaint
|
|||
|
cont:SetMouseInputEnabled(true)
|
|||
|
cont.id = i
|
|||
|
cont.uid = data.uid
|
|||
|
cont.oldMP, cont.OnMouseReleased, cont.Select = cont.OnMouseReleased, addedLineClick, addedLineSelect
|
|||
|
|
|||
|
local icon = cont:Add('DImage')
|
|||
|
icon:Dock(LEFT)
|
|||
|
icon:SetWide(16)
|
|||
|
icon:DockMargin(0, 2, 5, 2)
|
|||
|
icon:SetImage(data._icon)
|
|||
|
|
|||
|
local name = cont:Add('DLabel')
|
|||
|
name:Dock(FILL)
|
|||
|
name:SetText(data._name)
|
|||
|
|
|||
|
return cont
|
|||
|
end
|
|||
|
|
|||
|
for i,v in ipairs(gmpanel.actions.added) do
|
|||
|
active:AddPanel(i, v)
|
|||
|
end
|
|||
|
active.OnModified = onModified
|
|||
|
|
|||
|
local btnImport = right:Add('DButton')
|
|||
|
btnImport:Dock(BOTTOM)
|
|||
|
btnImport:SetTall(20)
|
|||
|
btnImport:DockMargin(0, 5, 0, 0)
|
|||
|
btnImport:SetText('Импорт действия')
|
|||
|
btnImport:SetIcon(octolib.icons.silk16('page_code'))
|
|||
|
function btnImport:DoClick()
|
|||
|
Derma_StringRequest('Импорт действия', 'Вставь код действия, полученный при экспорте', '', function(inp)
|
|||
|
local succ, data = pcall(pon.decode, inp)
|
|||
|
if not succ or not istable(data) then
|
|||
|
return octolib.notify.show('warning', 'Кажется, код действия поврежден')
|
|||
|
end
|
|||
|
gmpanel.actions.addAction(data.id, data)
|
|||
|
end)
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
gmpanel.actions.save = octolib.func.debounce(function()
|
|||
|
file.Write('gmpanel_actions.dat', pon.encode(gmpanel.actions.added))
|
|||
|
end, 1)
|
|||
|
|
|||
|
function gmpanel.actions.registerAction(id, action)
|
|||
|
gmpanel.actions.available[id] = action
|
|||
|
end
|
|||
|
|
|||
|
function gmpanel.actions.addAction(id, actionData)
|
|||
|
if not id or not gmpanel.actions.available[id] then return end
|
|||
|
actionData.id = id
|
|||
|
actionData.uid = octolib.string.uuid():sub(1, 8)
|
|||
|
gmpanel.actions.added[#gmpanel.actions.added + 1] = actionData
|
|||
|
gmpanel.actions.save()
|
|||
|
rebuildAdded()
|
|||
|
gmpanel.scenarios.updateActions()
|
|||
|
return true
|
|||
|
end
|
|||
|
|
|||
|
function gmpanel.actions.editAction(uid, actionData)
|
|||
|
|
|||
|
if not uid then return end
|
|||
|
local idx
|
|||
|
for i,v in ipairs(gmpanel.actions.added) do
|
|||
|
if v.uid == uid then
|
|||
|
idx = i
|
|||
|
break
|
|||
|
end
|
|||
|
end
|
|||
|
if not idx then return end
|
|||
|
|
|||
|
if not actionData then
|
|||
|
|
|||
|
table.remove(gmpanel.actions.added, idx)
|
|||
|
rebuildAdded()
|
|||
|
|
|||
|
else
|
|||
|
gmpanel.actions.added[idx] = actionData
|
|||
|
if IsValid(active) then
|
|||
|
local cont = active:GetChildren()[idx]
|
|||
|
cont:GetChildren()[1]:SetImage(actionData._icon)
|
|||
|
cont:GetChildren()[2]:SetText(actionData._name)
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
gmpanel.scenarios.updateActions()
|
|||
|
gmpanel.actions.save()
|
|||
|
|
|||
|
end
|
|||
|
|
|||
|
function gmpanel.actions.close()
|
|||
|
if IsValid(pan) then
|
|||
|
pan:Remove()
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
function gmpanel.actions.defaultExecute(dataPassed, players)
|
|||
|
dataPassed = table.Copy(dataPassed)
|
|||
|
local id = dataPassed.id
|
|||
|
dataPassed.id, dataPassed._name, dataPassed._icon = nil
|
|||
|
dataPassed.players = players
|
|||
|
netstream.Start('dbg-event.execute', id, dataPassed)
|
|||
|
end
|
|||
|
|
|||
|
function gmpanel.actions.insertButtons(id, data)
|
|||
|
|
|||
|
if not (id and gmpanel.actions.available[id]) then return end
|
|||
|
local action = gmpanel.actions.available[id]
|
|||
|
data = data or {}
|
|||
|
|
|||
|
octolib.button(settings, 'Тест', function()
|
|||
|
|
|||
|
local func = action.execute or gmpanel.actions.defaultExecute
|
|||
|
|
|||
|
local data
|
|||
|
if isfunction(action.getData) then
|
|||
|
data = action.getData(settings)
|
|||
|
else data = {} end
|
|||
|
if data == nil then
|
|||
|
octolib.notify.show('warning', 'Кажется, не все поля заполнены верно')
|
|||
|
return
|
|||
|
end
|
|||
|
data = istable(data) and data or {value = data}
|
|||
|
data.id = id
|
|||
|
data.test = true
|
|||
|
|
|||
|
func(data, {LocalPlayer():SteamID()})
|
|||
|
|
|||
|
end)
|
|||
|
|
|||
|
local btmPan = settings:Add('DPanel')
|
|||
|
btmPan:Dock(BOTTOM)
|
|||
|
btmPan:SetTall(48)
|
|||
|
btmPan:SetPaintBackground(false)
|
|||
|
|
|||
|
local nameCont = btmPan:Add('DPanel')
|
|||
|
nameCont:Dock(LEFT)
|
|||
|
nameCont:SetWide(150)
|
|||
|
nameCont:SetPaintBackground(false)
|
|||
|
|
|||
|
octolib.label(nameCont, 'Кнопка:')
|
|||
|
|
|||
|
local wrapper = nameCont:Add('DPanel')
|
|||
|
wrapper:Dock(FILL)
|
|||
|
wrapper:DockMargin(0, 0, 0, 5)
|
|||
|
|
|||
|
local icon = wrapper:Add('DImageButton')
|
|||
|
icon:Dock(LEFT)
|
|||
|
icon:DockMargin(2, 4, 2, 4)
|
|||
|
icon:SetSize(16, 16)
|
|||
|
icon:SetIcon(data._icon or 'icon16/control_play.png')
|
|||
|
function icon:DoClick()
|
|||
|
octolib.icons.picker(function(val)
|
|||
|
self:SetImage(val)
|
|||
|
end, 'materials/' .. self:GetImage(), 'materials/icon16/')
|
|||
|
end
|
|||
|
|
|||
|
local name = wrapper:Add('DTextEntry')
|
|||
|
name:Dock(FILL)
|
|||
|
name:SetPaintBackground(false)
|
|||
|
name:SetTextColor(color_white)
|
|||
|
name:SetValue(data._name or '')
|
|||
|
|
|||
|
local b = btmPan:Add('DPanel')
|
|||
|
b:Dock(RIGHT)
|
|||
|
b:DockMargin(0, 0, 0, 5)
|
|||
|
b:SetPaintBackground(false)
|
|||
|
b:SetWide(100)
|
|||
|
b = b:Add('DButton')
|
|||
|
b:Dock(BOTTOM)
|
|||
|
b:SetTall(30)
|
|||
|
b:SetText(settings.editUid and 'Сохранить' or 'Добавить')
|
|||
|
b:SetIcon('icon16/folder.png')
|
|||
|
function b:DoClick()
|
|||
|
|
|||
|
if string.Trim(name:GetValue()) == '' then
|
|||
|
octolib.notify.show('Пожалуйста, добавь название действия. Тебе так будет проще')
|
|||
|
return
|
|||
|
end
|
|||
|
|
|||
|
local data
|
|||
|
if isfunction(action.getData) then
|
|||
|
data = action.getData(settings)
|
|||
|
else data = {} end
|
|||
|
if data == nil then
|
|||
|
octolib.notify.show('warning', 'Кажется, не все поля заполнены верно')
|
|||
|
return
|
|||
|
end
|
|||
|
data = istable(data) and data or {value = data}
|
|||
|
data._name, data._icon = name:GetValue(), icon:GetImage()
|
|||
|
|
|||
|
if settings.editUid then
|
|||
|
data.id = id
|
|||
|
data.uid = settings.editUid
|
|||
|
gmpanel.actions.editAction(settings.editUid, data)
|
|||
|
else gmpanel.actions.addAction(id, data) end
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
hook.Add('gmpanel.populateActionsMenu', 'gmpanel.actions', function(menu, players)
|
|||
|
|
|||
|
for _,v in ipairs(gmpanel.actions.added) do
|
|||
|
|
|||
|
local action = gmpanel.actions.available[v.id]
|
|||
|
if action then
|
|||
|
menu:AddOption(v._name, function()
|
|||
|
local func = action.execute or gmpanel.actions.defaultExecute
|
|||
|
func(v, players)
|
|||
|
end):SetIcon(v._icon)
|
|||
|
end
|
|||
|
|
|||
|
end
|
|||
|
|
|||
|
menu:AddSpacer()
|
|||
|
|
|||
|
end)
|
|||
|
|
|||
|
local function build()
|
|||
|
gmpanel.actions.close()
|
|||
|
|
|||
|
pan = vgui.Create('DFrame')
|
|||
|
pan:SetSize(700, 500)
|
|||
|
pan:SetTitle('Действия')
|
|||
|
pan:Center()
|
|||
|
pan:MakePopup()
|
|||
|
pan:SetDeleteOnClose(true)
|
|||
|
|
|||
|
pAvailable = pan:Add('DListView')
|
|||
|
pAvailable:Dock(LEFT)
|
|||
|
pAvailable:SetWide(175)
|
|||
|
pAvailable:SetHideHeaders(true)
|
|||
|
pAvailable:DockMargin(0, 0, 5, 0)
|
|||
|
pAvailable:AddColumn(''):SetFixedWidth(32)
|
|||
|
pAvailable:AddColumn(L.title)
|
|||
|
pAvailable:SetDataHeight(32)
|
|||
|
pAvailable:SetMultiSelect(false)
|
|||
|
|
|||
|
for k,v in pairs(gmpanel.actions.available) do
|
|||
|
local icon = vgui.Create('DImage')
|
|||
|
icon:SetImage(v.icon)
|
|||
|
pAvailable:AddLine(icon, v.name).id = k
|
|||
|
end
|
|||
|
|
|||
|
settings = pan:Add('DPanel')
|
|||
|
settings:Dock(FILL)
|
|||
|
settings:DockPadding(5, 5, 5, 5)
|
|||
|
|
|||
|
function pAvailable:OnRowSelected(_, row)
|
|||
|
if self.dirty then return end
|
|||
|
for _,v in ipairs(active:GetChildren()) do
|
|||
|
v.sel = nil
|
|||
|
end
|
|||
|
settings:Clear()
|
|||
|
gmpanel.actions.available[row.id].openSettings(settings, {})
|
|||
|
settings.editUid = nil
|
|||
|
gmpanel.actions.insertButtons(row.id, {})
|
|||
|
end
|
|||
|
|
|||
|
rebuildAdded()
|
|||
|
|
|||
|
end
|
|||
|
|
|||
|
function gmpanel.actions.open()
|
|||
|
build()
|
|||
|
end
|