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

From Vectorworks Developer
Jump to navigation Jump to search
No edit summary
(→‎Sorting: add infos about Hierarchical Display)
Line 149: Line 149:
* 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]].
* [[User:CBM-c-/VS-List_Browsers_part_2#Hierarchical Display | Hierarchical Display]] has a built-in Alpha sorting.


;  NOTE:  setting a sorting column by script raises a List Browser event.
;  NOTE:   
:* Setting a sorting column by script raises a List Browser event.
:* Custom Sorting must be disabled for [[User:CBM-c-/VS-List_Browsers_part_2#Hierarchical Display | Hierarchical Display]] or you'll see a total mess of the sorting.


<code lang="pas">
<code lang="pas">
Line 173: Line 176:


[[VS:GetLBSortColumn]], [[VS:SetLBSortColumn]] 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.


=== Select ===
=== Select ===

Revision as of 15:56, 6 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.


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.
  • Hierarchical Display has a built-in Alpha sorting.
NOTE
  • Setting a sorting column by script raises a List Browser event.
  • Custom Sorting must be disabled for Hierarchical Display or you'll see a total mess of the sorting.
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.


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


Examples

Example: fetch event, row and column

{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;
{ ... }


Example: select all rows

{ _c_ ********************************************* }
{ Selects / Deselects all LB rows }
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;


Example: deselect all rows

{ _c_ ******************************************** }
{ Deselects all rows in a LB }
PROCEDURE LB_DeselectAllLBrows(d, LB: LONGINT);
	VAR
		temp_b : BOOLEAN;
	BEGIN
		temp_b := SetLBSelection(d, LB, 0, GetNumLBItems(d, LB) -1, FALSE);
	END;


Example: deselect selected rows

{ _c_ ********************************************* }
{ Delete selected LB items }
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;


Example: delete all columns

{ _c_ ******************************************** }
{ Deletes all columns in a LB }
PROCEDURE LB_DeleteAllLBcols(d, LB: LONGINT);
	VAR
		temp_b : BOOLEAN;
	BEGIN
		temp_b := DeleteAllLBItems(d, LB); { remove all rows }
		
		WHILE GetNumLBColumns(d, LB) > 0 DO BEGIN
			RemoveAllLBColumnDataItems(d, LB, 0); { remove all data items }
			temp_b := DeleteLBColumn(d, LB, 0);
		END;
	END;