From my understanding roblox does not support text selection outside of textboxes. With a textbox input you can use properties CursorPosition and SelectionStart. Read more on the api reference Textbox
Ah ok. Would there be a better way of making a format text system?
I was thinking to make the TextBox have RichText on and get people to just type HTML formats (eg. <b>Hi</b> would look like Hi but I didn’t think that would be the best UX.
Sadly roblox has not put a lot of effort into text editing. You still could use selection properties and rich text, inserting <b> and </b> wouldn’t be too difficult. Text boxes also clear on focus so make sure to store the text elsewhere
with some testing you also cannot really get the selection start as clicking elsewhere loses focus and the selection. So if you wanted to use a gui button you cannot because of the clicking focus loss, and if you want to use keyboard command too bad cause the textbox consumes those inputs too.
--!strict
local context = game:GetService("ContextActionService")
local textbox = script.Parent.TextBox
local boldbutton = script.Parent.TextButton
local function bold_selection()
if textbox.SelectionStart == -1 then
warn("No text selected")
return
end
local cstart = math.min(textbox.CursorPosition, textbox.SelectionStart)
local cend = math.max(textbox.CursorPosition, textbox.SelectionStart)
local newtext = string.format("%s<b>%s</b>%s", textbox.Text:sub(0, cstart), textbox.Text:sub(cstart, cend), textbox.Text:sub(cend))
textbox.Text = newtext
end
context:BindAction("bold", bold_selection, false, Enum.KeyCode.B)
boldbutton.Activated:Connect(bold_selection)
Here’s the script I used to test, the context action never fires and the bold button activation always warns “No text selected”, but typing in <b> manually shows rich text.
This is basically the idea I want, except I want a button that does it for you over your selection, as you know. Still don’t know how to find an alternative since the selection won’t work.
Edit - just found this:
I now know it is possible. I found a game called Lua Learning by @boatbomber which utilises this feature.
Below is a video where I was showing the features. At the end, I show some of the downsides of how it breaks.
Note: OBS didn’t record my mouse cursor, but I clicked on the buttons above the TextBox to format it.
I just made a somewhat working implementation of this:
local textBox = script.Parent
local UIS = game:GetService("UserInputService")
local mouseHeld = false
local lastSelection
UIS.InputBegan:Connect(function(inputObject)
if inputObject.UserInputType == Enum.UserInputType.MouseButton1 then
mouseHeld = true
end
end)
UIS.InputEnded:Connect(function(inputObject)
if inputObject.UserInputType == Enum.UserInputType.MouseButton1 then
mouseHeld = false
end
end)
function onCursorPosChanged()
if mouseHeld then
repeat task.wait() until not mouseHeld
lastSelection = string.sub(textBox.Text, textBox.SelectionStart, textBox.CursorPosition)
print(lastSelection)
end
end
textBox:GetPropertyChangedSignal("CursorPosition"):Connect(onCursorPosChanged)
There is probably a much much better way to go about it, it basically just waits until the mouse is let go and stores the selection in the lastSelection variable
Okay, I made a test textbox to mimic the same functionality using the script I wrote before as a basis, and it worked for me in studio:
-- Changes to the previous script
-- new definitions:
local selectionStart
local selectionEnd
function onCursorPosChanged()
if mouseHeld then
repeat task.wait() until not mouseHeld
lastSelection = string.sub(textBox.Text, textBox.SelectionStart, textBox.CursorPosition-1)
selectionStart = textBox.SelectionStart
selectionEnd = textBox.CursorPosition
end
end
textBox:GetPropertyChangedSignal("CursorPosition"):Connect(onCursorPosChanged)
-- Run this when the button is pressed
if lastSelection then
local bolded = '<b>' .. lastSelection .. '</b>'
textBox:ReleaseFocus()
textBox.Text = string.sub(textBox.Text, 1, selectionStart-1) .. bolded .. string.sub(textBox.Text, selectionEnd)
end
I hope this works for you, I included the ReleaseFocus() since I noticed that rich text only gets bolded when a textbox is unfocused.
If you want to modify things about it later I recommend reading up on the string functions roblox provides: string , since there is probably lots to improve upon here, I’m pretty new to roblox development myself.
I’m not sure if I’m missing something because it doesn’t seem to work for me.
My script currently looks like this (`script` is child of `TextBox`):
local textBox = script.Parent
local UIS = game:GetService("UserInputService")
local mouseHeld = false
local selectionStart
local selectionEnd
local lastSelection
UIS.InputBegan:Connect(function(inputObject)
if inputObject.UserInputType == Enum.UserInputType.MouseButton1 then
mouseHeld = true
end
end)
UIS.InputEnded:Connect(function(inputObject)
if inputObject.UserInputType == Enum.UserInputType.MouseButton1 then
mouseHeld = false
end
end)
function onCursorPosChanged()
if mouseHeld then
repeat task.wait() until not mouseHeld
lastSelection = string.sub(textBox.Text, textBox.SelectionStart, textBox.CursorPosition-1)
selectionStart = textBox.SelectionStart
selectionEnd = textBox.CursorPosition
end
end
textBox:GetPropertyChangedSignal("CursorPosition"):Connect(onCursorPosChanged)
script.Parent.Parent.Options.Bold.MouseButton1Click:Connect(function()
if lastSelection then
local bolded = '<b>' .. lastSelection .. '</b>'
textBox:ReleaseFocus()
textBox.Text = string.sub(textBox.Text, 1, selectionStart-1) .. bolded .. string.sub(textBox.Text, selectionEnd)
end
end)
When running, if I select the word ‘Hello’, it will change to ‘Hello<b></b>Hello’ which is close to what I am looking for, but instead it should be ‘<b>Hello</b>’.
Edit: I tried printing lastSelection and returns nothing, like literally “”.
I’ve tried a normal script and a local script, and the local script works better since the normal script doesn’t run.
a script on the server cannot know the text that the user has typed, so it uses a local script, about this, did you get what you are looking for? If not yet, I’ll get to work.