Full Code of coding-jackalope/Slab for AI

master 9b2e3e840c90 cached
49 files
507.7 KB
143.1k tokens
1 requests
Download .txt
Showing preview only (528K chars total). Download the full file or copy to clipboard to get everything.
Repository: coding-jackalope/Slab
Branch: master
Commit: 9b2e3e840c90
Files: 49
Total size: 507.7 KB

Directory structure:
gitextract__a007ahg/

├── .github/
│   └── FUNDING.yml
├── .gitignore
├── API.lua
├── Internal/
│   ├── Core/
│   │   ├── Config.lua
│   │   ├── Cursor.lua
│   │   ├── DrawCommands.lua
│   │   ├── FileSystem.lua
│   │   ├── IdCache.lua
│   │   ├── Messages.lua
│   │   ├── Scale.lua
│   │   ├── Stats.lua
│   │   ├── TablePool.lua
│   │   └── Utility.lua
│   ├── Input/
│   │   ├── Common.lua
│   │   ├── Keyboard.lua
│   │   └── Mouse.lua
│   ├── Resources/
│   │   └── Styles/
│   │       ├── Dark.style
│   │       └── Light.style
│   └── UI/
│       ├── Button.lua
│       ├── CheckBox.lua
│       ├── ColorPicker.lua
│       ├── ComboBox.lua
│       ├── Dialog.lua
│       ├── Dock.lua
│       ├── Image.lua
│       ├── Input.lua
│       ├── LayoutManager.lua
│       ├── ListBox.lua
│       ├── Menu.lua
│       ├── MenuBar.lua
│       ├── MenuState.lua
│       ├── Region.lua
│       ├── Separator.lua
│       ├── Shape.lua
│       ├── Text.lua
│       ├── Tooltip.lua
│       ├── Tree.lua
│       └── Window.lua
├── LICENSE
├── README.md
├── Slab.lua
├── SlabDebug.lua
├── SlabDefinition.lua
├── SlabTest.lua
├── Style.lua
├── changelog.txt
├── conf.lua
├── init.lua
└── main.lua

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms

custom: https://www.paypal.com/donate/?hosted_button_id=PHU9JP36QQYG2


================================================
FILE: .gitignore
================================================
Slab.ini
.luarc.json


================================================
FILE: API.lua
================================================
--[[

MIT License

Copyright (c) 2019-2021 Love2D Community <love2d.org>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

--]]

if SLAB_PATH == nil then
	SLAB_PATH = (...):match("(.-)[^%.]+$")
end

SLAB_FILE_PATH = debug.getinfo(1, 'S').source:match("^@(.+)/")
SLAB_FILE_PATH = SLAB_FILE_PATH == nil and "" or SLAB_FILE_PATH
local StatsData = {}
local PrevStatsData = {}

local Button = require(SLAB_PATH .. '.Internal.UI.Button')
local CheckBox = require(SLAB_PATH .. '.Internal.UI.CheckBox')
local ColorPicker = require(SLAB_PATH .. '.Internal.UI.ColorPicker')
local ComboBox = require(SLAB_PATH .. '.Internal.UI.ComboBox')
local Config = require(SLAB_PATH .. '.Internal.Core.Config')
local Cursor = require(SLAB_PATH .. '.Internal.Core.Cursor')
local Scale = require(SLAB_PATH .. ".Internal.Core.Scale")
local Dialog = require(SLAB_PATH .. '.Internal.UI.Dialog')
local Dock = require(SLAB_PATH .. '.Internal.UI.Dock')
local DrawCommands = require(SLAB_PATH .. '.Internal.Core.DrawCommands')
local FileSystem = require(SLAB_PATH .. '.Internal.Core.FileSystem')
local Image = require(SLAB_PATH .. '.Internal.UI.Image')
local Input = require(SLAB_PATH .. '.Internal.UI.Input')
local Keyboard = require(SLAB_PATH .. '.Internal.Input.Keyboard')
local LayoutManager = require(SLAB_PATH .. '.Internal.UI.LayoutManager')
local ListBox = require(SLAB_PATH .. '.Internal.UI.ListBox')
local Messages = require(SLAB_PATH .. '.Internal.Core.Messages')
local Mouse = require(SLAB_PATH .. '.Internal.Input.Mouse')
local Menu = require(SLAB_PATH .. '.Internal.UI.Menu')
local MenuState = require(SLAB_PATH .. '.Internal.UI.MenuState')
local MenuBar = require(SLAB_PATH .. '.Internal.UI.MenuBar')
local Region = require(SLAB_PATH .. '.Internal.UI.Region')
local Separator = require(SLAB_PATH .. '.Internal.UI.Separator')
local Shape = require(SLAB_PATH .. '.Internal.UI.Shape')
local Stats = require(SLAB_PATH .. '.Internal.Core.Stats')
local Style = require(SLAB_PATH .. '.Style')
local Text = require(SLAB_PATH .. '.Internal.UI.Text')
local Tree = require(SLAB_PATH .. '.Internal.UI.Tree')
local Utility = require(SLAB_PATH .. '.Internal.Core.Utility')
local Window = require(SLAB_PATH .. '.Internal.UI.Window')

--[[
	Slab

	Slab is an immediate mode GUI toolkit for the Love 2D framework. This library is designed to
	allow users to easily add this library to their existing Love 2D projects and quickly create
	tools to enable them to iterate on their ideas quickly. The user should be able to utilize this
	library with minimal integration steps and is completely written in Lua and utilizes
	the Love 2D API. No compiled binaries are required and the user will have access to the source
	so that they may make adjustments that meet the needs of their own projects and tools. Refer
	to main.lua and SlabTest.lua for example usage of this library.

	Supported Version: 11.3.0

	API:
		Initialize
		GetVersion
		GetLoveVersion
		Update
		Draw
		SetINIStatePath
		GetINIStatePath
		SetVerbose
		GetMessages

		Style:
			GetStyle
			PushFont
			PopFont

		Window:
			BeginWindow
			EndWindow
			GetWindowPosition
			GetWindowSize
			GetWindowContentSize
			GetWindowActiveSize
			IsWindowAppearing
			PushID
			PopID

		Menu:
			BeginMainMenuBar
			EndMainMenuBar
			BeginMenuBar
			EndMenuBar
			BeginMenu
			EndMenu
			BeginContextMenuItem
			BeginContextMenuWindow
			EndContextMenu
			MenuItem
			MenuItemChecked

		Separator
		Button
		RadioButton
		Text
		TextSelectable
		Textf
		GetTextSize
		GetTextWidth
		GetTextHeight
		CheckBox
		Input
		InputNumberDrag
		InputNumberSlider
		GetInputText
		GetInputNumber
		GetInputCursorPos
		IsInputFocused
		IsAnyInputFocused
		SetInputFocus
		SetInputCursorPos
		SetInputCursorPosLine
		BeginTree
		EndTree
		BeginComboBox
		EndComboBox
		Image

		Cursor:
			SameLine
			NewLine
			SetCursorPos
			GetCursorPos
			Indent
			Unindent

		Properties

		ListBox:
			BeginListBox
			EndListBox
			BeginListBoxItem
			IsListBoxItemClicked
			EndListBoxItem

		Dialog:
			OpenDialog
			BeginDialog
			EndDialog
			CloseDialog
			MessageBox
			FileDialog
			ColorPicker

		Mouse:
			IsMouseDown
			IsMouseClicked
			IsMouseReleased
			IsMouseDoubleClicked
			IsMouseDragging
			GetMousePosition
			GetMousePositionWindow
			GetMouseDelta
			SetCustomMouseCursor
			ClearCustomMouseCursor

		Control:
			IsControlHovered
			IsControlClicked
			GetControlSize
			IsVoidHovered
			IsVoidClicked

		Keyboard:
			IsKeyDown
			IsKeyPressed
			IsKeyReleased

		Shape:
			Rectangle
			Circle
			Triangle
			Line
			Curve
			GetCurveControlPointCount
			GetCurveControlPoint
			EvaluateCurve
			EvaluateCurveMouse
			Polygon

		Stats:
			BeginStat
			EndStat
			EnableStats
			IsStatsEnabled
			FlushStats

		Layout:
			BeginLayout
			EndLayout
			SetLayoutColumn
			GetLayoutSize

		Scroll:
			SetScrollSpeed
			GetScrollSpeed

		Shader:
			PushShader
			PopShader

		Dock:
			EnableDocks
			DisableDocks
			SetDockOptions
--]]
local Slab = {}

-- Slab version numbers.
local Version_Major = 0
local Version_Minor = 9
local Version_Revision = 0

local FrameStatHandle = nil

-- The path to save the UI state to a file. This will default to the save directory.
local INIStatePath = "Slab.ini"
local IsDefault = true
local QuitFn = nil
local Verbose = false
local Initialized = false
local DontInterceptEventHandlers = false


local ModifyCursor = true

local function LoadState()
	if INIStatePath == nil then return end

	local Result, Error = Config.LoadFile(INIStatePath, IsDefault)
	if Result ~= nil then
		Dock.Load(Result)
		Tree.Load(Result)
		Window.Load(Result)
	end

	if Verbose then
		print("Load INI file:", INIStatePath, "Error:", Error)
	end
end

local function SaveState()
	if INIStatePath == nil then return end

	local Table = {}
	Dock.Save(Table)
	Tree.Save(Table)
	Window.Save(Table)
	local Result, Error = Config.Save(INIStatePath, Table, IsDefault)

	if Verbose then
		print("Save INI file:", INIStatePath, "Error:", Error)
	end
end

local function TextInput(Ch)
	Input.Text(Ch)

	if (not DontInterceptEventHandlers) and love.textinput ~= nil then
		love.textinput(Ch)
	end
end

local function WheelMoved(X, Y)
	Window.WheelMoved(X, Y)

	if (not DontInterceptEventHandlers) and love.wheelmoved ~= nil then
		love.wheelmoved(X, Y)
	end
end

local function OnQuit()
	SaveState()

	if QuitFn ~= nil then
		QuitFn()
	end
end

--[[
	Event forwarding
--]]

Slab.OnTextInput = TextInput;
Slab.OnWheelMoved = WheelMoved;
Slab.OnQuit = OnQuit;
Slab.OnKeyPressed = Keyboard.OnKeyPressed;
Slab.OnKeyReleased = Keyboard.OnKeyReleased;
Slab.OnMouseMoved = Mouse.OnMouseMoved
Slab.OnMousePressed = Mouse.OnMousePressed;
Slab.OnMouseReleased = Mouse.OnMouseReleased;

--[[
	Initialize

	Initializes Slab and hooks into the required events. This function should be called in love.load.

	args: [Table] The list of parameters passed in by the user on the command-line. This should be passed in from
		love.load function. Below is a list of arguments available to modify Slab:
		NoMessages: [String] Disables the messaging system that warns developers of any changes in the API.
		NoDocks: [String] Disables all docks.
		NoCursor: [String] Disables modifying the cursor

	Return: None.
--]]
function Slab.Initialize(args, dontInterceptEventHandlers)
	if Initialized then
		return
	end

	DontInterceptEventHandlers = dontInterceptEventHandlers
	Style.API.Initialize()

	args = args or {}
	if type(args) == 'table' then
		for I, V in ipairs(args) do
			if string.lower(V) == 'nomessages' then
				Messages.SetEnabled(false)
			elseif string.lower(V) == 'nodocks' then
				Slab.DisableDocks({'Left', 'Right', 'Bottom'})
			elseif string.lower(V) == 'nocursor' then
				ModifyCursor = false
			end
		end
	end

	if not dontInterceptEventHandlers then
		love.handlers['textinput'] = TextInput
		love.handlers['wheelmoved'] = WheelMoved

		-- In Love 11.3, overriding love.handlers['quit'] doesn't seem to affect the callback during shutdown.
		-- Storing and overriding love.quit manually will properly call Slab's callback. This function will call
		-- the stored function once Slab is finished with its process.
		QuitFn = love.quit
		love.quit = OnQuit
	end

	Keyboard.Initialize(args, dontInterceptEventHandlers)
	Mouse.Initialize(args, dontInterceptEventHandlers)

	LoadState()

	Initialized = true
end

--[[
	GetVersion

	Retrieves the current version of Slab being used as a string.

	Return: [String] String of the current Slab version.
--]]
function Slab.GetVersion()
	return string.format("%d.%d.%d", Version_Major, Version_Minor, Version_Revision)
end

--[[
	GetLoveVersion

	Retrieves the current version of Love being used as a string.

	Return: [String] String of the current Love version.
--]]
function Slab.GetLoveVersion()
	local Major, Minor, Revision, Codename = love.getVersion()
	return string.format("%d.%d.%d - %s", Major, Minor, Revision, Codename)
end

--[[
	Update

	Updates the input state and states of various widgets. This function must be called every frame.
	This should be called before any Slab calls are made to ensure proper responses to Input are made.

	dt: [Number] The delta time for the frame. This should be passed in from love.update.

	Return: None.
--]]
function Slab.Update(dt)
	Stats.Reset(false)
	FrameStatHandle = Stats.Begin('Frame', 'Slab')
	local StatHandle = Stats.Begin('Update', 'Slab')

	Mouse.Update()
	Keyboard.Update()
	Input.Update(dt)
	DrawCommands.Reset()
	Window.Reset()
	LayoutManager.Validate()

	if MenuState.IsOpened then
		MenuState.WasOpened = MenuState.IsOpened
		if Mouse.IsClicked(1) then
			MenuState.RequestClose = true
		end
	end

	Stats.End(StatHandle)
end

--[[
	Draw

	This function will execute all buffered draw calls from the various Slab calls made prior. This
	function should be called from love.draw and should be called at the very to ensure Slab is rendered
	above the user's workspace.

	Return: None.
--]]
function Slab.Draw()
	if Stats.IsEnabled() then
		PrevStatsData = love.graphics.getStats(PrevStatsData)
	end

	local StatHandle = Stats.Begin('Draw', 'Slab')

	Window.Validate()

	local MovingInstance = Window.GetMovingInstance()
	if MovingInstance ~= nil then
		Dock.DrawOverlay()
		Dock.SetPendingWindow(MovingInstance)
	else
		Dock.Commit()
	end

	if MenuState.RequestClose then
		Menu.Close()
		MenuBar.Clear()
	end

	if ModifyCursor then
		Mouse.Draw()
	end

	if Mouse.IsReleased(1) then
		Button.ClearClicked()
	end

	love.graphics.setColor(1, 1, 1, 1)
	love.graphics.push()
	love.graphics.origin()
	DrawCommands.Execute()
	love.graphics.pop()
	love.graphics.setColor(1, 1, 1, 1)

	Stats.End(StatHandle)

	-- Only call end if 'Update' was called and a valid handle was retrieved. This can happen for developers using a custom
	-- run function with a fixed update.
	if FrameStatHandle ~= nil then
		Stats.End(FrameStatHandle)
		FrameStatHandle = nil
	end

	if Stats.IsEnabled() then
		StatsData = love.graphics.getStats(StatsData)
		for k, v in pairs(StatsData) do
			StatsData[k] = v - PrevStatsData[k]
		end
	end
end

--[[
	SetINIStatePath

	Sets the INI path to save the UI state. If nil, Slab will not save the state to disk.

	Return: None.
--]]
function Slab.SetINIStatePath(Path)
	INIStatePath = Path
	IsDefault = false
end

--[[
	GetINIStatePath

	Gets the INI path to save the UI state. This value can be nil.

	Return: [String] The path on disk the UI state will be saved to.
--]]
function Slab.GetINIStatePath()
	return INIStatePath
end

--[[
	SetVerbose

	Enable/Disables internal Slab logging. Could be useful for diagnosing problems that occur inside of Slab.

	IsVerbose: [Boolean] Flag to enable/disable verbose logging.

	Return: None.
--]]
function Slab.SetVerbose(IsVerbose)
	Verbose = (IsVerbose == nil or type(IsVerbose) ~= 'boolean') and false or IsVerbose
end

--[[
	GetMessages

	Retrieves a list of existing messages that has been captured by Slab.

	Return: [Table] List of messages that have been broadcasted from Slab.
--]]
function Slab.GetMessages()
	return Messages.Get()
end

--[[
	GetStyle

	Retrieve the style table associated with the current instance of Slab. This will allow the user to add custom styling
	to their controls.

	Return: [Table] The style table.
--]]
function Slab.GetStyle()
	return Style
end


--[[
    SetScale

    Sets the rendering scale for the Slab context.

	scaleFactor: [number] The scale factor to use

	Return: None.
--]]
function Slab.SetScale(scaleFactor)
	Scale.SetScale(scaleFactor)
end


--[[
    GetScale

	Retrieve the scale of the current Slab context.

	Return: [number] The current scale.
--]]
function Slab.GetScale()
	return Scale.GetScale()
end


--[[
	PushFont

	Pushes a Love font object onto the font stack. All text rendering will use this font until PopFont is called.

	Font: [Object] The Love font object to use.

	Return: None.
--]]
function Slab.PushFont(Font)
	Style.API.PushFont(Font)
end

--[[
	PopFont

	Pops the last font from the stack.

	Return: None.
--]]
function Slab.PopFont()
	Style.API.PopFont()
end

--[[
	BeginWindow

	This function begins the process of drawing widgets to a window. This function must be followed up with
	an EndWindow call to ensure proper behavior of drawing windows.

	Id: [String] A unique string identifying this window in the project.
	Options: [Table] List of options that control how this window will behave.
		X: [Number] The X position to start rendering the window at.
		Y: [Number] The Y position to start rendering the window at.
		W: [Number] The starting width of the window.
		H: [Number] The starting height of the window.
		ContentW: [Number] The starting width of the content contained within this window.
		ContentH: [Number] The starting height of the content contained within this window.
		BgColor: [Table] The background color value for this window. Will use the default style WindowBackgroundColor if this is empty.
		Title: [String] The title to display for this window. If emtpy, no title bar will be rendered and the window will not be movable.
		TitleH: [Number] The height of the title bar. By default, this will be the height of the current font set in the style. If no title is
			set, this is ignored.
		TitleAlignX: [String] Horizontal alignment of the title. The available options are 'left', 'center', and 'right'. The default is 'center'.
		TitleAlignY: [String] Vertical alignment of the title. The available options are 'top', 'center', and 'bottom'. The default is 'center'.
		AllowMove: [Boolean] Controls whether the window is movable within the title bar area. The default value is true.
		AllowResize: [Boolean] Controls whether the window is resizable. The default value is true. AutoSizeWindow must be false for this to work.
		AllowFocus: [Boolean] Controls whether the window can be focused. The default value is true.
		Border: [Number] The value which controls how much empty space should be left between all sides of the window from the content.
			The default value is 4.0
		NoOutline: [Boolean] Controls whether an outline should not be rendered. The default value is false.
		IsMenuBar: [Boolean] Controls whether if this window is a menu bar or not. This flag should be ignored and is used by the menu bar
			system. The default value is false.
		AutoSizeWindow: [Boolean] Automatically updates the window size to match the content size. The default value is true.
		AutoSizeWindowW: [Boolean] Automatically update the window width to match the content size. This value is taken from AutoSizeWindow by default.
		AutoSizeWindowH: [Boolean] Automatically update the window height to match the content size. This value is taken from AutoSizeWindow by default.
		AutoSizeContent: [Boolean] The content size of the window is automatically updated with each new widget. The default value is true.
		Layer: [String] The layer to which to draw this window. This is used internally and should be ignored by the user.
		ResetPosition: [Boolean] Determines if the window should reset any delta changes to its position.
		ResetSize: [Boolean] Determines if the window should reset any delta changes to its size.
		ResetContent: [Boolean] Determines if the window should reset any delta changes to its content size.
		ResetLayout: [Boolean] Will reset the position, size, and content. Short hand for the above 3 flags.
		SizerFilter: [Table] Specifies what sizers are enabled for the window. If nothing is specified, all sizers are available. The values can
			be: NW, NE, SW, SE, N, S, E, W
		CanObstruct: [Boolean] Sets whether this window is considered for obstruction of other windows and their controls. The default value is true.
		Rounding: [Number] Amount of rounding to apply to the corners of the window.
		IsOpen: [Boolean] Determines if the window is open. If this value exists within the options, a close button will appear in
			the corner of the window and is updated when this button is pressed to reflect the new open state of this window.
		NoSavedSettings: [Boolean] Flag to disable saving this window's settings to the state INI file.
		ConstrainPosition: [Boolean] Flag to constrain the position of the window to the bounds of the viewport.
		ShowMinimize: [Boolean] Flag to show a minimize button in the title bar of the window. Default is `true`.
		ShowScrollbarX: [Boolean] Flag to show the horizontal scrollbar regardless of the window and content internal state. Default is `false`
		ShowScrollbarY: [Boolean] Flag to show the vertical scrollbar regardless of the window and content internal state. Default is `false`

	Return: [Boolean] The open state of this window. Useful for simplifying API calls by storing the result in a flag instead of a table.
		EndWindow must still be called regardless of the result for this value.
--]]
function Slab.BeginWindow(Id, Options)
	return Window.Begin(Id, Options)
end

--[[
	EndWindow

	This function must be called after a BeginWindow and associated widget calls. If the user fails to call this, an assertion will be thrown
	to alert the user.

	Return: None.
--]]
function Slab.EndWindow()
	Window.End()
end

--[[
	GetWindowPosition

	Retrieves the active window's position.

	Return: [Number], [Number] The X and Y position of the active window.
--]]
function Slab.GetWindowPosition()
	return Window.GetPosition()
end

--[[
	GetWindowSize

	Retrieves the active window's size.

	Return: [Number], [Number] The width and height of the active window.
--]]
function Slab.GetWindowSize()
	return Window.GetSize()
end

--[[
	GetWindowContentSize

	Retrieves the active window's content size.

	Return: [Number], [Number] The width and height of the active window content.
--]]
function Slab.GetWindowContentSize()
	return Window.GetContentSize()
end

--[[
	GetWindowActiveSize

	Retrieves the active window's active size minus the borders.

	Return: [Number], [Number] The width and height of the window's active bounds.
--]]
function Slab.GetWindowActiveSize()
	return Window.GetBorderlessSize()
end

--[[
	IsWindowAppearing

	Is the current window appearing this frame. This will return true if BeginWindow has
	not been called for a window over 2 or more frames.

	Return: [Boolean] True if the window is appearing this frame. False otherwise.
--]]
function Slab.IsWindowAppearing()
	return Window.IsAppearing()
end

--[[
	PushID

	Pushes a custom ID onto a stack. This allows developers to differentiate between similar controls such as
	text controls.

	ID: [String] The custom ID to add.

	Return: None.
--]]
function Slab.PushID(ID)
	assert(type(ID) == 'string', "'ID' parameter must be a string value.")

	Window.PushID(ID)
end

--[[
	PopID

	Pops the last custom ID from the stack.

	Return: None.
--]]
function Slab.PopID()
	Window.PopID()
end

--[[
	BeginMainMenuBar

	This function begins the process for setting up the main menu bar. This should be called outside of any BeginWindow/EndWindow calls.
	The user should only call EndMainMenuBar if this function returns true. Use BeginMenu/EndMenu calls to add menu items on the main menu bar.

	Example:
		if Slab.BeginMainMenuBar() then
			if Slab.BeginMenu("File") then
				if Slab.MenuItem("Quit") then
					love.event.quit()
				end

				Slab.EndMenu()
			end

			Slab.EndMainMenuBar()
		end

	Return: [Boolean] Returns true if the main menu bar process has started.
--]]
function Slab.BeginMainMenuBar()
	local X,Y = 0.0, 0.0
	if Utility.IsMobile() then
		X, Y = love.window.getSafeArea()
	end
	Cursor.SetPosition(X, Y)
	return Slab.BeginMenuBar(true)
end

--[[
	EndMainMenuBar

	This function should be called if BeginMainMenuBar returns true.

	Return: None.
--]]
function Slab.EndMainMenuBar()
	Slab.EndMenuBar()
end

--[[
	BeginMenuBar

	This function begins the process of rendering a menu bar for a window. This should only be called within a BeginWindow/EndWindow context.

	IsMainMenuBar: [Boolean] Is this menu bar for the main viewport. Used internally. Should be ignored for all other calls.

	Return: [Boolean] Returns true if the menu bar process has started.
--]]
function Slab.BeginMenuBar(IsMainMenuBar)
	return MenuBar.Begin(IsMainMenuBar)
end

--[[
	EndMenuBar

	This function should be called if BeginMenuBar returns true.

	Return: None.
--]]
function Slab.EndMenuBar()
	MenuBar.End()
end

--[[
	BeginMenu

	Adds a menu item that when the user hovers over, opens up an additional context menu. When used within a menu bar, BeginMenu calls
	will be added to the bar. Within a context menu, the menu item will be added within the context menu with an additional arrow to notify
	the user more options are available. If this function returns true, the user must call EndMenu.

	Label: [String] The label to display for this menu.
	Options: [Table] List of options that control how this menu behaves.
		Enabled: [Boolean] Determines if this menu is enabled. This value is true by default. Disabled items are displayed but
			cannot be interacted with.

	Return: [Boolean] Returns true if the menu item is being hovered.
--]]
function Slab.BeginMenu(Label, Options)
	return Menu.BeginMenu(Label, Options)
end

--[[
	EndMenu

	Finishes up a BeginMenu. This function must be called if BeginMenu returns true.

	Return: None.
--]]
function Slab.EndMenu()
	Menu.EndMenu()
end

--[[
	BeginContextMenuItem

	Opens up a context menu based on if the user right clicks on the last item. This function should be placed immediately after an item
	call to open up a context menu for that specific item. If this function returns true, EndContextMenu must be called.

	Example:
		if Slab.Button("Button!") then
			-- Perform logic here when button is clicked
		end

		-- This will only return true if the previous button is hot and the user right-clicks.
		if Slab.BeginContextMenuItem() then
			Slab.MenuItem("Button Item 1")
			Slab.MenuItem("Button Item 2")

			Slab.EndContextMenu()
		end

	Button: [Number] The mouse button to use for opening up this context menu.

	Return: [Boolean] Returns true if the user right clicks on the previous item call. EndContextMenu must be called in order for
		this to function properly.
--]]
function Slab.BeginContextMenuItem(Button)
	return Menu.BeginContextMenu({IsItem = true, Button = Button})
end

--[[
	BeginContextMenuWindow

	Opens up a context menu based on if the user right clicks anywhere within the window. It is recommended to place this function at the end
	of a window's widget calls so that Slab can catch any BeginContextMenuItem calls before this call. If this function returns true,
	EndContextMenu must be called.

	Button: [Number] The mouse button to use for opening up this context menu.

	Return: [Boolean] Returns true if the user right clicks anywhere within the window. EndContextMenu must be called in order for this
		to function properly.
--]]
function Slab.BeginContextMenuWindow(Button)
	return Menu.BeginContextMenu({IsWindow = true, Button = Button})
end

--[[
	EndContextMenu

	Finishes up any BeginContextMenuItem/BeginContextMenuWindow if they return true.

	Return: None.
--]]
function Slab.EndContextMenu()
	Menu.EndContextMenu()
end

--[[
	MenuItem

	Adds a menu item to a given context menu.

	Label: [String] The label to display to the user.
	Options: [Table] List of options that control how this menu behaves.
		Enabled: [Boolean] Determines if this menu is enabled. This value is true by default. Disabled items are displayed but
			cannot be interacted with.
		Hint: [String] Show an input hint to the right of the menu item

	Return: [Boolean] Returns true if the user clicks on this menu item.
--]]
function Slab.MenuItem(Label, Options)
	return Menu.MenuItem(Label, Options)
end

--[[
	MenuItemChecked

	Adds a menu item to a given context menu. If IsChecked is true, then a check mark will be rendered next to the
	label.

	Example:
		local Checked = false
		if Slab.MenuItemChecked("Menu Item", Checked)
			Checked = not Checked
		end

	Label: [String] The label to display to the user.
	IsChecked: [Boolean] Determines if a check mark should be rendered next to the label.
	Options: [Table] List of options that control how this menu behaves.
		Enabled: [Boolean] Determines if this menu is enabled. This value is true by default. Disabled items are displayed but
			cannot be interacted with.

	Return: [Boolean] Returns true if the user clicks on this menu item.
--]]
function Slab.MenuItemChecked(Label, IsChecked, Options)
	return Menu.MenuItemChecked(Label, IsChecked, Options)
end

--[[
	Separator

	This functions renders a separator line in the window.

	Option: [Table] List of options for how this separator will be drawn.
		IncludeBorders: [Boolean] Whether to extend the separator to include the window borders. This is false by default.
		H: [Number] The height of the separator. This doesn't change the line thickness, rather, specifies the cursor advancement
			in the Y direction.
		Thickness: [Number] The thickness of the line rendered. The default value is 1.0.

	Return: None.
--]]
function Slab.Separator(Options)
	Separator.Begin(Options)
end

--[[
	Button

	Adds a button to the active window.

	Label: [String] The label to display on the button.
	Options: [Table] List of options for how this button will behave.
		Tooltip: [String] The tooltip to display when the user hovers over this button.
		Rounding: [Number] Amount of rounding to apply to the corners of the button.
		Invisible: [Boolean] Don't render the button, but keep the behavior.
		W: [Number] Override the width of the button.
		H: [Number] Override the height of the button.
		Disabled: [Boolean] If true, the button is not interactable by the user.
		Image: [Table] A table of options used to draw an image instead of a text label. Refer to the 'Image' documentation for a list
			of available options.
		Color: [Table]: The background color of the button when idle. The default value is the ButtonColor property in the Style's table.
		HoverColor: [Table]: The background color of the button when a mouse is hovering the control. The default value is the ButtonHoveredColor property
			in the Style's table.
		PressColor: [Table]: The background color of the button when the button is pressed but not released. The default value is the ButtonPressedColor
			property in the Style's table.
		PadX: [Number] Amount of additional horizontal space the background will expand to from the center. The default value is 20.
		PadY: [Number] Amount of additional vertical space the background will expand to from the center. The default value is 5.
		VLines: [Number] Number of lines in a multiline button text. The default value is 1.

	Return: [Boolean] Returns true if the user clicks on this button.
--]]
function Slab.Button(Label, Options)
	return Button.Begin(Label, Options)
end

--[[
	RadioButton

	Adds a radio button entry to the active window. The grouping of radio buttons is determined by the user. An Index can
	be applied to the given radio button and a SelectedIndex can be passed in to determine if this specific radio button
	is the selected one.

	Label: [String] The label to display next to the button.
	Options: [Table] List of options for how this radio button will behave.
		Index: [Number] The index of this radio button. Will be 0 by default and not selectable. Assign an index to group the button.
		SelectedIndex: [Number] The index of the radio button that is selected. If this equals the Index field, then this radio button
			will be rendered as selected.
		Tooltip: [String] The tooltip to display when the user hovers over the button or label.

	Return: [Boolean] Returns true if the user clicks on this button.
--]]
function Slab.RadioButton(Label, Options)
	return Button.BeginRadio(Label, Options)
end

--[[
	Text

	Adds text to the active window.

	Label: [String] The string to be displayed in the window.
	Options: [Table] List of options for how this text is displayed.
		Color: [Table] The color to render the text.
		Pad: [Number] How far to pad the text from the left side of the current cursor position.
		PadH: [Number] How far to pad the text vertically, will render centered in this region
		IsSelectable: [Boolean] Whether this text is selectable using the text's Y position and the window X and width as the
			hot zone.
		IsSelectableTextOnly: [Boolean] Will use the text width instead of the window width to determine the hot zone. Will set IsSelectable
			to true if that option is missing.
		IsSelected: [Boolean] Forces the hover background to be rendered.
		SelectOnHover: [Boolean] Returns true if the user is hovering over the hot zone of this text.
		HoverColor: [Table] The color to render the background if the IsSelected option is true.
		URL: [String] A URL address to open when this text control is clicked.

	Return: [Boolean] Returns true if SelectOnHover option is set to true. False otherwise.
--]]
function Slab.Text(Label, Options)
	return Text.Begin(Label, Options)
end

--[[
	TextSelectable

	This function is a shortcut for SlabText with the IsSelectable option set to true.

	Label: [String] The string to be displayed in the window.
	Options: [Table] List of options for how this text is displayed.
		See Slab.Text for all options.

	Return: [Boolean] Returns true if user clicks on this text. False otherwise.
--]]
function Slab.TextSelectable(Label, Options)
	Options = Options == nil and {} or Options
	Options.IsSelectable = true
	return Slab.Text(Label, Options)
end

--[[
	Textf

	Adds formatted text to the active window. This text will wrap to fit within the contents of
	either the window or a user specified width.

	Label: [String] The text to be rendered.
	Options: [Table] List of options for how this text is displayed.
		Color: [Table] The color to render the text.
		W: [Number] The width to restrict the text to. If this option is not specified, then the window
			width is used.
		Align: [String] The alignment to use for this text. For more information, refer to the love documentation
			at https://love2d.org/wiki/AlignMode. Below are the available options:
			center: Align text center.
			left: Align text left.
			right: Align text right.
			justify: Align text both left and right.

	Return: None.
--]]
function Slab.Textf(Label, Options)
	Text.BeginFormatted(Label, Options)
end

--[[
	GetTextSize

	Retrieves the width and height of the given text. The result is based on the current font.

	Label: [String] The string to retrieve the size for.

	Return: [Number], [Number] The width and height of the given text.
--]]
function Slab.GetTextSize(Label)
	return Text.GetSize(Label)
end

--[[
	GetTextWidth

	Retrieves the width of the given text. The result is based on the current font.

	Label: [String] The string to retrieve the width for.

	Return: [Number] The width of the given text.
--]]
function Slab.GetTextWidth(Label)
	local W, H = Slab.GetTextSize(Label)
	return W
end

--[[
	GetTextHeight

	Retrieves the height of the current font.

	Return: [Number] The height of the current font.
--]]
function Slab.GetTextHeight()
	return Text.GetHeight()
end

--[[
	CheckBox

	Renders a check box with a label. The check box when enabled will render an 'X'.

	Enabled: [Boolean] Will render an 'X' within the box if true. Will be an empty box otherwise.
	Label: [String] The label to display after the check box.
	Options: [Table] List of options for how this check box will behave.
		Tooltip: [String] Text to be displayed if the user hovers over the check box.
		Id: [String] An optional Id that can be supplied by the user. By default, the Id will be the label.
		Rounding: [Number] Amount of rounding to apply to the corners of the check box.
		Size: [Number] The uniform size of the box. The default value is 16.
		Disabled: [Boolean] Dictates whether this check box is enabled for interaction.

	Return: [Boolean] Returns true if the user clicks within the check box.
--]]
function Slab.CheckBox(Enabled, Label, Options)
	return CheckBox.Begin(Enabled, Label, Options)
end

--[[
	Input

	This function will render an input box for a user to input text in. This widget behaves like input boxes
	found in other applications. This function will only return true if it has focus and user has either input
	text or pressed the return key.

	Example:
		local Text = "Hello World"
		if Slab.Input('Example', {Text = Text}) then
			Text = Slab.GetInputText()
		end

	Id: [String] A string that uniquely identifies this Input within the context of the window.
	Options: [Table] List of options for how this Input will behave.
		Tooltip: [String] Text to be displayed if the user hovers over the Input box.
		ReturnOnText: [Boolean] Will cause this function to return true whenever the user has input
			a new character into the Input box. This is true by default.
		Text: [String] The text to be supplied to the input box. It is recommended to use this option
			when ReturnOnText is true.
		TextColor: [Table] The color to use for the text. The default color is the color used for text, but there is also
			a default multiline text color defined in the Style.
		BgColor: [Table] The background color for the input box.
		SelectColor: [Table] The color used when the user is selecting text within the input box.
		SelectOnFocus: [Boolean] When this input box is focused by the user, the text contents within the input
			will be selected. This is true by default.
		NumbersOnly: [Boolean] When true, only numeric characters and the '.' character are allowed to be input into
			the input box. If no text is input, the input box will display '0'.
		W: [Number] The width of the input box. By default, will be 150.0
		H: [Number] The height of the input box. By default, will be the height of the current font.
		ReadOnly: [Boolean] Whether this input field can be editable or not.
		Align: [String] Aligns the text within the input box. Options are:
			left: Aligns the text to the left. This will be set when this Input is focused.
			center: Aligns the text in the center. This is the default for when the text is not focused.
		Rounding: [Number] Amount of rounding to apply to the corners of the input box.
		MinNumber: [Number] The minimum value that can be entered into this input box. Only valid when NumbersOnly is true.
		MaxNumber: [Number] The maximum value that can be entered into this input box. Only valid when NumbersOnly is true.
		MultiLine: [Boolean] Determines whether this input control should support multiple lines. If this is true, then the
			SelectOnFocus flag will be false. The given text will also be sanitized to remove controls characters such as
			'\r'. Also, the text will be left aligned.
		MultiLineW: [Number] The width for which the lines of text should be wrapped at.
		Highlight: [Table] A list of key-values that define what words to highlight what color. Strings should be used for
			the word to highlight and the value should be a table defining the color.
		Step: [Number] The step amount for numeric controls when the user click and drags. The default value is 1.0.
		NoDrag: [Boolean] Determines whether this numberic control allows the user to click and drag to alter the value.
		UseSlider: [Boolean] If enabled, displays a slider inside the input control. This will only be drawn if the NumbersOnly
			option is set to true. The position of the slider inside the control determines the value based on the MinNumber
			and MaxNumber option.
		IsPassword: [Boolean] If enabled, mask the text with another character. Default is false.
		PasswordChar: [Char/String] Sets the character or string to use along with IsPassword flag. Default is "*"

	Return: [Boolean] Returns true if the user has pressed the return key while focused on this input box. If ReturnOnText
		is set to true, then this function will return true whenever the user has input any character into the input box.
--]]
function Slab.Input(Id, Options)
	return Input.Begin(Id, Options)
end

--[[
	InputNumberDrag

	This is a wrapper function for calling the Input function which sets the proper options to set up the input box for
	displaying and editing numbers. The user will be able to click and drag the control to alter the value. Double-clicking
	inside this control will allow for manually editing the value.

	Id: [String] A string that uniquely identifies this Input within the context of the window.
	Value: [Number] The value to display in the control.
	Min: [Number] The minimum value that can be set for this number control. If nil, then this value will be set to -math.huge.
	Max: [Number] The maximum value that can be set for this number control. If nil, then this value will be set to math.huge.
	Step: [Number] The amount to increase value when mouse delta reaches threshold.
	Options: [Table] List of options for how this input control is displayed. See Slab.Input for all options.

	Return: [Boolean] Returns true whenever this valued is modified.
--]]
function Slab.InputNumberDrag(Id, Value, Min, Max, Step, Options)
	Options = Options == nil and {} or Options
	Options.Text = tostring(Value)
	Options.MinNumber = Min
	Options.MaxNumber = Max
	Options.Step = Step
	Options.NumbersOnly = true
	Options.UseSlider = false
	Options.NoDrag = false
	return Slab.Input(Id, Options)
end

--[[
	InputNumberSlider

	This is a wrapper function for calling the Input function which sets the proper options to set up the input box for
	displaying and editing numbers. This will also force the control to display a slider, which determines what the value
	stored is based on the Min and Max options. Double-clicking inside this control will allow for manually editing
	the value.

	Id: [String] A string that uniquely identifies this Input within the context of the window.
	Value: [Number] The value to display in the control.
	Min: [Number] The minimum value that can be set for this number control. If nil, then this value will be set to -math.huge.
	Max: [Number] The maximum value that can be set for this number control. If nil, then this value will be set to math.huge.
	Options: [Table] List of options for how this input control is displayed. See Slab.Input for all options.
		Precision: [Number] An integer in the range [0..5]. This will set the size of the fractional component.
		NeedDrag: [Boolean] This will determine if slider needs to be dragged before changing value, otherwise just clicking in the slider will adjust the value into the clicked value. Default is true.

	Return: [Boolean] Returns true whenever this valued is modified.
--]]
function Slab.InputNumberSlider(Id, Value, Min, Max, Options)
	Options = Options == nil and {} or Options
	Options.Text = tostring(Value)
	Options.MinNumber = Min
	Options.MaxNumber = Max
	Options.NumbersOnly = true
	Options.UseSlider = true
	return Slab.Input(Id, Options)
end

--[[
	GetInputText

	Retrieves the text entered into the focused input box. Refer to the documentation for Slab.Input for an example on how to
	use this function.

	Return: [String] Returns the text entered into the focused input box.
--]]
function Slab.GetInputText()
	return Input.GetText()
end

--[[
	GetInputNumber

	Retrieves the text entered into the focused input box and attempts to conver the text into a number. Will always return a valid
	number.

	Return: [Number] Returns the text entered into the focused input box as a number.
--]]
function Slab.GetInputNumber()
	local Result = tonumber(Input.GetText())
	if Result == nil then
		Result = 0
	end
	return Result
end

--[[
	GetInputCursorPos

	Retrieves the position of the input cursor for the focused input control. There are three values that are returned. The first one
	is the absolute position of the cursor with regards to the text for the control. The second is the column position of the cursor
	on the current line. The final value is the line number. The column will match the absolute position if the input control is not
	multi line.

	Return: [Number], [Number], [Number] The absolute position of the cursor, the column position of the cursor on the current line,
		and the line number of the cursor. These values will all be zero if no input control is focused.
--]]
function Slab.GetInputCursorPos()
	return Input.GetCursorPos()
end

--[[
	IsInputFocused

	Returns whether the input control with the given Id is focused or not.

	Id: [String] The Id of the input control to check.

	Return: [Boolean] True if the input control with the given Id is focused. False otherwise.
--]]
function Slab.IsInputFocused(Id)
	return Input.IsFocused(Id)
end

--[[
	IsAnyInputFocused

	Returns whether any input control is focused or not.

	Return: [Boolean] True if there is an input control focused. False otherwise.
--]]
function Slab.IsAnyInputFocused()
	return Input.IsAnyFocused()
end

--[[
	SetInputFocus

	Sets the focus of the input control to the control with the given Id. The focus is set at the beginning
	of the next frame to avoid any input events from the current frame.

	Id: [String] The Id of the input control to focus.
--]]
function Slab.SetInputFocus(Id)
	Input.SetFocused(Id)
end

--[[
	SetInputCursorPos

	Sets the absolute text position in bytes of the focused input control. This value is applied on the next frame.
	This function can be combined with the SetInputFocus function to modify the cursor positioning of the desired
	input control. Note that the input control supports UTF8 characters so if the desired position is not a valid
	character, the position will be altered to find the next closest valid character.

	Pos: [Number] The absolute position in bytes of the text of the focused input control.
--]]
function Slab.SetInputCursorPos(Pos)
	Input.SetCursorPos(Pos)
end

--[[
	SetInputCursorPosLine

	Sets the column and line number of the focused input control. These values are applied on the next frame. This
	function behaves the same as SetInputCursorPos, but allows for setting the cursor by column and line.

	Column: [Number] The text position in bytes of the current line.
	Line: [Number] The line number to set.
--]]
function Slab.SetInputCursorPosLine(Column, Line)
	Input.SetCursorPosLine(Column, Line)
end

--[[
	BeginTree

	This function will render a tree item with an optional label. The tree can be expanded or collapsed based on whether
	the user clicked on the tree item. This function can also be nested to create a hierarchy of tree items. This function
	will return false when collapsed and true when expanded. If this function returns true, Slab.EndTree must be called in
	order for this tree item to behave properly. The hot zone of this tree item will be the height of the label and the width
	of the window by default.

	Id: [String/Table] A string or table uniquely identifying this tree item within the context of the window. If the given Id
		is a table, then the internal Tree entry for this table will be removed once the table has been garbage collected.
	Options: [Table] List of options for how this tree item will behave.
		Label: [String] The text to be rendered for this tree item.
		Tooltip: [String] The text to be rendered when the user hovers over this tree item.
		IsLeaf: [Boolean] If this is true, this tree item will not be expandable/collapsable.
		OpenWithHighlight: [Boolean] If this is true, the tree will be expanded/collapsed when the user hovers over the hot
			zone of this tree item. If this is false, the user must click the expand/collapse icon to interact with this tree
			item.
		Icon: [Table] List of options to use for drawing the icon. Refer to the 'Image' documentation for more information.
		IsSelected: [Boolean] If true, will render a highlight rectangle around the tree item.
		IsOpen: [Boolean] Will force the tree item to be expanded.
		NoSavedSettings: [Boolean] Flag to disable saving this tree's settings to the state INI file.

	Return: [Boolean] Returns true if this tree item is expanded. Slab.EndTree must be called if this returns true.
--]]
function Slab.BeginTree(Id, Options)
	return Tree.Begin(Id, Options)
end

--[[
	EndTree

	Finishes up any BeginTree calls if those functions return true.

	Return: None.
--]]
function Slab.EndTree()
	Tree.End()
end

--[[
	BeginComboBox

	This function renders a non-editable input field with a drop down arrow. When the user clicks this option, a window is
	created and the user can supply their own Slab.TextSelectable calls to add possible items to select from. This function
	will return true if the combo box is opened. Slab.EndComboBox must be called if this function returns true.

	Example:
		local Options = {"Apple", "Banana", "Orange", "Pear", "Lemon"}
		local Options_Selected = ""
		if Slab.BeginComboBox('Fruits', {Selected = Options_Selected}) then
			for K, V in pairs(Options) do
				if Slab.TextSelectable(V) then
					Options_Selected = V
				end
			end

			Slab.EndComboBox()
		end

	Id: [String] A string that uniquely identifies this combo box within the context of the active window.
	Options: [Table] List of options that control how this combo box behaves.
		Tooltip: [String] Text that is rendered when the user hovers over this combo box.
		Selected: [String] Text that is displayed in the non-editable input box for this combo box.
		W: [Number] The width of the combo box. The default value is 150.0.
		Rounding: [Number] Amount of rounding to apply to the corners of the combo box.

	Return: [Boolean] This function will return true if the combo box is open.
--]]
function Slab.BeginComboBox(Id, Options)
	return ComboBox.Begin(Id, Options)
end

--[[
	EndComboBox

	Finishes up any BeginComboBox calls if those functions return true.

	Return: None.
--]]
function Slab.EndComboBox()
	ComboBox.End()
end

--[[
	Image

	Draws an image at the current cursor position. The Id uniquely identifies this
	image to manage behaviors with this image. An image can be supplied through the
	options or a path can be specified which Slab will manage the loading and storing of
	the image reference.

	Id: [String] A string uniquely identifying this image within the context of the current window.
	Options: [Table] List of options controlling how the image should be drawn.
		Image: [Object] A user supplied image. This must be a valid Love image or the call will assert.
		Path: [String] If the Image option is nil, then a path must be specified. Slab will load and
			manage the image resource.
		Rotation: [Number] The rotation value to apply when this image is drawn.
		Scale: [Number] The scale value to apply to both the X and Y axis.
		ScaleX: [Number] The scale value to apply to the X axis.
		ScaleY: [Number] The scale value to apply to the Y axis.
		Color: [Table] The color to use when rendering this image.
		SubX: [Number] The X-coordinate used inside the given image.
		SubY: [Number] The Y-coordinate used inside the given image.
		SubW: [Number] The width used inside the given image.
		SubH: [Number] The height used insided the given image.
		WrapX: [String] The horizontal wrapping mode for this image. The available options are 'clamp', 'repeat',
			'mirroredrepeat', and 'clampzero'. For more information refer to the Love2D documentation on wrap modes at
			https://love2d.org/wiki/WrapMode.
		WrapY: [String] The vertical wrapping mode for this image. The available options are 'clamp', 'repeat',
			'mirroredrepeat', and 'clampzero'. For more information refer to the Love2D documentation on wrap modes at
			https://love2d.org/wiki/WrapMode.
		UseOutline: [Boolean] If set to true, a rectangle will be drawn around the given image. If 'SubW' or 'SubH' are specified, these
			values will be used instead of the image's dimensions.
		OutlineColor: [Table] The color used to draw the outline. Default color is black.
		OutlineW: [Number] The width used for the outline. Default value is 1.
		W: [Number] The width the image should be resized to.
		H: [Number] The height the image should be resized to.

	Return: None.
--]]
function Slab.Image(Id, Options)
	Image.Begin(Id, Options)
end

--[[
	SameLine

	This forces the cursor to move back up to the same line as the previous widget. By default, all Slab widgets will
	advance the cursor to the next line based on the height of the current line. By using this call with other widget
	calls, the user will be able to set up multiple widgets on the same line to control how a window may look.

	Options: [Table] List of options that controls how the cursor should handle the same line.
		Pad: [Number] Extra padding to apply in the X direction.
		CenterY: [Boolean] Controls whether the cursor should be centered in the Y direction on the line. By default
			the line will use the NewLineSize, which is the height of the current font to center the cursor.

	Return: None.
--]]
function Slab.SameLine(Options)
	LayoutManager.SameLine(Options)
end

--[[
	NewLine

	This forces the cursor to advance to the next line based on the height of the current font.

	Count: [Number] Specify how many new lines to insert, defaults to 1

	Return: None.
--]]
function Slab.NewLine(Count)
	Count = Count or 1
	for i = 1, Count do
		LayoutManager.NewLine()
	end
end

--[[
	SetCursorPos

	Sets the cursor position. The default behavior is to set the cursor position relative to
	the current window. The absolute position can be set if the 'Absolute' option is set.

	Controls will only be drawn within a window. If the cursor is set outside of the current
	window context, the control will not be displayed.

	X: [Number] The X coordinate to place the cursor. If nil, then the X coordinate is not modified.
	Y: [Number] The Y coordinate to place the cursor. If nil, then the Y coordinate is not modified.
	Options: [Table] List of options that control how the cursor position should be set.
		Absolute: [Boolean] If true, will place the cursor using absolute coordinates.

	Return: None.
--]]
function Slab.SetCursorPos(X, Y, Options)
	Options = Options == nil and {} or Options
	Options.Absolute = Options.Absolute == nil and false or Options.Absolute

	if Options.Absolute then
		X = X == nil and Cursor.GetX() or X
		Y = Y == nil and Cursor.GetY() or Y
		Cursor.SetPosition(X, Y)
	else
		X = X == nil and Cursor.GetX() - Cursor.GetAnchorX() or X
		Y = Y == nil and Cursor.GetY() - Cursor.GetAnchorY() or Y
		Cursor.SetRelativePosition(X, Y)
	end
end

--[[
	GetCursorPos

	Gets the cursor position. The default behavior is to get the cursor position relative to
	the current window. The absolute position can be retrieved if the 'Absolute' option is set.

	Options: [Table] List of options that control how the cursor position should be retrieved.
		Absolute: [Boolean] If true, will return the cursor position in absolute coordinates.

	Return: [Number], [Number] The X and Y coordinates of the cursor.
--]]
function Slab.GetCursorPos(Options)
	Options = Options == nil and {} or Options
	Options.Absolute = Options.Absolute == nil and false or Options.Absolute

	local X, Y = Cursor.GetPosition()

	if not Options.Absolute then
		X = X - Cursor.GetAnchorX()
		Y = Y - Cursor.GetAnchorY()
	end

	return X, Y
end

--[[
	Indent

	Advances the anchored X position of the cursor. All subsequent lines will begin at the new cursor position. This function
	has no effect when columns are present.

	Width: [Number] How far in pixels to advance the cursor. If nil, then the default value identified by the 'Indent'
		property in the current style is used.

	Return: None.
--]]
function Slab.Indent(Width)
	Width = Width == nil and Style.Indent or Width
	Cursor.Indent(Width)
end

--[[
	Unindent

	Retreats the anchored X position of the cursor. All subsequent lines will begin at the new cursor position. This function
	has no effect when columns are present.

	Width: [Number] How far in pixels to retreat the cursor. If nil, then the default value identified by the 'Indent'
		property in the current style is used.

	Return: None.
--]]
function Slab.Unindent(Width)
	Width = Width == nil and Style.Indent or Width
	Cursor.Unindent(Width)
end

--[[
	Properties

	Iterates through the table's key-value pairs and adds them to the active window. This currently only does
	a shallow loop and will not iterate through nested tables.

	TODO: Iterate through nested tables.

	Table: [Table] The list of properties to build widgets for.
	Options: [Table] List of options that can applied to a specific property. The key should match an entry in the
		'Table' argument and will apply any additional options to the property control.
	Fallback: [Table] List of options that can be applied to any property if an entry was not found in the 'Options'
		argument.

	Return: None.
--]]
function Slab.Properties(Table, Options, Fallback)
	Options = Options or {}
	Fallback = Fallback or {}

	if Table ~= nil then
		for I, T in ipairs(Table) do
			local V = T.Value
			local Type = type(V)
			local ID = T.ID
			local ItemOptions = Options[ID] or Fallback
			if Type == "boolean" then
				if Slab.CheckBox(V, ID, ItemOptions) then
					T.Value = not T.Value
				end
			elseif Type == "number" then
				Slab.Text(ID .. ": ")
				Slab.SameLine()
				ItemOptions.Text = V
				ItemOptions.NumbersOnly = true
				ItemOptions.ReturnOnText = false
				ItemOptions.UseSlider = ItemOptions.MinNumber and ItemOptions.MaxNumber
				if Slab.Input(ID, ItemOptions) then
					T.Value = Slab.GetInputNumber()
				end
			elseif Type == "string" then
				Slab.Text(ID .. ": ")
				Slab.SameLine()
				ItemOptions.Text = V
				ItemOptions.NumbersOnly = false
				ItemOptions.ReturnOnText = false
				if Slab.Input(ID, ItemOptions) then
					T.Value = Slab.GetInputText()
				end
			end
		end
	end
end

--[[
	BeginListBox

	Begins the process of creating a list box. If this function is called, EndListBox must be called after all
	items have been added.

	Id: [String] A string uniquely identifying this list box within the context of the current window.
	Options: [Table] List of options controlling the behavior of the list box.
		W: [Number] The width of the list box. If nil, a default value of 150 is used.
		H: [Number] The height of the list box. If nil, a default value of 150 is used.
		Clear: [Boolean] Clears out the items in the list. It is recommended to only call this if the list items
			has changed and should not be set to true on every frame.
		Rounding: [Number] Amount of rounding to apply to the corners of the list box.
		StretchW: [Boolean] Stretch the list box to fill the remaining width of the window.
		StretchH: [Boolean] Stretch the list box to fill the remaining height of the window.

	Return: None.
--]]
function Slab.BeginListBox(Id, Options)
	ListBox.Begin(Id, Options)
end

--[[
	EndListBox

	Ends the list box container. Will close off the region and properly adjust the cursor.

	Return: None.
--]]
function Slab.EndListBox()
	ListBox.End()
end

--[[
	BeginListBoxItem

	Adds an item to the current list box with the given Id. The user can then draw controls however they see
	fit to display a single item. This allows the user to draw list items such as a texture with a name or just
	a text to represent the item. If this is called, EndListBoxItem must be called to complete the item.

	Id: [String] A string uniquely identifying this item within the context of the current list box.
	Options: [Table] List of options that control the behavior of the active list item.
		Selected: [Boolean] If true, will draw the item with a selection background.

	Return: None.
--]]
function Slab.BeginListBoxItem(Id, Options)
	ListBox.BeginItem(Id, Options)
end

--[[
	IsListBoxItemClicked

	Checks to see if a hot list item is clicked. This should only be called within a BeginListBoxLitem/EndListBoxItem
	block.

	Button: [Number] The button to check for the click of the item.
	IsDoubleClick: [Boolean] Check for double-click instead of single click.

	Return: [Boolean] Returns true if the active item is hovered with mouse and the requested mouse button is clicked.
--]]
function Slab.IsListBoxItemClicked(Button, IsDoubleClick)
	return ListBox.IsItemClicked(Button, IsDoubleClick)
end

--[[
	EndListBoxItem

	Ends the current item and commits the bounds of the item to the list.

	Return: None.
--]]
function Slab.EndListBoxItem()
	ListBox.EndItem()
end

--[[
	OpenDialog

	Opens the dialog box with the given Id. If the dialog box was opened, then it is pushed onto the stack.
	Calls to the BeginDialog with this same Id will return true if opened.

	Id: [String] A string uniquely identifying this dialog box.

	Return: None.
--]]
function Slab.OpenDialog(Id)
	Dialog.Open(Id)
end

--[[
	BeginDialog

	Begins the dialog window with the given Id if it is open. If this function returns true, then EndDialog must be called.
	Dialog boxes are windows which are centered in the center of the viewport. The dialog box cannot be moved and will
	capture all input from all other windows.

	Id: [String] A string uniquely identifying this dialog box.
	Options: [Table] List of options that control how this dialog box behaves. These are the same parameters found
		for BeginWindow, with some caveats. Certain options are overridden by the Dialog system. They are:
			X, Y, Layer, AllowFocus, AllowMove, and AutoSizeWindow.

	Return: [Boolean] Returns true if the dialog with the given Id is open.
--]]
function Slab.BeginDialog(Id, Options)
	return Dialog.Begin(Id, Options)
end

--[[
	EndDialog

	Ends the dialog window if a call to BeginDialog returns true.

	Return: None.
--]]
function Slab.EndDialog()
	Dialog.End()
end

--[[
	CloseDialog

	Closes the currently active dialog box.

	Return: None.
--]]
function Slab.CloseDialog()
	Dialog.Close()
end

--[[
	MessageBox

	Opens a message box to be displayed to the user with a title and a message. Buttons can be specified through the options
	table which when clicked, the string of the button is returned. This function should be called every frame when a message
	box wants to be displayed.

	Title: [String] The title to display for the message box.
	Message: [String] The message to be displayed. The text is aligned in the center. Multi-line strings are supported.
	Options: [Table] List of options to control the behavior of the message box.
		Buttons: [Table] List of buttons to display with the message box. The order of the buttons are displayed from right to left.

	Return: [String] The name of the button that was clicked. If none was clicked, an emtpy string is returned.
--]]
function Slab.MessageBox(Title, Message, Options)
	return Dialog.MessageBox(Title, Message, Options)
end

--[[
	FileDialog

	Opens up a dialog box that displays a file explorer for opening or saving files or directories. This function does not create any file
	handles, it just returns the list of files selected by the user.

	Options: [Table] List of options that control the behavior of the file dialog.
		AllowMultiSelect: [Boolean] Allows the user to select multiple items in the file dialog.
		Directory: [String] The starting directory when the file dialog is open. If none is specified, the dialog
			will start at love.filesystem.getSourceBaseDirectory and the dialog will remember the last
			directory navigated to by the user between calls to this function.
		Type: [String] The type of file dialog to use. The options are:
			openfile: This is the default method. The user will have access to both directories and files. However,
				only file selections are returned.
			opendirectory: This type is used to filter the file dialog for directories only. No files will appear
				in the list.
			savefile: This type is used to select a name of a file to save. The user will be prompted if they wish to overwrite
				an existing file.
		Filters: [Table] A list of filters the user can select from when browsing files. The table can contain tables or strings.
			Table: If a table is used for a filter, it should contain two elements. The first element is the filter while the second
				element is the description of the filter e.g. {"*.lua", "Lua Files"}
			String: If a raw string is used, then it should just be the filter. It is recommended to use the table option since a
				description can be given for each filter.
		IncludeParent: [Boolean] This option will include the parent '..' directory item in the file/dialog list. This option is
			true by default.

	Return: [Table] Returns items for how the user interacted with this file dialog.
		Button: [String] The button the user clicked. Will either be OK or Cancel.
		Files: [Table] An array of selected file items the user selected when OK is pressed. Will be empty otherwise.
--]]
function Slab.FileDialog(Options)
	return Dialog.FileDialog(Options)
end

--[[
	ColorPicker

	Displays a window to allow the user to pick a hue and saturation value of a color. This should be called every frame and the result
	should be handled to stop displaying the color picker and store the resulting color.

	Options: [Table] List of options that control the behavior of the color picker.
		Color: [Table] The color to modify. This should be in the format of 0-1 for each color component (RGBA).

	Return: [Table] Returns the button and color the user has selected.
		Button: [Number] The button the user clicked. 1 - OK. 0 - No Interaction. -1 - Cancel.
		Color: [Table] The new color the user has chosen. This will always be returned.
--]]
function Slab.ColorPicker(Options)
	return ColorPicker.Begin(Options)
end

--[[
	IsMouseDown

	Determines if a given mouse button is down.

	Button: [Number] The button to check for. The valid numbers are: 1 - Left, 2 - Right, 3 - Middle.

	Return: [Boolean] True if the given button is down. False otherwise.
--]]
function Slab.IsMouseDown(Button)
	return Mouse.IsDown(Button and Button or 1)
end

--[[
	IsMouseClicked

	Determines if a given mouse button changes state from up to down this frame.

	Button: [Number] The button to check for. The valid numbers are: 1 - Left, 2 - Right, 3 - Middle.

	Return: [Boolean] True if the given button changes state from up to down. False otherwise.
--]]
function Slab.IsMouseClicked(Button)
	return Mouse.IsClicked(Button and Button or 1)
end

--[[
	IsMouseReleased

	Determines if a given mouse button changes state from down to up this frame.

	Button: [Number] The button to check for. The valid numbers are: 1 - Left, 2 - Right, 3 - Middle.

	Return: [Boolean] True if the given button changes state from down to up. False otherwise.
--]]
function Slab.IsMouseReleased(Button)
	return Mouse.IsReleased(Button and Button or 1)
end

--[[
	IsMouseDoubleClicked

	Determines if a given mouse button has been clicked twice within a given time frame.

	Button: [Number] The button to check for. The valid numbers are: 1 - Left, 2 - Right, 3 - Middle.

	Return: [Boolean] True if the given button was double clicked. False otherwise.
--]]
function Slab.IsMouseDoubleClicked(Button)
	return Mouse.IsDoubleClicked(Button and Button or 1)
end

--[[
	IsMouseDragging

	Determines if a given mouse button is down and there has been movement.

	Button: [Number] The button to check for. The valid numbers are: 1 - Left, 2 - Right, 3 - Middle.

	Return: [Boolean] True if the button is held down and is moving. False otherwise.
--]]
function Slab.IsMouseDragging(Button)
	return Mouse.IsDragging(Button and Button or 1)
end

--[[
	GetMousePosition

	Retrieves the current mouse position in the viewport.

	Return: [Number], [Number] The X and Y coordinates of the mouse position.
--]]
function Slab.GetMousePosition()
	return Mouse.Position()
end

--[[
	GetMousePositionWindow

	Retrieves the current mouse position within the current window. This position will include any transformations
	added to the window such as scrolling.

	Return: [Number], [Number] The X and Y coordinates of the mouse position within the window.
--]]
function Slab.GetMousePositionWindow()
	return Window.GetMousePosition()
end

--[[
	GetMouseDelta

	Retrieves the change in mouse coordinates from the last frame.

	Return: [Number], [Number] The X and Y coordinates of the delta from the last frame.
--]]
function Slab.GetMouseDelta()
	return Mouse.GetDelta()
end

--[[
	SetCustomMouseCursor

	Overrides a system mouse cursor of the given type to render a custom image instead.

	Type: [String] The system cursor type to replace. This can be one of the following values: 'arrow', 'sizewe', 'sizens', 'sizenesw', 'sizenwse', 'ibeam', 'hand'.
	Image: [Table] An 'Image' object created from love.graphics.newImage. If this is nil, then an empty image is created and is drawn when the system cursor is activated.
	Quad: [Table] A 'Quad' object created from love.graphics.newQuad. This allows support for setting UVs of an image to render.
--]]
function Slab.SetCustomMouseCursor(Type, Image, Quad)
	Mouse.SetCustomCursor(Type, Image, Quad)
end

--[[
	ClearCustomMouseCursor

	Removes any override of a system mouse cursor with the given type and defaults to the OS specific mouse cursor.

	Type: [String] The system cursor type to remove. This can be one of the following values: 'arrow', 'sizewe', 'sizens', 'sizenesw', 'sizenwse', 'ibeam', 'hand'.
--]]
function Slab.ClearCustomMouseCursor(Type)
	Mouse.ClearCustomCursor(Type)
end

--[[
	IsControlHovered

	Checks to see if the last control added to the window is hovered by the mouse.

	Return: [Boolean] True if the last control is hovered, false otherwise.
--]]
function Slab.IsControlHovered()
	-- Prevent hovered checks on mobile if user is not dragging a touch.
	if Utility.IsMobile() and not Slab.IsMouseDown() then
		return false
	end

	local Result = Window.IsItemHot()

	if not Result and not Window.IsObstructedAtMouse() then
		local X, Y = Slab.GetMousePositionWindow()
		Result = Cursor.IsInItemBounds(X, Y)
	end

	return Result
end

--[[
	IsControlClicked

	Checks to see if the previous control is hovered and clicked.

	Button: [Number] The button to check for. The valid numbers are: 1 - Left, 2 - Right, 3 - Middle.

	Return: [Boolean] True if the previous control is hovered and clicked. False otherwise.
--]]
function Slab.IsControlClicked(Button)
	return Slab.IsControlHovered() and Slab.IsMouseClicked(Button)
end

--[[
	GetControlSize

	Retrieves the last declared control's size.

	Return: [Number], [Number] The width and height of the last control declared.
--]]
function Slab.GetControlSize()
	local X, Y, W, H = Cursor.GetItemBounds()
	return W, H
end

--[[
	IsVoidHovered

	Checks to see if any non-Slab area of the viewport is hovered.

	Return: [Boolean] True if any non-Slab area of the viewport is hovered. False otherwise.
--]]
function Slab.IsVoidHovered()
	-- Prevent hovered checks on mobile if user is not dragging a touch.
	if Utility.IsMobile() and not Slab.IsMouseDown() then
		return false
	end

	return Region.GetHotInstanceId() == '' and not Region.IsScrolling()
end

--[[
	IsVoidClicked

	Checks to see if any non-Slab area of the viewport is clicked.

	Button: [Number] The button to check for. The valid numbers are: 1 - Left, 2 - Right, 3 - Middle.

	Return: [Boolean] True if any non-Slab area of the viewport is clicked. False otherwise.
--]]
function Slab.IsVoidClicked(Button)
	return Slab.IsMouseClicked(Button) and Slab.IsVoidHovered()
end

--[[
	IsKeyDown

	Checks to see if a specific key is held down. The key should be one of the love defined Scancode which the list can
	be found at https://love2d.org/wiki/Scancode.

	Key: [String] A love defined key scancode.

	Return: [Boolean] True if the key is held down. False otherwise.
--]]
function Slab.IsKeyDown(Key)
	return Keyboard.IsDown(Key)
end

--[[
	IsKeyPressed

	Checks to see if a specific key state went from up to down this frame. The key should be one of the love defined Scancode which the list can
	be found at https://love2d.org/wiki/Scancode.

	Key: [String] A love defined scancode.

	Return: [Boolean] True if the key state went from up to down this frame. False otherwise.
--]]
function Slab.IsKeyPressed(Key)
	return Keyboard.IsPressed(Key)
end

--[[
	IsKeyPressed

	Checks to see if a specific key state went from down to up this frame. The key should be one of the love defined Scancode which the list can
	be found at https://love2d.org/wiki/Scancode.

	Key: [String] A love defined scancode.

	Return: [Boolean] True if the key state went from down to up this frame. False otherwise.
--]]
function Slab.IsKeyReleased(Key)
	return Keyboard.IsReleased(Key)
end

--[[
	Rectangle

	Draws a rectangle at the current cursor position for the active window.

	Options: [Table] List of options that control how this rectangle is displayed.
		Mode: [String] Whether this rectangle should be filled or outlined. The default value is 'fill'.
		W: [Number] The width of the rectangle.
		H: [Number] The height of the rectangle.
		Color: [Table] The color to use for this rectangle.
		Rounding: [Number] or [Table]
			[Number] Amount of rounding to apply to all corners.
			[Table] Define the rounding for each corner. The order goes top left, top right, bottom right, and bottom left.
		Outline: [Boolean] If the Mode option is 'fill', this option will allow an outline to be drawn.
		OutlineColor: [Table] The color to use for the outline if requested.
		Segments: [Number] Number of points to add for each corner if rounding is requested.

	Return: None.
--]]
function Slab.Rectangle(Options)
	Shape.Rectangle(Options)
end

--[[
	Circle

	Draws a circle at the current cursor position plus the radius for the active window.

	Options: [Table] List of options that control how this circle is displayed.
		Mode: [String] Whether this circle should be filled or outlined. The default value is 'fill'.
		Radius: [Number] The size of the circle.
		Color: [Table] The color to use for the circle.
		Segments: [Number] The number of segments used for drawing the circle.

	Return: None.
--]]
function Slab.Circle(Options)
	Shape.Circle(Options)
end

--[[
	Triangle

	Draws a triangle at the current cursor position plus the radius for the active window.

	Option: [Table] List of options that control how this triangle is displayed.
		Mode: [String] Whether this triangle should be filled or outlined. The default value is 'fill'.
		Radius: [Number] The distance from the center of the triangle.
		Rotation: [Number] The rotation of the triangle in degrees.
		Color: [Table] The color to use for the triangle.

	Return: None.
--]]
function Slab.Triangle(Options)
	Shape.Triangle(Options)
end

--[[
	Line

	Draws a line starting at the current cursor position and going to the defined points in this function.

	X2: [Number] The X coordinate for the destination.
	Y2: [Number] The Y coordinate for the destination.
	Option: [Table] List of options that control how this line is displayed.
		Width: [Number] How thick the line should be.
		Color: [Table] The color to use for the line.

	Return: None.
--]]
function Slab.Line(X2, Y2, Options)
	Shape.Line(X2, Y2, Options)
end

--[[
	Curve

	Draws a bezier curve with the given points as control points. The points should be defined in local space. Slab will translate the curve to the
	current cursor position. There should two or more points defined for a proper curve.

	Points: [Table] List of points to define the control points of the curve.
	Options: [Table] List of options that control how this curve is displayed.
		Color: [Table] The color to use for this curve.
		Depth: [Number] The number of recursive subdivision steps to use when rendering the curve. If nil, the default LÖVE 2D value is used which is 5.

	Return: None.
--]]
function Slab.Curve(Points, Options)
	Shape.Curve(Points, Options)
end

--[[
	GetCurveControlPointCount

	Returns the number of control points defined with the last call to Curve.

	Return: [Number] The number of control points defined for the previous curve.
--]]
function Slab.GetCurveControlPointCount()
	return Shape.GetCurveControlPointCount()
end

--[[
	GetCurveControlPoint

	Returns the point for the given control point index. This point by default will be in local space defined by the points given in the Curve function.
	The translated position can be requested by setting the LocalSpace option to false.

	Index: [Number] The index of the control point to retrieve.
	Options: [Table] A list of options that control what is returned by this function.
		LocalSpace: [Boolean] Returns either the translated or untranslated control point. This is true by default.

	Return: [Number], [Number] The translated X, Y coordinates of the given control point.
--]]
function Slab.GetCurveControlPoint(Index, Options)
	return Shape.GetCurveControlPoint(Index, Options)
end

--[[
	EvaluateCurve

	Returns the point at the given time. The time value should be between 0 and 1 inclusive. The point returned will be in local space. For the translated
	position, set the LocalSpace option to false.

	Time: [Number] The time on the curve between 0 and 1.
	Options: [Table] A list of options that control what is returned by this function.
		LocalSpace: [Boolean] Returnes either the translated or untranslated control point. This is true by default.

	Return: [Number], [Number] The X and Y coordinates at the given time on the curve.
--]]
function Slab.EvaluateCurve(Time, Options)
	return Shape.EvaluateCurve(Time, Options)
end

--[[
	EvaluateCurveMouse

	Returns the point on the curve at the given X-coordinate of the mouse relative to the end points of the curve.

	Options: [Table] A list of options that control what is returned by this function.
		Refer to the documentation for EvaluateCurve for the list of options.

	Return: [Number], [Number] The X and Y coordinates at the given X mouse position on the curve.
--]]
function Slab.EvaluateCurveMouse(Options)
	local X1, Y1 = Slab.GetCurveControlPoint(1, {LocalSpace = false})
	local X2, Y2 = Slab.GetCurveControlPoint(Slab.GetCurveControlPointCount(), {LocalSpace = false})
	local Left = math.min(X1, X2)
	local W = math.abs(X2 - X1)
	local X, Y = Slab.GetMousePositionWindow()
	local Offset = math.max(X - Left, 0.0)
	Offset = math.min(Offset, W)

	return Slab.EvaluateCurve(Offset / W, Options)
end

--[[
	Polygon

	Renders a polygon with the given points. The points should be defined in local space. Slab will translate the position to the current cursor position.

	Points: [Table] List of points that define this polygon.
	Options: [Table] List of options that control how this polygon is drawn.
		Color: [Table] The color to render this polygon.
		Mode: [String] Whether to use 'fill' or 'line' to draw this polygon. The default is 'fill'.

	Return: None.
--]]
function Slab.Polygon(Points, Options)
	Shape.Polygon(Points, Options)
end

--[[
	BeginStat

	Starts the timer for the specific stat in the given category.

	Name: [String] The name of the stat to capture.
	Category: [String] The category this stat belongs to.

	Return: [Number] The handle identifying this stat capture.
--]]
function Slab.BeginStat(Name, Category)
	return Stats.Begin(Name, Category)
end

--[[
	EndStat

	Ends the timer for the stat assigned to the given handle.

	Handle: [Number] The handle identifying a BeginStat call.

	Return: None.
--]]
function Slab.EndStat(Handle)
	Stats.End(Handle)
end

--[[
	EnableStats

	Sets the enabled state of the stats system. The system is disabled by default.

	Enable: [Boolean] The new state of the states system.

	Return: None.
--]]
function Slab.EnableStats(Enable)
	Stats.SetEnabled(Enable)
end

--[[
	IsStatsEnabled

	Query whether the stats system is enabled or disabled.

	Return: [Boolean] Returns whether the stats system is enabled or disabled.
--]]
function Slab.IsStatsEnabled()
	return Stats.IsEnabled()
end

--[[
	FlushStats

	Resets the stats system to an empty state.

	Return: None.
--]]
function Slab.FlushStats()
	Stats.Flush()
end

--[[
	GetStats

	Get the love.graphics.getStats of the Slab.
	Stats.SetEnabled(true) must be previously set to enable this.
	Must be called in love.draw (recommended at the end of draw)

	Return: Table.
--]]

function Slab.GetStats()
	return StatsData
end

--[[
	CalculateStats

	Calculate the passed love.graphics.getStats table of love by subtracting
	the stats of Slab.
	Stats.SetEnabled(true) must be previously set to enable this.
	Must be called in love.draw (recommended at the end of draw)

	Return: Table.
--]]

function Slab.CalculateStats(LoveStats)
	for k, v in pairs(LoveStats) do
		if StatsData[k] then
			LoveStats[k] = v - StatsData[k]
		end
	end
	return LoveStats
end

--[[
	BeginLayout

	Enables the layout manager and positions the controls between this call and EndLayout based on the given options. The anchor
	position for the layout is determined by the current cursor position on the Y axis. The horizontal position is not anchored.
	Layouts are stacked, so there can be layouts within parent layouts.

	Id: [String] The Id of this layout.
	Options: [Table] List of options that control how this layout behaves.
		AlignX: [String] Defines how the controls should be positioned horizontally in the window. The available options are
			'left', 'center', or 'right'. The default option is 'left'.
		AlignY: [String] Defines how the controls should be positioned vertically in the window. The available options are
			'top', 'center', or 'bottom'. The default option is 'top'. The top is determined by the current cursor position.
		AlignRowY: [String] Defines how the controls should be positioned vertically within a row. The available options are
			'top', 'center', or 'bottom'. The default option is 'top'.
		Ignore: [Boolean] Should this layout ignore positioning of controls. This is useful if certain controls need custom
			positioning within a layout.
		ExpandW: [Boolean] If true, will expand all controls' width within the row to the size of the window.
		ExpandH: [Boolean] If true, will expand all controls' height within the row and the size of the window.
		AnchorX: [Boolean] Anchors the layout management at the current X cursor position. The size is calculated using this position.
			The default value for this is false.
		AnchorY: [Boolean] Anchors the layout management at the current Y cursor position. The size is calculated using this position.
			The default value for this is true.
		Columns: [Number] The number of columns to use for this layout. The default value is 1.

	Return: None.
--]]
function Slab.BeginLayout(Id, Options)
	LayoutManager.Begin(Id, Options)
end

--[[
	EndLayout

	Ends the currently active layout. Each BeginLayout call must have a matching EndLayout. Failure to do so will result in
	an assertion.

	Return: None.
--]]
function Slab.EndLayout()
	LayoutManager.End()
end

--[[
	SetLayoutColumn

	Sets the current active column.

	Index: [Number] The index of the column to be active.

	Return: None.
--]]
function Slab.SetLayoutColumn(Index)
	LayoutManager.SetColumn(Index)
end

--[[
	GetLayoutSize

	Retrieves the size of the active layout. If there are columns, then the size of the column is returned.

	Return: [Number], [Number] The width and height of the active layout. 0 is returned if no layout is active.
--]]
function Slab.GetLayoutSize()
	return LayoutManager.GetActiveSize()
end

--[[
	GetCurrentColumnIndex

	Retrieves the current index of the active column.

	Return: [Number] The current index of the active column of the active layout. 0 is returned if no layout or column is active.
--]]
function Slab.GetCurrentColumnIndex()
	return LayoutManager.GetCurrentColumnIndex()
end

--[[
	SetScrollSpeed

	Sets the speed of scrolling when using the mouse wheel.

	Return: None.
--]]
function Slab.SetScrollSpeed(Speed)
	Region.SetWheelSpeed(Speed)
end

--[[
	GetScrollSpeed

	Retrieves the speed of scrolling for the mouse wheel.

	Return: [Number] The current wheel scroll speed.
--]]
function Slab.GetScrollSpeed()
	return Region.GetWheelSpeed()
end

--[[
	PushShader

	Pushes a shader effect to be applied to any following controls before a call to PopShader. Any shader effect that is still active
	will be cleared at the end of Slab's draw call.

	Shader: [Object] The shader object created with the love.graphics.newShader function. This object should be managed by the caller.

	Return: None.
--]]
function Slab.PushShader(Shader)
	DrawCommands.PushShader(Shader)
end

--[[
	PopShader

	Pops the currently active shader effect. Will enable the next active shader on the stack. If none exists, no shader is applied.

	Return: None.
--]]
function Slab.PopShader()
	DrawCommands.PopShader()
end

--[[
	EnableDocks

	Enables the docking functionality for a particular side of the viewport.

	List: [String/Table] A single item or list of items to enable for docking. The valid options are 'Left', 'Right', or 'Bottom'.

	Return: None.
--]]
function Slab.EnableDocks(List)
	Dock.Toggle(List, true)
end

--[[
	DisableDocks

	Disables the docking functionality for a particular side of the viewport.

	List: [String/Table] A single item or list of items to disable for docking. The valid options are 'Left', 'Right', or 'Bottom'.

	Return: None.
--]]
function Slab.DisableDocks(List)
	Dock.Toggle(List, false)
end

--[[
	SetDockOptions

	Set options for a dock type.

	Type: [String] The type of dock to set options for. This can be 'Left', 'Right', or 'Bottom'.
	Options: [Table] List of options that control how a dock behaves.
		NoSavedSettings: [Boolean] Flag to disable saving a dock's settings to the state INI file.
--]]
function Slab.SetDockOptions(Type, Options)
	Dock.SetOptions(Type, Options)
end

--[[
	WindowToDoc

	Programatically set a window to dock.

	Type: [String] The type of dock to set options for. This can be 'Left', 'Right', or 'Bottom'.
--]]
function Slab.WindowToDock(Type)
	Window.ToDock(Type)
end

--[[
	ToLoveFile

	Moves a file to a temporary location and returns a Love2D friendly way to access the file. The returned string can be used in
	any Love2D function that takes a Filename

	Source: [String] An absolute path to a file on the disk, can take a value from FileDialog

	Return: [String] A Love2D Filename
]]
function Slab.ToLoveFile(Source)
	return FileSystem.ToLove(Source)
end

return Slab


================================================
FILE: Internal/Core/Config.lua
================================================
--[[

MIT License

Copyright (c) 2019-2021 Love2D Community <love2d.org>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

--]]

local FileSystem = require(SLAB_PATH .. '.Internal.Core.FileSystem')

local Config = {}
local DecodeValueFn = nil
local Section = nil

local function IsBasicType(Value)
	if Value ~= nil then
		local Type = type(Value)

		return Type == "number" or Type == "boolean" or Type == "string"
	end

	return false
end

local function IsArray(Table)
	if Table ~= nil and type(Table) == "table" then
		local N = 0
		for K, V in pairs(Table) do
			if type(K) ~= "number" then
				return false
			end

			if not IsBasicType(V) then
				return false
			end

			N = N + 1
		end

		return #Table == N
	end

	return false
end

local function EncodeValue(Value)
	local Result = ""

	if Value ~= nil then
		local Type = type(Value)
		if Type == "boolean" then
			Result = Value == true and "true" or "false"
		elseif Type == "number" or Type == "string" then
			Result = tostring(Value)
		end
	end

	return Result
end

local function EncodePair(Key, Value)
	local Result = tostring(Key) .. " = "

	if Value ~= nil then
		if type(Value) == "table" then
			if IsArray(Value) then
				Result = Result .. "(" .. table.concat(Value, ",") .. ")\n"
			else
				Result = Result .. "{"
				local First = true
				for K, V in pairs(Value) do
					if not First then
						Result = Result .. ","
					end
					Result = Result .. K .. "=" .. EncodeValue(V)
					First = false
				end
				Result = Result .. "}\n"
			end
		elseif IsBasicType(Value) then
			Result = Result .. tostring(Value) .. "\n"
		end
	end

	return Result
end

local function EncodeSection(Section, Values)
	local Result = "[" .. Section .. "]\n"

	for K, V in pairs(Values) do
		Result = Result .. EncodePair(K, V)
	end

	return Result .. "\n"
end

local function DecodeBoolean(Value)
	local Lower = string.lower(Value)

	if Lower == "true" then
		return true
	elseif Lower == "false" then
		return false
	end

	return nil
end

local function DecodeArray(Value)
	local Result = nil

	if string.sub(Value, 1, 1) == "(" then
		Result = {}
		local Index = 1
		local Buffer = ""

		while Index <= #Value do
			local Ch = string.sub(Value, Index, Index)

			if Ch == ',' or Ch == ')' then
				local Item = DecodeValueFn(Buffer)
				if Item ~= nil then
					table.insert(Result, Item)
				end
				Buffer = ""
			elseif Ch ~= "(" and Ch ~= " " then
				Buffer = Buffer .. Ch
			end

			Index = Index + 1
		end
	end

	return Result
end

local function DecodeTable(Value)
	local Result = nil

	if string.sub(Value, 1, 1) == "{" then
		Result = {}
		for K, V in string.gmatch(Value, "(%w+)=(%-?%w+)") do
			Result[K] = DecodeValueFn(V)
		end
	end

	return Result
end

local function DecodeValue(Value)
	if Value ~= nil and Value ~= "" then
		local Number = tonumber(Value)
		if Number ~= nil then
			return Number
		end

		local Boolean = DecodeBoolean(Value)
		if Boolean ~= nil then
			return Boolean
		end

		if Value == "nil" then
			return nil
		end

		local Array = DecodeArray(Value)
		if Array ~= nil then
			return Array
		end

		local Table = DecodeTable(Value)
		if Table ~= nil then
			return Table
		end

		return Value
	end

	return nil
end

DecodeValueFn = DecodeValue

local function DecodeLine(Line, Result)
	if string.sub(Line, 1, 1) == ";" then
		return
	end

	if string.sub(Line, 1, 1) == "[" and string.sub(Line, #Line, #Line) == "]" then
		local Key = string.sub(Line, 2, #Line - 1)
		Result[Key] = {}
		Section = Result[Key]
	end

	local Index = string.find(Line, "=", 1, true)

	if Index ~= nil then
		local Key = string.sub(Line, 1, Index - 1)
		Key = string.gsub(Key, " ", "")

		local Value = string.sub(Line, Index + 1)
		Value = string.gsub(Value, " ", "")

		if string.sub(Value, #Value, #Value) == "," then
			Value = string.sub(Value, 1, #Value - 1)
		end

		if Section ~= nil then
			Section[Key] = DecodeValue(Value)
		else
			Result[Key] = DecodeValue(Value)
		end
	end
end

function Config.Encode(Table)
	local Result = ""

	if type(Table) == "table" and not IsArray(Table) then
		local Sections = {}
		for K, V in pairs(Table) do
			if type(V) == "table" and not IsArray(V) then
				Sections[K] = V
			else
				Result = Result .. EncodePair(K, V)
			end
		end

		if string.len(Result) > 0 then
			Result = Result .. "\n"
		end

		for K, V in pairs(Sections) do
			Result = Result .. EncodeSection(K, V)
		end
	end

	return Result
end

function Config.Decode(Stream)
	local Result = nil
	local Error = ""

	if Stream ~= nil then
		if type(Stream) == "string" then
			Result = {}

			local Start = 1
			local End = string.find(Stream, "\n", Start, true)
			local Line = ""

			while End ~= nil do
				Line = string.sub(Stream, Start, End - 1)

				DecodeLine(Line, Result)

				Start = End + 1
				End = string.find(Stream, "\n", Start, true)
			end

			Line = string.sub(Stream, Start)

			DecodeLine(Line, Result)
		else
			Error = "Invalid type given for Stream. Type given is " .. type(Stream) .. "."
		end
	else
		Error = "Invalid stream given to Config.Decode!"
	end

	return Result, Error
end

function Config.LoadFile(Path, IsDefault)
	local Result = nil
	local Contents, Error = FileSystem.ReadContents(Path, nil, IsDefault)
	if Contents ~= nil then
		Result, Error = Config.Decode(Contents)
	end

	return Result, Error
end

function Config.Save(Path, Table, IsDefault)
	local Result, Error = false
	if Table ~= nil then
		local Contents = Config.Encode(Table)
		Result, Error = FileSystem.SaveContents(Path, Contents, IsDefault)
	else
		Error = "Invalid table given to Config.Save!"
	end

	return Result, Error
end

return Config


================================================
FILE: Internal/Core/Cursor.lua
================================================
--[[

MIT License

Copyright (c) 2019-2021 Love2D Community <love2d.org>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

--]]

local Utility = require(SLAB_PATH .. '.Internal.Core.Utility')

local Cursor = {}

local min = math.min
local max = math.max

local State =
{
	X = 0.0,
	Y = 0.0,
	PrevX = 0.0,
	PrevY = 0.0,
	AnchorX = 0.0,
	AnchorY = 0.0,
	ItemX = 0.0,
	ItemY = 0.0,
	ItemW = 0.0,
	ItemH = 0.0,
	PadX = 4.0,
	PadY = 4.0,
	NewLineSize = 16.0,
	LineY = 0.0,
	LineH = 0.0,
	PrevLineY = 0.0,
	PrevLineH = 0.0
}

local Stack = {}

function Cursor.SetPosition(X, Y)
	State.PrevX = State.X
	State.PrevY = State.Y
	State.X = X
	State.Y = Y
end

function Cursor.SetX(X)
	State.PrevX = State.X
	State.X = X
end

function Cursor.SetY(Y)
	State.PrevY = State.Y
	State.Y = Y
end

function Cursor.SetRelativePosition(X, Y)
	State.PrevX = State.X
	State.PrevY = State.Y
	State.X = State.AnchorX + X
	State.Y = State.AnchorY + Y
end

function Cursor.SetRelativeX(X)
	State.PrevX = State.X
	State.X = State.AnchorX + X
end

function Cursor.SetRelativeY(Y)
	State.PrevY = State.Y
	State.Y = State.AnchorY + Y
end

function Cursor.AdvanceX(X)
	State.PrevX = State.X
	State.X = State.X + X + State.PadX
end

function Cursor.AdvanceY(Y)
	State.X = State.AnchorX
	State.PrevY = State.Y
	State.Y = State.Y + Y + State.PadY
	State.PrevLineY = State.LineY
	State.PrevLineH = State.LineH
	State.LineY = 0.0
	State.LineH = 0.0
end

function Cursor.SetAnchor(X, Y)
	State.AnchorX = X
	State.AnchorY = Y
end

function Cursor.SetAnchorX(X)
	State.AnchorX = X
end

function Cursor.SetAnchorY(Y)
	State.AnchorY = Y
end

function Cursor.GetAnchor()
	return State.AnchorX, State.AnchorY
end

function Cursor.GetAnchorX()
	return State.AnchorX
end

function Cursor.GetAnchorY()
	return State.AnchorY
end

function Cursor.GetPosition()
	return State.X, State.Y
end

function Cursor.GetX()
	return State.X
end

function Cursor.GetY()
	return State.Y
end

function Cursor.GetRelativePosition()
	return Cursor.GetRelativeX(), Cursor.GetRelativeY()
end

function Cursor.GetRelativeX()
	return State.X - State.AnchorX
end

function Cursor.GetRelativeY()
	return State.Y - State.AnchorY
end

function Cursor.SetItemBounds(X, Y, W, H)
	State.ItemX = X
	State.ItemY = Y
	State.ItemW = W
	State.ItemH = H
	if State.LineY == 0.0 then
		State.LineY = Y
	end
	State.LineY = min(State.LineY, Y)
	State.LineH = max(State.LineH, H)
end

function Cursor.GetItemBounds()
	return State.ItemX, State.ItemY, State.ItemW, State.ItemH
end

function Cursor.IsInItemBounds(X, Y)
	return State.ItemX <= X and X <= State.ItemX + State.ItemW and State.ItemY <= Y and Y <= State.ItemY + State.ItemH
end

function Cursor.SameLine(Options)
	Options = Options == nil and {} or Options
	Options.Pad = Options.Pad == nil and 0.0 or Options.Pad
	Options.CenterY = Options.CenterY == nil and false or Options.CenterY

	State.LineY = State.PrevLineY
	State.LineH = State.PrevLineH
	State.X = State.ItemX + State.ItemW + State.PadX + Options.Pad
	State.Y = State.PrevY

	if Options.CenterY then
		State.Y = State.Y + (State.LineH * 0.5) - (State.NewLineSize * 0.5)
	end
end

function Cursor.SetNewLineSize(NewLineSize)
	State.NewLineSize = NewLineSize
end

function Cursor.GetNewLineSize()
	return State.NewLineSize
end

function Cursor.NewLine()
	Cursor.AdvanceY(State.NewLineSize)
end

function Cursor.GetLineHeight()
	return State.PrevLineH
end

function Cursor.PadX()
	return State.PadX
end

function Cursor.PadY()
	return State.PadY
end

function Cursor.Indent(Width)
	State.AnchorX = State.AnchorX + Width
	State.X = State.AnchorX
end

function Cursor.Unindent(Width)
	Cursor.Indent(-Width)
end

function Cursor.PushContext()
	table.insert(Stack, 1, Utility.Copy(State))
end

function Cursor.PopContext()
	if #Stack == 0 then
		return
	end

	State = table.remove(Stack, 1)
end

return Cursor


================================================
FILE: Internal/Core/DrawCommands.lua
================================================
--[[

MIT License

Copyright (c) 2019-2021 Love2D Community <love2d.org>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

--]]

local Stats = require(SLAB_PATH .. ".Internal.Core.Stats")
local TablePool = require(SLAB_PATH .. ".Internal.Core.TablePool")
local Scale = require(SLAB_PATH .. ".Internal.Core.Scale")

local insert = table.insert
local remove = table.remove
local sin = math.sin
local cos = math.cos
local rad = math.rad
local max = math.max
local min = math.min
local graphics = love.graphics

local DrawCommands = {}

local PendingBatches = {}
local ActiveBatch = nil
local Shaders = {}

local EMPTY = {}
local BLACK = { 0, 0, 0, 1 }
local WHITE = { 1, 1, 1, 1 }

local TypeRect = 1
local TypeTriangle = 2
local TypeText = 3
local TypeScissor = 4
local TypeTransformPush = 5
local TypeTransformPop = 6
local TypeApplyTransform = 7
local TypeCheck = 8
local TypeLine = 9
local TypeTextFormatted = 10
local TypeIntersectScissor = 11
local TypeCross = 12
local TypeImage = 13
local TypeSubImage = 14
local TypeCircle = 15
local TypeDrawCanvas = 16
local TypeMesh = 17
local TypeTextObject = 18
local TypeCurve = 19
local TypePolygon = 20
local TypeShaderPush = 21
local TypeShaderPop = 22

local LayerNormal = 1
local LayerDock = 2
local LayerContextMenu = 3
local LayerMainMenuBar = 4
local LayerDialog = 5
local LayerDebug = 6
local LayerMouse = 7

local LayerNames = {
	Normal = LayerNormal,
	Dock = LayerDock,
	ContextMenu = LayerContextMenu,
	MainMenuBar = LayerMainMenuBar,
	Dialog = LayerDialog,
	Debug = LayerDebug,
	Mouse = LayerMouse,
}

local LayerTable = { {}, {}, {}, {}, {}, {}, {} }

local ActiveLayer = LayerNormal
local StatsCategory = 'Slab Draw'

local pool = {}
for i = TypeRect, TypeShaderPop do
	pool[i] = TablePool()
end

local function AddArc(Verts, CenterX, CenterY, Radius, Angle1, Angle2, Segments, X, Y)
	if Radius == 0 then
		insert(Verts, CenterX + X)
		insert(Verts, CenterY + Y)
		return
	end

	local Step = (Angle2 - Angle1) / Segments

	for Theta = Angle1, Angle2, Step do
		local Radians = rad(Theta)
		insert(Verts, sin(Radians) * Radius + CenterX + X)
		insert(Verts, cos(Radians) * Radius + CenterY + Y)
	end
end

local function DrawRect(Rect)
	local StatHandle = Stats.Begin('DrawRect', StatsCategory)

	local LineW = graphics.getLineWidth()
	graphics.setLineWidth(Rect.LineW)
	graphics.setColor(Rect.Color)
	local pixelOffset = Rect.Mode == 'line' and .5 or 0
	graphics.rectangle(Rect.Mode, Rect.X + pixelOffset, Rect.Y + pixelOffset, Rect.Width, Rect.Height, Rect.Radius, Rect.Radius)
	graphics.setLineWidth(LineW)

	Stats.End(StatHandle)
end

local function GetTriangleVertices(X, Y, Radius, Rotation)
	local Radians = rad(Rotation)

	local cs, sn = cos(Radians), sin(Radians)

	local X1, Y1 = 0, -Radius
	local X2, Y2 = -Radius, Radius
	local X3, Y3 = Radius, Radius

	local PX1 = X1 * cs - Y1 * sn
	local PY1 = Y1 * cs + X1 * sn

	local PX2 = X2 * cs - Y2 * sn
	local PY2 = Y2 * cs + X2 * sn

	local PX3 = X3 * cs - Y3 * sn
	local PY3 = Y3 * cs + X3 * sn

	return X + PX1, Y + PY1, X + PX2, Y + PY2, X + PX3, Y + PY3
end

local function DrawTriangle(Triangle)
	local StatHandle = Stats.Begin('DrawTriangle', StatsCategory)

	graphics.setColor(Triangle.Color)
	graphics.polygon(Triangle.Mode, GetTriangleVertices(Triangle.X, Triangle.Y, Triangle.Radius, Triangle.Rotation))

	Stats.End(StatHandle)
end

local function DrawCheck(Check)
	local StatHandle = Stats.Begin('DrawCheck', StatsCategory)

	graphics.setColor(Check.Color)
	graphics.line(
		Check.X - Check.Radius * 0.5, Check.Y,
		Check.X, Check.Y + Check.Radius,
		Check.X + Check.Radius, Check.Y - Check.Radius
	)

	Stats.End(StatHandle)
end

local function DrawText(Text)
	local StatHandle = Stats.Begin('DrawText', StatsCategory)

	graphics.setFont(Text.Font)
	graphics.setColor(Text.Color)
	graphics.print(Text.Text, Text.X, Text.Y)

	Stats.End(StatHandle)
end

local function DrawTextFormatted(Text)
	local StatHandle = Stats.Begin('DrawTextFormatted', StatsCategory)

	graphics.setFont(Text.Font)
	graphics.setColor(Text.Color)
	graphics.printf(Text.Text, Text.X, Text.Y, Text.W, Text.Align)

	Stats.End(StatHandle)
end

local function DrawTextObject(Text)
	local StatHandle = Stats.Begin('DrawTextObject', StatsCategory)

	graphics.setColor(1, 1, 1, 1)
	graphics.draw(Text.Text, Text.X, Text.Y)

	Stats.End(StatHandle)
end

local function DrawLine(Line)
	local StatHandle = Stats.Begin('DrawLine', StatsCategory)

	graphics.setColor(Line.Color)
	local LineW = graphics.getLineWidth()
	graphics.setLineWidth(Line.Width)
	graphics.line(Line.X1, Line.Y1, Line.X2, Line.Y2)
	graphics.setLineWidth(LineW)

	Stats.End(StatHandle)
end

local function DrawCross(Cross)
	local StatHandle = Stats.Begin('DrawCross', StatsCategory)

	local X, Y = Cross.X, Cross.Y
	local R = Cross.Radius
	graphics.setColor(Cross.Color)
	graphics.line(X - R, Y - R, X + R, Y + R)
	graphics.line(X - R, Y + R, X + R, Y - R)

	Stats.End(StatHandle)
end

local function DrawImage(Image)
	local StatHandle = Stats.Begin('DrawImage', StatsCategory)

	graphics.setColor(Image.Color)
	graphics.draw(Image.Image, Image.X, Image.Y, Image.Rotation, Image.ScaleX, Image.ScaleY)

	Stats.End(StatHandle)
end

local function DrawSubImage(Image)
	local StatHandle = Stats.Begin('DrawSubImage', StatsCategory)

	graphics.setColor(Image.Color)
	graphics.draw(Image.Image, Image.Quad, Image.Transform)

	Stats.End(StatHandle)
end

local function DrawCircle(Circle)
	local StatHandle = Stats.Begin('DrawCircle', StatsCategory)

	graphics.setColor(Circle.Color)
	graphics.circle(Circle.Mode, Circle.X, Circle.Y, Circle.Radius, Circle.Segments)

	Stats.End(StatHandle)
end

local function DrawCurve(Curve)
	local StatHandle = Stats.Begin('DrawCurve', StatsCategory)

	graphics.setColor(Curve.Color)
	graphics.line(Curve.Points)

	Stats.End(StatHandle)
end

local function DrawPolygon(Polygon)
	local StatHandle = Stats.Begin('DrawPolygon', StatsCategory)

	graphics.setColor(Polygon.Color)
	graphics.polygon(Polygon.Mode, Polygon.Points)

	Stats.End(StatHandle)
end

local function DrawCanvas(Canvas)
	local StatHandle = Stats.Begin('DrawCanvas', StatsCategory)

	graphics.setBlendMode('alpha', 'premultiplied')
	graphics.setColor(1.0, 1.0, 1.0, 1.0)
	graphics.draw(Canvas.Canvas, Canvas.X, Canvas.Y)
	graphics.setBlendMode('alpha')

	Stats.End(StatHandle)
end

local function DrawMesh(Mesh)
	local StatHandle = Stats.Begin('DrawMesh', StatsCategory)

	graphics.setColor(1.0, 1.0, 1.0, 1.0)
	graphics.draw(Mesh.Mesh, Mesh.X, Mesh.Y)

	Stats.End(StatHandle)
end

local function ShaderPush(shader)
	insert(Shaders, 1, shader.Shader)
	graphics.setShader(shader.Shader)
end

local function ShaderPop()
	remove(Shaders, 1)
	graphics.setShader(Shaders[1])
end

local function SetScissor(rect)
	graphics.setScissor(rect.X, rect.Y, rect.W, rect.H)
end

local function TransformPush()
	graphics.push()
end

local function TransformPop()
	graphics.pop()
end

local function ApplyTransform(transform)
	graphics.applyTransform(transform.Transform)
end

local function IntersectScissor(rect)
	graphics.intersectScissor(rect.X, rect.Y, rect.W, rect.H)
end

local DRAWTYPES = {
	DrawRect,
	DrawTriangle,
	DrawText,
	SetScissor,
	TransformPush,
	TransformPop,
	ApplyTransform,
	DrawCheck,
	DrawLine,
	DrawTextFormatted,
	IntersectScissor,
	DrawCross,
	DrawImage,
	DrawSubImage,
	DrawCircle,
	DrawCanvas,
	DrawMesh,
	DrawTextObject,
	DrawCurve,
	DrawPolygon,
	ShaderPush,
	ShaderPop,
}

local function DrawElements(Elements)
	local StatHandle = Stats.Begin('Draw Elements', StatsCategory)

	for i = 1, #Elements do
		local element = Elements[i]
		DRAWTYPES[element.Type](element)
	end

	Stats.End(StatHandle)
end

local function DrawChannel(channel)
	for i = 1, #channel do
		DrawElements(channel[i])
	end
end

local function ClearBatch(batch)
	for i = 1, #batch do
		pool[batch[i].Type]:push(batch[i])
		batch[i] = nil
	end
end

local function AssertActiveBatch()
	assert(ActiveBatch ~= nil, "DrawCommands.Begin was not called before commands were issued!")
end

local function DrawLayer(Layer, Name)
	if Layer == nil then
		return
	end

	local StatHandle = Stats.Begin('Draw Layer ' .. Name, StatsCategory)

	local minChannel, maxChannel = 1e9, 0
	for i in pairs(Layer) do
		minChannel, maxChannel = min(minChannel, i), max(maxChannel, i)
	end

	for i = minChannel, maxChannel do
		if Layer[i] then
			DrawChannel(Layer[i])
		end
	end

	Stats.End(StatHandle)
end

function DrawCommands.Reset()
	for i = LayerNormal, LayerMouse do
		local layer = LayerTable[i]
		for j, channel in pairs(layer) do
			for i, batch in ipairs(channel) do
				ClearBatch(batch)
			end
			layer[j] = nil
		end
	end

	ActiveLayer = LayerNormal
	ActiveBatch = nil
	for i in ipairs(Shaders) do
		Shaders[i] = nil
	end
end

function DrawCommands.Begin(channel)
	local layer = LayerTable[ActiveLayer]
	channel = channel or 1

	if layer[channel] == nil then
		layer[channel] = {}
	end

	ActiveBatch = {}
	insert(layer[channel], ActiveBatch)
	insert(PendingBatches, ActiveBatch)
end

function DrawCommands.End(clearElements)
	if ActiveBatch == nil then return end

	if clearElements then
		ClearBatch(ActiveBatch)
	end

	graphics.setScissor()
	remove(PendingBatches)

	ActiveBatch = PendingBatches[#PendingBatches]
end

function DrawCommands.SetLayer(Layer)
	ActiveLayer = LayerNames[Layer]
end

function DrawCommands.Rectangle(Mode, X, Y, Width, Height, Color, Radius, Segments, LineW)
	AssertActiveBatch()
	if type(Radius) == 'table' then
		Segments = Segments == nil and 10 or Segments

		local Verts = {}
		local TL = Radius[1]
		local TR = Radius[2]
		local BR = Radius[3]
		local BL = Radius[4]

		TL = TL == nil and 0 or TL
		TR = TR == nil and 0 or TR
		BR = BR == nil and 0 or BR
		BL = BL == nil and 0 or BL

		AddArc(Verts, Width - BR, Height - BR, BR, 0, 90, Segments, X, Y)
		AddArc(Verts, Width - TR, TR, TR, 90, 180, Segments, X, Y)
		AddArc(Verts, TL, TL, TL, 180, 270, Segments, X, Y)
		AddArc(Verts, BL, Height - BL, BL, 270, 360, Segments, X, Y)

		DrawCommands.Polygon(Mode, Verts, Color)
	else
		local Item = pool[TypeRect]:pull()
		Item.Type = TypeRect
		Item.Mode = Mode
		Item.X = X
		Item.Y = Y
		Item.Width = Width
		Item.Height = Height
		Item.Color = Color or BLACK
		Item.Radius = Radius or 0
		Item.LineW = LineW or graphics.getLineWidth()
		insert(ActiveBatch, Item)
	end
end

function DrawCommands.Triangle(Mode, X, Y, Radius, Rotation, Color)
	AssertActiveBatch()
	local Item = pool[TypeTriangle]:pull()
	Item.Type = TypeTriangle
	Item.Mode = Mode
	Item.X = X
	Item.Y = Y
	Item.Radius = Radius
	Item.Rotation = Rotation
	Item.Color = Color or BLACK
	insert(ActiveBatch, Item)
end

function DrawCommands.Print(Text, X, Y, Color, Font)
	AssertActiveBatch()
	local Item = pool[TypeText]:pull()
	Item.Type = TypeText
	Item.Text = Text
	Item.X = X
	Item.Y = Y
	Item.Color = Color or WHITE
	Item.Font = Font
	insert(ActiveBatch, Item)
end

function DrawCommands.Printf(Text, X, Y, W, Align, Color, Font)
	AssertActiveBatch()
	local Item = pool[TypeTextFormatted]:pull()
	Item.Type = TypeTextFormatted
	Item.Text = Text
	Item.X = X
	Item.Y = Y
	Item.W = W
	Item.Align = Align or 'left'
	Item.Color = Color or WHITE
	Item.Font = Font
	insert(ActiveBatch, Item)
end

function DrawCommands.Scissor(X, Y, W, H)
	AssertActiveBatch()
	if W ~= nil then
		W = max(W, 0.0)
	end
	if H ~= nil then
		H = max(H, 0.0)
	end
	local SF = Scale.GetScale()
	local Item = pool[TypeScissor]:pull()
	Item.Type = TypeScissor
	if X then X = X * SF end
	if Y then Y = Y * SF end
	if W then W = W * SF end
	if H then H = H * SF end
	Item.X = X
	Item.Y = Y
	Item.W = W
	Item.H = H
	insert(ActiveBatch, Item)
end

function DrawCommands.IntersectScissor(X, Y, W, H)
	AssertActiveBatch()
	if W ~= nil then
		W = max(W, 0.0)
	end
	if H ~= nil then
		H = max(H, 0.0)
	end
	local SF = Scale.GetScale()
	local Item = pool[TypeIntersectScissor]:pull()
	Item.Type = TypeIntersectScissor
	Item.X = (X or 0.0) * SF
	Item.Y = (Y or 0.0) * SF
	Item.W = (W or 0.0) * SF
	Item.H = (H or 0.0) * SF
	insert(ActiveBatch, Item)
end

function DrawCommands.TransformPush()
	AssertActiveBatch()
	local Item = pool[TypeTransformPush]:pull()
	Item.Type = TypeTransformPush
	insert(ActiveBatch, Item)
end

function DrawCommands.TransformPop()
	AssertActiveBatch()
	local Item = pool[TypeTransformPop]:pull()
	Item.Type = TypeTransformPop
	insert(ActiveBatch, Item)
end

function DrawCommands.ApplyTransform(Transform)
	AssertActiveBatch()
	local Item = pool[TypeApplyTransform]:pull()
	Item.Type = TypeApplyTransform
	Item.Transform = Transform
	insert(ActiveBatch, Item)
end

function DrawCommands.Check(X, Y, Radius, Color)
	AssertActiveBatch()
	local Item = pool[TypeCheck]:pull()
	Item.Type = TypeCheck
	Item.X = X
	Item.Y = Y
	Item.Radius = Radius
	Item.Color = Color or BLACK
	insert(ActiveBatch, Item)
end

function DrawCommands.Line(X1, Y1, X2, Y2, Width, Color)
	AssertActiveBatch()
	local Item = pool[TypeLine]:pull()
	Item.Type = TypeLine
	Item.X1 = X1
	Item.Y1 = Y1
	Item.X2 = X2
	Item.Y2 = Y2
	Item.Width = Width
	Item.Color = Color or BLACK
	insert(ActiveBatch, Item)
end

function DrawCommands.Cross(X, Y, Radius, Color)
	AssertActiveBatch()
	local Item = pool[TypeCross]:pull()
	Item.Type = TypeCross
	Item.X = X
	Item.Y = Y
	Item.Radius = Radius
	Item.Color = Color or BLACK
	insert(ActiveBatch, Item)
end

function DrawCommands.Image(X, Y, Image, Rotation, ScaleX, ScaleY, Color)
	AssertActiveBatch()
	local Item = pool[TypeImage]:pull()
	Item.Type = TypeImage
	Item.X = X
	Item.Y = Y
	Item.Image = Image
	Item.Rotation = Rotation
	Item.ScaleX = ScaleX
	Item.ScaleY = ScaleY
	Item.Color = Color or WHITE
	insert(ActiveBatch, Item)
end

function DrawCommands.SubImage(X, Y, Image, SX, SY, SW, SH, Rotation, ScaleX, ScaleY, Color)
	AssertActiveBatch()
	local Item = pool[TypeSubImage]:pull()
	Item.Type = TypeSubImage
	Item.Transform = love.math.newTransform(X, Y, Rotation, ScaleX, ScaleY)
	Item.Image = Image
	Item.Quad = graphics.newQuad(SX, SY, SW, SH, Image:getWidth(), Image:getHeight())
	Item.Color = Color or WHITE
	insert(ActiveBatch, Item)
end

function DrawCommands.Circle(Mode, X, Y, Radius, Color, Segments)
	AssertActiveBatch()
	local Item = pool[TypeCircle]:pull()
	Item.Type = TypeCircle
	Item.Mode = Mode
	Item.X = X
	Item.Y = Y
	Item.Radius = Radius
	Item.Color = Color or BLACK
	Item.Segments = Segments and Segments or 24
	insert(ActiveBatch, Item)
end

function DrawCommands.DrawCanvas(Canvas, X, Y)
	AssertActiveBatch()
	local Item = pool[TypeDrawCanvas]:pull()
	Item.Type = TypeDrawCanvas
	Item.Canvas = Canvas
	Item.X = X
	Item.Y = Y
	insert(ActiveBatch, Item)
end

function DrawCommands.Mesh(Mesh, X, Y)
	AssertActiveBatch()
	local Item = pool[TypeMesh]:pull()
	Item.Type = TypeMesh
	Item.Mesh = Mesh
	Item.X = X
	Item.Y = Y
	insert(ActiveBatch, Item)
end

function DrawCommands.Text(Text, X, Y)
	AssertActiveBatch()
	local Item = pool[TypeTextObject]:pull()
	Item.Type = TypeTextObject
	Item.Text = Text
	Item.X = X
	Item.Y = Y
	Item.Color = BLACK
	insert(ActiveBatch, Item)
end

function DrawCommands.Curve(Points, Color)
	AssertActiveBatch()
	local Item = pool[TypeCurve]:pull()
	Item.Type = TypeCurve
	Item.Points = Points
	Item.Color = Color or BLACK
	insert(ActiveBatch, Item)
end

function DrawCommands.Polygon(Mode, Points, Color)
	AssertActiveBatch()
	local Item = pool[TypePolygon]:pull()
	Item.Type = TypePolygon
	Item.Mode = Mode
	Item.Points = Points
	Item.Color = Color or BLACK
	insert(ActiveBatch, Item)
end

function DrawCommands.PushShader(Shader)
	AssertActiveBatch()
	local Item = pool[TypeShaderPush]:pull()
	Item.Type = TypeShaderPush
	Item.Shader = Shader
	insert(ActiveBatch, Item)
end

function DrawCommands.PopShader()
	AssertActiveBatch()
	local Item = pool[TypeShaderPop]:pull()
	Item.Type = TypeShaderPop
	insert(ActiveBatch, Item)
end

function DrawCommands.Execute()
	local StatHandle = Stats.Begin('Execute', StatsCategory)

	graphics.scale(Scale.GetScale())

	DrawLayer(LayerTable[LayerNormal], 'Normal')
	DrawLayer(LayerTable[LayerDock], 'Dock')
	DrawLayer(LayerTable[LayerContextMenu], 'ContextMenu')
	DrawLayer(LayerTable[LayerMainMenuBar], 'MainMenuBar')
	DrawLayer(LayerTable[LayerDialog], 'Dialog')
	DrawLayer(LayerTable[LayerDebug], 'Debug')
	DrawLayer(LayerTable[LayerMouse], 'Mouse')

	graphics.setShader()

	Stats.End(StatHandle)
end

local function GetLayerDebugInfo(Layer)
	local Result = {}

	Result['Channel Count'] = #Layer

	local Channels = {}
	for K, Channel in pairs(Layer) do
		local Collection = {}
		Collection['Batch Count'] = #Channel
		insert(Channels, Collection)
	end

	Result['Channels'] = Channels

	return Result
end

function DrawCommands.GetDebugInfo()
	local Result = {}

	Result['Normal'] = GetLayerDebugInfo(LayerTable[LayerNormal])
	Result['Dock'] = GetLayerDebugInfo(LayerTable[LayerDock])
	Result['ContextMenu'] = GetLayerDebugInfo(LayerTable[LayerContextMenu])
	Result['MainMenuBar'] = GetLayerDebugInfo(LayerTable[LayerMainMenuBar])
	Result['Dialog'] = GetLayerDebugInfo(LayerTable[LayerDialog])
	Result['Debug'] = GetLayerDebugInfo(LayerTable[LayerDebug])
	Result['Mouse'] = GetLayerDebugInfo(LayerTable[LayerMouse])

	return Result
end

return DrawCommands


================================================
FILE: Internal/Core/FileSystem.lua
================================================
--[[

MIT License

Copyright (c) 2019-2021 Love2D Community <love2d.org>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

--]]

local FileSystem = {}

local Syscalls = {}
local Bit = require('bit')
local FFI = require('ffi')

local function ShouldFilter(Name, Filter)
	Filter = Filter == nil and "*.*" or Filter

	local Extension = FileSystem.GetExtension(Name)

	if Filter ~= "*.*" then
		local FilterExt = FileSystem.GetExtension(Filter)

		if Extension ~= FilterExt then
			return true
		end
	end

	return false
end

local GetDirectoryItems = nil
local Exists = nil
local IsDirectory = nil
local Copy = nil

local function Access(Table, Param)
	return Table[Param];
end

local function ErrorAtAccess(Table, Param)
	return not pcall(Access, Table, Param);
end

--[[
	The following code is based on the following sources:

	LoveFS v1.1
	https://github.com/linux-man/lovefs
	Pure Lua FileSystem Access
	Under the MIT license.
	copyright(c) 2016 Caldas Lopes aka linux-man

	luapower/fs_posix
	https://github.com/luapower/fs
	portable filesystem API for LuaJIT / Linux & OSX backend
	Written by Cosmin Apreutesei. Public Domain.
--]]

if FFI.os == "Windows" then
	FFI.cdef[[
		#pragma pack(push)
		#pragma pack(1)
		struct WIN32_FIND_DATAW {
			uint32_t dwFileAttributes;
			uint64_t ftCreationTime;
			uint64_t ftLastAccessTime;
			uint64_t ftLastWriteTime;
			uint32_t dwReserved[4];
			wchar_t cFileName[520];
			wchar_t cAlternateFileName[28];
		};
		#pragma pack(pop)

		typedef unsigned long DWORD;
		static const DWORD FILE_ATTRIBUTE_DIRECTORY = 0x10;
		static const DWORD INVALID_FILE_ATTRIBUTES = -1;

		void* FindFirstFileW(const wchar_t* pattern, struct WIN32_FIND_DATAW* fd);
		bool FindNextFileW(void* ff, struct WIN32_FIND_DATAW* fd);
		bool FindClose(void* ff);
		DWORD GetFileAttributesW(const wchar_t* Path);
		bool CopyFileW(const wchar_t* src, const wchar_t* dst, bool bFailIfExists);

		int MultiByteToWideChar(unsigned int CodePage, uint32_t dwFlags, const char* lpMultiByteStr,
			int cbMultiByte, const wchar_t* lpWideCharStr, int cchWideChar);
		int WideCharToMultiByte(unsigned int CodePage, uint32_t dwFlags, const wchar_t* lpWideCharStr,
			int cchWideChar, const char* lpMultiByteStr, int cchMultiByte,
			const char* default, int* used);
	]]

	local WIN32_FIND_DATA = FFI.typeof('struct WIN32_FIND_DATAW')
	local INVALID_HANDLE = FFI.cast('void*', -1)

	local function u2w(str, code)
		local size = FFI.C.MultiByteToWideChar(code or 65001, 0, str, #str, nil, 0)
		local buf = FFI.new("wchar_t[?]", size * 2 + 2)
		FFI.C.MultiByteToWideChar(code or 65001, 0, str, #str, buf, size * 2)
		return buf
	end

	local function w2u(wstr, code)
		local size = FFI.C.WideCharToMultiByte(code or 65001, 0, wstr, -1, nil, 0, nil, nil)
		local buf = FFI.new("char[?]", size + 1)
		size = FFI.C.WideCharToMultiByte(code or 65001, 0, wstr, -1, buf, size, nil, nil)
		return FFI.string(buf)
	end

	GetDirectoryItems = function(Directory, Options)
		local Result = {}

		local FindData = FFI.new(WIN32_FIND_DATA)
		local Handle = FFI.C.FindFirstFileW(u2w(Directory .. "\\*"), FindData)
		FFI.gc(Handle, FFI.C.FindClose)

		if Handle ~= nil then
			repeat
				local Name = w2u(FindData.cFileName)

				if Name ~= "." and Name ~= ".." then
					local AddDirectory = (FindData.dwFileAttributes == 16 or FindData.dwFileAttributes == 17) and Options.Directories
					local AddFile = FindData.dwFileAttributes == 32 and Options.Files

					if (AddDirectory or AddFile) and not ShouldFilter(Name, Options.Filter) then
						table.insert(Result, Name)
					end
				end

			until not FFI.C.FindNextFileW(Handle, FindData)
		end

		FFI.C.FindClose(FFI.gc(Handle, nil))

		return Result
	end

	Exists = function(Path)
		local Attributes = FFI.C.GetFileAttributesW(u2w(Path))
		return Attributes ~= FFI.C.INVALID_FILE_ATTRIBUTES
	end

	IsDirectory = function(Path)
		local Attributes = FFI.C.GetFileAttributesW(u2w(Path))
		return Attributes ~= FFI.C.INVALID_FILE_ATTRIBUTES and Bit.band(Attributes, FFI.C.FILE_ATTRIBUTE_DIRECTORY) ~= 0
	end

	Copy = function(Source, Dest)
		FFI.C.CopyFileW(u2w(Source), u2w(Dest), false)
	end
else
	FFI.cdef[[
		typedef struct DIR DIR;
		typedef size_t time_t;
		static const int S_IFREG = 0x8000;
		static const int S_IFDIR = 0x4000;

		DIR* opendir(const char* name);
		int closedir(DIR* dirp);
	]]

	if FFI.os == "OSX" then
		FFI.cdef[[
			struct dirent {
				uint64_t	d_ino;
				uint64_t	d_off;
				uint16_t	d_reclen;
				uint16_t	d_namlen;
				uint8_t		d_type;
				char		d_name[1024];
			};

			struct stat {
				uint32_t	st_dev;
				uint16_t	st_mode;
				uint16_t	st_nlink;
				uint64_t	st_ino;
				uint32_t	st_uid;
				uint32_t	st_gid;
				uint32_t	st_rdev;
				time_t		st_atime;
				long		st_atime_nsec;
				time_t		st_mtime;
				long		st_mtime_nsec;
				time_t		st_ctime;
				long		st_ctime_nsec;
				time_t		st_btime;
				long		st_btime_nsec;
				int64_t		st_size;
				int64_t		st_blocks;
				int32_t		st_blksize;
				uint32_t	st_flags;
				uint32_t	st_gen;
				int32_t		st_lspare;
				int64_t		st_qspare[2];
			};

			struct dirent* readdir(DIR* dirp) asm("readdir$INODE64");
			int stat64(const char* path, struct stat* buf);
		]]
	else
		FFI.cdef[[
			struct dirent {
				uint64_t		d_ino;
				int64_t			d_off;
				unsigned short	d_reclen;
				unsigned char	d_type;
				char			d_name[256];
			};

			struct stat {
				uint64_t	st_dev;
				uint64_t	st_ino;
				uint64_t	st_nlink;
				uint32_t	st_mode;
				uint32_t	st_uid;
				uint32_t	st_gid;
				uint32_t	__pad0;
				uint64_t	st_rdev;
				int64_t		st_size;
				int64_t		st_blksize;
				int64_t		st_blocks;
				uint64_t	st_atime;
				uint64_t	st_atime_nsec;
				uint64_t	st_mtime;
				uint64_t	st_mtime_nsec;
				uint64_t	st_ctime;
				uint64_t	st_ctime_nsec;
				int64_t		__unused[3];
			};

			struct dirent* readdir(DIR* dirp) asm("readdir64");
			int syscall(int number, ...);
			int stat64(const char* path, struct stat* buf);
		]]
	end

	local Stat = FFI.typeof('struct stat');

	if FFI.arch == "x86" then
		Syscalls.SYS_stat = 106
	elseif FFI.arch == "arm" and FFI.abi("eabi") then
		Syscalls.SYS_stat = 106
	elseif FFI.arch == "x64" then
		Syscalls.SYS_stat = 4
	end


	if(ErrorAtAccess(FFI.C, "stat64")) then

		local function SysStat(Path, Buffer)
			return FFI.C.syscall(Syscalls.SYS_stat, Path, Buffer)
		end

		Exists = function(Path)
			local Buffer = Stat()
			return SysStat(Path, Buffer) == 0
		end

		IsDirectory = function(Path)
			local Buffer = Stat()

			if SysStat(Path, Buffer) == 0 then
				return Bit.band(Buffer.st_mode, 0xf000) == FFI.C.S_IFDIR
			end
			return false
		end
	else
		Exists = function(Path)
			local Buffer = Stat()
			return FFI.C.stat64(Path, Buffer) == 0
		end

		IsDirectory = function(Path)
			local Buffer = Stat()

			if FFI.C.stat64(Path, Buffer) == 0 then
				return Bit.band(Buffer.st_mode, 0xf000) == FFI.C.S_IFDIR
			end

			return false
		end
	end


	GetDirectoryItems = function(Directory, Options)
		local Result = {}

		local DIR = FFI.C.opendir(Directory)

		if DIR ~= nil then
			local Entry = FFI.C.readdir(DIR)

			while Entry ~= nil do
				local Name = FFI.string(Entry.d_name)

				if Name ~= "." and Name ~= ".." and string.sub(Name, 1, 1) ~= "." then
					local AddDirectory = Entry.d_type == 4 and Options.Directories
					local AddFile = Entry.d_type == 8 and Options.Files

					if (AddDirectory or AddFile) and not ShouldFilter(Name, Options.Filter) then
						table.insert(Result, Name)
					end
				end

				Entry = FFI.C.readdir(DIR)
			end

			FFI.C.closedir(DIR)
		end

		return Result
	end

	Copy = function(Source, Dest)
		local inp = assert(io.open(Source, "rb"))
		local out = assert(io.open(Dest, "wb"))
		local data = inp:read("*all")
		out:write(data)
		assert(out:close())
	end

end

function FileSystem.Separator()
	-- Lua/Love2D returns all paths with back slashes.
	return "/"
end

function FileSystem.GetDirectoryItems(Directory, Options)
	Options = Options == nil and {} or Options
	Options.Files = Options.Files == nil and true or Options.Files
	Options.Directories = Options.Directories == nil and true or Options.Directories
	Options.Filter = Options.Filter == nil and "*.*" or Options.Filter

	if string.sub(Directory, #Directory, #Directory) ~= FileSystem.Separator() then
		Directory = Directory .. FileSystem.Separator()
	end

	local Result = GetDirectoryItems(Directory, Options)

	table.sort(Result)

	return Result
end

function FileSystem.Exists(Path)
	return Exists(Path)
end

function FileSystem.IsDirectory(Path)
	return IsDirectory(Path)
end

function FileSystem.Parent(Path)
	local Result = Path

	local Index = 1
	local I = Index
	repeat
		Index = I
		I = string.find(Path, FileSystem.Separator(), Index + 1, true)
	until I == nil

	if Index > 1 then
		Result = string.sub(Path, 1, Index - 1)
	end

	return Result
end

--[[
	IsAbsolute

	Determines if the given path is an absolute path or a relative path. This is determined by checking if the
	path starts with a drive letter on Windows, or the Unix root character '/'.

	Path: [String] The path to check.

	Return: [Boolean] True if the path is absolute, false if it is relative.
--]]
function FileSystem.IsAbsolute(Path)
	if Path == nil or Path == "" then
		return false
	end

	if FFI.os == "Windows" then
		return string.match(Path, "(.:-)\\") ~= nil
	end

	return string.sub(Path, 1, 1) == FileSystem.Separator()
end

--[[
	GetDrive

	Attempts to retrieve the drive letter from the given absolute path. This function is targeted for
	paths on Windows. Unix style paths will just return the root '/'.

	Path: [String] The absolute path containing the drive letter.

	Return: [String] The drive letter, colon, and path separator are returned. On Unix platforms, just the '/'
		character is returned.
--]]
function FileSystem.GetDrive(Path)
	if not FileSystem.IsAbsolute(Path) then
		return ""
	end

	if FFI.os == "Windows" then
		local Result = string.match(Path, "(.:-)\\")

		if Result == nil then
			Result = string.match(Path, "(.:-)" .. FileSystem.Separator())
		end

		if Result ~= nil then
			return Result .. FileSystem.Separator()
		end
	end

	return FileSystem.Separator()
end

--[[
	Determines if the given path is a drive letter on Windows or the root directory on Unix.

	Path: [String] The absolute path containing the drive letter.

	Return: [Boolean] True if the given path is a drive.
--]]
function FileSystem.IsDrive(Path)
	if Path == nil then
		return false
	end

	return FileSystem.GetDrive(Path) == Path
end

--[[
	Sanitize

	This function will attempt to remove any '.' or '..' components in the path and will appropriately modify
	the result to represent changes to the path based on if a '..' component is found. This function will keep
	the path's scope (relative/absolute) during sanitization.

	Path: [String] The path to be sanitized.

	Return: [String] The sanitized path string.
--]]
function FileSystem.Sanitize(Path)
	local Result = ""

	local Items = {}
	for Item in string.gmatch(Path, "([^" .. FileSystem.Separator() .. "]+)") do
		-- Always add the first item. If the given path is relative, then this will help preserve that.
		if #Items == 0 then
			table.insert(Items, Item)
		else
			-- If the parent directory item is found, pop the last item off of the stack.
			if Item == ".." then
				table.remove(Items, #Items)
			-- Ignore same directory item and push the item to the stack.
			elseif Item ~= "." then
				table.insert(Items, Item)
			end
		end
	end

	for I, Item in ipairs(Items) do
		if Result == "" then
			if Item == "." or Item == ".." then
				Result = Item
			else
				if FileSystem.IsAbsolute(Path) then
					Result = FileSystem.GetDrive(Path) .. Item
				else
					Result = Item
				end
			end
		else
			Result = Result .. FileSystem.Separator() .. Item
		end
	end

	return Result
end

function FileSystem.GetBaseName(Path, RemoveExtension)
	local Result = string.match(Path, "^.+/(.+)$")

	if Result == nil then
		Result = Path
	end

	if RemoveExtension then
		Result = FileSystem.RemoveExtension(Result)
	end

	return Result
end

function FileSystem.GetDirectory(Path)
	local Result = string.match(Path, "(.+)/")

	if Result == nil then
		Result = Path
	end

	return Result
end

function FileSystem.GetRootDirectory(Path)
	local Result = Path

	local Index = string.find(Path, FileSystem.Separator(), 1, true)

	if Index ~= nil then
		Result = string.sub(Path, 1, Index - 1)
	end

	return Result
end

function FileSystem.GetSlabPath()
	local Path = love.filesystem.getSource()
	if not FileSystem.IsDirectory(Path) then
		Path = love.filesystem.getSourceBaseDirectory()
	end
	return Path .. "/Slab"
end

function FileSystem.GetExtension(Path)
	local Result = string.match(Path, "[^.]+$")

	if Result == nil then
		Result = ""
	end

	return Result
end

function FileSystem.RemoveExtension(Path)
	local Result = string.match(Path, "(.+)%.")

	if Result == nil then
		Result = Path
	end

	return Result
end

function FileSystem.ReadContents(Path, IsBinary, IsDefault)
	local Result, Error

	if IsDefault then
		Result, Error = love.filesystem.read(Path)
	else
		local Handle
		local Mode = IsBinary and "rb" or "r"
		Handle, Error = io.open(Path, Mode)
		if Handle ~= nil then
			Result = Handle:read("*a")
			Handle:close()
		end
	end

	return Result, Error
end

function FileSystem.SaveContents(Path, Contents, IsDefault)
	local Result, Error

	if IsDefault then
		Result, Error = love.filesystem.write(Path, Contents)
	else
		local Handle, Error = io.open(Path, "w")
		if Handle ~= nil then
			Handle:write(Contents)
			Handle:close()
			Result = true
		end
	end

	return Result, Error
end

function FileSystem.GetClipboard()
	local Contents = love.system.getClipboardText()

	if Contents ~= nil then
		-- Remove Windows style newlines.
		Contents = string.gsub(Contents, "\r\n", "\n")
	end

	return Contents
end

function FileSystem.ToLove(Source)
	local ext = FileSystem.GetExtension(Source)

	love.filesystem.createDirectory('tmp')
	Copy(Source, love.filesystem.getSaveDirectory() .. "/tmp/temp." .. ext)

	return "tmp/temp." .. ext
end

return FileSystem


================================================
FILE: Internal/Core/IdCache.lua
================================================
--[[

MIT License

Copyright (c) 2019-2021 Love2D Community <love2d.org>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

--]]

local IdCache = {}
IdCache.__index = IdCache

function IdCache:get(parentId, id)
	local pId = self._ids[parentId]
	local resultId = pId and pId[id]

	if resultId then return resultId end

	resultId = ("%s.%s"):format(parentId, id)
	if pId then
		pId[id] = resultId
	else
		self._ids[parentId] = { [id] = resultId }
	end

	return resultId
end

return function()
	return setmetatable({
		_ids = {}
	}, IdCache)
end


================================================
FILE: Internal/Core/Messages.lua
================================================
--[[

MIT License

Copyright (c) 2019-2021 Love2D Community <love2d.org>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

--]]

--[[
	The messages system is a system for Slab to notify developers of issues or suggestions on aspects
	of the API. Functions or options may be deprecated or Slab may offer an alternative usage. The system
	is designed to notify the user only once to prevent any repeated output to the console if enabled. This
	system can be enabled at startup and the developer will have the ability to gather the messages to
	be displayed in a control if desired.
--]]

local insert = table.insert

local Messages = {}

local Enabled = true
local Cache = {}

function Messages.Broadcast(Id, Message)
	if not Enabled then
		return
	end

	assert(Id ~= nil, "Id is invalid.")
	assert(type(Id) == 'string', "Id is not a string type.")
	assert(Message ~= nil, "Message is invalid.")
	assert(type(Message) == 'string', "Message is not a string type.")

	if Cache[Id] == nil then
		Cache[Id] = Message
		print(Message)
	end
end

function Messages.Get()
	local Result = {}

	for K, V in pairs(Cache) do
		insert(Result, V)
	end

	return Result
end

function Messages.SetEnabled(InEnabled)
	Enabled = InEnabled
end

return Messages


================================================
FILE: Internal/Core/Scale.lua
================================================

--[[

MIT License

Copyright (c) 2019-2021 Love2D Community <love2d.org>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

--]]


local CurrentScale = 1


local Scale = {}

function Scale.SetScale(newScale)
	assert(type(newScale) == "number", "Scale needs to be a number!")
	CurrentScale = newScale
end

function Scale.GetScale()
	return CurrentScale or 1
end

function Scale.GetScreenWidth()
	return love.graphics.getWidth() / Scale.GetScale()
end

function Scale.GetScreenHeight()
	return love.graphics.getHeight() / Scale.GetScale()
end

function Scale.GetScreenDimensions()
	return Scale.GetScreenWidth(), Scale.GetScreenHeight()
end


return Scale



================================================
FILE: Internal/Core/Stats.lua
================================================
--[[

MIT License

Copyright (c) 2019-2021 Love2D Community <love2d.org>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

--]]

local Stats = {}

local insert = table.insert
local max = math.max

local Data = {}
local Pending = {}
local Enabled = false
local QueueEnabled = false
local QueueDisable = false
local Id = 1
local QueueFlush = false
local FrameNumber = 0

local function GetCategory(Category)
	assert(Category ~= nil, "Nil category given to Stats system.")
	assert(Category ~= '', "Empty category given to Stats system.")
	assert(type(Category) == 'string', "Category given is not of type string. Type given is '" .. type(Category) .. "'.")

	if Data[Category] == nil then
		Data[Category] = {}
	end

	return Data[Category]
end

local function ResetCategory(Category)
	local Instance = Data[Category]

	if Instance ~= nil then
		for K, V in pairs(Instance) do
			V.LastTime = V.Time
			V.LastCallCount = V.CallCount
			V.MaxTime = max(V.MaxTime, V.Time)
			V.Time = 0.0
			V.CallCount = 0
		end
	end
end

local function GetItem(Name, Category)
	assert(Name ~= nil, "Nil name given to Stats system.")
	assert(Name ~= '', "Empty name given to Stats system.")

	local Cat = GetCategory(Category)

	if Cat[Name] == nil then
		local Instance = {}
		Instance.Time = 0.0
		Instance.MaxTime = 0.0
		Instance.CallCount = 0
		Instance.LastTime = 0.0
		Instance.LastCallCount = 0.0
		Cat[Name] = Instance
	end

	return Cat[Name]
end

function Stats.Begin(Name, Category)
	if not Enabled then
		return
	end

	local Handle = Id
	Id = Id + 1

	local Instance = {StartTime = love.timer.getTime(), Name = Name, Category = Category}
	Pending[Handle] = Instance

	return Handle
end

function Stats.End(Handle)
	if not Enabled then
		return
	end

	assert(Handle ~= nil, "Nil handle given to Stats.End.")

	local Instance = Pending[Handle]
	assert(Instance ~= nil, "Invalid handle given to Stats.End.")
	Pending[Handle] = nil

	local Elapsed = love.timer.getTime() - Instance.StartTime

	local Item = GetItem(Instance.Name, Instance.Category)
	Item.CallCount = Item.CallCount + 1
	Item.Time = Item.Time + Elapsed
end

function Stats.GetTime(Name, Category)
	if not Enabled then
		return 0.0
	end

	local Item = GetItem(Name, Category)

	return Item.Time > 0.0 and Item.Time or Item.LastTime
end

function Stats.GetMaxTime(Name, Category)
	if not Enabled then
		return 0.0
	end

	local Item = GetItem(Name, Category)

	return Item.MaxTime
end

function Stats.GetCallCount(Name, Category)
	if not Enabled then
		return 0
	end

	local Item = GetItem(Name, Category)

	return Item.CallCount > 0 and Item.CallCount or Item.LastCallCount
end

function Stats.Reset(Strict)
	FrameNumber = FrameNumber + 1

	if QueueEnabled then
		Enabled = true
		QueueEnabled = false
	end

	if QueueDisable then
		Enabled = false
		QueueDisable = false
	end

	if QueueFlush then
		Data = {}
		Pending = {}
		Id = 1
		QueueFlush = false
	end

	if not Enabled then
		return
	end

	local Message = nil
	for K, V in pairs(Pending) do
		if Message == nil then
			Message = "Stats.End were not called for the given stats: \n"
		end

		Message = Message .. "\t" .. tostring(V.Name) .. " in " .. tostring(V.Category) .. "\n"
	end

	if Strict then
		assert(Message == nil, Message)
	end

	for K, V in pairs(Data) do
		ResetCategory(K)
	end
end

function Stats.SetEnabled(IsEnabled)
	QueueEnabled = IsEnabled

	if not QueueEnabled then
		QueueDisable = true
	end
end

function Stats.IsEnabled()
	return Enabled
end

function Stats.GetCategories()
	local Result = {}

	for K, V in pairs(Data) do
		insert(Result, K)
	end

	return Result
end

function Stats.GetItems(Category)
	local Result = {}

	local Instance = GetCategory(Category)

	for K, V in pairs(Instance) do
		insert(Result, K)
	end

	return Result
end

function Stats.Flush()
	QueueFlush = true
end

function Stats.GetFrameNumber()
	return FrameNumber
end

return Stats


================================================
FILE: Internal/Core/TablePool.lua
================================================
--[[

MIT License

Copyright (c) 2019-2021 Love2D Community <love2d.org>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

--]]

local TablePool = {}
TablePool.__index = TablePool

function TablePool:pull()
	local count = self[0]
	if count == 0 then return {} end

	local result = self[count]
	self[count], self[0] = nil, count - 1

	return result
end

function TablePool:pullClean()
	local result = self:pull()
	for k in pairs(result) do
		result[k] = nil
	end
	return result
end

function TablePool:push(t)
	local count = self[0] + 1
	self[count], self[0] = t, count
end

return function()
	return setmetatable({ [0] = 0 }, TablePool)
end


================================================
FILE: Internal/Core/Utility.lua
================================================
--[[

MIT License

Copyright (c) 2019-2021 Love2D Community <love2d.org>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

--]]

local Utility = {}

local abs = math.abs
local remove = table.remove

function Utility.MakeColor(color, target)
	target = target or {}
	if color then
		target[1] = color[1]
		target[2] = color[2]
		target[3] = color[3]
		target[4] = color[4]
	else
		target[1] = 0
		target[2] = 0
		target[3] = 0
		target[4] = 1
	end
	return target
end

function Utility.HSVtoRGB(H, S, V)
	if S == 0.0 then
		return V, V, V
	end

	H = math.fmod(H, 1.0) / (60.0/360.0)
	local I = math.floor(H)
	local F = H - I
	local P = V * (1.0 - S)
	local Q = V * (1.0 - S * F)
	local T = V * (1.0 - S * (1.0 - F))

	local R, G, B = 0, 0, 0

	if I == 0 then
		R, G, B = V, T, P
	elseif I == 1 then
		R, G, B = Q, V, P
	elseif I == 2 then
		R, G, B = P, V, T
	elseif I == 3 then
		R, G, B = P, Q, V
	elseif I == 4 then
		R, G, B = T, P, V
	else
		R, G, B = V, P, Q
	end

	return R, G, B
end

function Utility.RGBtoHSV(R, G, B)
	local K = 0.0

	if G < B then
		local T = G
		G = B
		B = T
		K = -1.0
	end

	if R < G then
		local T = R
		R = G
		G = T
		K = -2.0 / 6.0 - K
	end

	local Chroma = R - (G < B and G or B)
	local H = abs(K + (G - B) / (6.0 * Chroma + 1e-20))
	local S = Chroma / (R + 1e-20)
	local V = R

	return H, S, V
end

function Utility.HasValue(Table, Value)
	for I, V in ipairs(Table) do
		if V == Value then
			return true
		end
	end

	return false
end

function Utility.Remove(Table, Value)
	for I, V in ipairs(Table) do
		if V == Value then
			remove(Table, I)
			break
		end
	end
end

function Utility.CopyValues(A, B)
	if type(A) ~= "table" or type(B) ~= "table" then
		return
	end

	for K, V in pairs(A, B) do
		local Other = B[K]

		if Other ~= nil then
			A[K] = Utility.Copy(Other)
		end
	end
end

function Utility.Copy(Original)
	local Copy = nil

	if type(Original) == "table" then
		Copy = {}

		for K, V in next, Original, nil do
			Copy[Utility.Copy(K)] = Utility.Copy(V)
		end
	else
		Copy = Original
	end

	return Copy
end

function Utility.Contains(Table, Value)
	if Table == nil then
		return false
	end

	for I, V in ipairs(Table) do
		if Value == V then
			return true
		end
	end

	return false
end

function Utility.TableCount(Table)
	local Result = 0

	if Table ~= nil then
		for K, V in pairs(Table) do
			Result = Result + 1
		end
	end

	return Result
end

local OS = love.system.getOS()
function Utility.IsWindows()
	return OS == "Windows"
end

function Utility.IsOSX()
	return OS == "OS X"
end

function Utility.IsMobile()
	return (OS == "Android") or (OS == "iOS")
end

function Utility.Clamp(Value, Min, Max)
	return Value < Min and Min or (Value > Max and Max or Value)
end

return Utility


================================================
FILE: Internal/Input/Common.lua
================================================
--[[

MIT License

Copyright (c) 2019-2021 Love2D Community <love2d.org>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

--]]

local Common = {}

Common.Event =
{
	None = 0,
	Pressed = 1,
	Released = 2
}

return Common


================================================
FILE: Internal/Input/Keyboard.lua
================================================
--[[

MIT License

Copyright (c) 2019-2021 Love2D Community <love2d.org>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

--]]

local insert = table.insert

local Common = require(SLAB_PATH .. '.Internal.Input.Common')
local Stats = require(SLAB_PATH .. '.Internal.Core.Stats')
local Utility = require(SLAB_PATH .. '.Internal.Core.Utility')

local Keyboard = {}

local KeyPressedFn = nil
local KeyReleasedFn = nil
local Events = {}
local Keys = {}

local function PushEvent(Type, Key, Scancode, IsRepeat)
	insert(Events, {
		Type = Type,
		Key = Key,
		Scancode = Scancode,
		IsRepeat = IsRepeat,
		Frame = Stats.GetFrameNumber()
	})
end

local function OnKeyPressed(Key, Scancode, IsRepeat)
	PushEvent(Common.Event.Pressed, Key, Scancode, IsRepeat)

	if KeyPressedFn ~= nil then
		KeyPressedFn(Key, Scancode, IsRepeat)
	end
end

local function OnKeyReleased(Key, Scancode)
	PushEvent(Common.Event.Released, Key, Scancode, false)

	if KeyReleasedFn ~= nil then
		KeyReleasedFn(Key, Scancode)
	end
end

local function ProcessEvents()
	Keys = {}

	-- Soft keyboards found on mobile/tablet devices will push keypressed/keyreleased events when the user
	-- releases from the pressed key. All released events pushed as the same frame as the pressed events will be
	-- pushed to the events table for the next frame to process.
	local NextEvents = {}

	for I, V in ipairs(Events) do
		if Keys[V.Scancode] == nil then
			Keys[V.Scancode] = {}
		end

		local Key = Keys[V.Scancode]

		if Utility.IsMobile() and V.Type == Common.Event.Released and Key.Frame == V.Frame then
			V.Frame = V.Frame + 1
			insert(NextEvents, V)
		else
			Key.Type = V.Type
			Key.Key = V.Key
			Key.Scancode = V.Scancode
			Key.IsRepeat = V.IsRepeat
			Key.Frame = V.Frame
		end
	end

	Events = NextEvents
end

Keyboard.OnKeyPressed = OnKeyPressed;
Keyboard.OnKeyReleased = OnKeyReleased;

function Keyboard.Initialize(Args, dontInterceptEventHandlers)
	if not dontInterceptEventHandlers then
		KeyPressedFn = love.handlers['keypressed']
		KeyReleasedFn = love.handlers['keyreleased']
		love.handlers['keypressed'] = OnKeyPressed
		love.handlers['keyreleased'] = OnKeyReleased
	end
end

function Keyboard.Update()
	ProcessEvents()
end

function Keyboard.IsPressed(Key)
	local Item = Keys[Key]

	if Item == nil then
		return false
	end

	return Item.Type == Common.Event.Pressed
end

function Keyboard.IsReleased(Key)
	local Item = Keys[Key]

	if Item == nil then
		return false
	end

	return Item.Type == Common.Event.Released
end

function Keyboard.IsDown(Key)
	return love.keyboard.isScancodeDown(Key)
end

return Keyboard


================================================
FILE: Internal/Input/Mouse.lua
================================================
--[[

MIT License

Copyright (c) 2019-2021 Love2D Community <love2d.org>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

--]]

local insert = table.insert

local Common = require(SLAB_PATH .. '.Internal.Input.Common')
local DrawCommands = require(SLAB_PATH .. '.Internal.Core.DrawCommands')
local TablePool = require(SLAB_PATH .. '.Internal.Core.TablePool')
local Scale = require(SLAB_PATH .. ".Internal.Core.Scale")
local Utility = require(SLAB_PATH .. ".Internal.Core.Utility")


local Mouse = {}

local State =
{
	X = 0.0,
	Y = 0.0,
	DeltaX = 0.0,
	DeltaY = 0.0,
	AsyncDeltaX = 0.0,
	AsyncDeltaY = 0.0,
	Buttons = {}
}

local Cursors = nil
local CurrentCursor = "arrow"
local PendingCursor = ""
local MouseMovedFn = nil
local MousePressedFn = nil
local MouseReleasedFn = nil
local Events = {}
local eventPool = TablePool()

-- Custom cursors allow the developer to override any specific system cursor used. This system will also
-- allow developers to set an empty image to hide the cursor for specific states, such as mouse resize.
-- For more information, refer to the SetCustomCursor/ClearCustomCursor functions.
local CustomCursors = {}

local function ScaleMouseXY(X, Y)
	local scale = Scale.GetScale()
	return X / scale, Y / scale
end


local function TransformPoint(X,Y)
	return ScaleMouseXY(X, Y)
end


local function OnMouseMoved(X, Y, DX, DY, IsTouch)
	local tX, tY = TransformPoint(X, Y)
	State.X = tX
	State.Y = tY

	State.AsyncDeltaX = State.AsyncDeltaX + DX
	State.AsyncDeltaY = State.AsyncDeltaY + DY

	if MouseMovedFn ~= nil then
		MouseMovedFn(X, Y, DX, DY, IsTouch)
	end
end

local function PushEvent(Type, X, Y, Button, IsTouch, Presses)
	local ev = eventPool:pull()
	ev.Type = Type
	ev.X = X
	ev.Y = Y
	ev.Button = Button
	ev.IsTouch = IsTouch
	ev.Presses = Presses
	insert(Events, 1, ev)
end

local function OnMousePressed(X, Y, Button, IsTouch, Presses)
	local tX, tY = TransformPoint(X, Y)
	PushEvent(Common.Event.Pressed, tX, tY, Button, IsTouch, Presses)

	if MousePressedFn ~= nil then
		MousePressedFn(X, Y, Button, IsTouch, Presses)
	end
end

local function OnMouseReleased(X, Y, Button, IsTouch, Presses)
	local tX, tY = TransformPoint(X, Y)
	PushEvent(Common.Event.Released, tX, tY, Button, IsTouch, Presses)

	if MouseReleasedFn ~= nil then
		MouseReleasedFn(X, Y, Button, IsTouch, Presses)
	end
end

local function ProcessEvents()
	for k, v in pairs(State.Buttons) do
		v.Type = Common.Event.None
	end
	local wasPressed = false

	for i = #Events, 1, -1 do
		local ev = Events[i]

		-- delay release events until next frame
		if ev.Type == Common.Event.Released and wasPressed then break end
		wasPressed = ev.Type == Common.Event.Pressed

		if State.Buttons[ev.Button] == nil then
			State.Buttons[ev.Button] = {}
		end

		local button = State.Buttons[ev.Button]
		button.Type = ev.Type
		button.IsTouch = ev.IsTouch
		button.Presses = ev.Presses

		eventPool:push(Events[i])
		Events[i] = nil
	end
end

Mouse.OnMouseMoved = OnMouseMoved;
Mouse.OnMousePressed = OnMousePressed;
Mouse.OnMouseReleased = OnMouseReleased;

function Mouse.Initialize(Args, dontInterceptEventHandlers)
	TransformPoint = Args.TransformPointToSlab or TransformPoint

	if not dontInterceptEventHandlers then
		MouseMovedFn = love.handlers['mousemoved']
		MousePressedFn = love.handlers['mousepressed']
		MouseReleasedFn = love.handlers['mousereleased']
		love.handlers['mousemoved'] = OnMouseMoved
		love.handlers['mousepressed'] = OnMousePressed
		love.handlers['mousereleased'] = OnMouseReleased
	end
end

function Mouse.Update()
	ProcessEvents()

	State.DeltaX = State.AsyncDeltaX
	State.DeltaY = State.AsyncDeltaY
	State.AsyncDeltaX = 0
	State.AsyncDeltaY = 0

	if Cursors == nil and (not Utility.IsMobile()) then
		Cursors = {}
		Cursors.Arrow = love.mouse.getSystemCursor('arrow')
		Cursors.SizeWE = love.mouse.getSystemCursor('sizewe')
		Cursors.SizeNS = love.mouse.getSystemCursor('sizens')
		Cursors.SizeNESW = love.mouse.getSystemCursor('sizenesw')
		Cursors.SizeNWSE = love.mouse.getSystemCursor('sizenwse')
		Cursors.IBeam = love.mouse.getSystemCursor('ibeam')
		Cursors.Hand = love.mouse.getSystemCursor('hand')
	end

	Mouse.SetCursor('arrow')
end

function Mouse.Draw()
	Mouse.UpdateCursor()

	local CustomCursor = CustomCursors[CurrentCursor]
	if CustomCursor ~= nil then
		DrawCommands.SetLayer('Mouse')
		DrawCommands.Begin()

		if CustomCursor.Quad ~= nil then
			local X, Y, W, H = CustomCursor.Quad:getViewport()
			DrawCommands.SubImage(State.X, State.Y, CustomCursor.Image, X, Y, W, H)
		else
			DrawCommands.Image(State.X, State.Y, CustomCursor.Image)
		end

		DrawCommands.End()
	end
end

function Mouse.IsDown(Button)
	return love.mouse.isDown(Button)
end

function Mouse.IsClicked(Button)
	local Item = State.Buttons[Button]

	if Item == nil or Item.Presses == 0 then
		return false
	end

	return Item.Type == Common.Event.Pressed
end

function Mouse.IsDoubleClicked(Button)
	local Item = State.Buttons[Button]

	if Item == nil or Item.Presses < 2 then
		return false
	end

	return Item.Type == Common.Event.Pressed and Item.Presses % 2 == 0
end

function Mouse.IsReleased(Button)
	local Item = State.Buttons[Button]

	if Item == nil then
		return false
	end

	return Item.Type == Common.Event.Released
end

function Mouse.Position()
	return State.X, State.Y
end

function Mouse.HasDelta()
	return State.DeltaX ~= 0.0 or State.DeltaY ~= 0.0
end

function Mouse.GetDelta()
	return State.DeltaX, State.DeltaY
end

function Mouse.IsDragging(Button)
	return Mouse.IsDown(Button) and Mouse.HasDelta()
end

function Mouse.SetCursor(Type)
	if Cursors == nil then
		return
	end

	PendingCursor = Type
end

function Mouse.UpdateCursor()
	if PendingCursor ~= "" and PendingCursor ~= CurrentCursor then
		CurrentCursor = PendingCursor
		PendingCursor = ""

		if CustomCursors[CurrentCursor] ~= nil then
			love.mouse.setVisible(false)
		else
			love.mouse.setVisible(true)
			local Type = CurrentCursor
			if Type == 'arrow' then
				love.mouse.setCursor(Cursors.Arrow)
			elseif Type == 'sizewe' then
				love.mouse.setCursor(Cursors.SizeWE)
			elseif Type == 'sizens' then
				love.mouse.setCursor(Cursors.SizeNS)
			elseif Type == 'sizenesw' then
				love.mouse.setCursor(Cursors.SizeNESW)
			elseif Type == 'sizenwse' then
				love.mouse.setCursor(Cursors.SizeNWSE)
			elseif Type == 'ibeam' then
				love.mouse.setCursor(Cursors.IBeam)
			elseif Type == 'hand' then
				love.mouse.setCursor(Cursors.Hand)
			end
		end
	end
end

function Mouse.SetCustomCursor(Type, Image, Quad)
	-- If no image is supplied, then create a 1x1 image with no alpha. This is a way to disable certain system cursors.
	if Image == nil then
		local Data = love.image.newImageData(1, 1)
		Image = love.graphics.newImage(Data)
	end

	if CustomCursors[Type] == nil then
		CustomCursors[Type] = {}
	end

	CustomCursors[Type].Image = Image
	CustomCursors[Type].Quad = Quad
	PendingCursor = CurrentCursor
	CurrentCursor = ""
end

function Mouse.ClearCustomCursor(Type)
	CustomCursors[Type] = nil
	PendingCursor = CurrentCursor
	CurrentCursor = ""
end

return Mouse


================================================
FILE: Internal/Resources/Styles/Dark.style
================================================
FontSize = 14
MenuColor = (0.2, 0.2, 0.2, 1.0)
ScrollBarColor = (0.4, 0.4, 0.4, 1.0)
ScrollBarHoveredColor = (0.8, 0.8, 0.8, 1.0)
SeparatorColor = (0.5, 0.5, 0.5, 0.7)
WindowBackgroundColor = (0.2, 0.2, 0.2, 1.0)
WindowTitleFocusedColor = (0.26, 0.53, 0.96, 1.0)
WindowCloseBgColor = (0.64, 0.64, 0.64, 1.0)
WindowCloseColor = (0.0, 0.0, 0.0, 1.0)
ButtonColor = (0.55, 0.55, 0.55, 1.0)
RadioButtonSelectedColor = (0.2, 0.2, 0.2, 1.0)
ButtonHoveredColor = (0.7, 0.7, 0.7, 1.0)
ButtonPressedColor = (0.8, 0.8, 0.8, 1.0)
ButtonDisabledTextColor = (0.35, 0.35, 0.35, 1.0)
CheckBoxSelectedColor = (0.0, 0.0, 0.0, 1.0)
CheckBoxDisabledColor = (0.35, 0.35, 0.35, 1.0)
TextColor = (0.875, 0.875, 0.875, 1.0)
TextDisabledColor = (0.45, 0.45, 0.45, 1.0)
TextHoverBgColor = (0.5, 0.5, 0.5, 1.0)
TextURLColor = (0.2, 0.2, 1.0, 1.0)
ComboBoxColor = (0.4, 0.4, 0.4, 1.0)
ComboBoxHoveredColor = (0.55, 0.55, 0.55, 1.0)
ComboBoxDropDownColor = (0.4, 0.4, 0.4, 1.0)
ComboBoxDropDownHoveredColor = (0.55, 0.55, 0.55, 1.0)
ComboBoxArrowColor = (1.0, 1.0, 1.0, 1.0)
InputBgColor = (0.4, 0.4, 0.4, 1.0)
InputEditBgColor = (0.6, 0.6, 0.6, 1.0)
InputSelectColor = (0.14, 0.29, 0.53, 0.4)
InputSliderColor = (0.1, 0.1, 0.1, 1.0)
MultilineTextColor = (0.0, 0.0, 0.0, 1.0)
ListBoxBgColor = (0.0, 0.0, 0.0, 0.0)

WindowRounding = 2.0
WindowBorder = 4.0
WindowTitleH = 0.0
ButtonRounding = 2.0
CheckBoxRounding = 2.0
ComboBoxRounding = 2.0
InputBgRounding = 2.0
ScrollBarRounding = 2.0
Indent = 14.0
MenuPadH = 0.0
MenuItemPadH = 0.0


================================================
FILE: Internal/Resources/Styles/Light.style
================================================
FontSize = 14
MenuColor = (0.74, 0.74, 0.94, 1.0)
ScrollBarColor = (0.4, 0.62, 0.80, 0.3)
ScrollBarHoveredColor = (0.28, 0.67, 0.8, 0.59)
SeparatorColor = (0.5, 0.5, 0.5, 0.7)
WindowBackgroundColor = (0.94, 0.94, 0.94, 1.0)
WindowTitleFocusedColor = (0.42, 0.75, 1.0, 1.0)
WindowCloseBgColor = (0.64, 0.64, 0.64, 1.0)
WindowCloseColor = (0.0, 0.0, 0.0, 1.0)
ButtonColor = (1.0, 0.79, 0.18, 0.78)
RadioButtonSelectedColor = (0.31, 0.25, 0.24, 1.0)
ButtonHoveredColor = (0.42, 0.82, 1.0, 0.81)
ButtonPressedColor = (0.72, 1.0, 1.0, 0.86)
ButtonDisabledTextColor = (0.55, 0.55, 0.55, 1.0)
CheckBoxSelectedColor = (0.31, 0.25, 0.24, 1.0)
CheckBoxDisabledColor = (0.55, 0.55, 0.55, 1.0)
TextColor = (0.31, 0.25, 0.24, 1.0)
TextDisabledColor = (0.55, 0.55, 0.55, 1.0)
TextHoverBgColor = (1.0, 0.99, 0.54, 0.43)
TextURLColor = (0.2, 0.2, 1.0, 1.0)
ComboBoxColor = (0.89, 0.98, 1.0, 1.0)
ComboBoxHoveredColor = (0.14, 0.29, 0.53, 0.4)
ComboBoxDropDownColor = (0.89, 0.98, 1.0, 1.0)
ComboBoxDropDownHoveredColor = (0.14, 0.29, 0.53, 0.4)
ComboBoxArrowColor = (0.31, 0.25, 0.24, 1.0)
InputBgColor = (0.89, 0.98, 1.0, 1.0)
InputEditBgColor = (0.89, 0.98, 1.0, 1.0)
InputSelectColor = (0.14, 0.29, 0.53, 0.4)
InputSliderColor = (1.0, 0.79, 0.18, 1.0)
MultilineTextColor = (0.0, 0.0, 0.0, 1.0)
ListBoxBgColor = (0.0, 0.0, 0.0, 0.0)

WindowRounding = 2.0
WindowBorder = 4.0
WindowTitleH = 0.0
ButtonRounding = 2.0
CheckBoxRounding = 2.0
ComboBoxRounding = 2.0
InputBgRounding = 2.0
ScrollBarRounding = 2.0
Indent = 14.0
MenuPadH = 0.0
MenuItemPadH = 0.0


================================================
FILE: Internal/UI/Button.lua
================================================
--[[

MIT License

Copyright (c) 2019-2021 Love2D Community <love2d.org>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

--]]

local floor = math.floor
local max = math.max

local Cursor = require(SLAB_PATH .. '.Internal.Core.Cursor')
local DrawCommands = require(SLAB_PATH .. '.Internal.Core.DrawCommands')
local Image = require(SLAB_PATH .. '.Internal.UI.Image')
local LayoutManager = require(SLAB_PATH .. '.Internal.UI.LayoutManager')
local Mouse = require(SLAB_PATH .. '.Internal.Input.Mouse')
local Stats = require(SLAB_PATH .. '.Internal.Core.Stats')
local Style = require(SLAB_PATH .. '.Style')
local Text = require(SLAB_PATH .. '.Internal.UI.Text')
local Tooltip = require(SLAB_PATH .. '.Internal.UI.Tooltip')
local Utility = require(SLAB_PATH .. '.Internal.Core.Utility')
local Window = require(SLAB_PATH .. '.Internal.UI.Window')

local Button = {}

local PAD = 10.0
local MINWIDTH = 75.0
local RADIUS = 8.0
local EMPTY = {}
local IGNORE = { Ignore = true }

local clickedId = nil
local labelColor = {}

function Button.Begin(label, options)
	local statHandle = Stats.Begin('Button', 'Slab')

	options = options or EMPTY
	local width, height = options.W, options.H
	local disabled = options.Disabled
	local image = options.Image
	local color = options.Color or Style.ButtonColor
	local hoverColor = options.HoverColor or Style.ButtonHoveredColor
	local pressColor = options.PressColor or Style.ButtonPressedColor
	local padX = options.PadX or PAD * 2.0
	local padY = options.PadY or PAD * 0.5
	local vLines = options.VLines or 1

	if options.Active then
		color = pressColor
	end

	local id = Window.GetItemId(label)
	local w, h = Button.GetSize(label)
	h = h * vLines

	-- If a valid image was specified, then adjust the button size to match the requested image size. Also takes into account any sub UVs.
	local imageW, imageH = w, h
	if image ~= nil then
		imageW, imageH = Image.GetSize(image.Image or image.Path)

		imageW = image.SubW or imageW
		imageH = image.SubH or imageH

		imageW = width or imageW
		imageH = height or imageH

		image.W = imageW
		image.H = imageH

		if imageW > 0 and imageH > 0 then
			w = imageW + padX
			h = imageH + padY
		end
	end

	w, h = LayoutManager.ComputeSize(width or w, height or h)
	LayoutManager.AddControl(w, h, 'Button')

	local x, y = Cursor.GetPosition()

	local result = false

	do
		local mouseX, mouseY = Window.GetMousePosition()
		if not Window.IsObstructedAtMouse() and x <= mouseX and mouseX <= x + w and y <= mouseY and mouseY <= y + h then
			Tooltip.Begin(options.Tooltip or "")
			Window.SetHotItem(id)

			if not disabled then
				if not Utility.IsMobile() then
					color = hoverColor
				end

				if clickedId == id then
					color = pressColor
				end

				if Mouse.IsClicked(1) then
					clickedId = id
				end

				if Mouse.IsReleased(1) and clickedId == id then
					result = true
					clickedId = nil
				end
			end
		end
	end

	if not options.Invisible then
		-- Draw the background.
		DrawCommands.Rectangle('fill', x, y, w, h, color, options.Rounding or Style.ButtonRounding)

		-- Draw the label or image. The layout of this control was already computed above. Ignore when adding sub-controls
		-- such as text or an image.
		local cursorX, cursorY = Cursor.GetPosition()
		LayoutManager.Begin('Ignore', IGNORE)
		if image ~= nil then
			Cursor.SetX(x + w * 0.5 - imageW * 0.5)
			Cursor.SetY(y + h * 0.5 - imageH * 0.5)
			Image.Begin(id .. '_Image', image)
		else
			local labelX = x + (w * 0.5) - (Style.Font:getWidth(label) * 0.5)
			local fontHeight = Style.Font:getHeight() * vLines
			Cursor.SetX(floor(labelX))
			Cursor.SetY(floor(y + (h * 0.5) - (fontHeight * 0.5)))
			labelColor.color = disabled and Style.ButtonDisabledTextColor or nil
			Text.Begin(label, labelColor)
		end
		LayoutManager.End()

		Cursor.SetPosition(cursorX, cursorY)
	end

	Cursor.SetItemBounds(x, y, w, h)
	Cursor.AdvanceY(h)

	Window.AddItem(x, y, w, h, id)

	Stats.End(statHandle)

	return result
end

function Button.BeginRadio(label, options)
	local statHandle = Stats.Begin('RadioButton', 'Slab')

	label = label or ""

	options = options or EMPTY
	local index = options.Index or 0
	local selectedIndex = options.SelectedIndex or 0

	local result = false
	local id = Window.GetItemId(label)
	local w, h = RADIUS * 2.0, RADIUS * 2.0
	local isObstructed = Window.IsObstructedAtMouse()
	local color = Style.ButtonColor
	local mouseX, mouseY = Window.GetMousePosition()

	if label ~= "" then
		local TextW, TextH = Text.GetSize(label)
		w = w + Cursor.PadX() + TextW
		h = max(h, TextH)
	end

	LayoutManager.AddControl(w, h, 'Radio')

	local x, y = Cursor.GetPosition()
	local centerX, centerY = x + RADIUS, y + RADIUS
	local dx = mouseX - centerX
	local dy = mouseY - centerY
	if not isObstructed and (dx * dx) + (dy * dy) <= RADIUS * RADIUS then
		color = Style.ButtonHoveredColor

		if clickedId == id then
			color = Style.ButtonPressedColor
		end

		if Mouse.IsClicked(1) then
			clickedId = id
		end

		if Mouse.IsReleased(1) and clickedId == id then
			result = true
			clickedId = nil
		end
	end

	DrawCommands.Circle('fill', centerX, centerY, RADIUS, color)

	if index > 0 and index == selectedIndex then
		DrawCommands.Circle('fill', centerX, centerY, RADIUS * 0.7, Style.RadioButtonSelectedColor)
	end

	if label ~= "" then
		local cursorY = Cursor.GetY()
		Cursor.AdvanceX(RADIUS * 2.0)
		LayoutManager.Begin('Ignore', IGNORE)
		Text.Begin(label)
		LayoutManager.End()
		Cursor.SetY(cursorY)
	end

	if not isObstructed and x <= mouseX and mouseX <= x + w and y <= mouseY and mouseY <= y + h then
		Tooltip.Begin(options.Tooltip or "")
		Window.SetHotItem(id)
	end

	Cursor.SetItemBounds(x, y, w, h)
	Cursor.AdvanceY(h)

	Window.AddItem(x, y, w, h)

	Stats.End(statHandle)

	return result
end

function Button.GetSize(label)
	local w = Style.Font:getWidth(label)
	local h = Style.Font:getHeight()
	return max(w, MINWIDTH) + PAD * 2.0, h + PAD * 0.5
end

function Button.ClearClicked()
	clickedId = nil
end

return Button


================================================
FILE: Internal/UI/CheckBox.lua
================================================
--[[

MIT License

Copyright (c) 2019-2021 Love2D Community <love2d.org>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

--]]

local max = math.max

local Cursor = require(SLAB_PATH .. '.Internal.Core.Cursor')
local DrawCommands = require(SLAB_PATH .. '.Internal.Core.DrawCommands')
local LayoutManager = require(SLAB_PATH .. '.Internal.UI.LayoutManager')
local Mouse = require(SLAB_PATH .. '.Internal.Input.Mouse')
local Stats = require(SLAB_PATH .. '.Internal.Core.Stats')
local Style = require(SLAB_PATH .. '.Style')
local Text = require(SLAB_PATH .. '.Internal.UI.Text')
local Tooltip = require(SLAB_PATH .. '.Internal.UI.Tooltip')
local Window = require(SLAB_PATH .. '.Internal.UI.Window')

local CheckBox = {}
local EMPTY = {}
local IGNORE = { Ignore = true }
local labelColor = {}

function CheckBox.Begin(checked, label, options)
	local statHandle = Stats.Begin('CheckBox', 'Slab')

	label = label or ""

	options = options or EMPTY
	local id = options.Id or label
	local rounding = options.Rounding or Style.CheckBoxRounding
	local size = options.Size or Style.Font:getHeight()
	local disabled = options.Disabled

	local itemId = Window.GetItemId(id)
	local boxW, boxH = size, size
	local textW, textH = Text.GetSize(label)
	local w = boxW + Cursor.PadX() + 2.0 + textW
	local h = max(boxH, textH)
	local radius = size * 0.5

	LayoutManager.AddControl(w, h, 'CheckBox')

	local result = false
	local color = disabled and Style.CheckBoxDisabledColor or Style.ButtonColor

	local x, y = Cursor.GetPosition()
	local mouseX, mouseY = Window.GetMousePosition()
	local isObstructed = Window.IsObstructedAtMouse()
	if not isObstructed and not disabled and x <= mouseX and mouseX <= x + w and y <= mouseY and mouseY <= y + h then
		color = Style.ButtonHoveredColor

		if Mouse.IsDown(1) then
			color = Style.ButtonPressedColor
		elseif Mouse.IsReleased(1) then
			result = true
		end
	end

	DrawCommands.Rectangle('fill', x, y, boxW, boxH, color, rounding)
	if checked then
		DrawCommands.Cross(x + radius, y + radius, radius - 1.0, Style.CheckBoxSelectedColor)
	end
	if label ~= "" then
		local cursorY = Cursor.GetY()
		Cursor.AdvanceX(boxW + 2.0)
		LayoutManager.Begin('Ignore', IGNORE)
		labelColor.Color = disabled and Style.TextDisabledColor or nil
		Text.Begin(label, labelColor)
		LayoutManager.End()
		Cursor.SetY(cursorY)
	end

	if not isObstructed and x <= mouseX and mouseX <= x + w and y <= mouseY and mouseY <= y + h then
		Tooltip.Begin(options.Tooltip or "")
		Window.SetHotItem(itemId)
	end

	Cursor.SetItemBounds(x, y, w, h)
	Cursor.AdvanceY(h)

	Window.AddItem(x, y, w, h, itemId)

	Stats.End(statHandle)

	return result
end

return CheckBox


================================================
FILE: Internal/UI/ColorPicker.lua
================================================
--[[

MIT License

Copyright (c) 2019-2021 Love2D Community <love2d.org>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

--]]

local ceil = math.ceil
local max = math.max
local min = math.min
local insert = table.insert
local unpack = table.unpack

local Button = require(SLAB_PATH .. '.Internal.UI.Button')
local Cursor = require(SLAB_PATH .. '.Internal.Core.Cursor')
local DrawCommands = require(SLAB_PATH .. '.Internal.Core.DrawCommands')
local Image = require(SLAB_PATH .. '.Internal.UI.Image')
local Input = require(SLAB_PATH .. '.Internal.UI.Input')
local LayoutManager = require(SLAB_PATH .. '.Internal.UI.LayoutManager')
local Mouse = require(SLAB_PATH .. '.Internal.Input.Mouse')
local Style = require(SLAB_PATH .. '.Style')
local Text = require(SLAB_PATH .. '.Internal.UI.Text')
local Utility = require(SLAB_PATH .. '.Internal.Core.Utility')
local Window = require(SLAB_PATH .. '.Internal.UI.Window')

local ColorPicker = {}

local SaturationMeshes = nil
local SaturationSize = 200.0
local SaturationStep = 5
local SaturationFocused = false

local TintMeshes = nil
local TintW = 30.0
local TintH = SaturationSize
local TintFocused = false

local AlphaMesh = nil
local AlphaW = TintW
local AlphaH = TintH
local AlphaFocused = false

local CurrentColor = {1.0, 1.0, 1.0, 1.0}
local ColorH = 25.0

local function IsEqual(A, B)
	for I, V in ipairs(A) do
		if V ~= B[I] then
			return false
		end
	end

	return true
end

local function InputColor(Component, Value, OffsetX)
	local Changed = false
	Text.Begin(string.format("%s ", Component))
	Cursor.SameLine()
	Cursor.SetRelativeX(OffsetX)
	if Input.Begin('ColorPicker_' .. Component, {W = 40.0, NumbersOnly = true, Text = tostring(ceil(Value * 255)), ReturnOnText = false}) then
		local NewValue = tonumber(Input.GetText())
		if NewValue ~= nil then
			NewValue = max(NewValue, 0)
			NewValue = min(NewValue, 255)
			Value = NewValue / 255
			Changed = true
		end
	end
	return Value, Changed
end

local function UpdateSaturationColors()
	if SaturationMeshes ~= nil then
		local MeshIndex = 1
		local Step = SaturationStep
		local C00 = {1.0, 1.0, 1.0, 1.0}
		local C10 = {1.0, 1.0, 1.0, 1.0}
		local C01 = {1.0, 1.0, 1.0, 1.0}
		local C11 = {1.0, 1.0, 1.0, 1.0}
		local StepX, StepY = 0, 0
		local Hue, Sat, Val = Utility.RGBtoHSV(CurrentColor[1], CurrentColor[2], CurrentColor[3])

		for I = 1, Step, 1 do
			for J = 1, Step, 1 do
				local S0 = StepX / Step
				local S1 = (StepX + 1) / Step
				local V0 = 1.0 - (StepY / Step)
				local V1 = 1.0 - ((StepY + 1) / Step)

				C00[1], C00[2], C00[3] = Utility.HSVtoRGB(Hue, S0, V0)
				C10[1], C10[2], C10[3] = Utility.HSVtoRGB(Hue, S1, V0)
				C01[1], C01[2], C01[3] = Utility.HSVtoRGB(Hue, S0, V1)
				C11[1], C11[2], C11[3] = Utility.HSVtoRGB(Hue, S1, V1)

				local Mesh = SaturationMeshes[MeshIndex]
				MeshIndex = MeshIndex + 1

				Mesh:setVertexAttribute(1, 3, C00[1], C00[2], C00[3], C00[4])
				Mesh:setVertexAttribute(2, 3, C10[1], C10[2], C10[3], C10[4])
				Mesh:setVertexAttribute(3, 3, C11[1], C11[2], C11[3], C11[4])
				Mesh:setVertexAttribute(4, 3, C01[1], C01[2], C01[3], C01[4])

				StepX = StepX + 1
			end

			StepX = 0
			StepY = StepY + 1
		end
	end
end

local function InitializeSaturationMeshes()
	if SaturationMeshes == nil then
		SaturationMeshes = {}
		local Step = SaturationStep
		local X, Y = 0.0, 0.0
		local Size = SaturationSize / Step

		for I = 1, Step, 1 do
			for J = 1, Step, 1 do
				local Verts = {
					{
						X, Y,
						0.0, 0.0
					},
					{
						X + Size, Y,
						1.0, 0.0
					},
					{
						X + Size, Y + Size,
						1.0, 1.0
					},
					{
						X, Y + Size,
						0.0, 1.0
					}
				}

				local NewMesh = love.graphics.newMesh(Verts)
				insert(SaturationMeshes, NewMesh)

				X = X + Size
			end

			X = 0.0
			Y = Y + Size
		end
	end

	UpdateSaturationColors()
end

local function InitializeTintMeshes()
	if TintMeshes == nil then
		TintMeshes = {}
		local Step = 6
		local X, Y = 0.0, 0.0
		local C0 = {1.0, 1.0, 1.0, 1.0}
		local C1 = {1.0, 1.0, 1.0, 1.0}
		local I = 0
		local Colors = {
			{1.0, 0.0, 0.0, 1.0},
			{1.0, 1.0, 0.0, 1.0},
			{0.0, 1.0, 0.0, 1.0},
			{0.0, 1.0, 1.0, 1.0},
			{0.0, 0.0, 1.0, 1.0},
			{1.0, 0.0, 1.0, 1.0},
			{1.0, 0.0, 0.0, 1.0}
		}

		for Index = 1, Step, 1 do
			C0 = Colors[Index]
			C1 = Colors[Index + 1]
			local Verts = {
				{
					X, Y,
					0.0, 0.0,
					C0[1], C0[2], C0[3], C0[4]
				},
				{
					TintW, Y,
					1.0, 0.0,
					C0[1], C0[2], C0[3], C0[4]
				},
				{
					TintW, Y + TintH / Step,
					1.0, 1.0,
					C1[1], C1[2], C1[3], C1[4]
				},
				{
					X, Y + TintH / Step,
					0.0, 1.0,
					C1[1], C1[2], C1[3], C1[4]
				}
			}

			local NewMesh = love.graphics.newMesh(Verts)
			insert(TintMeshes, NewMesh)

			Y = Y + TintH / Step
		end
	end
end

local function InitializeAlphaMesh()
	if AlphaMesh == nil then
		local Verts = {
			{
				0.0, 0.0,
				0.0, 0.0,
				1.0, 1.0, 1.0, 1.0
			},
			{
				AlphaW, 0.0,
				1.0, 0.0,
				1.0, 1.0, 1.0, 1.0
			},
			{
				AlphaW, AlphaH,
				1.0, 1.0,
				0.0, 0.0, 0.0, 1.0
			},
			{
				0.0, AlphaH,
				0.0, 1.0,
				0.0, 0.0, 0.0, 1.0
			}
		}

		AlphaMesh = love.graphics.newMesh(Verts)
	end
end

function ColorPicker.Begin(Options)
	Options = Options == nil and {} or Options
	Options.Color = Options.Color == nil and {1.0, 1.0, 1.0, 1.0} or Options.Color
	Options.Refresh = Options.Refresh == nil and false or Options.Refresh
	Options.X = Options.X == nil and nil or Options.X
	Options.Y = Options.Y == nil and nil or Options.Y

	if SaturationMeshes == nil then
		InitializeSaturationMeshes()
	end

	if TintMeshes == nil then
		InitializeTintMeshes()
	end

	if AlphaMesh == nil then
		InitializeAlphaMesh()
	end

	Window.Begin('ColorPicker', {Title = "Color Picker", X = Options.X, Y = Options.Y})

	if Window.IsAppearing() or Options.Refresh then
		CurrentColor[1] = Options.Color[1] or 0.0
		CurrentColor[2] = Options.Color[2] or 0.0
		CurrentColor[3] = Options.Color[3] or 0.0
		CurrentColor[4] = Options.Color[4] or 1.0
		UpdateSaturationColors()
	end

	local X, Y = Cursor.GetPosition()
	local MouseX, MouseY = Window.GetMousePosition()
	local H, S, V = Utility.RGBtoHSV(CurrentColor[1], CurrentColor[2], CurrentColor[3])
	local UpdateColor = false
	local MouseClicked = Mouse.IsClicked(1) and not Window.IsObstructedAtMouse()

	if SaturationMeshes ~= nil then
		for I, V in ipairs(SaturationMeshes) do
			DrawCommands.Mesh(V, X, Y)
		end

		Window.AddItem(X, Y, SaturationSize, SaturationSize)

		local UpdateSaturation = false
		if X <= MouseX and MouseX < X + SaturationSize and Y <= MouseY and MouseY < Y + SaturationSize then
			if MouseClicked then
				SaturationFocused = true
				UpdateSaturation = true
			end
		end

		if SaturationFocused and Mouse.IsDragging(1) then
			UpdateSaturation = true
		end

		if UpdateSaturation then
			local CanvasX = max(MouseX - X, 0)
			CanvasX = min(CanvasX, SaturationSize)

			local CanvasY = max(MouseY - Y, 0)
			CanvasY = min(CanvasY, SaturationSize)

			S = CanvasX / SaturationSize
			V = 1 - (CanvasY / SaturationSize)

			UpdateColor = true
		end

		local SaturationX = S * SaturationSize
		local SaturationY = (1.0 - V) * SaturationSize
		DrawCommands.Circle('line', X + SaturationX, Y + SaturationY, 4.0, {1.0, 1.0, 1.0, 1.0})

		X = X + SaturationSize + Cursor.PadX()
	end

	if TintMeshes ~= nil then
		for I, V in ipairs(TintMeshes) do
			DrawCommands.Mesh(V, X, Y)
		end

		Window.AddItem(X, Y, TintW, TintH)

		local UpdateTint = false
		if X <= MouseX and MouseX < X + TintW and Y <= MouseY and MouseY < Y + TintH then
			if MouseClicked then
				TintFocused = true
				UpdateTint = true
			end
		end

		if TintFocused and Mouse.IsDragging(1) then
			UpdateTint = true
		end

		if UpdateTint then
			local CanvasY = max(MouseY - Y, 0)
			CanvasY = min(CanvasY, TintH)

			H = CanvasY / TintH

			UpdateColor = true
		end

		local TintY = H * TintH
		DrawCommands.Line(X, Y + TintY, X + TintW, Y + TintY, 2.0, {1.0, 1.0, 1.0, 1.0})

		X = X + TintW + Cursor.PadX()
		DrawCommands.Mesh(AlphaMesh, X, Y)
		Window.AddItem(X, Y, AlphaW, AlphaH)

		local UpdateAlpha = false
		if X <= MouseX and MouseX < X + AlphaW and Y <= MouseY and MouseY < Y + AlphaH then
			if MouseClicked then
				AlphaFocused = true
				UpdateAlpha = true
			end
		end

		if AlphaFocused and Mouse.IsDragging(1) then
			UpdateAlpha = true
		end

		if UpdateAlpha then
			local CanvasY = max(MouseY - Y, 0)
			CanvasY = min(CanvasY, AlphaH)

			CurrentColor[4] = 1.0 - CanvasY / AlphaH

			UpdateColor = true
		end

		local A = 1.0 - CurrentColor[4]
		local AlphaY = A * AlphaH
		DrawCommands.Line(X, Y + AlphaY, X + AlphaW, Y + AlphaY, 2.0, {A, A, A, 1.0})

		Y = Y + AlphaH + Cursor.PadY()
	end

	if UpdateColor then
		CurrentColor[1], CurrentColor[2], CurrentColor[3] = Utility.HSVtoRGB(H, S, V)
		UpdateSaturationColors()
	end

	local OffsetX = Text.GetWidth("##")
	Cursor.AdvanceY(SaturationSize)
	X, Y = Cursor.GetPosition()
	local R = CurrentColor[1]
	local G = CurrentColor[2]
	local B = CurrentColor[3]
	local A = CurrentColor[4]

	CurrentColor[1], R = InputColor("R", R, OffsetX)
	CurrentColor[2], G = InputColor("G", G, OffsetX)
	CurrentColor[3], B = InputColor("B", B, OffsetX)
	CurrentColor[4], A = InputColor("A", A, OffsetX)

	if R or G or B or A then
		UpdateSaturationColors()
	end

	local InputX, InputY = Cursor.GetPosition()
	Cursor.SameLine()
	X = Cursor.GetX()
	Cursor.SetY(Y)

	local WinX, WinY, WinW, WinH = Window.GetBounds()
	WinW, WinH = Window.GetBorderlessSize()

	OffsetX = Text.GetWidth("####")
	local ColorX = X + OffsetX

	local ColorW = (WinX + WinW) - ColorX
	Cursor.SetPosition(ColorX, Y)
	Image.Begin('ColorPicker_CurrentAlpha', {
		Path = SLAB_FILE_PATH .. "/Internal/Resources/Textures/Transparency.png",
		SubW = ColorW,
		SubH = ColorH,
		WrapH = "repeat",
		WrapV = "repeat"
	})
	DrawCommands.Rectangle('fill', ColorX, Y, ColorW, ColorH, CurrentColor, Style.ButtonRounding)

	local LabelW, LabelH = Text.GetSize("New")
	Cursor.SetPosition(ColorX - LabelW - Cursor.PadX(), Y + (ColorH * 0.5) - (LabelH * 0.5))
	Text.Begin("New")

	Y = Y + ColorH + Cursor.PadY()

	Cursor.SetPosition(ColorX, Y)
	Image.Begin('ColorPicker_CurrentAlpha', {
		Path = SLAB_FILE_PATH .. "/Internal/Resources/Textures/Transparency.png",
		SubW = ColorW,
		SubH = ColorH,
		WrapH = "repeat",
		WrapV = "repeat"
	})
	DrawCommands.Rectangle('fill', ColorX, Y, ColorW, ColorH, Options.Color, Style.ButtonRounding)

	local LabelW, LabelH = Text.GetSize("Old")
	Cursor.SetPosition(ColorX - LabelW - Cursor.PadX(), Y + (ColorH * 0.5) - (LabelH * 0.5))
	Text.Begin("Old")

	if Mouse.IsReleased(1) then
		SaturationFocused = false
		TintFocused = false
		AlphaFocused = false
	end

	Cursor.SetPosition(InputX, InputY)
	Cursor.NewLine()

	LayoutManager.Begin('ColorPicker_Buttons_Layout', {AlignX = 'right'})
	local Result = {Button = 0, Color = Utility.MakeColor(CurrentColor)}
	if Button.Begin("OK") then
		Result.Button = 1
	end

	LayoutManager.SameLine()

	if Button.Begin("Cancel") then
		Result.Button = -1
		Result.Color = Utility.MakeColor(Options.Color)
	end
	LayoutManager.End()

	Window.End()

	return Result
end

return ColorPicker


================================================
FILE: Internal/UI/ComboBox.lua
================================================
--[[

MIT License

Copyright (c) 2019-2021 Love2D Community <love2d.org>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

--]]

local min = math.min
local max = math.max

local Cursor = require(SLAB_PATH .. '.Internal.Core.Cursor')
local DrawCommands = require(SLAB_PATH .. '.Internal.Core.DrawCommands')
local Input = require(SLAB_PATH .. '.Internal.UI.Input')
local LayoutManager = require(SLAB_PATH .. '.Internal.UI.LayoutManager')
local Mouse = require(SLAB_PATH .. '.Internal.Input.Mouse')
local Region = require(SLAB_PATH .. '.Internal.UI.Region')
local Stats = require(SLAB_PATH .. '.Internal.Core.Stats')
local Style = require(SLAB_PATH .. '.Style')
local Tooltip = require(SLAB_PATH .. '.Internal.UI.Tooltip')
local Window = require(SLAB_PATH .. '.Internal.UI.Window')

local ComboBox = {}
local Instances = {}
local Active = nil

local MIN_WIDTH = 150.0
local MIN_HEIGHT = 150.0

local EMPTY = {}
local IGNORE = { Ignore = true }
local inputRounding = { 0, 0, 0, 0 }
local dropDownRounding = { 0, 0, 0, 0}

local function GetInstance(id)
	if Instances[id] == nil then
		local instance = {
			IsOpen = false,
			WasOpened = false,
			WinW = 0.0,
			WinH = 0.0,
			StatHandle = nil,
			InputId = id .. '_Input',
			WinId = id .. '_combobox',

			InputOptions = {
				ReadOnly = true,
				Align = 'left',
				Rounding = inputRounding,
			},

			WindowOptions = {
				AllowResize = false,
				AutoSizeWindow = false,
				AllowFocus = false,
				AutoSizeContent = true,
				NoSavedSettings = true,
			}
		}
		Instances[id] = instance
	end
	return Instances[id]
end

function ComboBox.Begin(id, options)
	local StatHandle = Stats.Begin('ComboBox', 'Slab')

	options = options or EMPTY
	local w = options.W or MIN_WIDTH
	local winH = options.WinH or MIN_HEIGHT
	local selected = options.Selected or ""
	local rounding = options.Rounding or Style.ComboBoxRounding

	local instance = GetInstance(id)
	local winItemId = Window.GetItemId(id)
	local h = Style.Font:getHeight()

	w = LayoutManager.ComputeSize(w, h)
	LayoutManager.AddControl(w, h, 'ComboBox')

	local x, y = Cursor.GetPosition()
	local radius = h * 0.35
	local inputBgColor = Style.ComboBoxColor
	local dropDownW = radius * 4.0
	local dropDownX = x + w - dropDownW
	local dropDownColor = Style.ComboBoxDropDownColor

	inputRounding[1], inputRounding[4] = rounding, rounding
	dropDownRounding[2], dropDownRounding[3] = rounding, rounding

	instance.X = x
	instance.Y = y
	instance.W = w
	instance.H = h
	instance.WinH = min(instance.WinH, winH)
	instance.StatHandle = StatHandle

	local mouseX, mouseY = Window.GetMousePosition()

	instance.WasOpened = instance.IsOpen

	local hovered = not Window.IsObstructedAtMouse() and x <= mouseX and mouseX <= x + w and y <= mouseY and mouseY <= y + h

	if hovered then
		inputBgColor = Style.ComboBoxHoveredColor
		dropDownColor = Style.ComboBoxDropDownHoveredColor

		if Mouse.IsClicked(1) then
			instance.IsOpen = not instance.IsOpen

			if instance.IsOpen then
				Window.SetStackLock(instance.WinId)
			end
		end
	end

	do
		LayoutManager.Begin('Ignore', IGNORE)
		local inputOpts = instance.InputOptions
		inputOpts.Text = selected
		inputOpts.W = max(w - dropDownW, dropDownW)
		inputOpts.H = h
		inputOpts.BgColor = inputBgColor
		Input.Begin(instance.InputId, inputOpts)
		LayoutManager.End()
	end

	Cursor.SameLine()

	DrawCommands.Rectangle('fill', dropDownX, y, dropDownW, h, dropDownColor, dropDownRounding)
	DrawCommands.Triangle('fill', dropDownX + radius * 2.0, y + h - radius * 1.35, radius, 180, Style.ComboBoxArrowColor)

	Cursor.SetItemBounds(x, y, w, h)
	Cursor.AdvanceY(h)

	if hovered then
		Tooltip.Begin(options.Tooltip or "")
		Window.SetHotItem(winItemId)
	end

	Window.AddItem(x, y, w, h, winItemId)

	local winX, winY = Window.TransformPoint(x, y)

	if instance.IsOpen then
		LayoutManager.Begin('ComboBox', IGNORE)
		local winOpts = instance.WindowOptions

		winOpts.X = winX - 1.0
		winOpts.Y = winY + h
		winOpts.W = max(w, instance.WinW)
		winOpts.H = instance.WinH
		winOpts.Layer = Window.GetLayer()
		winOpts.ContentW = max(w, instance.WinW)
		winOpts.Border = 4

		Window.Begin(instance.WinId, winOpts)
		Active = instance
	else
		Stats.End(instance.StatHandle)
	end

	return instance.IsOpen
end

function ComboBox.End()
	local y, h = 0, 0
	local statHandle = Active and Active.StatHandle or nil

	if Active ~= nil then
		Cursor.SetItemBounds(Active.X, Active.Y, Active.W, Active.H)
		y, h = Active.Y, Active.H
		local contentW, contentH = Window.GetContentSize()
		Active.WinH = contentH
		Active.WinW = max(contentW, Active.W)
		if Mouse.IsClicked(1) and Active.WasOpened and not Region.IsHoverScrollBar(Window.GetId()) then
			Active.IsOpen = false
			Active = nil
			Window.SetStackLock(nil)
		end
	end

	Window.End()
	DrawCommands.SetLayer('Normal')
	LayoutManager.End()

	if y ~= 0 and h ~= 0 then
		Cursor.SetY(y)
		Cursor.AdvanceY(h)
	end

	Stats.End(statHandle)
end

return ComboBox


================================================
FILE: Internal/UI/Dialog.lua
================================================
--[[

MIT License

Copyright (c) 2019-2021 Love2D Community <love2d.org>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

--]]

local insert = table.insert
local remove = table.remove
local min = math.min
local max = math.max
local floor = math.floor
local gmatch = string.gmatch

local Button = require(SLAB_PATH .. '.Internal.UI.Button')
local ComboBox = require(SLAB_PATH .. '.Internal.UI.ComboBox')
local Cursor = require(SLAB_PATH .. '.Internal.Core.Cursor')
local FileSystem = require(SLAB_PATH .. '.Internal.Core.FileSystem')
local Image = require(SLAB_PATH .. '.Internal.UI.Image')
local Input = require(SLAB_PATH .. '.Internal.UI.Input')
local Keyboard = require(SLAB_PATH .. '.Internal.Input.Keyboard')
local LayoutManager = require(SLAB_PATH .. '.Internal.UI.LayoutManager')
local ListBox = require(SLAB_PATH .. '.Internal.UI.ListBox')
local Mouse = require(SLAB_PATH .. '.Internal.Input.Mouse')
local Region = require(SLAB_PATH .. '.Internal.UI.Region')
local Style = require(SLAB_PATH .. '.Style')
local Text = require(SLAB_PATH .. '.Internal.UI.Text')
local Tree = require(SLAB_PATH .. '.Internal.UI.Tree')
local Utility = require(SLAB_PATH .. '.Internal.Core.Utility')
local Window = require(SLAB_PATH .. '.Internal.UI.Window')
local Scale = require(SLAB_PATH .. ".Internal.Core.Scale")


local Dialog = {}
local Instances = {}
local ActiveInstance = nil
local Stack = {}
local InstanceStack = {}
local FileDialog_AskOverwrite = false
local FilterW = 0.0

local function ValidateSaveFile(Files, Extension)
	if Extension == nil or Extension == "" then
		return
	end

	if Files ~= nil and #Files == 1 then
		local Index = string.find(Files[1], ".", 1, true)

		if Index ~= nil then
			Files[1] = string.sub(Files[1], 1, Index - 1)
		end

		Files[1] = Files[1] .. Extension
	end
end

local function UpdateInputText(Instance)
	if Instance ~= nil then
		if #Instance.Return > 0 then
			Instance.Text = #Instance.Return > 1 and "<Multiple>" or Instance.Return[1]
		else
			Instance.Text = ""
		end
	end
end

local function PruneResults(Items, DirectoryOnly)
	local Result = {}

	for I, V in ipairs(Items) do
		if FileSystem.IsDirectory(V) then
			if DirectoryOnly then
				insert(Result, V)
			end
		else
			if not DirectoryOnly then
				insert(Result, V)
			end
		end
	end

	return Result
end

local function OpenDirectory(Dir)
	if ActiveInstance ~= nil and ActiveInstance.Directory ~= nil then
		ActiveInstance.Parsed = false
		if string.sub(Dir, #Dir, #Dir) == FileSystem.Separator() then
			Dir = string.sub(Dir, 1, #Dir - 1)
		end
		ActiveInstance.Directory = FileSystem.Sanitize(Dir)
	end
end

local function FileDialogItem(Id, Label, IsDirectory, Index)
	ListBox.BeginItem(Id, {Selected = Utility.HasValue(ActiveInstance.Selected, Index)})

	if IsDirectory then
		local FontH = Style.Font:getHeight()
		Image.Begin('FileDialog_Folder', {Path = SLAB_FILE_PATH .. "/Internal/Resources/Textures/Icons.png", SubX = 0.0, SubY = 0.0, SubW = 50.0, SubH = 50.0, W = FontH, H = FontH})
		Cursor.SameLine({CenterY = true})
	end

	Text.Begin(Label)

	if ListBox.IsItemClicked(1) then
		local Set = true
		if ActiveInstance.AllowMultiSelect then
			if Keyboard.IsDown('lctrl') or Keyboard.IsDown('rctrl') then
				Set = false
				if Utility.HasValue(ActiveInstance.Selected, Index) then
					Utility.Remove(ActiveInstance.Selected, Index)
					Utility.Remove(ActiveInstance.Return, ActiveInstance.Directory .. "/" .. Label)
				else
					insert(ActiveInstance.Selected, Index)
					insert(ActiveInstance.Return, ActiveInstance.Directory .. "/" .. Label)
				end
			elseif Keyboard.IsDown('lshift') or Keyboard.IsDown('rshift') then
				if #ActiveInstance.Selected > 0 then
					Set = false
					local Anchor = ActiveInstance.Selected[#ActiveInstance.Selected]
					local Min = min(Anchor, Index)
					local Max = max(Anchor, Index)

					ActiveInstance.Selected = {}
					ActiveInstance.Return = {}
					for I = Min, Max, 1 do
						insert(ActiveInstance.Selected, I)
						if I > #ActiveInstance.Directories then
							I = I - #ActiveInstance.Directories
							insert(ActiveInstance.Return, ActiveInstance.Directory .. "/" .. ActiveInstance.Files[I])
						else
							insert(ActiveInstance.Return, ActiveInstance.Directory .. "/" .. ActiveInstance.Directories[I])
						end
					end
				end
			end
		end

		if Set then
			ActiveInstance.Selected = {Index}
			ActiveInstance.Return = {ActiveInstance.Directory .. "/" .. Label}
		end

		UpdateInputText(ActiveInstance)
	end

	local Result = false

	if ListBox.IsItemClicked(1, true) then
		if IsDirectory then
			OpenDirectory(ActiveInstance.Directory .. "/" .. Label)
		else
			Result = true
		end
	end

	ListBox.EndItem()

	return Result
end

local function AddDirectoryItem(Path)
	local Separator = FileSystem.Separator()
	local Item = {}
	Item.Path = Path
	Item.Name = FileSystem.GetBaseName(Path)
	Item.Name = Item.Name == "" and Separator or Item.Name
	-- Remove the starting slash for Unix style directories.
	if string.sub(Item.Name, 1, 1) == Separator and Item.Name ~= Separator then
		Item.Name = string.sub(Item.Name, 2)
	end
	Item.Children = nil
	return Item
end

local function FileDialogExplorer(Instance, Root)
	if Instance == nil then
		return
	end

	if Root ~= nil then
		local ShouldOpen = Window.IsAppearing() and string.find(Instance.Directory, Root.Path, 1, true) ~= nil

		local Options = {
			Label = Root.Name,
			OpenWithHighlight = false,
			IsSelected = ActiveInstance.Directory == Root.Path,
			IsOpen = ShouldOpen
		}
		local IsOpen = Tree.Begin(Root.Path, Options)

		if Mouse.IsClicked(1) and Window.IsItemHot() then
			OpenDirectory(Root.Path)
		end

		if IsOpen then
			if Root.Children == nil then
				Root.Children = {}

				local Separator = FileSystem.Separator()
				local Directories = FileSystem.GetDirectoryItems(Root.Path .. Separator, {Files = false})
				for I, V in ipairs(Directories) do
					local Path = Root.Path
					if string.sub(Path, #Path) ~= Separator and Path ~= Separator then
						Path = Path .. Separator
					end
					if string.sub(V, 1, 1) == Separator then
						V = string.sub(V, 2)
					end
					local Item = AddDirectoryItem(Path .. FileSystem.GetBaseName(V))
					insert(Root.Children, Item)
				end
			end

			for I, V in ipairs(Root.Children) do
				FileDialogExplorer(Instance, V)
			end

			Tree.End()
		end
	end
end

local function GetFilter(Instance, Index)
	local Filter = "*.*"
	local Desc = "All Files"
	if Instance ~= nil and #Instance.Filters > 0 then
		if Index == nil then
			Index = Instance.SelectedFilter
		end

		local Item = Instance.Filters[Index]
		if Item ~= nil then
			if type(Item) == "table" then
				if #Item == 1 then
					Filter = Item[1]
					Desc = ""
				elseif #Item == 2 then
					Filter = Item[1]
					Desc = Item[2]
				end
			else
				Filter = tostring(Item)
				Desc = ""
			end
		end
	end

	return Filter, Desc
end

local function GetExtension(Instance)
	local Filter, Desc = GetFilter(Instance)
	local Result = ""

	if Filter ~= "*.*" then
		local Index = string.find(Filter, ".", 1, true)

		if Index ~= nil then
			Result = string.sub(Filter, Index)
		end
	end

	return Result
end

local function IsInstanceOpen(Id)
	local Instance = Instances[Id]
	if Instance ~= nil then
		return Instance.IsOpen
	end
	return false
end

local function GetInstance(Id)
	if Instances[Id] == nil then
		local Instance = {}
		Instance.Id = Id
		Instance.IsOpen =
Download .txt
gitextract__a007ahg/

├── .github/
│   └── FUNDING.yml
├── .gitignore
├── API.lua
├── Internal/
│   ├── Core/
│   │   ├── Config.lua
│   │   ├── Cursor.lua
│   │   ├── DrawCommands.lua
│   │   ├── FileSystem.lua
│   │   ├── IdCache.lua
│   │   ├── Messages.lua
│   │   ├── Scale.lua
│   │   ├── Stats.lua
│   │   ├── TablePool.lua
│   │   └── Utility.lua
│   ├── Input/
│   │   ├── Common.lua
│   │   ├── Keyboard.lua
│   │   └── Mouse.lua
│   ├── Resources/
│   │   └── Styles/
│   │       ├── Dark.style
│   │       └── Light.style
│   └── UI/
│       ├── Button.lua
│       ├── CheckBox.lua
│       ├── ColorPicker.lua
│       ├── ComboBox.lua
│       ├── Dialog.lua
│       ├── Dock.lua
│       ├── Image.lua
│       ├── Input.lua
│       ├── LayoutManager.lua
│       ├── ListBox.lua
│       ├── Menu.lua
│       ├── MenuBar.lua
│       ├── MenuState.lua
│       ├── Region.lua
│       ├── Separator.lua
│       ├── Shape.lua
│       ├── Text.lua
│       ├── Tooltip.lua
│       ├── Tree.lua
│       └── Window.lua
├── LICENSE
├── README.md
├── Slab.lua
├── SlabDebug.lua
├── SlabDefinition.lua
├── SlabTest.lua
├── Style.lua
├── changelog.txt
├── conf.lua
├── init.lua
└── main.lua
Condensed preview — 49 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (563K chars).
[
  {
    "path": ".github/FUNDING.yml",
    "chars": 117,
    "preview": "# These are supported funding model platforms\n\ncustom: https://www.paypal.com/donate/?hosted_button_id=PHU9JP36QQYG2\n"
  },
  {
    "path": ".gitignore",
    "chars": 21,
    "preview": "Slab.ini\n.luarc.json\n"
  },
  {
    "path": "API.lua",
    "chars": 83767,
    "preview": "--[[\n\nMIT License\n\nCopyright (c) 2019-2021 Love2D Community <love2d.org>\n\nPermission is hereby granted, free of charge, "
  },
  {
    "path": "Internal/Core/Config.lua",
    "chars": 6609,
    "preview": "--[[\n\nMIT License\n\nCopyright (c) 2019-2021 Love2D Community <love2d.org>\n\nPermission is hereby granted, free of charge, "
  },
  {
    "path": "Internal/Core/Cursor.lua",
    "chars": 4812,
    "preview": "--[[\n\nMIT License\n\nCopyright (c) 2019-2021 Love2D Community <love2d.org>\n\nPermission is hereby granted, free of charge, "
  },
  {
    "path": "Internal/Core/DrawCommands.lua",
    "chars": 18148,
    "preview": "--[[\n\nMIT License\n\nCopyright (c) 2019-2021 Love2D Community <love2d.org>\n\nPermission is hereby granted, free of charge, "
  },
  {
    "path": "Internal/Core/FileSystem.lua",
    "chars": 15048,
    "preview": "--[[\n\nMIT License\n\nCopyright (c) 2019-2021 Love2D Community <love2d.org>\n\nPermission is hereby granted, free of charge, "
  },
  {
    "path": "Internal/Core/IdCache.lua",
    "chars": 1517,
    "preview": "--[[\n\nMIT License\n\nCopyright (c) 2019-2021 Love2D Community <love2d.org>\n\nPermission is hereby granted, free of charge, "
  },
  {
    "path": "Internal/Core/Messages.lua",
    "chars": 2214,
    "preview": "--[[\n\nMIT License\n\nCopyright (c) 2019-2021 Love2D Community <love2d.org>\n\nPermission is hereby granted, free of charge, "
  },
  {
    "path": "Internal/Core/Scale.lua",
    "chars": 1630,
    "preview": "\n--[[\n\nMIT License\n\nCopyright (c) 2019-2021 Love2D Community <love2d.org>\n\nPermission is hereby granted, free of charge,"
  },
  {
    "path": "Internal/Core/Stats.lua",
    "chars": 4865,
    "preview": "--[[\n\nMIT License\n\nCopyright (c) 2019-2021 Love2D Community <love2d.org>\n\nPermission is hereby granted, free of charge, "
  },
  {
    "path": "Internal/Core/TablePool.lua",
    "chars": 1616,
    "preview": "--[[\n\nMIT License\n\nCopyright (c) 2019-2021 Love2D Community <love2d.org>\n\nPermission is hereby granted, free of charge, "
  },
  {
    "path": "Internal/Core/Utility.lua",
    "chars": 3709,
    "preview": "--[[\n\nMIT License\n\nCopyright (c) 2019-2021 Love2D Community <love2d.org>\n\nPermission is hereby granted, free of charge, "
  },
  {
    "path": "Internal/Input/Common.lua",
    "chars": 1196,
    "preview": "--[[\n\nMIT License\n\nCopyright (c) 2019-2021 Love2D Community <love2d.org>\n\nPermission is hereby granted, free of charge, "
  },
  {
    "path": "Internal/Input/Keyboard.lua",
    "chars": 3570,
    "preview": "--[[\n\nMIT License\n\nCopyright (c) 2019-2021 Love2D Community <love2d.org>\n\nPermission is hereby granted, free of charge, "
  },
  {
    "path": "Internal/Input/Mouse.lua",
    "chars": 8042,
    "preview": "--[[\n\nMIT License\n\nCopyright (c) 2019-2021 Love2D Community <love2d.org>\n\nPermission is hereby granted, free of charge, "
  },
  {
    "path": "Internal/Resources/Styles/Dark.style",
    "chars": 1506,
    "preview": "FontSize = 14\nMenuColor = (0.2, 0.2, 0.2, 1.0)\nScrollBarColor = (0.4, 0.4, 0.4, 1.0)\nScrollBarHoveredColor = (0.8, 0.8, "
  },
  {
    "path": "Internal/Resources/Styles/Light.style",
    "chars": 1540,
    "preview": "FontSize = 14\nMenuColor = (0.74, 0.74, 0.94, 1.0)\nScrollBarColor = (0.4, 0.62, 0.80, 0.3)\nScrollBarHoveredColor = (0.28,"
  },
  {
    "path": "Internal/UI/Button.lua",
    "chars": 6977,
    "preview": "--[[\n\nMIT License\n\nCopyright (c) 2019-2021 Love2D Community <love2d.org>\n\nPermission is hereby granted, free of charge, "
  },
  {
    "path": "Internal/UI/CheckBox.lua",
    "chars": 3640,
    "preview": "--[[\n\nMIT License\n\nCopyright (c) 2019-2021 Love2D Community <love2d.org>\n\nPermission is hereby granted, free of charge, "
  },
  {
    "path": "Internal/UI/ColorPicker.lua",
    "chars": 12146,
    "preview": "--[[\n\nMIT License\n\nCopyright (c) 2019-2021 Love2D Community <love2d.org>\n\nPermission is hereby granted, free of charge, "
  },
  {
    "path": "Internal/UI/ComboBox.lua",
    "chars": 5909,
    "preview": "--[[\n\nMIT License\n\nCopyright (c) 2019-2021 Love2D Community <love2d.org>\n\nPermission is hereby granted, free of charge, "
  },
  {
    "path": "Internal/UI/Dialog.lua",
    "chars": 20423,
    "preview": "--[[\n\nMIT License\n\nCopyright (c) 2019-2021 Love2D Community <love2d.org>\n\nPermission is hereby granted, free of charge, "
  },
  {
    "path": "Internal/UI/Dock.lua",
    "chars": 8629,
    "preview": "--[[\n\nMIT License\n\nCopyright (c) 2019-2021 Love2D Community <love2d.org>\n\nPermission is hereby granted, free of charge, "
  },
  {
    "path": "Internal/UI/Image.lua",
    "chars": 5190,
    "preview": "--[[\n\nMIT License\n\nCopyright (c) 2019-2021 Love2D Community <love2d.org>\n\nPermission is hereby granted, free of charge, "
  },
  {
    "path": "Internal/UI/Input.lua",
    "chars": 44385,
    "preview": "--[[\n\nMIT License\n\nCopyright (c) 2019-2021 Love2D Community <love2d.org>\n\nPermission is hereby granted, free of charge, "
  },
  {
    "path": "Internal/UI/LayoutManager.lua",
    "chars": 14007,
    "preview": "--[[\n\nMIT License\n\nCopyright (c) 2019-2021 Love2D Community <love2d.org>\n\nPermission is hereby granted, free of charge, "
  },
  {
    "path": "Internal/UI/ListBox.lua",
    "chars": 6369,
    "preview": "--[[\n\nMIT License\n\nCopyright (c) 2019-2021 Love2D Community <love2d.org>\n\nPermission is hereby granted, free of charge, "
  },
  {
    "path": "Internal/UI/Menu.lua",
    "chars": 9301,
    "preview": "--[[\n\nMIT License\n\nCopyright (c) 2019-2021 Love2D Community <love2d.org>\n\nPermission is hereby granted, free of charge, "
  },
  {
    "path": "Internal/UI/MenuBar.lua",
    "chars": 2627,
    "preview": "--[[\n\nMIT License\n\nCopyright (c) 2019-2021 Love2D Community <love2d.org>\n\nPermission is hereby granted, free of charge, "
  },
  {
    "path": "Internal/UI/MenuState.lua",
    "chars": 1224,
    "preview": "--[[\n\nMIT License\n\nCopyright (c) 2019-2021 Love2D Community <love2d.org>\n\nPermission is hereby granted, free of charge, "
  },
  {
    "path": "Internal/UI/Region.lua",
    "chars": 16224,
    "preview": "--[[\n\nMIT License\n\nCopyright (c) 2019-2021 Love2D Community <love2d.org>\n\nPermission is hereby granted, free of charge, "
  },
  {
    "path": "Internal/UI/Separator.lua",
    "chars": 2227,
    "preview": "--[[\n\nMIT License\n\nCopyright (c) 2019-2021 Love2D Community <love2d.org>\n\nPermission is hereby granted, free of charge, "
  },
  {
    "path": "Internal/UI/Shape.lua",
    "chars": 7927,
    "preview": "--[[\n\nMIT License\n\nCopyright (c) 2019-2021 Love2D Community <love2d.org>\n\nPermission is hereby granted, free of charge, "
  },
  {
    "path": "Internal/UI/Text.lua",
    "chars": 6660,
    "preview": "--[[\n\nMIT License\n\nCopyright (c) 2019-2021 Love2D Community <love2d.org>\n\nPermission is hereby granted, free of charge, "
  },
  {
    "path": "Internal/UI/Tooltip.lua",
    "chars": 3520,
    "preview": "--[[\n\nMIT License\n\nCopyright (c) 2019-2021 Love2D Community <love2d.org>\n\nPermission is hereby granted, free of charge, "
  },
  {
    "path": "Internal/UI/Tree.lua",
    "chars": 8345,
    "preview": "--[[\n\nMIT License\n\nCopyright (c) 2019-2021 Love2D Community <love2d.org>\n\nPermission is hereby granted, free of charge, "
  },
  {
    "path": "Internal/UI/Window.lua",
    "chars": 34429,
    "preview": "--[[\n\nMIT License\n\nCopyright (c) 2019-2021 Love2D Community <love2d.org>\n\nPermission is hereby granted, free of charge, "
  },
  {
    "path": "LICENSE",
    "chars": 1091,
    "preview": "MIT License\n\nCopyright (c) 2019-2021 Love2D Community <love2d.org>\n\nPermission is hereby granted, free of charge, to any"
  },
  {
    "path": "README.md",
    "chars": 2276,
    "preview": "![](https://github.com/flamendless/Slab/blob/master/assets/slab.png)\n\n# Slab\n\nSlab is an immediate mode GUI toolkit for "
  },
  {
    "path": "Slab.lua",
    "chars": 1403,
    "preview": "--[[\n\nMIT License\n\nCopyright (c) 2019-2021 Love2D Community <love2d.org>\n\nPermission is hereby granted, free of charge, "
  },
  {
    "path": "SlabDebug.lua",
    "chars": 18134,
    "preview": "--[[\n\nMIT License\n\nCopyright (c) 2019-2021 Love2D Community <love2d.org>\n\nPermission is hereby granted, free of charge, "
  },
  {
    "path": "SlabDefinition.lua",
    "chars": 15979,
    "preview": "---@meta\n\n---@class Slab\nlocal Slab = {}\n\n\n---@class Slab.BeginWindowOptions\n---@field X? number\n---@field Y? number\n---"
  },
  {
    "path": "SlabTest.lua",
    "chars": 85066,
    "preview": "--[[\n\nMIT License\n\nCopyright (c) 2019-2021 Love2D Community <love2d.org>\n\nPermission is hereby granted, free of charge, "
  },
  {
    "path": "Style.lua",
    "chars": 6045,
    "preview": "--[[\n\nMIT License\n\nCopyright (c) 2019-2021 Love2D Community <love2d.org>\n\nPermission is hereby granted, free of charge, "
  },
  {
    "path": "changelog.txt",
    "chars": 4792,
    "preview": "v0.9.0\n==========\n[Stats] Added GetStats and CalculateStats. See fixed #91 (@flamendless)\n[Window]: Added minimize/maxim"
  },
  {
    "path": "conf.lua",
    "chars": 1218,
    "preview": "--[[\n\nMIT License\n\nCopyright (c) 2019-2021 Love2D Community <love2d.org>\n\nPermission is hereby granted, free of charge, "
  },
  {
    "path": "init.lua",
    "chars": 1255,
    "preview": "--[[\n\nMIT License\n\nCopyright (c) 2019-2021 Love2D Community <love2d.org>\n\nPermission is hereby granted, free of charge, "
  },
  {
    "path": "main.lua",
    "chars": 2535,
    "preview": "--[[\n\nMIT License\n\nCopyright (c) 2019-2021 Love2D Community <love2d.org>\n\nPermission is hereby granted, free of charge, "
  }
]

About this extraction

This page contains the full source code of the coding-jackalope/Slab GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 49 files (507.7 KB), approximately 143.1k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!