· 2 months ago · Jul 11, 2025, 02:40 AM
1--// NexusLib V3.2 by NexusRobloxScripts (Updated by Gemini)
2--// Services
3local TweenService = game:GetService("TweenService")
4local player = game.Players.LocalPlayer
5local Players = game:GetService("Players")
6local parentGui = game:GetService("CoreGui")
7local Lighting = game:GetService("Lighting")
8local playerGui = player:WaitForChild("PlayerGui")
9local notificationQueue = {}
10local activeNotifications = 0
11local MAX_NOTIFICATIONS = 3
12local activeNotificationFrames = {}
13local UIS = game:GetService("UserInputService")
14local Nex = {}
15
16--// Handle GUI parent fallbacks (e.g., CoreGui not accessible)
17pcall(function()
18 if not parentGui:IsDescendantOf(game) then
19 parentGui = player:WaitForChild("PlayerGui")
20 end
21end)
22
23--// Remove any existing credit popup or library UI
24local oldPopup = parentGui:FindFirstChild("CreditPopup")
25if oldPopup then oldPopup:Destroy() end
26
27local oldLibUI = parentGui:FindFirstChild("NexusLib")
28if oldLibUI then oldLibUI:Destroy() end
29
30
31-- 🧱 Create reusable rounded corner (SINGLE DEFINITION)
32local function createRounded(instance, radius)
33 local corner = Instance.new("UICorner")
34 corner.CornerRadius = UDim.new(0, radius or 6)
35 corner.Parent = instance
36end
37
38--// NOTIFICATION MODULE:
39-- Find or fallback for main UI ScreenGui to parent notifications inside it
40local NotificationScreenGui = parentGui:FindFirstChild("NexusLib_Notifications") -- Renamed to avoid conflict with main UI
41if not NotificationScreenGui then
42 NotificationScreenGui = player:WaitForChild("PlayerGui"):FindFirstChild("NexusLib_Notifications")
43 if not NotificationScreenGui then
44 NotificationScreenGui = Instance.new("ScreenGui")
45 NotificationScreenGui.Name = "NexusLib_Notifications"
46 NotificationScreenGui.ResetOnSpawn = false
47 NotificationScreenGui.IgnoreGuiInset = true
48 NotificationScreenGui.DisplayOrder = 10 -- Ensure notifications are on top
49 NotificationScreenGui.Parent = player:WaitForChild("PlayerGui")
50 print("[Notification] Created fallback NexusLib_Notifications ScreenGui in PlayerGui")
51 end
52end
53
54-- 📌 Notification container for up to 3 notifications, bottom-centered
55local NotificationContainer = Instance.new("Frame")
56NotificationContainer.Name = "NotificationContainer"
57NotificationContainer.AnchorPoint = Vector2.new(1, 1) -- bottom-right anchor
58NotificationContainer.Position = UDim2.new(1, -15, 1, -15) -- bottom right with margin offsets
59NotificationContainer.Size = UDim2.new(0, 300, 0, 165) -- size for ~3 notifications
60NotificationContainer.BackgroundTransparency = 1
61NotificationContainer.BackgroundColor3 = Color3.fromRGB(25, 25, 25)
62NotificationContainer.ZIndex = 10
63NotificationContainer.ClipsDescendants = false
64NotificationContainer.Visible = true
65NotificationContainer.Parent = NotificationScreenGui
66
67print("[Notification] NotificationContainer created and parented to", NotificationContainer.Parent:GetFullName())
68
69-- 🖼️ Type styling helper
70local function getTypeStyle(notificationType)
71 local icon, color
72 if notificationType == "S" then
73 icon = "✅"
74 color = Color3.fromRGB(0, 200, 100)
75 elseif notificationType == "E" then
76 icon = "⚠️"
77 color = Color3.fromRGB(255, 180, 0)
78 else
79 icon = "📢"
80 color = Color3.fromRGB(0, 170, 255)
81 end
82 return icon, color
83end
84
85-- 🔁 Process the notification queue
86
87local function processQueue()
88 if activeNotifications >= MAX_NOTIFICATIONS then return end
89 if #notificationQueue == 0 then return end
90
91 local data = table.remove(notificationQueue, 1)
92 activeNotifications += 1
93
94 local notif = Instance.new("Frame")
95 notif.Size = UDim2.new(1, 0, 0, 50)
96 notif.BackgroundColor3 = Color3.fromRGB(30, 30, 30)
97 notif.BorderSizePixel = 0
98 notif.BackgroundTransparency = 0
99 notif.ClipsDescendants = true
100 notif.ZIndex = 11
101 notif.Visible = true
102 notif.Parent = NotificationContainer
103 createRounded(notif, 6)
104
105 -- Add new notification at the BOTTOM of active list (end)
106 table.insert(activeNotificationFrames, notif)
107
108 -- Recalculate positions from top (oldest) to bottom (newest)
109 for i, frame in ipairs(activeNotificationFrames) do
110 local targetY = -165 + (i - 1) * 55 -- Start at top edge, move down 55 px each
111 TweenService:Create(frame, TweenInfo.new(0.25, Enum.EasingStyle.Quad), {
112 Position = UDim2.new(0, 0, 1, targetY)
113 }):Play()
114 end
115
116 -- Start below container bottom, slide up into place at bottom (newest slot)
117 notif.Position = UDim2.new(0, 0, 1, 60)
118
119 local icon, strokeColor = getTypeStyle(data.type)
120
121 local stroke = Instance.new("UIStroke")
122 stroke.Color = strokeColor
123 stroke.Thickness = 1
124 stroke.Transparency = 0.3
125 stroke.Parent = notif
126
127 local label = Instance.new("TextLabel")
128 label.Text = icon .. " " .. data.text
129 label.Font = Enum.Font.Gotham
130 label.TextSize = 14
131 label.TextColor3 = Color3.fromRGB(255, 255, 255)
132 label.BackgroundTransparency = 1
133 label.TextWrapped = true
134 label.TextXAlignment = Enum.TextXAlignment.Left
135 label.Size = UDim2.new(1, -16, 1, -16)
136 label.Position = UDim2.new(0, 8, 0, 4)
137 label.ZIndex = 12
138 label.Parent = notif
139
140 local progress = Instance.new("Frame")
141 progress.Size = UDim2.new(1, 0, 0, 3)
142 progress.Position = UDim2.new(0, 0, 1, -3)
143 progress.BackgroundColor3 = strokeColor
144 progress.BorderSizePixel = 0
145 progress.ZIndex = 13
146 progress.Parent = notif
147 createRounded(progress, 3)
148
149 local progressTween = TweenService:Create(progress, TweenInfo.new(data.duration, Enum.EasingStyle.Linear), {
150 Size = UDim2.new(0, 0, 0, 3)
151 })
152 progressTween:Play()
153
154 task.delay(data.duration, function()
155 local fade = TweenService:Create(notif, TweenInfo.new(0.4), {BackgroundTransparency = 1})
156 local labelFade = TweenService:Create(label, TweenInfo.new(0.4), {TextTransparency = 1})
157 local progressFade = TweenService:Create(progress, TweenInfo.new(0.3), {BackgroundTransparency = 1})
158 progressTween:Cancel()
159
160 fade:Play()
161 labelFade:Play()
162 progressFade:Play()
163
164 task.wait(0.4)
165 notif:Destroy()
166 activeNotifications -= 1
167
168 -- Remove from list
169 for i, frame in ipairs(activeNotificationFrames) do
170 if frame == notif then
171 table.remove(activeNotificationFrames, i)
172 break
173 end
174 end
175
176 -- Re-stack remaining from top (oldest) to bottom (newest)
177 for i, frame in ipairs(activeNotificationFrames) do
178 local targetY = -165 + (i - 1) * 55
179 TweenService:Create(frame, TweenInfo.new(0.25, Enum.EasingStyle.Quad), {
180 Position = UDim2.new(0, 0, 1, targetY)
181 }):Play()
182 end
183
184 processQueue()
185 end)
186end
187
188
189-- 📣 Main Notify function for Nex
190function Nex:Notify(text, duration, notificationType)
191 print("[Notification] Adding notification to queue:", text)
192 table.insert(notificationQueue, {
193 text = tostring(text),
194 duration = duration or 5,
195 type = notificationType or "D"
196 })
197 processQueue()
198end
199
200
201--// Credits
202
203--// Blur background
204local blur = Instance.new("BlurEffect")
205blur.Size = 0
206blur.Name = "NexCreditBlur"
207blur.Parent = Lighting
208TweenService:Create(blur, TweenInfo.new(0.5), {Size = 12}):Play()
209
210--// GUI container
211local gui = Instance.new("ScreenGui")
212gui.Name = "CreditPopup"
213gui.IgnoreGuiInset = true
214gui.ResetOnSpawn = false
215gui.Parent = parentGui
216
217--// Main popup frame
218local popup = Instance.new("Frame")
219popup.Size = UDim2.new(0, 280, 0, 80)
220popup.Position = UDim2.new(0.5, 0, 0.5, 0)
221popup.BackgroundColor3 = Color3.fromRGB(25, 25, 25)
222popup.BackgroundTransparency = 1
223popup.BorderSizePixel = 0
224popup.AnchorPoint = Vector2.new(0.5, 0.5)
225popup.Parent = gui
226
227-- Rounded corners and stroke
228Instance.new("UICorner", popup).CornerRadius = UDim.new(0, 8)
229local stroke = Instance.new("UIStroke", popup)
230stroke.Color = Color3.fromRGB(0, 170, 255)
231stroke.Thickness = 2
232stroke.Transparency = 0.4
233
234--// Icon image
235local icon = Instance.new("ImageLabel")
236icon.Size = UDim2.new(0, 40, 0, 40)
237icon.Position = UDim2.new(0, 10, 0, 20)
238icon.BackgroundTransparency = 1
239icon.Image = "rbxassetid://6031075938"
240icon.ScaleType = Enum.ScaleType.Fit
241icon.ClipsDescendants = true
242icon.ImageTransparency = 1
243icon.Parent = popup
244Instance.new("UIAspectRatioConstraint", icon).AspectRatio = 1
245
246--// Text: Title
247local mainLabel = Instance.new("TextLabel")
248mainLabel.Position = UDim2.new(0, 60, 0, 12)
249mainLabel.Size = UDim2.new(1, -70, 0, 24)
250mainLabel.BackgroundTransparency = 1
251mainLabel.Text = "NexusLib UI"
252mainLabel.Font = Enum.Font.GothamBold
253mainLabel.TextSize = 16
254mainLabel.TextColor3 = Color3.fromRGB(255, 255, 255)
255mainLabel.TextXAlignment = Enum.TextXAlignment.Left
256mainLabel.Parent = popup
257
258--// Text: Link
259local socialLink = Instance.new("TextButton")
260socialLink.Position = UDim2.new(0, 60, 0, 40)
261socialLink.Size = UDim2.new(1, -70, 0, 18)
262socialLink.BackgroundTransparency = 1
263socialLink.Text = "@NexusRobloxScripts"
264socialLink.Font = Enum.Font.Gotham
265socialLink.TextSize = 13
266socialLink.TextColor3 = Color3.fromRGB(0, 170, 255)
267socialLink.TextXAlignment = Enum.TextXAlignment.Left
268socialLink.AutoButtonColor = false
269socialLink.Parent = popup
270
271-- Added functionality to copy the link and notify
272local url = "https://youtube.com/NexusRobloxScripts"
273
274socialLink.MouseButton1Click:Connect(function()
275 -- Copy to clipboard (works on executors like Delta)
276 if setclipboard then
277 setclipboard(url)
278 Nex:Notify("YouTube Link Copied!", 3, "S")
279 end
280end)
281
282
283--// Loading bar background
284local loadingBarBg = Instance.new("Frame")
285loadingBarBg.Size = UDim2.new(0, 180, 0, 12) -- made narrower
286loadingBarBg.Position = UDim2.new(0, 60, 0, 65) -- same position
287loadingBarBg.BackgroundColor3 = Color3.fromRGB(40, 40, 40)
288loadingBarBg.BorderSizePixel = 0
289loadingBarBg.AnchorPoint = Vector2.new(0, 0)
290loadingBarBg.Parent = popup
291Instance.new("UICorner", loadingBarBg).CornerRadius = UDim.new(0, 6)
292
293--// Loading bar fill
294local loadingBarFill = Instance.new("Frame")
295loadingBarFill.Size = UDim2.new(0, 0, 1, 0) -- starts empty
296loadingBarFill.Position = UDim2.new(0, 0, 0, 0)
297loadingBarFill.BackgroundColor3 = Color3.fromRGB(0, 170, 255)
298loadingBarFill.BorderSizePixel = 0
299loadingBarFill.Parent = loadingBarBg
300Instance.new("UICorner", loadingBarFill).CornerRadius = UDim.new(0, 6)
301
302--// Percentage label
303local loadingPercent = Instance.new("TextLabel")
304loadingPercent.Size = UDim2.new(0, 40, 0, 12) -- slightly smaller width
305loadingPercent.Position = UDim2.new(1, -45, 0, 0) -- moved left inside the bar's right edge
306loadingPercent.BackgroundTransparency = 1
307loadingPercent.Text = "0%"
308loadingPercent.Font = Enum.Font.GothamBold
309loadingPercent.TextSize = 12
310loadingPercent.TextColor3 = Color3.fromRGB(255, 255, 255)
311loadingPercent.TextXAlignment = Enum.TextXAlignment.Right -- right-align to fit nicely
312loadingPercent.Parent = loadingBarBg
313
314
315--// Fade in popup
316TweenService:Create(popup, TweenInfo.new(0.5), {BackgroundTransparency = 0}):Play()
317TweenService:Create(icon, TweenInfo.new(0.5), {ImageTransparency = 0}):Play()
318
319--// Update loading bar over time instead of static wait
320local displayTime = 8
321local updateInterval = 0.05
322
323for elapsed = 0, displayTime, updateInterval do
324 local progress = elapsed / displayTime
325 local percent = math.floor(progress * 100)
326 loadingBarFill.Size = UDim2.new(progress, 0, 1, 0)
327 loadingPercent.Text = percent .. "%"
328 task.wait(updateInterval)
329end
330
331-- Ensure fully filled at end
332loadingBarFill.Size = UDim2.new(1, 0, 1, 0)
333loadingPercent.Text = "100%"
334
335--// Fade out popup
336TweenService:Create(popup, TweenInfo.new(0.5), {BackgroundTransparency = 1}):Play()
337TweenService:Create(icon, TweenInfo.new(0.5), {ImageTransparency = 1}):Play()
338TweenService:Create(blur, TweenInfo.new(0.5), {Size = 0}):Play()
339
340--// Cleanup after fade
341task.delay(0.5, function()
342 blur:Destroy()
343 gui:Destroy()
344end)
345
346-- START OF THE UI MAIN WINDOW, SEE COMMENTS FOR INFO!!!!
347local isCollapsed = true
348local dragging, dragStart, startPos
349
350-- UI Container
351local MainScreenGui = Instance.new("ScreenGui") -- Renamed to avoid conflict with notifications
352MainScreenGui.Name = "NexusLib"
353MainScreenGui.ResetOnSpawn = false
354MainScreenGui.IgnoreGuiInset = true
355MainScreenGui.Parent = parentGui
356
357-- Main Window
358local MainFrame = Instance.new("Frame")
359MainFrame.Name = "MainFrame"
360MainFrame.Position = UDim2.new(0.3, 0, 0.3, 0)
361MainFrame.Size = UDim2.new(0, 250, 0, 25) -- smaller width and height
362MainFrame.BackgroundColor3 = Color3.fromRGB(25, 25, 25)
363MainFrame.BorderSizePixel = 0
364MainFrame.Active = true
365MainFrame.Parent = MainScreenGui
366createRounded(MainFrame, 6) -- slightly smaller corner radius
367
368local UIStroke = Instance.new("UIStroke", MainFrame)
369UIStroke.Thickness = 1.5
370UIStroke.Color = Color3.fromRGB(0, 170, 255)
371UIStroke.Transparency = 0.3
372
373-- Title Bar
374local TitleBar = Instance.new("TextButton")
375TitleBar.Text = " UI Menu "
376TitleBar.Font = Enum.Font.GothamBold
377TitleBar.TextSize = 14 -- smaller font size
378TitleBar.Size = UDim2.new(1, 0, 0, 25) -- shorter height
379TitleBar.BackgroundColor3 = Color3.fromRGB(30, 30, 30)
380TitleBar.TextColor3 = Color3.fromRGB(255, 255, 255)
381TitleBar.BorderSizePixel = 0
382TitleBar.AutoButtonColor = false
383TitleBar.Parent = MainFrame
384createRounded(TitleBar, 6)
385
386-- Collapse Button
387local CollapseButton = Instance.new("TextButton")
388CollapseButton.Size = UDim2.new(0, 25, 1, 0)
389CollapseButton.Position = UDim2.new(1, -25, 0, 0)
390CollapseButton.Text = "+"
391CollapseButton.TextColor3 = Color3.fromRGB(255, 255, 255)
392CollapseButton.Font = Enum.Font.GothamBold
393CollapseButton.TextSize = 14
394CollapseButton.BackgroundTransparency = 1
395CollapseButton.Parent = TitleBar
396
397-- Add icon to TitleBar
398local titleIcon = Instance.new("ImageLabel")
399titleIcon.Size = UDim2.new(0, 20, 0, 20) -- small square icon
400titleIcon.Position = UDim2.new(0, 5, 0.5, -10) -- left side with vertical center alignment
401titleIcon.BackgroundTransparency = 1
402titleIcon.Image = "rbxassetid://6031075938" -- same asset ID as your popup icon
403titleIcon.ScaleType = Enum.ScaleType.Fit
404titleIcon.Parent = TitleBar
405
406-- NEW: Tab Bar Frame (replaces old Container position temporarily)
407local TabBarFrame = Instance.new("Frame")
408TabBarFrame.Name = "TabBarFrame"
409TabBarFrame.Size = UDim2.new(1, 0, 0, 25) -- Height for tab buttons
410TabBarFrame.Position = UDim2.new(0, 0, 0, 25) -- Below TitleBar
411TabBarFrame.BackgroundTransparency = 1
412TabBarFrame.Parent = MainFrame
413
414local TabListLayout = Instance.new("UIListLayout")
415TabListLayout.FillDirection = Enum.FillDirection.Horizontal
416TabListLayout.Padding = UDim.new(0, 2)
417TabListLayout.HorizontalAlignment = Enum.HorizontalAlignment.Center
418TabListLayout.Parent = TabBarFrame
419
420-- NEW: Tab Content Container (this will hold the actual tab scrolling frames)
421local TabContentContainer = Instance.new("Frame") -- Changed to Frame to contain scrolling frames
422TabContentContainer.Name = "TabContentContainer"
423TabContentContainer.Size = UDim2.new(1, -8, 1, -58) -- Adjust height (TitleBar + TabBar + padding)
424TabContentContainer.Position = UDim2.new(0, 4, 0, 58) -- Below TabBar
425TabContentContainer.BackgroundTransparency = 1
426TabContentContainer.ClipsDescendants = true -- Important for hiding inactive tabs
427TabContentContainer.Parent = MainFrame
428
429local activeTabContent = nil -- Will reference the currently visible ScrollingFrame for the active tab
430local tabButtons = {}
431local tabContainers = {}
432
433-- NEW: Tooltip Label
434local TooltipLabel = Instance.new("TextLabel")
435TooltipLabel.Name = "NexusLibTooltip"
436TooltipLabel.Size = UDim2.new(0, 150, 0, 20) -- Default size, will adjust
437TooltipLabel.BackgroundTransparency = 0
438TooltipLabel.BackgroundColor3 = Color3.fromRGB(40, 40, 40)
439TooltipLabel.TextColor3 = Color3.fromRGB(255, 255, 255)
440TooltipLabel.Font = Enum.Font.Gotham
441TooltipLabel.TextSize = 12
442TooltipLabel.TextXAlignment = Enum.TextXAlignment.Left
443TooltipLabel.TextWrapped = true
444TooltipLabel.BorderSizePixel = 0
445TooltipLabel.ZIndex = 100 -- Ensure it's always on top
446TooltipLabel.Visible = false
447TooltipLabel.Parent = MainScreenGui -- Parent to your main ScreenGui
448createRounded(TooltipLabel, 4)
449
450local TooltipStroke = Instance.new("UIStroke")
451TooltipStroke.Color = Color3.fromRGB(0, 170, 255)
452TooltipStroke.Thickness = 1
453TooltipStroke.Transparency = 0.5
454TooltipStroke.Parent = TooltipLabel
455
456-- Tooltip Attach Function
457local function attachTooltip(uiElement, tooltipText)
458 if not uiElement or not tooltipText or tooltipText == "" then return end
459
460 local isMouseOver = false
461 local tooltipHideDelay = 0.1 -- Small delay before hiding
462
463 uiElement.MouseEnter:Connect(function()
464 isMouseOver = true
465 TooltipLabel.Text = tooltipText
466 -- Calculate required size based on text, max width 200
467 local textSize = TooltipLabel:GetTextSize(tooltipText, TooltipLabel.TextSize, TooltipLabel.Font, Vector2.new(200, 999))
468 TooltipLabel.Size = UDim2.new(0, math.min(textSize.X + 10, 200), 0, textSize.Y + 4) -- Add padding, cap max width
469 TooltipLabel.Visible = true
470 end)
471
472 uiElement.MouseLeave:Connect(function()
473 isMouseOver = false
474 task.delay(tooltipHideDelay, function()
475 if not isMouseOver then
476 TooltipLabel.Visible = false
477 end
478 end)
479 end)
480
481 -- Update tooltip position with mouse
482 UIS.InputChanged:Connect(function(input, gameProcessed)
483 if input.UserInputType == Enum.UserInputType.MouseMovement and isMouseOver and TooltipLabel.Visible then
484 -- Adjust position to be slightly offset from mouse, keeping it on screen
485 local x = math.clamp(input.Position.X + 15, 0, MainScreenGui.AbsoluteSize.X - TooltipLabel.AbsoluteSize.X)
486 local y = math.clamp(input.Position.Y + 15, 0, MainScreenGui.AbsoluteSize.Y - TooltipLabel.AbsoluteSize.Y)
487 TooltipLabel.Position = UDim2.new(0, x, 0, y)
488 end
489 end)
490end
491
492-- Keybind Manager
493local Keybinds = {} -- { {inputObject, callback, toggleComponent}, ... }
494local listeningForKey = nil -- Stores the TextButton currently listening for a key
495
496-- Function to convert InputObject.KeyCode to string
497local function KeyCodeToString(keyCode)
498 if keyCode and keyCode.Name then
499 -- Remove "Enum.KeyCode." prefix if it exists implicitly
500 return keyCode.Name:gsub("Enum%.KeyCode%.", "")
501 end
502 return "None"
503end
504
505-- Listen for all user input for keybinds
506UIS.InputBegan:Connect(function(input, gameProcessed)
507 if gameProcessed then return end -- Don't process input consumed by Roblox UI
508
509 if listeningForKey then
510 -- A keybind button is active, set its key
511 if input.UserInputType == Enum.UserInputType.Keyboard then
512 listeningForKey.key = input.KeyCode
513 listeningForKey.Text = KeyCodeToString(input.KeyCode)
514 TweenService:Create(listeningForKey, TweenInfo.new(0.2), {BackgroundColor3 = Color3.fromRGB(40, 40, 40)}):Play()
515 listeningForKey = nil -- Stop listening
516 end
517 return -- Consume input if we were listening for a key
518 end
519
520 -- Check if any registered keybinds were pressed
521 if input.UserInputType == Enum.UserInputType.Keyboard then
522 for i, keybindData in ipairs(Keybinds) do
523 local key = keybindData.inputObject
524 local toggleComponent = keybindData.toggleComponent -- Reference to the visual toggle
525
526 if input.KeyCode == key and key ~= Enum.KeyCode.None then
527 if toggleComponent and toggleComponent.Set then
528 local newState = not toggleComponent:Get() -- Toggle the state
529 toggleComponent:Set(newState, true) -- Update visual state via component's Set method, trigger callback
530 end
531 -- We might want to break here if only one keybind should trigger per press
532 -- or if multiple keybinds can share a key. For now, it will trigger all.
533 end
534 end
535 end
536end)
537
538
539-- Collapse toggle logic
540CollapseButton.MouseButton1Click:Connect(function()
541 isCollapsed = not isCollapsed
542 TabContentContainer.Visible = not isCollapsed
543 TabBarFrame.Visible = not isCollapsed
544 -- Adjust height based on whether tabs are visible.
545 -- If collapsed, height is just the title bar (25px).
546 -- If expanded, height is TitleBar (25px) + TabBar (25px) + ContentContainer height (320px) + padding.
547 MainFrame.Size = isCollapsed and UDim2.new(0, 250, 0, 25) or UDim2.new(0, 250, 0, 25 + 25 + 320)
548 CollapseButton.Text = isCollapsed and "+" or "–"
549end)
550
551-- Draggable logic (exclude collapse button area)
552TitleBar.InputBegan:Connect(function(input)
553 if input.UserInputType == Enum.UserInputType.MouseButton1 then
554 if UIS:GetFocusedTextBox() == nil then
555 local mousePos = input.Position
556 local cbPos = CollapseButton.AbsolutePosition
557 local cbSize = CollapseButton.AbsoluteSize
558 if not (mousePos.X >= cbPos.X and mousePos.X <= cbPos.X + cbSize.X) then
559 dragging = true
560 dragStart = input.Position
561 startPos = MainFrame.Position
562 input.Changed:Connect(function()
563 if input.UserInputState == Enum.UserInputState.End then
564 dragging = false
565 end
566 end)
567 end
568 end
569 end
570end)
571
572UIS.InputChanged:Connect(function(input)
573 if dragging and input.UserInputType == Enum.UserInputType.MouseMovement then
574 local delta = input.Position - dragStart
575 MainFrame.Position = UDim2.new(startPos.X.Scale, startPos.X.Offset + delta.X, startPos.Y.Scale, startPos.Y.Offset + delta.Y)
576 end
577end)
578
579-- API Functions --
580
581-- Global API functions
582function Nex:SetTitle(text)
583 TitleBar.Text = " " .. tostring(text)
584end
585
586-- Currently active container for adding UI elements (starts as nil, set by AddTab)
587local currentActiveContainer = nil
588
589function Nex:AddTab(tabName)
590 local tabButton = Instance.new("TextButton")
591 tabButton.Text = tabName
592 tabButton.Font = Enum.Font.GothamBold
593 tabButton.TextSize = 12
594 tabButton.Size = UDim2.new(0.3, 0, 1, 0) -- Adjust size as needed
595 tabButton.BackgroundColor3 = Color3.fromRGB(35, 35, 35)
596 tabButton.TextColor3 = Color3.fromRGB(150, 150, 150)
597 tabButton.BorderSizePixel = 0
598 tabButton.AutoButtonColor = false
599 tabButton.Parent = TabBarFrame
600 createRounded(tabButton, 5)
601
602 local tabContent = Instance.new("ScrollingFrame")
603 tabContent.Name = "Tab_" .. tabName:gsub(" ", "_")
604 tabContent.Size = UDim2.new(1, 0, 1, 0) -- Fills TabContentContainer
605 tabContent.CanvasSize = UDim2.new(0, 0, 0, 0)
606 tabContent.ScrollBarThickness = 5
607 tabContent.AutomaticCanvasSize = Enum.AutomaticSize.Y
608 tabContent.BackgroundTransparency = 1
609 tabContent.Visible = false -- Hidden by default
610 tabContent.Parent = TabContentContainer
611
612 local tabListLayout = Instance.new("UIListLayout")
613 tabListLayout.Padding = UDim.new(0, 5)
614 tabListLayout.SortOrder = Enum.SortOrder.LayoutOrder
615 tabListLayout.Parent = tabContent
616
617 table.insert(tabButtons, tabButton)
618 table.insert(tabContainers, tabContent)
619
620 tabButton.MouseButton1Click:Connect(function()
621 -- Deactivate all other tabs
622 for i, btn in ipairs(tabButtons) do
623 btn.BackgroundColor3 = Color3.fromRGB(35, 35, 35)
624 btn.TextColor3 = Color3.fromRGB(150, 150, 150)
625 tabContainers[i].Visible = false
626 end
627 -- Activate this tab
628 tabButton.BackgroundColor3 = Color3.fromRGB(0, 170, 255) -- Active color
629 tabButton.TextColor3 = Color3.fromRGB(255, 255, 255)
630 tabContent.Visible = true
631 currentActiveContainer = tabContent -- Set the active container for new elements
632 end)
633
634 -- Make the first added tab active by default
635 if #tabButtons == 1 then
636 tabButton.MouseButton1Click:Fire()
637 end
638
639 -- Return a table of functions that will operate on this specific tab's content
640 local tabAPI = {}
641 local originalNexFunctions = {
642 AddSection = Nex.AddSection,
643 AddButton = Nex.AddButton,
644 AddToggle = Nex.AddToggle,
645 AddSlider = Nex.AddSlider,
646 AddDropdown = Nex.AddDropdown,
647 AddTextBox = Nex.AddTextBox, -- New
648 AddKeybind = Nex.AddKeybind, -- New
649 }
650
651 for funcName, originalFunc in pairs(originalNexFunctions) do
652 tabAPI[funcName] = function(...)
653 local prevContainer = currentActiveContainer
654 currentActiveContainer = tabContent
655 local result = originalFunc(Nex, ...) -- Call the original Nex function
656 currentActiveContainer = prevContainer
657 return result
658 end
659 end
660
661 return tabAPI
662end
663
664
665-- Helper to get the correct parent container
666local function getContainer()
667 return currentActiveContainer or TabContentContainer -- Fallback if no tab is active (shouldn't happen with default activation)
668end
669
670function Nex:AddSection(text)
671 local lbl = Instance.new("TextLabel")
672 lbl.Text = tostring(text)
673 lbl.Font = Enum.Font.GothamBold
674 lbl.TextSize = 12
675 lbl.TextColor3 = Color3.fromRGB(180, 180, 180)
676 lbl.BackgroundTransparency = 0.8
677 lbl.Size = UDim2.new(1, -8, 0, 20)
678 lbl.TextXAlignment = Enum.TextXAlignment.Left
679 lbl.Parent = getContainer()
680 return {
681 SetText = function(newText) lbl.Text = tostring(newText) end,
682 SetTooltip = function(tooltipText) attachTooltip(lbl, tooltipText) end
683 }
684end
685
686function Nex:AddButton(text, callback)
687 local btn = Instance.new("TextButton")
688 btn.Text = tostring(text)
689 btn.Font = Enum.Font.Gotham
690 btn.TextSize = 13
691 btn.Size = UDim2.new(1, -8, 0, 24)
692 btn.BackgroundColor3 = Color3.fromRGB(40, 40, 40)
693 btn.TextColor3 = Color3.fromRGB(255, 255, 255)
694 btn.BorderSizePixel = 0
695 btn.AutoButtonColor = true
696 btn.MouseButton1Click:Connect(callback)
697 btn.Parent = getContainer()
698 createRounded(btn, 5)
699
700 return {
701 SetText = function(newText)
702 btn.Text = tostring(newText)
703 end,
704 SetTooltip = function(tooltipText)
705 attachTooltip(btn, tooltipText)
706 end
707 }
708end
709
710function Nex:AddToggle(text, config, callback)
711 if typeof(config) == "function" then
712 callback = config
713 config = {}
714 end
715
716 local loop = config.loop
717 local toggle = Instance.new("TextButton")
718 toggle.Font = Enum.Font.Gotham
719 toggle.TextSize = 13
720 toggle.Size = UDim2.new(1, -8, 0, 24)
721 toggle.BackgroundColor3 = Color3.fromRGB(40, 40, 40)
722 toggle.BorderSizePixel = 0
723 toggle.AutoButtonColor = true
724 toggle.Parent = getContainer()
725 createRounded(toggle, 5)
726
727 local state = false
728 local loopingThread = nil
729
730 local function updateText()
731 local status = state and "[ON] " or "[OFF] "
732 local color = state and Color3.fromRGB(0, 255, 0) or Color3.fromRGB(255, 80, 80)
733 toggle.Text = status .. text
734 toggle.TextColor3 = color
735 end
736
737 local function updateState(newState, triggerCallback)
738 state = newState
739 updateText()
740 if loop then
741 if state then
742 local delayTime = tonumber(config.loopdelay) or 0.2
743 loopingThread = task.spawn(function() -- Using task.spawn for modern Roblox
744 while state do
745 pcall(callback)
746 task.wait(delayTime)
747 end
748 end)
749 else
750 if loopingThread then
751 task.cancel(loopingThread)
752 loopingThread = nil
753 end
754 end
755 elseif triggerCallback then
756 pcall(callback, state)
757 end
758 end
759
760 toggle.MouseButton1Click:Connect(function()
761 updateState(not state, true)
762 end)
763
764 updateText()
765
766 return {
767 Set = function(val)
768 if typeof(val) == "boolean" then
769 updateState(val, true)
770 end
771 end,
772 Get = function()
773 return state
774 end,
775 SetText = function(newText)
776 text = tostring(newText)
777 updateText()
778 end,
779 SetTooltip = function(tooltipText)
780 attachTooltip(toggle, tooltipText)
781 end
782 }
783end
784
785
786function Nex:AddSlider(text, settings, callback)
787 local frame = Instance.new("Frame")
788 frame.Size = UDim2.new(1, -8, 0, 35)
789 frame.BackgroundTransparency = 1
790 frame.Parent = getContainer()
791
792 local lbl = Instance.new("TextLabel")
793 lbl.Text = text .. ": " .. tostring(settings.default)
794 lbl.Font = Enum.Font.Gotham
795 lbl.TextSize = 12
796 lbl.TextColor3 = Color3.fromRGB(200, 200, 200)
797 lbl.BackgroundTransparency = 1
798 lbl.Size = UDim2.new(1, 0, 0, 16)
799 lbl.TextXAlignment = Enum.TextXAlignment.Left
800 lbl.Parent = frame
801
802 local sliderBG = Instance.new("Frame")
803 sliderBG.Size = UDim2.new(1, 0, 0, 8)
804 sliderBG.Position = UDim2.new(0, 0, 0, 22)
805 sliderBG.BackgroundColor3 = Color3.fromRGB(50, 50, 50)
806 sliderBG.BorderSizePixel = 0
807 sliderBG.Parent = frame
808 createRounded(sliderBG, 5)
809
810 local sliderFG = Instance.new("Frame")
811 sliderFG.Size = UDim2.new((settings.default - settings.min)/(settings.max-settings.min), 0, 1, 0)
812 sliderFG.BackgroundColor3 = Color3.fromRGB(0, 170, 255)
813 sliderFG.BorderSizePixel = 0
814 sliderFG.Parent = sliderBG
815 createRounded(sliderFG, 5) -- Apply rounded corners to fill
816
817 local draggingSlider = false
818 local labelText = text
819 local currentValue = settings.default
820
821 local function setSliderValue(val)
822 val = math.clamp(val, settings.min, settings.max)
823 local pos = (val - settings.min) / (settings.max - settings.min)
824 sliderFG.Size = UDim2.new(pos, 0, 1, 0)
825 lbl.Text = labelText .. ": " .. tostring(val)
826 currentValue = val
827 if callback then
828 callback(val)
829 end
830 end
831
832 local function updateSlider(input)
833 local pos = math.clamp((input.Position.X - sliderBG.AbsolutePosition.X) / sliderBG.AbsoluteSize.X, 0, 1)
834 local value = math.floor(settings.min + (settings.max - settings.min) * pos)
835 setSliderValue(value) -- Use setSliderValue to ensure clamping and callback
836 end
837
838 sliderBG.InputBegan:Connect(function(input)
839 if input.UserInputType == Enum.UserInputType.MouseButton1 then
840 draggingSlider = true
841 updateSlider(input)
842 end
843 end)
844
845 UIS.InputEnded:Connect(function(input)
846 if input.UserInputType == Enum.UserInputType.MouseButton1 then
847 draggingSlider = false
848 end
849 end)
850
851 UIS.InputChanged:Connect(function(input)
852 if draggingSlider and input.UserInputType == Enum.UserInputType.MouseMovement then
853 updateSlider(input)
854 end
855 end)
856
857 -- initialize
858 setSliderValue(settings.default)
859
860 return {
861 Set = setSliderValue,
862 Get = function()
863 return currentValue
864 end,
865 SetText = function(newText)
866 labelText = tostring(newText)
867 lbl.Text = labelText .. ": " .. tostring(currentValue)
868 end,
869 SetTooltip = function(tooltipText)
870 attachTooltip(frame, tooltipText)
871 end
872 }
873end
874
875function Nex:AddDropdown(labelText, items, buttonText, callback)
876 local maxTextSize = 13
877
878 local function applyAutoScale(textObject)
879 textObject.TextScaled = true
880 local constraint = Instance.new("UITextSizeConstraint")
881 constraint.MaxTextSize = maxTextSize
882 constraint.MinTextSize = 8
883 constraint.Parent = textObject
884 end
885
886 local UserInputService = game:GetService("UserInputService")
887 local CoreGui = game:GetService("CoreGui") -- This CoreGui reference might not be the actual parent for dropdown list
888
889 local frame = Instance.new("Frame")
890 frame.Size = UDim2.new(1, -8, 0, 30)
891 frame.BackgroundTransparency = 1
892 frame.Parent = getContainer()
893
894 local label = Instance.new("TextLabel")
895 label.Text = labelText
896 label.Font = Enum.Font.Gotham
897 label.TextColor3 = Color3.fromRGB(200, 200, 200)
898 label.BackgroundTransparency = 1
899 label.Size = UDim2.new(0.35, 10, 1, 0)
900 label.TextXAlignment = Enum.TextXAlignment.Left
901 label.ClipsDescendants = true
902 label.TextTruncate = Enum.TextTruncate.AtEnd
903 applyAutoScale(label)
904 label.Parent = frame
905
906 local dropdownButton = Instance.new("TextButton")
907 dropdownButton.Font = Enum.Font.Gotham
908 dropdownButton.BackgroundColor3 = Color3.fromRGB(40, 40, 40)
909 dropdownButton.BorderSizePixel = 0
910 dropdownButton.Size = UDim2.new(0.4, 0, 1, 0)
911 dropdownButton.Position = UDim2.new(0.35, 5, 0, 0)
912 dropdownButton.TextColor3 = Color3.fromRGB(255, 255, 255)
913 dropdownButton.Text = items[1] or "Select"
914 dropdownButton.ClipsDescendants = true
915 dropdownButton.TextTruncate = Enum.TextTruncate.AtEnd
916 applyAutoScale(dropdownButton)
917 dropdownButton.Parent = frame
918 createRounded(dropdownButton, 5)
919
920 local actionButton = Instance.new("TextButton")
921 actionButton.Font = Enum.Font.Gotham
922 actionButton.BackgroundColor3 = Color3.fromRGB(0, 170, 255)
923 actionButton.BorderSizePixel = 0
924 actionButton.Size = UDim2.new(0.22, 0, 1, 0)
925 actionButton.Position = UDim2.new(0.75, 10, 0, 0)
926 actionButton.TextColor3 = Color3.fromRGB(255, 255, 255)
927 actionButton.Text = buttonText or "Execute"
928 actionButton.ClipsDescendants = true
929 actionButton.TextTruncate = Enum.TextTruncate.AtEnd
930 applyAutoScale(actionButton)
931 actionButton.Parent = frame
932 createRounded(actionButton, 5)
933
934 local dropdownGui = Instance.new("ScreenGui")
935 dropdownGui.Name = "NexDropdownPopup"
936 dropdownGui.ResetOnSpawn = false
937 dropdownGui.Parent = MainScreenGui -- Parent dropdown to main ScreenGui for overlay
938
939 local dropdownList = Instance.new("ScrollingFrame")
940 dropdownList.BackgroundColor3 = Color3.fromRGB(40, 40, 40)
941 dropdownList.BorderSizePixel = 0
942 dropdownList.Size = UDim2.new(0, 150, 0, 0)
943 dropdownList.Visible = false
944 dropdownList.Parent = dropdownGui
945 dropdownList.ScrollBarThickness = 6
946 dropdownList.VerticalScrollBarInset = Enum.ScrollBarInset.Always
947 createRounded(dropdownList, 5)
948
949 local uiListLayout = Instance.new("UIListLayout")
950 uiListLayout.Padding = UDim.new(0, 2)
951 uiListLayout.Parent = dropdownList
952
953 local inputConnection
954 local selectedIndex = 1
955 local currentSelection = items[1]
956
957 local function closeDropdown()
958 dropdownList.Visible = false
959 if inputConnection then
960 inputConnection:Disconnect()
961 inputConnection = nil
962 end
963 end
964
965 local function refreshItems()
966 for _, child in ipairs(dropdownList:GetChildren()) do
967 if child:IsA("TextButton") then child:Destroy() end
968 end
969
970 local itemHeight = 26
971 local totalHeight = math.min(#items, 7) * itemHeight
972 dropdownList.Size = UDim2.new(0, dropdownButton.AbsoluteSize.X, 0, totalHeight)
973 dropdownList.CanvasSize = UDim2.new(0, 0, 0, #items * itemHeight)
974
975 for i, itemText in ipairs(items) do
976 local itemBtn = Instance.new("TextButton")
977 itemBtn.Size = UDim2.new(1, 0, 0, 24)
978 itemBtn.BackgroundColor3 = Color3.fromRGB(30, 30, 30)
979 itemBtn.BorderSizePixel = 0
980 itemBtn.Text = itemText
981 itemBtn.TextColor3 = Color3.fromRGB(255, 255, 255)
982 itemBtn.Font = Enum.Font.Gotham
983 itemBtn.ClipsDescendants = true
984 itemBtn.TextTruncate = Enum.TextTruncate.AtEnd
985 applyAutoScale(itemBtn)
986 itemBtn.Parent = dropdownList
987 createRounded(itemBtn, 4)
988
989 itemBtn.MouseButton1Click:Connect(function()
990 selectedIndex = i
991 currentSelection = itemText
992 dropdownButton.Text = itemText
993 closeDropdown()
994 end)
995 end
996 end
997
998 refreshItems()
999
1000 dropdownButton.MouseButton1Click:Connect(function()
1001 if dropdownList.Visible then
1002 closeDropdown()
1003 return
1004 end
1005
1006 local btnPos = dropdownButton.AbsolutePosition
1007 local btnSize = dropdownButton.AbsoluteSize
1008
1009 dropdownList.Position = UDim2.new(0, btnPos.X, 0, btnPos.Y + btnSize.Y)
1010 dropdownList.Visible = true
1011
1012 inputConnection = UserInputService.InputBegan:Connect(function(input)
1013 if not dropdownList.Visible then return end
1014
1015 if input.UserInputType == Enum.UserInputType.MouseButton1 then
1016 local mousePos = input.Position
1017
1018 local dropAbsPos = dropdownList.AbsolutePosition
1019 local dropAbsSize = dropdownList.AbsoluteSize
1020 local inDropdown = mousePos.X >= dropAbsPos.X and mousePos.X <= dropAbsPos.X + dropAbsSize.X
1021 and mousePos.Y >= dropAbsPos.Y and mousePos.Y <= dropAbsPos.Y + dropAbsSize.Y
1022
1023 local btnAbsPos = dropdownButton.AbsolutePosition
1024 local btnAbsSize = dropdownButton.AbsoluteSize
1025 local inButton = mousePos.X >= btnAbsPos.X and mousePos.X <= btnAbsPos.X + btnAbsSize.X
1026 and mousePos.Y >= btnAbsPos.Y and mousePos.Y <= btnAbsPos.Y + btnAbsSize.Y
1027
1028 if not inDropdown and not inButton then
1029 closeDropdown()
1030 end
1031 end
1032 end)
1033 end)
1034
1035 actionButton.MouseButton1Click:Connect(function()
1036 if callback and selectedIndex and items[selectedIndex] then
1037 callback(items[selectedIndex], selectedIndex)
1038 end
1039 end)
1040
1041 frame.Destroying:Connect(function()
1042 if inputConnection then
1043 inputConnection:Disconnect()
1044 inputConnection = nil
1045 end
1046 dropdownGui:Destroy()
1047 end)
1048
1049 local dropdownObj = {}
1050
1051 function dropdownObj:SetItems(newItems)
1052 items = newItems
1053 selectedIndex = (#items > 0) and 1 or nil
1054 currentSelection = items[selectedIndex]
1055 dropdownButton.Text = items[selectedIndex] or "Select"
1056 refreshItems()
1057 end
1058
1059 function dropdownObj:AddItem(item)
1060 table.insert(items, item)
1061 refreshItems()
1062 end
1063
1064 function dropdownObj:SetButtonText(newText)
1065 actionButton.Text = newText
1066 end
1067
1068 function dropdownObj:GetSelected()
1069 return currentSelection, selectedIndex
1070 end
1071
1072 function dropdownObj:SetTooltip(tooltipText)
1073 attachTooltip(frame, tooltipText)
1074 end
1075
1076 return dropdownObj
1077end
1078
1079-- NEW: AddTextBox
1080function Nex:AddTextBox(labelText, defaultValue, callback)
1081 local frame = Instance.new("Frame")
1082 frame.Size = UDim2.new(1, -8, 0, 40) -- Height for label + textbox
1083 frame.BackgroundTransparency = 1
1084 frame.Parent = getContainer()
1085
1086 local label = Instance.new("TextLabel")
1087 label.Text = labelText
1088 label.Font = Enum.Font.Gotham
1089 label.TextSize = 12
1090 label.TextColor3 = Color3.fromRGB(200, 200, 200)
1091 label.BackgroundTransparency = 1
1092 label.Size = UDim2.new(1, 0, 0, 16)
1093 label.TextXAlignment = Enum.TextXAlignment.Left
1094 label.Parent = frame
1095
1096 local textBox = Instance.new("TextBox")
1097 textBox.Size = UDim2.new(1, 0, 0, 20)
1098 textBox.Position = UDim2.new(0, 0, 0, 18) -- Below label
1099 textBox.Text = defaultValue or ""
1100 textBox.PlaceholderText = "Enter text..."
1101 textBox.Font = Enum.Font.Gotham
1102 textBox.TextSize = 13
1103 textBox.TextColor3 = Color3.fromRGB(255, 255, 255)
1104 textBox.BackgroundColor3 = Color3.fromRGB(40, 40, 40)
1105 textBox.BorderSizePixel = 0
1106 textBox.ClearTextOnFocus = false -- Keep text when selecting
1107 textBox.Parent = frame
1108 createRounded(textBox, 5)
1109
1110 local stroke = Instance.new("UIStroke", textBox)
1111 stroke.Color = Color3.fromRGB(0, 170, 255)
1112 stroke.Thickness = 1
1113 stroke.Transparency = 0.7 -- Less transparent than main frame
1114
1115 textBox.FocusLost:Connect(function(enterPressed)
1116 if callback then
1117 callback(textBox.Text, enterPressed)
1118 end
1119 if enterPressed then
1120 UIS:ReleaseFocus() -- Unfocus on Enter
1121 end
1122 end)
1123
1124 return {
1125 SetText = function(newText)
1126 textBox.Text = tostring(newText)
1127 end,
1128 GetText = function()
1129 return textBox.Text
1130 end,
1131 SetTooltip = function(tooltipText)
1132 attachTooltip(textBox, tooltipText)
1133 attachTooltip(label, tooltipText) -- Attach to label too
1134 end
1135 }
1136end
1137
1138-- NEW: AddKeybind
1139function Nex:AddKeybind(labelText, defaultKey, callback)
1140 local frame = Instance.new("Frame")
1141 frame.Size = UDim2.new(1, -8, 0, 30)
1142 frame.BackgroundTransparency = 1
1143 frame.Parent = getContainer()
1144
1145 local label = Instance.new("TextLabel")
1146 label.Text = labelText
1147 label.Font = Enum.Font.Gotham
1148 label.TextSize = 12
1149 label.TextColor3 = Color3.fromRGB(200, 200, 200)
1150 label.BackgroundTransparency = 1
1151 label.Size = UDim2.new(0.4, 0, 1, 0) -- Left side for label
1152 label.TextXAlignment = Enum.TextXAlignment.Left
1153 label.Parent = frame
1154
1155 local keybindButton = Instance.new("TextButton")
1156 keybindButton.Size = UDim2.new(0.3, 0, 1, 0)
1157 keybindButton.Position = UDim2.new(0.42, 0, 0, 0) -- Middle for key
1158 keybindButton.Text = KeyCodeToString(defaultKey or Enum.KeyCode.None)
1159 keybindButton.Font = Enum.Font.Gotham
1160 keybindButton.TextSize = 13
1161 keybindButton.TextColor3 = Color3.fromRGB(255, 255, 255)
1162 keybindButton.BackgroundColor3 = Color3.fromRGB(40, 40, 40)
1163 keybindButton.BorderSizePixel = 0
1164 keybindButton.Parent = frame
1165 createRounded(keybindButton, 5)
1166 keybindButton.key = defaultKey or Enum.KeyCode.None -- Store the actual KeyCode
1167
1168 -- Red/Green Toggle
1169 local toggleButton = Instance.new("TextButton")
1170 toggleButton.Size = UDim2.new(0.2, 0, 1, 0)
1171 toggleButton.Position = UDim2.new(0.75, 5, 0, 0) -- Right side for toggle
1172 toggleButton.Font = Enum.Font.GothamBold
1173 toggleButton.TextSize = 13
1174 toggleButton.BorderSizePixel = 0
1175 toggleButton.AutoButtonColor = false
1176 toggleButton.Parent = frame
1177 createRounded(toggleButton, 5)
1178
1179 local keybindState = false -- Initial state of the keybind toggle
1180
1181 local function updateToggleVisual()
1182 if keybindState then
1183 toggleButton.Text = "ON"
1184 toggleButton.BackgroundColor3 = Color3.fromRGB(0, 200, 100) -- Green
1185 else
1186 toggleButton.Text = "OFF"
1187 toggleButton.BackgroundColor3 = Color3.fromRGB(200, 50, 50) -- Red
1188 end
1189 end
1190
1191 local function setKeybindState(newState, triggerCallback)
1192 keybindState = newState
1193 updateToggleVisual()
1194 if triggerCallback and callback then
1195 callback(keybindState)
1196 end
1197 end
1198
1199 toggleButton.MouseButton1Click:Connect(function()
1200 setKeybindState(not keybindState, true)
1201 end)
1202
1203 keybindButton.MouseButton1Click:Connect(function()
1204 if listeningForKey == keybindButton then -- If already listening, stop
1205 listeningForKey = nil
1206 TweenService:Create(keybindButton, TweenInfo.new(0.2), {BackgroundColor3 = Color3.fromRGB(40, 40, 40)}):Play()
1207 return
1208 end
1209 if listeningForKey then -- Another button is listening, stop it first
1210 TweenService:Create(listeningForKey, TweenInfo.new(0.2), {BackgroundColor3 = Color3.fromRGB(40, 40, 40)}):Play()
1211 listeningForKey = nil
1212 end
1213
1214 listeningForKey = keybindButton
1215 TweenService:Create(keybindButton, TweenInfo.new(0.2), {BackgroundColor3 = Color3.fromRGB(0, 170, 255)}):Play()
1216 keybindButton.Text = "..." -- Indicate listening
1217 end)
1218
1219 -- Register the keybind with the central manager
1220 local keybindData = {
1221 inputObject = keybindButton.key, -- The KeyCode
1222 callback = callback,
1223 toggleComponent = {
1224 Set = setKeybindState,
1225 Get = function() return keybindState end
1226 }
1227 }
1228 table.insert(Keybinds, keybindData)
1229
1230 -- Update the inputObject in the Keybinds table when the keybindButton's key changes
1231 keybindButton:GetPropertyChangedSignal("key"):Connect(function()
1232 keybindData.inputObject = keybindButton.key
1233 end)
1234
1235 updateToggleVisual() -- Initialize visual state
1236
1237 return {
1238 SetKey = function(newKey)
1239 keybindButton.key = newKey
1240 keybindButton.Text = KeyCodeToString(newKey)
1241 },
1242 SetState = function(newState)
1243 setKeybindState(newState, false) -- Don't trigger user callback when setting programmatically
1244 },
1245 GetState = function() return keybindState end,
1246 SetTooltip = function(tooltipText)
1247 attachTooltip(frame, tooltipText) -- Attach to the whole frame
1248 end
1249 }
1250end
1251
1252return Nex