Git Product home page Git Product logo

slab's Introduction

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.

Usage

Integrating this library into existing projects is very simple.

local Slab = require 'Slab'

function love.load(args)
	love.graphics.setBackgroundColor(0.4, 0.88, 1.0)
	Slab.Initialize(args)
end

function love.update(dt)
	Slab.Update(dt)
  
	Slab.BeginWindow('MyFirstWindow', {Title = "My First Window"})
	Slab.Text("Hello World")
	Slab.EndWindow()
end

function love.draw()
	Slab.Draw()
end

For more detailed information on usage of this library, refer to the Wiki.

LOVE forum

License

Slab is licensed under the MIT license. Please see the LICENSE file for more information.

Credits

  • coding-jackalope original developer of this library.
  • Dear ImGui project built by Omar Cornut and various contributors. This project was the inspiration for building an Immediate Mode GUI for Love2D specifically. If anyone is building a game or application in C++, I highly recommend using this library and its rich toolset to speed up development.
  • Kenney.nl and the Tango Desktop Project for providing icons used in this project.
  • lovefs provides some FFI code for the filesystem.
  • luapower/fs provides cross platform FFI code for the filesystem.

slab's People

Contributors

akkartik avatar antoniotorresm avatar avril112113 avatar coding-jackalope avatar elemel avatar flamendless avatar giovifav avatar idbrii avatar lainez avatar matthew-allen avatar megagrump avatar mellowarpeggiation avatar miszczu2137 avatar nikaoto avatar pakeke-constructor avatar pirogronian avatar sdleffler avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

slab's Issues

Deinitialize Slab

Hi, in cases where there are multiple Slab initialized/used (i.e when switching from one state to another), Slab hangs the system upon exit.

I am still unsure of how this weird behavior happens as my project is very complex. I think that when multiple files/states uses Slab causes the issue (though they are not processed at the same time).

CheckBox's option - disable flag

Hi, it would be useful to have checkbox's api for the option to have a flag for disable, this would allow to render the checkbox but will not be clickable/toggleable regardless of the state.

An example would be:

local cb = true

if Slab.CheckBox(cb, "checkbox", { disabled = true}) then
  print("i can't be toggled!")
end

Request for Sliders Input

Hi, first of all, amazing library! It really is like coding using DearImGUI! Awesome. Keep up the good work :)

Aside from the clear title, is there any work/progress for sliders?

REQUEST: Window Close Button

Similar to most window designs, a close button in either the left or right side of the window title bar. I believe DearImGui has this as well.

`FileSystem.Exists(...)` returns wrong result on Windows

This is tested with the main.lua in this repo. At the "Dialog" section of the test window, click "Open File" opening a file selection window, then try to open any file:
slab
Any file is not able to be opened via either double-click or the "OK" button.

I made some test prints on local:

-- FileSystem.lua:219
function FileSystem.Exists(Path)
	print(Path) --debug
	local Handle = io.open(Path)
	if Handle ~= nil then
		print(Handle~=nil) --debug
		io.close(Handle)
		return true
	else

No output when I used double-click (perhaps it is not a bug, just me feeling a bit confused double-clicking can open folders but not files), and
here is the output when I used the "OK" button:

z:/ParentNameParentNameParentNameParentName/TestFolder/Folder1/File1.txt/
true
z:/ParentNameParentNameParentNameParentName/TestFolder/Folder1/File2/
true
z:/ParentNameParentNameParentNameParentName/TestFolder/Folder2/File3.extrasuffix.txt/
true
z:/ParentNameParentNameParentNameParentName/TestFolder/File4/
true

Since FileSystem.IsDirectory(...) directly depends on FileSystem.Exists(...), I suppose this should be the reason.

This happens on my Windows 10. Then I copied all the code to my Android phone, and it seemed that files can be opened as expected there.

Scroll Speed

What was the rationale behind the choice of Region scroll speed?
It feels slow, I modified it for my usecase but saw someone who foked and did the same on their side.

InputNumberSlider ignores Options.Step and has undocumented rounding behaviour

Nice work with the slider! It's awesome that you can double-click to edit the value. However, I find the way InputNumberSlider vs InputNumberDrag work a bit confusing. I'd expect the difference is just the visible slider, it looks like the drag behaviour is also different, but also they have different rounding behaviour.

InputNumberDrag takes a Step value which allows the user to determine if the output is an float.

InputNumberSlider takes no Step value and seems to use maximum precision. To make the result an float, you need to pass a float as either MinNumber or MaxNumber (which seems elegant, but I rarely pass floats as limits).

For me, a common value to adjust is in [0,1]. To use InputNumberSlider, I have to limit my choices so either 0 or 1 is not a valid value or allow going outside of my desired range. I find the slider handle to be a useful visual for where the current value is within the range. If I use InputNumberDrag, then I lose this visualization.

The documentation for GetInputNumber() doesn't mention the rounding behaviour. Even if it did, it would be confusing like this:

If Options.DrawSlider is true or InputNumberSlider was used and both Options.MinNumber and Options.MaxNumber were integers, the result is an integer.

the InputNumberSlider documentation implies that Step would be valid since it's an option for Slab.Input.

Options: [Table] List of options for how this input control is displayed. See Slab.Input for all options.

So maybe it's a bug that Step is not used by InputNumberSlider?

Bug: Slab fails to load styles when it's not in the top level of a love2d project

I modify my path in conf.lua to allow me to split my code into two
folders: src/ and src/lib/

love.filesystem.setRequirePath("src/?.lua;src/?/init.lua;src/lib/?.lua;src/lib/?/init.lua")

This allows me to import modules from either folder without any
prefixes:

local Slab = require 'Slab'

This doesn't work with Slab. Even excluding lib from require path (so it
must be specified in includes) doesn't work with Slab.

Investigation

Slab sets its path using the require path:

SLAB_PATH = ...

But styles use this as if it were a filesystem path (that ignores lua's
require path):

  local StylePath = "/Internal/Resources/Styles/"
  local Path = SLAB_PATH .. StylePath
  Path = string.gsub(Path, "%.", "/")
  -- Use love's filesystem functions to support both packaged and unpackaged builds
  local Items = love.filesystem.getDirectoryItems(Path)

Styles fail to load and every execution outputs this error:

  Style 'Dark' is not loaded.

So far, nothing looks wrong, but it does mean I can't use styles.

Two solutions I can see is for styles to search for the style folder using
love.filesystem.getRequirePath or be lua files that can use require(). My preference is the latter (removes style parser implementation, familiar data format), but I'd assume it's more work (style editor).

Repro example in my repro-style-load-path branch. I moved Slab's files around to replicate a real project. See how I moved things around in idbrii/love-slab@cc89b7e.

Closing a Window via the close button does not unset the hot region

When closing a window via the close button, if BeginWindow is not later called with IsOpen = false (going from BeginWindow(... { ... IsOpen = true ... }) to not calling BeginWindow at all but still calling Slab.Update) then the Region.HotInstance variable remains set to the now closed window and does not get corrected until another Slab object is hovered over and then unhovered. This interferes badly with Slab.IsVoidHovered.

ListBox Items Selectable Through GUI

First off, I wanted to say thanks for the library! It's been great to work with, and was exactly what I was looking for to start on my Animation tool project.

The attached gif shows an issue I noticed, where a list box item that was offscreen would be selected if I attempted to select a different UI element that was being drawn over that list box item

listbox

I noticed that there is "Slab.IsControlHovered()", and I was able to use that to determine if the list box item should be selected. I was wondering if that was the expected way to get around this issue, or if there were any plans to fix this inside the library.

Thanks in advanced for your reply!

[WIKI] Use Slab.GetInputNumber for numbers

Hi, i've noticed that in the wiki, under the "getting numbers", it uses tonumber(Slab.GetInputText()):

if Slab.Input('MyInput', {Text = tostring(Value), ReturnOnText = false, NumbersOnly = true}) then
	Value = tonumber(Slab.GetInputText())
end

I suggest to use the API Slab.GetInputText() to save call so as not to use tonumber anymore since it is explicitly stated to get numbers only with the config NumbersOnly = true

example crash

Error: /Internal/Core/DrawCommands.lua:526: Cannot set scissor with negative width.
stack traceback:
[string "boot.lua"]:777: in function <[string "boot.lua"]:773>
[C]: in function 'assert'
/Internal/Core/DrawCommands.lua:526: in function 'Scissor'
/Internal/UI/Region.lua:468: in function 'ApplyScissor'
/Internal/UI/Region.lua:345: in function 'Begin'
/Internal/UI/Window.lua:639: in function 'BeginWindow'
SlabTest.lua:1872: in function SlabTest.lua:1678
SlabTest.lua:2375: in function 'Begin'
main.lua:37: in function 'update'
[string "boot.lua"]:612: in function <[string "boot.lua"]:594>
[C]: in function 'xpcall'

[Enhancment] Support holding backspace

WOOPS: I changed this issue because I realised the original one wasn't working because it was bugged which I have already reported #64.

Support holding backspace to keep removing charecters from the input
Also for the delete key (Though I have not checked if it works for the delete key already)

Support for mobile devices

This ui library looks very good! It would be awesome if you consider providing a mobile device backend to it, It seems to mess up the coordinates when I try to use it on my Android

File dialog tree: collapse parent folders

It seems like it's not possible to collapse parent folders on the file dialog tree view
Tested on windows 10

Fk2RhjuTWt

@coding-jackalope if you don't know what could cause this I can look into it in the coming days and send a PR, as I need to fix it for my app :)

Multiline Input paste with newline charecters

Pasting text with a multiple lines seems to do some strange things, it is rather difficult to explain.

Steps to reproduce:

  1. Have text spanning 2+ lines in the clipboard
  2. Paste that text in a multiline input box

You will notice visually duplicated letters (that do not exist) and strange cursor position due to that

The issue seems to be related with the newline charecter \n

image
Note in the image, I can not move cursor any more right. There also is no 5th line.

Multiline tooltips

If i tried make multiline tooltip witn \n character it is not displayed correctly
Bug
Code:
slab.Button("GC", {Tooltip = "Performs a garbage collection:\nLua uses a garbage collector that runs from time to time to collect dead objects when they are no longer accessible from the Lua program."})

Multiple Input does not work

Hi, im doing something like this

	Slab.BeginWindow("Bump3DCollision", {Title = "Bump3DCollision"})
	local items, len = self.bump3d_world:getItems()
	for i = 1, len do
		local e = items[i]
		Slab.Text(e.bump3d.id)
		Slab.Indent()

		local x = e.collider3d.size.x
		local y = e.collider3d.size.y
		local z = e.collider3d.size.z

		Slab.Text("x: ")
		Slab.SameLine()
		if Slab.Input("input_x", {Text = tostring(x), ReturnOnText = false, NumbersOnly = true}) then
			x = tonumber(Slab.GetInputText())
		end

		Slab.Text("y: ")
		Slab.SameLine()
		if Slab.Input("input_y", {Text = tostring(y), ReturnOnText = false, NumbersOnly = true}) then
			y = tonumber(Slab.GetInputText())
		end

		Slab.Text("z: ")
		Slab.SameLine()
		if Slab.Input("input_z", {Text = tostring(z), ReturnOnText = false, NumbersOnly = true}) then
			z = tonumber(Slab.GetInputText())
		end

		Slab.Unindent()
	end
	Slab.EndWindow()

it properly shows but i cant click and change any value in the Slab.Input

Input request type message dialog

Hi,

Slab is a wonderful lib that I really enjoy working with.

I've created my own Input request message dialog, like a simple Text that ask for a value and a simple text Input.

But there is a small flaw in the Input object. In this case I ask to get the focus in my Input using : Slab.SetInputFocus(Id)

And this is working but here it comes : because it is a dialog I want that the value in the Input is always clear at opening. So I use the Text option. and I make sure that the var used is empty :

if (Slab.Input("ProjectName", { Text = self.newProjectName, W = 250 })) then self.newProjectName = Slab.GetInputText() end

So for sure self.newProjectName is == "" when I enter my dialog. But because I give the focus to the object Slab is not able to clear the Input (I found the line in the Input.lua file of Slab :

if Focused ~= Instance then if Options.MultiLine and #Options.Text ~= #Instance.Text then Instance.Lines = nil end Instance.Text = Options.Text == nil and Instance.Text or Options.Text end

(Around line 955) (edit : So sorry for the code block can't get it working :( )

it put me on the tracks of the focus problem.

So my solution for now is to wait for the user to press "tab" to give the focus to the input field.

Am I missing something ? Should I change the way I give the focus ?

Thanks for help and thanks for this amazing library.

Scrolling permanently breaks any intereaction

Slab stops reacting to any kind of mouse interaction and [almost any] keyboard interaction if you scroll your mousewheel in certain areas.

Scrolling while hovering over combo boxes, input fields and window titles triggers this reliably for me.

Window undock bad alignment on mouse coords

Slab version 0.7.1
LOVE version 11.3.0
OS: Windows 10

Its happend only sometimes. Reproducted this issue on fullscreen too as well as from left and right dock.

Including gif:
bug

`BeginMenu` and `ContextMenuWindow` missing top rounded corners

Just a note; I am still figuring out Slab, if I am missing something, my bad...

image
image

The tops of the context menu's are missing rounded corners.
For the MainMenuBar it makes sense to not have rounded corners.

It does make sense to have no rounded corners in this case though
image

Code (First Image)

if Slab.BeginContextMenuWindow() then
	Slab.MenuItem("BLANK")

	if Slab.BeginMenu("Create") then
		if Slab.MenuItem("Lamp") then
			print("Create Lamp")
		end

		if Slab.MenuItem("Button") then
			print("Create Lamp")
		end

		Slab.EndMenu()
	end

	Slab.EndContextMenu()
end

Crash when change indent on style editor

Error

/SlabDebug.lua:284: table index is nil

Traceback

/SlabDebug.lua:284: in function 'DrawStyleEditor'
/SlabDebug.lua:464: in function 'StyleEditor'
/SlabDebug.lua:615: in function 'Begin'
SlabTest.lua:2118: in function 'Begin'
main.lua:37: in function 'update'
[C]: in function 'xpcall'

system:
ubuntu 18.04 - love 11.3

Window Close Behaviour

Really awesome for the close button feature! Thanks!

I strongly recommend to add an example of how to properly use the IsOpen (close button) for the Window API in the wiki.

First I've tried this

local test = true
--in update
if test then
  Slab.BeginWindow("Test", {Title = "Test", IsOpen = test})
  Slab.EndWindow()
end

which shows properly the close open, but clicking it still shows the window, and printing the value of test results to always being true. Now the reason for this is simple, because if we pass a value like boolean in a function, the value is passed as a copy instead of a reference.

Second, I've tried passing a table so as an alternative to Lua pass by reference

local test = {Title = "Test", IsOpen = true}
--in update
if test then
  Slab.BeginWindow("Test", test)
  Slab.EndWindow()
end

This works, but somehow counter intuitive for me having to define the options table outside.

Perhaps, just like in the love-bindings for DearImGui, the BeginWindow returns a boolean value.

The usage would be

local test = true
--in update
if test then
  test = Slab.BeginWindow("Test, {Title = "Test", IsOpen = test})
  Slab.EndWindow()
end

Save dialog does not work on Linux

If i tried save file in any directory i got this error:

Error: lib/slab/Internal/Core/FileSystem.lua:277: /usr/lib/x86_64-linux-gnu/libluajit-5.1.so.2: undefined symbol: stat64
stack traceback:
	[string "boot.lua"]:777: in function <[string "boot.lua"]:773>
	[C]: in function '__index'
	lib/slab/Internal/Core/FileSystem.lua:277: in function 'IsDirectory'
	lib/slab/Internal/UI/Dialog.lua:564: in function 'FileDialog'
	main.lua:216: in function 'update'
	[string "boot.lua"]:612: in function <[string "boot.lua"]:594>
	[C]: in function 'xpcall'

Slab master branch
save dialog code:

    local result = slab.FileDialog({Type = "savefile"})

    if result.Button == "OK" then
      windows.saveDialog = false
      savepath = result.Files[1]
    end

    if result.Button == "Cancel" then
      windows.saveDialog = false
    end

Shader Support

What do you think abount having a Draw Shader command?

I enabled them for my own app by doing something like this:

local function DrawShader(Opts)
    local StatHandle = Stats.Begin("DrawShader", StatsCategory)

    if Opts.Fragment ~= nil then
        local shader = love.graphics.newShader(Opts.Fragment)
        for k, v in pairs(Opts.Values) do
            shader:send(k, v)
        end
        love.graphics.setShader(shader)
    else
        love.graphics.setShader()
    end

    Stats.End(StatHandle)
end

This is my first time using Lua/Love2D, and also using an ImGUI so I don't really know if this is an anti pattern. Could you give me some feedback?

On top of my head I'm guessing that the shader should only be created once and reused/disposed

When i try to run the style editor or making a multiline input, a error pops out

When i try to run the style editor or making a multiline input, a error pops out

Error
/Internal/UI/Input.lua:178: attempt to get length of field 'Text' (a number value)


Traceback

/Internal/UI/Input.lua:178: in function 'ValidateNumber'
/Internal/UI/Input.lua:998: in function 'Input'
/SlabDebug.lua:200: in function 'DrawStyleValue'
/SlabDebug.lua:250: in function 'DrawStyleEditor'
/SlabDebug.lua:425: in function 'StyleEditor'
/SlabDebug.lua:582: in function 'Begin'
SlabTest.lua:288: in function 'Begin'
main.lua:37: in function 'update'
[C]: in function 'xpcall'

Multiple examples

I would suggest creating an examples folder with multiple examples, especially for different layout permutations as it gets harder to achieve the desired results (like nested controls inside a layout) without a proper example on how to do it!

Different sized columns are also hard to figure out!

Interoperate with Ulydev/push (mouse position override)

Slab looks really great!

Would be nice to work with Ulydev/push or other libraries that mess with resolution. Push lets you assume one resolution and it scales the game to fit the window. It provides a conversion method from screen pixel coordinates to game coordinates (so if your game is 320x240, you'll never get y outside [0,240]).

I can hack it to work by changing this line:

https://github.com/coding-jackalope/Slab/blob/48e027193b43d730933447b6e6b7e97f2d2c47ce/Internal/Input/Mouse.lua#L58

to:

local push = require('push')
State.X, State.Y = push:toGame(love.mouse.getPosition())
-- Push returns nil if outside game screen
State.X = State.X or LastX
State.Y = State.Y or LastY

Or I can clobber love.mouse.getPosition:

local last_mouse = {
    x = 0,
    y = 0,
}
function love.load()
    local vanilla_mouse_position_fn = love.mouse.getPosition
    love.mouse.getPosition = function()
        local x,y = require('push'):toGame(vanilla_mouse_position_fn())
        -- Track last position within game screen to mimic behaviour of love
        -- window.
        x = x or last_mouse.x
        y = y or last_mouse.y
        last_mouse.x = x
        last_mouse.y = y
        return x,y
    end
end

But that makes it more difficult to take advantage of push's "outside game screen but inside love window" detection when your game is letterboxed/pillarboxed.

I'm not sure how you'd communicate the latter either since it's not an API call. A wiki page?

How would you prefer to handle interop with libraries?

Image - allow passing of quad and image and more

Hi, it would be useful to allow something like:

Slab.Image("Animation", {
  Title = "Animation",
  Image = spritesheet,
  Quad = quad
})

As an alternative to Sub(x,y,w,h)


Also, for clarification, does the Sub variant in Image does the same as quad or it's for controlling how the image is drawn in the widget?

I've noticed that using the Scale with Sub variants makes the image overflow in the widget without the widget size and succeeding elements adjust properly.

ScrollBar not appearing

Consider this snippet:

local Slab = require 'Slab'
local SlabTest = require 'SlabTest'

local list = {}
for i = 1, 50 do
	local t = { id = tostring(i) }
	table.insert(list, t)
end

function love.load(args)
	love.graphics.setBackgroundColor(0.4, 0.88, 1.0)
	Slab.Initialize(args)
end

function love.update(dt)
	Slab.Update(dt)
	SlabTest.Begin()

	Slab.BeginWindow("test", {Title = "test"})
	for i, v in ipairs(list) do
		Slab.Text(v.id)
		Slab.SameLine()
		if Slab.Button("x") then
			print(i)
		end
	end
	Slab.EndWindow()
end

function love.draw()
	Slab.Draw()
end

This makes a window that is very long but no vertical scrollbar appears.

Error on opening file via FileDialog

When opening selected file via FileDialog, I got

Error: thirdparty/Slab/Internal/Core/FileSystem.lua:277: /usr/lib/libluajit-5.1.so.2: undefined symbol: stat64
stack traceback:
[string "boot.lua"]:777: in function <[string "boot.lua"]:773>
[C]: in function '__index'
thirdparty/Slab/Internal/Core/FileSystem.lua:277: in function 'IsDirectory'
thirdparty/Slab/Internal/UI/Dialog.lua:564: in function 'FileDialog'
main.lua:87: in function 'AddFilepathDialog'
main.lua:57: in function 'update'
[string "boot.lua"]:612: in function <[string "boot.lua"]:594>
[C]: in function 'xpcall'

I invoked FileDialog these way:

local result = Slab.FileDialog({ Type = "openfile" })

My system: ArchLinux, updated yesterday.

What's interesting (and confusing) yesterday it worked fine. The only difference was update Slab in my project from version of ~21.07.2020 but I cannot find in commit logs any substantial changes, that could do that.
Maybe using FFI on Linux is not so good idea?

Edit:
To work on with my project, I forked Slab and do a workaround using love api:
pirogronian@9ecb1c8

Release v0.7.1 breaks LOVE key events

Hi, just pulled the latest release and this is now not working for some reason:

local Slab = require 'Slab'
local SlabTest = require 'SlabTest'

function love.load(args)
	love.graphics.setBackgroundColor(0.4, 0.88, 1.0)
	Slab.Initialize(args)
end

function love.update(dt)
	Slab.Update(dt)
	SlabTest.Begin()
end

function love.draw()
	Slab.Draw()
end

function love.keypressed(key)
	print(key) --DOES NOTHING
end

function love.mousepressed(mx, my, mb)
	print(mx, my, mb) --STILL PRINTS
end

[FEATURE REQUEST] Indentation

Sample use-case

Slab.Text("Position:")
Slab.Indent() --this is to indent succeeding 'text' (or event other element) calls
Slab.Text("x: " .. 0) 
Slab.Text("y: " .. 0)
Slab.Unindent() --the closing of Indent

Slab.Text("Position 2:")
Slab.Indent()
Slab.Text("x: " .. 1) 
Slab.Text("y: " .. 1)

to display:

Position:
    x: 0
    y: 0
Position 2:
    x: 1
    y: 1

Feature request: "Up to" button in file dialogs

It would be cool if File Dialogs will have this button - sometimes happens when you accidentally pick wrong folder and want to go back. But it cannot done in proper way. You need reopen file dialog again and complete full folder path again

Save dialog in windows

Pass options to Initialize - disable all docks

Looking at the source code, Slab.Initialize accepts args table as parameter but it does not do anything with it.

I suggest passing something like Slab.Initialize({Docks = false}) that will disable all docks for all windows.

Windows do not notice when mouse is released after they are closed

Hi! I have two windows, call them window A and window B. Window A contains a button which opens up window B. Window B is closable, so it has that nice lil X in the top right that you can click to make it buzz off. So, what's happening here is that I open window B from window A's button; then, I close window B. At this point, it appears that window B still thinks it is being dragged around; when I re-open window B using my button on window A, then whenever the cursor isn't hovering over window A, window B thinks it's getting dragged around. This causes some odd behavior. I think all that's needed to fix this is to set Instance.IsMoving = False on close; I'll test that shortly.

Feature request: "cleanup"/garbage collection/instance deletion

Hiya! I'm writing out some code and noticed something a little funky. I wanted to procedurally generate entries in a Slab tree. What I'm doing is writing out a level editor for an ECS-based game; so, I want a big ol' tree showing the hierarchy of entities and what components they have and what properties those components have and so on. But, when I have a few hundred entities and they're spawning in and despawning all the time, I don't have a fixed set of IDs to use for Slab objects. So, I generate IDs from the indices of these entities in the world object. This means every entity gets an ID in [1, #world.entities], and then I use "entity@" .. i to generate a Slab id and also a label for the tree node. Then, I do a similar thing for every component in that entity, to create child tree nodes; and then leaf nodes as children of each component node.

The issue with this is that when an entity is destroyed, I no longer need all the data associated with it which is kept around by Slab. If I create thousands and thousands of entities and then destroy them, I end up with thousands and thousands of entries in Slab's Instances tables which I don't need, and Slab's Instance tables are live for the lifetime of my program, not for the lifetime of my editor scene. So, really, what I get is a memory leak.

I have a few suggestions on ways this could be fixed. They range from simple to a possibly invasive redesign of how Slab handles Ids.

The first and simplest would be a "DeleteXxxx" function for a given Slab widget/object (DeleteWindow, DeleteInput, DeleteButton, etc.) which just nils out the given entry. A quick browse through Slab's source suggests this should work fine... but I've been using and looking at Slab's source for a little over a day, so grain of salt, etc. Among the obvious consequence of deleting a Slab instance, there is also the issue that this would cause the instance to not be saved in Slab.ini, but as long as that's documented I don't see a problem.

The second way would be to have an option for Slab to go through and track widgets which haven't been updated/drawn recently, and remove them from their corresponding Instances table. This could get a bit expensive... And would also interfere with Slab's state-saving feature. Actually, everything about this feature interferes with Slab's state-saving, so if implemented it needs to be optional no matter what, I suppose.

The third and most interesting/convenient/user-friendly way, and the one that entertains and interests me the most, would be to allow non-string IDs, and make all Instances tables have a metatable with __mode = "k". This could be done with local Instances = setmetatable({}, { __mode = "k" }), as the __mode metatable entry must be set before the metatable is assigned. What this does is make the Instances table have "weak keys". This has the major consequence that if an ID is no longer "strongly" referenced anywhere in a Lua program, then its entry in the Instances table will be removed from the table. I like this solution for a handful of reasons:

  • It shouldn't require much modification; I know string keys are constructed by concatenation in a few places, but for the most part I think it should be possible to lift the IDs-must-be-strings restriction without a lot of work.
  • Whether or not something has its state saved in Slab.ini can be determined by whether or not its key is a string. Instances made with non-string IDs can just not be saved, which make Slab.ini smaller for programs like mine.
  • In my particular use case, I can do something like use my entity's table itself as a Slab ID, and when the entity no longer exists, the corresponding Slab object will also be garbage collected, and without Slab having to do anything itself as the Lua/LuaJIT GC handles it all.
  • If all IDs are strings, setting __mode = "k" will do nothing at all because strings will never be garbage collected (see Programming in Lua Ch. 17).

I'm very interested in the third option, so even if it doesn't seem like a good solution for Slab, I'm going to try adding it to my own little branch. :D

If anyone has time to give some feedback on these ideas, I would appreciate it a lot. This is my first time using an immediate mode GUI library and Slab is making my life a lot easier. :)

Input's drag functionality is too sensitive for small ranges

If I want an integer value in [0,10], then there are only 11 possible values. Instead of using the full width (or half width) of the slider to adjust through this range, InputNumberDrag accepts tiny movements to adjust. It only takes the width of one character to move through the entire input range.

Using InputNumberSlider is much better. Could InputNumberDrag work the same way (or maybe scaled to require less movement)?

Example (or run SlabTest and set these values):

local DrawInput_Basic_Numbers_Clamped_Options =
{
    Text = tostring(DrawInput_Basic_Numbers_Clamped),
    NumbersOnly = true,
    MinNumber = 0,
    MaxNumber = 10,
    Step = 1,
}
if Slab.Input('DrawInput_Basic_Numbers_Clamped', DrawInput_Basic_Numbers_Clamped_Options) then
    DrawInput_Basic_Numbers_Clamped = Slab.GetInputNumber()
end

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.