Building on the GraphicsPort::copy() method reported last time, I’ve added a new GraphicsPort::scroll() method. This takes in x and y co-ordinates as the location of the region to scroll, in addition to the width and height of the region to be scrolled. This information represents a rectangle that will be shifted through a specified distance both vertically and horizontally, which are also parameters to the function.
The method uses the copy() method to do the actual pixel moving, but does some crazy clipping calculations in order to limit the region being copied to within the bounds of the visible regions of the relevant gadget. To be specific, it uses the copy() routine where possible, but there are a number of situations where no data is actually available to copy (ie. destination falls outside the bounds of the clipping region). To cater for this, the function expects to be passed a pointer to an empty WoopsiArray of rects. Where the copy cannot be performed, a rect representing the region to be refreshed is appended to the array. These can be redrawn (using a loop around the draw(Rect) method) once the scroll function exits.
In addition to this, the function adds all revealed regions to the array too. So, if you scroll a gadget horizontally by 10 pixels, the array will contain a rect 10 pixels wide representing the newly-visible area that needs to be redrawn.
The scroll() method rendered much of the code in the ScrollingPanel redundant. In fact, it reduced it from ~500 lines of code down to ~200, and removed another set of functions that dealt directly with the framebuffer and recalculated visible regions. Unfortunately, it doesn’t appear to have made any noticable difference to the speed of the ScrollingPanel’s dragging function - it’s still flickery. The only way around that would appear to be double-buffering the display, which is counter-productive given the way I’m using the DMA hardware to copy pixels around.