Run it
Copy the script and paste it into your executor.
EmbeddedModules = {
[] = ()
Main,Lib,Apps,Settings
Explorer, Properties, ScriptViewer, Notebook
API,RMD,env,service,plr,create,createSimple
(data)
Main = data.Main
Lib = data.Lib
Apps = data.Apps
Settings = data.Settings
API = data.API
RMD = data.RMD
env = data.env
service = data.service
plr = data.plr
create = data.create
createSimple = data.createSimple
()
Explorer = Apps.Explorer
Properties = Apps.Properties
ScriptViewer = Apps.ScriptViewer
Notebook = Apps.Notebook
()
Explorer = {}
nodes,tree,listEntries,explorerOrders,searchResults,specResults = {},{},{},{},{},{}
expanded
entryTemplate,treeFrame,toolBar,descendantAddedCon,descendantRemovingCon,itemChangedCon
ffa = .FindFirstAncestorWhichIsA
getDescendants = .GetDescendants
getTextSize = service.TextService.GetTextSize
updateDebounce,refreshDebounce = ,
nilNode = {Obj = .()}
idCounter =
scrollV,scrollH,selection,clipboard
renameBox,renamingNode,searchFunc
sortingEnabled,autoUpdateSearch
, = ,
nilMap,nilCons = {},{}
connectSignal = .DescendantAdded.Connect
addObject,removeObject,moveObject = ,,
addObject = (root)
nodes[root]
isNil =
rootParObj = (root,)
par = nodes[rootParObj]
par
nilMap[root]
nilCons[root] = nilCons[root] {
(root.ChildAdded,addObject),
(root.AncestryChanged,moveObject),
}
par = nilNode
isNil =
nilMap[rootParObj] par == nilNode
nilMap[root] =
nilCons[root] = nilCons[root] {
(root.ChildAdded,addObject),
(root.AncestryChanged,moveObject),
}
isNil =
newNode = {Obj = root, Parent = par}
nodes[root] = newNode
sortingEnabled expanded[par] par.Sorted
left,right = ,#par
floor = .floor
sorter = Explorer.NodeSorter
pos = (right == )
pos
left >= right
(newNode,par[left])
pos = left
pos = left+
mid = ((left+right)/)
(newNode,par[mid])
right = mid-
left = mid+
.(par,pos,newNode)
par[#par+] = newNode
par.Sorted =
insts = (root)
i = ,#insts
obj = insts[i]
nodes[obj]
par = nodes[(obj,)]
par
newNode = {Obj = obj, Parent = par}
nodes[obj] = newNode
par[#par+] = newNode
isNil
nilMap[obj] =
nilCons[obj] = nilCons[obj] {
(obj.ChildAdded,addObject),
(obj.AncestryChanged,moveObject),
}
searchFunc autoUpdateSearch
({newNode})
updateDebounce Explorer.(par)
expanded[par]
Explorer.()
refreshDebounce
Explorer.()
removeObject = (root)
node = nodes[root]
node
nilMap[node.Obj]
(node.Obj)
par = node.Parent
par
par.HasDel =
(root)
i = ,#root
node = root[i]
node.Del
nodes[node.Obj] =
#node > (node)
(node)
node.Del =
nodes[root] =
par updateDebounce Explorer.(par)
expanded[par]
Explorer.()
refreshDebounce
Explorer.()
moveObject = (obj)
node = nodes[obj]
node
oldPar = node.Parent
newPar = nodes[(obj,)]
oldPar == newPar
newPar
nilMap[obj]
newPar = nilNode
nilMap[newPar.Obj] newPar == nilNode
nilMap[obj] =
nilCons[obj] = nilCons[obj] {
(obj.ChildAdded,addObject),
(obj.AncestryChanged,moveObject),
}
oldPar
parPos = .(oldPar,node)
parPos .(oldPar,parPos)
node.Id =
node.Parent = newPar
sortingEnabled expanded[newPar] newPar.Sorted
left,right = ,#newPar
floor = .floor
sorter = Explorer.NodeSorter
pos = (right == )
pos
left >= right
(node,newPar[left])
pos = left
pos = left+
mid = ((left+right)/)
(node,newPar[mid])
right = mid-
left = mid+
.(newPar,pos,node)
newPar[#newPar+] = node
newPar.Sorted =
searchFunc searchResults[node]
currentNode = node.Parent
currentNode ( searchResults[currentNode] expanded[currentNode] == )
expanded[currentNode] =
searchResults[currentNode] =
currentNode = currentNode.Parent
updateDebounce (Explorer.(newPar) Explorer.(oldPar))
expanded[newPar] expanded[oldPar]
Explorer.()
refreshDebounce
Explorer.()
Explorer.ViewWidth =
Explorer.Index =
Explorer.EntryIndent =
Explorer.FreeWidth =
Explorer.GuiElems = {}
Explorer.InitRenameBox = ()
renameBox = ({{,,{BackgroundColor3=.(,,),BorderColor3=.(,,),BorderMode=,ClearTextOnFocus=,Font=,Name=,PlaceholderColor3=.(,,),Position=.(,,,),Size=.(,,,),Text=,TextColor3=.(,,),TextSize=,TextXAlignment=,Visible=,ZIndex=}}})
renameBox.Parent = Explorer.Window.GuiElems.Content.List
renameBox.FocusLost:(()
renamingNode
(() renamingNode.Obj.Name = renameBox.Text )
renamingNode =
Explorer.()
)
renameBox.Focused:(()
renameBox.SelectionStart =
renameBox.CursorPosition = #renameBox.Text +
)
Explorer.SetRenamingNode = (node)
renamingNode = node
renameBox.Text = (node.Obj)
renameBox:()
Explorer.()
Explorer.SetSortingEnabled = (val)
sortingEnabled = val
Settings.Explorer.Sorting = val
Explorer.UpdateView = ()
maxNodes = .(treeFrame.AbsoluteSize.Y / )
maxX = treeFrame.AbsoluteSize.X
totalWidth = Explorer.ViewWidth + Explorer.FreeWidth
scrollV.VisibleSpace = maxNodes
scrollV.TotalSpace = #tree +
scrollH.VisibleSpace = maxX
scrollH.TotalSpace = totalWidth
scrollV.Gui.Visible = #tree + > maxNodes
scrollH.Gui.Visible = totalWidth > maxX
oldSize = treeFrame.Size
treeFrame.Size = .(,(scrollV.Gui.Visible - ),,(scrollH.Gui.Visible - -))
oldSize ~= treeFrame.Size
Explorer.()
scrollV:()
scrollH:()
renameBox.Size = .(,maxX-,,)
scrollV.Gui.Visible scrollH.Gui.Visible
scrollV.Gui.Size = .(,,,-)
scrollH.Gui.Size = .(,-,,)
Explorer.Window.GuiElems.Content.ScrollCorner.Visible =
scrollV.Gui.Size = .(,,,-)
scrollH.Gui.Size = .(,,,)
Explorer.Window.GuiElems.Content.ScrollCorner.Visible =
Explorer.Index = scrollV.Index
Explorer.NodeSorter = (a,b)
a.Del b.Del
aClass = a.Class
bClass = b.Class
aClass aClass = a.Obj.ClassName a.Class = aClass
bClass bClass = b.Obj.ClassName b.Class = bClass
aOrder = explorerOrders[aClass]
bOrder = explorerOrders[bClass]
aOrder aOrder = RMD.Classes[aClass] (RMD.Classes[aClass].ExplorerOrder) explorerOrders[aClass] = aOrder
bOrder bOrder = RMD.Classes[bClass] (RMD.Classes[bClass].ExplorerOrder) explorerOrders[bClass] = bOrder
aOrder ~= bOrder
aOrder < bOrder
aName,bName = (a.Obj),(b.Obj)
aName ~= bName
aName < bName
aClass ~= bClass
aClass < bClass
aId = a.Id aId aId = idCounter idCounter = (idCounter+)% a.Id = aId
bId = b.Id bId bId = idCounter idCounter = (idCounter+)% b.Id = bId
aId < bId
Explorer.Update = ()
.(tree)
maxNameWidth,maxDepth,count = ,,
nameCache = {}
font = .Font.SourceSans
size = .(.huge,)
useNameWidth = Settings.Explorer.UseNameWidth
tSort = .sort
sortFunc = Explorer.NodeSorter
isSearching = (expanded == Explorer.SearchExpanded)
textServ = service.TextService
(root,depth)
depth > maxDepth maxDepth = depth
depth = depth +
sortingEnabled root.Sorted
(root,sortFunc)
root.Sorted =
i = ,#root
n = root[i]
(isSearching searchResults[n]) n.Del
useNameWidth
nameWidth = n.NameWidth
nameWidth
objName = (n.Obj)
nameWidth = nameCache[objName]
nameWidth
nameWidth = (textServ,objName,,font,size).X
nameCache[objName] = nameWidth
n.NameWidth = nameWidth
nameWidth > maxNameWidth
maxNameWidth = nameWidth
tree[count] = n
count = count +
expanded[n] #n >
(n,depth)
(nodes[],)
env.getnilinstances
(isSearching searchResults[nilNode])
tree[count] = nilNode
count = count +
expanded[nilNode]
(nilNode,)
Explorer.MaxNameWidth = maxNameWidth
Explorer.MaxDepth = maxDepth
Explorer.ViewWidth = useNameWidth Explorer.EntryIndent*maxDepth + maxNameWidth + Explorer.EntryIndent*maxDepth +
Explorer.()
Explorer.StartDrag = (offX,offY)
Explorer.Dragging
Explorer.Dragging =
dragTree = treeFrame:()
dragTree:()
i,v (listEntries)
node = tree[i + Explorer.Index]
node selection.Map[node]
clone = v:()
clone.Active =
clone.Indent.Expand.Visible =
clone.Parent = dragTree
newGui = .()
newGui.DisplayOrder = Main.DisplayOrders.Menu
dragTree.Parent = newGui
Lib.(newGui)
dragOutline = ({
{,,{BackgroundColor3=.(,,),BackgroundTransparency=,Name=,Size=.(,,,),}},
{,,{BackgroundColor3=.(,,),BorderSizePixel=,Name=,Parent={},Size=.(,,,),ZIndex=,}},
{,,{BackgroundColor3=.(,,),BorderSizePixel=,Name=,Parent={},Position=.(,,,-),Size=.(,,,),ZIndex=,}},
{,,{BackgroundColor3=.(,,),BorderSizePixel=,Name=,Parent={},Size=.(,,,),ZIndex=,}},
{,,{BackgroundColor3=.(,,),BorderSizePixel=,Name=,Parent={},Position=.(,-,,),Size=.(,,,),ZIndex=,}},
})
dragOutline.Parent = treeFrame
mouse = Main.Mouse service.Players.LocalPlayer:()
()
posX = mouse.X - offX
posY = mouse.Y - offY
dragTree.Position = .(,posX,,posY)
i = ,#listEntries
entry = listEntries[i]
Lib.(entry)
dragOutline.Position = .(,entry.Indent.Position.X.Offset-scrollH.Index,,entry.Position.Y.Offset)
dragOutline.Size = .(,entry.Size.X.Offset-entry.Indent.Position.X.Offset,,)
dragOutline.Visible =
dragOutline.Visible =
()
input = service.UserInputService
mouseEvent,releaseEvent
mouseEvent = input.InputChanged:((input)
input.UserInputType == .UserInputType.MouseMovement
()
)
releaseEvent = input.InputEnded:((input)
input.UserInputType == .UserInputType.MouseButton1
releaseEvent:()
mouseEvent:()
newGui:()
dragOutline:()
Explorer.Dragging =
i = ,#listEntries
Lib.(listEntries[i])
node = tree[i + Explorer.Index]
node
selection.Map[node]
newPar = node.Obj
sList = selection.List
i = ,#sList
n = sList[i]
(() n.Obj.Parent = newPar )
Explorer.(sList[])
)
Explorer.NewListEntry = (index)
newEntry = entryTemplate:()
newEntry.Position = .(,,,*(index-))
isRenaming =
newEntry.InputBegan:((input)
node = tree[index + Explorer.Index]
node selection.Map[node] input.UserInputType ~= .UserInputType.MouseMovement
newEntry.Indent.BackgroundColor3 = Settings.Theme.Button
newEntry.Indent.BorderSizePixel =
newEntry.Indent.BackgroundTransparency =
)
newEntry.InputEnded:((input)
node = tree[index + Explorer.Index]
node selection.Map[node] input.UserInputType ~= .UserInputType.MouseMovement
newEntry.Indent.BackgroundTransparency =
)
newEntry.MouseButton1Down:(()
)
newEntry.MouseButton1Up:(()
)
newEntry.InputBegan:((input)
input.UserInputType == .UserInputType.MouseButton1
releaseEvent,mouseEvent
mouse = Main.Mouse plr:()
startX = mouse.X
startY = mouse.Y
listOffsetX = startX - treeFrame.AbsolutePosition.X
listOffsetY = startY - treeFrame.AbsolutePosition.Y
releaseEvent = :().InputEnded:((input)
input.UserInputType == .UserInputType.MouseButton1
releaseEvent:()
mouseEvent:()
)
mouseEvent = :().InputChanged:((input)
input.UserInputType == .UserInputType.MouseMovement
deltaX = mouse.X - startX
deltaY = mouse.Y - startY
dist = .(deltaX^ + deltaY^)
dist >
releaseEvent:()
mouseEvent:()
isRenaming =
Explorer.(listOffsetX,listOffsetY)
)
)
newEntry.MouseButton2Down:(()
)
newEntry.Indent.Expand.InputBegan:((input)
node = tree[index + Explorer.Index]
node input.UserInputType ~= .UserInputType.MouseMovement
Explorer.MiscIcons:(newEntry.Indent.Expand.Icon, expanded[node] )
)
newEntry.Indent.Expand.InputEnded:((input)
node = tree[index + Explorer.Index]
node input.UserInputType ~= .UserInputType.MouseMovement
Explorer.MiscIcons:(newEntry.Indent.Expand.Icon, expanded[node] )
)
newEntry.Indent.Expand.MouseButton1Down:(()
node = tree[index + Explorer.Index]
node #node ==
expanded[node] = expanded[node]
Explorer.()
Explorer.()
)
newEntry.Parent = treeFrame
newEntry
Explorer.Refresh = ()
maxNodes = .(.((treeFrame.AbsoluteSize.Y) / ),)
renameNodeVisible =
isa = .IsA
i = ,maxNodes
entry = listEntries[i]
listEntries[i] entry = Explorer.(i) listEntries[i] = entry Explorer.ClickSystem:(entry)
node = tree[i + Explorer.Index]
node
obj = node.Obj
depth = Explorer.EntryIndent*Explorer.(node)
entry.Visible =
entry.Position = .(,-scrollH.Index,,entry.Position.Y.Offset)
entry.Size = .(,Explorer.ViewWidth,,)
entry.Indent.EntryName.Text = (node.Obj)
entry.Indent.Position = .(,depth,,)
entry.Indent.Size = .(,-depth,,)
entry.Indent.EntryName.TextTruncate = (Settings.Explorer.UseNameWidth .TextTruncate.None .TextTruncate.AtEnd)
((obj,) (obj,)) obj.Disabled
Explorer.MiscIcons:(entry.Indent.Icon, (obj,) )
rmdEntry = RMD.Classes[obj.ClassName]
Explorer.ClassIcons:(entry.Indent.Icon, rmdEntry rmdEntry.ExplorerImageIndex )
selection.Map[node]
entry.Indent.BackgroundColor3 = Settings.Theme.ListSelection
entry.Indent.BorderSizePixel =
entry.Indent.BackgroundTransparency =
Lib.(entry)
entry.Indent.BackgroundColor3 = Settings.Theme.Button
entry.Indent.BackgroundTransparency =
node == renamingNode
renameNodeVisible =
renameBox.Position = .(,depth+-scrollH.Index,,entry.Position.Y.Offset+)
renameBox.Visible =
#node > expanded[node] ~=
Lib.(entry.Indent.Expand)
Explorer.MiscIcons:(entry.Indent.Expand.Icon, expanded[node] )
Explorer.MiscIcons:(entry.Indent.Expand.Icon, expanded[node] )
entry.Indent.Expand.Visible =
entry.Indent.Expand.Visible =
entry.Visible =
renameNodeVisible
renameBox.Visible =
i = maxNodes+, #listEntries
Explorer.ClickSystem:(listEntries[i])
listEntries[i]:()
listEntries[i] =
Explorer.PerformUpdate = (instant)
updateDebounce =
Lib.( instant )
updateDebounce
updateDebounce =
Explorer.Window:()
Explorer.()
Explorer.()
Explorer.ForceUpdate = (norefresh)
updateDebounce =
Explorer.()
norefresh Explorer.()
Explorer.PerformRefresh = ()
refreshDebounce =
Lib.()
refreshDebounce =
updateDebounce Explorer.Window:()
Explorer.()
Explorer.IsNodeVisible = (node)
node
curNode = node.Parent
curNode
expanded[curNode]
curNode = curNode.Parent
Explorer.NodeDepth = (node)
depth =
node == nilNode
curNode = node.Parent
curNode
curNode == nilNode depth = depth +
curNode = curNode.Parent
depth = depth +
depth
Explorer.SetupConnections = ()
descendantAddedCon descendantAddedCon:()
descendantRemovingCon descendantRemovingCon:()
itemChangedCon itemChangedCon:()
Main.Elevated
descendantAddedCon = .DescendantAdded:(addObject)
descendantRemovingCon = .DescendantRemoving:(removeObject)
descendantAddedCon = .DescendantAdded:((obj) (addObject,obj) )
descendantRemovingCon = .DescendantRemoving:((obj) (removeObject,obj) )
Settings.Explorer.UseNameWidth
itemChangedCon = .ItemChanged:((obj,prop)
prop == nodes[obj]
(obj)
prop == nodes[obj]
nodes[obj].NameWidth =
)
itemChangedCon = .ItemChanged:((obj,prop)
prop == nodes[obj]
(obj)
)
Explorer.ViewNode = (node)
node
Explorer.(node)
Explorer.()
visibleSpace = scrollV.VisibleSpace
i,v ,tree
v == node
relative = i -
Explorer.Index > relative
scrollV.Index = relative
Explorer.Index + visibleSpace - <= relative
scrollV.Index = relative - visibleSpace +
scrollV:() Explorer.Index = scrollV.Index
Explorer.()
Explorer.ViewObj = (obj)
Explorer.(nodes[obj])
Explorer.MakeNodeVisible = (node,expandRoot)
node
hasExpanded =
expandRoot expanded[node]
expanded[node] =
hasExpanded =
currentNode = node.Parent
currentNode
hasExpanded =
expanded[currentNode] =
currentNode = currentNode.Parent
hasExpanded updateDebounce
.(Explorer.PerformUpdate)()
Explorer.ShowRightClick = ()
context = Explorer.RightClickContext
context:()
sList = selection.List
sMap = selection.Map
emptyClipboard = #clipboard ==
presentClasses = {}
apiClasses = API.Classes
i = ,#sList
node = sList[i]
class = node.Class
class class = node.Obj.ClassName node.Class = class
curClass = apiClasses[class]
curClass presentClasses[curClass.Name]
presentClasses[curClass.Name] =
curClass = curClass.Superclass
context:()
context:()
context:(,emptyClipboard)
context:()
context:()
context:(,#sList ~= )
context:()
context:()
context:()
context:()
context:()
context:()
context:()
context:()
expanded == Explorer.SearchExpanded
context:()
env.setclipboard
context:()
context:()
context:()
context:()
context:()
context:()
context:()
context:()
presentClasses[] presentClasses[]
context:()
context:()
presentClasses[]
context:()
presentClasses[]
context:()
sMap[nilNode]
context:()
context:()
Explorer.LastRightClickX,Explorer.LastRightClickY = Main.Mouse.X,Main.Mouse.Y
context:()
Explorer.InitRightClick = ()
context = Lib.ContextMenu.()
context:(,{Name = , IconMap = Explorer.MiscIcons, Icon = , DisabledIcon = , Shortcut = , OnClick = ()
destroy,clone = .Destroy,.Clone
sList,newClipboard = selection.List,{}
count =
i = ,#sList
inst = sList[i].Obj
s,cloned = (clone,inst)
s cloned
newClipboard[count] = cloned
count = count +
(destroy,inst)
clipboard = newClipboard
selection:()
})
context:(,{Name = , IconMap = Explorer.MiscIcons, Icon = , DisabledIcon = , Shortcut = , OnClick = ()
clone = .Clone
sList,newClipboard = selection.List,{}
count =
i = ,#sList
inst = sList[i].Obj
s,cloned = (clone,inst)
s cloned
newClipboard[count] = cloned
count = count +
clipboard = newClipboard
})
context:(,{Name = , IconMap = Explorer.MiscIcons, Icon = , DisabledIcon = , Shortcut = , OnClick = ()
sList = selection.List
newSelection = {}
count =
i = ,#sList
node = sList[i]
inst = node.Obj
Explorer.(node,)
c = ,#clipboard
cloned = clipboard[c]:()
cloned
cloned.Parent = inst
clonedNode = nodes[cloned]
clonedNode newSelection[count] = clonedNode count = count +
selection:(newSelection)
#newSelection >
Explorer.(newSelection[])
})
context:(,{Name = , IconMap = Explorer.MiscIcons, Icon = , DisabledIcon = , Shortcut = , OnClick = ()
clone = .Clone
sList = selection.List
newSelection = {}
count =
i = ,#sList
node = sList[i]
inst = node.Obj
instPar = node.Parent node.Parent.Obj
Explorer.(node)
s,cloned = (clone,inst)
s cloned
cloned.Parent = instPar
clonedNode = nodes[cloned]
clonedNode newSelection[count] = clonedNode count = count +
selection:(newSelection)
#newSelection >
Explorer.(newSelection[])
})
context:(,{Name = , IconMap = Explorer.MiscIcons, Icon = , DisabledIcon = , Shortcut = , OnClick = ()
destroy = .Destroy
sList = selection.List
i = ,#sList
(destroy,sList[i].Obj)
selection:()
})
context:(,{Name = , IconMap = Explorer.MiscIcons, Icon = , DisabledIcon = , Shortcut = , OnClick = ()
sList = selection.List
sList[]
Explorer.(sList[])
})
context:(,{Name = , IconMap = Explorer.MiscIcons, Icon = , DisabledIcon = , Shortcut = , OnClick = ()
sList = selection.List
#sList ==
model = .(,sList[#sList].Obj.Parent)
i = ,#sList
(() sList[i].Obj.Parent = model )
nodes[model]
selection:(nodes[model])
Explorer.(nodes[model])
})
context:(,{Name = , IconMap = Explorer.MiscIcons, Icon = , DisabledIcon = , Shortcut = , OnClick = ()
newSelection = {}
count =
isa = .IsA
(node)
par = node.Parent.Obj
ch = {}
chCount =
i = ,#node
n = node[i]
newSelection[count] = n
ch[chCount] = n
count = count +
chCount = chCount +
i = ,#ch
(() ch[i].Obj.Parent = par )
node.Obj:()
i,v ,selection.List
(v.Obj,)
(v)
selection:(newSelection)
#newSelection >
Explorer.(newSelection[])
})
context:(,{Name = , IconMap = Explorer.MiscIcons, Icon = , DisabledIcon = , OnClick = ()
newSelection = {}
count =
sList = selection.List
i = ,#sList
node = sList[i]
ind = ,#node
cNode = node[ind]
ind == Explorer.(cNode)
newSelection[count] = cNode
count = count +
selection:(newSelection)
#newSelection >
Explorer.(newSelection[])
Explorer.()
})
context:(,{Name = , IconMap = Explorer.MiscIcons, Icon = , OnClick = ()
newSelection = {}
count =
sList = selection.List
i = ,#sList
node = sList[i]
node.Parent
newSelection[count] = node.Parent
count = count +
selection:(newSelection)
#newSelection >
Explorer.(newSelection[])
Explorer.()
})
context:(,{Name = , IconMap = Explorer.MiscIcons, Icon = , OnClick = ()
sList = selection.List
isa = .IsA
hrp = plr.Character plr.Character:()
hrp
i = ,#sList
node = sList[i]
(node.Obj,)
hrp.CFrame = node.Obj.CFrame + Settings.Explorer.TeleportToOffset
(node.Obj,)
node.Obj.PrimaryPart
hrp.CFrame = node.Obj.PrimaryPart.CFrame + Settings.Explorer.TeleportToOffset
part = node.Obj:(,)
part nodes[part]
hrp.CFrame = nodes[part].Obj.CFrame + Settings.Explorer.TeleportToOffset
})
context:(,{Name = , OnClick = ()
sList = selection.List
(node)
expanded[node] =
i = ,#node
#node[i] >
(node[i])
i = ,#sList
(sList[i])
Explorer.()
})
context:(,{Name = , OnClick = ()
sList = selection.List
(node)
expanded[node] =
i = ,#node
#node[i] >
(node[i])
i = ,#sList
(sList[i])
Explorer.()
})
context:(,{Name = , OnClick = ()
newSelection = {}
count =
sList = selection.List
i = ,#sList
newSelection[count] = sList[i]
count = count +
selection:(newSelection)
Explorer.()
#newSelection >
Explorer.(newSelection[])
})
context:(,{Name = , OnClick = ()
sList = selection.List
#sList ==
env.(Explorer.(sList[].Obj))
#sList >
resList = {}
count =
i = ,#sList
path = ..Explorer.(sList[i].Obj)..
#path >
resList[count] = path
count = count+
resList[count] =
env.(.(resList,))
})
context:(,{Name = , IconMap = Explorer.MiscIcons, Icon = , OnClick = ()
mouse = Main.Mouse
x,y = Explorer.LastRightClickX mouse.X, Explorer.LastRightClickY mouse.Y
Explorer.InsertObjectContext:(x,y)
})
context:(,{Name = , IconMap = Explorer.ClassIcons, Icon = , OnClick = ()
})
context:(,{Name = , IconMap = Explorer.ClassIcons, Icon = , OnClick = ()
})
context:(,{Name = , IconMap = Explorer.MiscIcons, Icon = , OnClick = ()
})
context:(,{Name = , OnClick = ()
})
context:(,{Name = , IconMap = Explorer.MiscIcons, Icon = , OnClick = ()
})
context:(,{Name = , IconMap = Explorer.ClassIcons, Icon = , OnClick = ()
sList = selection.List
isa = .IsA
i = ,#sList
node = sList[i]
(node.Obj,) (node.Obj,)
.CurrentCamera.CameraSubject = node.Obj
, OnRightClick = ()
.CurrentCamera.CameraSubject = plr.Character
})
context:(,{Name = , IconMap = Explorer.MiscIcons, Icon = , OnClick = ()
scr = selection.List[] selection.List[].Obj
scr ScriptViewer.(scr)
})
context:(,{Name = , IconMap = Explorer.ClassIcons, Icon = , OnClick = ()
newSelection = {}
count =
sList = selection.List
isa = .IsA
i = ,#sList
node = sList[i]
(node.Obj,) nodes[node.Obj.Character]
newSelection[count] = nodes[node.Obj.Character]
count = count +
selection:(newSelection)
#newSelection >
Explorer.(newSelection[])
Explorer.()
})
context:(,{Name = , OnClick = ()
Explorer.()
})
context:(,{Name = , OnClick = ()
Explorer.()
})
Explorer.RightClickContext = context
Explorer.HideNilInstances = ()
.(nilMap)
disconnectCon = .().ChildAdded:(() ).Disconnect
i,v ,nilCons
(v[])
(v[])
.(nilCons)
i = ,#nilNode
.(removeObject)(nilNode[i].Obj)
Explorer.()
Explorer.()
Explorer.RefreshNilInstances = ()
env.getnilinstances
nilInsts = env.()
=
getDescs = .GetDescendants
i = ,#nilInsts
obj = nilInsts[i]
obj ~=
nilMap[obj] =
descs = (obj)
j = ,#descs
nilMap[descs[j]] =
i = ,#nilInsts
obj = nilInsts[i]
node = nodes[obj]
node .(addObject)(obj)
Explorer.()
Explorer.()
Explorer.GetInstancePath = (obj)
ffc = .FindFirstChild
getCh = .GetChildren
path =
curObj = obj
ts =
match = .match
gsub = .gsub
tableFind = .find
useGetCh = Settings.Explorer.CopyPathUseGetChildren
formatLuaString = Lib.FormatLuaString
curObj
curObj ==
path = ..path
className = curObj.ClassName
curName = (curObj)
indexName
(curName,)
indexName = ..curName
cleanName = (curName)
indexName = ..cleanName..
parObj = curObj.Parent
parObj
fc = (parObj,curName)
useGetCh fc fc ~= curObj
parCh = (parObj)
fcInd = (parCh,curObj)
indexName = ..fcInd..
parObj == API.Classes[className] API.Classes[className].Tags.Service
indexName = ..className..
path = indexName..path
curObj = parObj
path
Explorer.InitInsertObject = ()
context = Lib.ContextMenu.()
context.SearchEnabled =
context.MaxHeight =
context:({
ContentColor = Settings.Theme.Main2,
OutlineColor = Settings.Theme.Outline1,
DividerColor = Settings.Theme.Outline1,
TextColor = Settings.Theme.Text,
HighlightColor = Settings.Theme.ButtonHover
})
classes = {}
i,class ,API.Classes
tags = class.Tags
tags.NotCreatable tags.Service
rmdEntry = RMD.Classes[class.Name]
classes[#classes+] = {class,rmdEntry rmdEntry.ClassCategory }
.(classes,(a,b)
a[] ~= b[]
a[] < b[]
a[].Name < b[].Name
)
(className)
sList = selection.List
instNew = .new
i = ,#sList
node = sList[i]
obj = node.Obj
Explorer.(node,)
(instNew,className,obj)
lastCategory =
i = ,#classes
class = classes[i][]
rmdEntry = RMD.Classes[class.Name]
iconInd = rmdEntry (rmdEntry.ExplorerImageIndex)
category = classes[i][]
lastCategory ~= category
context:(category)
lastCategory = category
context:({Name = class.Name, IconMap = Explorer.ClassIcons, Icon = iconInd, OnClick = onClick})
Explorer.InsertObjectContext = context
Explorer.SearchFilters = {
Comparison = {
[] = (argString)
lower = .lower
find = .find
classQuery = .(argString)[]
classQuery
classQuery = (classQuery)
className
class,_ (API.Classes)
cName = (class)
cName == classQuery
className = class
(cName,classQuery,,)
className = class
className
{
Headers = {},
Predicate = ..className..
}
,
[] = (argString)
{
Headers = {},
Predicate =
}
,
[] = (argString)
{
Headers = {},
Predicate =
}
,
[] = (argString)
num = (argString)
num
service.Players.LocalPlayer.Character service.Players.LocalPlayer.Character:() service.Players.LocalPlayer.Character.HumanoidRootPart:()
{
Headers = {, },
Setups = {},
ObjectDefs = {},
Predicate = ..num..
}
,
},
Specific = {
[] = ()
() service.Players:()
,
[] = ()
env.getloadedmodules
,
},
Default = (argString,caseSensitive)
cleanString = argString:(,):(,)
caseSensitive
{
Headers = {},
ObjectDefs = {},
Predicate = .. cleanString ..
}
{
Headers = {,,},
ObjectDefs = {},
Predicate = .. cleanString:() ..
}
,
SpecificDefault = (n)
{
Headers = {},
ObjectDefs = {..n....n..},
Predicate = ..n
}
,
}
Explorer.BuildSearchFunc = (query)
specFilterList,specMap = {},{}
finalPredicate =
rep = .rep
formatQuery = query:(,):(,(str) (,#str) )
headers = {}
objectDefs = {}
setups = {}
find = .find
sub = .sub
lower = .lower
match = .match
ops = {
[] = ,
[] = ,
[] = ,
[] =
}
filterCount =
compFilters = Explorer.SearchFilters.Comparison
specFilters = Explorer.SearchFilters.Specific
init =
lastOp =
(dat)
dat.Headers
t = dat.Headers
i = ,#t
headers[t[i]] =
dat.ObjectDefs
t = dat.ObjectDefs
i = ,#t
objectDefs[t[i]] =
dat.Setups
t = dat.Setups
i = ,#t
setups[t[i]] =
finalPredicate = finalPredicate..dat.Predicate
found = {}
foundData = {}
find = .find
sub = .sub
(str,pattern)
count = #found+
init =
sz = #pattern
x,y,extra = (str,pattern,init,)
x
found[count] = x
foundData[x] = {sz,pattern}
count = count+
init = y+
x,y,extra = (str,pattern,init,)
start = ()
(formatQuery,)
(formatQuery,)
(formatQuery,)
(formatQuery,)
.(found)
.(found,#formatQuery+)
(str)
len = #str
(str,,) == (str,len,len) ==
(str,,len-)
i = ,#found
nextInd = found[i]
nextData = foundData[nextInd] {}
op = ops[nextData[]]
term = (query,init,nextInd-)
term = (term,)
#term >
(term,,) ==
term = (term,)
finalPredicate = finalPredicate..
qTerm = (term)
qTerm
(Explorer.SearchFilters.(qTerm,))
x,y = (term,)
x
first = (term,x,y)
specifier = (first,,) == ((first,))
compFunc = specifier compFilters[specifier]
specFunc = specifier specFilters[specifier]
compFunc
argStr = (term,y+)
ret = ((argStr) argStr)
ret
(ret)
finalPredicate = finalPredicate..
specFunc
argStr = (term,y+)
ret = ((argStr) argStr)
ret
specMap[term]
specFilterList[#specFilterList + ] = ret
specMap[term] = #specFilterList
(Explorer.SearchFilters.(specMap[term]))
finalPredicate = finalPredicate..
(Explorer.SearchFilters.(term))
op
finalPredicate = finalPredicate..op
op == (#term > lastOp == )
lastOp = op
init = nextInd+nextData[]
finalSetups =
finalHeaders =
finalObjectDefs =
setup,_ ,setups finalSetups = finalSetups..setup..
header,_ ,headers finalHeaders = finalHeaders..header..
oDef,_ ,objectDefs finalObjectDefs = finalObjectDefs..oDef..
template =
funcStr = template:(finalHeaders,finalSetups,finalObjectDefs,finalPredicate)
s,func = (,funcStr)
s func ,specFilterList
env = ({[] = searchResults, [] = nodes, [] = Explorer, [] = specResults,
[] = service},{__index = ()})
(func,env)
(),specFilterList
Explorer.DoSearch = (query)
.(Explorer.SearchExpanded)
.(searchResults)
expanded = (#query == Explorer.Expanded Explorer.SearchExpanded)
searchFunc =
#query >
expandTable = Explorer.SearchExpanded
specFilters
lower = .lower
find = .find
=
lowerQuery = (query)
(root)
expandedpar =
i = ,#root
node = root[i]
obj = node.Obj
(((obj)),lowerQuery,,)
expandTable[node] =
searchResults[node] =
expandedpar
parnode = node.Parent
parnode ( searchResults[parnode] expandTable[parnode] == )
expanded[parnode] =
searchResults[parnode] =
parnode = parnode.Parent
expandedpar =
#node > (node)
Main.Elevated
start = ()
searchFunc,specFilters = Explorer.(query)
searchFunc = defaultSearch
specFilters
.(specResults)
i = ,#specFilters
resMap = {}
specResults[i] = resMap
objs = specFilters[i]()
c = ,#objs
node = nodes[objs[c]]
node
resMap[node] =
searchFunc
start = ()
(nodes[])
(nilNode)
Explorer.()
Explorer.ClearSearch = ()
Explorer.GuiElems.SearchBar.Text =
expanded = Explorer.Expanded
searchFunc =
Explorer.InitSearch = ()
searchBox = Explorer.GuiElems.ToolBar.SearchFrame.SearchBox
Explorer.GuiElems.SearchBar = searchBox
Lib.ViewportTextBox.(searchBox)
searchBox.FocusLost:(()
Explorer.(searchBox.Text)
)
Explorer.InitEntryTemplate = ()
entryTemplate = ({
{,,{AutoButtonColor=,BackgroundColor3=.(,,),BackgroundTransparency=,BorderColor3=.(,,),Font=,Name=,Position=.(,,,),Size=.(,,,),Text=,TextSize=,}},
{,,{BackgroundColor3=.(,,),BackgroundTransparency=,BorderColor3=.(,,),BorderSizePixel=,Name=,Parent={},Position=.(,,,),Size=.(,-,,),}},
{,,{BackgroundColor3=.(,,),BackgroundTransparency=,Font=,Name=,Parent={},Position=.(,,,),Size=.(,-,,),Text=,TextColor3=.(,,),TextSize=,TextXAlignment=,}},
{,,{BackgroundColor3=.(,,),BackgroundTransparency=,ClipsDescendants=,Font=,Name=,Parent={},Position=.(,-,,),Size=.(,,,),Text=,TextSize=,}},
{,,{BackgroundColor3=.(,,),BackgroundTransparency=,Image=,ImageRectOffset=.(,),ImageRectSize=.(,),Name=,Parent={},Position=.(,,,),ScaleType=,Size=.(,,,),}},
{,,{BackgroundColor3=.(,,),BackgroundTransparency=,Image=,ImageRectOffset=.(,),ImageRectSize=.(,),Name=,Parent={},Position=.(,,,),ScaleType=,Size=.(,,,),}},
})
sys = Lib.ClickSystem.()
sys.AllowedButtons = {,}
sys.OnDown:((item,combo,button)
ind = .(listEntries,item)
ind
node = tree[ind + Explorer.Index]
node
entry = listEntries[ind]
button ==
combo ==
node.Obj:()
ScriptViewer.(node.Obj)
#node > expanded[node] ~=
expanded[node] = expanded[node]
Explorer.()
Properties.(node.Obj)
sys.IsRenaming =
sys.IsRenaming = selection.Map[node]
Lib.()
selection.Piviot
fromIndex = .(tree,selection.Piviot)
toIndex = .(tree,node)
fromIndex toIndex
fromIndex,toIndex = .(fromIndex,toIndex),.(fromIndex,toIndex)
sList = selection.List
i = #sList,,-
elem = sList[i]
selection.ShiftSet[elem]
selection.Map[elem] =
.(sList,i)
selection.ShiftSet = {}
i = fromIndex,toIndex
elem = tree[i]
selection.Map[elem]
selection.ShiftSet[elem] =
selection.Map[elem] =
sList[#sList+] = elem
selection.Changed:()
Lib.()
selection.ShiftSet = {}
selection.Map[node] selection:(node) selection:(node)
selection.Piviot = node
sys.IsRenaming =
selection.Map[node]
selection.ShiftSet = {}
selection:(node)
selection.Piviot = node
button ==
Properties.(node.Obj)
Lib.() selection.Map[node]
selection.ShiftSet = {}
selection:(node)
selection.Piviot = node
Explorer.()
Explorer.()
)
sys.OnRelease:((item,combo,button)
ind = .(listEntries,item)
ind
node = tree[ind + Explorer.Index]
node
button ==
selection.Map[node] Lib.() Lib.()
selection.ShiftSet = {}
selection:(node)
selection.Piviot = node
Explorer.()
id = sys.ClickId
Lib.(sys.ComboTime)
combo == id == sys.ClickId sys.IsRenaming selection.Map[node]
Explorer.(node)
button ==
Explorer.()
)
Explorer.ClickSystem = sys
Explorer.InitDelCleaner = ()
.(()
fw = Lib.FastWait
processed =
c =
_,node ,nodes
node.HasDel
delInd
i = ,#node
node[i].Del
delInd = i
delInd
i = delInd+,#node
cn = node[i]
cn.Del
node[delInd] = cn
delInd = delInd+
i = delInd,#node
node[i] =
node.HasDel =
processed =
()
c = c +
c >
c =
()
processed refreshDebounce Explorer.()
()
)()
Explorer.UpdateSelectionVisuals = ()
holder = Explorer.SelectionVisualsHolder
isa = .IsA
clone = .Clone
holder
holder = .()
holder.Name =
holder.DisplayOrder = Main.DisplayOrders.Core
Lib.(holder)
Explorer.SelectionVisualsHolder = holder
Explorer.SelectionVisualCons = {}
guiTemplate = ({
{,,{BackgroundColor3=.(,,),BackgroundTransparency=,Size=.(,,,),}},
{,,{BackgroundColor3=.(,,),BorderSizePixel=,Parent={},Position=.(,-,,-),Size=.(,,,),}},
{,,{BackgroundColor3=.(,,),BorderSizePixel=,Parent={},Position=.(,-,,),Size=.(,,,),}},
{,,{BackgroundColor3=.(,,),BorderSizePixel=,Parent={},Position=.(,-,,),Size=.(,,,),}},
{,,{BackgroundColor3=.(,,),BorderSizePixel=,Parent={},Position=.(,,,),Size=.(,,,),}},
})
Explorer.SelectionVisualGui = guiTemplate
boxTemplate = .()
boxTemplate.LineThickness =
boxTemplate.Color3 = .(, , )
Explorer.SelectionVisualBox = boxTemplate
holder:()
i,v (Explorer.SelectionVisualGui:())
v.BackgroundColor3 = .(, , )
attachCons = Explorer.SelectionVisualCons
i = ,#attachCons
attachCons[i].()
.(attachCons)
partEnabled = Settings.Explorer.PartSelectionBox
guiEnabled = Settings.Explorer.GuiSelectionBox
partEnabled guiEnabled
svg = Explorer.SelectionVisualGui
svb = Explorer.SelectionVisualBox
attachTo = Lib.AttachTo
sList = selection.List
count =
boxCount =
workspaceNode = nodes[]
i = ,#sList
boxCount >
node = sList[i]
obj = node.Obj
node ~= workspaceNode
(obj,) guiEnabled
newVisual = (svg)
attachCons[count] = (newVisual,{Target = obj, Resize = })
count = count +
newVisual.Parent = holder
boxCount = boxCount +
(obj,) partEnabled
newBox = (svb)
newBox.Adornee = obj
newBox.Parent = holder
boxCount = boxCount +
Explorer.Init = ()
Explorer.ClassIcons = Lib.IconMap.(,,)
Explorer.MiscIcons = Main.MiscIcons
clipboard = {}
selection = Lib.Set.()
selection.ShiftSet = {}
selection.Changed:(Properties.ShowExplorerProps)
Explorer.Selection = selection
Explorer.()
Explorer.()
Explorer.(Settings.Explorer.Sorting)
Explorer.Expanded = ({},{__mode = })
Explorer.SearchExpanded = ({},{__mode = })
expanded = Explorer.Expanded
nilNode.Obj.Name =
nilNode.Locked =
explorerItems = ({
{,,{Name=,}},
{,,{BackgroundColor3=.(,,),BorderSizePixel=,Name=,Parent={},Size=.(,,,),}},
{,,{BackgroundColor3=.(4901961386204,0.14901961386204,0.14901961386204),BorderColor3=Color3.new(0.1176470592618,0.1176470592618,0.1176470592618),BorderSizePixel=0,Name="SearchFrame",Parent={2},Position=UDim2.new(0,3,0,1),Size=UDim2.new(1,-6,0,18),}},
{4,"TextBox",{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,ClearTextOnFocus=false,Font=3,Name="SearchBox",Parent={3},PlaceholderColor3=Color3.new(0.39215689897537,0.39215689897537,0.39215689897537),PlaceholderText="Search workspace",Position=UDim2.new(0,4,0,0),Size=UDim2.new(1,-24,0,18),Text="",TextColor3=Color3.new(1,1,1),TextSize=14,TextXAlignment=0,}},
{5,"UICorner",{CornerRadius=UDim.new(0,2),Parent={3},}},
{6,"TextButton",{AutoButtonColor=false,BackgroundColor3=Color3.new(0.12549020349979,0.12549020349979,0.12549020349979),BackgroundTransparency=1,BorderSizePixel=0,Font=3,Name="Reset",Parent={3},Position=UDim2.new(1,-17,0,1),Size=UDim2.new(0,16,0,16),Text="",TextColor3=Color3.new(1,1,1),TextSize=14,}},
{7,"ImageLabel",{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Image="rbxassetid://5034718129",ImageColor3=Color3.new(0.39215686917305,0.39215686917305,0.39215686917305),Parent={6},Size=UDim2.new(0,16,0,16),}},
{8,"TextButton",{AutoButtonColor=false,BackgroundColor3=Color3.new(0.12549020349979,0.12549020349979,0.12549020349979),BackgroundTransparency=1,BorderSizePixel=0,Font=3,Name="Refresh",Parent={2},Position=UDim2.new(1,-20,0,1),Size=UDim2.new(0,18,0,18),Text="",TextColor3=Color3.new(1,1,1),TextSize=14,Visible=false,}},
{9,"ImageLabel",{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Image="rbxassetid://5642310344",Parent={8},Position=UDim2.new(0,3,0,3),Size=UDim2.new(0,12,0,12),}},
{10,"Frame",{BackgroundColor3=Color3.new(0.15686275064945,0.15686275064945,0.15686275064945),BorderSizePixel=0,Name="ScrollCorner",Parent={1},Position=UDim2.new(1,-16,1,-16),Size=UDim2.new(0,16,0,16),Visible=false,}},
{11,"Frame",{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,ClipsDescendants=true,Name="List",Parent={1},Position=UDim2.new(0,0,0,23),Size=UDim2.new(1,0,1,-23),}},
})
toolBar = explorerItems.ToolBar
treeFrame = explorerItems.List
Explorer.GuiElems.ToolBar = toolBar
Explorer.GuiElems.TreeFrame = treeFrame
scrollV = Lib.ScrollBar.new()
scrollV.WheelIncrement = 3
scrollV.Gui.Position = UDim2.new(1,-16,0,23)
scrollV:SetScrollFrame(treeFrame)
scrollV.Scrolled:Connect(function()
Explorer.Index = scrollV.Index
Explorer.Refresh()
end)
scrollH = Lib.ScrollBar.new(true)
scrollH.Increment = 5
scrollH.WheelIncrement = Explorer.EntryIndent
scrollH.Gui.Position = UDim2.new(0,0,1,-16)
scrollH.Scrolled:Connect(function()
Explorer.Refresh()
end)
local window = Lib.Window.new()
Explorer.Window = window
window:SetTitle("Explorer")
window.GuiElems.Line.Position = UDim2.new(0,0,0,22)
Explorer.InitEntryTemplate()
toolBar.Parent = window.GuiElems.Content
treeFrame.Parent = window.GuiElems.Content
explorerItems.ScrollCorner.Parent = window.GuiElems.Content
scrollV.Gui.Parent = window.GuiElems.Content
scrollH.Gui.Parent = window.GuiElems.Content
-- Init stuff that requires the window
Explorer.InitRenameBox()
Explorer.InitSearch()
Explorer.InitDelCleaner()
selection.Changed:Connect(Explorer.UpdateSelectionVisuals)
-- Window events
window.GuiElems.Main:GetPropertyChangedSignal("AbsoluteSize"):Connect(function()
if Explorer.Active then
Explorer.UpdateView()
Explorer.Refresh()
end
end)
window.OnActivate:Connect(function()
Explorer.Active = true
Explorer.UpdateView()
Explorer.Update()
Explorer.Refresh()
end)
window.OnRestore:Connect(function()
Explorer.Active = true
Explorer.UpdateView()
Explorer.Update()
Explorer.Refresh()
end)
window.OnDeactivate:Connect(function() Explorer.Active = false end)
window.OnMinimize:Connect(function() Explorer.Active = false end)
-- Settings
autoUpdateSearch = Settings.Explorer.AutoUpdateSearch
-- Fill in nodes
nodes[game] = {Obj = game}
expanded[nodes[game]] = true
-- Nil Instances
if env.getnilinstances then
nodes[nilNode.Obj] = nilNode
end
Explorer.SetupConnections()
local insts = getDescendants(game)
if Main.Elevated then
for i = 1,#insts do
local obj = insts[i]
local par = nodes[ffa(obj,"Instance")]
if not par then continue end
local newNode = {
Obj = obj,
Parent = par,
}
nodes[obj] = newNode
par[#par+1] = newNode
end
else
for i = 1,#insts do
local obj = insts[i]
local s,parObj = pcall(ffa,obj,"Instance")
local par = nodes[parObj]
if not par then continue end
local newNode = {
Obj = obj,
Parent = par,
}
nodes[obj] = newNode
par[#par+1] = newNode
end
end
end
return Explorer
end
-- TODO: Remove when open source
if gethsfuncs then
_G.moduleData = {InitDeps = initDeps, InitAfterMain = initAfterMain, Main = main}
else
return {InitDeps = initDeps, InitAfterMain = initAfterMain, Main = main}
end
end,
["Lib"] = function()
--[[
Lib Module
Container for functions and classes
]]
-- Common Locals
local Main,Lib,Apps,Settings -- Main Containers
local Explorer, Properties, ScriptViewer, Notebook -- Major Apps
local API,RMD,env,service,plr,create,createSimple -- Main Locals
local function initDeps(data)
Main = data.Main
Lib = data.Lib
Apps = data.Apps
Settings = data.Settings
API = data.API
RMD = data.RMD
env = data.env
service = data.service
plr = data.plr
create = data.create
createSimple = data.createSimple
end
local function initAfterMain()
Explorer = Apps.Explorer
Properties = Apps.Properties
ScriptViewer = Apps.ScriptViewer
Notebook = Apps.Notebook
end
local function main()
local Lib = {}
local renderStepped = service.RunService.RenderStepped
local signalWait = renderStepped.wait
local PH = newproxy() -- Placeholder, must be replaced in constructor
local SIGNAL = newproxy()
-- Usually for classes that work with a Roblox Object
local function initObj(props,mt)
local type = type
local function copy(t)
local res = {}
for i,v in pairs(t) do
if v == SIGNAL then
res[i] = Lib.Signal.new()
elseif type(v) == "table" then
res[i] = copy(v)
else
res[i] = v
end
end
return res
end
local newObj = copy(props)
return setmetatable(newObj,mt)
end
local function getGuiMT(props,funcs)
return {__index = function(self,ind) if not props[ind] then return funcs[ind] or self.Gui[ind] end end,
__newindex = function(self,ind,val) if not props[ind] then self.Gui[ind] = val else rawset(self,ind,val) end end}
end
-- Functions
Lib.FormatLuaString = (function()
local string = string
local gsub = string.gsub
local format = string.format
local char = string.char
local cleanTable = {['"'] = '\\"', ['\\'] = '\\\\'}
for i = 0,31 do
cleanTable[char(i)] = "\\"..format("%03d",i)
end
for i = 127,255 do
cleanTable[char(i)] = "\\"..format("%03d",i)
end
return function(str)
return gsub(str,"[\"\\\0-\31\127-\255]",cleanTable)
end
end)()
Lib.CheckMouseInGui = function(gui)
if gui == nil then return false end
local mouse = Main.Mouse
local guiPosition = gui.AbsolutePosition
local guiSize = gui.AbsoluteSize
return mouse.X >= guiPosition.X and mouse.X < guiPosition.X + guiSize.X and mouse.Y >= guiPosition.Y and mouse.Y < guiPosition.Y + guiSize.Y
end
Lib.IsShiftDown = function()
return service.UserInputService:IsKeyDown(Enum.KeyCode.LeftShift) or service.UserInputService:IsKeyDown(Enum.KeyCode.RightShift)
end
Lib.IsCtrlDown = function()
return service.UserInputService:IsKeyDown(Enum.KeyCode.LeftControl) or service.UserInputService:IsKeyDown(Enum.KeyCode.RightControl)
end
Lib.CreateArrow = function(size,num,dir)
local max = num
local arrowFrame = createSimple("Frame",{
BackgroundTransparency = 1,
Name = "Arrow",
Size = UDim2.new(0,size,0,size)
})
if dir == "up" then
for i = 1,num do
local newLine = createSimple("Frame",{
BackgroundColor3 = Color3.new(220/255,220/255,220/255),
BorderSizePixel = 0,
Position = UDim2.new(0,math.floor(size/2)-(i-1),0,math.floor(size/2)+i-math.floor(max/2)-1),
Size = UDim2.new(0,i+(i-1),0,1),
Parent = arrowFrame
})
end
return arrowFrame
elseif dir == "down" then
for i = 1,num do
local newLine = createSimple("Frame",{
BackgroundColor3 = Color3.new(220/255,220/255,220/255),
BorderSizePixel = 0,
Position = UDim2.new(0,math.floor(size/2)-(i-1),0,math.floor(size/2)-i+math.floor(max/2)+1),
Size = UDim2.new(0,i+(i-1),0,1),
Parent = arrowFrame
})
end
return arrowFrame
elseif dir == "left" then
for i = 1,num do
local newLine = createSimple("Frame",{
BackgroundColor3 = Color3.new(220/255,220/255,220/255),
BorderSizePixel = 0,
Position = UDim2.new(0,math.floor(size/2)+i-math.floor(max/2)-1,0,math.floor(size/2)-(i-1)),
Size = UDim2.new(0,1,0,i+(i-1)),
Parent = arrowFrame
})
end
return arrowFrame
elseif dir == "right" then
for i = 1,num do
local newLine = createSimple("Frame",{
BackgroundColor3 = Color3.new(220/255,220/255,220/255),
BorderSizePixel = 0,
Position = UDim2.new(0,math.floor(size/2)-i+math.floor(max/2)+1,0,math.floor(size/2)-(i-1)),
Size = UDim2.new(0,1,0,i+(i-1)),
Parent = arrowFrame
})
end
return arrowFrame
end
error("r u ok")
end
Lib.ParseXML = (function()
local func = function()
-- Only exists to parse RMD
-- from https://github.com/jonathanpoelen/xmlparser
local string, print, pairs = string, print, pairs
-- http://lua-users.org/wiki/StringTrim
local trim = function(s)
local from = s:match"^%s*()"
return from > #s and "" or s:match(".*%S", from)
end
local gtchar = string.byte('>', 1)
local slashchar = string.byte('/', 1)
local D = string.byte('D', 1)
local E = string.byte('E', 1)
function parse(s, evalEntities)
-- remove comments
s = s:gsub('<!%-%-(.-)%-%->', '')
local entities, tentities = {}
if evalEntities then
local pos = s:find('<[_%w]')
if pos then
s:sub(1, pos):gsub('<!ENTITY%s+([_%w]+)%s+(.)(.-)%2', function(name, q, entity)
entities[#entities+1] = {name=name, value=entity}
end)
tentities = createEntityTable(entities)
s = replaceEntities(s:sub(pos), tentities)
end
end
local t, l = {}, {}
local addtext = function(txt)
txt = txt:match'^%s*(.*%S)' or ''
if #txt ~= 0 then
t[#t+1] = {text=txt}
end
end
s:gsub('<([?!/]?)([-:_%w]+)%s*(/?>?)([^<]*)', function(type, name, closed, txt)
-- open
if #type == 0 then
local a = {}
if #closed == 0 then
local len = 0
for all,aname,_,value,starttxt in string.gmatch(txt, "(.-([-_%w]+)%s*=%s*(.)(.-)%3%s*(/?>?))") do
len = len + #all
a[aname] = value
if #starttxt ~= 0 then
txt = txt:sub(len+1)
closed = starttxt
break
end
end
end
t[#t+1] = {tag=name, attrs=a, children={}}
if closed:byte(1) ~= slashchar then
l[#l+1] = t
t = t[#t].children
end
addtext(txt)
-- close
elseif '/' == type then
t = l[#l]
l[#l] = nil
addtext(txt)
-- ENTITY
elseif '!' == type then
if E == name:byte(1) then
txt:gsub('([_%w]+)%s+(.)(.-)%2', function(name, q, entity)
entities[#entities+1] = {name=name, value=entity}
end, 1)
end
-- elseif '?' == type then
-- print('? ' .. name .. ' // ' .. attrs .. '$$')
-- elseif '-' == type then
-- print('comment ' .. name .. ' // ' .. attrs .. '$$')
-- else
-- print('o ' .. #p .. ' // ' .. name .. ' // ' .. attrs .. '$$')
end
end)
return {children=t, entities=entities, tentities=tentities}
end
function parseText(txt)
return parse(txt)
end
function defaultEntityTable()
return { quot='"', apos='\'', lt='<', gt='>', amp='&', tab='\t', nbsp=' ', }
end
function replaceEntities(s, entities)
return s:gsub('&([^;]+);', entities)
end
function createEntityTable(docEntities, resultEntities)
entities = resultEntities or defaultEntityTable()
for _,e in pairs(docEntities) do
e.value = replaceEntities(e.value, entities)
entities[e.name] = e.value
end
return entities
end
return parseText
end
local newEnv = setmetatable({},{__index = getfenv()})
setfenv(func,newEnv)
return func()
end)()
Lib.FastWait = function(s)
if not s then return signalWait(renderStepped) end
local start = tick()
while tick() - start < s do signalWait(renderStepped) end
end
Lib.ButtonAnim = function(button,data)
local holding = false
local disabled = false
local mode = data and data.Mode or 1
local control = {}
if mode == 2 then
local lerpTo = data.LerpTo or Color3.new(0,0,0)
local delta = data.LerpDelta or 0.2
control.StartColor = data.StartColor or button.BackgroundColor3
control.PressColor = data.PressColor or control.StartColor:lerp(lerpTo,delta)
control.HoverColor = data.HoverColor or control.StartColor:lerp(control.PressColor,0.6)
control.OutlineColor = data.OutlineColor
end
button.InputBegan:Connect(function(input)
if disabled then return end
if input.UserInputType == Enum.UserInputType.MouseMovement and not holding then
if mode == 1 then
button.BackgroundTransparency = 0.4
elseif mode == 2 then
button.BackgroundColor3 = control.HoverColor
end
elseif input.UserInputType == Enum.UserInputType.MouseButton1 then
holding = true
if mode == 1 then
button.BackgroundTransparency = 0
elseif mode == 2 then
button.BackgroundColor3 = control.PressColor
if control.OutlineColor then button.BorderColor3 = control.PressColor end
end
end
end)
button.InputEnded:Connect(function(input)
if disabled then return end
if input.UserInputType == Enum.UserInputType.MouseMovement and not holding then
if mode == 1 then
button.BackgroundTransparency = 1
elseif mode == 2 then
button.BackgroundColor3 = control.StartColor
end
elseif input.UserInputType == Enum.UserInputType.MouseButton1 then
holding = false
if mode == 1 then
button.BackgroundTransparency = Lib.CheckMouseInGui(button) and 0.4 or 1
elseif mode == 2 then
button.BackgroundColor3 = Lib.CheckMouseInGui(button) and control.HoverColor or control.StartColor
if control.OutlineColor then button.BorderColor3 = control.OutlineColor end
end
end
end)
control.Disable = function()
disabled = true
holding = false
if mode == 1 then
button.BackgroundTransparency = 1
elseif mode == 2 then
button.BackgroundColor3 = control.StartColor
end
end
control.Enable = function()
disabled = false
end
return control
end
Lib.FindAndRemove = function(t,item)
local pos = table.find(t,item)
if pos then table.remove(t,pos) end
end
Lib.AttachTo = function(obj,data)
local target,posOffX,posOffY,sizeOffX,sizeOffY,resize,con
local disabled = false
local function update()
if not obj or not target then return end
local targetPos = target.AbsolutePosition
local targetSize = target.AbsoluteSize
obj.Position = UDim2.new(0,targetPos.X + posOffX,0,targetPos.Y + posOffY)
if resize then obj.Size = UDim2.new(0,targetSize.X + sizeOffX,0,targetSize.Y + sizeOffY) end
end
local function setup(o,data)
obj = o
data = data or {}
target = data.Target
posOffX = data.PosOffX or 0
posOffY = data.PosOffY or 0
sizeOffX = data.SizeOffX or 0
sizeOffY = data.SizeOffY or 0
resize = data.Resize or false
if con then con:Disconnect() con = nil end
if target then
con = target.Changed:Connect(function(prop)
if not disabled and prop == "AbsolutePosition" or prop == "AbsoluteSize" then
update()
end
end)
end
update()
end
setup(obj,data)
return {
SetData = function(obj,data)
setup(obj,data)
end,
Enable = function()
disabled = false
update()
end,
Disable = function()
disabled = true
end,
Destroy = function()
con:Disconnect()
con = nil
end,
}
end
Lib.ProtectedGuis = {}
Lib.ShowGui = function(gui)
if env.protectgui then
env.protectgui(gui)
end
gui.Parent = Main.GuiHolder
end
Lib.ColorToBytes = function(col)
local round = math.round
return string.format("%d, %d, %d",round(col.r*255),round(col.g*255),round(col.b*255))
end
Lib.ReadFile = function(filename)
if not env.readfile then return end
local s,contents = pcall(env.readfile,filename)
if s and contents then return contents end
end
Lib.DeferFunc = function(f,...)
signalWait(renderStepped)
return f(...)
end
Lib.LoadCustomAsset = function(filepath)
if not env.getcustomasset or not env.isfile or not env.isfile(filepath) then return end
return env.getcustomasset(filepath)
end
Lib.FetchCustomAsset = function(url,filepath)
if not env.writefile then return end
local s,data = pcall(game.HttpGet,game,url)
if not s then return end
env.writefile(filepath,data)
return Lib.LoadCustomAsset(filepath)
end
-- Classes
Lib.Signal = (function()
local funcs = {}
local disconnect = function(con)
local pos = table.find(con.Signal.Connections,con)
if pos then table.remove(con.Signal.Connections,pos) end
end
funcs.Connect = function(self,func)
if type(func) ~= "function" then error("Attempt to connect a non-function") end
local con = {
Signal = self,
Func = func,
Disconnect = disconnect
}
self.Connections[#self.Connections+1] = con
return con
end
funcs.Fire = function(self,...)
for i,v in next,self.Connections do
xpcall(coroutine.wrap(v.Func),function(e) warn(e.."\n"..debug.traceback()) end,...)
end
end
local mt = {
__index = funcs,
__tostring = function(self)
return "Signal: " .. tostring(#self.Connections) .. " Connections"
end
}
local function new()
local obj = {}
obj.Connections = {}
return setmetatable(obj,mt)
end
return {new = new}
end)()
Lib.Set = (function()
local funcs = {}
funcs.Add = function(self,obj)
if self.Map[obj] then return end
local list = self.List
list[#list+1] = obj
self.Map[obj] = true
self.Changed:Fire()
end
funcs.AddTable = function(self,t)
local changed
local list,map = self.List,self.Map
for i = 1,#t do
local elem = t[i]
if not map[elem] then
list[#list+1] = elem
map[elem] = true
changed = true
end
end
if changed then self.Changed:Fire() end
end
funcs.Remove = function(self,obj)
if not self.Map[obj] then return end
local list = self.List
local pos = table.find(list,obj)
if pos then table.remove(list,pos) end
self.Map[obj] = nil
self.Changed:Fire()
end
funcs.RemoveTable = function(self,t)
local changed
local list,map = self.List,self.Map
local removeSet = {}
for i = 1,#t do
local elem = t[i]
map[elem] = nil
removeSet[elem] = true
end
for i = #list,1,-1 do
local elem = list[i]
if removeSet[elem] then
table.remove(list,i)
changed = true
end
end
if changed then self.Changed:Fire() end
end
funcs.Set = function(self,obj)
if #self.List == 1 and self.List[1] == obj then return end
self.List = {obj}
self.Map = {[obj] = true}
self.Changed:Fire()
end
funcs.SetTable = function(self,t)
local newList,newMap = {},{}
self.List,self.Map = newList,newMap
table.move(t,1,#t,1,newList)
for i = 1,#t do
newMap[t[i]] = true
end
self.Changed:Fire()
end
funcs.Clear = function(self)
if #self.List == 0 then return end
self.List = {}
self.Map = {}
self.Changed:Fire()
end
local mt = {__index = funcs}
local function new()
local obj = setmetatable({
List = {},
Map = {},
Changed = Lib.Signal.new()
},mt)
return obj
end
return {new = new}
end)()
Lib.IconMap = (function()
local funcs = {}
funcs.GetLabel = function(self)
local label = Instance.new("ImageLabel")
self:SetupLabel(label)
return label
end
funcs.SetupLabel = function(self,obj)
obj.BackgroundTransparency = 1
obj.ImageRectOffset = Vector2.new(0,0)
obj.ImageRectSize = Vector2.new(self.IconSizeX,self.IconSizeY)
obj.ScaleType = Enum.ScaleType.Crop
obj.Size = UDim2.new(0,self.IconSizeX,0,self.IconSizeY)
end
funcs.Display = function(self,obj,index)
obj.Image = self.MapId
if not self.NumX then
obj.ImageRectOffset = Vector2.new(self.IconSizeX*index, 0)
else
obj.ImageRectOffset = Vector2.new(self.IconSizeX*(index % self.NumX), self.IconSizeY*math.floor(index / self.NumX))
end
end
funcs.DisplayByKey = function(self,obj,key)
if self.IndexDict[key] then
self:Display(obj,self.IndexDict[key])
end
end
funcs.SetDict = function(self,dict)
self.IndexDict = dict
end
local mt = {}
mt.__index = funcs
local function new(mapId,mapSizeX,mapSizeY,iconSizeX,iconSizeY)
local obj = setmetatable({
MapId = mapId,
MapSizeX = mapSizeX,
MapSizeY = mapSizeY,
IconSizeX = iconSizeX,
IconSizeY = iconSizeY,
NumX = mapSizeX/iconSizeX,
IndexDict = {}
},mt)
return obj
end
local function newLinear(mapId,iconSizeX,iconSizeY)
local obj = setmetatable({
MapId = mapId,
IconSizeX = iconSizeX,
IconSizeY = iconSizeY,
IndexDict = {}
},mt)
return obj
end
return {new = new, newLinear = newLinear}
end)()
Lib.ScrollBar = (function()
local funcs = {}
local user = service.UserInputService
local mouse = plr:GetMouse()
local checkMouseInGui = Lib.CheckMouseInGui
local createArrow = Lib.CreateArrow
local function drawThumb(self)
local total = self.TotalSpace
local visible = self.VisibleSpace
local index = self.Index
local scrollThumb = self.GuiElems.ScrollThumb
local scrollThumbFrame = self.GuiElems.ScrollThumbFrame
if not (self:CanScrollUp() or self:CanScrollDown()) then
scrollThumb.Visible = false
else
scrollThumb.Visible = true
end
if self.Horizontal then
scrollThumb.Size = UDim2.new(visible/total,0,1,0)
if scrollThumb.AbsoluteSize.X < 16 then
scrollThumb.Size = UDim2.new(0,16,1,0)
end
local fs = scrollThumbFrame.AbsoluteSize.X
local bs = scrollThumb.AbsoluteSize.X
scrollThumb.Position = UDim2.new(self:GetScrollPercent()*(fs-bs)/fs,0,0,0)
else
scrollThumb.Size = UDim2.new(1,0,visible/total,0)
if scrollThumb.AbsoluteSize.Y < 16 then
scrollThumb.Size = UDim2.new(1,0,0,16)
end
local fs = scrollThumbFrame.AbsoluteSize.Y
local bs = scrollThumb.AbsoluteSize.Y
scrollThumb.Position = UDim2.new(0,0,self:GetScrollPercent()*(fs-bs)/fs,0)
end
end
local function createFrame(self)
local newFrame = createSimple("Frame",{Style=0,Active=true,AnchorPoint=Vector2.new(0,0),BackgroundColor3=Color3.new(0.35294118523598,0.35294118523598,0.35294118523598),BackgroundTransparency=0,BorderColor3=Color3.new(0.10588236153126,0.16470588743687,0.20784315466881),BorderSizePixel=0,ClipsDescendants=false,Draggable=false,Position=UDim2.new(1,-16,0,0),Rotation=0,Selectable=false,Size=UDim2.new(0,16,1,0),SizeConstraint=0,Visible=true,ZIndex=1,Name="ScrollBar",})
local button1 = nil
local button2 = nil
if self.Horizontal then
newFrame.Size = UDim2.new(1,0,0,16)
button1 = createSimple("ImageButton",{
Parent = newFrame,
Name = "Left",
Size = UDim2.new(0,16,0,16),
BackgroundTransparency = 1,
BorderSizePixel = 0,
AutoButtonColor = false
})
createArrow(16,4,"left").Parent = button1
button2 = createSimple("ImageButton",{
Parent = newFrame,
Name = "Right",
Position = UDim2.new(1,-16,0,0),
Size = UDim2.new(0,16,0,16),
BackgroundTransparency = 1,
BorderSizePixel = 0,
AutoButtonColor = false
})
createArrow(16,4,"right").Parent = button2
else
newFrame.Size = UDim2.new(0,16,1,0)
button1 = createSimple("ImageButton",{
Parent = newFrame,
Name = "Up",
Size = UDim2.new(0,16,0,16),
BackgroundTransparency = 1,
BorderSizePixel = 0,
AutoButtonColor = false
})
createArrow(16,4,"up").Parent = button1
button2 = createSimple("ImageButton",{
Parent = newFrame,
Name = "Down",
Position = UDim2.new(0,0,1,-16),
Size = UDim2.new(0,16,0,16),
BackgroundTransparency = 1,
BorderSizePixel = 0,
AutoButtonColor = false
})
createArrow(16,4,"down").Parent = button2
end
local scrollThumbFrame = createSimple("Frame",{
BackgroundTransparency = 1,
Parent = newFrame
})
if self.Horizontal then
scrollThumbFrame.Position = UDim2.new(0,16,0,0)
scrollThumbFrame.Size = UDim2.new(1,-32,1,0)
else
scrollThumbFrame.Position = UDim2.new(0,0,0,16)
scrollThumbFrame.Size = UDim2.new(1,0,1,-32)
end
local scrollThumb = createSimple("Frame",{
BackgroundColor3 = Color3.new(120/255,120/255,120/255),
BorderSizePixel = 0,
Parent = scrollThumbFrame
})
local markerFrame = createSimple("Frame",{
BackgroundTransparency = 1,
Name = "Markers",
Size = UDim2.new(1,0,1,0),
Parent = scrollThumbFrame
})
local buttonPress = false
local thumbPress = false
local thumbFramePress = false
--local thumbColor = Color3.new(120/255,120/255,120/255)
--local thumbSelectColor = Color3.new(140/255,140/255,140/255)
button1.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseMovement and not buttonPress and self:CanScrollUp() then button1.BackgroundTransparency = 0.8 end
if input.UserInputType ~= Enum.UserInputType.MouseButton1 or not self:CanScrollUp() then return end
buttonPress = true
button1.BackgroundTransparency = 0.5
if self:CanScrollUp() then self:ScrollUp() self.Scrolled:Fire() end
local buttonTick = tick()
local releaseEvent
releaseEvent = user.InputEnded:Connect(function(input)
if input.UserInputType ~= Enum.UserInputType.MouseButton1 then return end
releaseEvent:Disconnect()
if checkMouseInGui(button1) and self:CanScrollUp() then button1.BackgroundTransparency = 0.8 else button1.BackgroundTransparency = 1 end
buttonPress = false
end)
while buttonPress do
if tick() - buttonTick >= 0.3 and self:CanScrollUp() then
self:ScrollUp()
self.Scrolled:Fire()
end
wait()
end
end)
button1.InputEnded:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseMovement and not buttonPress then button1.BackgroundTransparency = 1 end
end)
button2.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseMovement and not buttonPress and self:CanScrollDown() then button2.BackgroundTransparency = 0.8 end
if input.UserInputType ~= Enum.UserInputType.MouseButton1 or not self:CanScrollDown() then return end
buttonPress = true
button2.BackgroundTransparency = 0.5
if self:CanScrollDown() then self:ScrollDown() self.Scrolled:Fire() end
local buttonTick = tick()
local releaseEvent
releaseEvent = user.InputEnded:Connect(function(input)
if input.UserInputType ~= Enum.UserInputType.MouseButton1 then return end
releaseEvent:Disconnect()
if checkMouseInGui(button2) and self:CanScrollDown() then button2.BackgroundTransparency = 0.8 else button2.BackgroundTransparency = 1 end
buttonPress = false
end)
while buttonPress do
if tick() - buttonTick >= 0.3 and self:CanScrollDown() then
self:ScrollDown()
self.Scrolled:Fire()
end
wait()
end
end)
button2.InputEnded:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseMovement and not buttonPress then button2.BackgroundTransparency = 1 end
end)
scrollThumb.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseMovement and not thumbPress then scrollThumb.BackgroundTransparency = 0.2 scrollThumb.BackgroundColor3 = self.ThumbSelectColor end
if input.UserInputType ~= Enum.UserInputType.MouseButton1 then return end
local dir = self.Horizontal and "X" or "Y"
local lastThumbPos = nil
buttonPress = false
thumbFramePress = false
thumbPress = true
scrollThumb.BackgroundTransparency = 0
local mouseOffset = mouse[dir] - scrollThumb.AbsolutePosition[dir]
local mouseStart = mouse[dir]
local releaseEvent
local mouseEvent
releaseEvent = user.InputEnded:Connect(function(input)
if input.UserInputType ~= Enum.UserInputType.MouseButton1 then return end
releaseEvent:Disconnect()
if mouseEvent then mouseEvent:Disconnect() end
if checkMouseInGui(scrollThumb) then scrollThumb.BackgroundTransparency = 0.2 else scrollThumb.BackgroundTransparency = 0 scrollThumb.BackgroundColor3 = self.ThumbColor end
thumbPress = false
end)
self:Update()
mouseEvent = user.InputChanged:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseMovement and thumbPress and releaseEvent.Connected then
local thumbFrameSize = scrollThumbFrame.AbsoluteSize[dir]-scrollThumb.AbsoluteSize[dir]
local pos = mouse[dir] - scrollThumbFrame.AbsolutePosition[dir] - mouseOffset
if pos > thumbFrameSize then
pos = thumbFrameSize
elseif pos < 0 then
pos = 0
end
if lastThumbPos ~= pos then
lastThumbPos = pos
self:ScrollTo(math.floor(0.5+pos/thumbFrameSize*(self.TotalSpace-self.VisibleSpace)))
end
wait()
end
end)
end)
scrollThumb.InputEnded:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseMovement and not thumbPress then scrollThumb.BackgroundTransparency = 0 scrollThumb.BackgroundColor3 = self.ThumbColor end
end)
scrollThumbFrame.InputBegan:Connect(function(input)
if input.UserInputType ~= Enum.UserInputType.MouseButton1 or checkMouseInGui(scrollThumb) then return end
local dir = self.Horizontal and "X" or "Y"
local scrollDir = 0
if mouse[dir] >= scrollThumb.AbsolutePosition[dir] + scrollThumb.AbsoluteSize[dir] then
scrollDir = 1
end
local function doTick()
local scrollSize = self.VisibleSpace - 1
if scrollDir == 0 and mouse[dir] < scrollThumb.AbsolutePosition[dir] then
self:ScrollTo(self.Index - scrollSize)
elseif scrollDir == 1 and mouse[dir] >= scrollThumb.AbsolutePosition[dir] + scrollThumb.AbsoluteSize[dir] then
self:ScrollTo(self.Index + scrollSize)
end
end
thumbPress = false
thumbFramePress = true
doTick()
local thumbFrameTick = tick()
local releaseEvent
releaseEvent = user.InputEnded:Connect(function(input)
if input.UserInputType ~= Enum.UserInputType.MouseButton1 then return end
releaseEvent:Disconnect()
thumbFramePress = false
end)
while thumbFramePress do
if tick() - thumbFrameTick >= 0.3 and checkMouseInGui(scrollThumbFrame) then
doTick()
end
wait()
end
end)
newFrame.MouseWheelForward:Connect(function()
self:ScrollTo(self.Index - self.WheelIncrement)
end)
newFrame.MouseWheelBackward:Connect(function()
self:ScrollTo(self.Index + self.WheelIncrement)
end)
self.GuiElems.ScrollThumb = scrollThumb
self.GuiElems.ScrollThumbFrame = scrollThumbFrame
self.GuiElems.Button1 = button1
self.GuiElems.Button2 = button2
self.GuiElems.MarkerFrame = markerFrame
return newFrame
end
funcs.Update = function(self,nocallback)
local total = self.TotalSpace
local visible = self.VisibleSpace
local index = self.Index
local button1 = self.GuiElems.Button1
local button2 = self.GuiElems.Button2
self.Index = math.clamp(self.Index,0,math.max(0,total-visible))
if self.LastTotalSpace ~= self.TotalSpace then
self.LastTotalSpace = self.TotalSpace
self:UpdateMarkers()
end
if self:CanScrollUp() then
for i,v in pairs(button1.Arrow:GetChildren()) do
v.BackgroundTransparency = 0
end
else
button1.BackgroundTransparency = 1
for i,v in pairs(button1.Arrow:GetChildren()) do
v.BackgroundTransparency = 0.5
end
end
if self:CanScrollDown() then
for i,v in pairs(button2.Arrow:GetChildren()) do
v.BackgroundTransparency = 0
end
else
button2.BackgroundTransparency = 1
for i,v in pairs(button2.Arrow:GetChildren()) do
v.BackgroundTransparency = 0.5
end
end
drawThumb(self)
end
funcs.UpdateMarkers = function(self)
local markerFrame = self.GuiElems.MarkerFrame
markerFrame:ClearAllChildren()
for i,v in pairs(self.Markers) do
if i < self.TotalSpace then
createSimple("Frame",{
BackgroundTransparency = 0,
BackgroundColor3 = v,
BorderSizePixel = 0,
Position = self.Horizontal and UDim2.new(i/self.TotalSpace,0,1,-6) or UDim2.new(1,-6,i/self.TotalSpace,0),
Size = self.Horizontal and UDim2.new(0,1,0,6) or UDim2.new(0,6,0,1),
Name = "Marker"..tostring(i),
Parent = markerFrame
})
end
end
end
funcs.AddMarker = function(self,ind,color)
self.Markers[ind] = color or Color3.new(0,0,0)
end
funcs.ScrollTo = function(self,ind,nocallback)
self.Index = ind
self:Update()
if not nocallback then
self.Scrolled:Fire()
end
end
funcs.ScrollUp = function(self)
self.Index = self.Index - self.Increment
self:Update()
end
funcs.ScrollDown = function(self)
self.Index = self.Index + self.Increment
self:Update()
end
funcs.CanScrollUp = function(self)
return self.Index > 0
end
funcs.CanScrollDown = function(self)
return self.Index + self.VisibleSpace < self.TotalSpace
end
funcs.GetScrollPercent = function(self)
return self.Index/(self.TotalSpace-self.VisibleSpace)
end
funcs.SetScrollPercent = function(self,perc)
self.Index = math.floor(perc*(self.TotalSpace-self.VisibleSpace))
self:Update()
end
funcs.Texture = function(self,data)
self.ThumbColor = data.ThumbColor or Color3.new(0,0,0)
self.ThumbSelectColor = data.ThumbSelectColor or Color3.new(0,0,0)
self.GuiElems.ScrollThumb.BackgroundColor3 = data.ThumbColor or Color3.new(0,0,0)
self.Gui.BackgroundColor3 = data.FrameColor or Color3.new(0,0,0)
self.GuiElems.Button1.BackgroundColor3 = data.ButtonColor or Color3.new(0,0,0)
self.GuiElems.Button2.BackgroundColor3 = data.ButtonColor or Color3.new(0,0,0)
for i,v in pairs(self.GuiElems.Button1.Arrow:GetChildren()) do
v.BackgroundColor3 = data.ArrowColor or Color3.new(0,0,0)
end
for i,v in pairs(self.GuiElems.Button2.Arrow:GetChildren()) do
v.BackgroundColor3 = data.ArrowColor or Color3.new(0,0,0)
end
end
funcs.SetScrollFrame = function(self,frame)
if self.ScrollUpEvent then self.ScrollUpEvent:Disconnect() self.ScrollUpEvent = nil end
if self.ScrollDownEvent then self.ScrollDownEvent:Disconnect() self.ScrollDownEvent = nil end
self.ScrollUpEvent = frame.MouseWheelForward:Connect(function() self:ScrollTo(self.Index - self.WheelIncrement) end)
self.ScrollDownEvent = frame.MouseWheelBackward:Connect(function() self:ScrollTo(self.Index + self.WheelIncrement) end)
end
local mt = {}
mt.__index = funcs
local function new(hor)
local obj = setmetatable({
Index = 0,
VisibleSpace = 0,
TotalSpace = 0,
Increment = 1,
WheelIncrement = 1,
Markers = {},
GuiElems = {},
Horizontal = hor,
LastTotalSpace = 0,
Scrolled = Lib.Signal.new()
},mt)
obj.Gui = createFrame(obj)
obj:Texture({
ThumbColor = Color3.fromRGB(60,60,60),
ThumbSelectColor = Color3.fromRGB(75,75,75),
ArrowColor = Color3.new(1,1,1),
FrameColor = Color3.fromRGB(40,40,40),
ButtonColor = Color3.fromRGB(75,75,75)
})
return obj
end
return {new = new}
end)()
Lib.Window = (function()
local funcs = {}
local static = {MinWidth = 200, FreeWidth = 200}
local mouse = plr:GetMouse()
local sidesGui,alignIndicator
local visibleWindows = {}
local leftSide = {Width = 300, Windows = {}, ResizeCons = {}, Hidden = true}
local rightSide = {Width = 300, Windows = {}, ResizeCons = {}, Hidden = true}
local displayOrderStart
local sideDisplayOrder
local sideTweenInfo = TweenInfo.new(0.3,Enum.EasingStyle.Quad,Enum.EasingDirection.Out)
local tweens = {}
local isA = game.IsA
local theme = {
MainColor1 = Color3.fromRGB(52,52,52),
MainColor2 = Color3.fromRGB(45,45,45),
Button = Color3.fromRGB(60,60,60)
}
local function stopTweens()
for i = 1,#tweens do
tweens[i]:Cancel()
end
tweens = {}
end
local function resizeHook(self,resizer,dir)
local guiMain = self.GuiElems.Main
resizer.InputBegan:Connect(function(input)
if not self.Dragging and not self.Resizing and self.Resizable and self.ResizableInternal then
local isH = dir:find("[WE]") and true
local isV = dir:find("[NS]") and true
local signX = dir:find("W",1,true) and -1 or 1
local signY = dir:find("N",1,true) and -1 or 1
if self.Minimized and isV then return end
if input.UserInputType == Enum.UserInputType.MouseMovement then
resizer.BackgroundTransparency = 0.5
elseif input.UserInputType == Enum.UserInputType.MouseButton1 then
local releaseEvent,mouseEvent
local offX = mouse.X - resizer.AbsolutePosition.X
local offY = mouse.Y - resizer.AbsolutePosition.Y
self.Resizing = resizer
resizer.BackgroundTransparency = 1
releaseEvent = service.UserInputService.InputEnded:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 then
releaseEvent:Disconnect()
mouseEvent:Disconnect()
self.Resizing = false
resizer.BackgroundTransparency = 1
end
end)
mouseEvent = service.UserInputService.InputChanged:Connect(function(input)
if self.Resizable and self.ResizableInternal and input.UserInputType == Enum.UserInputType.MouseMovement then
self:StopTweens()
local deltaX = input.Position.X - resizer.AbsolutePosition.X - offX
local deltaY = input.Position.Y - resizer.AbsolutePosition.Y - offY
if guiMain.AbsoluteSize.X + deltaX*signX < self.MinX then deltaX = signX*(self.MinX - guiMain.AbsoluteSize.X) end
if guiMain.AbsoluteSize.Y + deltaY*signY < self.MinY then deltaY = signY*(self.MinY - guiMain.AbsoluteSize.Y) end
if signY < 0 and guiMain.AbsolutePosition.Y + deltaY < 0 then deltaY = -guiMain.AbsolutePosition.Y end
guiMain.Position = guiMain.Position + UDim2.new(0,(signX < 0 and deltaX or 0),0,(signY < 0 and deltaY or 0))
self.SizeX = self.SizeX + (isH and deltaX*signX or 0)
self.SizeY = self.SizeY + (isV and deltaY*signY or 0)
guiMain.Size = UDim2.new(0,self.SizeX,0,self.Minimized and 20 or self.SizeY)
--if isH then self.SizeX = guiMain.AbsoluteSize.X end
--if isV then self.SizeY = guiMain.AbsoluteSize.Y end
end
end)
end
end
end)
resizer.InputEnded:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseMovement and self.Resizing ~= resizer then
resizer.BackgroundTransparency = 1
end
end)
end
local updateWindows
local function moveToTop(window)
local found = table.find(visibleWindows,window)
if found then
table.remove(visibleWindows,found)
table.insert(visibleWindows,1,window)
updateWindows()
end
end
local function sideHasRoom(side,neededSize)
local maxY = sidesGui.AbsoluteSize.Y - (math.max(0,#side.Windows - 1) * 4)
local inc = 0
for i,v in pairs(side.Windows) do
inc = inc + (v.MinY or 100)
if inc > maxY - neededSize then return false end
end
return true
end
local function getSideInsertPos(side,curY)
local pos = #side.Windows + 1
local range = {0,sidesGui.AbsoluteSize.Y}
for i,v in pairs(side.Windows) do
local midPos = v.PosY + v.SizeY/2
if curY <= midPos then
pos = i
range[2] = midPos
break
else
range[1] = midPos
end
end
return pos,range
end
local function focusInput(self,obj)
if isA(obj,"GuiButton") then
obj.MouseButton1Down:Connect(function()
moveToTop(self)
end)
elseif isA(obj,"TextBox") then
obj.Focused:Connect(function()
moveToTop(self)
end)
end
end
local createGui = function(self)
local gui = create({
{1,"ScreenGui",{Name="Window",}},
{2,"Frame",{Active=true,BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,BorderSizePixel=0,Name="Main",Parent={1},Position=UDim2.new(0.40000000596046,0,0.40000000596046,0),Size=UDim2.new(0,300,0,300),}},
{3,"Frame",{BackgroundColor3=Color3.new(0.17647059261799,0.17647059261799,0.17647059261799),BorderSizePixel=0,Name="Content",Parent={2},Position=UDim2.new(0,0,0,20),Size=UDim2.new(1,0,1,-20),ClipsDescendants=true}},
{4,"Frame",{BackgroundColor3=Color3.fromRGB(33,33,33),BorderSizePixel=0,Name="Line",Parent={3},Size=UDim2.new(1,0,0,1),}},
{5,"Frame",{BackgroundColor3=Color3.new(0.20392157137394,0.20392157137394,0.20392157137394),BorderSizePixel=0,Name="TopBar",Parent={2},Size=UDim2.new(1,0,0,20),}},
{6,"TextLabel",{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Font=3,Name="Title",Parent={5},Position=UDim2.new(0,5,0,0),Size=UDim2.new(1,-10,0,20),Text="Window",TextColor3=Color3.new(1,1,1),TextSize=14,TextXAlignment=0,}},
{7,"TextButton",{AutoButtonColor=false,BackgroundColor3=Color3.new(0.12549020349979,0.12549020349979,0.12549020349979),BackgroundTransparency=1,BorderSizePixel=0,Font=3,Name="Close",Parent={5},Position=UDim2.new(1,-18,0,2),Size=UDim2.new(0,16,0,16),Text="",TextColor3=Color3.new(1,1,1),TextSize=14,}},
{8,"ImageLabel",{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Image="rbxassetid://5054663650",Parent={7},Position=UDim2.new(0,3,0,3),Size=UDim2.new(0,10,0,10),}},
{9,"UICorner",{CornerRadius=UDim.new(0,4),Parent={7},}},
{10,"TextButton",{AutoButtonColor=false,BackgroundColor3=Color3.new(0.12549020349979,0.12549020349979,0.12549020349979),BackgroundTransparency=1,BorderSizePixel=0,Font=3,Name="Minimize",Parent={5},Position=UDim2.new(1,-36,0,2),Size=UDim2.new(0,16,0,16),Text="",TextColor3=Color3.new(1,1,1),TextSize=14,}},
{11,"ImageLabel",{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Image="rbxassetid://5034768003",Parent={10},Position=UDim2.new(0,3,0,3),Size=UDim2.new(0,10,0,10),}},
{12,"UICorner",{CornerRadius=UDim.new(0,4),Parent={10},}},
{13,"ImageLabel",{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,BorderSizePixel=0,Image="rbxassetid://1427967925",Name="Outlines",Parent={2},Position=UDim2.new(0,-5,0,-5),ScaleType=1,Size=UDim2.new(1,10,1,10),SliceCenter=Rect.new(6,6,25,25),TileSize=UDim2.new(0,20,0,20),}},
{14,"Frame",{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Name="ResizeControls",Parent={2},Position=UDim2.new(0,-5,0,-5),Size=UDim2.new(1,10,1,10),}},
{15,"TextButton",{AutoButtonColor=false,BackgroundColor3=Color3.new(0.27450981736183,0.27450981736183,0.27450981736183),BackgroundTransparency=1,BorderSizePixel=0,Font=3,Name="North",Parent={14},Position=UDim2.new(0,5,0,0),Size=UDim2.new(1,-10,0,5),Text="",TextColor3=Color3.new(0,0,0),TextSize=14,}},
{16,"TextButton",{AutoButtonColor=false,BackgroundColor3=Color3.new(0.27450981736183,0.27450981736183,0.27450981736183),BackgroundTransparency=1,BorderSizePixel=0,Font=3,Name="South",Parent={14},Position=UDim2.new(0,5,1,-5),Size=UDim2.new(1,-10,0,5),Text="",TextColor3=Color3.new(0,0,0),TextSize=14,}},
{17,"TextButton",{AutoButtonColor=false,BackgroundColor3=Color3.new(0.27450981736183,0.27450981736183,0.27450981736183),BackgroundTransparency=1,BorderSizePixel=0,Font=3,Name="NorthEast",Parent={14},Position=UDim2.new(1,-5,0,0),Size=UDim2.new(0,5,0,5),Text="",TextColor3=Color3.new(0,0,0),TextSize=14,}},
{18,"TextButton",{AutoButtonColor=false,BackgroundColor3=Color3.new(0.27450981736183,0.27450981736183,0.27450981736183),BackgroundTransparency=1,BorderSizePixel=0,Font=3,Name="East",Parent={14},Position=UDim2.new(1,-5,0,5),Size=UDim2.new(0,5,1,-10),Text="",TextColor3=Color3.new(0,0,0),TextSize=14,}},
{19,"TextButton",{AutoButtonColor=false,BackgroundColor3=Color3.new(0.27450981736183,0.27450981736183,0.27450981736183),BackgroundTransparency=1,BorderSizePixel=0,Font=3,Name="West",Parent={14},Position=UDim2.new(0,0,0,5),Size=UDim2.new(0,5,1,-10),Text="",TextColor3=Color3.new(0,0,0),TextSize=14,}},
{20,"TextButton",{AutoButtonColor=false,BackgroundColor3=Color3.new(0.27450981736183,0.27450981736183,0.27450981736183),BackgroundTransparency=1,BorderSizePixel=0,Font=3,Name="SouthEast",Parent={14},Position=UDim2.new(1,-5,1,-5),Size=UDim2.new(0,5,0,5),Text="",TextColor3=Color3.new(0,0,0),TextSize=14,}},
{21,"TextButton",{AutoButtonColor=false,BackgroundColor3=Color3.new(0.27450981736183,0.27450981736183,0.27450981736183),BackgroundTransparency=1,BorderSizePixel=0,Font=3,Name="NorthWest",Parent={14},Size=UDim2.new(0,5,0,5),Text="",TextColor3=Color3.new(0,0,0),TextSize=14,}},
{22,"TextButton",{AutoButtonColor=false,BackgroundColor3=Color3.new(0.27450981736183,0.27450981736183,0.27450981736183),BackgroundTransparency=1,BorderSizePixel=0,Font=3,Name="SouthWest",Parent={14},Position=UDim2.new(0,0,1,-5),Size=UDim2.new(0,5,0,5),Text="",TextColor3=Color3.new(0,0,0),TextSize=14,}},
})
local guiMain = gui.Main
local guiTopBar = guiMain.TopBar
local guiResizeControls = guiMain.ResizeControls
self.GuiElems.Main = guiMain
self.GuiElems.TopBar = guiMain.TopBar
self.GuiElems.Content = guiMain.Content
self.GuiElems.Line = guiMain.Content.Line
self.GuiElems.Outlines = guiMain.Outlines
self.GuiElems.Title = guiTopBar.Title
self.GuiElems.Close = guiTopBar.Close
self.GuiElems.Minimize = guiTopBar.Minimize
self.GuiElems.ResizeControls = guiResizeControls
self.ContentPane = guiMain.Content
guiTopBar.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 and self.Draggable then
local releaseEvent,mouseEvent
local maxX = sidesGui.AbsoluteSize.X
local initX = guiMain.AbsolutePosition.X
local initY = guiMain.AbsolutePosition.Y
local offX = mouse.X - initX
local offY = mouse.Y - initY
local alignInsertPos,alignInsertSide
guiDragging = true
releaseEvent = game:GetService("UserInputService").InputEnded:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 then
releaseEvent:Disconnect()
mouseEvent:Disconnect()
guiDragging = false
alignIndicator.Parent = nil
if alignInsertSide then
local targetSide = (alignInsertSide == "left" and leftSide) or (alignInsertSide == "right" and rightSide)
self:AlignTo(targetSide,alignInsertPos)
end
end
end)
mouseEvent = game:GetService("UserInputService").InputChanged:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseMovement and self.Draggable and not self.Closed then
if self.Aligned then
if leftSide.Resizing or rightSide.Resizing then return end
local posX,posY = input.Position.X-offX,input.Position.Y-offY
local delta = math.sqrt((posX-initX)^2 + (posY-initY)^2)
if delta >= 5 then
self:SetAligned(false)
end
else
local inputX,inputY = input.Position.X,input.Position.Y
local posX,posY = inputX-offX,inputY-offY
if posY < 0 then posY = 0 end
guiMain.Position = UDim2.new(0,posX,0,posY)
if self.Resizable and self.Alignable then
if inputX < 25 then
if sideHasRoom(leftSide,self.MinY or 100) then
local insertPos,range = getSideInsertPos(leftSide,inputY)
alignIndicator.Indicator.Position = UDim2.new(0,-15,0,range[1])
alignIndicator.Indicator.Size = UDim2.new(0,40,0,range[2]-range[1])
Lib.ShowGui(alignIndicator)
alignInsertPos = insertPos
alignInsertSide = "left"
return
end
elseif inputX >= maxX - 25 then
if sideHasRoom(rightSide,self.MinY or 100) then
local insertPos,range = getSideInsertPos(rightSide,inputY)
alignIndicator.Indicator.Position = UDim2.new(0,maxX-25,0,range[1])
alignIndicator.Indicator.Size = UDim2.new(0,40,0,range[2]-range[1])
Lib.ShowGui(alignIndicator)
alignInsertPos = insertPos
alignInsertSide = "right"
return
end
end
end
alignIndicator.Parent = nil
alignInsertPos = nil
alignInsertSide = nil
end
end
end)
end
end)
guiTopBar.Close.MouseButton1Click:Connect(function()
if self.Closed then return end
self:Close()
end)
guiTopBar.Minimize.MouseButton1Click:Connect(function()
if self.Closed then return end
if self.Aligned then
self:SetAligned(false)
else
self:SetMinimized()
end
end)
guiTopBar.Minimize.MouseButton2Click:Connect(function()
if self.Closed then return end
if not self.Aligned then
self:SetMinimized(nil,2)
guiTopBar.Minimize.BackgroundTransparency = 1
end
end)
guiMain.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 and not self.Aligned and not self.Closed then
moveToTop(self)
end
end)
guiMain:GetPropertyChangedSignal("AbsolutePosition"):Connect(function()
local absPos = guiMain.AbsolutePosition
self.PosX = absPos.X
self.PosY = absPos.Y
end)
resizeHook(self,guiResizeControls.North,"N")
resizeHook(self,guiResizeControls.NorthEast,"NE")
resizeHook(self,guiResizeControls.East,"E")
resizeHook(self,guiResizeControls.SouthEast,"SE")
resizeHook(self,guiResizeControls.South,"S")
resizeHook(self,guiResizeControls.SouthWest,"SW")
resizeHook(self,guiResizeControls.West,"W")
resizeHook(self,guiResizeControls.NorthWest,"NW")
guiMain.Size = UDim2.new(0,self.SizeX,0,self.SizeY)
gui.DescendantAdded:Connect(function(obj) focusInput(self,obj) end)
local descs = gui:GetDescendants()
for i = 1,#descs do
focusInput(self,descs[i])
end
self.MinimizeAnim = Lib.ButtonAnim(guiTopBar.Minimize)
self.CloseAnim = Lib.ButtonAnim(guiTopBar.Close)
return gui
end
local function updateSideFrames(noTween)
stopTweens()
leftSide.Frame.Size = UDim2.new(0,leftSide.Width,1,0)
rightSide.Frame.Size = UDim2.new(0,rightSide.Width,1,0)
leftSide.Frame.Resizer.Position = UDim2.new(0,leftSide.Width,0,0)
rightSide.Frame.Resizer.Position = UDim2.new(0,-5,0,0)
--leftSide.Frame.Visible = (#leftSide.Windows > 0)
--rightSide.Frame.Visible = (#rightSide.Windows > 0)
--[[if #leftSide.Windows > 0 and leftSide.Frame.Position == UDim2.new(0,-leftSide.Width-5,0,0) then
leftSide.Frame:TweenPosition(UDim2.new(0,0,0,0),Enum.EasingDirection.Out,Enum.EasingStyle.Quad,0.3,true)
elseif #leftSide.Windows == 0 and leftSide.Frame.Position == UDim2.new(0,0,0,0) then
leftSide.Frame:TweenPosition(UDim2.new(0,-leftSide.Width-5,0,0),Enum.EasingDirection.Out,Enum.EasingStyle.Quad,0.3,true)
end
local rightTweenPos = (#rightSide.Windows == 0 and UDim2.new(1,5,0,0) or UDim2.new(1,-rightSide.Width,0,0))
rightSide.Frame:TweenPosition(rightTweenPos,Enum.EasingDirection.Out,Enum.EasingStyle.Quad,0.3,true)]]
local leftHidden = #leftSide.Windows == 0 or leftSide.Hidden
local rightHidden = #rightSide.Windows == 0 or rightSide.Hidden
local leftPos = (leftHidden and UDim2.new(0,-leftSide.Width-10,0,0) or UDim2.new(0,0,0,0))
local rightPos = (rightHidden and UDim2.new(1,10,0,0) or UDim2.new(1,-rightSide.Width,0,0))
sidesGui.LeftToggle.Text = leftHidden and ">" or "<"
sidesGui.RightToggle.Text = rightHidden and "<" or ">"
if not noTween then
local function insertTween(...)
local tween = service.TweenService:Create(...)
tweens[#tweens+1] = tween
tween:Play()
end
insertTween(leftSide.Frame,sideTweenInfo,{Position = leftPos})
insertTween(rightSide.Frame,sideTweenInfo,{Position = rightPos})
insertTween(sidesGui.LeftToggle,sideTweenInfo,{Position = UDim2.new(0,#leftSide.Windows == 0 and -16 or 0,0,-36)})
insertTween(sidesGui.RightToggle,sideTweenInfo,{Position = UDim2.new(1,#rightSide.Windows == 0 and 0 or -16,0,-36)})
else
leftSide.Frame.Position = leftPos
rightSide.Frame.Position = rightPos
sidesGui.LeftToggle.Position = UDim2.new(0,#leftSide.Windows == 0 and -16 or 0,0,-36)
sidesGui.RightToggle.Position = UDim2.new(1,#rightSide.Windows == 0 and 0 or -16,0,-36)
end
end
local function getSideFramePos(side)
local leftHidden = #leftSide.Windows == 0 or leftSide.Hidden
local rightHidden = #rightSide.Windows == 0 or rightSide.Hidden
if side == leftSide then
return (leftHidden and UDim2.new(0,-leftSide.Width-10,0,0) or UDim2.new(0,0,0,0))
else
return (rightHidden and UDim2.new(1,10,0,0) or UDim2.new(1,-rightSide.Width,0,0))
end
end
local function sideResized(side)
local currentPos = 0
local sideFramePos = getSideFramePos(side)
for i,v in pairs(side.Windows) do
v.SizeX = side.Width
v.GuiElems.Main.Size = UDim2.new(0,side.Width,0,v.SizeY)
v.GuiElems.Main.Position = UDim2.new(sideFramePos.X.Scale,sideFramePos.X.Offset,0,currentPos)
currentPos = currentPos + v.SizeY+4
end
end
local function sideResizerHook(resizer,dir,side,pos)
local mouse = Main.Mouse
local windows = side.Windows
resizer.InputBegan:Connect(function(input)
if not side.Resizing then
if input.UserInputType == Enum.UserInputType.MouseMovement then
resizer.BackgroundColor3 = theme.MainColor2
elseif input.UserInputType == Enum.UserInputType.MouseButton1 then
local releaseEvent,mouseEvent
local offX = mouse.X - resizer.AbsolutePosition.X
local offY = mouse.Y - resizer.AbsolutePosition.Y
side.Resizing = resizer
resizer.BackgroundColor3 = theme.MainColor2
releaseEvent = service.UserInputService.InputEnded:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 then
releaseEvent:Disconnect()
mouseEvent:Disconnect()
side.Resizing = false
resizer.BackgroundColor3 = theme.Button
end
end)
mouseEvent = service.UserInputService.InputChanged:Connect(function(input)
if not resizer.Parent then
releaseEvent:Disconnect()
mouseEvent:Disconnect()
side.Resizing = false
return
end
if input.UserInputType == Enum.UserInputType.MouseMovement then
if dir == "V" then
local delta = input.Position.Y - resizer.AbsolutePosition.Y - offY
if delta > 0 then
local neededSize = delta
for i = pos+1,#windows do
local window = windows[i]
local newSize = math.max(window.SizeY-neededSize,(window.MinY or 100))
neededSize = neededSize - (window.SizeY - newSize)
window.SizeY = newSize
end
windows[pos].SizeY = windows[pos].SizeY + math.max(0,delta-neededSize)
else
local neededSize = -delta
for i = pos,1,-1 do
local window = windows[i]
local newSize = math.max(window.SizeY-neededSize,(window.MinY or 100))
neededSize = neededSize - (window.SizeY - newSize)
window.SizeY = newSize
end
windows[pos+1].SizeY = windows[pos+1].SizeY + math.max(0,-delta-neededSize)
end
updateSideFrames()
sideResized(side)
elseif dir == "H" then
local maxWidth = math.max(300,sidesGui.AbsoluteSize.X-static.FreeWidth)
local otherSide = (side == leftSide and rightSide or leftSide)
local delta = input.Position.X - resizer.AbsolutePosition.X - offX
delta = (side == leftSide and delta or -delta)
local proposedSize = math.max(static.MinWidth,side.Width + delta)
if proposedSize + otherSide.Width <= maxWidth then
side.Width = proposedSize
else
local newOtherSize = maxWidth - proposedSize
if newOtherSize >= static.MinWidth then
side.Width = proposedSize
otherSide.Width = newOtherSize
else
side.Width = maxWidth - static.MinWidth
otherSide.Width = static.MinWidth
end
end
updateSideFrames(true)
sideResized(side)
sideResized(otherSide)
end
end
end)
end
end
end)
resizer.InputEnded:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseMovement and side.Resizing ~= resizer then
resizer.BackgroundColor3 = theme.Button
end
end)
end
local function renderSide(side,noTween) -- TODO: Use existing resizers
local currentPos = 0
local sideFramePos = getSideFramePos(side)
local template = side.WindowResizer:Clone()
for i,v in pairs(side.ResizeCons) do v:Disconnect() end
for i,v in pairs(side.Frame:GetChildren()) do if v.Name == "WindowResizer" then v:Destroy() end end
side.ResizeCons = {}
side.Resizing = nil
for i,v in pairs(side.Windows) do
v.SidePos = i
local isEnd = i == #side.Windows
local size = UDim2.new(0,side.Width,0,v.SizeY)
local pos = UDim2.new(sideFramePos.X.Scale,sideFramePos.X.Offset,0,currentPos)
Lib.ShowGui(v.Gui)
--v.GuiElems.Main:TweenSizeAndPosition(size,pos,Enum.EasingDirection.Out,Enum.EasingStyle.Quad,0.3,true)
if noTween then
v.GuiElems.Main.Size = size
v.GuiElems.Main.Position = pos
else
local tween = service.TweenService:Create(v.GuiElems.Main,sideTweenInfo,{Size = size, Position = pos})
tweens[#tweens+1] = tween
tween:Play()
end
currentPos = currentPos + v.SizeY+4
if not isEnd then
local newTemplate = template:Clone()
newTemplate.Position = UDim2.new(1,-side.Width,0,currentPos-4)
side.ResizeCons[#side.ResizeCons+1] = v.Gui.Main:GetPropertyChangedSignal("Size"):Connect(function()
newTemplate.Position = UDim2.new(1,-side.Width,0, v.GuiElems.Main.Position.Y.Offset + v.GuiElems.Main.Size.Y.Offset)
end)
side.ResizeCons[#side.ResizeCons+1] = v.Gui.Main:GetPropertyChangedSignal("Position"):Connect(function()
newTemplate.Position = UDim2.new(1,-side.Width,0, v.GuiElems.Main.Position.Y.Offset + v.GuiElems.Main.Size.Y.Offset)
end)
sideResizerHook(newTemplate,"V",side,i)
newTemplate.Parent = side.Frame
end
end
--side.Frame.Back.Position = UDim2.new(0,0,0,0)
--side.Frame.Back.Size = UDim2.new(0,side.Width,1,0)
end
local function updateSide(side,noTween)
local oldHeight = 0
local currentPos = 0
local neededSize = 0
local windows = side.Windows
local height = sidesGui.AbsoluteSize.Y - (math.max(0,#windows - 1) * 4)
for i,v in pairs(windows) do oldHeight = oldHeight + v.SizeY end
for i,v in pairs(windows) do
if i == #windows then
v.SizeY = height-currentPos
neededSize = math.max(0,(v.MinY or 100)-v.SizeY)
else
v.SizeY = math.max(math.floor(v.SizeY/oldHeight*height),v.MinY or 100)
end
currentPos = currentPos + v.SizeY
end
if neededSize > 0 then
for i = #windows-1,1,-1 do
local window = windows[i]
local newSize = math.max(window.SizeY-neededSize,(window.MinY or 100))
neededSize = neededSize - (window.SizeY - newSize)
window.SizeY = newSize
end
local lastWindow = windows[#windows]
lastWindow.SizeY = (lastWindow.MinY or 100)-neededSize
end
renderSide(side,noTween)
end
updateWindows = function(noTween)
updateSideFrames(noTween)
updateSide(leftSide,noTween)
updateSide(rightSide,noTween)
local count = 0
for i = #visibleWindows,1,-1 do
visibleWindows[i].Gui.DisplayOrder = displayOrderStart + count
Lib.ShowGui(visibleWindows[i].Gui)
count = count + 1
end
--[[local leftTweenPos = (#leftSide.Windows == 0 and UDim2.new(0,-leftSide.Width-5,0,0) or UDim2.new(0,0,0,0))
leftSide.Frame:TweenPosition(leftTweenPos,Enum.EasingDirection.Out,Enum.EasingStyle.Quad,0.3,true)
local rightTweenPos = (#rightSide.Windows == 0 and UDim2.new(1,5,0,0) or UDim2.new(1,-rightSide.Width,0,0))
rightSide.Frame:TweenPosition(rightTweenPos,Enum.EasingDirection.Out,Enum.EasingStyle.Quad,0.3,true)]]
end
funcs.SetMinimized = function(self,set,mode)
local oldVal = self.Minimized
local newVal
if set == nil then newVal = not self.Minimized else newVal = set end
self.Minimized = newVal
if not mode then mode = 1 end
local resizeControls = self.GuiElems.ResizeControls
local minimizeControls = {"North","NorthEast","NorthWest","South","SouthEast","SouthWest"}
for i = 1,#minimizeControls do
local control = resizeControls:FindFirstChild(minimizeControls[i])
if control then control.Visible = not newVal end
end
if mode == 1 or mode == 2 then
self:StopTweens()
if mode == 1 then
self.GuiElems.Main:TweenSize(UDim2.new(0,self.SizeX,0,newVal and 20 or self.SizeY),Enum.EasingDirection.Out,Enum.EasingStyle.Quart,0.25,true)
else
local maxY = sidesGui.AbsoluteSize.Y
local newPos = UDim2.new(0,self.PosX,0,newVal and math.min(maxY-20,self.PosY + self.SizeY - 20) or math.max(0,self.PosY - self.SizeY + 20))
self.GuiElems.Main:TweenPosition(newPos,Enum.EasingDirection.Out,Enum.EasingStyle.Quart,0.25,true)
self.GuiElems.Main:TweenSize(UDim2.new(0,self.SizeX,0,newVal and 20 or self.SizeY),Enum.EasingDirection.Out,Enum.EasingStyle.Quart,0.25,true)
end
self.GuiElems.Minimize.ImageLabel.Image = newVal and "rbxassetid://5060023708" or "rbxassetid://5034768003"
end
if oldVal ~= newVal then
if newVal then
self.OnMinimize:Fire()
else
self.OnRestore:Fire()
end
end
end
funcs.Resize = function(self,sizeX,sizeY)
self.SizeX = sizeX or self.SizeX
self.SizeY = sizeY or self.SizeY
self.GuiElems.Main.Size = UDim2.new(0,self.SizeX,0,self.SizeY)
end
funcs.SetSize = funcs.Resize
funcs.SetTitle = function(self,title)
self.GuiElems.Title.Text = title
end
funcs.SetResizable = function(self,val)
self.Resizable = val
self.GuiElems.ResizeControls.Visible = self.Resizable and self.ResizableInternal
end
funcs.SetResizableInternal = function(self,val)
self.ResizableInternal = val
self.GuiElems.ResizeControls.Visible = self.Resizable and self.ResizableInternal
end
funcs.SetAligned = function(self,val)
self.Aligned = val
self:SetResizableInternal(not val)
self.GuiElems.Main.Active = not val
self.GuiElems.Main.Outlines.Visible = not val
if not val then
for i,v in pairs(leftSide.Windows) do if v == self then table.remove(leftSide.Windows,i) break end end
for i,v in pairs(rightSide.Windows) do if v == self then table.remove(rightSide.Windows,i) break end end
if not table.find(visibleWindows,self) then table.insert(visibleWindows,1,self) end
self.GuiElems.Minimize.ImageLabel.Image = "rbxassetid://5034768003"
self.Side = nil
updateWindows()
else
self:SetMinimized(false,3)
for i,v in pairs(visibleWindows) do if v == self then table.remove(visibleWindows,i) break end end
self.GuiElems.Minimize.ImageLabel.Image = "rbxassetid://5448127505"
end
end
funcs.Add = function(self,obj,name)
if type(obj) == "table" and obj.Gui and obj.Gui:IsA("GuiObject") then
obj.Gui.Parent = self.ContentPane
else
obj.Parent = self.ContentPane
end
if name then self.Elements[name] = obj end
end
funcs.GetElement = function(self,obj,name)
return self.Elements[name]
end
funcs.AlignTo = function(self,side,pos,size,silent)
if table.find(side.Windows,self) or self.Closed then return end
size = size or self.SizeY
if size > 0 and size <= 1 then
local totalSideHeight = 0
for i,v in pairs(side.Windows) do totalSideHeight = totalSideHeight + v.SizeY end
self.SizeY = (totalSideHeight > 0 and totalSideHeight * size * 2) or size
else
self.SizeY = (size > 0 and size or 100)
end
self:SetAligned(true)
self.Side = side
self.SizeX = side.Width
self.Gui.DisplayOrder = sideDisplayOrder + 1
for i,v in pairs(side.Windows) do v.Gui.DisplayOrder = sideDisplayOrder end
pos = math.min(#side.Windows+1, pos or 1)
self.SidePos = pos
table.insert(side.Windows, pos, self)
if not silent then
side.Hidden = false
end
updateWindows(silent)
end
funcs.Close = function(self)
self.Closed = true
self:SetResizableInternal(false)
Lib.FindAndRemove(leftSide.Windows,self)
Lib.FindAndRemove(rightSide.Windows,self)
Lib.FindAndRemove(visibleWindows,self)
self.MinimizeAnim.Disable()
self.CloseAnim.Disable()
self.ClosedSide = self.Side
self.Side = nil
self.OnDeactivate:Fire()
if not self.Aligned then
self:StopTweens()
local ti = TweenInfo.new(0.2,Enum.EasingStyle.Quad,Enum.EasingDirection.Out)
local closeTime = tick()
self.LastClose = closeTime
self:DoTween(self.GuiElems.Main,ti,{Size = UDim2.new(0,self.SizeX,0,20)})
self:DoTween(self.GuiElems.Title,ti,{TextTransparency = 1})
self:DoTween(self.GuiElems.Minimize.ImageLabel,ti,{ImageTransparency = 1})
self:DoTween(self.GuiElems.Close.ImageLabel,ti,{ImageTransparency = 1})
Lib.FastWait(0.2)
if closeTime ~= self.LastClose then return end
self:DoTween(self.GuiElems.TopBar,ti,{BackgroundTransparency = 1})
self:DoTween(self.GuiElems.Outlines,ti,{ImageTransparency = 1})
Lib.FastWait(0.2)
if closeTime ~= self.LastClose then return end
end
self.Aligned = false
self.Gui.Parent = nil
updateWindows(true)
end
funcs.Hide = funcs.Close
funcs.IsVisible = function(self)
return not self.Closed and ((self.Side and not self.Side.Hidden) or not self.Side)
end
funcs.IsContentVisible = function(self)
return self:IsVisible() and not self.Minimized
end
funcs.Focus = function(self)
moveToTop(self)
end
funcs.MoveInBoundary = function(self)
local posX,posY = self.PosX,self.PosY
local maxX,maxY = sidesGui.AbsoluteSize.X,sidesGui.AbsoluteSize.Y
posX = math.min(posX,maxX-self.SizeX)
posY = math.min(posY,maxY-20)
self.GuiElems.Main.Position = UDim2.new(0,posX,0,posY)
end
funcs.DoTween = function(self,...)
local tween = service.TweenService:Create(...)
self.Tweens[#self.Tweens+1] = tween
tween:Play()
end
funcs.StopTweens = function(self)
for i,v in pairs(self.Tweens) do
v:Cancel()
end
self.Tweens = {}
end
funcs.Show = function(self,data)
return static.ShowWindow(self,data)
end
funcs.ShowAndFocus = function(self,data)
static.ShowWindow(self,data)
service.RunService.RenderStepped:wait()
self:Focus()
end
static.ShowWindow = function(window,data)
data = data or {}
local align = data.Align
local pos = data.Pos
local size = data.Size
local targetSide = (align == "left" and leftSide) or (align == "right" and rightSide)
if not window.Closed then
if not window.Aligned then
window:SetMinimized(false)
elseif window.Side and not data.Silent then
static.SetSideVisible(window.Side,true)
end
return
end
window.Closed = false
window.LastClose = tick()
window.GuiElems.Title.TextTransparency = 0
window.GuiElems.Minimize.ImageLabel.ImageTransparency = 0
window.GuiElems.Close.ImageLabel.ImageTransparency = 0
window.GuiElems.TopBar.BackgroundTransparency = 0
window.GuiElems.Outlines.ImageTransparency = 0
window.GuiElems.Minimize.ImageLabel.Image = "rbxassetid://5034768003"
window.GuiElems.Main.Active = true
window.GuiElems.Main.Outlines.Visible = true
window:SetMinimized(false,3)
window:SetResizableInternal(true)
window.MinimizeAnim.Enable()
window.CloseAnim.Enable()
if align then
window:AlignTo(targetSide,pos,size,data.Silent)
else
if align == nil and window.ClosedSide then -- Regular open
window:AlignTo(window.ClosedSide,window.SidePos,size,true)
static.SetSideVisible(window.ClosedSide,true)
else
if table.find(visibleWindows,window) then return end
-- TODO: make better
window.GuiElems.Main.Size = UDim2.new(0,window.SizeX,0,20)
local ti = TweenInfo.new(0.2,Enum.EasingStyle.Quad,Enum.EasingDirection.Out)
window:StopTweens()
window:DoTween(window.GuiElems.Main,ti,{Size = UDim2.new(0,window.SizeX,0,window.SizeY)})
window.SizeY = size or window.SizeY
table.insert(visibleWindows,1,window)
updateWindows()
end
end
window.ClosedSide = nil
window.OnActivate:Fire()
end
static.ToggleSide = function(name)
local side = (name == "left" and leftSide or rightSide)
side.Hidden = not side.Hidden
for i,v in pairs(side.Windows) do
if side.Hidden then
v.OnDeactivate:Fire()
else
v.OnActivate:Fire()
end
end
updateWindows()
end
static.SetSideVisible = function(s,vis)
local side = (type(s) == "table" and s) or (s == "left" and leftSide or rightSide)
side.Hidden = not vis
for i,v in pairs(side.Windows) do
if side.Hidden then
v.OnDeactivate:Fire()
else
v.OnActivate:Fire()
end
end
updateWindows()
end
static.Init = function()
displayOrderStart = Main.DisplayOrders.Window
sideDisplayOrder = Main.DisplayOrders.SideWindow
sidesGui = Instance.new("ScreenGui")
local leftFrame = create({
{1,"Frame",{Active=true,Name="LeftSide",BackgroundColor3=Color3.new(0.17647059261799,0.17647059261799,0.17647059261799),BorderSizePixel=0,}},
{2,"TextButton",{AutoButtonColor=false,BackgroundColor3=Color3.new(0.2549019753933,0.2549019753933,0.2549019753933),BorderSizePixel=0,Font=3,Name="Resizer",Parent={1},Size=UDim2.new(0,5,1,0),Text="",TextColor3=Color3.new(0,0,0),TextSize=14,}},
{3,"Frame",{BackgroundColor3=Color3.new(0.14117647707462,0.14117647707462,0.14117647707462),BorderSizePixel=0,Name="Line",Parent={2},Position=UDim2.new(0,0,0,0),Size=UDim2.new(0,1,1,0),}},
{4,"TextButton",{AutoButtonColor=false,BackgroundColor3=Color3.new(0.2549019753933,0.2549019753933,0.2549019753933),BorderSizePixel=0,Font=3,Name="WindowResizer",Parent={1},Position=UDim2.new(1,-300,0,0),Size=UDim2.new(1,0,0,4),Text="",TextColor3=Color3.new(0,0,0),TextSize=14,}},
{5,"Frame",{BackgroundColor3=Color3.new(0.14117647707462,0.14117647707462,0.14117647707462),BorderSizePixel=0,Name="Line",Parent={4},Size=UDim2.new(1,0,0,1),}},
})
leftSide.Frame = leftFrame
leftFrame.Position = UDim2.new(0,-leftSide.Width-10,0,0)
leftSide.WindowResizer = leftFrame.WindowResizer
leftFrame.WindowResizer.Parent = nil
leftFrame.Parent = sidesGui
local rightFrame = create({
{1,"Frame",{Active=true,Name="RightSide",BackgroundColor3=Color3.new(0.17647059261799,0.17647059261799,0.17647059261799),BorderSizePixel=0,}},
{2,"TextButton",{AutoButtonColor=false,BackgroundColor3=Color3.new(0.2549019753933,0.2549019753933,0.2549019753933),BorderSizePixel=0,Font=3,Name="Resizer",Parent={1},Size=UDim2.new(0,5,1,0),Text="",TextColor3=Color3.new(0,0,0),TextSize=14,}},
{3,"Frame",{BackgroundColor3=Color3.new(0.14117647707462,0.14117647707462,0.14117647707462),BorderSizePixel=0,Name="Line",Parent={2},Position=UDim2.new(0,4,0,0),Size=UDim2.new(0,1,1,0),}},
{4,"TextButton",{AutoButtonColor=false,BackgroundColor3=Color3.new(0.2549019753933,0.2549019753933,0.2549019753933),BorderSizePixel=0,Font=3,Name="WindowResizer",Parent={1},Position=UDim2.new(1,-300,0,0),Size=UDim2.new(1,0,0,4),Text="",TextColor3=Color3.new(0,0,0),TextSize=14,}},
{5,"Frame",{BackgroundColor3=Color3.new(0.14117647707462,0.14117647707462,0.14117647707462),BorderSizePixel=0,Name="Line",Parent={4},Size=UDim2.new(1,0,0,1),}},
})
rightSide.Frame = rightFrame
rightFrame.Position = UDim2.new(1,10,0,0)
rightSide.WindowResizer = rightFrame.WindowResizer
rightFrame.WindowResizer.Parent = nil
rightFrame.Parent = sidesGui
sideResizerHook(leftFrame.Resizer,"H",leftSide)
sideResizerHook(rightFrame.Resizer,"H",rightSide)
alignIndicator = Instance.new("ScreenGui")
alignIndicator.DisplayOrder = Main.DisplayOrders.Core
local indicator = Instance.new("Frame",alignIndicator)
indicator.BackgroundColor3 = Color3.fromRGB(0, 170, 255)
indicator.BorderSizePixel = 0
indicator.BackgroundTransparency = 0.8
indicator.Name = "Indicator"
local corner = Instance.new("UICorner",indicator)
corner.CornerRadius = UDim.new(0,10)
local leftToggle = create({{1,"TextButton",{AutoButtonColor=false,BackgroundColor3=Color3.new(0.20392157137394,0.20392157137394,0.20392157137394),BorderColor3=Color3.new(0.14117647707462,0.14117647707462,0.14117647707462),BorderMode=2,Font=10,Name="LeftToggle",Position=UDim2.new(0,0,0,-36),Size=UDim2.new(0,16,0,36),Text="<",TextColor3=Color3.new(1,1,1),TextSize=14,}}})
local rightToggle = leftToggle:Clone()
rightToggle.Name = "RightToggle"
rightToggle.Position = UDim2.new(1,-16,0,-36)
Lib.ButtonAnim(leftToggle,{Mode = 2,PressColor = Color3.fromRGB(32,32,32)})
Lib.ButtonAnim(rightToggle,{Mode = 2,PressColor = Color3.fromRGB(32,32,32)})
leftToggle.MouseButton1Click:Connect(function()
static.ToggleSide("left")
end)
rightToggle.MouseButton1Click:Connect(function()
static.ToggleSide("right")
end)
leftToggle.Parent = sidesGui
rightToggle.Parent = sidesGui
sidesGui:GetPropertyChangedSignal("AbsoluteSize"):Connect(function()
local maxWidth = math.max(300,sidesGui.AbsoluteSize.X-static.FreeWidth)
leftSide.Width = math.max(static.MinWidth,math.min(leftSide.Width,maxWidth-rightSide.Width))
rightSide.Width = math.max(static.MinWidth,math.min(rightSide.Width,maxWidth-leftSide.Width))
for i = 1,#visibleWindows do
visibleWindows[i]:MoveInBoundary()
end
updateWindows(true)
end)
sidesGui.DisplayOrder = sideDisplayOrder - 1
Lib.ShowGui(sidesGui)
updateSideFrames()
end
local mt = {__index = funcs}
static.new = function()
local obj = setmetatable({
Minimized = false,
Dragging = false,
Resizing = false,
Aligned = false,
Draggable = true,
Resizable = true,
ResizableInternal = true,
Alignable = true,
Closed = true,
SizeX = 300,
SizeY = 300,
MinX = 200,
MinY = 200,
PosX = 0,
PosY = 0,
GuiElems = {},
Tweens = {},
Elements = {},
OnActivate = Lib.Signal.new(),
OnDeactivate = Lib.Signal.new(),
OnMinimize = Lib.Signal.new(),
OnRestore = Lib.Signal.new()
},mt)
obj.Gui = createGui(obj)
return obj
end
return static
end)()
Lib.ContextMenu = (function()
local funcs = {}
local mouse
local function createGui(self)
local contextGui = create({
{1,"ScreenGui",{DisplayOrder=1000000,Name="Context",ZIndexBehavior=1,}},
{2,"Frame",{Active=true,BackgroundColor3=Color3.new(0.14117647707462,0.14117647707462,0.14117647707462),BorderColor3=Color3.new(0.14117647707462,0.14117647707462,0.14117647707462),Name="Main",Parent={1},Position=UDim2.new(0.5,-100,0.5,-150),Size=UDim2.new(0,200,0,100),}},
{3,"UICorner",{CornerRadius=UDim.new(0,4),Parent={2},}},
{4,"Frame",{BackgroundColor3=Color3.new(0.17647059261799,0.17647059261799,0.17647059261799),Name="Container",Parent={2},Position=UDim2.new(0,1,0,1),Size=UDim2.new(1,-2,1,-2),}},
{5,"UICorner",{CornerRadius=UDim.new(0,4),Parent={4},}},
{6,"ScrollingFrame",{Active=true,BackgroundColor3=Color3.new(0.20392157137394,0.20392157137394,0.20392157137394),BackgroundTransparency=1,BorderSizePixel=0,CanvasSize=UDim2.new(0,0,0,0),Name="List",Parent={4},Position=UDim2.new(0,2,0,2),ScrollBarImageColor3=Color3.new(0,0,0),ScrollBarThickness=4,Size=UDim2.new(1,-4,1,-4),VerticalScrollBarInset=1,}},
{7,"UIListLayout",{Parent={6},SortOrder=2,}},
{8,"Frame",{BackgroundColor3=Color3.new(0.20392157137394,0.20392157137394,0.20392157137394),BorderSizePixel=0,Name="SearchFrame",Parent={4},Size=UDim2.new(1,0,0,24),Visible=false,}},
{9,"Frame",{BackgroundColor3=Color3.new(0.14901961386204,0.14901961386204,0.14901961386204),BorderColor3=Color3.new(0.1176470592618,0.1176470592618,0.1176470592618),BorderSizePixel=0,Name="SearchContainer",Parent={8},Position=UDim2.new(0,3,0,3),Size=UDim2.new(1,-6,0,18),}},
{10,"TextBox",{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Font=3,Name="SearchBox",Parent={9},PlaceholderColor3=Color3.new(0.39215689897537,0.39215689897537,0.39215689897537),PlaceholderText="Search",Position=UDim2.new(0,4,0,0),Size=UDim2.new(1,-8,0,18),Text="",TextColor3=Color3.new(1,1,1),TextSize=14,TextXAlignment=0,}},
{11,"UICorner",{CornerRadius=UDim.new(0,2),Parent={9},}},
{12,"Frame",{BackgroundColor3=Color3.new(0.14117647707462,0.14117647707462,0.14117647707462),BorderSizePixel=0,Name="Line",Parent={8},Position=UDim2.new(0,0,1,0),Size=UDim2.new(1,0,0,1),}},
{13,"TextButton",{AutoButtonColor=false,BackgroundColor3=Color3.new(0.20392157137394,0.20392157137394,0.20392157137394),BackgroundTransparency=1,BorderColor3=Color3.new(0.33725491166115,0.49019610881805,0.73725491762161),BorderSizePixel=0,Font=3,Name="Entry",Parent={1},Size=UDim2.new(1,0,0,22),Text="",TextSize=14,Visible=false,}},
{14,"TextLabel",{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,BorderSizePixel=0,Font=3,Name="EntryName",Parent={13},Position=UDim2.new(0,24,0,0),Size=UDim2.new(1,-24,1,0),Text="Duplicate",TextColor3=Color3.new(0.86274516582489,0.86274516582489,0.86274516582489),TextSize=14,TextXAlignment=0,}},
{15,"TextLabel",{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Font=3,Name="Shortcut",Parent={13},Position=UDim2.new(0,24,0,0),Size=UDim2.new(1,-30,1,0),Text="Ctrl+D",TextColor3=Color3.new(0.86274516582489,0.86274516582489,0.86274516582489),TextSize=14,TextXAlignment=1,}},
{16,"ImageLabel",{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,ImageRectOffset=Vector2.new(304,0),ImageRectSize=Vector2.new(16,16),Name="Icon",Parent={13},Position=UDim2.new(0,2,0,3),ScaleType=4,Size=UDim2.new(0,16,0,16),}},
{17,"UICorner",{CornerRadius=UDim.new(0,4),Parent={13},}},
{18,"Frame",{BackgroundColor3=Color3.new(0.21568629145622,0.21568629145622,0.21568629145622),BackgroundTransparency=1,BorderSizePixel=0,Name="Divider",Parent={1},Position=UDim2.new(0,0,0,20),Size=UDim2.new(1,0,0,7),Visible=false,}},
{19,"Frame",{BackgroundColor3=Color3.new(0.20392157137394,0.20392157137394,0.20392157137394),BorderSizePixel=0,Name="Line",Parent={18},Position=UDim2.new(0,0,0.5,0),Size=UDim2.new(1,0,0,1),}},
{20,"TextLabel",{AnchorPoint=Vector2.new(0,0.5),BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,BorderSizePixel=0,Font=3,Name="DividerName",Parent={18},Position=UDim2.new(0,2,0.5,0),Size=UDim2.new(1,-4,1,0),Text="Objects",TextColor3=Color3.new(1,1,1),TextSize=14,TextTransparency=0.60000002384186,TextXAlignment=0,Visible=false,}},
})
self.GuiElems.Main = contextGui.Main
self.GuiElems.List = contextGui.Main.Container.List
self.GuiElems.Entry = contextGui.Entry
self.GuiElems.Divider = contextGui.Divider
self.GuiElems.SearchFrame = contextGui.Main.Container.SearchFrame
self.GuiElems.SearchBar = self.GuiElems.SearchFrame.SearchContainer.SearchBox
Lib.ViewportTextBox.convert(self.GuiElems.SearchBar)
self.GuiElems.SearchBar:GetPropertyChangedSignal("Text"):Connect(function()
local lower,find = string.lower,string.find
local searchText = lower(self.GuiElems.SearchBar.Text)
local items = self.Items
local map = self.ItemToEntryMap
if searchText ~= "" then
local results = {}
local count = 1
for i = 1,#items do
local item = items[i]
local entry = map[item]
if entry then
if not item.Divider and find(lower(item.Name),searchText,1,true) then
results[count] = item
count = count + 1
else
entry.Visible = false
end
end
end
table.sort(results,function(a,b) return a.Name < b.Name end)
for i = 1,#results do
local entry = map[results[i]]
entry.LayoutOrder = i
entry.Visible = true
end
else
for i = 1,#items do
local entry = map[items[i]]
if entry then entry.LayoutOrder = i entry.Visible = true end
end
end
local toSize = self.GuiElems.List.UIListLayout.AbsoluteContentSize.Y + 6
self.GuiElems.List.CanvasSize = UDim2.new(0,0,0,toSize-6)
end)
return contextGui
end
funcs.Add = function(self,item)
local newItem = {
Name = item.Name or "Item",
Icon = item.Icon or "",
Shortcut = item.Shortcut or "",
OnClick = item.OnClick,
OnHover = item.OnHover,
Disabled = item.Disabled or false,
DisabledIcon = item.DisabledIcon or "",
IconMap = item.IconMap,
OnRightClick = item.OnRightClick
}
if self.QueuedDivider then
local text = self.QueuedDividerText and #self.QueuedDividerText > 0 and self.QueuedDividerText
self:AddDivider(text)
end
self.Items[#self.Items+1] = newItem
self.Updated = nil
end
funcs.AddRegistered = function(self,name,disabled)
if not self.Registered[name] then error(name.." is not registered") end
if self.QueuedDivider then
local text = self.QueuedDividerText and #self.QueuedDividerText > 0 and self.QueuedDividerText
self:AddDivider(text)
end
self.Registered[name].Disabled = disabled
self.Items[#self.Items+1] = self.Registered[name]
self.Updated = nil
end
funcs.Register = function(self,name,item)
self.Registered[name] = {
Name = item.Name or "Item",
Icon = item.Icon or "",
Shortcut = item.Shortcut or "",
OnClick = item.OnClick,
OnHover = item.OnHover,
DisabledIcon = item.DisabledIcon or "",
IconMap = item.IconMap,
OnRightClick = item.OnRightClick
}
end
funcs.UnRegister = function(self,name)
self.Registered[name] = nil
end
funcs.AddDivider = function(self,text)
self.QueuedDivider = false
local textWidth = text and service.TextService:GetTextSize(text,14,Enum.Font.SourceSans,Vector2.new(999999999,20)).X or nil
table.insert(self.Items,{Divider = true, Text = text, TextSize = textWidth and textWidth+4})
self.Updated = nil
end
funcs.QueueDivider = function(self,text)
self.QueuedDivider = true
self.QueuedDividerText = text or ""
end
funcs.Clear = function(self)
self.Items = {}
self.Updated = nil
end
funcs.Refresh = function(self)
for i,v in pairs(self.GuiElems.List:GetChildren()) do
if not v:IsA("UIListLayout") then
v:Destroy()
end
end
local map = {}
self.ItemToEntryMap = map
local dividerFrame = self.GuiElems.Divider
local contextList = self.GuiElems.List
local entryFrame = self.GuiElems.Entry
local items = self.Items
for i = 1,#items do
local item = items[i]
if item.Divider then
local newDivider = dividerFrame:Clone()
newDivider.Line.BackgroundColor3 = self.Theme.DividerColor
if item.Text then
newDivider.Size = UDim2.new(1,0,0,20)
newDivider.Line.Position = UDim2.new(0,item.TextSize,0.5,0)
newDivider.Line.Size = UDim2.new(1,-item.TextSize,0,1)
newDivider.DividerName.TextColor3 = self.Theme.TextColor
newDivider.DividerName.Text = item.Text
newDivider.DividerName.Visible = true
end
newDivider.Visible = true
map[item] = newDivider
newDivider.Parent = contextList
else
local newEntry = entryFrame:Clone()
newEntry.BackgroundColor3 = self.Theme.HighlightColor
newEntry.EntryName.TextColor3 = self.Theme.TextColor
newEntry.EntryName.Text = item.Name
newEntry.Shortcut.Text = item.Shortcut
if item.Disabled then
newEntry.EntryName.TextColor3 = Color3.new(150/255,150/255,150/255)
newEntry.Shortcut.TextColor3 = Color3.new(150/255,150/255,150/255)
end
if self.Iconless then
newEntry.EntryName.Position = UDim2.new(0,2,0,0)
newEntry.EntryName.Size = UDim2.new(1,-4,0,20)
newEntry.Icon.Visible = false
else
local iconIndex = item.Disabled and item.DisabledIcon or item.Icon
if item.IconMap then
if type(iconIndex) == "number" then
item.IconMap:Display(newEntry.Icon,iconIndex)
elseif type(iconIndex) == "string" then
item.IconMap:DisplayByKey(newEntry.Icon,iconIndex)
end
elseif type(iconIndex) == "string" then
newEntry.Icon.Image = iconIndex
end
end
if not item.Disabled then
if item.OnClick then
newEntry.MouseButton1Click:Connect(function()
item.OnClick(item.Name)
if not item.NoHide then
self:Hide()
end
end)
end
if item.OnRightClick then
newEntry.MouseButton2Click:Connect(function()
item.OnRightClick(item.Name)
if not item.NoHide then
self:Hide()
end
end)
end
end
newEntry.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseMovement then
newEntry.BackgroundTransparency = 0
end
end)
newEntry.InputEnded:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseMovement then
newEntry.BackgroundTransparency = 1
end
end)
newEntry.Visible = true
map[item] = newEntry
newEntry.Parent = contextList
end
end
self.Updated = true
end
funcs.Show = function(self,x,y)
-- Initialize Gui
local elems = self.GuiElems
elems.SearchFrame.Visible = self.SearchEnabled
elems.List.Position = UDim2.new(0,2,0,2 + (self.SearchEnabled and 24 or 0))
elems.List.Size = UDim2.new(1,-4,1,-4 - (self.SearchEnabled and 24 or 0))
if self.SearchEnabled and self.ClearSearchOnShow then elems.SearchBar.Text = "" end
self.GuiElems.List.CanvasPosition = Vector2.new(0,0)
if not self.Updated then
self:Refresh() -- Create entries
end
-- Vars
local reverseY = false
local x,y = x or mouse.X, y or mouse.Y
local maxX,maxY = mouse.ViewSizeX,mouse.ViewSizeY
-- Position and show
if x + self.Width > maxX then
x = self.ReverseX and x - self.Width or maxX - self.Width
end
elems.Main.Position = UDim2.new(0,x,0,y)
elems.Main.Size = UDim2.new(0,self.Width,0,0)
self.Gui.DisplayOrder = Main.DisplayOrders.Menu
Lib.ShowGui(self.Gui)
-- Size adjustment
local toSize = elems.List.UIListLayout.AbsoluteContentSize.Y + 6 -- Padding
if self.MaxHeight and toSize > self.MaxHeight then
elems.List.CanvasSize = UDim2.new(0,0,0,toSize-6)
toSize = self.MaxHeight
else
elems.List.CanvasSize = UDim2.new(0,0,0,0)
end
if y + toSize > maxY then reverseY = true end
-- Close event
local closable
if self.CloseEvent then self.CloseEvent:Disconnect() end
self.CloseEvent = service.UserInputService.InputBegan:Connect(function(input)
if not closable or input.UserInputType ~= Enum.UserInputType.MouseButton1 then return end
if not Lib.CheckMouseInGui(elems.Main) then
self.CloseEvent:Disconnect()
self:Hide()
end
end)
-- Resize
if reverseY then
elems.Main.Position = UDim2.new(0,x,0,y-(self.ReverseYOffset or 0))
local newY = y - toSize - (self.ReverseYOffset or 0)
y = newY >= 0 and newY or 0
elems.Main:TweenSizeAndPosition(UDim2.new(0,self.Width,0,toSize),UDim2.new(0,x,0,y),Enum.EasingDirection.Out,Enum.EasingStyle.Quart,0.2,true)
else
elems.Main:TweenSize(UDim2.new(0,self.Width,0,toSize),Enum.EasingDirection.Out,Enum.EasingStyle.Quart,0.2,true)
end
-- Close debounce
Lib.FastWait()
if self.SearchEnabled and self.FocusSearchOnShow then elems.SearchBar:CaptureFocus() end
closable = true
end
funcs.Hide = function(self)
self.Gui.Parent = nil
end
funcs.ApplyTheme = function(self,data)
local theme = self.Theme
theme.ContentColor = data.ContentColor or Settings.Theme.Menu
theme.OutlineColor = data.OutlineColor or Settings.Theme.Menu
theme.DividerColor = data.DividerColor or Settings.Theme.Outline2
theme.TextColor = data.TextColor or Settings.Theme.Text
theme.HighlightColor = data.HighlightColor or Settings.Theme.Main1
self.GuiElems.Main.BackgroundColor3 = theme.OutlineColor
self.GuiElems.Main.Container.BackgroundColor3 = theme.ContentColor
end
local mt = {__index = funcs}
local function new()
if not mouse then mouse = Main.Mouse or service.Players.LocalPlayer:GetMouse() end
local obj = setmetatable({
Width = 200,
MaxHeight = nil,
Iconless = false,
SearchEnabled = false,
ClearSearchOnShow = true,
FocusSearchOnShow = true,
Updated = false,
QueuedDivider = false,
QueuedDividerText = "",
Items = {},
Registered = {},
GuiElems = {},
Theme = {}
},mt)
obj.Gui = createGui(obj)
obj:ApplyTheme({})
return obj
end
return {new = new}
end)()
Lib.CodeFrame = (function()
local funcs = {}
local typeMap = {
[1] = "String",
[2] = "String",
[3] = "String",
[4] = "Comment",
[5] = "Operator",
[6] = "Number",
[7] = "Keyword",
[8] = "BuiltIn",
[9] = "LocalMethod",
[10] = "LocalProperty",
[11] = "Nil",
[12] = "Bool",
[13] = "Function",
[14] = "Local",
[15] = "Self",
[16] = "FunctionName",
[17] = "Bracket"
}
local specialKeywordsTypes = {
["nil"] = 11,
["true"] = 12,
["false"] = 12,
["function"] = 13,
["local"] = 14,
["self"] = 15
}
local keywords = {
["and"] = true,
["break"] = true,
["do"] = true,
["else"] = true,
["elseif"] = true,
["end"] = true,
["false"] = true,
["for"] = true,
["function"] = true,
["if"] = true,
["in"] = true,
["local"] = true,
["nil"] = true,
["not"] = true,
["or"] = true,
["repeat"] = true,
["return"] = true,
["then"] = true,
["true"] = true,
["until"] = true,
["while"] = true,
["plugin"] = true
}
local builtIns = {
["delay"] = true,
["elapsedTime"] = true,
["require"] = true,
["spawn"] = true,
["tick"] = true,
["time"] = true,
["typeof"] = true,
["UserSettings"] = true,
["wait"] = true,
["warn"] = true,
["game"] = true,
["shared"] = true,
["script"] = true,
["workspace"] = true,
["assert"] = true,
["collectgarbage"] = true,
["error"] = true,
["getfenv"] = true,
["getmetatable"] = true,
["ipairs"] = true,
["loadstring"] = true,
["newproxy"] = true,
["next"] = true,
["pairs"] = true,
["pcall"] = true,
["print"] = true,
["rawequal"] = true,
["rawget"] = true,
["rawset"] = true,
["select"] = true,
["setfenv"] = true,
["setmetatable"] = true,
["tonumber"] = true,
["tostring"] = true,
["type"] = true,
["unpack"] = true,
["xpcall"] = true,
["_G"] = true,
["_VERSION"] = true,
["coroutine"] = true,
["debug"] = true,
["math"] = true,
["os"] = true,
["string"] = true,
["table"] = true,
["bit32"] = true,
["utf8"] = true,
["Axes"] = true,
["BrickColor"] = true,
["CFrame"] = true,
["Color3"] = true,
["ColorSequence"] = true,
["ColorSequenceKeypoint"] = true,
["DockWidgetPluginGuiInfo"] = true,
["Enum"] = true,
["Faces"] = true,
["Instance"] = true,
["NumberRange"] = true,
["NumberSequence"] = true,
["NumberSequenceKeypoint"] = true,
["PathWaypoint"] = true,
["PhysicalProperties"] = true,
["Random"] = true,
["Ray"] = true,
["Rect"] = true,
["Region3"] = true,
["Region3int16"] = true,
["TweenInfo"] = true,
["UDim"] = true,
["UDim2"] = true,
["Vector2"] = true,
["Vector2int16"] = true,
["Vector3"] = true,
["Vector3int16"] = true
}
local builtInInited = false
local richReplace = {
["'"] = "'",
["\""] = """,
["<"] = "<",
[">"] = ">",
["&"] = "&"
}
local tabSub = "\205"
local tabReplacement = (" %s%s "):format(tabSub,tabSub)
local tabJumps = {
[("[^%s] %s"):format(tabSub,tabSub)] = 0,
[(" %s%s"):format(tabSub,tabSub)] = -1,
[("%s%s "):format(tabSub,tabSub)] = 2,
[("%s [^%s]"):format(tabSub,tabSub)] = 1,
}
local tweenService = service.TweenService
local lineTweens = {}
local function initBuiltIn()
local env = getfenv()
local type = type
local tostring = tostring
for name,_ in next,builtIns do
local envVal = env[name]
if type(envVal) == "table" then
local items = {}
for i,v in next,envVal do
items[i] = true
end
builtIns[name] = items
end
end
local enumEntries = {}
local enums = Enum:GetEnums()
for i = 1,#enums do
enumEntries[tostring(enums[i])] = true
end
builtIns["Enum"] = enumEntries
builtInInited = true
end
local function setupEditBox(obj)
local editBox = obj.GuiElems.EditBox
editBox.Focused:Connect(function()
obj:ConnectEditBoxEvent()
obj.Editing = true
end)
editBox.FocusLost:Connect(function()
obj:DisconnectEditBoxEvent()
obj.Editing = false
end)
editBox:GetPropertyChangedSignal("Text"):Connect(function()
local text = editBox.Text
if #text == 0 or obj.EditBoxCopying then return end
editBox.Text = ""
obj:AppendText(text)
end)
end
local function setupMouseSelection(obj)
local mouse = plr:GetMouse()
local codeFrame = obj.GuiElems.LinesFrame
local lines = obj.Lines
codeFrame.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 then
local fontSizeX,fontSizeY = math.ceil(obj.FontSize/2),obj.FontSize
local relX = mouse.X - codeFrame.AbsolutePosition.X
local relY = mouse.Y - codeFrame.AbsolutePosition.Y
local selX = math.round(relX / fontSizeX) + obj.ViewX
local selY = math.floor(relY / fontSizeY) + obj.ViewY
local releaseEvent,mouseEvent,scrollEvent
local scrollPowerV,scrollPowerH = 0,0
selY = math.min(#lines-1,selY)
local relativeLine = lines[selY+1] or ""
selX = math.min(#relativeLine, selX + obj:TabAdjust(selX,selY))
obj.SelectionRange = {{-1,-1},{-1,-1}}
obj:MoveCursor(selX,selY)
obj.FloatCursorX = selX
local function updateSelection()
local relX = mouse.X - codeFrame.AbsolutePosition.X
local relY = mouse.Y - codeFrame.AbsolutePosition.Y
local sel2X = math.max(0,math.round(relX / fontSizeX) + obj.ViewX)
local sel2Y = math.max(0,math.floor(relY / fontSizeY) + obj.ViewY)
sel2Y = math.min(#lines-1,sel2Y)
local relativeLine = lines[sel2Y+1] or ""
sel2X = math.min(#relativeLine, sel2X + obj:TabAdjust(sel2X,sel2Y))
if sel2Y < selY or (sel2Y == selY and sel2X < selX) then
obj.SelectionRange = {{sel2X,sel2Y},{selX,selY}}
else
obj.SelectionRange = {{selX,selY},{sel2X,sel2Y}}
end
obj:MoveCursor(sel2X,sel2Y)
obj.FloatCursorX = sel2X
obj:Refresh()
end
releaseEvent = service.UserInputService.InputEnded:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 then
releaseEvent:Disconnect()
mouseEvent:Disconnect()
scrollEvent:Disconnect()
obj:SetCopyableSelection()
--updateSelection()
end
end)
mouseEvent = service.UserInputService.InputChanged:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseMovement then
local upDelta = mouse.Y - codeFrame.AbsolutePosition.Y
local downDelta = mouse.Y - codeFrame.AbsolutePosition.Y - codeFrame.AbsoluteSize.Y
local leftDelta = mouse.X - codeFrame.AbsolutePosition.X
local rightDelta = mouse.X - codeFrame.AbsolutePosition.X - codeFrame.AbsoluteSize.X
scrollPowerV = 0
scrollPowerH = 0
if downDelta > 0 then
scrollPowerV = math.floor(downDelta*0.05) + 1
elseif upDelta < 0 then
scrollPowerV = math.ceil(upDelta*0.05) - 1
end
if rightDelta > 0 then
scrollPowerH = math.floor(rightDelta*0.05) + 1
elseif leftDelta < 0 then
scrollPowerH = math.ceil(leftDelta*0.05) - 1
end
updateSelection()
end
end)
scrollEvent = game:GetService("RunService").RenderStepped:Connect(function()
if scrollPowerV ~= 0 or scrollPowerH ~= 0 then
obj:ScrollDelta(scrollPowerH,scrollPowerV)
updateSelection()
end
end)
obj:Refresh()
end
end)
end
local function makeFrame(obj)
local frame = create({
{1,"Frame",{BackgroundColor3=Color3.new(0.15686275064945,0.15686275064945,0.15686275064945),BorderSizePixel = 0,Position=UDim2.new(0.5,-300,0.5,-200),Size=UDim2.new(0,600,0,400),}},
})
local elems = {}
local linesFrame = Instance.new("Frame")
linesFrame.Name = "Lines"
linesFrame.BackgroundTransparency = 1
linesFrame.Size = UDim2.new(1,0,1,0)
linesFrame.ClipsDescendants = true
linesFrame.Parent = frame
local lineNumbersLabel = Instance.new("TextLabel")
lineNumbersLabel.Name = "LineNumbers"
lineNumbersLabel.BackgroundTransparency = 1
lineNumbersLabel.Font = Enum.Font.Code
lineNumbersLabel.TextXAlignment = Enum.TextXAlignment.Right
lineNumbersLabel.TextYAlignment = Enum.TextYAlignment.Top
lineNumbersLabel.ClipsDescendants = true
lineNumbersLabel.RichText = true
lineNumbersLabel.Parent = frame
local cursor = Instance.new("Frame")
cursor.Name = "Cursor"
cursor.BackgroundColor3 = Color3.fromRGB(220,220,220)
cursor.BorderSizePixel = 0
cursor.Parent = frame
local editBox = Instance.new("TextBox")
editBox.Name = "EditBox"
editBox.MultiLine = true
editBox.Visible = false
editBox.Parent = frame
lineTweens.Invis = tweenService:Create(cursor,TweenInfo.new(0.4,Enum.EasingStyle.Quart,Enum.EasingDirection.Out),{BackgroundTransparency = 1})
lineTweens.Vis = tweenService:Create(cursor,TweenInfo.new(0.2,Enum.EasingStyle.Quart,Enum.EasingDirection.Out),{BackgroundTransparency = 0})
elems.LinesFrame = linesFrame
elems.LineNumbersLabel = lineNumbersLabel
elems.Cursor = cursor
elems.EditBox = editBox
elems.ScrollCorner = create({{1,"Frame",{BackgroundColor3=Color3.new(0.15686275064945,0.15686275064945,0.15686275064945),BorderSizePixel=0,Name="ScrollCorner",Position=UDim2.new(1,-16,1,-16),Size=UDim2.new(0,16,0,16),Visible=false,}}})
elems.ScrollCorner.Parent = frame
linesFrame.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 then
obj:SetEditing(true,input)
end
end)
obj.Frame = frame
obj.Gui = frame
obj.GuiElems = elems
setupEditBox(obj)
setupMouseSelection(obj)
return frame
end
funcs.GetSelectionText = function(self)
if not self:IsValidRange() then return "" end
local selectionRange = self.SelectionRange
local selX,selY = selectionRange[1][1], selectionRange[1][2]
local sel2X,sel2Y = selectionRange[2][1], selectionRange[2][2]
local deltaLines = sel2Y-selY
local lines = self.Lines
if not lines[selY+1] or not lines[sel2Y+1] then return "" end
if deltaLines == 0 then
return self:ConvertText(lines[selY+1]:sub(selX+1,sel2X), false)
end
local leftSub = lines[selY+1]:sub(selX+1)
local rightSub = lines[sel2Y+1]:sub(1,sel2X)
local result = leftSub.."\n"
for i = selY+1,sel2Y-1 do
result = result..lines[i+1].."\n"
end
result = result..rightSub
return self:ConvertText(result,false)
end
funcs.SetCopyableSelection = function(self)
local text = self:GetSelectionText()
local editBox = self.GuiElems.EditBox
self.EditBoxCopying = true
editBox.Text = text
editBox.SelectionStart = 1
editBox.CursorPosition = #editBox.Text + 1
self.EditBoxCopying = false
end
funcs.ConnectEditBoxEvent = function(self)
if self.EditBoxEvent then
self.EditBoxEvent:Disconnect()
end
self.EditBoxEvent = service.UserInputService.InputBegan:Connect(function(input)
if input.UserInputType ~= Enum.UserInputType.Keyboard then return end
local keycodes = Enum.KeyCode
local keycode = input.KeyCode
local function setupMove(key,func)
local endCon,finished
endCon = service.UserInputService.InputEnded:Connect(function(input)
if input.KeyCode ~= key then return end
endCon:Disconnect()
finished = true
end)
func()
Lib.FastWait(0.5)
while not finished do func() Lib.FastWait(0.03) end
end
if keycode == keycodes.Down then
setupMove(keycodes.Down,function()
self.CursorX = self.FloatCursorX
self.CursorY = self.CursorY + 1
self:UpdateCursor()
self:JumpToCursor()
end)
elseif keycode == keycodes.Up then
setupMove(keycodes.Up,function()
self.CursorX = self.FloatCursorX
self.CursorY = self.CursorY - 1
self:UpdateCursor()
self:JumpToCursor()
end)
elseif keycode == keycodes.Left then
setupMove(keycodes.Left,function()
local line = self.Lines[self.CursorY+1] or ""
self.CursorX = self.CursorX - 1 - (line:sub(self.CursorX-3,self.CursorX) == tabReplacement and 3 or 0)
if self.CursorX < 0 then
self.CursorY = self.CursorY - 1
local line2 = self.Lines[self.CursorY+1] or ""
self.CursorX = #line2
end
self.FloatCursorX = self.CursorX
self:UpdateCursor()
self:JumpToCursor()
end)
elseif keycode == keycodes.Right then
setupMove(keycodes.Right,function()
local line = self.Lines[self.CursorY+1] or ""
self.CursorX = self.CursorX + 1 + (line:sub(self.CursorX+1,self.CursorX+4) == tabReplacement and 3 or 0)
if self.CursorX > #line then
self.CursorY = self.CursorY + 1
self.CursorX = 0
end
self.FloatCursorX = self.CursorX
self:UpdateCursor()
self:JumpToCursor()
end)
elseif keycode == keycodes.Backspace then
setupMove(keycodes.Backspace,function()
local startRange,endRange
if self:IsValidRange() then
startRange = self.SelectionRange[1]
endRange = self.SelectionRange[2]
else
endRange = {self.CursorX,self.CursorY}
end
if not startRange then
local line = self.Lines[self.CursorY+1] or ""
self.CursorX = self.CursorX - 1 - (line:sub(self.CursorX-3,self.CursorX) == tabReplacement and 3 or 0)
if self.CursorX < 0 then
self.CursorY = self.CursorY - 1
local line2 = self.Lines[self.CursorY+1] or ""
self.CursorX = #line2
end
self.FloatCursorX = self.CursorX
self:UpdateCursor()
startRange = startRange or {self.CursorX,self.CursorY}
end
self:DeleteRange({startRange,endRange},false,true)
self:ResetSelection(true)
self:JumpToCursor()
end)
elseif keycode == keycodes.Delete then
setupMove(keycodes.Delete,function()
local startRange,endRange
if self:IsValidRange() then
startRange = self.SelectionRange[1]
endRange = self.SelectionRange[2]
else
startRange = {self.CursorX,self.CursorY}
end
if not endRange then
local line = self.Lines[self.CursorY+1] or ""
local endCursorX = self.CursorX + 1 + (line:sub(self.CursorX+1,self.CursorX+4) == tabReplacement and 3 or 0)
local endCursorY = self.CursorY
if endCursorX > #line then
endCursorY = endCursorY + 1
endCursorX = 0
end
self:UpdateCursor()
endRange = endRange or {endCursorX,endCursorY}
end
self:DeleteRange({startRange,endRange},false,true)
self:ResetSelection(true)
self:JumpToCursor()
end)
elseif service.UserInputService:IsKeyDown(Enum.KeyCode.LeftControl) then
if keycode == keycodes.A then
self.SelectionRange = {{0,0},{#self.Lines[#self.Lines],#self.Lines-1}}
self:SetCopyableSelection()
self:Refresh()
end
end
end)
end
funcs.DisconnectEditBoxEvent = function(self)
if self.EditBoxEvent then
self.EditBoxEvent:Disconnect()
end
end
funcs.ResetSelection = function(self,norefresh)
self.SelectionRange = {{-1,-1},{-1,-1}}
if not norefresh then self:Refresh() end
end
funcs.IsValidRange = function(self,range)
local selectionRange = range or self.SelectionRange
local selX,selY = selectionRange[1][1], selectionRange[1][2]
local sel2X,sel2Y = selectionRange[2][1], selectionRange[2][2]
if selX == -1 or (selX == sel2X and selY == sel2Y) then return false end
return true
end
funcs.DeleteRange = function(self,range,noprocess,updatemouse)
range = range or self.SelectionRange
if not self:IsValidRange(range) then return end
local lines = self.Lines
local selX,selY = range[1][1], range[1][2]
local sel2X,sel2Y = range[2][1], range[2][2]
local deltaLines = sel2Y-selY
if not lines[selY+1] or not lines[sel2Y+1] then return end
local leftSub = lines[selY+1]:sub(1,selX)
local rightSub = lines[sel2Y+1]:sub(sel2X+1)
lines[selY+1] = leftSub..rightSub
local remove = table.remove
for i = 1,deltaLines do
remove(lines,selY+2)
end
if range == self.SelectionRange then self.SelectionRange = {{-1,-1},{-1,-1}} end
if updatemouse then
self.CursorX = selX
self.CursorY = selY
self:UpdateCursor()
end
if not noprocess then
self:ProcessTextChange()
end
end
funcs.AppendText = function(self,text)
self:DeleteRange(nil,true,true)
local lines,cursorX,cursorY = self.Lines,self.CursorX,self.CursorY
local line = lines[cursorY+1]
local before = line:sub(1,cursorX)
local after = line:sub(cursorX+1)
text = text:gsub("\r\n","\n")
text = self:ConvertText(text,true) -- Tab Convert
local textLines = text:split("\n")
local insert = table.insert
for i = 1,#textLines do
local linePos = cursorY+i
if i > 1 then insert(lines,linePos,"") end
local textLine = textLines[i]
local newBefore = (i == 1 and before or "")
local newAfter = (i == #textLines and after or "")
lines[linePos] = newBefore..textLine..newAfter
end
if #textLines > 1 then cursorX = 0 end
self:ProcessTextChange()
self.CursorX = cursorX + #textLines[#textLines]
self.CursorY = cursorY + #textLines-1
self:UpdateCursor()
end
funcs.ScrollDelta = function(self,x,y)
self.ScrollV:ScrollTo(self.ScrollV.Index + y)
self.ScrollH:ScrollTo(self.ScrollH.Index + x)
end
-- x and y starts at 0
funcs.TabAdjust = function(self,x,y)
local lines = self.Lines
local line = lines[y+1]
x=x+1
if line then
local left = line:sub(x-1,x-1)
local middle = line:sub(x,x)
local right = line:sub(x+1,x+1)
local selRange = (#left > 0 and left or " ") .. (#middle > 0 and middle or " ") .. (#right > 0 and right or " ")
for i,v in pairs(tabJumps) do
if selRange:find(i) then
return v
end
end
end
return 0
end
funcs.SetEditing = function(self,on,input)
self:UpdateCursor(input)
if on then
if self.Editable then
self.GuiElems.EditBox.Text = ""
self.GuiElems.EditBox:CaptureFocus()
end
else
self.GuiElems.EditBox:ReleaseFocus()
end
end
funcs.CursorAnim = function(self,on)
local cursor = self.GuiElems.Cursor
local animTime = tick()
self.LastAnimTime = animTime
if not on then return end
lineTweens.Invis:Cancel()
lineTweens.Vis:Cancel()
cursor.BackgroundTransparency = 0
coroutine.wrap(function()
while self.Editable do
Lib.FastWait(0.5)
if self.LastAnimTime ~= animTime then return end
lineTweens.Invis:Play()
Lib.FastWait(0.4)
if self.LastAnimTime ~= animTime then return end
lineTweens.Vis:Play()
Lib.FastWait(0.2)
end
end)()
end
funcs.MoveCursor = function(self,x,y)
self.CursorX = x
self.CursorY = y
self:UpdateCursor()
self:JumpToCursor()
end
funcs.JumpToCursor = function(self)
self:Refresh()
end
funcs.UpdateCursor = function(self,input)
local linesFrame = self.GuiElems.LinesFrame
local cursor = self.GuiElems.Cursor
local hSize = math.max(0,linesFrame.AbsoluteSize.X)
local vSize = math.max(0,linesFrame.AbsoluteSize.Y)
local maxLines = math.ceil(vSize / self.FontSize)
local maxCols = math.ceil(hSize / math.ceil(self.FontSize/2))
local viewX,viewY = self.ViewX,self.ViewY
local totalLinesStr = tostring(#self.Lines)
local fontWidth = math.ceil(self.FontSize / 2)
local linesOffset = #totalLinesStr*fontWidth + 4*fontWidth
if input then
local linesFrame = self.GuiElems.LinesFrame
local frameX,frameY = linesFrame.AbsolutePosition.X,linesFrame.AbsolutePosition.Y
local mouseX,mouseY = input.Position.X,input.Position.Y
local fontSizeX,fontSizeY = math.ceil(self.FontSize/2),self.FontSize
self.CursorX = self.ViewX + math.round((mouseX - frameX) / fontSizeX)
self.CursorY = self.ViewY + math.floor((mouseY - frameY) / fontSizeY)
end
local cursorX,cursorY = self.CursorX,self.CursorY
local line = self.Lines[cursorY+1] or ""
if cursorX > #line then cursorX = #line
elseif cursorX < 0 then cursorX = 0 end
if cursorY >= #self.Lines then
cursorY = math.max(0,#self.Lines-1)
elseif cursorY < 0 then
cursorY = 0
end
cursorX = cursorX + self:TabAdjust(cursorX,cursorY)
-- Update modified
self.CursorX = cursorX
self.CursorY = cursorY
local cursorVisible = (cursorX >= viewX) and (cursorY >= viewY) and (cursorX <= viewX + maxCols) and (cursorY <= viewY + maxLines)
if cursorVisible then
local offX = (cursorX - viewX)
local offY = (cursorY - viewY)
cursor.Position = UDim2.new(0,linesOffset + offX*math.ceil(self.FontSize/2) - 1,0,offY*self.FontSize)
cursor.Size = UDim2.new(0,1,0,self.FontSize+2)
cursor.Visible = true
self:CursorAnim(true)
else
cursor.Visible = false
end
end
funcs.MapNewLines = function(self)
local newLines = {}
local count = 1
local text = self.Text
local find = string.find
local init = 1
local pos = find(text,"\n",init,true)
while pos do
newLines[count] = pos
count = count + 1
init = pos + 1
pos = find(text,"\n",init,true)
end
self.NewLines = newLines
end
funcs.PreHighlight = function(self)
local start = tick()
local text = self.Text:gsub("\\\\"," ")
--print("BACKSLASH SUB",tick()-start)
local textLen = #text
local found = {}
local foundMap = {}
local extras = {}
local find = string.find
local sub = string.sub
self.ColoredLines = {}
local function findAll(str,pattern,typ,raw)
local count = #found+1
local init = 1
local x,y,extra = find(str,pattern,init,raw)
while x do
found[count] = x
foundMap[x] = typ
if extra then
extras[x] = extra
end
count = count+1
init = y+1
x,y,extra = find(str,pattern,init,raw)
end
end
local start = tick()
findAll(text,'"',1,true)
findAll(text,"'",2,true)
findAll(text,"%[(=*)%[",3)
findAll(text,"--",4,true)
table.sort(found)
local newLines = self.NewLines
local curLine = 0
local lineTableCount = 1
local lineStart = 0
local lineEnd = 0
local lastEnding = 0
local foundHighlights = {}
for i = 1,#found do
local pos = found[i]
if pos <= lastEnding then continue end
local ending = pos
local typ = foundMap[pos]
if typ == 1 then
ending = find(text,'"',pos+1,true)
while ending and sub(text,ending-1,ending-1) == "\\" do
ending = find(text,'"',ending+1,true)
end
if not ending then ending = textLen end
elseif typ == 2 then
ending = find(text,"'",pos+1,true)
while ending and sub(text,ending-1,ending-1) == "\\" do
ending = find(text,"'",ending+1,true)
end
if not ending then ending = textLen end
elseif typ == 3 then
_,ending = find(text,"]"..extras[pos].."]",pos+1,true)
if not ending then ending = textLen end
elseif typ == 4 then
local ahead = foundMap[pos+2]
if ahead == 3 then
_,ending = find(text,"]"..extras[pos+2].."]",pos+1,true)
if not ending then ending = textLen end
else
ending = find(text,"\n",pos+1,true) or textLen
end
end
while pos > lineEnd do
curLine = curLine + 1
--lineTableCount = 1
lineEnd = newLines[curLine] or textLen+1
end
while true do
local lineTable = foundHighlights[curLine]
if not lineTable then lineTable = {} foundHighlights[curLine] = lineTable end
lineTable[pos] = {typ,ending}
--lineTableCount = lineTableCount + 1
if ending > lineEnd then
curLine = curLine + 1
lineEnd = newLines[curLine] or textLen+1
else
break
end
end
lastEnding = ending
--if i < 200 then print(curLine) end
end
self.PreHighlights = foundHighlights
--print(tick()-start)
--print(#found,curLine)
end
funcs.HighlightLine = function(self,line)
local cached = self.ColoredLines[line]
if cached then return cached end
local sub = string.sub
local find = string.find
local match = string.match
local highlights = {}
local preHighlights = self.PreHighlights[line] or {}
local lineText = self.Lines[line] or ""
local lineLen = #lineText
local lastEnding = 0
local currentType = 0
local lastWord = nil
local wordBeginsDotted = false
local funcStatus = 0
local lineStart = self.NewLines[line-1] or 0
local preHighlightMap = {}
for pos,data in next,preHighlights do
local relativePos = pos-lineStart
if relativePos < 1 then
currentType = data[1]
lastEnding = data[2] - lineStart
--warn(pos,data[2])
else
preHighlightMap[relativePos] = {data[1],data[2]-lineStart}
end
end
for col = 1,#lineText do
if col <= lastEnding then highlights[col] = currentType continue end
local pre = preHighlightMap[col]
if pre then
currentType = pre[1]
lastEnding = pre[2]
highlights[col] = currentType
wordBeginsDotted = false
lastWord = nil
funcStatus = 0
else
local char = sub(lineText,col,col)
if find(char,"[%a_]") then
local word = match(lineText,"[%a%d_]+",col)
local wordType = (keywords[word] and 7) or (builtIns[word] and 8)
lastEnding = col+#word-1
if wordType ~= 7 then
if wordBeginsDotted then
local prevBuiltIn = lastWord and builtIns[lastWord]
wordType = (prevBuiltIn and type(prevBuiltIn) == "table" and prevBuiltIn[word] and 8) or 10
end
if wordType ~= 8 then
local x,y,br = find(lineText,"^%s*([%({\"'])",lastEnding+1)
if x then
wordType = (funcStatus > 0 and br == "(" and 16) or 9
funcStatus = 0
end
end
else
wordType = specialKeywordsTypes[word] or wordType
funcStatus = (word == "function" and 1 or 0)
end
lastWord = word
wordBeginsDotted = false
if funcStatus > 0 then funcStatus = 1 end
if wordType then
currentType = wordType
highlights[col] = currentType
else
currentType = nil
end
elseif find(char,"%p") then
local isDot = (char == ".")
local isNum = isDot and find(sub(lineText,col+1,col+1),"%d")
highlights[col] = (isNum and 6 or 5)
if not isNum then
local dotStr = isDot and match(lineText,"%.%.?%.?",col)
if dotStr and #dotStr > 1 then
currentType = 5
lastEnding = col+#dotStr-1
wordBeginsDotted = false
lastWord = nil
funcStatus = 0
else
if isDot then
if wordBeginsDotted then
lastWord = nil
else
wordBeginsDotted = true
end
else
wordBeginsDotted = false
lastWord = nil
end
funcStatus = ((isDot or char == ":") and funcStatus == 1 and 2) or 0
end
end
elseif find(char,"%d") then
local _,endPos = find(lineText,"%x+",col)
local endPart = sub(lineText,endPos,endPos+1)
if (endPart == "e+" or endPart == "e-") and find(sub(lineText,endPos+2,endPos+2),"%d") then
endPos = endPos + 1
end
currentType = 6
lastEnding = endPos
highlights[col] = 6
wordBeginsDotted = false
lastWord = nil
funcStatus = 0
else
highlights[col] = currentType
local _,endPos = find(lineText,"%s+",col)
if endPos then
lastEnding = endPos
end
end
end
end
self.ColoredLines[line] = highlights
return highlights
end
funcs.Refresh = function(self)
local start = tick()
local linesFrame = self.Frame.Lines
local hSize = math.max(0,linesFrame.AbsoluteSize.X)
local vSize = math.max(0,linesFrame.AbsoluteSize.Y)
local maxLines = math.ceil(vSize / self.FontSize)
local maxCols = math.ceil(hSize / math.ceil(self.FontSize/2))
local gsub = string.gsub
local sub = string.sub
local viewX,viewY = self.ViewX,self.ViewY
local lineNumberStr = ""
for row = 1,maxLines do
local lineFrame = self.LineFrames[row]
if not lineFrame then
lineFrame = Instance.new("Frame")
lineFrame.Name = "Line"
lineFrame.Position = UDim2.new(0,0,0,(row-1)*self.FontSize)
lineFrame.Size = UDim2.new(1,0,0,self.FontSize)
lineFrame.BorderSizePixel = 0
lineFrame.BackgroundTransparency = 1
local selectionHighlight = Instance.new("Frame")
selectionHighlight.Name = "SelectionHighlight"
selectionHighlight.BorderSizePixel = 0
selectionHighlight.BackgroundColor3 = Settings.Theme.Syntax.SelectionBack
selectionHighlight.Parent = lineFrame
local label = Instance.new("TextLabel")
label.Name = "Label"
label.BackgroundTransparency = 1
label.Font = Enum.Font.Code
label.TextSize = self.FontSize
label.Size = UDim2.new(1,0,0,self.FontSize)
label.RichText = true
label.TextXAlignment = Enum.TextXAlignment.Left
label.TextColor3 = self.Colors.Text
label.ZIndex = 2
label.Parent = lineFrame
lineFrame.Parent = linesFrame
self.LineFrames[row] = lineFrame
end
local relaY = viewY + row
local lineText = self.Lines[relaY] or ""
local resText = ""
local highlights = self:HighlightLine(relaY)
local colStart = viewX + 1
local richTemplates = self.RichTemplates
local textTemplate = richTemplates.Text
local selectionTemplate = richTemplates.Selection
local curType = highlights[colStart]
local curTemplate = richTemplates[typeMap[curType]] or textTemplate
-- Selection Highlight
local selectionRange = self.SelectionRange
local selPos1 = selectionRange[1]
local selPos2 = selectionRange[2]
local selRow,selColumn = selPos1[2],selPos1[1]
local sel2Row,sel2Column = selPos2[2],selPos2[1]
local selRelaX,selRelaY = viewX,relaY-1
if selRelaY >= selPos1[2] and selRelaY <= selPos2[2] then
local fontSizeX = math.ceil(self.FontSize/2)
local posX = (selRelaY == selPos1[2] and selPos1[1] or 0) - viewX
local sizeX = (selRelaY == selPos2[2] and selPos2[1]-posX-viewX or maxCols+viewX)
lineFrame.SelectionHighlight.Position = UDim2.new(0,posX*fontSizeX,0,0)
lineFrame.SelectionHighlight.Size = UDim2.new(0,sizeX*fontSizeX,1,0)
lineFrame.SelectionHighlight.Visible = true
else
lineFrame.SelectionHighlight.Visible = false
end
-- Selection Text Color for first char
local inSelection = selRelaY >= selRow and selRelaY <= sel2Row and (selRelaY == selRow and viewX >= selColumn or selRelaY ~= selRow) and (selRelaY == sel2Row and viewX < sel2Column or selRelaY ~= sel2Row)
if inSelection then
curType = -999
curTemplate = selectionTemplate
end
for col = 2,maxCols do
local relaX = viewX + col
local selRelaX = relaX-1
local posType = highlights[relaX]
-- Selection Text Color
local inSelection = selRelaY >= selRow and selRelaY <= sel2Row and (selRelaY == selRow and selRelaX >= selColumn or selRelaY ~= selRow) and (selRelaY == sel2Row and selRelaX < sel2Column or selRelaY ~= sel2Row)
if inSelection then
posType = -999
end
if posType ~= curType then
local template = (inSelection and selectionTemplate) or richTemplates[typeMap[posType]] or textTemplate
if template ~= curTemplate then
local nextText = gsub(sub(lineText,colStart,relaX-1),"['\"<>&]",richReplace)
resText = resText .. (curTemplate ~= textTemplate and (curTemplate .. nextText .. "</font>") or nextText)
colStart = relaX
curTemplate = template
end
curType = posType
end
end
local lastText = gsub(sub(lineText,colStart,viewX+maxCols),"['\"<>&]",richReplace)
--warn("SUB",colStart,viewX+maxCols-1)
if #lastText > 0 then
resText = resText .. (curTemplate ~= textTemplate and (curTemplate .. lastText .. "</font>") or lastText)
end
if self.Lines[relaY] then
lineNumberStr = lineNumberStr .. (relaY == self.CursorY and ("<b>"..relaY.."</b>\n") or relaY .. "\n")
end
lineFrame.Label.Text = resText
end
for i = maxLines+1,#self.LineFrames do
self.LineFrames[i]:Destroy()
self.LineFrames[i] = nil
end
self.Frame.LineNumbers.Text = lineNumberStr
self:UpdateCursor()
--print("REFRESH TIME",tick()-start)
end
funcs.UpdateView = function(self)
local totalLinesStr = tostring(#self.Lines)
local fontWidth = math.ceil(self.FontSize / 2)
local linesOffset = #totalLinesStr*fontWidth + 4*fontWidth
local linesFrame = self.Frame.Lines
local hSize = linesFrame.AbsoluteSize.X
local vSize = linesFrame.AbsoluteSize.Y
local maxLines = math.ceil(vSize / self.FontSize)
local totalWidth = self.MaxTextCols*fontWidth
local scrollV = self.ScrollV
local scrollH = self.ScrollH
scrollV.VisibleSpace = maxLines
scrollV.TotalSpace = #self.Lines + 1
scrollH.VisibleSpace = math.ceil(hSize/fontWidth)
scrollH.TotalSpace = self.MaxTextCols + 1
scrollV.Gui.Visible = #self.Lines + 1 > maxLines
scrollH.Gui.Visible = totalWidth > hSize
local oldOffsets = self.FrameOffsets
self.FrameOffsets = Vector2.new(scrollV.Gui.Visible and -16 or 0, scrollH.Gui.Visible and -16 or 0)
if oldOffsets ~= self.FrameOffsets then
self:UpdateView()
else
scrollV:ScrollTo(self.ViewY,true)
scrollH:ScrollTo(self.ViewX,true)
if scrollV.Gui.Visible and scrollH.Gui.Visible then
scrollV.Gui.Size = UDim2.new(0,16,1,-16)
scrollH.Gui.Size = UDim2.new(1,-16,0,16)
self.GuiElems.ScrollCorner.Visible = true
else
scrollV.Gui.Size = UDim2.new(0,16,1,0)
scrollH.Gui.Size = UDim2.new(1,0,0,16)
self.GuiElems.ScrollCorner.Visible = false
end
self.ViewY = scrollV.Index
self.ViewX = scrollH.Index
self.Frame.Lines.Position = UDim2.new(0,linesOffset,0,0)
self.Frame.Lines.Size = UDim2.new(1,-linesOffset+oldOffsets.X,1,oldOffsets.Y)
self.Frame.LineNumbers.Position = UDim2.new(0,fontWidth,0,0)
self.Frame.LineNumbers.Size = UDim2.new(0,#totalLinesStr*fontWidth,1,oldOffsets.Y)
self.Frame.LineNumbers.TextSize = self.FontSize
end
end
funcs.ProcessTextChange = function(self)
local maxCols = 0
local lines = self.Lines
for i = 1,#lines do
local lineLen = #lines[i]
if lineLen > maxCols then
maxCols = lineLen
end
end
self.MaxTextCols = maxCols
self:UpdateView()
self.Text = table.concat(self.Lines,"\n")
self:MapNewLines()
self:PreHighlight()
self:Refresh()
--self.TextChanged:Fire()
end
funcs.ConvertText = function(self,text,toEditor)
if toEditor then
return text:gsub("\t",(" %s%s "):format(tabSub,tabSub))
else
return text:gsub((" %s%s "):format(tabSub,tabSub),"\t")
end
end
funcs.GetText = function(self) -- TODO: better (use new tab format)
local source = table.concat(self.Lines,"\n")
return self:ConvertText(source,false) -- Tab Convert
end
funcs.SetText = function(self,txt)
txt = self:ConvertText(txt,true) -- Tab Convert
local lines = self.Lines
table.clear(lines)
local count = 1
for line in txt:gmatch("([^\n\r]*)[\n\r]?") do
local len = #line
lines[count] = line
count = count + 1
end
self:ProcessTextChange()
end
funcs.MakeRichTemplates = function(self)
local floor = math.floor
local templates = {}
for name,color in pairs(self.Colors) do
templates[name] = ('<font color="rgb(%s,%s,%s)">'):format(floor(color.r*255),floor(color.g*255),floor(color.b*255))
end
self.RichTemplates = templates
end
funcs.ApplyTheme = function(self)
local colors = Settings.Theme.Syntax
self.Colors = colors
self.Frame.LineNumbers.TextColor3 = colors.Text
self.Frame.BackgroundColor3 = colors.Background
end
local mt = {__index = funcs}
local function new()
if not builtInInited then initBuiltIn() end
local scrollV = Lib.ScrollBar.new()
local scrollH = Lib.ScrollBar.new(true)
scrollH.Gui.Position = UDim2.new(0,0,1,-16)
local obj = setmetatable({
FontSize = 15,
ViewX = 0,
ViewY = 0,
Colors = Settings.Theme.Syntax,
ColoredLines = {},
Lines = {""},
LineFrames = {},
Editable = true,
Editing = false,
CursorX = 0,
CursorY = 0,
FloatCursorX = 0,
Text = "",
PreHighlights = {},
SelectionRange = {{-1,-1},{-1,-1}},
NewLines = {},
FrameOffsets = Vector2.new(0,0),
MaxTextCols = 0,
ScrollV = scrollV,
ScrollH = scrollH
},mt)
scrollV.WheelIncrement = 3
scrollH.Increment = 2
scrollH.WheelIncrement = 7
scrollV.Scrolled:Connect(function()
obj.ViewY = scrollV.Index
obj:Refresh()
end)
scrollH.Scrolled:Connect(function()
obj.ViewX = scrollH.Index
obj:Refresh()
end)
makeFrame(obj)
obj:MakeRichTemplates()
obj:ApplyTheme()
scrollV:SetScrollFrame(obj.Frame.Lines)
scrollV.Gui.Parent = obj.Frame
scrollH.Gui.Parent = obj.Frame
obj:UpdateView()
obj.Frame:GetPropertyChangedSignal("AbsoluteSize"):Connect(function()
obj:UpdateView()
obj:Refresh()
end)
return obj
end
return {new = new}
end)()
Lib.Checkbox = (function()
local funcs = {}
local c3 = Color3.fromRGB
local v2 = Vector2.new
local ud2s = UDim2.fromScale
local ud2o = UDim2.fromOffset
local ud = UDim.new
local max = math.max
local new = Instance.new
local TweenSize = new("Frame").TweenSize
local ti = TweenInfo.new
local delay = delay
local function ripple(object, color)
local circle = new('Frame')
circle.BackgroundColor3 = color
circle.BackgroundTransparency = 0.75
circle.BorderSizePixel = 0
circle.AnchorPoint = v2(0.5, 0.5)
circle.Size = ud2o()
circle.Position = ud2s(0.5, 0.5)
circle.Parent = object
local rounding = new('UICorner')
rounding.CornerRadius = ud(1)
rounding.Parent = circle
local abssz = object.AbsoluteSize
local size = max(abssz.X, abssz.Y) * 5/3
TweenSize(circle, ud2o(size, size), "Out", "Quart", 0.4)
service.TweenService:Create(circle, ti(0.4, Enum.EasingStyle.Quart, Enum.EasingDirection.In), {BackgroundTransparency = 1}):Play()
service.Debris:AddItem(circle, 0.4)
end
local function initGui(self,frame)
local checkbox = frame or create({
{1,"Frame",{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,BorderSizePixel=0,Name="Checkbox",Position=UDim2.new(0,3,0,3),Size=UDim2.new(0,16,0,16),}},
{2,"Frame",{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,BorderSizePixel=0,Name="ripples",Parent={1},Size=UDim2.new(1,0,1,0),}},
{3,"Frame",{BackgroundColor3=Color3.new(0.10196078568697,0.10196078568697,0.10196078568697),BorderSizePixel=0,Name="outline",Parent={1},Size=UDim2.new(0,16,0,16),}},
{4,"Frame",{BackgroundColor3=Color3.new(0.14117647707462,0.14117647707462,0.14117647707462),BorderSizePixel=0,Name="filler",Parent={3},Position=UDim2.new(0,1,0,1),Size=UDim2.new(0,14,0,14),}},
{5,"Frame",{BackgroundColor3=Color3.new(0.90196084976196,0.90196084976196,0.90196084976196),BorderSizePixel=0,Name="top",Parent={4},Size=UDim2.new(0,16,0,0),}},
{6,"Frame",{AnchorPoint=Vector2.new(0,1),BackgroundColor3=Color3.new(0.90196084976196,0.90196084976196,0.90196084976196),BorderSizePixel=0,Name="bottom",Parent={4},Position=UDim2.new(0,0,0,14),Size=UDim2.new(0,16,0,0),}},
{7,"Frame",{BackgroundColor3=Color3.new(0.90196084976196,0.90196084976196,0.90196084976196),BorderSizePixel=0,Name="left",Parent={4},Size=UDim2.new(0,0,0,16),}},
{8,"Frame",{AnchorPoint=Vector2.new(1,0),BackgroundColor3=Color3.new(0.90196084976196,0.90196084976196,0.90196084976196),BorderSizePixel=0,Name="right",Parent={4},Position=UDim2.new(0,14,0,0),Size=UDim2.new(0,0,0,16),}},
{9,"Frame",{AnchorPoint=Vector2.new(0.5,0.5),BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,BorderSizePixel=0,ClipsDescendants=true,Name="checkmark",Parent={4},Position=UDim2.new(0.5,0,0.5,0),Size=UDim2.new(0,0,0,20),}},
{10,"ImageLabel",{AnchorPoint=Vector2.new(0.5,0.5),BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,BorderSizePixel=0,Image="rbxassetid://6234266378",Parent={9},Position=UDim2.new(0.5,0,0.5,0),ScaleType=3,Size=UDim2.new(0,15,0,11),}},
{11,"ImageLabel",{AnchorPoint=Vector2.new(0.5,0.5),BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Image="rbxassetid://6401617475",ImageColor3=Color3.new(0.20784313976765,0.69803923368454,0.98431372642517),Name="checkmark2",Parent={4},Position=UDim2.new(0.5,0,0.5,0),Size=UDim2.new(0,12,0,12),Visible=false,}},
{12,"ImageLabel",{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Image="rbxassetid://6425281788",ImageTransparency=0.20000000298023,Name="middle",Parent={4},ScaleType=2,Size=UDim2.new(1,0,1,0),TileSize=UDim2.new(0,2,0,2),Visible=false,}},
{13,"UICorner",{CornerRadius=UDim.new(0,2),Parent={3},}},
})
local outline = checkbox.outline
local filler = outline.filler
local checkmark = filler.checkmark
local ripples_container = checkbox.ripples
-- walls
local top, bottom, left, right = filler.top, filler.bottom, filler.left, filler.right
self.Gui = checkbox
self.GuiElems = {
Top = top,
Bottom = bottom,
Left = left,
Right = right,
Outline = outline,
Filler = filler,
Checkmark = checkmark,
Checkmark2 = filler.checkmark2,
Middle = filler.middle
}
checkbox.InputBegan:Connect(function(i)
if i.UserInputType == Enum.UserInputType.MouseButton1 then
local release
release = service.UserInputService.InputEnded:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 then
release:Disconnect()
if Lib.CheckMouseInGui(checkbox) then
if self.Style == 0 then
ripple(ripples_container, self.Disabled and self.Colors.Disabled or self.Colors.Primary)
end
if not self.Disabled then
self:SetState(not self.Toggled,true)
else
self:Paint()
end
self.OnInput:Fire()
end
end
end)
end
end)
self:Paint()
end
funcs.Collapse = function(self,anim)
local guiElems = self.GuiElems
if anim then
TweenSize(guiElems.Top, ud2o(14, 14), "In", "Quart", 4/15, true)
TweenSize(guiElems.Bottom, ud2o(14, 14), "In", "Quart", 4/15, true)
TweenSize(guiElems.Left, ud2o(14, 14), "In", "Quart", 4/15, true)
TweenSize(guiElems.Right, ud2o(14, 14), "In", "Quart", 4/15, true)
else
guiElems.Top.Size = ud2o(14, 14)
guiElems.Bottom.Size = ud2o(14, 14)
guiElems.Left.Size = ud2o(14, 14)
guiElems.Right.Size = ud2o(14, 14)
end
end
funcs.Expand = function(self,anim)
local guiElems = self.GuiElems
if anim then
TweenSize(guiElems.Top, ud2o(14, 0), "InOut", "Quart", 4/15, true)
TweenSize(guiElems.Bottom, ud2o(14, 0), "InOut", "Quart", 4/15, true)
TweenSize(guiElems.Left, ud2o(0, 14), "InOut", "Quart", 4/15, true)
TweenSize(guiElems.Right, ud2o(0, 14), "InOut", "Quart", 4/15, true)
else
guiElems.Top.Size = ud2o(14, 0)
guiElems.Bottom.Size = ud2o(14, 0)
guiElems.Left.Size = ud2o(0, 14)
guiElems.Right.Size = ud2o(0, 14)
end
end
funcs.Paint = function(self)
local guiElems = self.GuiElems
if self.Style == 0 then
local color_base = self.Disabled and self.Colors.Disabled
guiElems.Outline.BackgroundColor3 = color_base or (self.Toggled and self.Colors.Primary) or self.Colors.Secondary
local walls_color = color_base or self.Colors.Primary
guiElems.Top.BackgroundColor3 = walls_color
guiElems.Bottom.BackgroundColor3 = walls_color
guiElems.Left.BackgroundColor3 = walls_color
guiElems.Right.BackgroundColor3 = walls_color
else
guiElems.Outline.BackgroundColor3 = self.Disabled and self.Colors.Disabled or self.Colors.Secondary
guiElems.Filler.BackgroundColor3 = self.Disabled and self.Colors.DisabledBackground or self.Colors.Background
guiElems.Checkmark2.ImageColor3 = self.Disabled and self.Colors.DisabledCheck or self.Colors.Primary
end
end
funcs.SetState = function(self,val,anim)
self.Toggled = val
if self.OutlineColorTween then self.OutlineColorTween:Cancel() end
local setStateTime = tick()
self.LastSetStateTime = setStateTime
if self.Toggled then
if self.Style == 0 then
if anim then
self.OutlineColorTween = service.TweenService:Create(self.GuiElems.Outline, ti(4/15, Enum.EasingStyle.Circular, Enum.EasingDirection.Out), {BackgroundColor3 = self.Colors.Primary})
self.OutlineColorTween:Play()
delay(0.15, function()
if setStateTime ~= self.LastSetStateTime then return end
self:Paint()
TweenSize(self.GuiElems.Checkmark, ud2o(14, 20), "Out", "Bounce", 2/15, true)
end)
else
self.GuiElems.Outline.BackgroundColor3 = self.Colors.Primary
self:Paint()
self.GuiElems.Checkmark.Size = ud2o(14, 20)
end
self:Collapse(anim)
else
self:Paint()
self.GuiElems.Checkmark2.Visible = true
self.GuiElems.Middle.Visible = false
end
else
if self.Style == 0 then
if anim then
self.OutlineColorTween = service.TweenService:Create(self.GuiElems.Outline, ti(4/15, Enum.EasingStyle.Circular, Enum.EasingDirection.In), {BackgroundColor3 = self.Colors.Secondary})
self.OutlineColorTween:Play()
delay(0.15, function()
if setStateTime ~= self.LastSetStateTime then return end
self:Paint()
TweenSize(self.GuiElems.Checkmark, ud2o(0, 20), "Out", "Quad", 1/15, true)
end)
else
self.GuiElems.Outline.BackgroundColor3 = self.Colors.Secondary
self:Paint()
self.GuiElems.Checkmark.Size = ud2o(0, 20)
end
self:Expand(anim)
else
self:Paint()
self.GuiElems.Checkmark2.Visible = false
self.GuiElems.Middle.Visible = self.Toggled == nil
end
end
end
local mt = {__index = funcs}
local function new(style)
local obj = setmetatable({
Toggled = false,
Disabled = false,
OnInput = Lib.Signal.new(),
Style = style or 0,
Colors = {
Background = c3(36,36,36),
Primary = c3(49,176,230),
Secondary = c3(25,25,25),
Disabled = c3(64,64,64),
DisabledBackground = c3(52,52,52),
DisabledCheck = c3(80,80,80)
}
},mt)
initGui(obj)
return obj
end
local function fromFrame(frame)
local obj = setmetatable({
Toggled = false,
Disabled = false,
Colors = {
Background = c3(36,36,36),
Primary = c3(49,176,230),
Secondary = c3(25,25,25),
Disabled = c3(64,64,64),
DisabledBackground = c3(52,52,52)
}
},mt)
initGui(obj,frame)
return obj
end
return {new = new, fromFrame}
end)()
Lib.BrickColorPicker = (function()
local funcs = {}
local paletteCount = 0
local mouse = service.Players.LocalPlayer:GetMouse()
local hexStartX = 4
local hexSizeX = 27
local hexTriangleStart = 1
local hexTriangleSize = 8
local bottomColors = {
Color3.fromRGB(17,17,17),
Color3.fromRGB(99,95,98),
Color3.fromRGB(163,162,165),
Color3.fromRGB(205,205,205),
Color3.fromRGB(223,223,222),
Color3.fromRGB(237,234,234),
Color3.fromRGB(27,42,53),
Color3.fromRGB(91,93,105),
Color3.fromRGB(159,161,172),
Color3.fromRGB(202,203,209),
Color3.fromRGB(231,231,236),
Color3.fromRGB(248,248,248)
}
local function isMouseInHexagon(hex)
local relativeX = mouse.X - hex.AbsolutePosition.X
local relativeY = mouse.Y - hex.AbsolutePosition.Y
if relativeX >= hexStartX and relativeX < hexStartX + hexSizeX then
relativeX = relativeX - 4
local relativeWidth = (13-math.min(relativeX,26 - relativeX))/13
if relativeY >= hexTriangleStart + hexTriangleSize*relativeWidth and relativeY < hex.AbsoluteSize.Y - hexTriangleStart - hexTriangleSize*relativeWidth then
return true
end
end
return false
end
local function hexInput(self,hex,color)
hex.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 and isMouseInHexagon(hex) then
self.OnSelect:Fire(color)
self:Close()
end
end)
hex.InputChanged:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseMovement and isMouseInHexagon(hex) then
self.OnPreview:Fire(color)
end
end)
end
local function createGui(self)
local gui = create({
{1,"ScreenGui",{Name="BrickColor",}},
{2,"Frame",{Active=true,BackgroundColor3=Color3.new(0.17647059261799,0.17647059261799,0.17647059261799),BorderColor3=Color3.new(0.1294117718935,0.1294117718935,0.1294117718935),Parent={1},Position=UDim2.new(0.40000000596046,0,0.40000000596046,0),Size=UDim2.new(0,337,0,380),}},
{3,"TextButton",{BackgroundColor3=Color3.new(0.2352941185236,0.2352941185236,0.2352941185236),BorderColor3=Color3.new(0.21568627655506,0.21568627655506,0.21568627655506),BorderSizePixel=0,Font=3,Name="MoreColors",Parent={2},Position=UDim2.new(0,5,1,-30),Size=UDim2.new(1,-10,0,25),Text="More Colors",TextColor3=Color3.new(1,1,1),TextSize=14,}},
{4,"ImageLabel",{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,BorderSizePixel=0,Image="rbxassetid://1281023007",ImageColor3=Color3.new(0.33333334326744,0.33333334326744,0.49803924560547),Name="Hex",Parent={2},Size=UDim2.new(0,35,0,35),Visible=false,}},
})
local colorFrame = gui.Frame
local hex = colorFrame.Hex
for row = 1,13 do
local columns = math.min(row,14-row)+6
for column = 1,columns do
local nextColor = BrickColor.palette(paletteCount).Color
local newHex = hex:Clone()
newHex.Position = UDim2.new(0, (column-1)*25-(columns-7)*13+3*26 + 1, 0, (row-1)*23 + 4)
newHex.ImageColor3 = nextColor
newHex.Visible = true
hexInput(self,newHex,nextColor)
newHex.Parent = colorFrame
paletteCount = paletteCount + 1
end
end
for column = 1,12 do
local nextColor = bottomColors[column]
local newHex = hex:Clone()
newHex.Position = UDim2.new(0, (column-1)*25-(12-7)*13+3*26 + 3, 0, 308)
newHex.ImaDex is a debugging suite designed to help the user debug games and find any potential vulnerabilities. This is the final version of this script. You are encouraged to edit, fork, do whatever with this. I pretty much won't be updating it anymore. Though I would appreciate it if you kept the credits in the script if you enjoy this hard work. If you want more info, you can join the server: https://discord.gg/zinnia Note that very limited to no support will be provided.

Universal