TextBox Plus [Open Source!]

Another open source module for you guys!

I hate TextBoxes and their total lack of important functionality.

Reasons for hating, in order of most to least hated

TextWrapped doesn’t add control chars to mark where it added newlines, so any line related code is left in the dark. This is my main aggravation.

It doesn’t actually allow tabs. It just renders them as a single space, ruining everything. :upside_down_face:

There’s no Up/Down arrows to move the cursor.

It’s missing so many simple shortcut controls like Ctrl-D.

There’s no Ctrl-Z/Y for undo/redo. This is fair enough, but I want it anyway so I made it.

Therefore, I wrote this module to make them usable. Not great, but good enough.


Features:

  • Undo/Redo support.
    Ctrl-Z and Ctrl-Y are done automatically, and you can call :Undo() and :Redo() on the controller object. Snapshots are taken when you stop typing, or if you haven’t taken one in 3 seconds, or if you’ve added 10+ chars since last snapshot. This works well, without having to snapshot every single changed character.

  • Ctrl-D to select current word.

  • Built into a ScrollingFrame that autosizes to fit the text.
    You can do Settings.Padded = true so that you can scroll down to bring the last line to the top of the frame.

  • Up/Down arrows cursor movement.
    This only works when .MultiLine is true and .TextWrapped is false, because .TextWrapped doesn’t mark where it created newlines so string.split(Text,"\n") doesn’t work anymore.


API:

TBPlus:

function TBPlus.new(Frame, Settings)

Creates a TBPlusObject

Parameters:

  • Frame [GuiObject]
    The GuiObject to parent the TBPlus object to

  • Settings [Optional Table]

    • number Settings.TextSize (Defaults to 16)
    • boolean Settings.Padded (Defaults to true)
    • boolean Settings.TextWrapped (Defaults to true)
    • boolean Settings.MultiLine (Defaults to true)
    • Color3 Settings.TextColor3 (Defaults to black)
    • Enum Settings.Font (Defaults to SourceSans)
    • boolean Settings.ClearTextOnFocus (Defaults to false)
    • Enum Settings.TextXAlignment (Defaults to Left)
    • Enum Settings.TextYAlignment (Defaults to Top)
    • string Settings.PlaceholderText (Defaults to blank)
    • Color3 Settings.PlaceholderColor3 (Defaults to dark grey)

Returns:

  • TBPlusObject

Note that the TBPlusObject has .TextBox which is a pointer to the actual TextBox, so you can easily tweak properties like .PlaceholderText without needing to send via Settings.

TBPlusObject:

object TBPlusObject.TextBox

Points to the actual TextBox object

Returns:

  • TextBox

This is mostly used to check the current .Text of the TextBox or do something with the events/functions of the TextBox.

function TBPlusObject.Write(Text,Start,End)

Writes the Text in at the given start and end position

Parameters:

  • Text [string]
    The text to write in

  • Start [number]
    The position to start the text

  • End [number]
    The position to end the text

Returns:

  • nil

Note that if Start and End are the same, it’s just inserting text at that point, whereas if they are different then it’s overwriting text that was in between those positions.

function TBPlusObject.SetContent(Text)

Sets the TextBox’s Text and clears the Undo/Redo stack

Parameters:

  • Text [string]
    The text to write in

Returns:

  • nil
function TBPlusObject:Undo()

Undoes by one snapshot

Parameters:

  • N/A

Returns:

  • nil
function TBPlusObject:Redo()

Redoes by one snapshot

Parameters:

  • N/A

Returns:

  • nil

Example Code:


local TBPlusObject = require(script.TextBoxPlus).new(
	script.Parent.Frame,
	{
		TextSize = 15;
		TextWrapped = false;
		Font = Enum.Font.Code;
		
	}
)

TBPlusObject.TextBox:GetPropertyChangedSignal("Text"):Connect(function()
	
	print(TBPlusObject.TextBox.CursorPosition)
	
end)


Module:


I hope you find this useful! I use a slightly modified version for the markdown editor in Lua Learning, so I figured it’s worth sharing.

31 Likes

Curiosity speaks.

What do you mean when you refer to line related code? Does this have to do with coding that needs to know how many lines the text spans, or is it for dynamic scaling, or…? I don’t see much utility in knowing how many lines a text box spans.

Next is a question.

Any reason why this method differs from the rest of the API in how it’s called, or is this just mistaken syntax? Could be jarring when it comes to consistency.

Knowing what line the CursorPosition is on.
Knowing how many lines there are in total.
Knowing what line a position is on.

Want to implement up/down arrows? Can’t do that with TextWrapped enabled.
Want to draw line numbers on the side? Can’t do that with TextWrapped enabled.
Want to highlight the line you’re currently editing? Can’t do that with TextWrapped enabled.

Actually, yes. It’s like that for a backwards compatibility reason, and you guys have gotten this as your V1 so it seems out of place. You can easily switch that if it bothers you. Edit: Same applies to .Write()

2 Likes