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:
- AddXXX(...)
- AddXXXAt(index,...)
- RemoveXXXAt(index)
- FirstXXXIndex
- LastXXXIndex
- XXXCount
- XXX(index)
- IndexOfXXX(value, [starting index])
Examining some of the control classes we also find things like this:
- XXXAt(index)
- XXXs - iterable list
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)?
- AddRow(...)
- AddRowAt(index,...)
- RemoveRowAt(index)
- LastRowIndex
- RowCount
- RowTagAt(index)
- SelectedRowIndex
- SelectedRowValue
- SelectRowWithTag
- SelectRowWithValue
So what needs to be added?
- RowAt(index) - for consistency of access (returns 'value' of row)
- SelectedRowTag - for completeness
- AddRowWithTag(...,tag) - to expedite creation with Tags
- AddRowWithTagAt(index,...,tag) - to expedite creation with Tags
- IndexOfRow(value, [starting index]) - returns row index for row with matching value
- IndexOfTag(value, [starting index]) - returns row index for row with matching tag
- ?? anything else ??
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.