Well I’ll try this and see how well it goes. This sample uses the api to create a listview with some effects. It was tested under ROKU 3 latest everything. All you have to do to use it is copy the entire code section of the post into a file and run it. It does not use resources or access any servers.
If you have any questions feel free to ask. It gives a good overview of many of the api features
Function Main() As Void
' You only need one roScreen. Use the setdrawto feature of roCompositor to
' Emulate a screen stack. In this example
m.APPScreen = CreateObject("roScreen", True)
m.APPBkgClr = &hE0DFDFFF
m.APPScreen.Clear(&hE0DFDFFF)
' Create the list view passing along the handle to the screen
' A composite will be attached to the entire screen which gives the
' appearance of opening a new roScreen object
ne = NewListView(m.APPScreen)
ne.Initialize()
ne.Show()
ne.Clear()
ne = Invalid
End Function
' Create an example object
Function NewListView(a_roScreen As Object) As Object
lv = CreateObject("roAssociativeArray")
' Base component objects
lv.Screen = a_roScreen
lv.Device = Invalid
lv.Timer = Invalid
lv.Port = Invalid
lv.Compositor = Invalid
' Registry and fonts declarations
lv.DefaultRegistry = Invalid
lv.FontMedium = Invalid
' Data for the example
lv.DataList = Invalid
' The Buffer bitmap is the drawing area
' for the datalist. If interested I'll demonstrate
' How to create a virtual buffer for large data lists
' This example uses a fixed buffer the size of the data list
' If your datalists are very large then you can quickly run into
' memory problems or exceed the size of a bitmap.
' Each bitmap has a region or viewable area
' into the bitmap. The region lets you define how many lines of the
' list you want to display, while the rest are hidden and scrolled in/out view
' The sprite lets you pin the menu anywhere on the screen that you want to
' Both the region and the sprite are useful in creating animation and effects
lv.BufferBitmap = Invalid
lv.BufferRegion = Invalid
lv.BufferSprite = Invalid
' Background of the list.
lv.BackgroundBitmap = Invalid
lv.BackgroundRegion = Invalid
lv.BackgroundSprite = Invalid
' Size of menu and item size
lv.ListWidth = 0
lv.ListHeight = 0
lv.ListRowHeight = 0
lv.ListLineSpace = 0
lv.ListPageSize = 5
' Colors used in the application
lv.Transparent = &h00000000
lv.ScrBkgClr = &hE0DFDFFF
lv.DlgBkgClr = &hCECECEFF
lv.DlgFrameClr = &h808080FF
lv.DlgBlueClr = &h85AEFFFF
lv.TextClr = &h003366FF
lv.DarkRedClr = &h7A0000FF
lv.Initialize = list_view_initialize
lv.Show = list_view_show
lv.EventLoop = list_view_eventloop
lv.ScrollLine = list_view_scroll_line
lv.ScrollPage = list_view_scroll_page
lv.FadeScale = list_view_fade_scale
lv.DrawAll = list_view_drawall
return lv
End Function
Function list_view_initialize() As Void
' Create all objects to be used
m.Device = CreateObject("roDeviceInfo")
m.Timer = CreateObject("roTimeSpan")
m.Port = CreateObject("roMessagePort")
m.Compositor = CreateObject("roCompositor")
' Create a default registry and get the font
m.DefaultRegistry = CreateObject("roFontRegistry")
m.FontMedium = m.DefaultRegistry.GetDefaultFont(28, False, False)
' Get the sample data list and save its count
m.DataList = GetData()
l_count = m.DataList.Count()
' Get the constant one-line-height of the font. This value does not change
' The row height will be the combination of any extra line spacing plus text height
l_oneLineHeight = m.FontMedium.GetOneLineHeight()
m.ListLineSpace = 12
' Save the row height for building the buffer and regions, and to offset the regions
' for scrolling
m.ListRowHeight = l_oneLineHeight + m.ListLineSpace
' Calculate a Length for the BitmapBuffer based upon the number of items
' times the height of the font plus any additional line spacing you wish
' This could get large if you have a very large list. A virtual buffer is
' a little more complex, but it is fast and has a very small memory imprint
' I can demonstrate a virtual buffer if there is enough interest
l_height = l_count * m.ListRowHeight
' Calculate the maximum width. This is not the best way to do this as it
' is redundant and expensive in processing but for this example, to keep it
' short I am going to use it. But there is a better way, for example saving
' l_width to a parallel array or associative data container class which is what
' I use. I also center it and just offset it by the difference between the approximated
' and actual size when I write it to the bitmap
l_maxWidth = 0
for each l_text in m.DataList
l_width = m.FontMedium.GetOneLineWidth(l_text, 1000)
if l_maxWidth < l_width then l_maxWidth = l_width
end for
' Create the buffer bitmap according to the precalulated maximum width and height
' Clear it to the desired color
m.BufferBitmap = CreateObject("roBitmap", {width: l_maxWidth, height: l_height, AlphaEnable: False})
m.BufferBitmap.Clear(m.DlgBkgClr)
' Draw the text into the buffer centered. Increment the y pos by m.ListRowHeight
' This is all redundant as mentioned earlier. I do not use this method in my own application
l_x = 0
l_y = 0
l_halfWidth = l_maxWidth / 2
for l_i = 0 to l_count - 1
l_text = m.DataList[l_i]
' Paint the first line red
l_clr = m.TextClr
if l_i = 0 then l_clr = m.DarkRedClr
l_width = m.FontMedium.GetOneLineWidth(l_text, l_maxWidth)
l_x = int(l_maxWidth / 2 - l_width / 2)
m.BufferBitmap.DrawText(l_text, l_x, l_y, l_clr, m.FontMedium)
l_y = l_y + m.ListRowHeight
end for
' Now I want to display only listPageSize of data at one time. This is what
' a region is for (among many other good things as you will see). Calculate the
' same way as you would for the bitmap. If you want a more level scrolling
' leave off the bottom linespace. the 0,0 offset means to start the view at
' the 0,0 offsets in the bitmap, continue the entire width of the bitmap, but only
' show the first 5 lines. Then you just offset this region for scroling
l_height = m.ListPageSize * m.ListRowHeight - m.ListLineSpace
m.BufferRegion = CreateObject("roRegion", m.BufferBitmap, 0, 0, l_maxWidth, l_height)
' Set the regions wrap to true, this way it handles all the scrolling for you
m.BufferRegion.SetWrap(True)
' Create the background bitmap. Increase by 30 for a frame and inset border. Note that
' the frame should be surrounding the buffers region not the buffer bitmap as the region's
' length is smaller only showing a page size of rows
l_width = m.BufferRegion.GetWidth() + 30
l_height = m.BufferRegion.GetHeight() + 30
m.BackgroundBitmap = CreateObject("roBitmap", {width: l_width, height: l_height, AlphaEnable: False})
' Create a Frame - You could use drawline but it will only be done once. Color with frame color, offset
' and rectangle in the dialog color.
m.BackgroundBitmap.Clear(m.DlgFrameClr)
m.BackgroundBitmap.DrawRect(5, 5, l_width - 10, l_height - 10, m.DlgBkgClr)
' Create the region which will be the entire frame. Many times you only create regions once
' or can disgard their handles after the compositor creates the sprite. You only save them
' when you want to maniuplate them or copy them later
m.BackgroundRegion = CreateObject("roRegion", m.BackgroundBitmap, 0, 0, l_width, l_height)
' Ok lets pin all this in the center with a couple of sprites
' Get the display size and calculate and center the listview frame. Then you
' can just drop in the buffer bitmap right over it using the 30/2 pixel offsets used above
' You can continue using the l_width, l_height since the region and bitmap are the same size
' for the background
l_device_rect = m.Device.GetDisplaySize()
l_x = int(l_device_rect.w / 2 - l_width / 2)
l_y = int(l_device_rect.h / 2 - l_height / 2)
' Place the frame at the lower z order
m.BackgroundSprite = m.Compositor.NewSprite(l_x, l_y, m.BackgroundRegion, 2)
' Then drop in the bitmap buffer on top of it at the 30/2 pixel offsets
m.BufferSprite = m.Compositor.NewSprite(l_x + 15, l_y + 15, m.BufferRegion, 3)
' Create a header and footer all this can be placed in functions. It is left here for example
' Don't need to remove from the compositor as they are created once and reamin for the program
l_font = m.DefaultRegistry.GetDefaultFont(32, False, True)
l_headerText = "PROVERBS CHAPTER 2"
l_width = l_font.GetOneLineWidth(l_headerText, 800)
l_height = l_font.GetOneLineHeight()
l_bitmap = CreateObject("roBitmap", {width: l_width, height: l_height, AlphaEnable: False})
l_bitmap.Clear(m.ScrBkgClr)
l_bitmap.DrawText(l_headerText, 0, 0, &h000000FF, l_font)
l_region = CreateObject("roRegion", l_bitmap, 0, 0, l_width, l_height)
l_x = int(l_device_rect.w / 2 - l_width / 2)
m.Compositor.NewSprite(l_x, 150, l_region, 1)
l_font = m.DefaultRegistry.GetDefaultFont(32, False, False)
l_footerText = "Use The Page And Arrow Keys To Scroll, Info Key To Toggle Scale/Fade"
l_width = m.FontMedium.GetOneLineWidth( l_footerText, 1000)
l_height = m.FontMedium.GetOneLineHeight()
l_bitmap = CreateObject("roBitmap", {width: l_width, height: l_height, AlphaEnable: False})
l_bitmap.Clear(m.ScrBkgClr)
l_bitmap.DrawText(l_footerText, 0, 0, &h222835FF, m.FontMedium)
l_region = CreateObject("roRegion", l_bitmap, 0, 0, l_width, l_height)
l_x = int(l_device_rect.w / 2 - l_width / 2)
m.Compositor.NewSprite(l_x, l_device_rect.h - 175, l_region, 1)
return
End Function
' Hook up the compositor to the screen and drawall previously
' created above. Poll the message port for input
Function list_view_show() As Void
m.Screen.SetMessagePort(m.Port)
m.Compositor.SetDrawTo(m.Screen, m.ScrBkgClr)
m.DrawAll()
m.EventLoop()
End Function
' The composite creates and maintains sprites. Sprites are based upon
' regions within bitmaps. The region could be the entire bitmap if desired
' The compositor draws all its sprites as defined above.
' It simplifies and optimizes for applications that
' have alot of bitmaps
Function list_view_drawall() As Void
m.Compositor.DrawAll()
m.Screen.SwapBuffers()
End Function
' Slide up/down by offseting the region by rowheight in the desired direction
' You dont have to worry about any bounds as setwrap is true
Function list_view_scroll_line(a_goDown = True As Boolean, a_frames = 16 As Integer) As Void
l_offset = 0
l_offdiff = 0
l_prevset = 0
for l_i = 1 to a_frames
l_offset = int(m.ListRowHeight * l_i / a_frames)
l_offdiff = l_offset - l_prevset
if l_offdiff > 0
if not a_goDown l_offdiff = -l_offdiff
m.BufferRegion.Offset(0, l_offdiff, 0, 0)
m.DrawAll()
l_prevset = l_offset
end if
end for
End Function
' Since the setwrap is on for the bufferregion. You just offset it
' by the page size in either direction and it will wrap itself around
' This paging example does not slide like the rows do but you can
' just use the code above with the l_height variable
Function list_view_scroll_page(a_goDown = True As Boolean) As Void
l_height = m.ListPageSize * m.ListRowHeight
if not a_goDown l_height = -l_height
m.BufferRegion.Offset(0, l_height, 0, 0)
m.DrawAll()
End Function
' This example takes a real-time snapshot of list view to perform its effect
' to do this is pretty easy once you understand it
Function list_view_fade_scale(a_in = True, a_speed = 20 As Integer) As Void
' Alpha enable the screen
l_alphaEnable = m.Screen.GetAlphaEnable()
m.Screen.SetAlphaEnable(True)
' Get background x,y width and height
' The sprite gives the position
' The bitmap (or the reigon if it is created the same size) gives the
' width and height
l_x = m.BackgroundSprite.GetX()
l_y = m.BackgroundSprite.GetY()
l_w = m.BackgroundRegion.GetWidth()
l_h = m.BackgroundRegion.GetHeight()
' Create a temporary clone bitmap the same size and draw the backgrounds region
' into it. Note that the background's region is the same size as the bitmap
' So in this case the bitmap or the region can be used as the source for drawobject
l_cloneBitmap = CreateObject("roBitmap", {width: l_w, height: l_h , AlphaEnable: False})
l_cloneBitmap.DrawObject(0, 0, m.BackgroundRegion)
' Draw the buffer bitmap's region on top of that at the same x, y inset when ititialized.
' Since the region is smaller than the bitmap you would not use the bufferbitmap as a source
l_cloneBitmap.DrawObject(15, 15, m.BufferRegion)
' Create a region into the cloned bitmap that exposes the entire length, width of the bitmap
' Set its scale mode to 1 for best rendering
l_cloneRegion = CreateObject("roRegion", l_cloneBitmap, 0, 0, l_w, l_h)
l_cloneRegion.SetScaleMode(1)
' Now that there is a perfect picture of the current state of the list view
' create a scrap bitmap and have some fun with it. The cloned region will
' be drawn into the scrap bitmap at various scaling/fading percentages
l_scrapBitmap = CreateObject("roBitmap", {width: l_w, height: l_h , AlphaEnable: False})
' Optional - perform the first draw at normal dimensions
l_scrapBitmap.DrawObject(0,0, l_cloneRegion)
' Create a region in the scrap. This is only needed because the compositor requires
' a region to create a sprite
l_region = CreateObject("roRegion", l_scrapBitmap, 0, 0, l_w, l_h)
' Position the scrap bitmap directly over the original sprites
' KEEP the handle you need to explicitly release it or the memory WIL NOT be released
l_sprite = m.Compositor.NewSprite(l_x, l_y, l_region, 3)
' Hide the original sprites
m.BufferSprite.SetZ(-1)
m.BackgroundSprite.SetZ(-1)
' Set up the rgb value.
l_rgb = &hFFFFFF00
' Perform the scale/fade
for l_i = 0 to a_speed
' Just reverse everything when doing the opposite
if a_in
l_scale = l_i / a_speed
else
l_scale = (a_speed - l_i) / a_speed
end if
' Add the alpha percentage to the rgb value
l_rgba = int(255 * l_scale) + l_rgb
' Keep the scaled region centered as it's size changes
' always using the background bitmaps dimensions as a guide
' You could also use the scrap bitmap since its parameters
' are the same but why the extra code
l_x = (l_w - int(l_w * l_scale)) / 2
l_y = (l_h - int(l_h * l_scale)) / 2
' Clear out the old
'Draw int the new region centered in the bitmap with the new scale and fade percentages
l_scrapBitmap.Clear(m.Transparent)
l_scrapBitmap.DrawScaledObject(l_x, l_y, l_scale, l_scale, l_cloneRegion, l_rgba )
' Dump to the screen
m.DrawAll()
end for
' Make sure to REMOVE the clone sprite. Even though everything appears local
' The Compositor is not local and keeps a reference to it. Each time you re-create the
' sprite a new one is actually added (makes sense) quickly consuming memory
' Thankfully somone was sensible enough to let us have r2d2_bitmaps telnet command
' Removing the sprite removes it from the screen as well
l_sprite.Remove()
' reshow the permanent sprite if fading in
if a_in then
m.BackgroundSprite.SetZ(2)
m.BufferSprite.SetZ(3)
m.DrawAll()
end if
' Restore the original value to the screen
m.Screen.SetAlphaEnable(l_alphaEnable)
End Function
' This event loop is primarily for the example. You would want to use
' a timer for more accurate speed regulation. But this does a pretty good job
' I created the timer but I dont use it here. I do in my own code
Function list_view_eventloop() As Void
l_running = True
l_fadeIn = False
l_index = 0
l_lastKey = -1
l_scrollSpeed = 120
l_kp_BK = 0
l_kp_UP = 2
l_kp_DN = 3
l_kp_OK = 6
l_kp_RW = 7
l_kp_REV = 8
l_kp_FWD = 9
l_kp_INFO = 10
l_kp_UP_REL = 102
l_kp_DN_REL = 103
while(l_running)
l_msg = wait(l_scrollSpeed, m.port)
if type(l_msg) = "roUniversalControlEvent"
l_index = l_msg.GetInt()
l_lastKey = l_index
if l_index = l_kp_UP or l_index = l_kp_DN
m.ScrollLine(l_index = l_kp_DN)
else if l_index = l_kp_FWD or l_index = l_kp_REV
m.ScrollPage(l_index = l_kp_FWD)
else if l_index > 100 ' All key ups are value + 100
l_lastKey = -1
l_scrollSpeed = 120
else if l_index = l_kp_BK
l_running = False
else if l_index = l_kp_INFO
m.FadeScale(l_fadeIn)
l_fadeIn = not l_fadeIn
end if
else
if l_lastKey = l_kp_UP or l_lastKey = l_kp_DN
l_scrollSpeed = 5
m.ScrollLine(l_lastKey = l_kp_DN)
end if
end if
end while
End Function
Function GetData() As Object
l_proverbs = [
"Make Your Ear Attentive To Wisdom",
"Incline Your Heart To Understanding",
"Cry Out For Discernment",
"Lift Up Your Voice For Understanding",
"If You Seek Her Like Silver And",
"Search For Her Like Hidden Treasures",
"Then You Will Understand The Fear",
"Of Jehovah And Find The Knowledge Of God",
"For Jehovah Gives Wisdom; From His Mouth",
"Come Knowledge And Understanding",
"He Stores Up Sound Wisdom For The Upright",
"He Is A Shield To Those Who Walk In Integrity",
"Guarding The Paths Of Justice And Keeping",
"The Way Of His Faithful Ones",
]
return l_proverbs
End Function