function Icon.set(j,d,Q,t,H)local X=j._settingsDictionary[d]assert(X~=nil,("\115\101\116\116\105\110\103 \'\037\115\' \100\111\101\115 \110\111\116 \101\120\105\115\116"):format(d))if type(t)=="\115\116\114\105\110\103"then t=t:lower()end local y=j:get(d,t)if t=="\104\111\118\101\114\105\110\103"then X.hoveringValue=Q if H~="\095\105\103\110\111\114\101\080\114\101\118\105\111\117\115"then X.additionalValues["\112\114\101\118\105\111\117\115\095"..t]=y end if type(H)=="\115\116\114\105\110\103"then X.additionalValues[H..("\095"..t)]=y end j:_update(d)else local r=t local p=X.type if p=="\116\111\103\103\108\101\097\098\108\101"then local d={}if r=="\100\101\115\101\108\101\099\116\101\100"or r=="\115\101\108\101\099\116\101\100"then table.insert(d,r)else table.insert(d,"\100\101\115\101\108\101\099\116\101\100")table.insert(d,"\115\101\108\101\099\116\101\100")r=nil end for d,t in pairs(d)do X.values[t]=Q if H~="\095\105\103\110\111\114\101\080\114\101\118\105\111\117\115"then X.additionalValues["\112\114\101\118\105\111\117\115\095"..t]=y end if type(H)=="\115\116\114\105\110\103"then X.additionalValues[H..("\095"..t)]=y end end else X.value=Q if type(H)=="\115\116\114\105\110\103"then if H~="\095\105\103\110\111\114\101\080\114\101\118\105\111\117\115"then X.additionalValues.previous=y end X.additionalValues[H]=y end end if y==Q then return j,"\086\097\108\117\101 \119\097\115 \097\108\114\101\097\100\121 \115\101\116"end local v=j:getToggleState()if not j._updateAfterSettingAll and(X.instanceNames and(v==r or r==nil))then local Q=d=="\105\099\111\110\083\105\122\101"and(y and y.X.Scale==1)local t=X.tweenAction and(not Q and j:get(X.tweenAction))or TweenInfo.new(0)j:_update(d,v,t)end end if X.callMethods then for d,H in pairs(X.callMethods)do H(j,Q,t)end end if X.callSignals then for d,Q in pairs(X.callSignals)do Q:Fire()end end return j end function Icon.setAdditionalValue(j,d,Q,t,H)local X=j._settingsDictionary[d]assert(X~=nil,("\115\101\116\116\105\110\103 \'\037\115\' \100\111\101\115 \110\111\116 \101\120\105\115\116"):format(d))local y=Q.."\095"if H then y=y..H end for d,Q in pairs(X.additionalValues)do if string.match(d,y)then X.additionalValues[d]=t end end end function Icon.get(H,d,Q,t)local j=H._settingsDictionary[d]assert(j~=nil,("\115\101\116\116\105\110\103 \'\037\115\' \100\111\101\115 \110\111\116 \101\120\105\115\116"):format(d))local X,y if typeof(Q)=="\115\116\114\105\110\103"then Q=Q:lower()end if Q=="\104\111\118\101\114\105\110\103"and t==nil then X=j.hoveringValue y=type(t)=="\115\116\114\105\110\103"and j.additionalValues[t..("\095"..Q)]end local r=j.type if r=="\116\111\103\103\108\101\097\098\108\101"then local d=(Q=="\100\101\115\101\108\101\099\116\101\100"or Q=="\115\101\108\101\099\116\101\100")and Q or H:getToggleState()if y==nil then y=type(t)=="\115\116\114\105\110\103"and j.additionalValues[t..("\095"..d)]end if X==nil then X=j.values[d]end else if y==nil then y=type(t)=="\115\116\114\105\110\103"and j.additionalValues[t]end if X==nil then X=j.value end end return X,y end function Icon.getHovering(Q,d)local t=Q._settingsDictionary[d]assert(t~=nil,("\115\101\116\116\105\110\103 \'\037\115\' \100\111\101\115 \110\111\116 \101\120\105\115\116"):format(d))return t.hoveringValue end function Icon.getToggleState(Q,d)d=d or Q.isSelected return d and"\115\101\108\101\099\116\101\100"or"\100\101\115\101\108\101\099\116\101\100"end function Icon.getIconState(d)if d.hovering then return"\104\111\118\101\114\105\110\103"else return d:getToggleState()end end function Icon._update(H,d,Q,t)local j=H._settingsDictionary[d]assert(j~=nil,("\115\101\116\116\105\110\103 \'\037\115\' \100\111\101\115 \110\111\116 \101\120\105\115\116"):format(d))Q=Q or H:getToggleState()local X=j.value or j.values and j.values[Q]if H.hovering and j.hoveringValue then X=j.hoveringValue end if X==nil then return end local y=t or j.tweenAction and(j.tweenAction~=""and H:get(j.tweenAction))or H:get("\116\111\103\103\108\101\084\114\097\110\115\105\116\105\111\110\073\110\102\111")or TweenInfo.new(.15)local r=j.propertyName local p={string=true,NumberSequence=true;Text=true;EnumItem=true;ColorSequence=true}local v=H._uniqueSettingsDictionary[d]local N=X if j.useForcedGroupValue then N=j.forcedGroupValue end if j.instanceNames then for Q,t in pairs(j.instanceNames)do local j=H.instances[t]local Y=typeof(j[r])local R=p[Y]or typeof(j)=="\116\097\098\108\101"if v then v(d,j,r,N)elseif R then j[r]=X else(tweenService:Create(j,y,{[r]=N})):Play()end if d=="\105\099\111\110\083\105\122\101"and j[r]~=N then H.updated:Fire()end end end end function Icon._updateAll(t,d,Q)for H,j in pairs(t._settingsDictionary)do if j.instanceNames then t:_update(H,d,Q)end end t:_updateIconSize()t:_updateCaptionSize()t:_updateTipSize()end function Icon._updateHovering(Q,d)for t,H in pairs(Q._settingsDictionary)do if H.instanceNames and H.hoveringValue~=nil then Q:_update(t,nil,d)end end end function Icon._updateStateOverlay(t,d,Q)local H=t.instances.iconOverlay H.BackgroundTransparency=d or 1 H.BackgroundColor3=Q or Color3.new(1,1,1)end function Icon.setTheme(t,d,Q)t._updateAfterSettingAll=Q for d,Q in pairs(d)do if d=="\116\111\103\103\108\101\097\098\108\101"then for d,Q in pairs(Q.deselected)do if not t.lockedSettings[d]then t:set(d,Q,"\098\111\116\104")end end for d,Q in pairs(Q.selected)do if not t.lockedSettings[d]then t:set(d,Q,"\115\101\108\101\099\116\101\100")end end else for Q,H in pairs(Q)do if not t.lockedSettings[Q]then local j=t._settingsDictionary[Q]if d=="\097\099\116\105\111\110"and j==nil then j={}t._settingsDictionary[Q]={}end t:set(Q,H)end end end end t._updateAfterSettingAll=nil if Q then t:_updateAll()end return t end function Icon.getInstance(Q,d)return Q.instances[d]end function Icon.setInstance(t,d,Q)local H=t.instances[d]t.instances[d]=Q if H then H:Destroy()end return t end function Icon.getSettingDetail(Q,d)for Q,t in pairs(Q._settings)do for Q,t in pairs(t)do if Q==d then return t end end end return false end function Icon.modifySetting(t,d,Q)local H=t:getSettingDetail(d)for d,Q in pairs(Q)do H[d]=Q end return t end function Icon.convertLabelToNumberSpinner(Q,d)Q:set("\105\099\111\110\076\097\098\101\108\083\105\122\101",UDim2.new(1,0,1,0))d.Parent=Q:getInstance("\105\099\111\110\066\117\116\116\111\110")local t={}setmetatable(t,{__newindex=function(Q,t,H)for d,Q in pairs(d.Frame:GetDescendants())do if Q:IsA("\084\101\120\116\076\097\098\101\108")then Q[t]=H end end end})local H=Q:getInstance("\105\099\111\110\066\117\116\116\111\110")H.ZIndex=0 Q:setInstance("\105\099\111\110\076\097\098\101\108",t)Q:modifySetting("\105\099\111\110\084\101\120\116",{instanceNames={}})Q:setInstance("\105\099\111\110\076\097\098\101\108\083\112\105\110\110\101\114",d.Frame)local j={"\105\099\111\110\076\097\098\101\108\086\105\115\105\098\108\101","\105\099\111\110\076\097\098\101\108\065\110\099\104\111\114\080\111\105\110\116";"\105\099\111\110\076\097\098\101\108\080\111\115\105\116\105\111\110";"\105\099\111\110\076\097\098\101\108\083\105\122\101"}for d,t in pairs(j)do Q:modifySetting(t,{instanceNames={"\105\099\111\110\076\097\098\101\108\083\112\105\110\110\101\114"}})end Q:_updateAll()return Q end function Icon.setEnabled(Q,d)Q.enabled=d Q.instances.iconContainer.Visible=d Q.updated:Fire()return Q end function Icon.setName(Q,d)Q.name=d Q.instances.iconContainer.Name=d return Q end function Icon.setProperty(t,d,Q)t[d]=Q return t end function Icon._playClickSound(d)local Q=d.instances.clickSound if Q.SoundId~=nil and(#Q.SoundId>0 and Q.Volume>0)then local d=Q:Clone()d.Parent=Q.Parent d:Play()debris:AddItem(d,Q.TimeLength)end end function Icon.select(Q,d)Q.isSelected=true Q:_setToggleItemsVisible(true,d)Q:_updateNotice()Q:_updateAll()Q:_playClickSound()if#Q.dropdownIcons>0 or#Q.menuIcons>0 then IconController:_updateSelectionGroup()end if userInputService.GamepadEnabled then for d,t in pairs(Q.toggleItems)do if#t>0 then local d=Maid.new()guiService:AddSelectionTuple(Q.UID,unpack(t))guiService.SelectedObject=t[1]IconController.activeButtonBCallbacks+=1 d:give(userInputService.InputEnded:Connect(function(d,t)local H=false for d,Q in pairs(Q.blockBackBehaviourChecks)do if Q()==true then H=true break end end if d.KeyCode==Enum.KeyCode.ButtonB and not H then guiService.SelectedObject=Q.instances.iconButton Q:deselect()end end))d:give(Q.deselected:Connect(function()d:clean()end))d:give(function()IconController.activeButtonBCallbacks-=1 if IconController.activeButtonBCallbacks<0 then IconController.activeButtonBCallbacks=0 end end)end end end Q.selected:Fire()Q.toggled:Fire(Q.isSelected)return Q end function Icon.deselect(Q,d)Q.isSelected=false Q:_setToggleItemsVisible(false,d)Q:_updateNotice()Q:_updateAll()Q:_playClickSound()if#Q.dropdownIcons>0 or#Q.menuIcons>0 then IconController:_updateSelectionGroup()end Q.deselected:Fire()Q.toggled:Fire(Q.isSelected)if userInputService.GamepadEnabled then guiService:RemoveSelectionGroup(Q.UID)end return Q end function Icon.notify(t,d,Q)(coroutine.wrap(function()if not d then d=t.deselected end if t._parentIcon then t._parentIcon:notify(d)end local H=Signal.new()local j=t._endNotices:Connect(function()H:Fire()end)local X=d:Connect(function()H:Fire()end)Q=Q or httpService:GenerateGUID(true)t.notices[Q]={completeSignal=H,clearNoticeEvent=d}t.totalNotices+=1 t:_updateNotice()t.notified:Fire(Q)H:Wait()j:Disconnect()X:Disconnect()H:Disconnect()t.totalNotices-=1 t.notices[Q]=nil t:_updateNotice()end))()return t end function Icon._updateNotice(d)local Q=true if d.totalNotices<1 then Q=false end if not d.isSelected then if(#d.dropdownIcons>0 or#d.menuIcons>0)and d.totalNotices>0 then Q=true end end if d.isSelected then if#d.dropdownIcons>0 or#d.menuIcons>0 then Q=false end end local t=Q and 0 or 1 d:set("\110\111\116\105\099\101\073\109\097\103\101\084\114\097\110\115\112\097\114\101\110\099\121",t)d:set("\110\111\116\105\099\101\084\101\120\116\084\114\097\110\115\112\097\114\101\110\099\121",t)d.instances.noticeLabel.Text=d.totalNotices<100 and d.totalNotices or"\057\057\043"end function Icon.clearNotices(d)d._endNotices:Fire()return d end function Icon.disableStateOverlay(Q,d)if d==nil then d=true end local t=Q.instances.iconOverlay t.Visible=not d return Q end

function Icon:set(settingName, value, iconState, setAdditional)
	local settingDetail = self._settingsDictionary[settingName]
	assert(settingDetail ~= nil, ("setting '%s' does not exist"):format(settingName))
	if type(iconState) == "string" then
		iconState = iconState:lower()
	end
	local previousValue = self:get(settingName, iconState)

	if iconState == "hovering" then
		-- Apply hovering state if valid
		settingDetail.hoveringValue = value
		if setAdditional ~= "_ignorePrevious" then
			settingDetail.additionalValues["previous_"..iconState] = previousValue
		end
		if type(setAdditional) == "string" then
			settingDetail.additionalValues[setAdditional.."_"..iconState] = previousValue
		end
		self:_update(settingName)

	else
		-- Update the settings value
		local toggleState = iconState
		local settingType = settingDetail.type
		if settingType == "toggleable" then
			local valuesToSet = {}
			if toggleState == "deselected" or toggleState == "selected" then
				table.insert(valuesToSet, toggleState)
			else
				table.insert(valuesToSet, "deselected")
				table.insert(valuesToSet, "selected")
				toggleState = nil
			end
			for i, v in pairs(valuesToSet) do
				settingDetail.values[v] = value
				if setAdditional ~= "_ignorePrevious" then
					settingDetail.additionalValues["previous_"..v] = previousValue
				end
				if type(setAdditional) == "string" then
					settingDetail.additionalValues[setAdditional.."_"..v] = previousValue
				end
			end
		else
			settingDetail.value = value
			if type(setAdditional) == "string" then
				if setAdditional ~= "_ignorePrevious" then
					settingDetail.additionalValues["previous"] = previousValue
				end
				settingDetail.additionalValues[setAdditional] = previousValue
			end
		end

		-- Check previous and new are not the same
		if previousValue == value then
			return self, "Value was already set"
		end

		-- Update appearances of associated instances
		local currentToggleState = self:getToggleState()
		if not self._updateAfterSettingAll and settingDetail.instanceNames and (currentToggleState == toggleState or toggleState == nil) then
			local ignoreTweenAction = (settingName == "iconSize" and previousValue and previousValue.X.Scale == 1)
			local tweenInfo = (settingDetail.tweenAction and not ignoreTweenAction and self:get(settingDetail.tweenAction)) or TweenInfo.new(0)
			self:_update(settingName, currentToggleState, tweenInfo)
		end
	end

	-- Call any methods present
	if settingDetail.callMethods then
		for _, callMethod in pairs(settingDetail.callMethods) do
			callMethod(self, value, iconState)
		end
	end
	
	-- Call any signals present
	if settingDetail.callSignals then
		for _, callSignal in pairs(settingDetail.callSignals) do
			callSignal:Fire()
		end
	end
	return self
end

function Icon:setAdditionalValue(settingName, setAdditional, value, iconState)
	local settingDetail = self._settingsDictionary[settingName]
	assert(settingDetail ~= nil, ("setting '%s' does not exist"):format(settingName))
	local stringMatch = setAdditional.."_"
	if iconState then
		stringMatch = stringMatch..iconState
	end
	for key, _ in pairs(settingDetail.additionalValues) do
		if string.match(key, stringMatch) then
			settingDetail.additionalValues[key] = value
		end
	end
end

function Icon:get(settingName, iconState, getAdditional)
	local settingDetail = self._settingsDictionary[settingName]
	assert(settingDetail ~= nil, ("setting '%s' does not exist"):format(settingName))
	local valueToReturn, additionalValueToReturn
	if typeof(iconState) == "string" then
		iconState = iconState:lower()
	end

	--if ((self.hovering and settingDetail.hoveringValue) or iconState == "hovering") and getAdditional == nil then
	if (iconState == "hovering") and getAdditional == nil then
		valueToReturn = settingDetail.hoveringValue
		additionalValueToReturn = type(getAdditional) == "string" and settingDetail.additionalValues[getAdditional.."_"..iconState]
	end

	local settingType = settingDetail.type
	if settingType == "toggleable" then
		local toggleState = ((iconState == "deselected" or iconState == "selected") and iconState) or self:getToggleState()
		if additionalValueToReturn == nil then
			additionalValueToReturn = type(getAdditional) == "string" and settingDetail.additionalValues[getAdditional.."_"..toggleState]
		end
		if valueToReturn == nil then
			valueToReturn = settingDetail.values[toggleState]
		end
	
	else
		if additionalValueToReturn == nil then
			additionalValueToReturn = type(getAdditional) == "string" and settingDetail.additionalValues[getAdditional]
		end
		if valueToReturn == nil then
			valueToReturn = settingDetail.value
		end
	end

	return valueToReturn, additionalValueToReturn
end

function Icon:getHovering(settingName)
	local settingDetail = self._settingsDictionary[settingName]
	assert(settingDetail ~= nil, ("setting '%s' does not exist"):format(settingName))
	return settingDetail.hoveringValue
end

function Icon:getToggleState(isSelected)
	isSelected = isSelected or self.isSelected
	return (isSelected and "selected") or "deselected"
end

function Icon:getIconState()
	if self.hovering then
		return "hovering"
	else
		return self:getToggleState()
	end
end

function Icon:_update(settingName, toggleState, customTweenInfo)
	local settingDetail = self._settingsDictionary[settingName]
	assert(settingDetail ~= nil, ("setting '%s' does not exist"):format(settingName))
	toggleState = toggleState or self:getToggleState()
	local value = settingDetail.value or (settingDetail.values and settingDetail.values[toggleState])
	if self.hovering and settingDetail.hoveringValue then
		value = settingDetail.hoveringValue
	end
	if value == nil then return end
	local tweenInfo = customTweenInfo or (settingDetail.tweenAction and settingDetail.tweenAction ~= "" and self:get(settingDetail.tweenAction)) or self:get("toggleTransitionInfo") or TweenInfo.new(0.15)
	local propertyName = settingDetail.propertyName
	local invalidPropertiesTypes = {
		["string"] = true,
		["NumberSequence"] = true,
		["Text"] = true,
		["EnumItem"] = true,
		["ColorSequence"] = true,
	}
	local uniqueSetting = self._uniqueSettingsDictionary[settingName]
	local newValue = value
	if settingDetail.useForcedGroupValue then
		newValue = settingDetail.forcedGroupValue
	end
	if settingDetail.instanceNames then
		for _, instanceName in pairs(settingDetail.instanceNames) do
			local instance = self.instances[instanceName]
			local propertyType = typeof(instance[propertyName])
			local cannotTweenProperty = invalidPropertiesTypes[propertyType] or typeof(instance) == "table"
			if uniqueSetting then
				uniqueSetting(settingName, instance, propertyName, newValue)
			elseif cannotTweenProperty then
				instance[propertyName] = value
			else
				tweenService:Create(instance, tweenInfo, {[propertyName] = newValue}):Play()
			end
			--
			if settingName == "iconSize" and instance[propertyName] ~= newValue then
				self.updated:Fire()
			end
			--
		end
	end
end

function Icon:_updateAll(iconState, customTweenInfo)
	for settingName, settingDetail in pairs(self._settingsDictionary) do
		if settingDetail.instanceNames then
			self:_update(settingName, iconState, customTweenInfo)
		end
	end
	-- It's important we adapt the size of anything that could be changed through Localization
	-- In this case, the icon label, caption and tip
	self:_updateIconSize()
	self:_updateCaptionSize()
	self:_updateTipSize()
end

function Icon:_updateHovering(customTweenInfo)
	for settingName, settingDetail in pairs(self._settingsDictionary) do
		if settingDetail.instanceNames and settingDetail.hoveringValue ~= nil then
			self:_update(settingName, nil, customTweenInfo)
		end
	end
end

function Icon:_updateStateOverlay(transparency, color)
	local stateOverlay = self.instances.iconOverlay
	stateOverlay.BackgroundTransparency = transparency or 1
	stateOverlay.BackgroundColor3 = color or Color3.new(1, 1, 1)
end

function Icon:setTheme(theme, updateAfterSettingAll)
	self._updateAfterSettingAll = updateAfterSettingAll
	for settingsType, settingsDetails in pairs(theme) do
		if settingsType == "toggleable" then
			for settingName, settingValue in pairs(settingsDetails.deselected) do
				if not self.lockedSettings[settingName] then
					self:set(settingName, settingValue, "both")
				end
			end
			for settingName, settingValue in pairs(settingsDetails.selected) do
				if not self.lockedSettings[settingName] then
					self:set(settingName, settingValue, "selected")
				end
			end
		else
			for settingName, settingValue in pairs(settingsDetails) do
				if not self.lockedSettings[settingName] then
					local settingDetail = self._settingsDictionary[settingName]
					if settingsType == "action" and settingDetail == nil then
						settingDetail = {}
						self._settingsDictionary[settingName] = {}
					end
					self:set(settingName, settingValue)
				end
			end
		end
	end
	self._updateAfterSettingAll = nil
	if updateAfterSettingAll then
		self:_updateAll()
	end
	return self
end

function Icon:getInstance(instanceName)
	return self.instances[instanceName]
end

function Icon:setInstance(instanceName, instance)
	local originalInstance = self.instances[instanceName]
	self.instances[instanceName] = instance
	if originalInstance then
		originalInstance:Destroy()
	end
	return self
end

function Icon:getSettingDetail(targetSettingName)
	for _, settingsDetails in pairs(self._settings) do
		for settingName, settingDetail in pairs(settingsDetails) do
			if settingName == targetSettingName then
				return settingDetail
			end
		end
	end
	return false
end

function Icon:modifySetting(settingName, dictionary)
	local settingDetail = self:getSettingDetail(settingName)
	for key, value in pairs(dictionary) do
		settingDetail[key] = value
	end
	return self
end

function Icon:convertLabelToNumberSpinner(numberSpinner)
	-- This updates the number spinners appearance
	self:set("iconLabelSize", UDim2.new(1,0,1,0))
	numberSpinner.Parent = self:getInstance("iconButton")

	-- This creates a fake iconLabel which updates the property of all descendant spinner TextLabels when indexed
	local textLabel = {}
	setmetatable(textLabel, {__newindex = function(_, index, value)
		for _, label in pairs(numberSpinner.Frame:GetDescendants()) do
			if label:IsA("TextLabel") then
				label[index] = value
			end
		end
	end})

	-- This overrides existing instances and settings so that they update the spinners properties (instead of the old textlabel)
	local iconButton = self:getInstance("iconButton")
	iconButton.ZIndex = 0
	self:setInstance("iconLabel", textLabel)
	self:modifySetting("iconText", {instanceNames = {}}) -- We do this to prevent text being modified within the metatable above
	self:setInstance("iconLabelSpinner", numberSpinner.Frame)
	local settingsToConvert = {"iconLabelVisible", "iconLabelAnchorPoint", "iconLabelPosition", "iconLabelSize"}
	for _, settingName in pairs(settingsToConvert) do
		self:modifySetting(settingName, {instanceNames = {"iconLabelSpinner"}})
	end

	-- This applies all the values we just updated
	self:_updateAll()
	return self
end

function Icon:setEnabled(bool)
	self.enabled = bool
	self.instances.iconContainer.Visible = bool
	self.updated:Fire()
	return self
end

function Icon:setName(string)
	self.name = string
	self.instances.iconContainer.Name = string
	return self
end

function Icon:setProperty(propertyName, value)
	self[propertyName] = value
	return self
end

function Icon:_playClickSound()
	local clickSound = self.instances.clickSound
	if clickSound.SoundId ~= nil and #clickSound.SoundId > 0 and clickSound.Volume > 0 then
		local clickSoundCopy = clickSound:Clone()
		clickSoundCopy.Parent = clickSound.Parent
		clickSoundCopy:Play()
		debris:AddItem(clickSoundCopy, clickSound.TimeLength)
	end
end

function Icon:select(byIcon)
	--if self.locked then return self end
	self.isSelected = true
	self:_setToggleItemsVisible(true, byIcon)
	self:_updateNotice()
	self:_updateAll()
	self:_playClickSound()
	if #self.dropdownIcons > 0 or #self.menuIcons > 0 then
		IconController:_updateSelectionGroup()
	end
	if userInputService.GamepadEnabled then
		-- If a corresponding guiObject is found (set via :setToggleItem()) then this automatically
		-- moves the controller selection to a selectable and active instance within that guiObject.
		-- It also support back (Controller B) being pressed by navigating to previous pages or
		-- closing the icon and focusing selection back on the controller navigation topbar.
		for toggleItem, buttonInstancesArray in pairs(self.toggleItems) do
			if #buttonInstancesArray > 0 then
				local focusMaid = Maid.new()
				guiService:AddSelectionTuple(self.UID, unpack(buttonInstancesArray))
				guiService.SelectedObject = buttonInstancesArray[1]
				IconController.activeButtonBCallbacks += 1
				focusMaid:give(userInputService.InputEnded:Connect(function(input, processed)
					local blockBackBehaviour = false
					for _, func in pairs(self.blockBackBehaviourChecks) do
						if func() == true then
							blockBackBehaviour = true
							break
						end
					end
					if input.KeyCode == Enum.KeyCode.ButtonB and not blockBackBehaviour then
						guiService.SelectedObject = self.instances.iconButton
						self:deselect()
					end
				end))
				focusMaid:give(self.deselected:Connect(function()
					focusMaid:clean()
				end))
				focusMaid:give(function()
					IconController.activeButtonBCallbacks -= 1
					if IconController.activeButtonBCallbacks < 0 then
						IconController.activeButtonBCallbacks = 0
					end
				end)
			end
		end
	end
	self.selected:Fire()
    self.toggled:Fire(self.isSelected)
	return self
end

function Icon:deselect(byIcon)
	--if self.locked then return self end
	self.isSelected = false
	self:_setToggleItemsVisible(false, byIcon)
	self:_updateNotice()
	self:_updateAll()
	self:_playClickSound()
	if #self.dropdownIcons > 0 or #self.menuIcons > 0 then
		IconController:_updateSelectionGroup()
	end
    self.deselected:Fire()
    self.toggled:Fire(self.isSelected)
	if userInputService.GamepadEnabled then
		guiService:RemoveSelectionGroup(self.UID)
	end
	return self
end

function Icon:notify(clearNoticeEvent, noticeId)
	coroutine.wrap(function()
		if not clearNoticeEvent then
			clearNoticeEvent = self.deselected
		end
		if self._parentIcon then
			self._parentIcon:notify(clearNoticeEvent)
		end
		
		local notifComplete = Signal.new()
		local endEvent = self._endNotices:Connect(function()
			notifComplete:Fire()
		end)
		local customEvent = clearNoticeEvent:Connect(function()
			notifComplete:Fire()
		end)
		
		noticeId = noticeId or httpService:GenerateGUID(true)
		self.notices[noticeId] = {
			completeSignal = notifComplete,
			clearNoticeEvent = clearNoticeEvent,
		}
		self.totalNotices += 1
		self:_updateNotice()

		self.notified:Fire(noticeId)
		notifComplete:Wait()
		
		endEvent:Disconnect()
		customEvent:Disconnect()
		notifComplete:Disconnect()
		
		self.totalNotices -= 1
		self.notices[noticeId] = nil
		self:_updateNotice()
	end)()
	return self
end

function Icon:_updateNotice()
	local enabled = true
	if self.totalNotices < 1 then
		enabled = false
	end
	-- Deselect
	if not self.isSelected then
		if (#self.dropdownIcons > 0 or #self.menuIcons > 0) and self.totalNotices > 0 then
			enabled = true
		end
	end
	-- Select
	if self.isSelected then
		if #self.dropdownIcons > 0 or #self.menuIcons > 0 then
			enabled = false
		end
	end
	local value = (enabled and 0) or 1
	self:set("noticeImageTransparency", value)
	self:set("noticeTextTransparency", value)
	self.instances.noticeLabel.Text = (self.totalNotices < 100 and self.totalNotices) or "99+"
end

function Icon:clearNotices()
	self._endNotices:Fire()
	return self
end

function Icon:disableStateOverlay(bool)
	if bool == nil then
		bool = true
	end
	local stateOverlay = self.instances.iconOverlay
	stateOverlay.Visible = not bool
	return self
end


