diff --git a/src/Elements/Container.lua b/src/Elements/Container.lua
index cb166e7..49ed456 100644
--- a/src/Elements/Container.lua
+++ b/src/Elements/Container.lua
@@ -130,7 +130,7 @@ return function(Icon)
end
screenGuiCenter.Name = "TopbarCentered"
screenGuiCenter.DisplayOrder = Icon.baseDisplayOrder
- screenGuiCenter.ScreenInsets = Enum.ScreenInsets.None
+ screenGuiCenter.ScreenInsets = Enum.ScreenInsets.TopbarSafeInsets
Icon.baseDisplayOrderChanged:Connect(function()
screenGuiCenter.DisplayOrder = Icon.baseDisplayOrder
end)
diff --git a/src/Elements/Dropdown.lua b/src/Elements/Dropdown.lua
index 13b99fe..4e1e0a7 100644
--- a/src/Elements/Dropdown.lua
+++ b/src/Elements/Dropdown.lua
@@ -134,6 +134,16 @@ return function(icon)
end
totalHeight += height
end
+ -- FIX: Include UIListLayout padding in height calculation
+ -- Previously, the dropdown height didn't account for spacing between icons
+ -- causing a slight visual mismatch when MaxIcons was set
+ local listPadding = dropdownList.Padding.Offset
+ local visibleIconCount = math.min(maxIconsRoundedUp, #children)
+ if visibleIconCount > 1 then
+ totalHeight += listPadding * (visibleIconCount - 1)
+ end
+
+ -- Add container padding
totalHeight += dropdownPadding.PaddingTop.Offset + dropdownPadding.PaddingBottom.Offset
return totalHeight
end
@@ -274,10 +284,16 @@ return function(icon)
childIcon:getInstance("ClickRegion").NextSelectionUp = nextSelection
end
end
+ -- FIX: Include UIListLayout padding in height calculation
+ -- Previously, the dropdown height didn't account for spacing between icons
+ -- causing a slight visual mismatch when MaxIcons was set
+ local listPadding = dropdownList.Padding.Offset
+ local visibleIconCount = math.min(maxIconsRoundedUp, #orderedInstances)
+ if visibleIconCount > 1 then
+ totalHeight += listPadding * (visibleIconCount - 1)
+ end
totalHeight += dropdownPadding.PaddingTop.Offset + dropdownPadding.PaddingBottom.Offset
-
dropdownScroller.Size = UDim2.fromOffset(0, totalHeight)
-
end
dropdownJanitor:add(dropdownScroller:GetPropertyChangedSignal("AbsoluteCanvasSize"):Connect(updateMaxIconsListener))
diff --git a/src/Features/Overflow.lua b/src/Features/Overflow.lua
index bc7b18d..a1037dd 100644
--- a/src/Features/Overflow.lua
+++ b/src/Features/Overflow.lua
@@ -353,6 +353,93 @@ function Overflow.updateBoundary(alignment)
overflowIcon:select()
end
+ -- Restore relocated center icons when space is available
+ if not isCentral then
+ -- Only restore if both overflow menus are completely inactive
+ local leftOverflow = overflowIcons["Left"]
+ local rightOverflow = overflowIcons["Right"]
+ local leftIsInactive = not leftOverflow or not leftOverflow.isEnabled
+ local rightIsInactive = not rightOverflow or not rightOverflow.isEnabled
+ local bothSidesStable = leftIsInactive and rightIsInactive
+
+ if not joinOverflow and bothSidesStable then
+ local relocatedIcons = {}
+ for _, icon in pairs(ourOrderedIcons) do
+ if icon.hasRelocatedInOverflow and not icon.parentIconUID then
+ table.insert(relocatedIcons, icon)
+ end
+ end
+
+ if #relocatedIcons > 0 then
+ table.sort(relocatedIcons, function(a, b)
+ return (a.widget.LayoutOrder or 0) < (b.widget.LayoutOrder or 0)
+ end)
+
+ for _, icon in ipairs(relocatedIcons) do
+ local centerOrderedIcons = Overflow.getAvailableIcons("Center")
+ local centerHolder = holders["Center"]
+ local centerHolderXPos = centerHolder.AbsolutePosition.X
+ local centerHolderXSize = centerHolder.AbsoluteSize.X
+ local centerUIList = centerHolder.UIListLayout
+ local centerPadding = centerUIList.Padding.Offset
+
+ local totalCenterWidth = 0
+ for _, centerIcon in pairs(centerOrderedIcons) do
+ totalCenterWidth += Overflow.getWidth(centerIcon) + centerPadding
+ end
+ totalCenterWidth += Overflow.getWidth(icon) + centerPadding
+
+ local leftOrderedIcons = Overflow.getAvailableIcons("Left")
+ local rightOrderedIcons = Overflow.getAvailableIcons("Right")
+
+ local leftBoundary = centerHolderXPos
+ local rightBoundary = centerHolderXPos + centerHolderXSize
+
+ -- Calculate boundaries excluding relocated icons
+ if #leftOrderedIcons > 0 then
+ local leftRealXPositions = Overflow.getRealXPositions("Left", leftOrderedIcons)
+ for _, leftIcon in pairs(leftOrderedIcons) do
+ if not leftIcon.hasRelocatedInOverflow then
+ local leftIconX = leftRealXPositions[leftIcon.UID]
+ local leftIconWidth = Overflow.getWidth(leftIcon)
+ leftBoundary = math.max(leftBoundary, leftIconX + leftIconWidth + BOUNDARY_GAP)
+ end
+ end
+ end
+
+ if #rightOrderedIcons > 0 then
+ local rightRealXPositions = Overflow.getRealXPositions("Right", rightOrderedIcons)
+ for _, rightIcon in pairs(rightOrderedIcons) do
+ if not rightIcon.hasRelocatedInOverflow then
+ local rightIconX = rightRealXPositions[rightIcon.UID]
+ rightBoundary = math.min(rightBoundary, rightIconX - BOUNDARY_GAP)
+ end
+ end
+ end
+
+ -- Safety margin to prevent oscillation
+ local SAFETY_MARGIN = BOUNDARY_GAP * 2.5
+ local availableCenterWidth = rightBoundary - leftBoundary - SAFETY_MARGIN
+
+ if availableCenterWidth > 0 and totalCenterWidth <= availableCenterWidth then
+ icon:align("Center")
+ icon.hasRelocatedInOverflow = nil
+
+ Overflow.updateAvailableIcons("Center")
+ Overflow.updateAvailableIcons(alignment)
+
+ task.spawn(function()
+ task.wait(0.2)
+ Overflow.updateBoundary("Left")
+ Overflow.updateBoundary("Right")
+ end)
+
+ break
+ end
+ end
+ end
+ end
+ end
end
diff --git a/src/Types.lua b/src/Types.lua
index 922488c..a2adc62 100644
--- a/src/Types.lua
+++ b/src/Types.lua
@@ -279,6 +279,23 @@ type Methods = {
return nil :: any
end
),
+ bindSignal: typeof(
+ --[[
+ Connects an RBXScriptSignal (such as Touched or Changed) to the icon.
+ callback is called with arguments (self, ...) when the signal fires.
+ ]]
+ function(self: Icon, signal: RBXScriptSignal, callback: (...any) -> ()): Icon
+ return nil :: any
+ end
+ ),
+ unbindSignal: typeof(
+ --[[
+ Disconnects a signal previously bound with :bindSignal().
+ ]]
+ function(self: Icon, signal: RBXScriptSignal): Icon
+ return nil :: any
+ end
+ ),
bindToggleKey: typeof(
--[[
Binds a keycode which toggles the icon when pressed.
diff --git a/src/init.lua b/src/init.lua
index 55b5dd8..c4e0945 100644
--- a/src/init.lua
+++ b/src/init.lua
@@ -252,6 +252,7 @@ function Icon.new()
self.dropdownIcons = {}
self.childIconsDict = {}
self.creationTime = os.clock()
+ self.bindedSignalEvents = {}
-- Widget is the new name for an icon
local widget = janitor:add(require(elements.Widget)(self, Icon))
@@ -924,6 +925,27 @@ function Icon:unbindEvent(iconEventName)
return self
end
+function Icon:bindSignal(signal, signalFunction)
+ assert(typeof(signal) == "RBXScriptSignal", "argument[1] must be a valid RBXScriptSignal!")
+ assert(typeof(signalFunction) == "function", "argument[2] must be a function!")
+
+ local connection = signal:Connect(function(...)
+ signalFunction(self, ...)
+ end)
+ self.bindSignalEvents[signal] = connection
+ return self
+end
+
+function Icon:unbindSignal(signal)
+ local connection = self.bindSignalEvents[signal]
+ if connection then
+ connection:Disconnect()
+ self.bindSignalEvents[signal] = nil
+ end
+
+ return self
+end
+
function Icon:bindToggleKey(keyCodeEnum)
assert(typeof(keyCodeEnum) == "EnumItem", "argument[1] must be a KeyCode EnumItem!")
self.bindedToggleKeys[keyCodeEnum] = true