mirror of
https://github.com/copyrighttxt/watrbx-game-engine.git
synced 2026-09-05 13:17:49 +00:00
241 lines
6.9 KiB
Lua
241 lines
6.9 KiB
Lua
--[[
|
|
]]
|
|
local CoreGui = Game:GetService("CoreGui")
|
|
local GuiRoot = CoreGui:FindFirstChild("RobloxGui")
|
|
local Modules = GuiRoot:FindFirstChild("Modules")
|
|
local GuiService = game:GetService("GuiService")
|
|
local UserInputService = game:GetService("UserInputService")
|
|
|
|
local ThumbnailLoader = require(Modules:FindFirstChild('ThumbnailLoader'))
|
|
local Utility = require(Modules:FindFirstChild('Utility'))
|
|
|
|
local function CreateImageSlider(size, position)
|
|
local this = {}
|
|
|
|
local items = {}
|
|
local maxItems = 0
|
|
local currentItemIndex = 1
|
|
local padding = 0
|
|
local focusSize = 450
|
|
local itemSize = 300
|
|
local dataTable = nil
|
|
|
|
local lastSelectedObject = nil
|
|
local newSelectedObjectCn = nil
|
|
this.OnNewFocusItem = Utility.Signal()
|
|
|
|
local imageObjectToLoaderMap = {}
|
|
|
|
this.Container = Utility.Create'ScrollingFrame'
|
|
{
|
|
Name = "ImageSliderContainer";
|
|
Size = size;
|
|
Position = position;
|
|
BackgroundTransparency = 1;
|
|
ClipsDescendants = false;
|
|
ScrollingEnabled = false;
|
|
Selectable = false;
|
|
ScrollBarThickness = 0;
|
|
}
|
|
|
|
local function loadNewImage(item, dataIndex)
|
|
if imageObjectToLoaderMap[item] then
|
|
imageObjectToLoaderMap[item]:Cancel()
|
|
imageObjectToLoaderMap[item] = nil
|
|
end
|
|
local iconId = dataTable[dataIndex].IconId
|
|
local thumbLoader = ThumbnailLoader:Create(item, iconId,
|
|
ThumbnailLoader.Sizes.Medium, ThumbnailLoader.AssetType.Icon)
|
|
imageObjectToLoaderMap[item] = thumbLoader
|
|
spawn(function()
|
|
thumbLoader:LoadAsync()
|
|
imageObjectToLoaderMap[item] = nil
|
|
end)
|
|
end
|
|
|
|
local MAX_LEFT = 2
|
|
local MAX_RIGHT = 6
|
|
-- TODO: Figure out left/right better
|
|
local function recalcPositionAndSize(tweenTime, isRight, newSelectedObject)
|
|
local smIconYPos = (focusSize - itemSize) / 2
|
|
local startPosition = 0
|
|
if currentItemIndex == 1 then
|
|
startPosition = 0
|
|
elseif currentItemIndex == 2 then
|
|
startPosition = -1
|
|
elseif maxItems == #items then
|
|
startPosition = 1 - currentItemIndex
|
|
elseif maxItems - currentItemIndex < MAX_RIGHT then
|
|
startPosition = maxItems - currentItemIndex - MAX_RIGHT - MAX_LEFT
|
|
else
|
|
startPosition = -MAX_LEFT
|
|
end
|
|
|
|
-- put front at back
|
|
if maxItems > #items then
|
|
if isRight == true and startPosition == -MAX_LEFT and currentItemIndex > 3 then
|
|
local front = items[1]
|
|
local back = items[#items]
|
|
front.Position = UDim2.new(0, back.Position.X.Offset + back.Size.X.Offset + padding, 0, smIconYPos)
|
|
this:RemoveFromFront()
|
|
this:AddItemToBack(front)
|
|
if dataTable and dataTable[currentItemIndex + MAX_RIGHT] then
|
|
loadNewImage(front, currentItemIndex + MAX_RIGHT)
|
|
end
|
|
-- put back in front
|
|
elseif isRight == false and currentItemIndex < maxItems - MAX_RIGHT and startPosition == -MAX_LEFT then
|
|
local back = items[#items]
|
|
local front = items[1]
|
|
back.Position = UDim2.new(0, front.Position.X.Offset - padding - itemSize, 0, smIconYPos)
|
|
this:RemoveFromBack()
|
|
this:AddToFront(back)
|
|
if dataTable and dataTable[currentItemIndex - MAX_LEFT] then
|
|
loadNewImage(back, currentItemIndex - MAX_LEFT)
|
|
end
|
|
end
|
|
end
|
|
|
|
local currentXPosition = itemSize * startPosition + padding * startPosition
|
|
for i = 1, #items do
|
|
if items[i] == newSelectedObject then
|
|
if tweenTime == 0 then
|
|
items[i].Size = UDim2.new(0, focusSize, 0, focusSize)
|
|
items[i].Position = UDim2.new(0, currentXPosition, 0, 0)
|
|
else
|
|
items[i]:TweenSizeAndPosition(UDim2.new(0, focusSize, 0, focusSize), UDim2.new(0, currentXPosition, 0, 0),
|
|
Enum.EasingDirection.InOut, Enum.EasingStyle.Sine, tweenTime, true)
|
|
end
|
|
currentXPosition = currentXPosition + focusSize + padding
|
|
else
|
|
if tweenTime == 0 then
|
|
items[i].Size = UDim2.new(0, itemSize, 0, itemSize)
|
|
items[i].Position = UDim2.new(0, currentXPosition, 0, smIconYPos)
|
|
else
|
|
items[i]:TweenSizeAndPosition(UDim2.new(0, itemSize, 0, itemSize), UDim2.new(0, currentXPosition, 0, smIconYPos),
|
|
Enum.EasingDirection.InOut, Enum.EasingStyle.Sine, tweenTime, true)
|
|
end
|
|
currentXPosition = currentXPosition + itemSize + padding
|
|
end
|
|
end
|
|
end
|
|
|
|
--[[ Events ]]--
|
|
newSelectedObjectCn = GuiService.Changed:connect(function(property)
|
|
if property == 'SelectedCoreObject' then
|
|
local selectedObject = GuiService.SelectedCoreObject
|
|
if selectedObject and selectedObject ~= lastSelectedObject and selectedObject:IsDescendantOf(this.Container) then
|
|
local isRight = nil
|
|
if lastSelectedObject then
|
|
-- slide left
|
|
if lastSelectedObject.AbsolutePosition.x < selectedObject.AbsolutePosition.x then
|
|
currentItemIndex = currentItemIndex + 1
|
|
isRight = true
|
|
-- slide right
|
|
else
|
|
currentItemIndex = currentItemIndex - 1
|
|
isRight = false
|
|
end
|
|
end
|
|
recalcPositionAndSize(lastSelectedObject and 0.25 or 0, isRight, selectedObject)
|
|
lastSelectedObject = selectedObject
|
|
this.OnNewFocusItem:fire(currentItemIndex, isRight, selectedObject)
|
|
end
|
|
end
|
|
end)
|
|
|
|
--[[ Public API ]]--
|
|
function this:SetPosition(position)
|
|
self.Container.Position = position
|
|
end
|
|
|
|
function this:SetSize(size)
|
|
self.Container.Size = size
|
|
end
|
|
|
|
function this:SetParent(parent)
|
|
self.Container.Parent = parent
|
|
end
|
|
|
|
function this:SetFocusPosition(index)
|
|
if index > 0 and index < #items + 1 then
|
|
currentItemIndex = index
|
|
recalcPositionAndSize(0, nil, items[currentItemIndex])
|
|
end
|
|
end
|
|
|
|
function this:SetDataTable(tbl)
|
|
dataTable = tbl
|
|
end
|
|
|
|
function this:SetMaxItems(value)
|
|
local index = nil
|
|
-- we're near the end, so we need to update image content
|
|
if currentItemIndex > maxItems - MAX_RIGHT then
|
|
-- find the current selected index in relation to image pool
|
|
for i = 1, #items do
|
|
if lastSelectedObject and items[i] == GuiService.SelectedCoreObject then
|
|
index = i
|
|
break
|
|
end
|
|
end
|
|
-- TODO: Still might be a visual bug in some cases
|
|
if index then
|
|
-- replace images from front of pool
|
|
for i = 1, index - 3 do
|
|
if dataTable[currentItemIndex + i] then
|
|
local item = items[1]
|
|
loadNewImage(item, currentItemIndex + (maxItems - currentItemIndex) + i)
|
|
print("NEW IMAGE:", currentItemIndex, ":", maxItems, ":", i, ":", currentItemIndex + (maxItems - currentItemIndex) + i)
|
|
self:RemoveFromFront()
|
|
self:AddItemToBack(item)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
maxItems = value
|
|
recalcPositionAndSize(0)
|
|
end
|
|
|
|
function this:SetPadding(newPadding)
|
|
padding = newPadding
|
|
end
|
|
|
|
function this:AddToFront(newItem)
|
|
table.insert(items, 1, newItem)
|
|
newItem.Parent = this.Container
|
|
end
|
|
|
|
function this:AddItemToBack(newItem)
|
|
if this and this.Container then
|
|
items[#items + 1] = newItem
|
|
newItem.Parent = this.Container
|
|
end
|
|
end
|
|
|
|
function this:AddItem(newItem)
|
|
self:AddItemToBack(newItem)
|
|
end
|
|
|
|
function this:RemoveFromFront()
|
|
table.remove(items, 1)
|
|
end
|
|
|
|
function this:RemoveFromBack()
|
|
table.remove(items)
|
|
end
|
|
|
|
function this:Destroy()
|
|
if newSelectedObjectCn then
|
|
newSelectedObjectCn:disconnect()
|
|
newSelectedObjectCn = nil
|
|
end
|
|
this.Container:Destroy()
|
|
this.OnNewFocus = nil
|
|
this = nil
|
|
end
|
|
|
|
return this
|
|
end
|
|
|
|
return CreateImageSlider
|