Understanding Carousel and User Designed Controls in Visual LANSA V13

Date:31 January 2013
Product/Release:Visual LANSA V13
Abstract:An example of Carousel and User Designed Controls usage in Visual LANSA V13
Submitted By:LANSA Technical Support

Many modern user interfaces have gone far beyond showing simple columnar lists and instead use free format panels of information, images, or both. Ebay item listings and iTunes album view are both great examples of this. Rather than the user seeing a long list of names, controls such as carousel can allow a user to browse through data visually

Example Carousel Screen

Given the requirements, it is no longer possible for a predefined control to match the needs of the developer. Even something as simple as a carousel item is almost endlessly configurable and control has to be handed over to the developer to determine how each of the panels will appear.

User Designed Controls (UDC):

Carousel (prim_caro) is one of a number of new DirectX controls in version 13, which, along with Book (prim_book) , Tree (prim_tree) and Tile (prim_tile), address the growing need for greater interface flexibility. Developers still want the power and simplicity of LANSA’s list handling, but, to incorporate the rise of touch enabled devices and Windows 8, also need their screen designs to go far beyond the strictures put in place by tradition controls such as Tree view (prim_trvw).
UDCs act just like lists, supporting Add_Entry, SelectList and the other typical list commands. However, instead of the control determining the appearance of each item and the columns of the list determing the fields, the developer is free to create a design, or many different designs, to be added to the control, using whatever fields are required. When an entry is added to the control, an instance of the design is created and populated with the fields based on the current values.
The reusable part acting as the design for the UDC needs to implement a specific interface.

Begin_Com Role(*EXTENDS #Prim_panl *Implements #Prim_caro.ICarouselDesign *ListFields #ListFields)
Group_By Name(#ListFields) Fields(#Givename #Surname #Empimg #Empno)

This allows the UDC to communicate with the design instances at runtime, allowing them to respond to a change of Focus or Selection. Each UDC has its own design interface (prim_tile.iTileDesign, prim_tree.iTreeDesign etc.),
When the Carousel is defined, the design reusable part is specified on the Define_com. This is enough for Visual LANSA to be able to hook up the necessary fields and manage the underlying list.

Define_Com Class(#prim_caro<#CarouselDesign>) Name(#UDCCarousel)

This simple pattern is repeated on all UDCs with a control having a design and many instances of the design being created at runtime as entries are added. However, because of this, there is an overhead to using a UDC. Creating many component instances is relatively expensive, and UDCs are best suited to UIs that are high graphical but show a relatively small amounts of data per screen. For high volume scenarios, other techniques are recommended.

Example:

The following example is a simple form that uses a carousel and a track bar for navigation. You will need the demonstration materials and it is assumed the partition has long name support.

Firstly, create a reusable part called CarouselDesign and copy the code below. This will act as the design for each of the items.

Function Options(*DIRECT)
Begin_Com Role(*EXTENDS #XDXBasePanel *implements #Prim_caro.ICarouselDesign *ListFields #ListFields) Height(341) Layoutmanager(#Layout) Width(307)

* Fields mapped in when the entry is added to the Book
Group_By Name(#ListFields) Fields(#Givename #Surname #Empimg #Empno)

Define_Com Class(#Prim_atlm) Name(#Layout)
Define_Com Class(#Prim_atli) Name(#LayoutItem) Attachment(Center) Manage(#Content) Marginbottom(2) Marginleft(20) Marginright(20) Margintop(12) Parent(#Layout)
Define_Com Class(#Prim_atli) Name(#LayoutItemBG) Attachment(Center) Manage(#Background) Parent(#Layout)
Define_Com Class(#PRIM_ATLI) Name(#LayoutItemCaption) Attachment(Bottom) Manage(#Name) Marginbottom(12) Marginleft(20) Marginright(20) Margintop(2) Parent(#Layout)

Define_Com Class(#PRIM_Panl) Name(#Background) Displayposition(1) Height(341) Layoutmanager(#Layout) Left(0) Parent(#COM_OWNER) Tabposition(1) Tabstop(False) Top(0) Width(307)

Define_Com Class(#PRIM_Panl) Name(#Content) Displayposition(1) Height(263) Left(20) Parent(#Background) Style(#ContentStyle) Tabposition(1) Tabstop(False) Top(12) Width(267)
Define_Com Class(#prim_labl) Name(#Name) Alignment(Center) Caption('Employee Name') Displayposition(2) Left(20) Parent(#Background) Style(#LargeText) Tabposition(2) Tabstop(False) Top(279) Verticalalignment(Center) Width(267)

Define_Com Class(#prim_vs.Style) Name(#ContentStyle) Backgroundbrush(#ContentBrush)
Define_Com Class(#prim_vs.ImageBrush) Name(#ContentBrush) Sizing(BestFit)

Define_Com Class(#prim_vs.Style) Name(#LargeText) Fontsize(14)

Define_Com Class(#Prim_bmp) Name(#Image) Reference(*Dynamic)

Mthroutine Name(OnAdd) Options(*redefine)

#Com_owner.Opacity := 30

#Com_owner.Cursor <= #sys_appln.Cursors<Hand>

#Name := ("&1 &2 (&3)").Substitute( #GiveName #Surname #Empno )

* A panel with an image brush is a better technique than simply using an image control.
* DirectX has inbuilt mechanisms that handle images extremely well.

#Image <= #sys_appln.CreateBitmap
#Image.FileName := #Empimg.FileName
#ContentBrush.Image <= #Image

Endroutine

Mthroutine Name(onItemGotFocus) Options(*Redefine)

#Com_owner.Opacity := 100

Endroutine

Mthroutine Name(onItemLostFocus) Options(*Redefine)

#Com_owner.Opacity := 30

Endroutine

End_Com

Secondly, create a new form called Carousel and copy the code below. This defines the carousel and the design that it will use. Compile both and execute the form, ensuring that you execute as DirectX.

Once you’ve seen it run, execute again in debug to see how the design instances are created and how they react with focus change.

Function Options(*DIRECT)
Begin_Com Role(*EXTENDS #PRIM_FORM) Caption('Carousel') Clientheight(492) Clientwidth(890) Height(530) Layoutmanager(#Layout) Left(114) Style(#Background) Top(208) Width(906)

* User Designed Control - Carousel
* Individual items are made by adding entries as per typical LANSA list processing
* Fields in the list are defined by the *ListFields parameter of the Design being made

* Prim_caro defines the carousel
* #CarouselDesign defines the appearance of the items created
Define_Com Class(#prim_caro<#CarouselDesign>) Name(#UDCCarousel) Displayposition(1) Height(442) Left(0) Navigationstyle(None) Parent(#COM_OWNER) Tabposition(1) Top(0) Width(890)

* Trackbar used to navigate through the carousel
Define_Com Class(#prim_tkbr) Name(#TrackBar) Displayposition(2) Left(20) Parent(#COM_OWNER) Tabposition(2) Tickstyle(None) Top(442) Value(1) Width(850)

Define_Com Class(#prim_atlm) Name(#Layout)
Define_Com Class(#PRIM_ATLI) Name(#ATLI_1) Attachment(Center) Manage(#UDCCarousel) Parent(#Layout)
Define_Com Class(#PRIM_ATLI) Name(#ATLI_2) Attachment(Bottom) Manage(#TrackBar) Marginleft(20) Marginright(20) Parent(#Layout)

Define_Com Class(#Prim_timr) Name(#TrackBarTimer) Interval(300)

* Simple white background - Defined locally for simplicity
* Styles are best defined as part of a Visual Style.
Define_Com Class(#prim_vs.style) Name(#Background) Normbackcolor(White)

Evtroutine Handling(#Com_owner.CreateInstance)

#TrackBarTimer.Stop

#Com_owner.Load

Endroutine

Mthroutine Name(Load) Help("Create carousel items") Access(*Private)

* Create Carousel Items
Select Fields(#Surname #Givename #empno) From_File(pslmst)

Fetch Fields(#empimg) From_File(pslimg) With_Key(#Empno)

* Adding an entry creates an instance of the design (#CarouselDesign)
* The fields specified by the *Listfields parameter in the design will be populated in the design instance.

Add_Entry To_List(#UDCCarousel)

Endselect

#UDCCarousel.Items<1>.Focus := True

Endroutine

Evtroutine Handling(#TrackBar.Changed)

* A timer is used so that mulitple changes to the trackbar aren't immediately transmitted to the carousel, just the last one.
* This provides a smoother user experience.

#TrackBarTimer.Stop
#TrackBarTimer.Start

Endroutine

Evtroutine Handling(#UDCCarousel.ItemGotFocus) Item(#Item)

* Update the trackbar to match the carousel position.

#TrackBar.Value := #Item.Entry

Endroutine

Evtroutine Handling(#TrackBarTimer.Tick)

* When the timer fires, the user has stopped making changes to the trackbar position.
* Update the carousel position and stop the timer.

#UDCCarousel.Items.Item<#TrackBar.Value>.Focus := True

#TrackBarTimer.Stop

Endroutine

End_Com