RBLXGUI v.1.0.4 | Studio-like GUI Library that emulates the standard "studio" look and feel

rblxguibanner

💾 Github | 📩 Discord
 
Hosts a wide variety of GUI Elements made for dockable widgets in order to improve GUI workflow in Roblox Studio and provide a uniform look and feel for plugins.

OVERVIEW

RBLXGUI is an open-source GUI library for plugins inspired by Studio Widgets which seeks to emulate the standard “Roblox Studio” look and feel.

Warning: RBLXGUI completely overhauls wigets. if you want something more visually customizable rather than the basic Roblox Studio aesthetic, this is probably not for you.

Please Contribute!

This was a solo project and any help improving or keeping the library up to date would be greatly appreciated! (forgive me if the code is messy, this the first serious project I've ever done w/ roblox)
 
 
A few examples of plugins that I've made in the past with rblxgui

Features

  • Simple vertical layout

  • Automatically matches current studio theme (Light and Dark mode)

  • Customizable color themes

  • Sections, Sliders, Buttons, InputFields, Checkboxes, Progress Indicators, Color Selectors, Dropdown Menus, etc.

  • Fully functioning keybind system (works both in preview window and widget)

  • Customizable Window Prompts
    image

  • Window Tab system

  • Save and load custom widow layouts

Getting Started

In order to install this library, drag the latest release into roblox studio or into your plugin folder

You can also clone the repo and build the project with rojo.

rojo build --output "C:\Users\[Username]\AppData\Local\Roblox\Plugins\[Plugin Name].rbxmx"

Another way to install the library is by using HttpService to pull the contents directly from this github project into module scripts. Make sure you have http service from Game Settings enabled in order for this to work.

local http = game:GetService("HttpService")
local req = http:GetAsync("https://api.github.com/repos/xa1on/rblxguilib/contents/src")
local json = http:JSONDecode(req)

local targetFolder = Instance.new("Folder")
targetFolder.Name = "rblxgui"
targetFolder.Parent = game.Workspace

for i = 1, #json do
	local file = json[i]
	if (file.type == "file") then
		local name = file.name:sub(1, #file.name-4)
		local module = targetFolder:FindFirstChild(name) or Instance.new("ModuleScript")
		module.Name = name
		module.Source = http:GetAsync(file.download_url)
		module.Parent = targetFolder
	end
end

(Credit to the StudioWidgets repo for the import code)

Files

Frames

Element Description
GUIFrame.lua Class for all frame elements
BackgroundFrame.lua Creates a frame that syncs its color to the current studio theme
ListFrame.lua A uniform frame that goes in ScrollingFrames used to house objects
Page.lua Creates a page tab in a widget’s TitlebarMenu
PluginWidget.lua Creates a rblxgui widget
ScrollingFrame.lua A self-scaling ScrollingFrame
Section.lua A collapsible frame used to house objects
TitlebarMenu.lua Menu on widgets that contains it’s pages and TitlebarButtons

Objects

Element Description
GUIObject.lua Class for all object elements
Button.lua Creates a Button
Checkbox.lua Toggleable checkbox object that returns true and false
ColorInput.lua Object used to input colors using RGB values or ColorPropmt
InputField.lua TextBox object with a filtered dropdown menu
InstanceInputFrame.lua InputField for adding selected workspace objects
KeybindInputFrame.lua InputField for keybinds
Labeled.lua Text object that acts as a label for other objects
ProgressBar.lua Bar that fills up to represent progress
Slider.lua Adjustable slider that returns number values
Textbox.lua Creates a TextLabel object
TitlebarButton.lua Creates a TitlebarMenu Tab that acts as a button
ViewButton.lua Creates a TitlebarButton that allows users to editing widgets, layouts, and themes

Prompts

Element Description
Prompt.lua Creates a widget that acts as a prompt window and class for all prompt elements
ColorPrompt.lua TextPrompt window that allows user to edit colors
InputPrompt.lua TextPrompt window with an InputField
TextPrompt.lua Prompt with text and buttons

Managers

File Description
EventManager.lua Manages plugin events
InputManager.lua Keyyboard/mouse input event manager for rblxgui elements
KeybindManager.lua Keybind Manager for KeybindInputObjects
LayoutManager.lua Layout manager for plugin widget/page layouts in studio
ThemeManager.lua Theme manager for rblxgui element colors

Misc

File Description
GUIElement.lua Class for all GUI Elements
GUIUtil.lua ModuleScript that contains utility functions that dont fit the other categories
PluginGlobalVariables.lua ModuleScript that consolidates all variables used globally in the library

Documentation

No documentation at the moment, but you should be able to see how everything works in the Example Script.

--[[
    [RBLXGUILib]
    something#7597
    todo:
        
]]--

-- loads the library(plugin object, plugin id)
local gui = require(script.Parent.rblxgui.initialize)(plugin, "rblxgui")

-- plugin toolbar
toolbar = plugin:CreateToolbar("rblxgui")

-- widget
-- ID, Title, Enabled, NoTitlebarMenu, DockState, OverrideRestore
local widget = gui.PluginWidget.new({
    ID = "rblxgui",
    Enabled = true,
    DockState = Enum.InitialDockState.Left
})

-- toolbar button to toggle the widget
local b_toggle = toolbar:CreateButton("","open widget","")
b_toggle.Click:Connect(function() widget.Content.Enabled = not widget.Content.Enabled end)
local b_resetlayout = toolbar:CreateButton("", "reset layout", "")
b_resetlayout.Click:Connect(function() gui.LayoutManager.ResetLayout() end)


-- page:
-- Name, TitlebarMenu, Open, TabSize, ID
local mainpage = gui.Page.new({
    Name = "MAIN",
    TitlebarMenu = widget.TitlebarMenu,
    Open = true
})

-- view button(edit layouts and widgets)
-- 
gui.ViewButton.new()

local randommenu = plugin:CreatePluginMenu(game:GetService("HttpService"):GenerateGUID(false), "Random Menu")
randommenu.Name = "Random Menu"
randommenu:AddNewAction("1", "Option 1", "rbxasset://textures/loading/robloxTiltRed.png")
randommenu:AddNewAction("2", "Option 2", "rbxasset://textures/loading/robloxTilt.png")
local subMenu = plugin:CreatePluginMenu(game:GetService("HttpService"):GenerateGUID(false), "C", "rbxasset://textures/explosion.png")
subMenu.Name = "Sub Menu"
subMenu:AddNewAction("ActionD", "D", "rbxasset://textures/whiteCircle.png")
subMenu:AddNewAction("ActionE", "E", "rbxasset://textures/icon_ROBUX.png")
randommenu:AddMenu(subMenu)

-- title bar button(button on the titlebar of widgets with titlebars)
-- Name, TabSize, Disabled, PluginMenu
local titlebarbutton = gui.TitlebarButton.new({
    Name = "BUTTON",
    PluginMenu = randommenu
})
titlebarbutton:Clicked(function()
    print("Titlebar button pressed!")
end)

titlebarbutton:SelectedAction(function(SelectedAction)
    if SelectedAction then
        print("Selected Action:", SelectedAction.Text, "with ActionId:", SelectedAction.ActionId)
    else
        print("User did not select an action!")
    end
end)


gui.Page.new({Name = "SETTINGS"}, widget)
gui.Page.new({Name = "PAGE1"}, widget)
gui.Page.new({Name = "PAGE2"}, widget)
gui.Page.new({Name = "PAGE3"}, widget)
gui.Page.new({Name = "PAGE4"}, widget)

-- scrolling frame(lets you scroll through the gui):
-- BarSize
local mainframe = gui.ScrollingFrame.new(nil, mainpage.Content)
-- sets mainframe as the main element(everything will go here by default unless you specify a parent)
mainframe:SetMain()

-- textbox:
-- Text, Font, Alignment, TextSize
gui.Textbox.new({
    Text = "Welcome to rblxgui!",
    Font = Enum.Font.SourceSansBold,
    Alignment = Enum.TextXAlignment.Center
})

-- listframe(contains stuff):
-- Name, Height
local acoolframe = gui.ListFrame.new({
    Name = "cool new frame"
})
gui.Textbox.new({
    Text = "welcome to rblxgui!"
}, acoolframe.Content)
gui.Textbox.new({
    Text = "WELCOME TO RBLXGUI!",
    Font = Enum.Font.SourceSansBold
}, acoolframe.Content)

-- buttons:
-- Text/Textbox, ButtonSize, Disabled
local button1 = gui.Button.new({
    Text = "hi"
})
button1:Clicked(function() print("hi") end)
local button2 = gui.Button.new({
    Text = "Hello",
    ButtonSize = 1
}, button1.Parent)
button2:Clicked(function() print("Hello") button1:ToggleDisable() end)



-- using a list frame to add padding between elements
gui.ListFrame.new({
    Height = 5
})

-- sections:
-- Text, Open, Parent
local buttonsection = gui.Section.new({
    Text = "Buttons"
})
-- setting the section to main (saves time having to type out the section for every button)
buttonsection:SetMain()

-- textbox inside button for custom text
local fancybuttonlabel = gui.Textbox.new({
    Text = "fancier button",
    Font = Enum.Font.Arcade
})
local button2 = gui.Button.new({
    Textbox = fancybuttonlabel
})
button2.Object.MouseButton1Click:Connect(function()
    -- textprompt:
    -- Title, Textbox, Buttons
    local textprompt = gui.TextPrompt.new({
        Title = "The Fancy Button",
        Text = "Hello!",
        Buttons = {"Hi!", "Hello!"}
    })
    textprompt:Clicked(function(p)
        print(p)
    end)
end)

-- using frames to move a button
local frame1 = gui.ListFrame.new({
    Name = "the first frame"
})
local frame2 = gui.ListFrame.new({
    Name = "the second frame"
})

local button3 = gui.Button.new({
    Text = "press to go down"
}, frame1.Content)
local buttonup = true
button3:Clicked(function()
    if buttonup then
        button3:Move(frame2.Content)
        button3.Textbox.Text = "press to go up"
    else
        button3:Move(frame1.Content)
        button3.Textbox.Text = "press to go down"
    end
    print("im in "..button3.Parent.Name.."!")
    buttonup = not buttonup
end)

mainframe:SetMain()
local newsection = gui.Section.new({
    Text = "section with a section inside it",
    Open = true
})
local sectionwithin = gui.Section.new({
    Text = "another section",
    Open = true
}, newsection.Content)
gui.Textbox.new({
    Text = "test"
}, gui.ListFrame.new(nil, sectionwithin.Content).Content)
local testbutton = gui.Button.new({
    Text = "test"
}, gui.ListFrame.new(nil, sectionwithin.Content).Content)
testbutton:Clicked(function()
    local inputprompt = gui.InputPrompt.new({
        Title = "Input Prompt title",
        Text = "hey, this is an inputprompt",
        Input = "hi"
    })
    inputprompt:Clicked(function(p)
        print("option " .. p .. " chosen")
        print("entered text:" .. inputprompt.InputField.Value)
    end)
end)


-- inputfields
-- Placeholder, CurrentItem/Value, Items, InputSize, NoDropdown, NoFiltering, DisableEditing, ClearText, Disabled
gui.InputField.new({
    CurrentItem = "default text",
    Items = {
        {
            Name = "bob",
            Value = "Bob"
        }, "Steve"
    }
})

-- Labeled objects
-- Textbox, LabelSize, Objects
local inpfield = gui.Labeled.new({
    Text = "another input",
    Objects = gui.InputField.new({
        Placeholder = "placeholder"
    })
})
inpfield.Object:AddItems({
    "1",
    "2",
    "remove",
    {
        Name = "1 thousand",
        Value = 1000
    }
})
inpfield.Object:RemoveItem("remove")
for i=4,100 do
    inpfield.Object:AddItem(i)
end
inpfield.Object:Changed(function(text)
    print(text)
end)

-- toggleable buttons
-- Textbox, ButtonSize, Value, Disabled
local togglebutton1 = gui.ToggleableButton.new({
    Text = "toggle next button"
})
local togglebutton2 = gui.ToggleableButton.new({
    Text = "Untoggle previous button",
    Value = true
})
togglebutton1:Clicked(function(p) if p then togglebutton2:SetValue(false) end end)
togglebutton2:Clicked(function(p) if p then togglebutton1:SetValue(false) end end)

-- instanceinputfield
-- Value/CurrentItem, Items, InputSize, NoDropdown, NoFiltering, DisabledEditing, ClearText, Disabled
local instanceinpfield = gui.InstanceInputField.new({
    Items = {
        {
            Value = {
                game:GetService("Lighting"),
                game:GetService("MaterialService")
            },
            Name = "Lighting/MaterialService combo"
        }, workspace,{
            game:GetService("ReplicatedFirst"),
            game:GetService("ReplicatedStorage")
        }
    }
})
gui.Labeled.new({
    Text = "an instance",
    Object = instanceinpfield
})
instanceinpfield:Changed(function(result)
    for _, v in pairs(result) do
        print(v:GetFullName())
    end
end)
instanceinpfield:DropdownToggled(function(p)
    print("dropdown has beeen toggled")
    print(p)
end)


-- keybindinputfield
-- PressedAction, ReleasedAction, Holdable, Unrestricted, Bind/CurrentBind, Items/Binds, InputSize, NoDropdown, NoFiltering, DisabledEditing, ClearText, Disabled
gui.Labeled.new({
    Text = "keybind",
    Object = gui.KeybindInputField.new({
        PressedAction = function() print("keybind1 pressed!") end,
        ReleasedAction = function() print("keybind1 released!") end,
        CurrentBind = {
            {"N"},
            {"LeftShift", "T"}
        },
        Binds = {
            {
                Value = {
                    {"U"},
                    {"LeftShift", "L"}
                }
            },{
                Value = {
                    {"N"},
                    {"LeftShift", "K"}
                }
            },{
                Name = "Default",
                Value = {
                    {"N"},
                    {"LeftShift", "T"}
                },
            }
        }
    })
})

local keybindinpfield2 = gui.Labeled.new({
    Text = "another keybind",
    Object = gui.KeybindInputField.new({Holdable = true, Unrestricted = true})
})
keybindinpfield2.Object:Pressed(function()
    print("second keybind pressed!")
end)
keybindinpfield2.Object:Released(function()
    print("second keybind released!")
end)

-- checkbox
-- Value, Disabled
local checkbox = gui.Labeled.new({
    Text = "checkbox",
    LabelSize = 0.5,
    Object = gui.Checkbox.new({
        Value = true
    })
})
checkbox.Object:Clicked(function(p)
    print(p)
    keybindinpfield2:SetDisabled(not p)
end)

local toggle_checkbox = gui.Checkbox.new()
gui.Labeled.new({
    Text = "Disable checkbox",
    LabelSize = 0.5,
    Object = toggle_checkbox
})
toggle_checkbox:Clicked(function(p)
    checkbox:SetDisabled(p)
end)

-- slider
-- Min, Max, Value, Increment, SliderSize, Disabled
local labeledslider = gui.Labeled.new({
    Text = "Labled Slider",
    Objects = {
        {
            Object = gui.InputField.new({
                Value = 50,
                InputSize = 1,
                NoDropdown = true,
                DisableEditing = true
            }),
            Name = "display",
            Size = UDim.new(0,30)
        },{
            Object = gui.Slider.new({
                Min = 0,
                Max = 100,
                Value = 50,
                Increment = 1
            }),
            Name = "slider"
        }
    }
})

-- progressbar
-- BarSize, Value, Disabled
local progressbar = gui.ProgressBar.new({
    Value = 0.5
})

labeledslider.slider:Changed(function(p)
    labeledslider.display:SetValue(p)
    progressbar:SetValue(p/100)
end)

local toggle_checkbox2 = gui.Checkbox.new()
gui.Labeled.new({
    Text = "Disable Slider",
    LabelSize = 0.5,
    Object = toggle_checkbox2
})
toggle_checkbox2:Clicked(function(p)
    labeledslider:SetDisabled(p)
    progressbar:SetDisabled(p)
end)

local colorinput = gui.ColorInput.new({
    Color = gui.ThemeManager.DefaultAccentColor,
    NoPause = true
})
colorinput:SetValue(gui.ThemeManager.AccentColor)
gui.Labeled.new({
    Text = "Color Input",
    LabelSize = 0.5,
    Object = colorinput
})

-- dumps the gui into workspace for debugging
local dumpbutton = gui.Button.new({Text = "Dump GUI into workspace"})
dumpbutton:Clicked(function()
    print("Dumping GUI")
    gui.GUIUtil.DumpGUI(widget.Content)
end)

gui.LayoutManager.RecallSave()

If anyone actually plans on using this, DM me on Twitter or Discord (xa1on) if you have any further questions or if you just want to show off what you made.

42 Likes

Nice! Like ImGui but for Studio/QT5 UI.

1 Like

Hey what is it for like a normal text input, TextBox without dropdown filter? Thanks!

1 Like

Theres a NoDropdown property you can set when you make the InputField.
For example:

gui.InputField.new({
    CurrentItem = "default text",
    Items = {
        {
            Name = "bob",
            Value = "Bob"
        }, "Steve"
    },
    NoDropdown = true
})

These are all the inputfield properties: Placeholder, CurrentItem/Value, Items, InputSize, NoDropdown, NoFiltering, DisableEditing, ClearText, Disabled

Is this for plugins only or can it be used for live servers?

In theory, it could work for live servers. If youd like, i could make an example script

Please do. What do you mean by in theory though???

You have certainly outdone yourself here, will be using this library.

2 Likes

It was made primarily for plugins and i havent tested it live in game but everything in rblxgui should work just fine in theory. There might be a few features missing but it could work with a bit of tweaking.

I’ll see what I can do.

Very well made and that to solo!

1 Like

Intimidating at first, very easy to use once you actually understand how everything works. Good project!

1 Like