You don’t have to iterate through all the frames every time the canvas position changes. You can calculate exactly which frames are going to be visible just from knowing the canvas position and size and such.
Imagine that the frames are in a grid like this:
So the upper left frame has coordinate (0, 0), the one to the right of that (1, 0), and the bottom right in the image has coordinate (2, 3). The Y coordinate just keeps going as you go down in the list.
Now imagine that we number the frames from 1 to 1000, starting with frame (0, 0), then frame (1, 0), (2, 0), (0, 1), (1, 1), etc. I.e. just like reading, one row at a time and going to the next row when you reach the right side. You can convert between frame index and frame coordinate like this:
local frame_x = frame_index % list_width
local frame_y = math.floor( frame_index / list_width )
Trying this for frame_index = 1..7
I get
0 0 1 1
1 0 2 2
2 0 3 3
0 1 4 4
1 1 5 5
2 1 6 6
0 2 7 7
… which seems right. You can convert the other way like so:
frame_index = 1 + frame_x + frame_y * list_width
In other words, if you know the number of a frame in the list, you also know it’s Y coordinate in the “frame grid”. You can convert that to its Y pixel coordinate in the scrolling frame, something like this:
local pixel_y = frame_y * frame_height
… and convert the other way like this:
local frame_y = pixel_y / frame_height
So if you know the Y coordinates of the top of the scrolling frame and the bottom of the scrolling frame, then you can convert that to a list of frames in the list that are currently visible:
local visible_frames = {} --a global in the script
--- ... later in the script...
function update_visible_frames()
local frame_y_top = list_canvas_top / frame_height
local frame_y_bottom = list_canvas_bottom / frame_height
local newly_visible_frames = {}
for y = frame_y_top, frame_y_bottom do
local done_iterating = false
for x = 0, 2 do
local frame = frame_array[1 + x + y * list_width]
if frame then
table.insert(visible_frames, frame)
else
--We reached the end of the frame_array, and since we're iterating in order, no frames could possibly come after this one, so we don't need to keep iterating
done_iterating = true
break
end
if done_iterating then
break
end
end
end
You can then toggle only the necessary frames like so:
--Turn on newly visible frames
for _, newly_visible_frame in pairs(newly_visible_frames) do
if not table.find(previously_visible_frames, newly_visible_frame) then
newly_visible_frame.Visible = true
end
end
--Turn on newly invisible frames
for _, previously_visible_frame in pairs(visible_frames) do
if not table.find(newly_visible_frames, previously_visible_frame) then
previously_visible_frame.Visible = false
end
end
… and don’t for get to update the list of visible frames for the next time we update:
visible_frames = newly_visible_frames
end
I hope this helps! I’ve left finding the top and bottom of the canvas up to you, let me know if you need help with that or if anything is unclear Also… I haven’t tested this with real GUIs, so let me know if something doesn’t work because my thinking may be a bit flawed
In the end though, this solution should make it so you only have to iterate over the 24 or so frames that could possible have changed visibility.