Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local TextService = game:GetService("TextService")
- local root = script.Parent.Parent.Parent
- local gui = root.Gui
- local colors = require(gui.Colors)
- local core = require(gui.Core)
- local event = core.Event
- local instanceEvent = core.InstanceEvent
- local forceMousePosition = core.ForceMousePosition
- local forceInputChange = core.ForceInputChange
- local functions = root.Functions
- local setupTooltip = require(functions.Tooltip).Setup
- local sanitizeRichText = require(functions.SanitizeRichText)
- local color3Difference = require(functions.Color3Difference)
- local function getTextWidth(text)
- return TextService:GetTextSize(text, 14, Enum.Font.SourceSans, Vector2.new(math.huge, math.huge)).X
- end
- type Module = (name: string, parent: ScrollingFrame, default: string?, tooltip: string?) -> Frame
- return function(name, parent, default, tooltip)
- if typeof(parent) ~= "Instance" or parent.ClassName ~= "ScrollingFrame" then error("Invalid parent.") end
- local container = Instance.new("Frame")
- container.Size = UDim2.new(1, -2, 0, 20)
- container.BackgroundTransparency = 1
- container.BorderSizePixel = 0
- container.Name = name
- container.Parent = parent
- local left = Instance.new("Frame")
- left.Position = UDim2.new(0, 1, 0, 0)
- left.Size = UDim2.new(0.5, -1, 1, 0)
- left.BackgroundColor3 = colors.Background
- left.Name = "Left"
- left.Parent = container
- do
- local stroke = Instance.new("UIStroke")
- stroke.Color = colors.Border.Secondary
- stroke.ApplyStrokeMode = Enum.ApplyStrokeMode.Border
- stroke.LineJoinMode = Enum.LineJoinMode.Miter
- stroke.Parent = left
- end
- if type(tooltip) == "string" then
- setupTooltip(left, tooltip)
- end
- local right = Instance.new("Frame")
- right.Position = UDim2.new(0.5, 1, 0, 0)
- right.Size = UDim2.fromScale(0.5, 1)
- right.BackgroundColor3 = colors.Background
- right.ClipsDescendants = true
- right.Name = "Right"
- right.Parent = container
- do
- local stroke = Instance.new("UIStroke")
- stroke.Color = colors.Border.Secondary
- stroke.ApplyStrokeMode = Enum.ApplyStrokeMode.Border
- stroke.LineJoinMode = Enum.LineJoinMode.Miter
- stroke.Parent = right
- end
- local rightBottomBorderCover = Instance.new("Frame")
- rightBottomBorderCover.Position = UDim2.new(0.5, 1, 1, 0)
- rightBottomBorderCover.Size = UDim2.new(0.5, 0, 0, 1)
- rightBottomBorderCover.BackgroundColor3 = colors.TextField
- rightBottomBorderCover.BorderSizePixel = 0
- rightBottomBorderCover.ZIndex = 2147483647 -- int-32 limit.
- rightBottomBorderCover.Visible = false
- rightBottomBorderCover.Name = "RightBottomBorderCover"
- rightBottomBorderCover.Parent = container
- container:SetAttribute("Selected", false)
- instanceEvent.MouseEnter(container, function()
- if not container:GetAttribute("Selected") then
- left.BackgroundColor3 = colors.Highlighted
- right.BackgroundColor3 = colors.Highlighted
- end
- end)
- instanceEvent.MouseLeave(container, function()
- if not container:GetAttribute("Selected") then
- left.BackgroundColor3 = colors.Background
- right.BackgroundColor3 = colors.Background
- end
- end)
- local label = Instance.new("TextLabel")
- label.Position = UDim2.fromOffset(24, 2)
- label.Size = UDim2.new(1, -28, 1, 0)
- label.BackgroundTransparency = 1
- label.Font = Enum.Font.SourceSans
- label.TextSize = 14
- label.TextColor3 = colors.Text.Primary
- label.TextXAlignment = Enum.TextXAlignment.Left
- label.TextYAlignment = Enum.TextYAlignment.Top
- label.TextTruncate = Enum.TextTruncate.SplitWord
- label.Text = name
- label.Name = "Label"
- label.Parent = left
- local textBox = Instance.new("TextBox")
- textBox.Size = UDim2.fromScale(1, 1)
- textBox.BackgroundTransparency = 1
- textBox.TextTransparency = 1
- textBox.Font = Enum.Font.SourceSans
- textBox.TextSize = 14
- textBox.TextXAlignment = Enum.TextXAlignment.Left
- textBox.TextYAlignment = Enum.TextYAlignment.Top
- textBox.ClearTextOnFocus = false
- textBox.Active = false
- textBox.Parent = right
- do
- local padding = Instance.new("UIPadding")
- padding.PaddingTop = UDim.new(0, 2)
- padding.PaddingLeft = UDim.new(0, 2)
- padding.PaddingRight = UDim.new(0, 2)
- padding.Parent = textBox
- end
- local textLabel = Instance.new("TextLabel")
- textLabel.Position = UDim2.fromOffset(4, 2)
- textLabel.Size = UDim2.new(1, -8, 1, -12)
- textLabel.BackgroundTransparency = 1
- textLabel.BorderSizePixel = 0
- textLabel.Font = Enum.Font.SourceSans
- textLabel.TextSize = 14
- textLabel.TextColor3 = colors.Text.Primary
- textLabel.TextXAlignment = Enum.TextXAlignment.Left
- textLabel.TextYAlignment = Enum.TextYAlignment.Top
- textLabel.TextTruncate = Enum.TextTruncate.SplitWord
- textLabel.Parent = right
- if type(default) == "string" then
- container:SetAttribute("Text", default)
- textBox.Text = default
- textLabel.Text = sanitizeRichText(default)
- else
- container:SetAttribute("Text", "")
- textBox.Text = ""
- textLabel.Text = ""
- end
- local cursor = Instance.new("Frame")
- cursor.Position = UDim2.fromOffset(0, 1)
- cursor.Size = UDim2.fromOffset(1, 15)
- cursor.BackgroundColor3 = colors.Cursor -- rbg(255, 255, 255) with "difference" blending mode for identical to Studio - not supported in Roblox unfortunately.
- cursor.BorderSizePixel = 0
- cursor.ZIndex = 2
- cursor.Visible = false
- cursor.Parent = textBox
- local selectionBackground = Instance.new("Frame")
- selectionBackground.Position = UDim2.fromOffset(0, 1)
- selectionBackground.Size = UDim2.fromOffset(0, 15)
- selectionBackground.BackgroundColor3 = colors.Primary
- selectionBackground.BorderSizePixel = 0
- selectionBackground.Visible = false
- selectionBackground.Parent = textBox
- local cursorThread = nil
- local hoverConnection = nil
- local inputConnection = nil
- local lastAbsoluteCursorPosition = 0
- local lastCursorPosition = -1
- local lastSelectionStart = -1
- local lastText = textBox.Text
- local justDefocused = false
- local differentSelectionColor = color3Difference(colors.Text.Edit, colors.Text.Highlighted) > 0.000004 -- We detect 0.01 difference; a difference that is visually unpresent, yet the code can detect.
- event.ThemeChanged:Connect(function()
- if color3Difference(colors.Text.Edit, colors.Text.Highlighted) < 0.000004 then
- textLabel.Text = lastText
- textLabel.RichText = false
- differentSelectionColor = false
- elseif not differentSelectionColor then
- textLabel.Text = sanitizeRichText(lastText)
- textLabel.RichText = true
- differentSelectionColor = true
- end
- end)
- local function cursorLoop()
- while true do
- task.wait(0.533)
- cursor.Visible = false
- task.wait(0.533)
- cursor.Visible = true
- end
- end
- local function updateSelection()
- -- lastText will be current text.
- -- lastSelectionStart will be current selection start.
- -- lastCursorPosition will be current cursor position.
- -- lastAbsoluteCursorPosition will be current absolute cursor position.
- if lastSelectionStart == -1 then
- selectionBackground.Visible = false
- textLabel.Text = lastText
- textLabel.RichText = false
- else
- if lastSelectionStart > lastCursorPosition then
- local selectedText = lastText:sub(lastCursorPosition, lastSelectionStart - 1)
- selectionBackground.Size = UDim2.fromOffset(getTextWidth(selectedText), 15)
- selectionBackground.Position = UDim2.fromOffset(textLabel.Position.X.Offset - 2 + lastAbsoluteCursorPosition, 1)
- if differentSelectionColor then
- textLabel.Text = sanitizeRichText(lastText:sub(1, lastCursorPosition - 1))..'<font color="#'..colors.Text.Highlighted:ToHex()..'">'..sanitizeRichText(selectedText).."</font>"..sanitizeRichText(lastText:sub(lastSelectionStart, -1))
- textLabel.RichText = true
- end
- else
- local selectedText = lastText:sub(lastSelectionStart, lastCursorPosition - 1)
- local leftOfSelectionText = lastText:sub(1, lastSelectionStart - 1)
- selectionBackground.Size = UDim2.fromOffset(getTextWidth(selectedText), 15)
- selectionBackground.Position = UDim2.fromOffset(textLabel.Position.X.Offset - 2 + getTextWidth(leftOfSelectionText), 1)
- if differentSelectionColor then
- textLabel.Text = sanitizeRichText(leftOfSelectionText)..'<font color="#'..colors.Text.Highlighted:ToHex()..'">'..sanitizeRichText(selectedText).."</font>"..sanitizeRichText(lastText:sub(lastCursorPosition, -1))
- textLabel.RichText = true
- end
- end
- selectionBackground.Visible = true
- end
- end
- local function updatePosition()
- -- lastText will be current text.
- coroutine.close(cursorThread)
- cursor.Visible = true
- cursorThread = coroutine.create(cursorLoop)
- coroutine.resume(cursorThread)
- local absoluteCursorPosition = getTextWidth(lastText:sub(1, textBox.CursorPosition - 1))
- local move = absoluteCursorPosition - lastAbsoluteCursorPosition
- if move > 0 then
- lastAbsoluteCursorPosition = absoluteCursorPosition
- local newCursorPosition = cursor.Position.X.Offset + move
- local difference = newCursorPosition - (textBox.AbsoluteSize.X - 4)
- if difference > 0 then
- textLabel.Position = UDim2.fromOffset(textLabel.Position.X.Offset - difference, 2)
- textLabel.Size = UDim2.new(1, textLabel.Size.X.Offset + difference, 1, -12)
- cursor.Position = UDim2.fromOffset(textBox.AbsoluteSize.X - 4, 1)
- else
- cursor.Position = UDim2.fromOffset(newCursorPosition, 1)
- end
- elseif move < 0 then
- lastAbsoluteCursorPosition = absoluteCursorPosition
- local newCursorPosition = cursor.Position.X.Offset + move
- if newCursorPosition < 0 then
- textLabel.Position = UDim2.fromOffset(textLabel.Position.X.Offset - newCursorPosition, 2)
- textLabel.Size = UDim2.new(1, textLabel.Size.X.Offset + newCursorPosition, 1, -12)
- cursor.Position = UDim2.fromOffset(0, 1)
- else
- cursor.Position = UDim2.fromOffset(newCursorPosition, 1)
- end
- end
- if textLabel.Position.X.Offset < 2 then
- local difference = textLabel.Position.X.Offset + getTextWidth(lastText) - (textBox.AbsoluteSize.X - 2)
- if difference < 0 then
- local position = textLabel.Position.X.Offset - difference
- if position > 2 then
- textLabel.Position = UDim2.fromOffset(2, 2)
- textLabel.Size = UDim2.new(1, textLabel.Size.X.Offset + difference + position - 2, 1, -12)
- cursor.Position = UDim2.fromOffset(cursor.Position.X.Offset - difference - position + 2, 1)
- else
- textLabel.Position = UDim2.fromOffset(position, 2)
- textLabel.Size = UDim2.new(1, textLabel.Size.X.Offset + difference, 1, -12)
- cursor.Position = UDim2.fromOffset(cursor.Position.X.Offset - difference, 1)
- end
- end
- end
- end
- textBox.Changed:Connect(function()
- if cursorThread == nil then return end
- local newCursorPosition = false
- if textBox.Text ~= lastText then
- lastText = textBox.Text -- lastText is now current text.
- if differentSelectionColor then
- textLabel.Text = sanitizeRichText(lastText)
- else
- textLabel.Text = lastText
- end
- updatePosition()
- container:SetAttribute("Text", lastText)
- elseif textBox.CursorPosition ~= lastCursorPosition then
- newCursorPosition = true
- lastCursorPosition = textBox.CursorPosition
- updatePosition()
- updateSelection()
- end
- if newCursorPosition then
- updateSelection()
- elseif lastSelectionStart ~= textBox.SelectionStart then
- lastSelectionStart = textBox.SelectionStart -- lastSelectionStart is now current selection start.
- updateSelection()
- end
- end)
- instanceEvent.MouseButton1Down(container, function()
- local focused = false
- if cursorThread == nil and not justDefocused then
- focused = true
- textBox:CaptureFocus()
- textBox.ZIndex = 2147483647 -- int-32 limit.
- textBox.SelectionStart = 1
- hoverConnection = textBox.MouseEnter:Connect(function()
- forceMousePosition(Vector2.new(textBox.AbsolutePosition.X, textBox.AbsolutePosition.Y))
- end)
- inputConnection = textBox.InputChanged:Connect(forceInputChange)
- textLabel.Position = UDim2.fromOffset(2, 2)
- textLabel.Size = UDim2.new(1, -4, 1, -12)
- textLabel.TextColor3 = colors.Text.Edit
- right.BackgroundColor3 = colors.TextField
- textLabel.TextTruncate = Enum.TextTruncate.None
- cursor.Visible = true
- rightBottomBorderCover.Visible = true
- cursorThread = coroutine.create(cursorLoop)
- coroutine.resume(cursorThread)
- end
- if not container:GetAttribute("Selected") then
- container:SetAttribute("Selected", true)
- left.BackgroundColor3 = colors.Primary
- if cursorThread == nil then
- right.BackgroundColor3 = colors.Primary
- end
- label.TextColor3 = colors.Text.Highlighted
- if not differentSelectionColor or not focused then
- textLabel.TextColor3 = colors.Text.Highlighted
- else
- textLabel.TextColor3 = colors.Text.Edit
- end
- for _, instance in ipairs(parent:GetChildren()) do
- if instance.ClassName ~= "Frame" then continue end
- if instance == container then continue end
- instance:SetAttribute("Selected", false)
- end
- end
- end)
- textBox.FocusLost:Connect(function()
- justDefocused = true
- coroutine.close(cursorThread)
- cursorThread = nil
- hoverConnection:Disconnect()
- hoverConnection = nil
- inputConnection:Disconnect()
- inputConnection = nil
- textBox.ZIndex = 1
- lastCursorPosition = -1
- lastAbsoluteCursorPosition = 0
- cursor.Position = UDim2.fromOffset(0, 1)
- textLabel.Position = UDim2.fromOffset(4, 2)
- textLabel.Size = UDim2.new(1, -8, 1, -12)
- if container:GetAttribute("Selected") then
- textLabel.TextColor3 = colors.Text.Highlighted
- else
- textLabel.TextColor3 = colors.Text.Primary
- end
- right.BackgroundColor3 = colors.Primary
- textLabel.TextTruncate = Enum.TextTruncate.SplitWord
- cursor.Visible = false
- rightBottomBorderCover.Visible = false
- task.wait()
- justDefocused = false
- end)
- container:GetAttributeChangedSignal("Selected"):Connect(function()
- if not container:GetAttribute("Selected") then
- left.BackgroundColor3 = colors.Background
- right.BackgroundColor3 = colors.Background
- label.TextColor3 = colors.Text.Primary
- textLabel.TextColor3 = colors.Text.Primary
- end
- end)
- return container
- end :: Module
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement