scrolling in roScreen, roBitmap, roRegion, roCompositor

Hi Guys,
Since the default listscreen doesnot meet my needs, I have trying to create a custom scroll area using roScreen, roBitmap, roRegion AND roCompositor. I want some text to be displayed at the top part of the screen then on the middle to bottom part, I want to present the user with the available offers which can be scrolled vertically. Therefore I drew some text on the top part of the screen. Then created a bitmap, drew text on the bitmap, used region and compositor to get the bitmap to the lower part of the screen.
It is scrolling but whenever I scroll, it will erase the text that I drew on the screen then if I scroll again it will display it again, I dont know the reason, Can any of you please help.


Library "v30/bslDefender.brs"
Function Main () AS void
        
        'creating screen object
        screen=CreateObject("roScreen",true)
        screen.clear(&hff0000ff)

         ' font for the text
        fontRegistry = CreateObject("roFontRegistry")
        font =  fontRegistry.GetDefaultFont(24,false,false)    
        
        
        'writing the text to the screen
        screen.DrawText("Hi Customer",400,90, &h00FFFFFF ,font)
        screen.DrawText("Your name is : John Doe",285,145,&h00FFFFFF,font)
        screen.DrawText("__________________________________",400,180, &h00FFFFFF,font)
        screen.DrawText("Here are your choices: ",270,225, &h00FFFFFF,font)
        
        'creating compositor objects         
        compositor=CreateObject("roCompositor")
       ' compositor.SetDrawTo(screen, &hff0000ff)    
        compositor.SetDrawTo(screen,0)      
        
        'creaating bitmap and writing text to bitmap
        srollBm=CreateObject("roBitmap",{ width: 650, height: 200, AlphaEnable: false })    
            
        srollBm.DrawText("Get a Macbook pro with 4GB ram and 250gb harddrive",0,0,&h00FFFFFF,font)
        srollBm.DrawText("Get a Macbook pro with 8GB ram and 250gb harddrive",0,50,&h00FFFFFF,font)
        srollBm.DrawText("Get a Macbook pro with 12GB ram and 250gb harddrive",0,100,&h00FFFFFF,font)
        
        
        'creating region that will be used for scrolling
        region=CreateObject("roRegion", srollBm, 0, 0, srollBm.getwidth(), srollBm.getheight())'size of scroll area
        
        region.SetWrap(True)
         
        'this will create new sprite 
        view_sprite=compositor.NewSprite(370,400, region)
        
        'draw the sprites created
        compositor.drawAll()
        screen.SwapBuffers()
        
        'creating port inorder to listen to user events
        msgport = CreateObject("roMessagePort")
        screen.SetMessagePort(msgport)
        codes = bslUniversalControlEventCodes()
        
        While True
                msg=wait(0, msgport) ' wait for a button
                print "Msg: "; type(msg); " event: "; msg.GetInt()
                If type(msg)="roUniversalControlEvent" Then
                        If msg.GetInt()=codes.BUTTON_UP_PRESSED Then
                                Shift(screen, view_sprite, compositor, 0,-15) 'up 0,-15
                        Else If msg.GetInt()=codes.BUTTON_DOWN_PRESSED Then
                                Shift(screen, view_sprite, compositor, 0,+15) ' down 0,+15
                       
                        Else If msg.GetInt() = codes.BUTTON_BACK_PRESSED ' back button
                                Exit While
                        End If
                End If
        End While
End Function

'''''''''''''''''''''''''''''''''''''''''''''''''''''  
''''''''''''''''''''''''''''''''''''''''''''''''''''  
''''''''' Shift Function To shift the bitmap region 
''''''''''by the given numbers
''''''''''''''''''''''''''''''''''''''''''''''''''''  
''''''''''''''''''''''''''''''''''''''''''''''''''''  
Function Shift(screen, view_sprite, compositor, xd, yd)
                view_sprite.OffsetRegion(xd,yd,0,0)
                compositor.drawAll()
                screen.SwapBuffers()
End Function

You draw the text on the screen (in the back-buffer), then call SwapBuffers (now the text you drew is in the front-buffer; the back-buffer will have no text). Each time through your main loop you call SwapBuffers. The first call to SwapBuffers in your loop will swap the front and back buffers, so the screen buffer with no text is now in the front-buffer (the text is in the back-buffer) and the text seems to disappear. The next time you call SwapBuffers the text, which was in the back-buffer, is swapped to the front-buffer, and the text re-appears. Etc, etc, etc. One way to fix this is to re-draw the text after the initial SwapBuffers call.

“belltown” wrote:
You draw the text on the screen (in the back-buffer), then call SwapBuffers (now the text you drew is in the front-buffer; the back-buffer will have no text). Each time through your main loop you call SwapBuffers. The first call to SwapBuffers in your loop will swap the front and back buffers, so the screen buffer with no text is now in the front-buffer (the text is in the back-buffer) and the text seems to disappear. The next time you call SwapBuffers the text, which was in the back-buffer, is swapped to the front-buffer, and the text re-appears. Etc, etc, etc. One way to fix this is to re-draw the text after the initial SwapBuffers call.

Thank you for the reply. It worked that way however the background color is different between the two buffers. I mean I can again set the screen background color along with text after the initial swappBuffer(). But is it a good programming practice to set everything again.
Also, i noticed that if I use single buffer instead of double buffer, I don’t have to deal with these problems. I can set everything once then call finish(). So, what advantage does the double buffer have over single buffer.

If you use the double-buffered approach (for reasons described in RokuMarkn’s answer to your same question last week, http://forums.roku.com/viewtopic.php?f=34&t=90259), then yes, you have to take into account that you are only writing to the current back-buffer, and every time you call SwapBuffers that back-buffer becomes the next front-buffer (displayed on screen), and the new current back-buffer will contain whatever it contained before the previous call to SwapBuffers.

Rather than trying to keep track of what was written to the previous back-buffer and only displaying what has changed, you may find it easier each time through your processing loop to completely Clear the back-buffer, re-write everything, then call SwapBuffers again. For text, make sure you draw the text to a bitmap once during your initial setup then draw that bitmap to the back-buffer in each loop. The same appies to scaled images: do the scaling once to a bitmap, then write the scaled bitmap each time through the loop.

Drawing the text to bitmap and drawing the bitmap to screen when needed makes more sense. Thanks for these information. I will edit it later.
For now, I am confused in the scrolling region. If I increased the quantity of offers(here I have listed 12 offers), only the ones that fit inside the region are displayed and even if I scroll the remaining items are not displayed. I thought the remaining offers will be hidden somewhere downside and would appear once i scroll the region, but even if I scroll the same items that were displayed earlier keeps repeating.
What should I do inorder for my region to accomodate more items and display them when scrolling?


Library "v30/bslDefender.brs"
Function Main () AS void
        
        'creating screen object
        screen=CreateObject("roScreen",false)
        screen.clear(&hff0000ff)

         ' font for the text
        fontRegistry = CreateObject("roFontRegistry")
        font =  fontRegistry.GetDefaultFont(24,false,false)    
        
        
        'writing the text to the screen
        screen.DrawText("Hi Customer",400,90, &h00FFFFFF ,font)
        screen.DrawText("Your name is : John Doe",285,145,&h00FFFFFF,font)
        screen.DrawText("__________________________________",400,180, &h00FFFFFF,font)
        screen.DrawText("Here are your choices: ",270,225, &h00FFFFFF,font)
        
        'creating compositor objects         
        compositor=CreateObject("roCompositor")
       ' compositor.SetDrawTo(screen, &hff0000ff)    
        compositor.SetDrawTo(screen,0)      
        
        'creaating bitmap and writing text to bitmap
        srollBm=CreateObject("roBitmap",{ width: 650, height: 200, AlphaEnable: false })    
            
        srollBm.DrawText("1)Get a Macbook pro with 4GB ram and 250gb harddrive",0,0,&h00FFFFFF,font)
        srollBm.DrawText("2)Get a Macbook pro with 8GB ram and 260gb harddrive",0,20,&h00FFFFFF,font)
        srollBm.DrawText("3)Get a Macbook pro with 12GB ram and 270gb harddrive",0,40,&h00FFFFFF,font)
        srollBm.DrawText("4)Get a Macbook pro with 14GB ram and 280gb harddrive",0,60,&h00FFFFFF,font)
        srollBm.DrawText("5)Get a Macbook pro with 16GB ram and 290gb harddrive",0,80,&h00FFFFFF,font)
        srollBm.DrawText("6)Get a Macbook pro with 18GB ram and 300gb harddrive",0,100,&h00FFFFFF,font)
        srollBm.DrawText("7)Get a Macbook pro with 20GB ram and 310gb harddrive",0,120,&h00FFFFFF,font)
        srollBm.DrawText("8)Get a Macbook pro with 22GB ram and 320gb harddrive",0,140,&h00FFFFFF,font)
        srollBm.DrawText("9)Get a Macbook pro with 24GB ram and 330gb harddrive",0,160,&h00FFFFFF,font)
        srollBm.DrawText("10)Get a Macbook pro with 26GB ram and 340gb harddrive",0,180,&h00FFFFFF,font)
        srollBm.DrawText("11)Get a Macbook pro with 28GB ram and 350gb harddrive",0,200,&h00FFFFFF,font)
        srollBm.DrawText("12)Get a Macbook pro with 30GB ram and 360gb harddrive",0,220,&h00FFFFFF,font)
        
        
        'creating region that will be used for scrolling
        region=CreateObject("roRegion", srollBm, 0, 0, srollBm.getwidth(), srollBm.getheight())'size of scroll area
        
        region.SetWrap(True)
         
        'this will create new sprite 
        view_sprite=compositor.NewSprite(370,400, region)
        
        'draw the sprites created
        compositor.drawAll()
        screen.finish()
        
         
        
        'creating port inorder to listen to user events
        msgport = CreateObject("roMessagePort")
        screen.SetMessagePort(msgport)
        codes = bslUniversalControlEventCodes()
        
        While True
                msg=wait(0, msgport) ' wait for a button
                print "Msg: "; type(msg); " event: "; msg.GetInt()
                If type(msg)="roUniversalControlEvent" Then
                        If msg.GetInt()=codes.BUTTON_UP_PRESSED Then
                                Shift(screen, view_sprite, compositor, 0,-15) 'up 0,-15
                        Else If msg.GetInt()=codes.BUTTON_DOWN_PRESSED Then
                                Shift(screen, view_sprite, compositor, 0,+15) ' down 0,+15
                       
                        Else If msg.GetInt() = codes.BUTTON_BACK_PRESSED ' back button
                                Exit While
                        End If
                End If
        End While
End Function

'''''''''''''''''''''''''''''''''''''''''''''''''''''  
''''''''''''''''''''''''''''''''''''''''''''''''''''  
''''''''' Shift Function To shift the bitmap region 
''''''''''by the given numbers
''''''''''''''''''''''''''''''''''''''''''''''''''''  
''''''''''''''''''''''''''''''''''''''''''''''''''''  
Function Shift(screen, view_sprite, compositor, xd, yd)
                view_sprite.OffsetRegion(xd,yd,0,0)
                compositor.drawAll()
                screen.finish()
End Function

Sub Main()

   ' This is strictly for example - You really should NOT create your globals this way
   ' There is a much better way which I will not go into now, but to demonstrate how a region works
   ' this will have to do

   l_color      = &h262626FF
 
   m.Screen     = CreateObject( "roScreen", True )
   m.Compositor = CreateObject( "roCompositor" )
   Port         = CreateObject( "roMessagePort" )
   m.Screen.SetMessagePort( Port )
   m.Screen.Clear( l_color )
   m.Compositor.SetDrawTo( m.Screen, l_color )
   
   Registry     = CreateObject( "roFontRegistry" )
   FontR26      = Registry.GetDefaultFont( 26, False, False ) 
 
   l_data = [
      "1)  Get a Macbook pro with 4GB ram and 250gb harddrive",
      "2)  Get a Macbook pro with 8GB ram and 260gb harddrive",
      "3)  Get a Macbook pro with 12GB ram and 270gb harddrive",
      "4)  Get a Macbook pro with 14GB ram and 280gb harddrive",
      "5)  Get a Macbook pro with 16GB ram and 290gb harddrive",
      "6)  Get a Macbook pro with 18GB ram and 300gb harddrive",
      "7)  Get a Macbook pro with 20GB ram and 310gb harddrive",
      "8)  Get a Macbook pro with 22GB ram and 320gb harddrive",
      "9)  Get a Macbook pro with 24GB ram and 330gb harddrive",
      "10) Get a Macbook pro with 26GB ram and 340gb harddrive",
      "11) Get a Macbook pro with 28GB ram and 350gb harddrive",
      "12) Get a Macbook pro with 30GB ram and 360gb harddrive"
   ]
   
   ' Keep in mind there are only so many text strings that you can fit into a bitmap buffer, before you exceed its maximum size
   ' there is a much better way to do all of this, but for now to help you understand regions, i'll keep it simple
   
   ' You have 12 items in your data
   l_count      = l_data.Count()
   ' You want to show a page size of 5 items
   l_pageSize   = 5
   ' The height of one text line for this font is GetOneLineHeight()
   l_textHeight = FontR26.GetOneLineHeight()
   ' The largest width for your data is probably item 12 + some padding, normally you would interate
   ' the data and save the maximum width for your bitmap buffer.  So this is the bitmap buffers width
   l_width      = FontR26.GetOneLineWidth( l_data[ l_count - 1 ], 1000 ) + 25
   ' For this examle you have to fit all those strings into a bitmap buffer.  If you had 250 + strings you could not
   ' do this, but there is a better way like i said
   ' so the total height of your bitmap buffer is l_height, which is the total count * the height of each line 
   l_height     = l_count * l_textHeight
   ' Now for the region size.  It will be the same width as the bitmap but you only want to show pagesize of data
   ' So the height of the region will bee the textheight * the page size
   l_pageHeight = l_textHeight * l_pageSize
   
   ' Create the bitmap with l_width and l_height
   Bitmap = CreateObject( "roBitmap", { Width: l_width, Height: l_height, AlphaEnable: True } )
   'Clear it or leave it transparent
   Bitmap.Clear( &h333333FF )
   ' Starting at y offset 0 ( you could play with this for margins, but then the region would have to change
   ' write each line of text, offsetting the y coord by text height
   l_y = 0
   for each l_str in l_data
      Bitmap.DrawText( l_str, 0, l_y, &hCCCCCCFF, FontR26 )
      l_y = l_y + l_textHeight
   end for
   
   ' Create your region the same with, but only the page height
   Region = CreateObject( "roRegion", Bitmap, 0, 0, l_width, l_pageHeight )
   ' Set wrap true
   Region.SetWrap( True )
   ' Create the sprite
   Sprite = m.Compositor.NewSprite( 200, 300, Region, 1 )
   ' Draw everything
   m.Compositor.DrawAll()
   m.Screen.SwapBuffers()
   
   ' Set up your event loop
   ' The frame rate for the up/down arrow
   l_slowRate = 8
   ' The frame rate/number fwd/reverse arrows - ( this is not a true rate but good enough for lists )
   l_fastRate = 2
   ' Delay between the button presses 
   l_delay    = 200
   
   ' These are the constants for the buttons you can use the AA if you wish, probably best to
   l_bp_BK    = 0
   l_bp_UP    = 2
   l_bp_DN    = 3
   l_bp_REV   = 8
   l_bp_FWD   = 9
  
   ' Button pressed
   l_index    = 0
   ' Last button pressed
   l_lastKey  = -1
   l_running  = True
  
   l_timer = CreateObject( "roTimeSpan" )
   
   while( l_running )
   
      ' Get used to GetMessage, Wait is not really very good for anything but simple interface
      l_msg = Port.GetMessage() 
      
      if type( l_msg ) = "roUniversalControlEvent"
    
         l_index   = l_msg.GetInt()
         l_lastKey = l_index
       
         ' Based upon the key press, call the functions below
         if l_index = l_bp_DN or l_index = l_bp_FWD
            ScrollDown( Region, l_textHeight, l_slowRate )
         else if l_index = l_bp_UP or l_index = l_bp_REV
            ScrollUp( Region, l_textHeight, l_slowRate )
         else if l_index = l_bp_BK 
            l_running = False
         else if l_index >= 100 ' All key ups are value + 100
            l_lastKey = -1
         end if
         
         ' reset the timer for the delay
         l_timer.Mark()
      ' User is holding down a button and the delay has been exceeded
      else if (  l_lastKey >= 0 and l_timer.TotalMilliseconds() >= l_delay )
      
         if l_lastKey = l_bp_DN 
            ScrollDown( Region, l_textHeight, l_slowRate )
         else if l_lastKey = l_bp_FWD 
            ScrollDown( Region, l_textHeight, l_fastRate )
         else if l_lastKey = l_bp_UP
            ScrollUp( Region, l_textHeight, l_slowRate )
         else if l_lastKey = l_bp_REV
            ScrollUp( Region, l_textHeight, l_fastRate )
         end if
         
      end if
      
   end while
   
   ' Always remove the sprite or you will have a memory leak, even out of scope it is not released
   ' must be explicity released at all times
   if ( Sprite <> Invalid ) then Sprite.Remove()
   
End Sub

' This employs region offsetting and a very simple ease.  You want to move the regions y pos by textheight each time the function is called
Function ScrollDown( roRegion As Object, height As Integer, frames As Integer ) As Void

  ' Not sure how optimized the byte code is so I simplify references when in loops  
   l_compositor = m.Compositor
   l_screen     = m.Screen
   l_prevset    = 0 
  
   for l_i = 1 to frames
      ' Offset means to move from the current position by the value 
      l_offset  = int( height * l_i / frames )
      l_offdiff = l_offset - l_prevset
      l_prevset = l_offset
      
      ' Moving forward in Y direction so everything else is 0
      roRegion.Offset( 0, l_offdiff, 0, 0 )
      l_compositor.DrawAll()
      l_screen.SwapBuffers()
   end for

End Function

Function ScrollUp( roRegion As Object, height As Integer, frames As Integer ) As Void
   l_compositor = m.Compositor
   l_screen     = m.Screen
   l_prevset    = 0 
  
   for l_i = 1 to frames
      l_offset  = int( height * l_i / frames )
      l_offdiff = l_offset - l_prevset
      l_prevset = l_offset
      ' same as aobve only moving back so the offset is negative
      roRegion.Offset( 0, -l_offdiff, 0, 0 )
      l_compositor.DrawAll()
      l_screen.SwapBuffers()
   end for
End Function

“NewManLiving” wrote:

Sub Main()

   ' This is strictly for example - You really should NOT create your globals this way
   ' There is a much better way which I will not go into now, but to demonstrate how a region works
   ' this will have to do

   l_color      = &h262626FF
 
   m.Screen     = CreateObject( "roScreen", True )
   m.Compositor = CreateObject( "roCompositor" )
   Port         = CreateObject( "roMessagePort" )
   m.Screen.SetMessagePort( Port )
   m.Screen.Clear( l_color )
   m.Compositor.SetDrawTo( m.Screen, l_color )
   
   Registry     = CreateObject( "roFontRegistry" )
   FontR26      = Registry.GetDefaultFont( 26, False, False ) 
 
   l_data = [
      "1)  Get a Macbook pro with 4GB ram and 250gb harddrive",
      "2)  Get a Macbook pro with 8GB ram and 260gb harddrive",
      "3)  Get a Macbook pro with 12GB ram and 270gb harddrive",
      "4)  Get a Macbook pro with 14GB ram and 280gb harddrive",
      "5)  Get a Macbook pro with 16GB ram and 290gb harddrive",
      "6)  Get a Macbook pro with 18GB ram and 300gb harddrive",
      "7)  Get a Macbook pro with 20GB ram and 310gb harddrive",
      "8)  Get a Macbook pro with 22GB ram and 320gb harddrive",
      "9)  Get a Macbook pro with 24GB ram and 330gb harddrive",
      "10) Get a Macbook pro with 26GB ram and 340gb harddrive",
      "11) Get a Macbook pro with 28GB ram and 350gb harddrive",
      "12) Get a Macbook pro with 30GB ram and 360gb harddrive"
   ]
   
   ' Keep in mind there are only so many text strings that you can fit into a bitmap buffer, before you exceed its maximum size
   ' there is a much better way to do all of this, but for now to help you understand regions, i'll keep it simple
   
   ' You have 12 items in your data
   l_count      = l_data.Count()
   ' You want to show a page size of 5 items
   l_pageSize   = 5
   ' The height of one text line for this font is GetOneLineHeight()
   l_textHeight = FontR26.GetOneLineHeight()
   ' The largest width for your data is probably item 12 + some padding, normally you would interate
   ' the data and save the maximum width for your bitmap buffer.  So this is the bitmap buffers width
   l_width      = FontR26.GetOneLineWidth( l_data[ l_count - 1 ], 1000 ) + 25
   ' For this examle you have to fit all those strings into a bitmap buffer.  If you had 250 + strings you could not
   ' do this, but there is a better way like i said
   ' so the total height of your bitmap buffer is l_height, which is the total count * the height of each line 
   l_height     = l_count * l_textHeight
   ' Now for the region size.  It will be the same width as the bitmap but you only want to show pagesize of data
   ' So the height of the region will bee the textheight * the page size
   l_pageHeight = l_textHeight * l_pageSize
   
   ' Create the bitmap with l_width and l_height
   Bitmap = CreateObject( "roBitmap", { Width: l_width, Height: l_height, AlphaEnable: True } )
   'Clear it or leave it transparent
   Bitmap.Clear( &h333333FF )
   ' Starting at y offset 0 ( you could play with this for margins, but then the region would have to change
   ' write each line of text, offsetting the y coord by text height
   l_y = 0
   for each l_str in l_data
      Bitmap.DrawText( l_str, 0, l_y, &hCCCCCCFF, FontR26 )
      l_y = l_y + l_textHeight
   end for
   
   ' Create your region the same with, but only the page height
   Region = CreateObject( "roRegion", Bitmap, 0, 0, l_width, l_pageHeight )
   ' Set wrap true
   Region.SetWrap( True )
   ' Create the sprite
   Sprite = m.Compositor.NewSprite( 200, 300, Region, 1 )
   ' Draw everything
   m.Compositor.DrawAll()
   m.Screen.SwapBuffers()
   
   ' Set up your event loop
   ' The frame rate for the up/down arrow
   l_slowRate = 8
   ' The frame rate/number fwd/reverse arrows - ( this is not a true rate but good enough for lists )
   l_fastRate = 2
   ' Delay between the button presses 
   l_delay    = 200
   
   ' These are the constants for the buttons you can use the AA if you wish, probably best to
   l_bp_BK    = 0
   l_bp_UP    = 2
   l_bp_DN    = 3
   l_bp_REV   = 8
   l_bp_FWD   = 9
  
   ' Button pressed
   l_index    = 0
   ' Last button pressed
   l_lastKey  = -1
   l_running  = True
  
   l_timer = CreateObject( "roTimeSpan" )
   
   while( l_running )
   
      ' Get used to GetMessage, Wait is not really very good for anything but simple interface
      l_msg = Port.GetMessage() 
      
      if type( l_msg ) = "roUniversalControlEvent"
    
         l_index   = l_msg.GetInt()
         l_lastKey = l_index
       
         ' Based upon the key press, call the functions below
         if l_index = l_bp_DN or l_index = l_bp_FWD
            ScrollDown( Region, l_textHeight, l_slowRate )
         else if l_index = l_bp_UP or l_index = l_bp_REV
            ScrollUp( Region, l_textHeight, l_slowRate )
         else if l_index = l_bp_BK 
            l_running = False
         else if l_index >= 100 ' All key ups are value + 100
            l_lastKey = -1
         end if
         
         ' reset the timer for the delay
         l_timer.Mark()
      ' User is holding down a button and the delay has been exceeded
      else if (  l_lastKey >= 0 and l_timer.TotalMilliseconds() >= l_delay )
      
         if l_lastKey = l_bp_DN 
            ScrollDown( Region, l_textHeight, l_slowRate )
         else if l_lastKey = l_bp_FWD 
            ScrollDown( Region, l_textHeight, l_fastRate )
         else if l_lastKey = l_bp_UP
            ScrollUp( Region, l_textHeight, l_slowRate )
         else if l_lastKey = l_bp_REV
            ScrollUp( Region, l_textHeight, l_fastRate )
         end if
         
      end if
      
   end while
   
   ' Always remove the sprite or you will have a memory leak, even out of scope it is not released
   ' must be explicity released at all times
   if ( Sprite <> Invalid ) then Sprite.Remove()
   
End Sub

' This employs region offsetting and a very simple ease.  You want to move the regions y pos by textheight each time the function is called
Function ScrollDown( roRegion As Object, height As Integer, frames As Integer ) As Void

  ' Not sure how optimized the byte code is so I simplify references when in loops  
   l_compositor = m.Compositor
   l_screen     = m.Screen
   l_prevset    = 0 
  
   for l_i = 1 to frames
      ' Offset means to move from the current position by the value 
      l_offset  = int( height * l_i / frames )
      l_offdiff = l_offset - l_prevset
      l_prevset = l_offset
      
      ' Moving forward in Y direction so everything else is 0
      roRegion.Offset( 0, l_offdiff, 0, 0 )
      l_compositor.DrawAll()
      l_screen.SwapBuffers()
   end for

End Function

Function ScrollUp( roRegion As Object, height As Integer, frames As Integer ) As Void
   l_compositor = m.Compositor
   l_screen     = m.Screen
   l_prevset    = 0 
  
   for l_i = 1 to frames
      l_offset  = int( height * l_i / frames )
      l_offdiff = l_offset - l_prevset
      l_prevset = l_offset
      ' same as aobve only moving back so the offset is negative
      roRegion.Offset( 0, -l_offdiff, 0, 0 )
      l_compositor.DrawAll()
      l_screen.SwapBuffers()
   end for
End Function

Thanks a lot for helping me with the examples. It helped me a lot. Really appreciate it.

You might try .Clear() on whatever bitmap/region you are drawing your text to

“Komag” wrote:
You might try .Clear() on whatever bitmap/region you are drawing your text to

Thank your for the input. I already have the code to clear the bitmap. I am not sure if i am doing it right though.

'making the bitmap transparent
Bitmap.Clear(&h00000000 )

You’re only clearing it once at the beginning of the program. You need to clear it every time you draw the text, so that you’re not drawing new text on top of old text.

–Mark

“RokuMarkn” wrote:
You’re only clearing it once at the beginning of the program. You need to clear it every time you draw the text, so that you’re not drawing new text on top of old text.

–Mark

Thank you for the input. I am using the code provided by NewManLiving. If I run the code as provided, it runs fine. I am able to scroll up and down smothly.
However, I need to have a background image that will cover the entire screen and on the middle part of the screen I need a transparent area where the scrollable items will be placed. Therefore it should look like scrollable items are on top of the image.

Here is the code provided by NewManLiving:


Sub Main()

   ' This is strictly for example - You really should NOT create your globals this way
   ' There is a much better way which I will not go into now, but to demonstrate how a region works
   ' this will have to do

   l_color      = &h262626FF
 
   m.Screen     = CreateObject( "roScreen", True )
   m.Compositor = CreateObject( "roCompositor" )
   Port         = CreateObject( "roMessagePort" )
   m.Screen.SetMessagePort( Port )
   m.Screen.Clear( l_color )
   m.Compositor.SetDrawTo( m.Screen, l_color )
   
   Registry     = CreateObject( "roFontRegistry" )
   FontR26      = Registry.GetDefaultFont( 26, False, False ) 
 
   l_data = [
      "1)  Get a Macbook pro with 4GB ram and 250gb harddrive",
      "2)  Get a Macbook pro with 8GB ram and 260gb harddrive",
      "3)  Get a Macbook pro with 12GB ram and 270gb harddrive",
      "4)  Get a Macbook pro with 14GB ram and 280gb harddrive",
      "5)  Get a Macbook pro with 16GB ram and 290gb harddrive",
      "6)  Get a Macbook pro with 18GB ram and 300gb harddrive",
      "7)  Get a Macbook pro with 20GB ram and 310gb harddrive",
      "8)  Get a Macbook pro with 22GB ram and 320gb harddrive",
      "9)  Get a Macbook pro with 24GB ram and 330gb harddrive",
      "10) Get a Macbook pro with 26GB ram and 340gb harddrive",
      "11) Get a Macbook pro with 28GB ram and 350gb harddrive",
      "12) Get a Macbook pro with 30GB ram and 360gb harddrive"
   ]
   
   ' Keep in mind there are only so many text strings that you can fit into a bitmap buffer, before you exceed its maximum size
   ' there is a much better way to do all of this, but for now to help you understand regions, i'll keep it simple
   
   ' You have 12 items in your data
   l_count      = l_data.Count()
   ' You want to show a page size of 5 items
   l_pageSize   = 5
   ' The height of one text line for this font is GetOneLineHeight()
   l_textHeight = FontR26.GetOneLineHeight()
   ' The largest width for your data is probably item 12 + some padding, normally you would interate
   ' the data and save the maximum width for your bitmap buffer.  So this is the bitmap buffers width
   l_width      = FontR26.GetOneLineWidth( l_data[ l_count - 1 ], 1000 ) + 25
   ' For this examle you have to fit all those strings into a bitmap buffer.  If you had 250 + strings you could not
   ' do this, but there is a better way like i said
   ' so the total height of your bitmap buffer is l_height, which is the total count * the height of each line 
   l_height     = l_count * l_textHeight
   ' Now for the region size.  It will be the same width as the bitmap but you only want to show pagesize of data
   ' So the height of the region will bee the textheight * the page size
   l_pageHeight = l_textHeight * l_pageSize
   
   ' Create the bitmap with l_width and l_height
   Bitmap = CreateObject( "roBitmap", { Width: l_width, Height: l_height, AlphaEnable: True } )
   'Clear it or leave it transparent
   Bitmap.Clear( &h333333FF )
   ' Starting at y offset 0 ( you could play with this for margins, but then the region would have to change
   ' write each line of text, offsetting the y coord by text height
   l_y = 0
   for each l_str in l_data
      Bitmap.DrawText( l_str, 0, l_y, &hCCCCCCFF, FontR26 )
      l_y = l_y + l_textHeight
   end for
   
   ' Create your region the same with, but only the page height
   Region = CreateObject( "roRegion", Bitmap, 0, 0, l_width, l_pageHeight )
   ' Set wrap true
   Region.SetWrap( True )
   ' Create the sprite
   Sprite = m.Compositor.NewSprite( 200, 300, Region, 1 )
   ' Draw everything
   m.Compositor.DrawAll()
   m.Screen.SwapBuffers()
   
   ' Set up your event loop
   ' The frame rate for the up/down arrow
   l_slowRate = 8
   ' The frame rate/number fwd/reverse arrows - ( this is not a true rate but good enough for lists )
   l_fastRate = 2
   ' Delay between the button presses 
   l_delay    = 200
   
   ' These are the constants for the buttons you can use the AA if you wish, probably best to
   l_bp_BK    = 0
   l_bp_UP    = 2
   l_bp_DN    = 3
   l_bp_REV   = 8
   l_bp_FWD   = 9
  
   ' Button pressed
   l_index    = 0
   ' Last button pressed
   l_lastKey  = -1
   l_running  = True
  
   l_timer = CreateObject( "roTimeSpan" )
   
   while( l_running )
   
      ' Get used to GetMessage, Wait is not really very good for anything but simple interface
      l_msg = Port.GetMessage() 
      
      if type( l_msg ) = "roUniversalControlEvent"
    
         l_index   = l_msg.GetInt()
         l_lastKey = l_index
       
         ' Based upon the key press, call the functions below
         if l_index = l_bp_DN or l_index = l_bp_FWD
            ScrollDown( Region, l_textHeight, l_slowRate )
         else if l_index = l_bp_UP or l_index = l_bp_REV
            ScrollUp( Region, l_textHeight, l_slowRate )
         else if l_index = l_bp_BK 
            l_running = False
         else if l_index >= 100 ' All key ups are value + 100
            l_lastKey = -1
         end if
         
         ' reset the timer for the delay
         l_timer.Mark()
      ' User is holding down a button and the delay has been exceeded
      else if (  l_lastKey >= 0 and l_timer.TotalMilliseconds() >= l_delay )
      
         if l_lastKey = l_bp_DN 
            ScrollDown( Region, l_textHeight, l_slowRate )
         else if l_lastKey = l_bp_FWD 
            ScrollDown( Region, l_textHeight, l_fastRate )
         else if l_lastKey = l_bp_UP
            ScrollUp( Region, l_textHeight, l_slowRate )
         else if l_lastKey = l_bp_REV
            ScrollUp( Region, l_textHeight, l_fastRate )
         end if
         
      end if
      
   end while
   
   ' Always remove the sprite or you will have a memory leak, even out of scope it is not released
   ' must be explicity released at all times
   if ( Sprite <> Invalid ) then Sprite.Remove()
   
End Sub

' This employs region offsetting and a very simple ease.  You want to move the regions y pos by textheight each time the function is called
Function ScrollDown( roRegion As Object, height As Integer, frames As Integer ) As Void

  ' Not sure how optimized the byte code is so I simplify references when in loops  
   l_compositor = m.Compositor
   l_screen     = m.Screen
   l_prevset    = 0 
  
   for l_i = 1 to frames
      ' Offset means to move from the current position by the value 
      l_offset  = int( height * l_i / frames )
      l_offdiff = l_offset - l_prevset
      l_prevset = l_offset
      
      ' Moving forward in Y direction so everything else is 0
      roRegion.Offset( 0, l_offdiff, 0, 0 )
      l_compositor.DrawAll()
      l_screen.SwapBuffers()
   end for

End Function

Function ScrollUp( roRegion As Object, height As Integer, frames As Integer ) As Void
   l_compositor = m.Compositor
   l_screen     = m.Screen
   l_prevset    = 0 
  
   for l_i = 1 to frames
      l_offset  = int( height * l_i / frames )
      l_offdiff = l_offset - l_prevset
      l_prevset = l_offset
      ' same as aobve only moving back so the offset is negative
      roRegion.Offset( 0, -l_offdiff, 0, 0 )
      l_compositor.DrawAll()
      l_screen.SwapBuffers()
   end for
End Function

I think you may have to clear the bitmap and redraw the text every frame (within you’re WHILE loop) to get that transparent effect you’re looking for. Although it sort of kills the point of NML’s code which was to avoid having to redraw the text every frame.

Yes That’s correct. Clear would get rid of all the text defeating the whole purpose. If a design incorporates the compositor then the menu sprite should be created at a Z order higher than the background, so the background needs to be a Sprite as well generally placed at z order 0. Then compositor.drawall would first redraw the background and then the menu on top of it. In this case where there are a limited number of text all previously drawn into a bitmap then to scroll is simple. Create a region, set wrap to true and +/-offset the y position by the text height + any additional spacing as it was originally layed out in the bitmap. In the case of a virtual list where the number of items can vary or become very large then the bitmap is created with a virtual buffer zone hidden by the region. In this case there must be an explicit clear to get rid of the text that was previously there. However, this presents a problem when the clearing must be transparent. Drawing a transparent rectangle in that zone (which is always changing like a dog chasing its tail ) will not do the trick. The other option of using the bitmap or region to clear transparently will cause all text to be cleared resulting in a complete redraw of all text. To get around this caveat a seperate region is created the size of one row of text. When the user scrolls the data indexes are calculated to return the next text in the list, then the new y position of the buffer zone is determined by an offset from the previous rows position. This area is always hidden because the region is created one row size smaller than the bitmap. Since scrolling involves offsetting the region as opposed to redrawing all the text, then naturally the region moves exposing a new area of the bitmap while hiding another until it wraps around, thus the dog chasing its tail analogy. It is the new area that needs to be cleared before the new text is written and before the easing function offsets the region to expose that updated portion of the bitmap to the user. To clear this area then involves moving the seperate row region into that same area and clearing it transparently before the new text is written and before the main region is offset into that area.

I’m having some dialog with the poster. I like to help people interested in the 2D. Not sure where Scene Graph is going and what effect it will have upon the use of the 2D. One must first overcome their distaste for XML which I think is pretty ubiquitous and then grapple with the node-tree concept, and then finally get around all the things that just don’t come out the way you expected them to by rummaging through the disconnected documentation to which you have 10 pages open in 10 browser Instances. But I am spending time with it. So we will see

“Komag” wrote:
I think you may have to clear the bitmap and redraw the text every frame (within you’re WHILE loop) to get that transparent effect you’re looking for. Although it sort of kills the point of NML’s code which was to avoid having to redraw the text every frame.

yup it will defeat the purpose of drawing all the list items earlier. thank you for the response.

“NewManLiving” wrote:
Yes That’s correct. Clear would get rid of all the text defeating the whole purpose. If a design incorporates the compositor then the menu sprite should be created at a Z order higher than the background, so the background needs to be a Sprite as well generally placed at z order 0. Then compositor.drawall would first redraw the background and then the menu on top of it. In this case where there are a limited number of text all previously drawn into a bitmap then to scroll is simple. Create a region, set wrap to true and +/-offset the y position by the text height + any additional spacing as it was originally layed out in the bitmap. In the case of a virtual list where the number of items can vary or become very large then the bitmap is created with a virtual buffer zone hidden by the region. In this case there must be an explicit clear to get rid of the text that was previously there. However, this presents a problem when the clearing must be transparent. Drawing a transparent rectangle in that zone (which is always changing like a dog chasing its tail ) will not do the trick. The other option of using the bitmap or region to clear transparently will cause all text to be cleared resulting in a complete redraw of all text. To get around this caveat a seperate region is created the size of one row of text. When the user scrolls the data indexes are calculated to return the next text in the list, then the new y position of the buffer zone is determined by an offset from the previous rows position. This area is always hidden because the region is created one row size smaller than the bitmap. Since scrolling involves offsetting the region as opposed to redrawing all the text, then naturally the region moves exposing a new area of the bitmap while hiding another until it wraps around, thus the dog chasing its tail analogy. It is the new area that needs to be cleared before the new text is written and before the easing function offsets the region to expose that updated portion of the bitmap to the user. To clear this area then involves moving the seperate row region into that same area and clearing it transparently before the new text is written and before the main region is offset into that area.

I’m having some dialog with the poster. I like to help people interested in the 2D. Not sure where Scene Graph is going and what effect it will have upon the use of the 2D. One must first overcome their distaste for XML which I think is pretty ubiquitous and then grapple with the node-tree concept, and then finally get around all the things that just don’t come out the way you expected them to by rummaging through the disconnected documentation to which you have 10 pages open in 10 browser Instances. But I am spending time with it. So we will see

Thanks a lot NewManLiving for such insightful explanation. I have been gaining a lot of knowledge from this forum.

Here’s a version of NML’s code that doesn’t use the compositor but draws the text in each frame. You’ll see the changes are actually very small. In this version it should be simpler to add a DrawObject to draw the background in each frame too.


    Sub Main()

       ' This is strictly for example - You really should NOT create your globals this way
       ' There is a much better way which I will not go into now, but to demonstrate how a region works
       ' this will have to do

       m.l_color      = &h262626FF
     
       m.Screen     = CreateObject( "roScreen", True )
       Port         = CreateObject( "roMessagePort" )
       m.Screen.SetMessagePort( Port )

       Registry     = CreateObject( "roFontRegistry" )
       FontR26      = Registry.GetDefaultFont( 26, False, False )
     
       l_data = [
          "1)  Get a Macbook pro with 4GB ram and 250gb harddrive",
          "2)  Get a Macbook pro with 8GB ram and 260gb harddrive",
          "3)  Get a Macbook pro with 12GB ram and 270gb harddrive",
          "4)  Get a Macbook pro with 14GB ram and 280gb harddrive",
          "5)  Get a Macbook pro with 16GB ram and 290gb harddrive",
          "6)  Get a Macbook pro with 18GB ram and 300gb harddrive",
          "7)  Get a Macbook pro with 20GB ram and 310gb harddrive",
          "8)  Get a Macbook pro with 22GB ram and 320gb harddrive",
          "9)  Get a Macbook pro with 24GB ram and 330gb harddrive",
          "10) Get a Macbook pro with 26GB ram and 340gb harddrive",
          "11) Get a Macbook pro with 28GB ram and 350gb harddrive",
          "12) Get a Macbook pro with 30GB ram and 360gb harddrive"
       ]
       
       ' Keep in mind there are only so many text strings that you can fit into a bitmap buffer, before you exceed its maximum size
       ' there is a much better way to do all of this, but for now to help you understand regions, i'll keep it simple
       
       ' You have 12 items in your data
       l_count      = l_data.Count()
       ' You want to show a page size of 5 items
       l_pageSize   = 5
       ' The height of one text line for this font is GetOneLineHeight()
       l_textHeight = FontR26.GetOneLineHeight()
       ' The largest width for your data is probably item 12 + some padding, normally you would interate
       ' the data and save the maximum width for your bitmap buffer.  So this is the bitmap buffers width
       l_width      = FontR26.GetOneLineWidth( l_data[ l_count - 1 ], 1000 ) + 25
       ' For this examle you have to fit all those strings into a bitmap buffer.  If you had 250 + strings you could not
       ' do this, but there is a better way like i said
       ' so the total height of your bitmap buffer is l_height, which is the total count * the height of each line
       l_height     = l_count * l_textHeight
       ' Now for the region size.  It will be the same width as the bitmap but you only want to show pagesize of data
       ' So the height of the region will bee the textheight * the page size
       l_pageHeight = l_textHeight * l_pageSize
       
       ' Create the bitmap with l_width and l_height
       Bitmap = CreateObject( "roBitmap", { Width: l_width, Height: l_height, AlphaEnable: True } )
       'Clear it or leave it transparent
       Bitmap.Clear( &h333333FF )
       ' Starting at y offset 0 ( you could play with this for margins, but then the region would have to change
       ' write each line of text, offsetting the y coord by text height
       l_y = 0
       for each l_str in l_data
          Bitmap.DrawText( l_str, 0, l_y, &hCCCCCCFF, FontR26 )
          l_y = l_y + l_textHeight
       end for
       
       ' Create your region the same with, but only the page height
       Region = CreateObject( "roRegion", Bitmap, 0, 0, l_width, l_pageHeight )
       ' Set wrap true
       Region.SetWrap( True )
       
       ' Set up your event loop
       ' The frame rate for the up/down arrow
       l_slowRate = 8
       ' The frame rate/number fwd/reverse arrows - ( this is not a true rate but good enough for lists )
       l_fastRate = 2
       ' Delay between the button presses
       l_delay    = 200
       
       ' These are the constants for the buttons you can use the AA if you wish, probably best to
       l_bp_BK    = 0
       l_bp_UP    = 2
       l_bp_DN    = 3
       l_bp_REV   = 8
       l_bp_FWD   = 9
     
       ' Button pressed
       l_index    = 0
       ' Last button pressed
       l_lastKey  = -1
       l_running  = True
     
       l_timer = CreateObject( "roTimeSpan" )
       
       while( l_running )

           DrawScreen( Region )
       
          ' Get used to GetMessage, Wait is not really very good for anything but simple interface
          l_msg = Port.GetMessage()
         
          if type( l_msg ) = "roUniversalControlEvent"
       
             l_index   = l_msg.GetInt()
             l_lastKey = l_index
           
             ' Based upon the key press, call the functions below
             if l_index = l_bp_DN or l_index = l_bp_FWD
                ScrollDown( Region, l_textHeight, l_slowRate )
             else if l_index = l_bp_UP or l_index = l_bp_REV
                ScrollUp( Region, l_textHeight, l_slowRate )
             else if l_index = l_bp_BK
                l_running = False
             else if l_index >= 100 ' All key ups are value + 100
                l_lastKey = -1
             end if
             
             ' reset the timer for the delay
             l_timer.Mark()
          ' User is holding down a button and the delay has been exceeded
          else if (  l_lastKey >= 0 and l_timer.TotalMilliseconds() >= l_delay )
         
             if l_lastKey = l_bp_DN
                ScrollDown( Region, l_textHeight, l_slowRate )
             else if l_lastKey = l_bp_FWD
                ScrollDown( Region, l_textHeight, l_fastRate )
             else if l_lastKey = l_bp_UP
                ScrollUp( Region, l_textHeight, l_slowRate )
             else if l_lastKey = l_bp_REV
                ScrollUp( Region, l_textHeight, l_fastRate )
             end if
             
          end if
         
       end while
       
    End Sub

    ' This employs region offsetting and a very simple ease.  You want to move the regions y pos by textheight each time the function is called
    Function ScrollDown( roRegion As Object, height As Integer, frames As Integer ) As Void

      ' Not sure how optimized the byte code is so I simplify references when in loops 
       l_screen     = m.Screen
       l_prevset    = 0
     
       for l_i = 1 to frames
          ' Offset means to move from the current position by the value
          l_offset  = int( height * l_i / frames )
          l_offdiff = l_offset - l_prevset
          l_prevset = l_offset
         
          ' Moving forward in Y direction so everything else is 0
          roRegion.Offset( 0, l_offdiff, 0, 0 )
          DrawScreen(roRegion)
       end for

    End Function

    Function ScrollUp( roRegion As Object, height As Integer, frames As Integer ) As Void
       l_screen     = m.Screen
       l_prevset    = 0
     
       for l_i = 1 to frames
          l_offset  = int( height * l_i / frames )
          l_offdiff = l_offset - l_prevset
          l_prevset = l_offset
          ' same as aobve only moving back so the offset is negative
          roRegion.Offset( 0, -l_offdiff, 0, 0 )
          DrawScreen(roRegion)
       end for
    End Function

    Function DrawScreen( region as Object )
           m.Screen.Clear( m.l_color )
           m.Screen.DrawObject( 200, 300, region )
           m.Screen.SwapBuffers()
    End Function

Yes, That would be the way it is done without the compositor; However, I believe that he is using the compositor, at least that is what I had gathered from previous posts. Which is why I stated initially: “‘If one is to incorporate’ the compositor into their design, then just setting the z order properly and creating a background sprite would work”

Your method is extremely useful for optimizing complex animation when not using the compositor and reduces the need to create temporary bitmaps and sprites when using the compositor. I make use of it extensively, and this technique is demonstrated the keyboard.zip that I put out recently. Most of the selector animation is a direct drawing of regions to the screen sandwiched in-between Compositor.DrawAll and screen.swapbuffers.

The combination of both permits even a higher level of complexity, especially in asynchronous drawing. This is demonstrated in the Matrix Grid in my demo channel. With this type of complexity you do not know when anything is coming in from the texturemanager, until it arrives, coupled with the user scrolling/selecting/ cursor animation, the possibility that the texture had not arrived prior to the user selecting the grid cell, and/or other multi-layered animation all going on at the same time. So one way or the other you have to introduce this logic into your channel using a bunch of flags and if statements ( have done it ) or you can just depend upon the compositor to draw whatever sprite happens to be in its sprite list at the time the event occurs, and concentrate on optimizing any drawing that is concrete and known during the execution of a particular event. I personally have found this beneficial, and have been able over the years to produce interface that is unique

“RokuMarkn” wrote:
Here’s a version of NML’s code that doesn’t use the compositor but draws the text in each frame. You’ll see the changes are actually very small. In this version it should be simpler to add a DrawObject to draw the background in each frame too.


    Sub Main()

       ' This is strictly for example - You really should NOT create your globals this way
       ' There is a much better way which I will not go into now, but to demonstrate how a region works
       ' this will have to do

       m.l_color      = &h262626FF
     
       m.Screen     = CreateObject( "roScreen", True )
       Port         = CreateObject( "roMessagePort" )
       m.Screen.SetMessagePort( Port )

       Registry     = CreateObject( "roFontRegistry" )
       FontR26      = Registry.GetDefaultFont( 26, False, False )
     
       l_data = [
          "1)  Get a Macbook pro with 4GB ram and 250gb harddrive",
          "2)  Get a Macbook pro with 8GB ram and 260gb harddrive",
          "3)  Get a Macbook pro with 12GB ram and 270gb harddrive",
          "4)  Get a Macbook pro with 14GB ram and 280gb harddrive",
          "5)  Get a Macbook pro with 16GB ram and 290gb harddrive",
          "6)  Get a Macbook pro with 18GB ram and 300gb harddrive",
          "7)  Get a Macbook pro with 20GB ram and 310gb harddrive",
          "8)  Get a Macbook pro with 22GB ram and 320gb harddrive",
          "9)  Get a Macbook pro with 24GB ram and 330gb harddrive",
          "10) Get a Macbook pro with 26GB ram and 340gb harddrive",
          "11) Get a Macbook pro with 28GB ram and 350gb harddrive",
          "12) Get a Macbook pro with 30GB ram and 360gb harddrive"
       ]
       
       ' Keep in mind there are only so many text strings that you can fit into a bitmap buffer, before you exceed its maximum size
       ' there is a much better way to do all of this, but for now to help you understand regions, i'll keep it simple
       
       ' You have 12 items in your data
       l_count      = l_data.Count()
       ' You want to show a page size of 5 items
       l_pageSize   = 5
       ' The height of one text line for this font is GetOneLineHeight()
       l_textHeight = FontR26.GetOneLineHeight()
       ' The largest width for your data is probably item 12 + some padding, normally you would interate
       ' the data and save the maximum width for your bitmap buffer.  So this is the bitmap buffers width
       l_width      = FontR26.GetOneLineWidth( l_data[ l_count - 1 ], 1000 ) + 25
       ' For this examle you have to fit all those strings into a bitmap buffer.  If you had 250 + strings you could not
       ' do this, but there is a better way like i said
       ' so the total height of your bitmap buffer is l_height, which is the total count * the height of each line
       l_height     = l_count * l_textHeight
       ' Now for the region size.  It will be the same width as the bitmap but you only want to show pagesize of data
       ' So the height of the region will bee the textheight * the page size
       l_pageHeight = l_textHeight * l_pageSize
       
       ' Create the bitmap with l_width and l_height
       Bitmap = CreateObject( "roBitmap", { Width: l_width, Height: l_height, AlphaEnable: True } )
       'Clear it or leave it transparent
       Bitmap.Clear( &h333333FF )
       ' Starting at y offset 0 ( you could play with this for margins, but then the region would have to change
       ' write each line of text, offsetting the y coord by text height
       l_y = 0
       for each l_str in l_data
          Bitmap.DrawText( l_str, 0, l_y, &hCCCCCCFF, FontR26 )
          l_y = l_y + l_textHeight
       end for
       
       ' Create your region the same with, but only the page height
       Region = CreateObject( "roRegion", Bitmap, 0, 0, l_width, l_pageHeight )
       ' Set wrap true
       Region.SetWrap( True )
       
       ' Set up your event loop
       ' The frame rate for the up/down arrow
       l_slowRate = 8
       ' The frame rate/number fwd/reverse arrows - ( this is not a true rate but good enough for lists )
       l_fastRate = 2
       ' Delay between the button presses
       l_delay    = 200
       
       ' These are the constants for the buttons you can use the AA if you wish, probably best to
       l_bp_BK    = 0
       l_bp_UP    = 2
       l_bp_DN    = 3
       l_bp_REV   = 8
       l_bp_FWD   = 9
     
       ' Button pressed
       l_index    = 0
       ' Last button pressed
       l_lastKey  = -1
       l_running  = True
     
       l_timer = CreateObject( "roTimeSpan" )
       
       while( l_running )

           DrawScreen( Region )
       
          ' Get used to GetMessage, Wait is not really very good for anything but simple interface
          l_msg = Port.GetMessage()
         
          if type( l_msg ) = "roUniversalControlEvent"
       
             l_index   = l_msg.GetInt()
             l_lastKey = l_index
           
             ' Based upon the key press, call the functions below
             if l_index = l_bp_DN or l_index = l_bp_FWD
                ScrollDown( Region, l_textHeight, l_slowRate )
             else if l_index = l_bp_UP or l_index = l_bp_REV
                ScrollUp( Region, l_textHeight, l_slowRate )
             else if l_index = l_bp_BK
                l_running = False
             else if l_index >= 100 ' All key ups are value + 100
                l_lastKey = -1
             end if
             
             ' reset the timer for the delay
             l_timer.Mark()
          ' User is holding down a button and the delay has been exceeded
          else if (  l_lastKey >= 0 and l_timer.TotalMilliseconds() >= l_delay )
         
             if l_lastKey = l_bp_DN
                ScrollDown( Region, l_textHeight, l_slowRate )
             else if l_lastKey = l_bp_FWD
                ScrollDown( Region, l_textHeight, l_fastRate )
             else if l_lastKey = l_bp_UP
                ScrollUp( Region, l_textHeight, l_slowRate )
             else if l_lastKey = l_bp_REV
                ScrollUp( Region, l_textHeight, l_fastRate )
             end if
             
          end if
         
       end while
       
    End Sub

    ' This employs region offsetting and a very simple ease.  You want to move the regions y pos by textheight each time the function is called
    Function ScrollDown( roRegion As Object, height As Integer, frames As Integer ) As Void

      ' Not sure how optimized the byte code is so I simplify references when in loops 
       l_screen     = m.Screen
       l_prevset    = 0
     
       for l_i = 1 to frames
          ' Offset means to move from the current position by the value
          l_offset  = int( height * l_i / frames )
          l_offdiff = l_offset - l_prevset
          l_prevset = l_offset
         
          ' Moving forward in Y direction so everything else is 0
          roRegion.Offset( 0, l_offdiff, 0, 0 )
          DrawScreen(roRegion)
       end for

    End Function

    Function ScrollUp( roRegion As Object, height As Integer, frames As Integer ) As Void
       l_screen     = m.Screen
       l_prevset    = 0
     
       for l_i = 1 to frames
          l_offset  = int( height * l_i / frames )
          l_offdiff = l_offset - l_prevset
          l_prevset = l_offset
          ' same as aobve only moving back so the offset is negative
          roRegion.Offset( 0, -l_offdiff, 0, 0 )
          DrawScreen(roRegion)
       end for
    End Function

    Function DrawScreen( region as Object )
           m.Screen.Clear( m.l_color )
           m.Screen.DrawObject( 200, 300, region )
           m.Screen.SwapBuffers()
    End Function

As NML mentioned I am using compositor. However, this approach is interesting too. Thank you for your help.