User:CBM-c-/VS-List Browsers part 4: Difference between revisions

From Vectorworks Developer
Jump to navigation Jump to search
(Create Subpage for List Browser 4)
 
No edit summary
Line 19: Line 19:




A List Browser is capable of returning an event on user's click. Using events offers an easy way to store the last selected row and column. It is always advisable to use events since this reduces your code. The user's selection is parsable through '''GetLBEventInfo'''. It returns a set of three informations:
A List Browser is capable of returning an event on user's click. Using events offers an easy way to store the type of action and last selected row and column,.  
* event triggered
 
The user's selection is parsable through [[VS:GetLBEventInfo]]. It returns a set of three informations:
 
* row selected
* row selected
* column selected
* column selected
There is a subtle difference in the type of event triggered, depending on the control type of the column involved. Documented is the event "-4", upon row selection, but undocumented is that the event returned can also be "-2" if the cell clicked belongs to a column whose [[User:CBM-c-/VS-List_Browsers_part_2#Control_Type| Control Type]] uses [[User:CBM-c-/VS-List_Browsers_part_2#Column_Data_Items_.28list.29| Column Data Items]].
* event triggered
Mind please that the row returned might be "-1" if the user clicks on white space within the List Browser. This can happen if your List Browser is higher than the rows displayed. After the last row some white space displays and clicks on this space cause event "-1".
It is *highly* recommendable to parse for List Browsers events exclusively in the dialog events CASE statement, straight where you code the response to user's action on the listBrowserID item. The event returned will be "-1" if the List Browsers hasn't been clicked at least once (for example just at dialog start). Or even more misleading values. Read this attentively.
[EDIT Dieter Geerts 2014-03-15] : I could not reproduce the '-1' event type. I guess it is solved in the current version of VW, 2014.


<code lang="pas">
<code lang="pas">
GetLBEventInfo( dialogID:LONGINT; componentID:LONGINT;  
{ list browser events }
VAR eventType:INTEGER; VAR rowIndex:INTEGER; VAR columIndex:INTEGER):BOOLEAN;
kLBrowColDataSel = -2; { user changed column data items, this occurs also without click! }
kLBDataChangeAllClick = -3; {}
kLBrowSel = -4; { user clicked on row }
kLBDoubleClick = -5;
kLBDeleteKeyPressed = -6;
kLBUpKeyPressed = -7;
kLBDownKeyPressed = -8; { user scrolled a row using arrow keys: no rows and cols are set by GetLBEventInfo! }
kLBAlphaNumericKeyPressed = -9; { user typed a key and the LB scrolls down: no rows/cols are set by GetLBEventInfo! }
kLBSortOccurred = -10;
kLBSelectionMultChangeClick = -11;
kLBEnterKeyPressed = -12;
kLBDataChangeRecursiveClick = -13;
kLBDoubleAllClick = -14;
kLBDoubleRecursiveClick = -15;
kLBItemEditCompletionData = -19;
</code>
</code>


Sets variables with the last event raised, the last selected row and last selected column.
* You should always use this routine in an IF condition for the case that it returns FALSE.
* You shall pay a lot of care if you call ''GetLBEventInfo'' outside the CASE statement for the involved List Browser item ID. See below. ''GetLBEventInfo'' should be used exclusively in the CASE statement for your List Browser. The events returned are not reliable otherwise.
* If you store selection indexes in global variables, you'll do well to initialize them to -1 and code accordingly. If for some reason ''GetLBEventInfo'' returns false, you risk misleading values otherwise (for example "0" which would lead to believe a first column or row has selected).
* Setting a sorting column somewhere in your script raises an event. I believe it shouldn't. This will record as last user event and will mislead you. Be careful if you change sorting column after column creation.
;  Event flags:  
;  Event flags:  
* no event: row selection for on-click-toggle control types but no Data Items List is available
* no event: row selection for on-click-toggle control types but no Data Items List is available
* -1 if the user clicks on white space within the List Browser. Can happen if your List Browser is higher than the rows displayed. After the last row some white space displays and clicks on this space cause event "-1".
* event = -2: row selection for on-click-toggle control types when items are available
* event = -2: row selection for on-click-toggle control types when items are available
* event = -4: row selection for control types Static and Number
* event = -4: row selection for control types Static and Number
:* event = -8: the user scrolls the LB using the arrow keys. This event sets no vars for the rows or cols: rowIndex is always -1, columIndex is always -1. The involved row will highlight nevertheless. But you have no way to find out what is selected until the user actually clicks on a row.
* event = -8: the user scrolls the LB using the arrow keys. This event sets no vars for the rows or cols: rowIndex is always -1, columIndex is always -1. The involved row will highlight nevertheless. But you have no way to find out what is selected until the user actually clicks on a row.
* event = -9: the user types a string while the focus is on the LB. This behaves the same as event -8. From Julian Carr on the V-list.
* event = -9: the user types a string while the focus is on the LB. This behaves the same as event -8. From Julian Carr on the V-list.
* event = -10: column selection  
* event = -10: column selection  
<code lang="pas">
GetLBEventInfo( dialogID: LONGINT; componentID: LONGINT;
VAR eventType:INTEGER; VAR rowIndex:INTEGER; VAR columIndex:INTEGER):BOOLEAN;
</code>
[[VS:GetLBEventInfo]] Sets variables with the last event raised, the last selected row and last selected column.
* You should always use this routine in an IF condition for the case that it returns FALSE.
* You shall pay a lot of care if you call ''GetLBEventInfo'' outside the CASE statement for the involved List Browser item ID. See below. ''GetLBEventInfo'' should be used exclusively in the CASE statement for your List Browser. The events returned are not reliable otherwise.
* If you store selection indexes in global variables, you'll do well to initialize them to -1 and code accordingly. If for some reason ''GetLBEventInfo'' returns false, you risk misleading values otherwise (for example "0" which would lead to believe a first column or row has selected).
* Setting a sorting column somewhere in your script raises an event. I believe it shouldn't. This will record as last user event. Be careful if you change sorting column after column creation.
;  Events on drag-drop: [DG - 2014-03-16]
;  Events on drag-drop: [DG - 2014-03-16]
You need to use the data that comes with the dialog event handler here to catch the drag-drop events!
You need to use the data that comes with the dialog event handler here to catch the drag-drop events!
:* event = -4; data = rowIndex: When starting, a normal event is thrown, so just a select event.
* event = -4; data = rowIndex: When starting, a normal event is thrown, so just a select event.
* event = -4; data = -50: The first event on releasing the item(s).
* event = -4; data = -50: The first event on releasing the item(s).
* event = -4; data = 43703408: The second event on releasing the item(s).
* event = -4; data = 43703408: The second event on releasing the item(s).
* event = -4; data = -51: The third and last event on releasing the item(s).
* event = -4; data = -51: The third and last event on releasing the item(s).
So check for the -51 data to react on drag-drop of items.
So check for the -51 data to react on drag-drop of items.
And here I go. Orso's usual dissection:
 
; Beastly misleading:  
; Beastly misleading:  
* event = 0: you called GetLBEventInfo outside the CASE block AND didn't set a sorting column somewhere in your code  
* event = 0: you called GetLBEventInfo outside the CASE block AND didn't set a sorting column somewhere in your code  
* eventRow = 0: see above
* eventRow = 0: see above
* eventCol = 0: see above
* eventCol = 0: see above
:* event = -10: you called GetLBEventInfo outside the CASE block AND set a sorting column somewhere in your code!
* event = -10: you called GetLBEventInfo outside the CASE block AND set a sorting column somewhere in your code!
* eventRow = -1: see above
* eventRow = -1: see above
* eventCol = 0: see above
* eventCol = 0: see above
;  Probable hint of crashy VW:  
;  Probable hint of crashy VW:  
* event = -&lt;long integer value&gt;: you called GetLBEventInfo outside the CASE block and you got some garbage value from previous codes. I saw this happen but cannot reproduce.
* event = -&lt;long integer value&gt;: you called GetLBEventInfo outside the CASE block and you got some garbage value from previous codes. I saw this happen but cannot reproduce.
* eventRow = -&lt;long integer value&gt;: see above
* eventRow = -&lt;long integer value&gt;: see above
* eventCol = -&lt;long integer value&gt;: see above
* eventCol = -&lt;long integer value&gt;: see above
;  Warning:  
;  Warning:  
* eventRow = -1: clicking on white space below the last row (for example when your row count doesn't fill the whole available List Browser space).
* eventRow = -1: clicking on white space below the last row (for example when your row count doesn't fill the whole available List Browser space).
Line 69: Line 93:
* eventCol = 0: default value, before first user's click on the List Browser (for example just after dialog launch). this might be regarded as a bug.
* eventCol = 0: default value, before first user's click on the List Browser (for example just after dialog launch). this might be regarded as a bug.
* Resizing columns doesn't return an event parsable with GetLBEventInfo.
* Resizing columns doesn't return an event parsable with GetLBEventInfo.
;  Furthermore:  it can be observed that image based control types behave differently:
;  Furthermore:  it can be observed that image based control types behave differently:
* event = -2: row selection for control types: Static Icon, Multiple Icons
* event = -2: row selection for control types: Static Icon, Multiple Icons
* event = -2: row selection for control types: Radio, Multi State, Single Instance when Column Data Items are defined.
* event = -2: row selection for control types: Radio, Multi State, Single Instance when Column Data Items are defined.
Must have something to do with the Column Data Items wanting to change or these controls expecting them.
Must have something to do with the Column Data Items wanting to change or these controls expecting them.
 
;  Returns FALSE:  
;  Returns FALSE:  
* on row selection for control types: Radio, Multi State, Single Instance when Column Data Items are missing (this is a hint that you forgot to set up Column Data Items).
* on row selection for control types: Radio, Multi State, Single Instance when Column Data Items are missing (this is a hint that you forgot to set up Column Data Items).
;  Unexpectedly returns TRUE:  
;  Unexpectedly returns TRUE:  
* calling the routine before first user's click on the List Browser (for example just after dialog launch).... and you called it outside the CASE statement for your List Browser ID.
* calling the routine before first user's click on the List Browser (for example just after dialog launch).... and you called it outside the CASE statement for your List Browser ID.
=== Example: basic usage ===


<code lang="pas">
<code lang="pas">
Line 83: Line 113:
SetupDialogC:
SetupDialogC:
BEGIN
BEGIN
{ set up the list browser listBrowserID }
{ ... }
{ ... }
END;
END;
 
listBrowserID: IF GetLBEventInfo(dlog, listBrowserID, event, eventRow, eventCol) THEN
{ on some event in the list browser, parse event, rowand column }
listBrowserID:
IF GetLBEventInfo(dlog, listBrowserID, event, eventRow, eventCol) THEN
alrtDialog(concat('event: ', event, ' last sel row: ', eventRow, ' last sel col: ', eventCol));
alrtDialog(concat('event: ', event, ' last sel row: ', eventRow, ' last sel col: ', eventCol));
END;
END;
Line 95: Line 128:
=== Drag and drop ===
=== Drag and drop ===


Drag and drop permits to the user to change order of the rows. This feature is disabled by default. Upon selecting a row and beginning a drag, the List Browser will wait for the user to drop it at some other position: it triggers user interaction. This feature can only be set on columns with control [[User:CBM-c-/VS-List_Browsers_part_2#Number| Number]]. Other columns will simply behave weird. An example can be observed on the "Design Layers" tab of NNA's Organizations dialog, when the option "Details" is activated: the stacking order is dealt with ''Drag and Drop''.  
Drag and drop permits to the user to change order of the rows. This feature is disabled by default. Upon selecting a row and beginning a drag, the List Browser will wait for the user to drop it at some other position: it triggers user interaction.  
This feature can be made even more interesting when combined with [[#List_Browsers_Events| List Browsers Events]]. At this point you can pass rows of data between two List Browsers. If you code such functionality you must pay great attention to reset the last selected indexes of both List Browsers. There is to my knowledge no NNA dialog using drag and drop between two (or more) List Browsers so user's of your dialog won't recognize the possibility on their own. They are not used to it. Abundant alerts should inform the user that a drop on another List Browser is awaited. Then it works like a charm. Among my favorites, but it takes some heavy coding to set up properly.
 
;  For this to work you need:
This feature can only be set on columns with control [[User:CBM-c-/VS-List_Browsers_part_2#Number| Number]].  
* [[User:CBM-c-/VS-List_Browsers_part_2#Number| Number]]
Other columns will simply behave weird. An example can be observed on the "Design Layers" tab of NNA's Organizations dialog, when the option "Details" is activated: the stacking order is dealt with ''Drag and Drop''.  
;  BUG:  ''on Windows during the user interaction (when the user is dragging a row) the whole screen in all monitors will flicker mercilessly, excluding the Vectorworks document window, which stay put and quiet. This is a long standing issue, but after all we don't look at anything else but our List Browser, while we are about to drop rows. (Fixed by VW 14 SP3)''


<code lang="pas">
<code lang="pas">
Line 105: Line 137:
enable: BOOLEAN) : BOOLEAN;
enable: BOOLEAN) : BOOLEAN;
</code>
</code>
Enables/disables drag and drop on a List Browser. It only works for columns of type ''Number''.
 
[[VS:EnableLBDragAndDrop]] Enables/disables drag and drop on a List Browser. It only works for columns of type '''Number'''.
 
;  result:  always TRUE, like ''SetLBDragDropColumn''. Simply pass the result to a temporary boolean variable that you can trash.
;  result:  always TRUE, like ''SetLBDragDropColumn''. Simply pass the result to a temporary boolean variable that you can trash.


Line 112: Line 146:
columnIndex: INTEGER) : BOOLEAN;
columnIndex: INTEGER) : BOOLEAN;
</code>
</code>
Declare the drag and drop column.
 
[[VS:SetLBDragDropColumn]] Declare the drag and drop column.
 
;  result:  it doesn't look capable of returning false. Even if the List Browser doesn't have a single column, it will happily return TRUE.
;  result:  it doesn't look capable of returning false. Even if the List Browser doesn't have a single column, it will happily return TRUE.
See also: [[#List_Browsers_Events| Using List Browsers Events]]


<code lang="pas">
<code lang="pas">
Line 120: Line 155:
iStartIndex, iEndIndex : INTEGER; bEnable : BOOLEAN) : BOOLEAN;
iStartIndex, iEndIndex : INTEGER; bEnable : BOOLEAN) : BOOLEAN;
</code>
</code>
By default all rows accept dropping. With this call is possible to disable, or re-enable, some rows from dropping. It shall be noticed that this is targeting rows, not columns.
 
[[VS:SetLBDragDropColumn]] By default all rows accept dropping. With this call is possible to disable, or re-enable, some rows from dropping. It shall be noticed that this is targeting rows, not columns.
 
;  iStartIndex, iEndIndex:  range of rows where dropping is disabled.
;  iStartIndex, iEndIndex:  range of rows where dropping is disabled.


Line 126: Line 163:
=== Sorting ===
=== Sorting ===


By default sorting is activated upon creating a List Browser, but it's possible to enable, disable and set sorting order (ascending or descending) during dialog execution. A few observations:
By default sorting is activated upon creating a List Browser, but it's possible to enable, disable and set sorting order (ascending or descending) during dialog execution.  
 
A few observations:
* Sorting image cells is meaningless, you can disable it since it will only upset your user.
* Sorting image cells is meaningless, you can disable it since it will only upset your user.
* Sorting text cells on Mac behaves differently than on PC: this I wish to explore further.
* Sorting text cells on Mac behaves differently than on PC: this I wish to explore further.
* Sorting numeric cells sort them alphabetically, see the cell ''Owner'' [[User:CBM-c-/VS-List_Browsers_part_2#Number| Number]].
* Sorting numeric cells sort them alphabetically, see the cell ''Owner'' [[User:CBM-c-/VS-List_Browsers_part_2#Number| Number]].
;  NOTE:  setting a sorting column by script raises a List Browser event, which is a bug. This should only happen on user interaction. See [[#List_Browsers_Events| List Browsers Events]].
 
;  NOTE:  setting a sorting column by script raises a List Browser event.


<code lang="pas">
<code lang="pas">
Line 136: Line 176:
enableSorting: BOOLEAN);
enableSorting: BOOLEAN);
</code>
</code>
Enables/disables sorting for a whole List Browser. Sorting is TRUE by default.
 
[[VS:EnableLBSorting]] Enables/disables sorting for a whole List Browser. Sorting is TRUE by default.


<code lang="pas">
<code lang="pas">
GetLBColumnSortState( dialogID:LONGINT; componentID:LONGINT;  
GetLBColumnSortState( dialogID: LONGINT; componentID: LONGINT;  
columnIndex:INTEGER):INTEGER;
columnIndex:INTEGER):INTEGER;
</code>
</code>
Returns sorting state of a column.
 
[[VS:GetLBColumnSortState]] Returns sorting state of a column.


<code lang="pas">
<code lang="pas">
GetLBSortColumn( dialogID:LONGINT; componentID:LONGINT):INTEGER;
GetLBSortColumn( dialogID: LONGINT; componentID: LONGINT):INTEGER;
SetLBSortColumn( dialogID:LONGINT; componentID:LONGINT; columnIndex:INTEGER;  
SetLBSortColumn( dialogID: LONGINT; componentID: LONGINT; columnIndex:INTEGER;  
isAscending:BOOLEAN);
isAscending:BOOLEAN);
</code>
</code>
Returns or set the current sort column in a List Browser whose sorting is enabled.
 
[[VS:GetLBSortColumn]], [[VS:SetLBSortColumn]] Returns or set the current sort column in a List Browser whose sorting is enabled.




Line 160: Line 203:
firstItemIndex: INTEGER; lastItemIndex: INTEGER; select: BOOLEAN): BOOLEAN;
firstItemIndex: INTEGER; lastItemIndex: INTEGER; select: BOOLEAN): BOOLEAN;
</code>
</code>
Select/deselects a range of rows from row "firstItemIndex" to row "lastItemIndex". If the selection is outside the List Browser's scroll window, the window will automatically scroll to show the selection. See [[#Visibility| EnsureLBItemIsVisible]] for a similar behavior, but without selection.
 
[[VS:SetLBSelection]] Selects/deselects a range of rows from row "firstItemIndex" to row "lastItemIndex". If the selection is outside the List Browser's scroll window, the window will automatically scroll to show the selection. See [[VS:EnsureLBItemIsVisible]] for a similar behavior, but without selection.


<code lang="pas">
<code lang="pas">
GetNumSelectedLBItems(dialogID: LONGINT; componentID: LONGINT): INTEGER;
GetNumSelectedLBItems(dialogID: LONGINT; componentID: LONGINT): INTEGER;
</code>
</code>
Count of currently selected rows. Among the most used routines, allows to loop down all selected rows for processing. Using [[#List_Browsers_Events| List Browsers Events]] the last selected row and column will be collected. But this still doesn't inform you on other rows eventually selected. This check is not needed if '''EnableLBSingleLineSelection''' is active: the user cannot select more than one line.  
 
[[VS:SetLBSelection]] Count of currently selected rows. Allows to loop down all selected rows for processing. Using Events the last selected row and column will be collected. But this still doesn't inform you on other rows eventually selected. This check is not needed if [[VS:EnableLBSingleLineSelection]] is active, where the user cannot select more than one line.  


<code lang="pas">
<code lang="pas">
Line 171: Line 216:
itemIndex: INTEGER): BOOLEAN;
itemIndex: INTEGER): BOOLEAN;
</code>
</code>
Checks if row "itemIndex" is currently selected (itemIndex = rowIndex). Like the previous routine, this check is not needed if ''EnableLBSingleLineSelection''' is active and the script parses for [[#List_Browsers_Events| List Browsers Events]].
 
[[VS:IsLBItemSelected]] Checks if row "itemIndex" is currently selected (itemIndex = rowIndex). Like the previous routine, this check is not needed if [[VS:EnableLBSingleLineSelection]] is active and the script parses for Events.


<code lang="pas">
<code lang="pas">
Line 177: Line 223:
enable: BOOLEAN): BOOLEAN;
enable: BOOLEAN): BOOLEAN;
</code>
</code>
Enable/disable selection of multiple rows. By default multiple selection is enabled. This is affects the whole list browser.
 
[[VS:EnableLBSingleLineSelection]] Enable/disable selection of multiple rows. By default multiple selection is enabled. This affects the whole list browser.


<code lang="pas">
<code lang="pas">
Line 183: Line 230:
enable: BOOLEAN): BOOLEAN;
enable: BOOLEAN): BOOLEAN;
</code>
</code>
Enable/disable changing all cells' values in a column when a modifier key (ctrl/alt on Mac/PC) is pressed. An example of this feature is the Navigation palette: the visibility column. Upon clicking on a row and while multiple rows are selected, the value displayed in the clicked row will apply to all selected rows. Is a good feature that can save some code, if your script allows for this functionality.
 
[[VS:EnableLBClickAllDataChange]] Enable/disable changing all cells' values in a column when a modifier key (ctrl/alt on Mac/PC) is pressed. An example of this feature is the Navigation palette: the visibility column. Upon clicking on a row and while multiple rows are selected, the value displayed in the clicked row will apply to all selected rows.
 
 
 
==== Examples: selection ====


<div style="margin: 1em; border: dotted 1px #aaa; padding: 1em; background-color: #F2F2F2;">
<div style="margin: 1em; border: dotted 1px #aaa; padding: 1em; background-color: #F2F2F2;">
Examples: 
<code lang="pas">
<code lang="pas">
PROCEDURE LB_SetSelAllRows(d, LB: LONGINT; select: BOOLEAN);
PROCEDURE LB_SetSelAllRows(d, LB: LONGINT; select: BOOLEAN);
Line 221: Line 271:
columnIndex: INTEGER): BOOLEAN;
columnIndex: INTEGER): BOOLEAN;
</code>
</code>
Remove the column at "columnIndex" from the List Browser. Is seldom, but it can happen that you need to rebuild the List Browser's columns anew. One such circumstance is that you need to re-write the columns titles.
 
: ''BUG: If you pass the index of a column (NOT Column Data Item) for deleting it, and this doesn't exists, the application will crash (VW 13 and 14).''
[[VS:DeleteLBColumn]] Remove the column at "columnIndex" from the List Browser. Is seldom, but it can happen that you need to rebuild the List Browser's columns anew. One such circumstance is that you need to re-write the columns titles.


<code lang="pas">
<code lang="pas">
RemoveAllLBColumnDataItems( dialogID:LONGINT; componentID:LONGINT;  
RemoveAllLBColumnDataItems( dialogID: LONGINT; componentID: LONGINT;  
columnIndex:INTEGER);
columnIndex:INTEGER);
</code>
</code>
Remove all items in the [[User:CBM-c-/VS-List_Browsers_part_2#Column_Data_Items_.28list.29| List of Column Data Items]] defined for the column at "columnIndex".  
 
[[VS:RemoveAllLBColumnDataItems]] Remove all items in the [[User:CBM-c-/VS-List_Browsers_part_2#Column_Data_Items_.28list.29| List of Column Data Items]] defined for the column at "columnIndex".  


<code lang="pas">
<code lang="pas">
RemoveLBColumnDataItem( dialogID:LONGINT; componentID:LONGINT;  
RemoveLBColumnDataItem( dialogID: LONGINT; componentID: LONGINT;  
columnIndex:INTEGER; columnDataItemIndex:INTEGER):BOOLEAN;
columnIndex:INTEGER; columnDataItemIndex:INTEGER):BOOLEAN;
</code>
</code>
Remove the chosen item at "columnDataItemIndex" from the [[User:CBM-c-/VS-List_Browsers_part_2#Column_Data_Items_.28list.29| List of Column Data Items]] defined for the column at "columnIndex".
 
[[VS:RemoveLBColumnDataItem]] Remove the chosen item at "columnDataItemIndex" from the [[User:CBM-c-/VS-List_Browsers_part_2#Column_Data_Items_.28list.29| List of Column Data Items]] defined for the column at "columnIndex".


<code lang="pas">
<code lang="pas">
DeleteAllLBItems(dialogID: LONGINT; componentID: LONGINT): BOOLEAN;
DeleteAllLBItems(dialogID: LONGINT; componentID: LONGINT): BOOLEAN;
</code>
</code>
Remove all rows in List Browser.
 
[[VS:DeleteAllLBItems]] Remove all rows in List Browser.


<code lang="pas">
<code lang="pas">
Line 245: Line 298:
itemIndex: INTEGER): BOOLEAN;
itemIndex: INTEGER): BOOLEAN;
</code>
</code>
Remove the row at "itemIndex".
 
[[VS:DeleteLBItem]] Remove the row at "itemIndex".




=== Update and Refresh ===
=== Update and Refresh ===


When the entire content of your List Browser shall be rebuilt destroying or modifying rows in a loop, you should always remember to disable the List Browser updates using '''EnableLBUpdates''' before the loop and reactivate it after the loop has finished executing. If you don't, you might bog down VW, which will recalculate the List Browser at each row, each cell inserted. Don't forget to re-enable updates otherwise you get a white list browser according to the event sent on user's click.
Disable the List Browser updates with [[VS:EnableLBUpdates]] before looping through a list browser for any operation, reactivate it after the loop has finished executing. If you don't, VW will recalculate the List Browser at each row, each cell inserted.  
To be noted that enabling doesn't really work well on PC (!expand!).
 
A List Browser refresh might be needed after changing row's data. This applies specially for resource images which might be changing during your script execution. The routine '''RefreshLB''' coerces the refresh. If you change data in a loop please remember to keep "RefreshLB" out of it. This call should always be the last thing you do after renewing data in any fashion. This is among the most important settings when you are dealing with heavy data.
Don't forget to re-enable updates and refresh the List Browser using [[VS:RefreshLB]].
This call should always be the last thing you do after renewing data.


<code lang="pas">
<code lang="pas">
EnableLBUpdates(liDialogID, liComponentID :LONGINT;  
EnableLBUpdates(liDialogID, liComponentID : LONGINT;  
bEnableUpdates :BOOLEAN);
bEnableUpdates :BOOLEAN);
</code>
</code>
Enable/disable updating cells in a List Browser. Disable ''always'' before looping rows with content modification and re-enable after the loop is terminated.
 
[[VS:EnableLBUpdates]] Enable/disable updating cells in a List Browser. Disable ''always'' before looping rows with content modification and re-enable after the loop is terminated.


<code lang="pas">
<code lang="pas">
RefreshLB( dialogID:LONGINT; componentID:LONGINT):BOOLEAN;
RefreshLB( dialogID: LONGINT; componentID: LONGINT):BOOLEAN;
</code>
</code>
Redraws the whole List Browser. Keep this outside content modifications involving loops.
 
[[VS:RefreshLB]] Redraws the whole List Browser. Keep this outside content modifications involving loops.




Line 271: Line 328:


<code lang="pas">
<code lang="pas">
SetFocusOnLB( dialogID:LONGINT; componentID:LONGINT):BOOLEAN;
SetFocusOnLB(dialogID: LONGINT; componentID: LONGINT):BOOLEAN;
</code>
</code>
[[VS:SetFocusOnLB]] Focus on the chosen List Browser.


<code lang="pas">
<code lang="pas">
EnsureLBItemIsVisible( dialogID:LONGINT; componentID:LONGINT;  
EnsureLBItemIsVisible( dialogID: LONGINT; componentID: LONGINT;  
index:INTEGER):BOOLEAN;
index:INTEGER):BOOLEAN;
</code>
</code>
Make the List Browser window display a row even if outside the scroll bounds of the list browser's window. Upon refreshing a List Browser the displayed rows always start at row "0". You don't need this call if you coerce a selection with '''SetLBSelection''': the selection will scroll automatically the window to fit.
 
[[VS:EnsureLBItemIsVisible]] Make the List Browser window display a row even if outside the scroll bounds of the list browser's window. Upon refreshing a List Browser the displayed rows always start at row "0". You don't need this call if you coerce a selection with [[VS:SetLBSelection]], the selection will scroll automatically the window to fit.




=== Enabling ===
=== Enabling ===


Sometimes you need to make your List Browser not accessible to the user, this can be obtained with '''EnableLB'''. The List Browser displays grayed and any user interaction is disabled ([[#Drag_and_drop| Drag and Drop]], on-click events). The List Browser is nevertheless fully enabled internally: you can still change content and display by script and it will update as expected.
Sometimes you need to make your List Browser not accessible to the user, use [[VS:EnableLB]]. The List Browser displays grayed and any user interaction is disabled ([[#Drag_and_drop| Drag and Drop]], on-click events). The List Browser is nevertheless fully enabled internally: you can still change content and display by script and it will update as expected.
 
See [[#Drag_and_drop| Drag and Drop]] for disabling dropping only on a range of rows (instead of disabling the whole list browser).
See [[#Drag_and_drop| Drag and Drop]] for disabling dropping only on a range of rows (instead of disabling the whole list browser).


Line 290: Line 350:
enable: BOOLEAN): BOOLEAN;
enable: BOOLEAN): BOOLEAN;
</code>
</code>
Enable/disable a List Browser. Disabled: not clickable and grayed.
 
[[VS:EnableLB]] Enable/disable a List Browser. Disabled: not clickable and grayed.




Line 296: Line 357:


Elsewhere called "itemData". Never figured this out.  
Elsewhere called "itemData". Never figured this out.  
One could think that it expects a resource index, similar to '''CreateControl''', but it doesn't. Since it demands a Longint, I also tipped on indexed resources (records, symbols, images...) or a list created with BuildResourceList, but this must be a wrong concept. Another possibility is that it expects a handle to some sub-object, but we cannot pass it with Vectorscript. For example user data objects of type 76 accompanying some parametric objects or records of certain kinds (textures, sketches...). Last possibility: too much fantasy and is just unsupported.
One could think that it expects a resource index, similar to '''CreateControl''', but it doesn't. Since it demands a Longint,  
 
I also tipped on indexed resources (records, symbols, images...) or a list created with BuildResourceList, but this must be a wrong concept. Another possibility is that it expects a handle to some sub-object, but we cannot pass it with Vectorscript. For example user data objects of type 76 accompanying some parametric objects or records of certain kinds (textures, sketches...). Last possibility: too much fantasy and is just unsupported.
Or does it perhaps await data from another dialog?
Or does it perhaps await data from another dialog?
I have no idea if this should be initialized to "0" or "-1". And I still didn't encounter a situation where this matters. Intuitively I'd say that init on "0" is well.
I have no idea if this should be initialized to "0" or "-1". And I still didn't encounter a situation where this matters. Intuitively I'd say that init on "0" is well.
You will find a reference to this mysterious type of data in the routines below:
You will find a reference to this mysterious type of data in the routines below:
;  InsertLBColumnDataItem:  targets a column and add something to the particular column data item using the parameter "itemData"? What is that we can add here?
 
;  GetLBColumnDataItemInfo:  securely get infos of the mysterious thing added at the particular column data item. Whatever that might be.
[[VS:InsertLBColumnDataItem]]:  targets a column and add something to the particular column data item using the parameter "itemData"? What is that we can add here?
;  SetLBItemData:  ''broken in VW 2017'', either this or GetLBItemData doesn't work any longer, but it did. It targets a cell. Changing it to any possible value didn't ever produce a result by me, but the value set with it could be fetched using GetLBItemData.
 
;  GetLBItemData:  ''broken in VW 2017'', either this or SetLBItemData doesn't work any longer, but it did, returning what was set with SetLBItemData.  
[[VS:GetLBColumnDataItemInfo]]:  securely get infos of the mysterious thing added at the particular column data item. Whatever that might be.
 
[[VS:SetLBItemData]]:  ''broken in VW 2017'', either this or '''GetLBItemData''' doesn't work any longer, but it did. It targets a cell. Changing it to any possible value didn't ever produce a result by me, but the value set with it could be fetched using GetLBItemData.
 
[[VS:GetLBItemData]]:  ''broken in VW 2017'', either this or '''SetLBItemData''' doesn't work any longer, but it did, returning what was set with '''SetLBItemData'''.  





Revision as of 17:43, 1 January 2021

For better understanding please use the comprehensive example at Dialog with List Browser. By --_c_ (talk) 03:08, 31 December 2020 (EST) (previously Orso B. Schmid)


Part 1: Creation Part 2: Columns Part 3: Rows and Cells Part 4: Events


Events

A List Browser is capable of returning an event on user's click. Using events offers an easy way to store the type of action and last selected row and column,.

The user's selection is parsable through VS:GetLBEventInfo. It returns a set of three informations:

  • row selected
  • column selected
  • event triggered
{ list browser events }
kLBrowColDataSel = -2;	{ user changed column data items, this occurs also without click! }
kLBDataChangeAllClick	= -3; {}
kLBrowSel = -4;	{ user clicked on row }
kLBDoubleClick = -5;
kLBDeleteKeyPressed	= -6;
kLBUpKeyPressed	 = -7;
kLBDownKeyPressed = -8; { user scrolled a row using arrow keys: no rows and cols are set by GetLBEventInfo! }
kLBAlphaNumericKeyPressed = -9; { user typed a key and the LB scrolls down: no rows/cols are set by GetLBEventInfo! }
kLBSortOccurred = -10;
kLBSelectionMultChangeClick = -11;
kLBEnterKeyPressed = -12;
kLBDataChangeRecursiveClick = -13;
kLBDoubleAllClick = -14;
kLBDoubleRecursiveClick = -15;
kLBItemEditCompletionData = -19;
Event flags
  • no event: row selection for on-click-toggle control types but no Data Items List is available
  • -1 if the user clicks on white space within the List Browser. Can happen if your List Browser is higher than the rows displayed. After the last row some white space displays and clicks on this space cause event "-1".
  • event = -2: row selection for on-click-toggle control types when items are available
  • event = -4: row selection for control types Static and Number
  • event = -8: the user scrolls the LB using the arrow keys. This event sets no vars for the rows or cols: rowIndex is always -1, columIndex is always -1. The involved row will highlight nevertheless. But you have no way to find out what is selected until the user actually clicks on a row.
  • event = -9: the user types a string while the focus is on the LB. This behaves the same as event -8. From Julian Carr on the V-list.
  • event = -10: column selection
GetLBEventInfo( dialogID: LONGINT; componentID: LONGINT; 
	VAR eventType:INTEGER; VAR rowIndex:INTEGER; VAR columIndex:INTEGER):BOOLEAN;

VS:GetLBEventInfo Sets variables with the last event raised, the last selected row and last selected column.

  • You should always use this routine in an IF condition for the case that it returns FALSE.
  • You shall pay a lot of care if you call GetLBEventInfo outside the CASE statement for the involved List Browser item ID. See below. GetLBEventInfo should be used exclusively in the CASE statement for your List Browser. The events returned are not reliable otherwise.
  • If you store selection indexes in global variables, you'll do well to initialize them to -1 and code accordingly. If for some reason GetLBEventInfo returns false, you risk misleading values otherwise (for example "0" which would lead to believe a first column or row has selected).
  • Setting a sorting column somewhere in your script raises an event. I believe it shouldn't. This will record as last user event. Be careful if you change sorting column after column creation.
Events on drag-drop
[DG - 2014-03-16]

You need to use the data that comes with the dialog event handler here to catch the drag-drop events!

  • event = -4; data = rowIndex: When starting, a normal event is thrown, so just a select event.
  • event = -4; data = -50: The first event on releasing the item(s).
  • event = -4; data = 43703408: The second event on releasing the item(s).
  • event = -4; data = -51: The third and last event on releasing the item(s).

So check for the -51 data to react on drag-drop of items.

Beastly misleading
  • event = 0: you called GetLBEventInfo outside the CASE block AND didn't set a sorting column somewhere in your code
  • eventRow = 0: see above
  • eventCol = 0: see above
  • event = -10: you called GetLBEventInfo outside the CASE block AND set a sorting column somewhere in your code!
  • eventRow = -1: see above
  • eventCol = 0: see above
Probable hint of crashy VW
  • event = -<long integer value>: you called GetLBEventInfo outside the CASE block and you got some garbage value from previous codes. I saw this happen but cannot reproduce.
  • eventRow = -<long integer value>: see above
  • eventCol = -<long integer value>: see above
Warning
  • eventRow = -1: clicking on white space below the last row (for example when your row count doesn't fill the whole available List Browser space).
  • eventCol = -1: see above.
  • eventCol = 0: default value, before first user's click on the List Browser (for example just after dialog launch). this might be regarded as a bug.
  • Resizing columns doesn't return an event parsable with GetLBEventInfo.
Furthermore
it can be observed that image based control types behave differently:
  • event = -2: row selection for control types: Static Icon, Multiple Icons
  • event = -2: row selection for control types: Radio, Multi State, Single Instance when Column Data Items are defined.

Must have something to do with the Column Data Items wanting to change or these controls expecting them.

Returns FALSE
  • on row selection for control types: Radio, Multi State, Single Instance when Column Data Items are missing (this is a hint that you forgot to set up Column Data Items).
Unexpectedly returns TRUE
  • calling the routine before first user's click on the List Browser (for example just after dialog launch).... and you called it outside the CASE statement for your List Browser ID.


Example: basic usage

{put in SetupDialogC case }
CASE item OF
SetupDialogC:
	BEGIN
		{ set up the list browser listBrowserID }
		{ ... }
	END;

{ on some event in the list browser, parse event, rowand column }
listBrowserID:
	IF GetLBEventInfo(dlog, listBrowserID, event, eventRow, eventCol) THEN
		alrtDialog(concat('event: ', event, ' last sel row: ', eventRow, ' last sel col: ', eventCol));
END;
{ ... }


Drag and drop

Drag and drop permits to the user to change order of the rows. This feature is disabled by default. Upon selecting a row and beginning a drag, the List Browser will wait for the user to drop it at some other position: it triggers user interaction.

This feature can only be set on columns with control Number. Other columns will simply behave weird. An example can be observed on the "Design Layers" tab of NNA's Organizations dialog, when the option "Details" is activated: the stacking order is dealt with Drag and Drop.

EnableLBDragAndDrop(dlog: LONGINT; LB: LONGINT; 
	enable: BOOLEAN) : BOOLEAN;

VS:EnableLBDragAndDrop Enables/disables drag and drop on a List Browser. It only works for columns of type Number.

result
always TRUE, like SetLBDragDropColumn. Simply pass the result to a temporary boolean variable that you can trash.
SetLBDragDropColumn( dlog : LONGINT; LB : LONGINT; 
	columnIndex: INTEGER) : BOOLEAN;

VS:SetLBDragDropColumn Declare the drag and drop column.

result
it doesn't look capable of returning false. Even if the List Browser doesn't have a single column, it will happily return TRUE.
EnableLBDropOnIndices(dlog, LB : LONGINT; 
	iStartIndex, iEndIndex : INTEGER; bEnable : BOOLEAN) : BOOLEAN;

VS:SetLBDragDropColumn By default all rows accept dropping. With this call is possible to disable, or re-enable, some rows from dropping. It shall be noticed that this is targeting rows, not columns.

iStartIndex, iEndIndex
range of rows where dropping is disabled.


Sorting

By default sorting is activated upon creating a List Browser, but it's possible to enable, disable and set sorting order (ascending or descending) during dialog execution.

A few observations:

  • Sorting image cells is meaningless, you can disable it since it will only upset your user.
  • Sorting text cells on Mac behaves differently than on PC: this I wish to explore further.
  • Sorting numeric cells sort them alphabetically, see the cell Owner Number.
NOTE
setting a sorting column by script raises a List Browser event.
EnableLBSorting(dialogID: LONGINT; componentI LONGINT; 
	enableSorting: BOOLEAN);

VS:EnableLBSorting Enables/disables sorting for a whole List Browser. Sorting is TRUE by default.

GetLBColumnSortState( dialogID: LONGINT; componentID: LONGINT; 
	columnIndex:INTEGER):INTEGER;

VS:GetLBColumnSortState Returns sorting state of a column.

GetLBSortColumn( dialogID: LONGINT; componentID: LONGINT):INTEGER;
SetLBSortColumn( dialogID: LONGINT; componentID: LONGINT; columnIndex:INTEGER; 
	isAscending:BOOLEAN);

VS:GetLBSortColumn, VS:SetLBSortColumn Returns or set the current sort column in a List Browser whose sorting is enabled.


Select

Script-side selection is very well combined with List Browsers Events, which allows to keep easy track of the last user's selection, if any.

SetLBSelection(dialogID: LONGINT; componentID: LONGINT; 
	firstItemIndex: INTEGER; lastItemIndex: INTEGER; select: BOOLEAN): BOOLEAN;

VS:SetLBSelection Selects/deselects a range of rows from row "firstItemIndex" to row "lastItemIndex". If the selection is outside the List Browser's scroll window, the window will automatically scroll to show the selection. See VS:EnsureLBItemIsVisible for a similar behavior, but without selection.

GetNumSelectedLBItems(dialogID: LONGINT; componentID: LONGINT): INTEGER;

VS:SetLBSelection Count of currently selected rows. Allows to loop down all selected rows for processing. Using Events the last selected row and column will be collected. But this still doesn't inform you on other rows eventually selected. This check is not needed if VS:EnableLBSingleLineSelection is active, where the user cannot select more than one line.

IsLBItemSelected(dialogID: LONGINT; componentID: LONGINT; 
	itemIndex: INTEGER): BOOLEAN;

VS:IsLBItemSelected Checks if row "itemIndex" is currently selected (itemIndex = rowIndex). Like the previous routine, this check is not needed if VS:EnableLBSingleLineSelection is active and the script parses for Events.

EnableLBSingleLineSelection(dialogID: LONGINT; componentID: LONGINT; 
	enable: BOOLEAN): BOOLEAN;

VS:EnableLBSingleLineSelection Enable/disable selection of multiple rows. By default multiple selection is enabled. This affects the whole list browser.

EnableLBClickAllDataChange(dialogID: LONGINT; componentID: LONGINT; 
	enable: BOOLEAN): BOOLEAN;

VS:EnableLBClickAllDataChange Enable/disable changing all cells' values in a column when a modifier key (ctrl/alt on Mac/PC) is pressed. An example of this feature is the Navigation palette: the visibility column. Upon clicking on a row and while multiple rows are selected, the value displayed in the clicked row will apply to all selected rows.


Examples: selection

PROCEDURE LB_SetSelAllRows(d, LB: LONGINT; select: BOOLEAN);
	VAR
		temp_b : BOOLEAN;
	BEGIN
		IF GetNumLBItems(d, LB) > 0 THEN
			temp_b := SetLBSelection(d, LB, 0, GetNumLBItems(d, LB)-1, select);
	END;
	
PROCEDURE LB_DeleteSelRows(d, LB: LONGINT);
	VAR
		i : INTEGER;
		temp_b : BOOLEAN;
	BEGIN
		i := 0;
		WHILE i < GetNumLBItems(d, LB) DO
			IF IsLBItemSelected(d, LB, i) THEN
				temp_b := DeleteLBItem(d, LB, i)
			ELSE
				i := i + 1;
	END;


Destroy data

Sometimes what you need is to destroy data. Below the routine allowing for this to be achieved:

DeleteLBColumn(dialogID: LONGINT; componentID: LONGINT; 
	columnIndex: INTEGER): BOOLEAN;

VS:DeleteLBColumn Remove the column at "columnIndex" from the List Browser. Is seldom, but it can happen that you need to rebuild the List Browser's columns anew. One such circumstance is that you need to re-write the columns titles.

RemoveAllLBColumnDataItems( dialogID: LONGINT; componentID: LONGINT; 
	columnIndex:INTEGER);

VS:RemoveAllLBColumnDataItems Remove all items in the List of Column Data Items defined for the column at "columnIndex".

RemoveLBColumnDataItem( dialogID: LONGINT; componentID: LONGINT; 
	columnIndex:INTEGER; columnDataItemIndex:INTEGER):BOOLEAN;

VS:RemoveLBColumnDataItem Remove the chosen item at "columnDataItemIndex" from the List of Column Data Items defined for the column at "columnIndex".

DeleteAllLBItems(dialogID: LONGINT; componentID: LONGINT): BOOLEAN;

VS:DeleteAllLBItems Remove all rows in List Browser.

DeleteLBItem(dialogID: LONGINT; componentID: LONGINT; 
	itemIndex: INTEGER): BOOLEAN;

VS:DeleteLBItem Remove the row at "itemIndex".


Update and Refresh

Disable the List Browser updates with VS:EnableLBUpdates before looping through a list browser for any operation, reactivate it after the loop has finished executing. If you don't, VW will recalculate the List Browser at each row, each cell inserted.

Don't forget to re-enable updates and refresh the List Browser using VS:RefreshLB. This call should always be the last thing you do after renewing data.

EnableLBUpdates(liDialogID, liComponentID : LONGINT; 
	bEnableUpdates :BOOLEAN);

VS:EnableLBUpdates Enable/disable updating cells in a List Browser. Disable always before looping rows with content modification and re-enable after the loop is terminated.

RefreshLB( dialogID: LONGINT; componentID: LONGINT):BOOLEAN;

VS:RefreshLB Redraws the whole List Browser. Keep this outside content modifications involving loops.


Visibility

Useful routines for ensuring that List Browsers are visible:

SetFocusOnLB(dialogID: LONGINT; componentID: LONGINT):BOOLEAN;

VS:SetFocusOnLB Focus on the chosen List Browser.

EnsureLBItemIsVisible( dialogID: LONGINT; componentID: LONGINT; 
	index:INTEGER):BOOLEAN;

VS:EnsureLBItemIsVisible Make the List Browser window display a row even if outside the scroll bounds of the list browser's window. Upon refreshing a List Browser the displayed rows always start at row "0". You don't need this call if you coerce a selection with VS:SetLBSelection, the selection will scroll automatically the window to fit.


Enabling

Sometimes you need to make your List Browser not accessible to the user, use VS:EnableLB. The List Browser displays grayed and any user interaction is disabled ( Drag and Drop, on-click events). The List Browser is nevertheless fully enabled internally: you can still change content and display by script and it will update as expected.

See Drag and Drop for disabling dropping only on a range of rows (instead of disabling the whole list browser).

EnableLB(dialogID: LONGINT; componentID: LONGINT; 
	enable: BOOLEAN): BOOLEAN;

VS:EnableLB Enable/disable a List Browser. Disabled: not clickable and grayed.


User Data

Elsewhere called "itemData". Never figured this out. One could think that it expects a resource index, similar to CreateControl, but it doesn't. Since it demands a Longint,

I also tipped on indexed resources (records, symbols, images...) or a list created with BuildResourceList, but this must be a wrong concept. Another possibility is that it expects a handle to some sub-object, but we cannot pass it with Vectorscript. For example user data objects of type 76 accompanying some parametric objects or records of certain kinds (textures, sketches...). Last possibility: too much fantasy and is just unsupported. Or does it perhaps await data from another dialog? I have no idea if this should be initialized to "0" or "-1". And I still didn't encounter a situation where this matters. Intuitively I'd say that init on "0" is well. You will find a reference to this mysterious type of data in the routines below:

VS:InsertLBColumnDataItem
targets a column and add something to the particular column data item using the parameter "itemData"? What is that we can add here?
VS:GetLBColumnDataItemInfo
securely get infos of the mysterious thing added at the particular column data item. Whatever that might be.
VS:SetLBItemData
broken in VW 2017, either this or GetLBItemData doesn't work any longer, but it did. It targets a cell. Changing it to any possible value didn't ever produce a result by me, but the value set with it could be fetched using GetLBItemData.
VS:GetLBItemData
broken in VW 2017, either this or SetLBItemData doesn't work any longer, but it did, returning what was set with SetLBItemData.


Part 1: Creation Part 2: Columns Part 3: Rows and Cells Part 4: Events