Iris - Immediate Mode UI library, based on Dear ImGui

Will there ever be docking support for Window widgets?

I know this will probably be a complicated feature to add but it would be amazing to dock a settings panel to the right while messing with settings. I know this is already possible by well moving the window and resizing it but still I think it could be a great addition.

You are able to just pass through the same state object to multiple widgets:

local state = Iris.State(true)

Iris.Window({ "Window A" })
    Iris.Checkbox({ "Checkbox A" }, { isChecked = state })
Iris.End()

Iris.Window({ "Window B" })
    Iris.Checkbox({ "Checkbox B" }, { isChecked = state })
Iris.End()

Not in the near future. I’ve had less time recently to devote to it, but as we get most of the widgets out and finished, I’m interested in pursuing this line.

Apologies for the late reply, for some reason I didn’t get a notification… Again.

Anyway, I know, but both Checkbox Widgets’ States are bound to their own separate State. I tried adding a new line under sort of like this:

local state = Iris.State(true)
local state2 = Iris.State(true)

Iris.Window({ "Window A" })
    local foo = Iris.Checkbox({ "Checkbox A" }, { isChecked = state })
    foo.state.isChecked:set(state2:get())
Iris.End()

Iris.Window({ "Window B" }) -- Settings Window
    local foo = Iris.Checkbox({ "Checkbox B" }, { isChecked = state2 })
    foo.state.isChecked:set(state:get())
Iris.End()

But obviously, like I mentioned before, Iris just broke.

change state:get() to state.value, worked for me. not in your case, but i mean, getting state’s value in general

1 Like

Thank you, I’m a bit busy at the moment, but I’ll try this when I get around to it and get back to you, cheers mate! :slight_smile:

Absolutely revolutionary plugin, testing out systems with weird edge cases has never been easier!

1 Like

I don’t quite understand your use case here. If you want two checkboxes to have the same state, then you can just use one. If they are going to be linked, then why do they each need their own state?

1 Like

It’s hard to explain, I’ll try and see if I can use one state linked to both, thank you.

i cannot seem to wrap my head around in what order widgets are added.
What i’m trying to do is have as many text widgets in each tree as there are trees.

for example when i press the button once there will be 1 tree with 1 text widget inside.
if i press it a second time there should be 2 trees with each tree having 2 text widgets inside and so on. However when i press it a third time the order seems to mess up and it gets worse the more i press it.

Code
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Iris = require(ReplicatedStorage.Iris).Init()

local trees = 0

Iris:Connect(function()
	
	Iris.Window({"Window"}, { size = Vector2.new(250, 300) })
	do
		if Iris.Button("Add tree").clicked() then
			trees += 1
		end

		for i = 1, trees do
			Iris.Tree("Tree_" .. i)
			do
				for i2 = 1, trees do
					Iris.Indent()
					do
						Iris.Text("Text_" .. i2)
					end
					Iris.End()
				end
			end
			Iris.End()
		end
	end
	Iris.End()
end)

expected behaviour when pressing the button twice:
image

however when i press it a third time it results in this
image

it should be
image

If anyone could tell me what i’m doing wrong i would really appreciate it.

this looks like a cool module
i haven’t tried it yet, but i’ll prob try it out

I wonder how he’d think if he looks back at this two years later. :thinking:

Outputting is quite inconvenient… and a rookie thing. I was a rookie that did not discover that Watch panels exists just to watch the variables real-time and see where things get messed up.

This could just make it easier to watch variables in-game on the Roblox client outside of Studio.

2 Likes

turns out i use Iris quite often, so this time i’ve decided to get into themes. i don’t really like the separation of colors to options, but i had to deal with it ig.

RobloxStudioBeta_8KNYJbX4Md

i’ve simplified the work anyway to generate the theme from 2 simple colors: background and accent. the colors i used are my… i’d say brand ones.

feel free to use the generator function, just credit me!

4 Likes

iris is generating an id depending on stack of the lines from traceback where’s action is made.
i’ve just found it easier to override it with the one i find more unique depending on a context.

Im not sure why but sometimes it doesnt let me select some items

Are you able to isolate an example of this, with code? Someone else has a simlar issue, but I can’t reproduce it on my end, so I don’t know what’s going wrong.

Heres my code

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Types             = require(ReplicatedStorage.Packages.Iris.Types)
local IrisCore          = require(ReplicatedStorage.Packages.Iris)

local Packet        = require(ReplicatedStorage.Packets.Main)
local UpdateWeather = Packet.UpdateWeather

local climateNames = { [0] = "None", [1] = "Rain", [2] = "Snow", [3] = "Blizzard" }

local skyboxFolder = ReplicatedStorage.Assets.Weather.Skyboxes
local skyboxList   = skyboxFolder:GetChildren()
table.sort(skyboxList, function(a,b) return a.Name < b.Name end)
local skyboxNames = {}
for i, sky in ipairs(skyboxList) do
	skyboxNames[i] = sky.Name
end

local irisStates = {}
local dirty      = {}

local function getOrInitState(key, initial)
	if not irisStates[key] then
		irisStates[key] = IrisCore.State(initial)
	end
	return irisStates[key]
end

local function buildUI(Iris, isOpenedState, weatherState)
	for k, v in pairs(weatherState) do
		if type(v) == "table" and v.R then
			getOrInitState(k, Color3.fromRGB(v.R, v.G, v.B))
		else
			getOrInitState(k, v)
		end
	end

	local window = Iris.Window({ [Iris.Args.Window.Title] = "Weather Debug" }, { isOpened = isOpenedState })
	if window.state.isOpened.value then

		local function slider(key, label, min, max, inc)
			min = min or 0
			max = max or 1
			inc = inc or 0.01
			local st  = getOrInitState(key, weatherState[key] or 0)
			local res = Iris.SliderNum({ label, inc, min, max }, { number = st })
			if res.numberChanged() then
				dirty[key] = true
			end
		end

		local function colorInput(key, label)
			local raw = weatherState[key] or { R = 255, G = 255, B = 255 }
			local st  = getOrInitState(key, Color3.fromRGB(raw.R, raw.G, raw.B))
			Iris.InputColor3({ label }, { color = st })
		end

		local function windSlider(sub, label, min, max, inc)
			local fullKey = "Wind_" .. sub
			local wind    = weatherState.Wind or {}
			local st      = getOrInitState(fullKey, wind[sub] or 0)
			local res     = Iris.SliderNum({ label, inc or 1, min, max }, { number = st })
			if res.numberChanged() then
				dirty[fullKey] = true
			end
		end

		Iris.CollapsingHeader({ "Environment" })
		local stC   = getOrInitState("Climate", weatherState.Climate or 0)
		local lbl   = climateNames[stC.value] or tostring(stC.value)
		local combo = Iris.Combo({ "Climate: " .. lbl }, { index = stC })
		for code, name in pairs(climateNames) do
			Iris.Selectable({ name, code }, { index = stC })
		end
		Iris.End()
		if combo.closed() then
			dirty["Climate"] = true
		end

		slider("CloudDensity", "Cloud Density", 0, 1, 0.01)
		slider("CloudCover",   "Cloud Cover",   0, 1, 0.01)
		colorInput("CloudColor", "Cloud Color")
		slider("FogDensity",   "Fog Density",   0, 1, 0.01)
		slider("Brightness",   "Brightness",    0, 10, 0.1)

		windSlider("S", "Wind Speed",      0, 200, 1)
		windSlider("Y", "Wind Yaw (deg)",  0, 360, 1)
		windSlider("P", "Wind Pitch (deg)", -90, 90, 1)
		Iris.End()
		
		Iris.CollapsingHeader({ "Time" })
		slider("ClockTime", "Clock Time", 0, 24, 1)
		slider("TimeSpeed", "Time Speed", 0, 10, 0.1)
		local stTF = getOrInitState("TimeFrozen", weatherState.TimeFrozen)
		local cb   = Iris.Checkbox({ "Time Frozen" }, { isChecked = stTF })
		if cb.checked() or cb.unchecked() then
			dirty["TimeFrozen"] = true
		end

		local stSB   = getOrInitState("Skybox", weatherState.Skybox)
		local lblSB  = skyboxNames[stSB.value] or tostring(stSB.value)
		local comboSB = Iris.Combo({ "Skybox: " .. lblSB }, { index = stSB })
		for idx, name in ipairs(skyboxNames) do
			Iris.Selectable({ name, idx }, { index = stSB })
		end
		Iris.End()
		if comboSB.closed() then
			dirty["Skybox"] = true
		end

		slider("CycleTime", "Cycle Time", 0, 3600, 10)
		Iris.End()

		Iris.CollapsingHeader({ "Ambient" })
		slider("Haze",               "Haze",            0, 1)
		colorInput("Ambient",        "Ambient Color")
		colorInput("OutdoorAmbient", "Outdoor Ambient")
		Iris.End()

		Iris.CollapsingHeader({ "Post-Processing" })
		slider("Depth",                     "Depth",                        0, 100, 0.1)
		slider("Focus",                     "Focus",                        0, 100, 1)
		slider("BlurSize",                  "Blur Size",                    0, 10, 0.1)
		slider("SunIntensity",              "Sun Intensity",                0, 2, 0.01)
		slider("SunSpread",                 "Sun Spread",                   0, 1, 0.01)
		slider("BloomIntensity",            "Bloom Intensity",              0, 2, 0.01)
		slider("ColorCorrectionBrightness", "Color Correction Brightness", -1, 1, 0.01)
		slider("Contrast",                  "Contrast",                    -1, 1, 0.01)
		slider("Saturation",                "Saturation",                  -1, 1, 0.01)
		Iris.End()

		if Iris.Button({ "Update Weather" }).clicked() then
			local changes = {}
			for key in pairs(dirty) do
				if key:sub(1,5) == "Wind_" then
					changes.Wind = changes.Wind or {}
					changes.Wind[key:sub(6)] = irisStates[key].value
				else
					changes[key] = irisStates[key].value
				end
			end
			for _, ck in ipairs({ "CloudColor", "Ambient", "OutdoorAmbient" }) do
				local orig = weatherState[ck]
				local st   = irisStates[ck]
				local c3   = st.value
				if not (orig
					and math.floor(c3.R*255) == orig.R
					and math.floor(c3.G*255) == orig.G
					and math.floor(c3.B*255) == orig.B
					) then
					changes[ck] = {
						R = math.floor(c3.R*255),
						G = math.floor(c3.G*255),
						B = math.floor(c3.B*255),
					}
				end
			end
			dirty = {}
			if next(changes) then
				UpdateWeather:Fire(changes)
			end
		end
	end

	Iris.End()
	return window
end

return {
	irisStates = irisStates,
	default     = buildUI,
}

Is there an updated documentation of Iris? I cannot find it

The documentation is as up-to-date as possible. Iris | Iris

@ThePyooterMallard What do you think?