SlabDebug.lua 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595
  1. --[[
  2. MIT License
  3. Copyright (c) 2019 Mitchell Davis <coding.jackalope@gmail.com>
  4. Permission is hereby granted, free of charge, to any person obtaining a copy
  5. of this software and associated documentation files (the "Software"), to deal
  6. in the Software without restriction, including without limitation the rights
  7. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. copies of the Software, and to permit persons to whom the Software is
  9. furnished to do so, subject to the following conditions:
  10. The above copyright notice and this permission notice shall be included in all
  11. copies or substantial portions of the Software.
  12. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  13. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  14. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  15. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  16. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  17. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  18. SOFTWARE.
  19. --]]
  20. local Slab = require('Slab')
  21. local DrawCommands = require(SLAB_PATH .. '.Internal.Core.DrawCommands')
  22. local Input = require(SLAB_PATH .. '.Internal.UI.Input')
  23. local Keyboard = require(SLAB_PATH .. '.Internal.Input.Keyboard')
  24. local Mouse = require(SLAB_PATH .. '.Internal.Input.Mouse')
  25. local Region = require(SLAB_PATH .. '.Internal.UI.Region')
  26. local Stats = require(SLAB_PATH .. '.Internal.Core.Stats')
  27. local Style = require(SLAB_PATH .. '.Style')
  28. local Tooltip = require(SLAB_PATH .. '.Internal.UI.Tooltip')
  29. local Window = require(SLAB_PATH .. '.Internal.UI.Window')
  30. local SlabDebug = {}
  31. local SlabDebug_About = 'SlabDebug_About'
  32. local SlabDebug_Mouse = false
  33. local SlabDebug_Keyboard = false
  34. local SlabDebug_Windows = false
  35. local SlabDebug_Regions = false
  36. local SlabDebug_Tooltip = false
  37. local SlabDebug_DrawCommands = false
  38. local SlabDebug_Performance = false
  39. local SlabDebug_StyleEditor = false
  40. local SlabDebug_Input = false
  41. local SlabDebug_MultiLine = false
  42. local SlabDebug_MultiLine_FileDialog = false
  43. local SlabDebug_MultiLine_FileName = ""
  44. local SlabDebug_MultiLine_Contents = ""
  45. local SlabDebug_Windows_Categories = {"Inspector", "Stack"}
  46. local SlabDebug_Windows_Category = "Inspector"
  47. local SlabDebug_Regions_Selected = ""
  48. local Selected_Window = ""
  49. local Style_EditingColor = nil
  50. local Style_ColorStore = nil
  51. local Style_FileDialog = nil
  52. local function Window_Inspector()
  53. local Ids = Window.GetInstanceIds()
  54. if Slab.BeginComboBox('SlabDebug_Windows_Inspector', {Selected = Selected_Window}) then
  55. for I, V in ipairs(Ids) do
  56. if Slab.TextSelectable(V) then
  57. Selected_Window = V
  58. end
  59. end
  60. Slab.EndComboBox()
  61. end
  62. local Info = Window.GetInstanceInfo(Selected_Window)
  63. for I, V in ipairs(Info) do
  64. Slab.Text(V)
  65. end
  66. end
  67. local function Window_Stack()
  68. local Stack = Window.GetStackDebug()
  69. Slab.Text("Stack: " .. #Stack)
  70. for I, V in ipairs(Stack) do
  71. Slab.Text(V)
  72. end
  73. end
  74. local function DrawCommands_Item(Root, Label)
  75. if type(Root) == "table" then
  76. if Slab.BeginTree(Label) then
  77. for K, V in pairs(Root) do
  78. DrawCommands_Item(V, K)
  79. end
  80. Slab.EndTree()
  81. end
  82. else
  83. Slab.BeginTree(Label .. " " .. tostring(Root), {IsLeaf = true})
  84. end
  85. end
  86. local function PrintStatsCategory(Label, Category, Last, AddSeparator)
  87. Slab.BeginColumn(1)
  88. Slab.Text(Label)
  89. if AddSeparator then
  90. Slab.Separator()
  91. end
  92. Slab.EndColumn()
  93. Slab.BeginColumn(2)
  94. Slab.Text(string.format("%.5f", Stats.GetTime(Category, Last)), {CenterX = true})
  95. if AddSeparator then
  96. Slab.Separator()
  97. end
  98. Slab.EndColumn()
  99. Slab.BeginColumn(3)
  100. Slab.Text(Stats.GetCallCount(Category, Last), {CenterX = true})
  101. if AddSeparator then
  102. Slab.Separator()
  103. end
  104. Slab.EndColumn()
  105. end
  106. local function DrawPerformance()
  107. Slab.BeginWindow('SlabDebug_Performance', {Title = "Performance", Columns = 3, AutoSizeWindow = false, W = 450.0, H = 350.0})
  108. Slab.BeginColumn(1)
  109. Slab.Text("Category", {CenterX = true})
  110. Slab.Separator()
  111. Slab.EndColumn()
  112. Slab.BeginColumn(2)
  113. Slab.Text("Time", {CenterX = true})
  114. Slab.Separator()
  115. Slab.EndColumn()
  116. Slab.BeginColumn(3)
  117. Slab.Text("Call Count", {CenterX = true})
  118. Slab.Separator()
  119. Slab.EndColumn()
  120. PrintStatsCategory("Frame Time", 'Frame', true)
  121. PrintStatsCategory("Update Time", 'Update')
  122. PrintStatsCategory("Draw Time", 'Draw', true, true)
  123. PrintStatsCategory("Button Time", 'Button')
  124. PrintStatsCategory("Radio Button Time", 'RadioButton')
  125. PrintStatsCategory("Check Box Time", 'CheckBox')
  126. PrintStatsCategory("Combo Box Time", 'ComboBox')
  127. PrintStatsCategory("Image Time", 'Image')
  128. PrintStatsCategory("Input Time", 'Input')
  129. PrintStatsCategory("List Box Time", 'ListBox')
  130. PrintStatsCategory("Text Time", 'Text')
  131. PrintStatsCategory("Text Formatted Time", 'Textf')
  132. PrintStatsCategory("Tree Time", 'Tree')
  133. PrintStatsCategory("Window Time", 'Window')
  134. Slab.EndWindow()
  135. end
  136. local function EditColor(Color)
  137. Style_EditingColor = Color
  138. Style_ColorStore = {Color[1], Color[2], Color[3], Color[4]}
  139. end
  140. local function DrawStyleColor(Label, Color)
  141. local Style = Slab.GetStyle()
  142. local H = Style.Font:getHeight()
  143. local TextColor = Style.TextColor
  144. if Style_EditingColor == Color then
  145. TextColor = {1.0, 1.0, 0.0, 1.0}
  146. end
  147. Slab.BeginColumn(1)
  148. Slab.Text(Label, {Color = TextColor})
  149. Slab.EndColumn()
  150. Slab.BeginColumn(2)
  151. local ColW, ColH = Slab.GetWindowActiveSize()
  152. local X, Y = Slab.GetCursorPos()
  153. Slab.Rectangle({W = ColW, H = H, Color = Color, Outline = true})
  154. Slab.SetCursorPos(X, Y)
  155. if Slab.Button("", {Invisible = true, W = ColW, H = H}) then
  156. EditColor(Color)
  157. end
  158. Slab.EndColumn()
  159. end
  160. local function DrawStyleValue(Label, Value)
  161. local Style = Slab.GetStyle()
  162. Slab.BeginColumn(1)
  163. Slab.Text(Label)
  164. Slab.EndColumn()
  165. Slab.BeginColumn(2)
  166. local W, H = Slab.GetWindowActiveSize()
  167. if Slab.Input('SlabDebug_Style_' .. Label, {Text = tostring(Value), ReturnOnText = false, NumbersOnly = true, W = W}) then
  168. Style[Label] = Slab.GetInputNumber()
  169. end
  170. Slab.EndColumn()
  171. end
  172. local function DrawStyleEditor()
  173. Slab.BeginWindow('SlabDebug_StyleEditor', {Title = "Style Editor", Columns = 2, AutoSizeWindow = false, AllowResize = true, W = 500.0, H = 400.0})
  174. local Style = Slab.GetStyle()
  175. local Names = Style.API.GetStyleNames()
  176. local CurrentStyle = Style.API.GetCurrentStyleName()
  177. local W, H = Slab.GetWindowActiveSize()
  178. if Slab.BeginComboBox('SlabDebug_StyleEditor_Styles', {W = W, Selected = CurrentStyle}) then
  179. for I, V in ipairs(Names) do
  180. if Slab.TextSelectable(V) then
  181. Style.API.SetStyle(V)
  182. end
  183. end
  184. Slab.EndComboBox()
  185. end
  186. if Slab.Button("New") then
  187. Style_FileDialog = 'new'
  188. end
  189. Slab.SameLine()
  190. if Slab.Button("Load") then
  191. Style_FileDialog = 'load'
  192. end
  193. Slab.SameLine()
  194. local SaveDisabled = Style.API.IsDefaultStyle(CurrentStyle)
  195. if Slab.Button("Save", {Disabled = SaveDisabled}) then
  196. Style.API.SaveCurrentStyle()
  197. end
  198. Slab.Separator()
  199. for K, V in pairs(Style) do
  200. if type(V) == "table" and K ~= "Font" and K ~= "API" then
  201. DrawStyleColor(K, V)
  202. end
  203. end
  204. for K, V in pairs(Style) do
  205. if type(V) == "number" and K ~= "FontSize" then
  206. DrawStyleValue(K, V)
  207. end
  208. end
  209. Slab.EndWindow()
  210. if Style_EditingColor ~= nil then
  211. local Result = Slab.ColorPicker({Color = Style_ColorStore})
  212. Style_EditingColor[1] = Result.Color[1]
  213. Style_EditingColor[2] = Result.Color[2]
  214. Style_EditingColor[3] = Result.Color[3]
  215. Style_EditingColor[4] = Result.Color[4]
  216. if Result.Button ~= "" then
  217. if Result.Button == "OK" then
  218. Style.API.StoreCurrentStyle()
  219. end
  220. if Result.Button == "Cancel" then
  221. Style_EditingColor[1] = Style_ColorStore[1]
  222. Style_EditingColor[2] = Style_ColorStore[2]
  223. Style_EditingColor[3] = Style_ColorStore[3]
  224. Style_EditingColor[4] = Style_ColorStore[4]
  225. end
  226. Style_EditingColor = nil
  227. end
  228. end
  229. if Style_FileDialog ~= nil then
  230. local Type = Style_FileDialog == 'new' and 'savefile' or Style_FileDialog == 'load' and 'openfile' or nil
  231. if Type ~= nil then
  232. local Path = love.filesystem.getRealDirectory(SLAB_PATH) .. "/" .. SLAB_PATH .. "Internal/Resources/Styles"
  233. local Result = Slab.FileDialog({AllowMultiSelect = false, Directory = Path, Type = Type, Filters = {{"*.style", "Styles"}}})
  234. if Result.Button ~= "" then
  235. if Result.Button == "OK" then
  236. if Style_FileDialog == 'new' then
  237. Style.API.CopyCurrentStyle(Result.Files[1])
  238. else
  239. Style.API.LoadStyle(Result.Files[1], true)
  240. end
  241. end
  242. Style_FileDialog = nil
  243. end
  244. else
  245. Style_FileDialog = nil
  246. end
  247. end
  248. end
  249. function SlabDebug.About()
  250. if Slab.BeginDialog(SlabDebug_About, {Title = "About"}) then
  251. Slab.Text("Slab Version: " .. Slab.GetVersion())
  252. Slab.Text("Love Version: " .. Slab.GetLoveVersion())
  253. Slab.NewLine()
  254. if Slab.Button("OK", {AlignRight = true}) then
  255. Slab.CloseDialog()
  256. end
  257. Slab.EndDialog()
  258. end
  259. end
  260. function SlabDebug.OpenAbout()
  261. Slab.OpenDialog(SlabDebug_About)
  262. end
  263. function SlabDebug.Mouse()
  264. Slab.BeginWindow('SlabDebug_Mouse', {Title = "Mouse"})
  265. local X, Y = Mouse.Position()
  266. Slab.Text("X: " .. X)
  267. Slab.Text("Y: " .. Y)
  268. local DeltaX, DeltaY = Mouse.GetDelta()
  269. Slab.Text("Delta X: " .. DeltaX)
  270. Slab.Text("Delta Y: " .. DeltaY)
  271. for I = 1, 3, 1 do
  272. Slab.Text("Button " .. I .. ": " .. (Mouse.IsPressed(I) and "Pressed" or "Released"))
  273. end
  274. Slab.Text("Hot Region: " .. Region.GetHotInstanceId())
  275. Slab.EndWindow()
  276. end
  277. function SlabDebug.Keyboard()
  278. Slab.BeginWindow('SlabDebug_Keyboard', {Title = "Keyboard", Columns = 2})
  279. local Keys = Keyboard.Keys()
  280. for I, V in ipairs(Keys) do
  281. Slab.BeginColumn(1)
  282. Slab.Text(V)
  283. Slab.EndColumn()
  284. Slab.BeginColumn(2)
  285. Slab.Text(tostring(Keyboard.IsDown(V)))
  286. Slab.EndColumn()
  287. end
  288. Slab.EndWindow()
  289. end
  290. function SlabDebug.Windows()
  291. Slab.BeginWindow('SlabDebug_Windows', {Title = "Windows"})
  292. if Slab.BeginComboBox('SlabDebug_Windows_Categories', {Selected = SlabDebug_Windows_Category}) then
  293. for I, V in ipairs(SlabDebug_Windows_Categories) do
  294. if Slab.TextSelectable(V) then
  295. SlabDebug_Windows_Category = V
  296. end
  297. end
  298. Slab.EndComboBox()
  299. end
  300. if SlabDebug_Windows_Category == "Inspector" then
  301. Window_Inspector()
  302. elseif SlabDebug_Windows_Category == "Stack" then
  303. Window_Stack()
  304. end
  305. Slab.EndWindow()
  306. end
  307. function SlabDebug.Regions()
  308. Slab.BeginWindow('SlabDebug_Regions', {Title = "Regions"})
  309. local Ids = Region.GetInstanceIds()
  310. if Slab.BeginComboBox('SlabDebug_Regions_Ids', {Selected = SlabDebug_Regions_Selected}) then
  311. for I, V in ipairs(Ids) do
  312. if Slab.TextSelectable(V) then
  313. SlabDebug_Regions_Selected = V
  314. end
  315. end
  316. Slab.EndComboBox()
  317. end
  318. local Info = Region.GetDebugInfo(SlabDebug_Regions_Selected)
  319. for I, V in ipairs(Info) do
  320. Slab.Text(V)
  321. end
  322. Slab.EndWindow()
  323. end
  324. function SlabDebug.Tooltip()
  325. Slab.BeginWindow('SlabDebug_Tooltip', {Title = "Tooltip"})
  326. local Info = Tooltip.GetDebugInfo()
  327. for I, V in ipairs(Info) do
  328. Slab.Text(V)
  329. end
  330. Slab.EndWindow()
  331. end
  332. function SlabDebug.DrawCommands()
  333. Slab.BeginWindow('SlabDebug_DrawCommands', {Title = "Draw Commands"})
  334. local Info = DrawCommands.GetDebugInfo()
  335. for K, V in pairs(Info) do
  336. DrawCommands_Item(V, K)
  337. end
  338. Slab.EndWindow()
  339. end
  340. function SlabDebug.Performance()
  341. Stats.SetEnabled(true)
  342. DrawPerformance()
  343. end
  344. function SlabDebug.StyleEditor()
  345. DrawStyleEditor()
  346. end
  347. function SlabDebug.Input()
  348. Slab.BeginWindow('SlabDebug_Input', {Title = "Input"})
  349. local Info = Input.GetDebugInfo()
  350. Slab.Text("Focused: " .. Info['Focused'])
  351. Slab.Text("Width: " .. Info['Width'])
  352. Slab.Text("Height: " .. Info['Height'])
  353. Slab.Text("Cursor X: " .. Info['CursorX'])
  354. Slab.Text("Cursor Y: " .. Info['CursorY'])
  355. Slab.Text("Cursor Position: " .. Info['CursorPos'])
  356. Slab.Text("Character: " .. Info['Character'])
  357. Slab.Text("Line Position: " .. Info['LineCursorPos'])
  358. Slab.Text("Line Position Max: " .. Info['LineCursorPosMax'])
  359. Slab.Text("Line Number: " .. Info['LineNumber'])
  360. Slab.Text("Line Length: " .. Info['LineLength'])
  361. local Lines = Info['Lines']
  362. if Lines ~= nil then
  363. Slab.Text("Lines: " .. #Lines)
  364. end
  365. Slab.EndWindow()
  366. end
  367. function SlabDebug.MultiLine()
  368. Slab.BeginWindow('SlabDebug_MultiLine', {Title = "Multi-Line Input"})
  369. if Slab.Button("Load") then
  370. SlabDebug_MultiLine_FileDialog = true
  371. end
  372. Slab.SameLine()
  373. if Slab.Button("Save", {Disabled = SlabDebug_MultiLine_FileName == ""}) then
  374. local Handle, Error = io.open(SlabDebug_MultiLine_FileName, "w")
  375. if Handle ~= nil then
  376. Handle:write(SlabDebug_MultiLine_Contents)
  377. Handle:close()
  378. end
  379. end
  380. Slab.Separator()
  381. Slab.Text("File: " .. SlabDebug_MultiLine_FileName)
  382. if Slab.Input('SlabDebug_MultiLine', {MultiLine = true, Text = SlabDebug_MultiLine_Contents, W = 500.0, H = 500.0}) then
  383. SlabDebug_MultiLine_Contents = Slab.GetInputText()
  384. end
  385. Slab.EndWindow()
  386. if SlabDebug_MultiLine_FileDialog then
  387. local Result = Slab.FileDialog({AllowMultiSelect = false, Type = 'openfile'})
  388. if Result.Button ~= "" then
  389. SlabDebug_MultiLine_FileDialog = false
  390. if Result.Button == "OK" then
  391. SlabDebug_MultiLine_FileName = Result.Files[1]
  392. local Handle, Error = io.open(SlabDebug_MultiLine_FileName, "r")
  393. if Handle ~= nil then
  394. SlabDebug_MultiLine_Contents = Handle:read("*a")
  395. Handle:close()
  396. end
  397. end
  398. end
  399. end
  400. end
  401. function SlabDebug.Menu()
  402. if Slab.BeginMenu("Debug") then
  403. if Slab.MenuItem("About") then
  404. SlabDebug.OpenAbout()
  405. end
  406. if Slab.MenuItemChecked("Mouse", SlabDebug_Mouse) then
  407. SlabDebug_Mouse = not SlabDebug_Mouse
  408. end
  409. if Slab.MenuItemChecked("Keyboard", SlabDebug_Keyboard) then
  410. SlabDebug_Keyboard = not SlabDebug_Keyboard
  411. end
  412. if Slab.MenuItemChecked("Windows", SlabDebug_Windows) then
  413. SlabDebug_Windows = not SlabDebug_Windows
  414. end
  415. if Slab.MenuItemChecked("Regions", SlabDebug_Regions) then
  416. SlabDebug_Regions = not SlabDebug_Regions
  417. end
  418. if Slab.MenuItemChecked("Tooltip", SlabDebug_Tooltip) then
  419. SlabDebug_Tooltip = not SlabDebug_Tooltip
  420. end
  421. if Slab.MenuItemChecked("Draw Commands", SlabDebug_DrawCommands) then
  422. SlabDebug_DrawCommands = not SlabDebug_DrawCommands
  423. end
  424. if Slab.MenuItemChecked("Performance", SlabDebug_Performance) then
  425. SlabDebug_Performance = not SlabDebug_Performance
  426. Stats.SetEnabled(SlabDebug_Performance)
  427. end
  428. if Slab.MenuItemChecked("Style Editor", SlabDebug_StyleEditor) then
  429. SlabDebug_StyleEditor = not SlabDebug_StyleEditor
  430. end
  431. if Slab.MenuItemChecked("Input", SlabDebug_Input) then
  432. SlabDebug_Input = not SlabDebug_Input
  433. end
  434. if Slab.MenuItemChecked("Multi-Line", SlabDebug_MultiLine) then
  435. SlabDebug_MultiLine = not SlabDebug_MultiLine
  436. end
  437. Slab.EndMenu()
  438. end
  439. end
  440. function SlabDebug.Begin()
  441. SlabDebug.About()
  442. if SlabDebug_Mouse then
  443. SlabDebug.Mouse()
  444. end
  445. if SlabDebug_Keyboard then
  446. SlabDebug.Keyboard()
  447. end
  448. if SlabDebug_Windows then
  449. SlabDebug.Windows()
  450. end
  451. if SlabDebug_Regions then
  452. SlabDebug.Regions()
  453. end
  454. if SlabDebug_Tooltip then
  455. SlabDebug.Tooltip()
  456. end
  457. if SlabDebug_DrawCommands then
  458. SlabDebug.DrawCommands()
  459. end
  460. if SlabDebug_Performance then
  461. SlabDebug.Performance()
  462. end
  463. if SlabDebug_StyleEditor then
  464. SlabDebug.StyleEditor()
  465. end
  466. if SlabDebug_Input then
  467. SlabDebug.Input()
  468. end
  469. if SlabDebug_MultiLine then
  470. SlabDebug.MultiLine()
  471. end
  472. end
  473. return SlabDebug