1
0

mobile support

This commit is contained in:
tul
2026-08-04 15:14:58 +00:00
parent cabe2298b1
commit b7867dff0b
+141 -132
View File
@@ -80,7 +80,7 @@
labels = {}, labels = {},
label_gradients = {}, label_gradients = {},
is_mobile = uis.TouchEnabled and not uis.KeyboardEnabled, is_mobile = uis.TouchEnabled,
colorpicker_open = false; colorpicker_open = false;
gui; gui;
@@ -279,57 +279,78 @@
end end
end end
-- one pointer-drag helper behind the window, the resize grip and every label.
-- a touch is tracked by its input object rather than its type, so a second finger
-- (moving, shooting, another panel) can never hijack a drag that is already running.
function library:pointer_drag(trigger, on_begin, on_move, on_end)
local dragging = false
local touch_input -- the finger driving this drag, nil while on mouse
local function drives(input, mouse_type)
if touch_input then return input == touch_input end
return input.UserInputType == mouse_type
end
trigger.InputBegan:Connect(function(input)
local kind = input.UserInputType
if kind ~= Enum.UserInputType.MouseButton1 and kind ~= Enum.UserInputType.Touch then return end
if dragging then return end
dragging = true
touch_input = (kind == Enum.UserInputType.Touch) and input or nil
on_begin(input)
end)
library:connection(uis.InputChanged, function(input)
if not dragging then return end
if not drives(input, Enum.UserInputType.MouseMovement) then return end
on_move(input)
end)
-- released anywhere, not just over the trigger, or a drag can get stuck on
library:connection(uis.InputEnded, function(input)
if not dragging then return end
if not drives(input, Enum.UserInputType.MouseButton1) then return end
dragging = false
touch_input = nil
if on_end then on_end(input) end
end)
end
function library:resizify(frame) function library:resizify(frame)
-- a 10px corner is unhittable with a finger
local grip = library.is_mobile and 24 or 10
local Frame = Instance.new("TextButton") local Frame = Instance.new("TextButton")
Frame.Position = dim2(1, -10, 1, -10) Frame.Position = dim2(1, -grip, 1, -grip)
Frame.BorderColor3 = rgb(0, 0, 0) Frame.BorderColor3 = rgb(0, 0, 0)
Frame.Size = dim2(0, 10, 0, 10) Frame.Size = dim2(0, grip, 0, grip)
Frame.BorderSizePixel = 0 Frame.BorderSizePixel = 0
Frame.BackgroundColor3 = rgb(255, 255, 255) Frame.BackgroundColor3 = rgb(255, 255, 255)
Frame.Parent = frame Frame.Parent = frame
Frame.BackgroundTransparency = 1 Frame.BackgroundTransparency = 1
Frame.Text = "" Frame.Text = ""
Frame.AutoButtonColor = false
Frame.Active = true
local resizing = false
local start_size local start_size
local start local start
local og_size = frame.Size local og_size = frame.Size
Frame.InputBegan:Connect(function(input) library:pointer_drag(Frame, function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 then
resizing = true
start = input.Position start = input.Position
start_size = frame.Size start_size = frame.Size
end end, function(input)
end) local delta = input.Position - start
Frame.InputEnded:Connect(function(input) frame.Size = dim2(
if input.UserInputType == Enum.UserInputType.MouseButton1 then
resizing = false
end
end)
library:connection(uis.InputChanged, function(input, game_event)
if resizing and input.UserInputType == Enum.UserInputType.MouseMovement then
local viewport_x = camera.ViewportSize.X
local viewport_y = camera.ViewportSize.Y
local current_size = dim2(
start_size.X.Scale, start_size.X.Scale,
math.clamp( clamp(start_size.X.Offset + delta.X, og_size.X.Offset, camera.ViewportSize.X),
start_size.X.Offset + (input.Position.X - start.X),
og_size.X.Offset,
viewport_x
),
start_size.Y.Scale, start_size.Y.Scale,
math.clamp( clamp(start_size.Y.Offset + delta.Y, og_size.Y.Offset, camera.ViewportSize.Y)
start_size.Y.Offset + (input.Position.Y - start.Y),
og_size.Y.Offset,
viewport_y
) )
)
frame.Size = current_size
end
end) end)
end end
@@ -340,6 +361,16 @@
return (y_cond and x_cond) return (y_cond and x_cond)
end end
-- point is optional, so mouse callers keep the old behaviour and touch can pass a finger
function library:point_in_frame(uiobject, point)
if not point then return library:mouse_in_frame(uiobject) end
local pos, size = uiobject.AbsolutePosition, uiobject.AbsoluteSize
return point.X >= pos.X and point.X <= pos.X + size.X
and point.Y >= pos.Y and point.Y <= pos.Y + size.Y
end
library.lerp = function(start, finish, t) library.lerp = function(start, finish, t)
t = t or 1 / 8 t = t or 1 / 8
@@ -347,49 +378,25 @@
end end
function library:draggify(frame) function library:draggify(frame)
local dragging = false
local start_size = frame.Position local start_size = frame.Position
local start local start
frame.InputBegan:Connect(function(input) -- without this a touch falls straight through to the camera controls and the
if input.UserInputType == Enum.UserInputType.MouseButton1 -- frame never sees the drag, which is why mobile could not move anything
or input.UserInputType == Enum.UserInputType.Touch then frame.Active = true
dragging = true
library:pointer_drag(frame, function(input)
start = input.Position start = input.Position
start_size = frame.Position start_size = frame.Position
end end, function(input)
end) local delta = input.Position - start
-- measured size, so AutomaticSize frames clamp against their real width
local size = frame.AbsoluteSize
frame.InputEnded:Connect(function(input) frame.Position = dim2(
if input.UserInputType == Enum.UserInputType.MouseButton1 0, clamp(start_size.X.Offset + delta.X, 0, camera.ViewportSize.X - size.X),
or input.UserInputType == Enum.UserInputType.Touch then 0, clamp(start_size.Y.Offset + delta.Y, 0, camera.ViewportSize.Y - size.Y)
dragging = false
end
end)
library:connection(uis.InputChanged, function(input, game_event)
if dragging and (input.UserInputType == Enum.UserInputType.MouseMovement
or input.UserInputType == Enum.UserInputType.Touch) then
local viewport_x = camera.ViewportSize.X
local viewport_y = camera.ViewportSize.Y
local current_position = dim2(
0,
clamp(
start_size.X.Offset + (input.Position.X - start.X),
0,
viewport_x - frame.Size.X.Offset
),
0,
math.clamp(
start_size.Y.Offset + (input.Position.Y - start.Y),
0,
viewport_y - frame.Size.Y.Offset
) )
)
frame.Position = current_position
end
end) end)
end end
@@ -1019,6 +1026,7 @@
Text = ""; Text = "";
AutoButtonColor = false; AutoButtonColor = false;
BorderSizePixel = 0; BorderSizePixel = 0;
Active = true;
ZIndex = 5 ZIndex = 5
}); });
-- --
@@ -1053,24 +1061,16 @@
state.callback = value state.callback = value
end end
-- drag, with a tap fallback -- a touch that barely moves is a click, not a drag -- drag, with a tap fallback -- a pointer that barely moves is a click, not a drag.
local dragging, drag_start, drag_origin, travelled = false, nil, nil, 0 -- fingers wobble far more than a mouse, so touch gets a looser threshold
local drag_start, drag_origin, travelled = nil, nil, 0
local tap_slop = library.is_mobile and 12 or 6
hitbox.InputBegan:Connect(function(input) library:pointer_drag(hitbox, function(input)
if input.UserInputType ~= Enum.UserInputType.MouseButton1
and input.UserInputType ~= Enum.UserInputType.Touch then return end
dragging = true
travelled = 0 travelled = 0
drag_start = input.Position drag_start = input.Position
drag_origin = outline.Position drag_origin = outline.Position
end) end, function(input)
library:connection(uis.InputChanged, function(input)
if not dragging then return end
if input.UserInputType ~= Enum.UserInputType.MouseMovement
and input.UserInputType ~= Enum.UserInputType.Touch then return end
local delta = input.Position - drag_start local delta = input.Position - drag_start
travelled = max(travelled, abs(delta.X) + abs(delta.Y)) travelled = max(travelled, abs(delta.X) + abs(delta.Y))
@@ -1079,16 +1079,8 @@
clamp(drag_origin.X.Offset + delta.X, 0, camera.ViewportSize.X - outline.AbsoluteSize.X), clamp(drag_origin.X.Offset + delta.X, 0, camera.ViewportSize.X - outline.AbsoluteSize.X),
clamp(drag_origin.Y.Offset + delta.Y, 0, camera.ViewportSize.Y - outline.AbsoluteSize.Y) clamp(drag_origin.Y.Offset + delta.Y, 0, camera.ViewportSize.Y - outline.AbsoluteSize.Y)
)) ))
end) end, function()
if travelled <= tap_slop and state.callback then
library:connection(uis.InputEnded, function(input)
if not dragging then return end
if input.UserInputType ~= Enum.UserInputType.MouseButton1
and input.UserInputType ~= Enum.UserInputType.Touch then return end
dragging = false
if travelled <= 6 and state.callback then
state.callback(proxy) state.callback(proxy)
end end
end) end)
@@ -1674,23 +1666,18 @@
-- --
-- Connections -- Connections
outline.MouseButton1Down:Connect(function() local function slide_to(input)
cfg.dragging = true
end)
library:connection(uis.InputChanged, function(input)
if cfg.dragging and input.UserInputType == Enum.UserInputType.MouseMovement then
local size_x = (input.Position.X - inline.AbsolutePosition.X) / inline.AbsoluteSize.X local size_x = (input.Position.X - inline.AbsolutePosition.X) / inline.AbsoluteSize.X
local value = ((cfg.max - cfg.min) * size_x) + cfg.min
cfg.set(value) cfg.set(((cfg.max - cfg.min) * size_x) + cfg.min)
end end
end)
library:connection(uis.InputEnded, function(input) -- setting on press as well as on move, since a tap has nowhere to move to
if input.UserInputType == Enum.UserInputType.MouseButton1 then library:pointer_drag(outline, function(input)
cfg.dragging = true
slide_to(input)
end, slide_to, function()
cfg.dragging = false cfg.dragging = false
end
end) end)
-- --
@@ -1929,13 +1916,17 @@
cfg.set_visible(cfg.open) cfg.set_visible(cfg.open)
end) end)
uis.InputEnded:Connect(function(input) library:connection(uis.InputEnded, function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 then local kind = input.UserInputType
if not (library:mouse_in_frame(accent) or library:mouse_in_frame(dropdown)) then if kind ~= Enum.UserInputType.MouseButton1 and kind ~= Enum.UserInputType.Touch then return end
local at = (kind == Enum.UserInputType.Touch)
and vec2(input.Position.X, input.Position.Y) or nil
if not (library:point_in_frame(accent, at) or library:point_in_frame(dropdown, at)) then
cfg.open = false cfg.open = false
cfg.set_visible(false) cfg.set_visible(false)
end end
end
end) end)
-- --
@@ -2273,9 +2264,15 @@
cfg.callback(Color, a) cfg.callback(Color, a)
end end
function cfg.update_color() -- position is only supplied for touch, where there is no mouse to query.
-- it arrives already in AbsolutePosition space, same as the slider uses
function cfg.update_color(position)
local offset = position
if not offset then
local mouse = uis:GetMouseLocation() local mouse = uis:GetMouseLocation()
local offset = vec2(mouse.X, mouse.Y - gui_offset) offset = vec2(mouse.X, mouse.Y - gui_offset)
end
if dragging_sat then if dragging_sat then
s = math.clamp((offset - saturation_value_button.AbsolutePosition).X / saturation_value_button.AbsoluteSize.X, 0, 1) s = math.clamp((offset - saturation_value_button.AbsolutePosition).X / saturation_value_button.AbsoluteSize.X, 0, 1)
@@ -2301,36 +2298,43 @@
cfg.set_visible(cfg.open) cfg.set_visible(cfg.open)
end) end)
uis.InputChanged:Connect(function(input) -- mouse keeps querying GetMouseLocation, a finger has to report itself
if (dragging_sat or dragging_hue or dragging_alpha) and input.UserInputType == Enum.UserInputType.MouseMovement then local function pointer_at(input)
cfg.update_color() if input.UserInputType == Enum.UserInputType.Touch then
return vec2(input.Position.X, input.Position.Y)
end end
return nil
end
local function handle(button, set_dragging)
library:pointer_drag(button, function(input)
set_dragging(true)
cfg.update_color(pointer_at(input))
end, function(input)
cfg.update_color(pointer_at(input))
end, function()
set_dragging(false)
end) end)
end
handle(saturation_button, function(v) dragging_sat = v end)
handle(hue_button, function(v) dragging_hue = v end)
handle(alpha_button, function(v) dragging_alpha = v end)
library:connection(uis.InputEnded, function(input) library:connection(uis.InputEnded, function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 then local kind = input.UserInputType
if kind ~= Enum.UserInputType.MouseButton1 and kind ~= Enum.UserInputType.Touch then return end
dragging_sat = false dragging_sat = false
dragging_hue = false dragging_hue = false
dragging_alpha = false dragging_alpha = false
if not (library:mouse_in_frame(colorpicker_element) or library:mouse_in_frame(colorpicker)) then local at = pointer_at(input)
if not (library:point_in_frame(colorpicker_element, at) or library:point_in_frame(colorpicker, at)) then
cfg.open = false cfg.open = false
cfg.set_visible(false) cfg.set_visible(false)
end end
end
end)
alpha_button.MouseButton1Down:Connect(function()
dragging_alpha = true
end)
hue_button.MouseButton1Down:Connect(function()
dragging_hue = true
end)
saturation_button.MouseButton1Down:Connect(function()
print("hiu")
dragging_sat = true
end) end)
textbox.FocusLost:Connect(function() textbox.FocusLost:Connect(function()
@@ -2706,8 +2710,13 @@
end end
end end
if input.UserInputType == Enum.UserInputType.MouseButton1 then local kind = input.UserInputType
if not (library:mouse_in_frame(keybind_holder) or library:mouse_in_frame(accent)) then
if kind == Enum.UserInputType.MouseButton1 or kind == Enum.UserInputType.Touch then
local at = (kind == Enum.UserInputType.Touch)
and vec2(input.Position.X, input.Position.Y) or nil
if not (library:point_in_frame(keybind_holder, at) or library:point_in_frame(accent, at)) then
cfg.open = false cfg.open = false
cfg.set_visible(false) cfg.set_visible(false)
end end