Skip to content

Commit

Permalink
Changed GuiInset behaviour
Browse files Browse the repository at this point in the history
There exists a mismatch between the coordinate system of the mouse position and that used in the AbsolutePosition and the root frame position. Initially, this was only an issue for the topbar inset but this is also an issue when the root frame is not positioned at the (0, 0) coordinate position for either mouse or AbsolutePosition coordinate systems.

To fix this, two offsets are used, one for the mouse and one for the absolute position:
- MouseOffset - which is used to only modify the mouse position
- GuiOffset - which is used to modify every AbsolutePosition

Outside of a play session, where there is not a topbar, both should be the same and be the absolute position of the root frame position. This is necessary for stories or plugins where the root Iris frame does not cover the entire screen.

In a regular play session where the topbar exists, they will be different depending on the IgnoreGuiInset property:
- false - GuiOffset is (0, 0) and MouseOffset is (0, -58) because the AbsolutePosition and Root frame are the same but the mouse position is offset by the topbar.
- true - GuiOffset is (0, -58) and MouseOffset is (0, 0) because the Root frame and mouse position have the same coordinates but the AbsolutePosition is offset by the topbar.
  • Loading branch information
SirMallard committed Aug 6, 2024
1 parent f0a9df2 commit 4b1acfe
Show file tree
Hide file tree
Showing 7 changed files with 54 additions and 46 deletions.
5 changes: 2 additions & 3 deletions lib/Types.lua
Original file line number Diff line number Diff line change
Expand Up @@ -471,9 +471,8 @@ export type WidgetUtility = {
UNKNOWN_TEXTURE: string,
},

GuiInset: Vector2?,
setGuiInset: () -> Vector2,
getGuiInset: () -> Vector2,
GuiOffset: Vector2,
MouseOffset: Vector2,

findBestWindowPosForPopup: (refPos: Vector2, size: Vector2, outerMin: Vector2, outerMax: Vector2) -> Vector2,
getScreenSizeForWindow: (thisWidget: Widget) -> Vector2,
Expand Down
7 changes: 6 additions & 1 deletion lib/demoWindow.lua
Original file line number Diff line number Diff line change
Expand Up @@ -634,8 +634,14 @@ return function(Iris: Types.Iris)
do
Iris.CollapsingHeader({ "Widgets" })
do
Iris.SeparatorText({ "GuiService" })
Iris.Text({ `GuiOffset: {Iris.Internal._utility.GuiOffset}` })
Iris.Text({ `MouseOffset: {Iris.Internal._utility.MouseOffset}` })

Iris.SeparatorText({ "UserInputService" })
Iris.Text({ `MousePosition: {Iris.Internal._utility.UserInputService:GetMouseLocation()}` })
Iris.Text({ `MouseLocation: {Iris.Internal._utility.getMouseLocation()}` })

Iris.Text({ `Left Control: {Iris.Internal._utility.UserInputService:IsKeyDown(Enum.KeyCode.LeftControl)}` })
Iris.Text({ `Right Control: {Iris.Internal._utility.UserInputService:IsKeyDown(Enum.KeyCode.RightControl)}` })
end
Expand Down Expand Up @@ -778,7 +784,6 @@ return function(Iris: Types.Iris)

Iris.SeparatorText({ "Config" })
BooleanInput({ "UseScreenGUIs" })
BooleanInput({ "IgnoreGuiInset" })
SliderInput("DragNum", { "DisplayOrderOffset", 1, 0 })
SliderInput("DragNum", { "ZIndexOffset", 1, 0 })
SliderInput("SliderNum", { "MouseDoubleClickTime", 0.1, 0, 5 })
Expand Down
2 changes: 1 addition & 1 deletion lib/widgets/Input.lua
Original file line number Diff line number Diff line change
Expand Up @@ -873,7 +873,7 @@ return function(Iris: Types.Internal, widgets: Types.WidgetUtility)
local max: number = ActiveSlider.arguments.Max and getValueByIndex(ActiveSlider.arguments.Max, ActiveIndex, ActiveSlider.arguments) or defaultMax[ActiveDataType][ActiveIndex]

local GrabWidth: number = GrabBar.AbsoluteSize.X
local Offset: number = widgets.getMouseLocation().X - (SliderField.AbsolutePosition.X + GrabWidth / 2)
local Offset: number = widgets.getMouseLocation().X - (SliderField.AbsolutePosition.X - widgets.GuiOffset.X + GrabWidth / 2)
local Ratio: number = Offset / (SliderField.AbsoluteSize.X - GrabWidth)
local Positions: number = math.floor((max - min) / increment)
local newValue: number = math.clamp(math.round(Ratio * Positions) * increment + min, min, max)
Expand Down
8 changes: 4 additions & 4 deletions lib/widgets/Menu.lua
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ return function(Iris: Types.Internal, widgets: Types.WidgetUtility)
local MouseLocation: Vector2 = widgets.getMouseLocation()
for _, menu: Types.Widget in MenuStack do
for _, container: GuiObject in { menu.ChildContainer, menu.Instance } do
local rectMin: Vector2 = container.AbsolutePosition
local rectMin: Vector2 = container.AbsolutePosition - widgets.GuiOffset
local rectMax: Vector2 = rectMin + container.AbsoluteSize
if widgets.isPosInsideRect(MouseLocation, rectMin, rectMax) then
isInMenu = true
Expand Down Expand Up @@ -256,9 +256,9 @@ return function(Iris: Types.Internal, widgets: Types.WidgetUtility)
end)

local ChildContainer: ScrollingFrame = Instance.new("ScrollingFrame")
ChildContainer.Name = "ChildContainer"
ChildContainer.BackgroundColor3 = Iris._config.WindowBgColor
ChildContainer.BackgroundTransparency = Iris._config.WindowBgTransparency
ChildContainer.Name = "MenuContainer"
ChildContainer.BackgroundColor3 = Iris._config.PopupBgColor
ChildContainer.BackgroundTransparency = Iris._config.PopupBgTransparency
ChildContainer.BorderSizePixel = 0
ChildContainer.Size = UDim2.fromOffset(0, 0)
ChildContainer.AutomaticSize = Enum.AutomaticSize.XY
Expand Down
2 changes: 1 addition & 1 deletion lib/widgets/Window.lua
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ return function(Iris: Types.Internal, widgets: Types.WidgetUtility)
local position: Vector2 = widgets.getMouseLocation()
for _, window in windowWidgets do
local ResizeBorder: TextButton = window.Instance and window.Instance.WindowButton.ResizeBorder
if ResizeBorder and widgets.isPosInsideRect(position, ResizeBorder.AbsolutePosition, ResizeBorder.AbsolutePosition + ResizeBorder.AbsoluteSize) then
if ResizeBorder and widgets.isPosInsideRect(position, ResizeBorder.AbsolutePosition - widgets.GuiOffset, ResizeBorder.AbsolutePosition - widgets.GuiOffset + ResizeBorder.AbsoluteSize) then
inWindow = true
break
end
Expand Down
67 changes: 32 additions & 35 deletions lib/widgets/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -29,23 +29,26 @@ return function(Iris: Types.Internal)
end
end

function widgets.setGuiInset()
local inset = widgets.GuiService:GetGuiInset()
-- acts as an offset where the absolute position of the base frame is not zero, such as IgnoreGuiInset or for stories
widgets.GuiOffset = Vector2.zero
-- the registered mouse position always ignores the topbar, so needs a separate variable offset
widgets.MouseOffset = if Iris._config.IgnoreGuiInset then Vector2.zero else widgets.GuiService:GetGuiInset()

-- the topbar inset changes updates a frame later.
local connection: RBXScriptConnection = widgets.GuiService:GetPropertyChangedSignal("TopbarInset"):Once(function()
widgets.MouseOffset = if Iris._config.IgnoreGuiInset then Vector2.zero else widgets.GuiService:GetGuiInset()
end)
-- in case the topbar doesn't change, we cancel the event.
task.delay(3, function()
connection:Disconnect()
end)

-- Inset is not guaranteed to be set upon initialization.
if inset.Magnitude > 0 then
widgets.GuiInset = inset
end

return inset
end

function widgets.getGuiInset()
return widgets.GuiInset or widgets.setGuiInset()
function widgets.getMouseLocation(): Vector2
return widgets.UserInputService:GetMouseLocation() - widgets.MouseOffset
end

function widgets.getMouseLocation(): Vector2
return widgets.UserInputService:GetMouseLocation() - widgets.getGuiInset()
function widgets.isPosInsideRect(pos: Vector2, rectMin: Vector2, rectMax: Vector2): boolean
return pos.X > rectMin.X and pos.X < rectMax.X and pos.Y > rectMin.Y and pos.Y < rectMax.Y
end

function widgets.findBestWindowPosForPopup(refPos: Vector2, size: Vector2, outerMin: Vector2, outerMax: Vector2): Vector2
Expand All @@ -68,8 +71,21 @@ return function(Iris: Types.Internal)
return clampedPos
end

function widgets.isPosInsideRect(pos: Vector2, rectMin: Vector2, rectMax: Vector2): boolean
return pos.X > rectMin.X and pos.X < rectMax.X and pos.Y > rectMin.Y and pos.Y < rectMax.Y
function widgets.getScreenSizeForWindow(thisWidget: Types.Widget): Vector2 -- possible parents are GuiBase2d, CoreGui, PlayerGui
if thisWidget.Instance:IsA("GuiBase2d") then
return thisWidget.Instance.AbsoluteSize
else
local rootParent = thisWidget.Instance.Parent
if rootParent:IsA("GuiBase2d") then
return rootParent.AbsoluteSize
else
if rootParent.Parent:IsA("GuiBase2d") then
return rootParent.AbsoluteSize
else
return workspace.CurrentCamera.ViewportSize
end
end
end
end

function widgets.extend(superClass: Types.WidgetClass, subClass: Types.WidgetClass): Types.WidgetClass
Expand Down Expand Up @@ -134,25 +150,6 @@ return function(Iris: Types.Internal)
return ObjectValue
end

function widgets.getScreenSizeForWindow(thisWidget: Types.Widget): Vector2 -- possible parents are GuiBase2d, CoreGui, PlayerGui
local size: Vector2
if thisWidget.Instance:IsA("GuiBase2d") then
size = thisWidget.Instance.AbsoluteSize
else
local rootParent = thisWidget.Instance.Parent
if rootParent:IsA("GuiBase2d") then
size = rootParent.AbsoluteSize
else
if rootParent.Parent:IsA("GuiBase2d") then
size = rootParent.AbsoluteSize
else
size = workspace.CurrentCamera.ViewportSize
end
end
end
return size
end

-- below uses Iris

local textParams: GetTextBoundsParams = Instance.new("GetTextBoundsParams")
Expand Down
9 changes: 8 additions & 1 deletion stories/exampleStory.story.lua
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Types = require(ReplicatedStorage.Iris.Types)

return function(parent: GuiObject)
local Iris = require(ReplicatedStorage.Iris)
local Iris: Types.Iris = require(ReplicatedStorage.Iris)
local Input = require(script.Parent.UserInputService)

Input.SinkFrame.Parent = parent
Expand All @@ -10,6 +11,12 @@ return function(parent: GuiObject)
Iris.UpdateGlobalConfig({
UseScreenGUIs = false,
})
Iris.Internal._utility.GuiOffset = Input.SinkFrame.AbsolutePosition
Iris.Internal._utility.MouseOffset = Input.SinkFrame.AbsolutePosition
Input.SinkFrame:GetPropertyChangedSignal("AbsolutePosition"):Connect(function()
Iris.Internal._utility.GuiOffset = Input.SinkFrame.AbsolutePosition
Iris.Internal._utility.MouseOffset = Input.SinkFrame.AbsolutePosition
end)

Iris.Init(parent)

Expand Down

0 comments on commit 4b1acfe

Please sign in to comment.