Sub RunUserInterface()
o = Setup()
o.setup()
o.paint()
o.eventloop()
End Sub
Sub Setup() As Object
this = {
port: CreateObject("roMessagePort")
progress: 0 'buffering progress
position: 0 'playback position (in seconds)
paused: false 'is the video currently paused?
feedData: invalid
playing: 0
playingPrev: 0
playlistSize: 0
canvas: CreateObject("roImageCanvas") 'user interface
player: CreateObject("roVideoPlayer")
load: LoadFeed
setup: SetupFullscreenCanvas
paint: PaintFullscreenCanvas
create_playlist_text: CreatePlaylistText
drawtext: false
eventloop: EventLoop
}
this.targetRect = this.canvas.GetCanvasRect()
this.textRect = {x: 520, y: 480, w: 300, h:200}
this.load()
'Setup image canvas:
this.canvas.SetMessagePort(this.port)
this.canvas.SetLayer(0, { Color: "#000000" })
this.canvas.Show()
this.player.SetMessagePort(this.port)
this.player.SetLoop(true)
this.player.SetPositionNotificationPeriod(1)
this.player.SetDestinationRect(this.targetRect)
this.player.Play()
this.playingPrev = this.playing
return this
End Sub
Sub EventLoop()
while true
msg = wait(0, m.port)
if msg <> invalid
if msg.isStatusMessage() and msg.GetMessage() = "startup progress"
m.paused = false
print "Raw progress: " + stri(msg.GetIndex())
progress% = msg.GetIndex() / 10
if m.progress <> progress%
m.progress = progress%
m.paint()
end if
'Playback progress (in seconds):
else if msg.isPlaybackPosition()
m.position = msg.GetIndex()
print "Playback position: " + stri(m.position)
else if msg.isRemoteKeyPressed()
index = msg.GetIndex()
print "Remote button pressed: " + index.tostr()
if index = 4 '<LEFT>
m.playing = m.playing - 1
if (m.playing < 0)
m.playing = 2
endif
m.player.SetNext(m.playing)
m.player.Play()
m.playingPrev = m.playing
else if index = 8 '<REV>
m.position = m.position - 60
m.player.Seek(m.position * 1000)
else if index = 5 '<RIGHT>
m.playing = m.playing + 1
if (m.playing > 2)
m.playing = 0
endif
m.player.SetNext(m.playing)
m.player.Play()
m.playingPrev = m.playing
else if index = 9 '<REV>
m.position = m.position + 60
m.player.Seek(m.position * 1000)
else if index = 2 '<Up>
if m.drawtext
m.playing = m.playing - 1
if (m.playing < 0)
m.playing = m.playlistSize-1
endif
m.paint()
endif
else if index = 3 '<Down>
if m.drawtext
m.playing = m.playing + 1
if (m.playing > m.playlistSize-1)
m.playing = 0
endif
m.paint()
endif
else if index = 13 '<PAUSE/PLAY>
if m.paused m.player.Resume() else m.player.Pause()
else if index = 6 'OK
if m.drawtext
m.drawtext = false
if m.playing <> m.playingPrev
m.player.SetNext(m.playing)
m.player.Play()
m.playingPrev = m.playing
endif
else
m.drawtext = true
endif
m.paint()
end if
else if msg.isPaused()
m.paused = true
m.paint()
else if msg.isResumed()
m.paused = false
m.paint()
end if
endif
end while
End Sub
Sub SetupFullscreenCanvas()
m.canvas.AllowUpdates(false)
m.paint()
m.canvas.AllowUpdates(true)
End Sub
Sub PaintFullscreenCanvas()
splash = []
list = []
if m.progress < 100
progress_bar = {TargetRect: {x: 350, y: 500, w: 598, h: 37}, url: "pkg:/images/progress_bar.png"}
color = "#00a0a0a0"
splash.Push({
url: "pkg:/images/splash.png"
TargetRect: m.targetRect
})
list.Push({
Text: "Loading..."
TextAttrs: { font: "large", color: "#707070" }
TargetRect: m.textRect
})
if m.progress >= 0 AND m.progress < 20
progress_bar.url = "pkg:/images/progress_bar_1.png"
print progress_bar.url
else if m.progress >= 20 AND m.progress < 40
progress_bar.url = "pkg:/images/progress_bar_2.png"
print progress_bar.url
else if m.progress >= 40 AND m.progress < 75
progress_bar.url = "pkg:/images/progress_bar_3.png"
print progress_bar.url
else
progress_bar.url = "pkg:/images/progress_bar_4.png"
print progress_bar.url
endif
list.Push(progress_bar)
end if
if m.drawtext
textArr = m.create_playlist_text()
yTxt = 100
color = "#00000000"
index = 0
for each str in textArr
if index = m.playing
textColor = "#00ff00"
else
textColor = "#dddddd"
endif
list.Push({
Text: str
TextAttrs: {color: textColor, font: "medium"}
TargetRect: {x:200, y:yTxt, w: 500, h: 100}
})
yTxt = yTxt + 100
index = index + 1
end for
else
color = "#00000000"
list.Push({
Text: ""
TextAttrs: {font: "medium"}
TargetRect: {x:100, y:600, w: 300, h: 100}
})
endif
'Clear previous contents
m.canvas.ClearLayer(0)
m.canvas.ClearLayer(1)
m.canvas.ClearLayer(2)
m.canvas.SetLayer(0, { Color: color, CompositionMode: "Source" })
if (splash.Count() > 0)
m.canvas.SetLayer(1, splash)
m.canvas.SetLayer(2, list)
else
m.canvas.SetLayer(1, list)
endif
list.Clear()
splash.Clear()
End Sub
Function LoadFeed() as void
jsonAsString = ReadAsciiFile("pkg:/json/feed.json")
m.feedData = ParseJSON(jsonAsString)
m.playlistSize = m.feedData.Videos.Count()
contentList = []
for each video in m.feedData.Videos
contentList.Push({
Stream: { url: video.url }
StreamFormat: "mp4"
})
end for
m.player.SetContentList(contentList)
End Function
Function CreatePlaylistText() as object
textArr = []
for each video in m.feedData.Videos
textArr.Push(video.title)
end for
return textArr
End Function
' Example of wrap-around menu. Since you really don't have exact metrics,
' unless you want to use the depreciated roFontMetrics or a work-around you have to experiment
' with the height of each row based upon the font size ( medium, small ) and the alignment meta-data properties
' the usual buttons operate up/dn fw/rw for paging, can also hold the buttons down for continuous movement
Sub Main()
' Constants for isRemoteKeyPressed
kp_BK = 0
kp_UP = 2
kp_DN = 3
kp_LT = 4
kp_RT = 5
kp_OK = 6
kp_RW = 8
kp_FW = 9
' The color of the imagecanvas - of course you just need to use your own canvas
backL = 0
back = { Color:"#262626", CompositionMode: "Source" }
' Create the canvas, port and set the color of the imagecanvas
canvas = CreateObject( "roImageCanvas" )
port = CreateObject( "roMessagePort" )
canvas.SetMessagePort(port)
canvas.SetLayer( backL, back )
' Create the menu component. I strongly suggest you learn how to use AA to encapsulate a component or other
' data. Its not that hard, actually we use it all the time but don't realize it. I see that you are using
' it yourself so this should not be a problem
' Instantiate and create the menu passing a reference to your canvas, it will store it and use it
' You will need to go into the canvas.create and change the properties to place and size it according to your data
menu = NewMenu( canvas )
' Must call create before using any of its methods. Pass a reference to your data, if its more than an array of strings you will have to make the adjustments
menu.Create( GetData() )
' Show the canvas
canvas.Show()
' Unlike roScreen, when you hold down the buttons here, there is a continuous sending of the
' keydown ( at least there is with ROKU 3 firmware 7 ), you never know whats going to happen
' there are a few bugs across devices with the new update. You write it today, its broken tomorrow
' And you never know when your going to get those "sounds", up/down you dont but fw and rw you do
while( True )
msg = wait( 0, port )
if ( type( msg ) = "roImageCanvasEvent" )
if ( msg.isRemoteKeyPressed() )
i = msg.GetIndex()
' All you have to do is use the members of the menu component to scroll
' when the proper buttons are pressed. up/dn moves the selector first
' if the selector is up against the top or bottom rows, then the menu scrolls and
' the selector is updated
' For paging, an entire page is redrawn
if (i = kp_BK ) then
canvas.close()
else if ( i = kp_DN )
menu.ScrollDown()
else if ( i = kp_UP )
menu.ScrollUp()
else if ( i = kp_FW )
menu.PageDown()
else if ( i = kp_RW )
menu.PageUp()
else if( i = kp_OK )
print menu.GetText()
end if
else if (msg.isScreenClosed()) then
return
end if
end if
end while
End Sub
' The menu component is designed using an Associative Array
' To instantiate an instance var = NewManu() passing a reference to your canvas
Function NewMenu( a_canvas As Object ) As Object
return {
' Reference to the created image canvas
Canvas: a_canvas
' Reference to the Array of data, if you need to include description text or anything else
' then make this an array of AA { Text: text Description: desc } m.Data[ IndexTop ].Text
Data: Invalid
' The number of items in Data
DataCount: 0
' The row the the selector is on ( indexTop to IndexBot
RowIndex: 0
' The selectors text index within Data
FocusIndex: 0
' Top and bottom indexes of the menu ( what is displayed on the first line and last line
IndexTop: 0
IndexBot: 0
' Offset from the sides of the backgound of the menu
Margin: 0
' The height of each row, you have to set this according to how much space you want
' between rows, and the size of your text
RowHeight: 0'
' Number of visible rows in the menu
PageSize: 0
' RowHeight * PageSize = the menu height
PageHeight: 0
' Meta-data for the menu backgound and selector background
MenuBkg: Invalid
SelBkg: Invalid
' Meta-data for the text displayed in the menu,
' this is an array of PageSize. As the user scrolls it is updated
MenuText: Invalid
' The single line of text over the selector that changes as the user scrolls
SelText: Invalid
' Layer constants
menuL: 2
menuTL: 3
menuSL: 4
menuSTL: 5
' Functions that act upon the data above using the m pointer
' Creates the menu component
Create: menu_create
' Draws/redraws a page of data
DrawPage: menu_draw_page
' The scrolling and paging functions
ScrollUp: menu_scroll_up
ScrollDown: menu_scroll_down
PageDown: menu_page_down
PageUp: menu_page_up
GetText: menu_get_text
}
End Function
' The menu's create function MUST be called before calling any other functions - NO error checking is done
' Pass in the data - can be a complex data type (AA) but you would have to modify the code to assign
' the proper field
Function menu_create( a_data As Object ) As Void
' Store a reference to data
m.Data = a_data
' The total count of data and the page size is set to 12 rows, you can change this to what you want
m.DataCount = m.Data.count()
m.PageSize = 12
' Insure the pagesize is within range
if ( m.PageSize > m.DataCount ) then m.PageSize = m.DataCount
' The margin is the space that borders the menu so that the menu text is not flushed against the edges
m.Margin = 5
' This is the height that I use for the Medium font, you have to adjust to your own font size
' You will also have to adjust the text metadata alignment properties to get it to center properly
m.RowHeight = 45
' So then the pageHeight or menu Height would be te following:
m.PageHeight = m.RowHeight * m.PageSize + m.Margin * 2
' This is the menu rectangle you adjust this according to your own needs
' its width would have to accomodate your largest text width and the height is
' determined by how many rows you are going to display. the x, y is where you want it in your canvas
mr = { x: 100, y: 90, w: 295, h: m.PageHeight }
' The selector rectangle ( blue ) rides above each row so it is the same except for the height
' which is only one row
sr = { x: mr.x, y: mr.y + m.Margin, w: mr.w, h: m.RowHeight }
' Set your meta-data for the layers
' Menu menu background
m.menuBkg = {
Color: "#353535"
TargetRect: mr
CompositionMode: "Source" }
' Selector background
m.SelBkg = {
Color: "#436372"
TargetRect: sr
CompositionMode:"Source" }
' The menu text is an array of meta data just for the text that sits
' on top of the menu backgound. So it will be the pagesize of the menu
m.menuText = CreateObject( "roArray", m.PageSize, False )
' Since The menu backgound is a different color from the canvas background
' I don't want the text to start at the edges so I'm going to offset the text
x = mr.x + m.Margin * 3
y = mr.y + m.Margin * 2
' The width is the menu width
w = mr.w
' And the text height is the row height. For h and ta you have to experiment with the size and alignment
' if you change the font size. with the medium font, 45 height and VAlign it is centered properly
h = m.RowHeight
' This is static so just create a variable for it.
ta = { Color: "#707070", Font: "Medium", HAlign:"Left",
VAlign: "Top", Direction: "LeftToRight" }
' Now create a text meta-data for each row in the page and store it into the menuText array
for i = 1 to m.PageSize
mt = {
Text: ""
TargetRect: { x: x , y: y , w: w, h: h }
TextAttrs: ta
CompositionMode: "Source"
}
m.menuText.Push( mt )
' Increment y by the row height
y = y + h
end for
' The selection text is only one row
m.SelText = {
Text: ""
TargetRect: { x: x , y: mr.y + m.Margin * 2, w: w, h: h }
TextAttrs: { Color: "#FFFFFF", Font: "Medium", HAlign:"Left",
VAlign: "Top", Direction: "LeftToRight"}
CompositionMode: "Source"
}
' These are the controlling indexes for the scrolling and
' paging functions
m.IndexTop = 0
m.IndexBot = 0
' This index keeps tract of the row in the menu that the selector is on
m.RowIndex = 0
' This index keeps tract of the text that is in the selector
m.FocusIndex = 0
' Call DrawPage to setup the first page, with false ( dont want it to redraw the canvas here )
' That will be done with the initial showing of the canvas
m.DrawPage( False )
' Then finally, set your layers
' Menu Background - If you do this some other way ( after showing the canvas ) you will have to
' turn off the AllowUpdates
m.canvas.SetLayer( m.menuL , m.menuBkg )
' The complete page of text over the background
m.canvas.SetLayer( m.menuTL, m.menuText )
' The selector background
m.canvas.SetLayer( m.menuSL, m.SelBkg )
' And finally the selectors text
m.canvas.SetLayer( m.menuSTL, m.SelText )
End Function
' Returns the selected text
Function menu_get_text() As String
return m.SelText.Text
End Function
' refresh menu meta data to index of user input
Function menu_draw_page( a_update = True As Boolean ) As Void
' I generally simplify references as I really do not know
' if it provides any optimization, but being a geriatric-programmer 🙂
' I come from environments where it did, especially in loops
menuText = m.MenuText
data = m.Data
index = m.IndexTop
count = m.DataCount
' So based upon where the indextop is
' you begin to draw from the top down, starting at
' indexTop ( index = m.IndexTop ), which is calculated in the
' scrolling functions below. Just wrap around if it reaches the bottom
for i = 0 to m.PageSize - 1
menuText[i].Text = data[ index ]
index = index + 1
if ( index >= count ) then index = 0
end for
' Then recalc the bottom index , or the row at the bottom of the menu
index = index - 1
if ( index < 0 ) then index = count - 1
m.IndexBot = index
' Adjust the focus index allowing for wrap-around
' and set the new selected text
index = m.RowIndex + m.IndexTop
if ( index >= count ) then index = index - count
m.FocusIndex = index
m.SelText.Text = data[ index ]
' if a_update is True (default) then update the canvas
if ( a_update )
iCanvas = m.Canvas
iCanvas.AllowUpdates( False )
iCanvas.SetLayer( m.menuTL, menuText )
iCanvas.SetLayer( m.menuSTL, m.SelText )
iCanvas.AllowUpdates( True )
end if
End Function
' Scrolls down one row
Function menu_scroll_down() As Void
' If the selector is not at the bottom
if ( m.RowIndex < m.PageSize - 1 )
' Increment its row
m.RowIndex = m.RowIndex + 1
' Increment the selector's text focusindex, wrap-around if needed
index = m.FocusIndex + 1
if ( index >= m.DataCount ) then index = 0
m.FocusIndex = index
' Change the meta-data
m.SelText.Text = m.Data[ index ]
tRect = m.SelBkg.TargetRect
tRect.y = tRect.y + m.RowHeight
tRect = m.SelText.TargetRect
tRect.y = tRect.y + m.RowHeight
' Redraw the layers and return
iCanvas = m.Canvas
iCanvas.AllowUpdates( False )
iCanvas.SetLayer( m.menuSL, m.SelBkg )
iCanvas.SetLayer( m.menuSTL, m.SelText )
iCanvas.AllowUpdates( True )
return
end if
' Otherwise the selector is at the bottom
' so increase the top index by one and redraw the page
' the Focusindex will be handled in DrawPage. It does not move just
' changes its text
m.IndexTop = m.IndexTop + 1
if ( m.IndexTop >= m.DataCount ) then m.IndexTop = 0
m.DrawPage()
End Function
' Same as above only going in the opposite direction
Function menu_scroll_up() As Void
if ( m.RowIndex > 0 )
m.RowIndex = m.RowIndex - 1
index = m.FocusIndex - 1
if ( index < 0 ) then index = m.DataCount - 1
m.FocusIndex = index
m.SelText.Text = m.Data[ index ]
tRect = m.SelBkg.TargetRect
tRect.y = tRect.y - m.RowHeight
tRect = m.SelText.TargetRect
tRect.y = tRect.y - m.RowHeight
iCanvas = m.Canvas
iCanvas.AllowUpdates( False )
iCanvas.SetLayer( m.menuSL, m.SelBkg )
iCanvas.SetLayer( m.menuSTL, m.SelText )
iCanvas.AllowUpdates( True )
return
end if
' Selector is at the top so scroll up
m.IndexTop = m.IndexTop - 1
if ( m.IndexTop < 0 ) then m.IndexTop = m.DataCount - 1
m.DrawPage()
End Function
' Paging down - use the bottom index as the reference point
' to change the top index, wrap around if needed and redraw the page
' the focusindex will be updated in drawpage
Function menu_page_down() As Void
index = m.IndexBot + 1
if ( index >= m.DataCount ) then index = 0
m.IndexTop = index
m.DrawPage()
End Function
' When moving back a page you decrement the top index by the page size
' Wrap around correctly if needed, set the new TopIndex and redraw the page
Function menu_page_up() As Void
index = m.IndexTop - m.PageSize
if ( index < 0 ) then index = m.DataCount + index
m.IndexTop = index
m.DrawPage()
End Function
' Get sample data - just returns strings here but you can return
' anything just make sure you make the changes when assigning the Text to the correct field
Function GetData() As Object
l_data = []
for l_i = 1 to 200
l_text = l_i.ToStr()
if ( l_i < 100 )
if ( l_i < 10 )
l_text = "00" + l_text
else
l_text = "0" + l_text
end if
end if
l_text = "Menu Item Number " + l_text
l_data.Push( l_text )
end for
return l_data
End Function
' Example of wrap-around menu. Since you really don't have exact metrics,
' unless you want to use the depreciated roFontMetrics or a work-around you have to experiment
' with the height of each row based upon the font size ( medium, small ) and the alignment meta-data properties
' the usual buttons operate up/dn fw/rw for paging, can also hold the buttons down for continuous movement
Sub Main()
' Constants for isRemoteKeyPressed
kp_BK = 0
kp_UP = 2
kp_DN = 3
kp_LT = 4
kp_RT = 5
kp_OK = 6
kp_RW = 8
kp_FW = 9
' The color of the imagecanvas - of course you just need to use your own canvas
backL = 0
back = { Color:"#262626", CompositionMode: "Source" }
' Create the canvas, port and set the color of the imagecanvas
canvas = CreateObject( "roImageCanvas" )
port = CreateObject( "roMessagePort" )
canvas.SetMessagePort(port)
canvas.SetLayer( backL, back )
' Create the menu component. I strongly suggest you learn how to use AA to encapsulate a component or other
' data. Its not that hard, actually we use it all the time but don't realize it. I see that you are using
' it yourself so this should not be a problem
' Instantiate and create the menu passing a reference to your canvas, it will store it and use it
' You will need to go into the canvas.create and change the properties to place and size it according to your data
menu = NewMenu( canvas )
' Must call create before using any of its methods. Pass a reference to your data, if its more than an array of strings you will have to make the adjustments
menu.Create( GetData() )
' Show the canvas
canvas.Show()
' Unlike roScreen, when you hold down the buttons here, there is a continuous sending of the
' keydown ( at least there is with ROKU 3 firmware 7 ), you never know whats going to happen
' there are a few bugs across devices with the new update. You write it today, its broken tomorrow
' And you never know when your going to get those "sounds", up/down you dont but fw and rw you do
while( True )
msg = wait( 0, port )
if ( type( msg ) = "roImageCanvasEvent" )
if ( msg.isRemoteKeyPressed() )
i = msg.GetIndex()
' All you have to do is use the members of the menu component to scroll
' when the proper buttons are pressed. up/dn moves the selector first
' if the selector is up against the top or bottom rows, then the menu scrolls and
' the selector is updated
' For paging, an entire page is redrawn
if (i = kp_BK ) then
canvas.close()
else if ( i = kp_DN )
menu.ScrollDown()
else if ( i = kp_UP )
menu.ScrollUp()
else if ( i = kp_FW )
menu.PageDown()
else if ( i = kp_RW )
menu.PageUp()
else if( i = kp_OK )
print menu.GetText()
end if
else if (msg.isScreenClosed()) then
return
end if
end if
end while
End Sub
' The menu component is designed using an Associative Array
' To instantiate an instance var = NewManu() passing a reference to your canvas
Function NewMenu( a_canvas As Object ) As Object
return {
' Reference to the created image canvas
Canvas: a_canvas
' Reference to the Array of data, if you need to include description text or anything else
' then make this an array of AA { Text: text Description: desc } m.Data[ IndexTop ].Text
Data: Invalid
' The number of items in Data
DataCount: 0
' The row the the selector is on
RowIndex: 0
' Data index of first line in menu
IndexTop: 0
' Offset from the sides of the backgound of the menu
Margin: 0
' The height of each row, you have to set this according to how much space you want
' between rows, and the size of your text
RowHeight: 0'
' Number of visible rows in the menu
PageSize: 0
' RowHeight * PageSize = the menu height
PageHeight: 0
' Meta-data for the menu backgound and selector background
MenuBkg: Invalid
SelBkg: Invalid
' Meta-data for the text displayed in the menu,
' this is an array of PageSize. As the user scrolls it is updated
MenuText: Invalid
' The single line of text over the selector that changes as the user scrolls
SelText: Invalid
' Layer constants
menuL: 2
menuTL: 3
menuSL: 4
menuSTL: 5
' Functions that act upon the data above using the m pointer
' Creates the menu component
Create: menu_create
' Draws/redraws a page of data
DrawPage: menu_draw_page
' The scrolling and paging functions
ScrollUp: menu_scroll_up
ScrollDown: menu_scroll_down
PageDown: menu_page_down
PageUp: menu_page_up
GetText: menu_get_text
}
End Function
' The menu's create function MUST be called before calling any other functions - NO error checking is done
' Pass in the data - can be a complex data type (AA) but you would have to modify the code to assign
' the proper field
Function menu_create( a_data As Object ) As Void
' Store a reference to data
m.Data = a_data
' The total count of data and the page size is set to 12 rows, you can change this to what you want
m.DataCount = m.Data.count()
m.PageSize = 12
' Insure the pagesize is within range
if ( m.PageSize > m.DataCount ) then m.PageSize = m.DataCount
' The margin is the space that borders the menu so that the menu text is not flushed against the edges
m.Margin = 5
' This is the height that I use for the Medium font, you have to adjust to your own font size
' You will also have to adjust the text metadata alignment properties to get it to center properly
m.RowHeight = 45
' So then the pageHeight or menu Height would be te following:
m.PageHeight = m.RowHeight * m.PageSize + m.Margin * 2
' This is the menu rectangle you adjust this according to your own needs
' its width would have to accomodate your largest text width and the height is
' determined by how many rows you are going to display. the x, y is where you want it in your canvas
mr = { x: 100, y: 90, w: 295, h: m.PageHeight }
' The selector rectangle ( blue ) rides above each row so it is the same except for the height
' which is only one row
sr = { x: mr.x, y: mr.y + m.Margin, w: mr.w, h: m.RowHeight }
' Set your meta-data for the layers
' Menu menu background
m.menuBkg = {
Color: "#353535"
TargetRect: mr
CompositionMode: "Source" }
' Selector background
m.SelBkg = {
Color: "#436372"
TargetRect: sr
CompositionMode:"Source" }
' The menu text is an array of meta data just for the text that sits
' on top of the menu backgound. So it will be the pagesize of the menu
m.menuText = CreateObject( "roArray", m.PageSize, False )
' Since The menu backgound is a different color from the canvas background
' I don't want the text to start at the edges so I'm going to offset the text
x = mr.x + m.Margin * 3
y = mr.y + m.Margin * 2
' The width is the menu width
w = mr.w
' And the text height is the row height. For h and ta you have to experiment with the size and alignment
' if you change the font size. with the medium font, 45 height and VAlign it is centered properly
h = m.RowHeight
' This is static so just create a variable for it.
ta = { Color: "#707070", Font: "Medium", HAlign:"Left",
VAlign: "Top", Direction: "LeftToRight" }
' Now create a text meta-data for each row in the page and store it into the menuText array
for i = 1 to m.PageSize
mt = {
Text: ""
TargetRect: { x: x , y: y , w: w, h: h }
TextAttrs: ta
CompositionMode: "Source"
}
m.menuText.Push( mt )
' Increment y by the row height
y = y + h
end for
' The selection text is only one row
m.SelText = {
Text: ""
TargetRect: { x: x , y: mr.y + m.Margin * 2, w: w, h: h }
TextAttrs: { Color: "#FFFFFF", Font: "Medium", HAlign:"Left",
VAlign: "Top", Direction: "LeftToRight"}
CompositionMode: "Source"
}
' These are the controlling indexes for the scrolling and
' paging functions
m.IndexTop = 0
' This index keeps tract of the row in the menu that the selector is on
m.RowIndex = 0
' Call DrawPage to setup the first page, with false ( dont want it to redraw the canvas here )
' That will be done with the initial showing of the canvas
m.DrawPage( False )
' Then finally, set your layers
' Menu Background - If you do this some other way ( after showing the canvas ) you will have to
' turn off the AllowUpdates
m.canvas.SetLayer( m.menuL , m.menuBkg )
' The complete page of text over the background
m.canvas.SetLayer( m.menuTL, m.menuText )
' The selector background
m.canvas.SetLayer( m.menuSL, m.SelBkg )
' And finally the selectors text
m.canvas.SetLayer( m.menuSTL, m.SelText )
End Function
' Returns the selected text
Function menu_get_text() As String
return m.SelText.Text
End Function
' refresh menu meta data to index of user input
Function menu_draw_page( a_update = True As Boolean ) As Void
' I generally simplify references as I really do not know
' if it provides any optimization, but being a geriatric-programmer 🙂
' I come from environments where it did, especially in loops
menuText = m.MenuText
data = m.Data
index = m.IndexTop
count = m.DataCount
' So based upon where the indextop is
' you begin to draw from the top down, starting at
' indexTop ( index = m.IndexTop ), which is calculated in the
' scrolling functions below. Just wrap around if it reaches the bottom
for each item in menuText
item.Text = data[ index ]
index = index + 1
if ( index >= count ) then index = 0
end for
' Adjust the focus index allowing for wrap-around
' and set the new selected text
index = m.RowIndex + m.IndexTop
if ( index >= count ) then index = index - count
m.SelText.Text = data[ index ]
' if a_update is True (default) then update the canvas
if ( a_update )
iCanvas = m.Canvas
iCanvas.AllowUpdates( False )
iCanvas.SetLayer( m.menuTL, menuText )
iCanvas.SetLayer( m.menuSTL, m.SelText )
iCanvas.AllowUpdates( True )
end if
End Function
' Scrolls down one row
Function menu_scroll_down() As Void
' If the selector is not at the bottom
if ( m.RowIndex < m.PageSize - 1 )
' Increment its row
m.RowIndex = m.RowIndex + 1
' Calculate the focus index
index = m.RowIndex + m.IndexTop
if ( index >= m.DataCount ) then index = index - m.DataCount
m.SelText.Text = m.Data[ index ]
' Change the meta-data
tRect = m.SelBkg.TargetRect
tRect.y = tRect.y + m.RowHeight
tRect = m.SelText.TargetRect
tRect.y = tRect.y + m.RowHeight
' Redraw the layers and return
iCanvas = m.Canvas
iCanvas.AllowUpdates( False )
iCanvas.SetLayer( m.menuSL, m.SelBkg )
iCanvas.SetLayer( m.menuSTL, m.SelText )
iCanvas.AllowUpdates( True )
return
end if
' Otherwise the selector is at the bottom
' so increase the top index by one and redraw the page
' the Focus index will be handled in DrawPage. It does not move just
' changes its text
m.IndexTop = m.IndexTop + 1
if ( m.IndexTop >= m.DataCount ) then m.IndexTop = 0
m.DrawPage()
End Function
' Same as above only going in the opposite direction
Function menu_scroll_up() As Void
if ( m.RowIndex > 0 )
m.RowIndex = m.RowIndex - 1
index = m.RowIndex + m.IndexTop
if ( index >= m.DataCount ) then index = index - m.DataCount
m.SelText.Text = m.Data[ index ]
tRect = m.SelBkg.TargetRect
tRect.y = tRect.y - m.RowHeight
tRect = m.SelText.TargetRect
tRect.y = tRect.y - m.RowHeight
iCanvas = m.Canvas
iCanvas.AllowUpdates( False )
iCanvas.SetLayer( m.menuSL, m.SelBkg )
iCanvas.SetLayer( m.menuSTL, m.SelText )
iCanvas.AllowUpdates( True )
return
end if
' Selector is at the top so scroll up
m.IndexTop = m.IndexTop - 1
if ( m.IndexTop < 0 ) then m.IndexTop = m.DataCount - 1
m.DrawPage()
End Function
'Paging down woulb be the top index + page size, corrected for wrap around
Function menu_page_down() As Void
index = m.IndexTop + m.PageSize
if ( index >= m.DataCount ) then index = index - m.DataCount
m.IndexTop = index
m.DrawPage()
End Function
' When moving back a page you decrement the top index by the page size
' Wrap around correctly if needed, set the new TopIndex and redraw the page
Function menu_page_up() As Void
index = m.IndexTop - m.PageSize
if ( index < 0 ) then index = m.DataCount + index
m.IndexTop = index
m.DrawPage()
End Function
' Get sample data - just returns strings here but you can return
' anything just make sure you make the changes when assigning the Text to the correct field
Function GetData() As Object
l_data = []
for l_i = 1 to 200
l_text = l_i.ToStr()
if ( l_i < 100 )
if ( l_i < 10 )
l_text = "00" + l_text
else
l_text = "0" + l_text
end if
end if
l_text = "Menu Item Number " + l_text
l_data.Push( l_text )
end for
return l_data
End Function