The API documentation on TopBarPlus for Icon.new()
doesn’t really provide much information about what it returns, how it functions, etc…
So, I’ll just rip the source code off from this GitHub page, and and post it here for others to see. (Note that this function contains functions outside of this constructor)
function Icon.new()
local self = {}
setmetatable(self, Icon)
--- Janitors (for cleanup)
local janitor = Janitor.new()
self.janitor = janitor
self.themesJanitor = janitor:add(Janitor.new())
self.singleClickJanitor = janitor:add(Janitor.new())
self.captionJanitor = janitor:add(Janitor.new())
self.joinJanitor = janitor:add(Janitor.new())
self.menuJanitor = janitor:add(Janitor.new())
self.dropdownJanitor = janitor:add(Janitor.new())
-- Register
local iconUID = Utility.generateUID()
iconsDict[iconUID] = self
janitor:add(function()
iconsDict[iconUID] = nil
end)
-- Signals (events)
self.selected = janitor:add(Signal.new())
self.deselected = janitor:add(Signal.new())
self.toggled = janitor:add(Signal.new())
self.viewingStarted = janitor:add(Signal.new())
self.viewingEnded = janitor:add(Signal.new())
self.stateChanged = janitor:add(Signal.new())
self.notified = janitor:add(Signal.new())
self.noticeStarted = janitor:add(Signal.new())
self.noticeChanged = janitor:add(Signal.new())
self.endNotices = janitor:add(Signal.new())
self.toggleKeyAdded = janitor:add(Signal.new())
self.fakeToggleKeyChanged = janitor:add(Signal.new())
self.alignmentChanged = janitor:add(Signal.new())
self.updateSize = janitor:add(Signal.new())
self.resizingComplete = janitor:add(Signal.new())
self.joinedParent = janitor:add(Signal.new())
self.menuSet = janitor:add(Signal.new())
self.dropdownSet = janitor:add(Signal.new())
self.updateMenu = janitor:add(Signal.new())
self.startMenuUpdate = janitor:add(Signal.new())
self.childThemeModified = janitor:add(Signal.new())
self.indicatorSet = janitor:add(Signal.new())
self.dropdownChildAdded = janitor:add(Signal.new())
self.menuChildAdded = janitor:add(Signal.new())
-- Properties
self.iconModule = iconModule
self.UID = iconUID
self.isEnabled = true
self.isSelected = false
self.isViewing = false
self.joinedFrame = false
self.parentIconUID = false
self.deselectWhenOtherIconSelected = true
self.totalNotices = 0
self.activeState = "Deselected"
self.alignment = ""
self.originalAlignment = ""
self.appliedTheme = {}
self.appearance = {}
self.cachedInstances = {}
self.cachedNamesToInstances = {}
self.cachedCollectives = {}
self.bindedToggleKeys = {}
self.customBehaviours = {}
self.toggleItems = {}
self.bindedEvents = {}
self.notices = {}
self.menuIcons = {}
self.dropdownIcons = {}
self.childIconsDict = {}
self.isOldTopbar = Icon.isOldTopbar
self.creationTime = os.clock()
-- Widget is the new name for an icon
local widget = janitor:add(require(elements.Widget)(self, Icon))
self.widget = widget
self:setAlignment()
-- It's important we set an order otherwise icons will not align
-- correctly within menus
totalCreatedIcons += 1
local ourOrder = totalCreatedIcons
self:setOrder(ourOrder)
-- This applies the default them
self:setTheme(Icon.baseTheme)
-- Button Clicked (for states "Selected" and "Deselected")
local clickRegion = self:getInstance("ClickRegion")
local function handleToggle()
if self.locked then
return
end
if self.isSelected then
self:deselect("User", self)
else
self:select("User", self)
end
end
local isTouchTapping = false
local isClicking = false
clickRegion.MouseButton1Click:Connect(function()
if isTouchTapping then
return
end
isClicking = true
task.delay(0.01, function()
isClicking = false
end)
handleToggle()
end)
clickRegion.TouchTap:Connect(function()
-- This resolves the bug report by @28Pixels:
-- https://devforum.roblox.com/t/topbarplus/1017485/1104
if isClicking then
return
end
isTouchTapping = true
task.delay(0.01, function()
isTouchTapping = false
end)
handleToggle()
end)
-- Keys can be bound to toggle between Selected and Deselected
janitor:add(UserInputService.InputBegan:Connect(function(input, touchingAnObject)
if self.locked then
return
end
if self.bindedToggleKeys[input.KeyCode] and not touchingAnObject then
handleToggle()
end
end))
-- Button Hovering (for state "Viewing")
-- Hovering is a state only for devices with keyboards
-- and controllers (not touchpads)
local function viewingStarted(dontSetState)
if self.locked then
return
end
self.isViewing = true
self.viewingStarted:Fire(true)
if not dontSetState then
self:setState("Viewing", "User", self)
end
end
local function viewingEnded()
if self.locked then
return
end
self.isViewing = false
self.viewingEnded:Fire(true)
self:setState(nil, "User", self)
end
self.joinedParent:Connect(function()
if self.isViewing then
viewingEnded()
end
end)
clickRegion.MouseEnter:Connect(function()
local dontSetState = not UserInputService.KeyboardEnabled
viewingStarted(dontSetState)
end)
local touchCount = 0
janitor:add(UserInputService.TouchEnded:Connect(viewingEnded))
clickRegion.MouseLeave:Connect(viewingEnded)
clickRegion.SelectionGained:Connect(viewingStarted)
clickRegion.SelectionLost:Connect(viewingEnded)
clickRegion.MouseButton1Down:Connect(function()
if not self.locked and UserInputService.TouchEnabled then
touchCount += 1
local myTouchCount = touchCount
task.delay(0.2, function()
if myTouchCount == touchCount then
viewingStarted()
end
end)
end
end)
clickRegion.MouseButton1Up:Connect(function()
touchCount += 1
end)
-- Handle overlay on viewing
local iconOverlay = self:getInstance("IconOverlay")
self.viewingStarted:Connect(function()
iconOverlay.Visible = not self.overlayDisabled
end)
self.viewingEnded:Connect(function()
iconOverlay.Visible = false
end)
-- Deselect when another icon is selected
janitor:add(anyIconSelected:Connect(function(incomingIcon)
if incomingIcon ~= self and self.deselectWhenOtherIconSelected and incomingIcon.deselectWhenOtherIconSelected then
self:deselect("AutoDeselect", incomingIcon)
end
end))
-- This checks if the script calling this module is a descendant of a ScreenGui
-- with 'ResetOnSpawn' set to true. If it is, then we destroy the icon the
-- client respawns. This solves one of the most asked about questions on the post
-- The only caveat this may not work if the player doesn't uniquely name their ScreenGui and the frames
-- the LocalScript rests within
local source = debug.info(2, "s")
local sourcePath = string.split(source, ".")
local origin = game
local originsScreenGui
for i, sourceName in pairs(sourcePath) do
origin = origin:FindFirstChild(sourceName)
if not origin then
break
end
if origin:IsA("ScreenGui") then
originsScreenGui = origin
end
end
if origin and originsScreenGui and originsScreenGui.ResetOnSpawn == true then
Utility.localPlayerRespawned(function()
self:destroy()
end)
end
-- Additional children behaviour when toggled (mostly notices)
local noticeLabel = self:getInstance("NoticeLabel")
self.toggled:Connect(function(isSelected)
self.noticeChanged:Fire(self.totalNotices)
for childIconUID, _ in pairs(self.childIconsDict) do
local childIcon = Icon.getIconByUID(childIconUID)
childIcon.noticeChanged:Fire(childIcon.totalNotices)
if not isSelected and childIcon.isSelected then
-- If an icon within a menu or dropdown is also
-- a dropdown or menu, then close it
for _, _ in pairs(childIcon.childIconsDict) do
childIcon:deselect("HideParentFeature", self)
end
end
end
end)
-- This closes/reopens the chat or playerlist if the icon is a dropdown
-- In the future I'd prefer to use the position+size of the chat
-- to determine whether to close dropdown (instead of non-right-set)
-- but for reasons mentioned here it's unreliable at the time of
-- writing this: https://devforum.roblox.com/t/here/2794915
-- I could also make this better by accounting for multiple
-- dropdowns being open (not just this one) but this will work
-- fine for almost every use case for now.
self.selected:Connect(function()
local isDropdown = #self.dropdownIcons > 0
if isDropdown then
if StarterGui:GetCore("ChatActive") and self.alignment ~= "Right" then
self.chatWasPreviouslyActive = true
StarterGui:SetCore("ChatActive", false)
end
if StarterGui:GetCoreGuiEnabled("PlayerList") and self.alignment ~= "Left" then
self.playerlistWasPreviouslyActive = true
StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.PlayerList, false)
end
end
end)
self.deselected:Connect(function()
if self.chatWasPreviouslyActive then
self.chatWasPreviouslyActive = nil
StarterGui:SetCore("ChatActive", true)
end
if self.playerlistWasPreviouslyActive then
self.playerlistWasPreviouslyActive = nil
StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.PlayerList, true)
end
end)
-- There's a rare occassion where the appearance is not
-- fully set to deselected so this ensures the icons
-- appearance is fully as it should be
--print("self.activeState =", self.activeState)
task.delay(0.1, function()
if self.activeState == "Deselected" then
self.stateChanged:Fire("Deselected")
self:refresh()
end
end)
-- Call icon added
Icon.iconAdded:Fire(self)
return self
end
As far as I know, it is meant to be returned, but it isn’t according to your problem.
Have you tried reinstalling the TopbarPlus module?