API 2.0 - Filling the gaps with Extensions - DesktopPopupMenu Revised 10/28/2022

In my earlier article on API 2.0 - What and Why?, among the discussion of the improvements of API 2.0, I mentioned, some might say focused upon, perceived deficiencies or inconsistencies in API 2.0.

In this article I'm going to list and detail my approach and first bit of work to fill-in the API 2.0 gaps and inconsistencies through class extensions.  I will then work through this process with a concrete example (code included) for the DesktopPopupMenu class.

For listed items which methods & properties should be provided? Using Arrays as a guide we see these are standard for Arrays:  

Examining some of the control classes we also find things like this:

I am not going to implement 'FirstIndex'.  I have long been in the habit of using a literal '0' as the first index and API 2.0 has made 0-based indexing much more universal in the Xojo API.

Many of the framework classes, mainly controls, have 'Tag' data available along with the list of data, so I want to extend these functions to cover tags where reasonable.

Where iterable lists or arrays are not directly provided in classes, it may not provide utility commensurate with the work to implement.  Of course, you might decide otherwise for yourself, but I find that iterating a list, while syntactically cleaner and less error-prone than looping through all the items using an index, I often need the item's index for other reasons.

Finally, some classes have numerous aspects which can be viewed as lists, such as DesktopListBox. It can have multiple columns, so there is a count of columns, a first and last index of columns, widths and titles of the columns etc.  However, the implementation may be lengthy or a considerable burden, so I will not necessarily address every possible aspect of these controls.  For an example, examine DesktopListBox.ColumnWidths and try to imagine the code required to implement something like XXX.ColumnWidthAt().  It is possible, but would take alot of code and very large amount of testing to assure proper behavior.

For a consistent structure, I have a project folder (LDS_API2_Extensions) into which I have modules, one per class, with the extensions for that class.  This keeps extensions well organized, compact & portable.

I'm going to start my work using DesktopPopupMenu as a concrete example:

What does it have now (as of Xojo 2022 Release 3)?

So what needs to be added?

RowAt(index) 

Public Function RowAt(extends pum as DesktopPopupMenu, index as integer) As string
 return pum.RowValueAt(index)
End Function

SelectedRowTag 

Public Function SelectedRowTag(extends pum as DesktopPopupMenu) As variant
 return pum.RowTagAt(pum.SelectedRowIndex)
End Function

AddRowWithTag(...,tag) 

This method has two parameter lists:

1. (item as string, tag as variant)

2. (item as DesktopMenuItem, tag as variant)

Public Sub AddRowWithTag(extends pum as DesktopPopupMenu, item as string, tag as Variant)
 pum.AddRow(item)
 pum.RowTagAt(pum.LastAddedRowIndex)=tag
End Sub

Public Sub AddRowWithTag(extends pum as DesktopPopupMenu, item as DesktopMenuItem, tag as Variant)
 pum.AddRow(item)
 pum.RowTagAt(pum.LastAddedRowIndex)=tag
End Sub

AddRowWithTagAt(index,...,tag) 

This method has two parameter lists:

1. (index as integer, item as string, tag as variant)

2. (index as integer, item as DesktopMenuItem, tag as variant)

Public Sub AddRowWithTag(extends pum as DesktopPopupMenu, item as string, tag as Variant)
 pum.AddRow(item)
 pum.RowTagAt(pum.LastAddedRowIndex)=tag
End Sub

Public Sub AddRowWithTag(extends pum as DesktopPopupMenu, item as DesktopMenuItem, tag as Variant)
 pum.AddRow(item)
 pum.RowTagAt(pum.LastAddedRowIndex)=tag
End Sub

IndexOfRow(value,[startingIndex]) 

Public Function IndexOfRow(extends pum as desktopPopupMenu, value as string, startIndex as integer = 0) As integer
 for i as integer = startIndex to pum.LastRowIndex
  if(pum.RowValueAt(i) = value) then return i
 next
 var e as new OutOfBoundsException
 e.message = "Row value '"+value+"' not found in the menu's items"
 raise e
End Function

IndexOfRowTag(value,[startingIndex]) 

Public Function IndexOfRowTag(extends pum as desktopPopupMenu, value as string, startIndex as integer = 0) As integer
 for i as integer = startIndex to pum.LastRowIndex
  if(pum.RowTagAt(i) = value) then return i
 next
 var e as new OutOfBoundsException
 e.message = "Tag value '"+value+"' not found in the menu's items"
 Raise e
End Function

That's all there is to DesktopPopupMenu's extensions.