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

From Vectorworks Developer
Jump to navigation Jump to search
(Expand)
 
(35 intermediate revisions by the same user not shown)
Line 4: Line 4:




= Creation and columns =
Some of you know me as Orso from the now defunct Vectorlab, I maintained it for many years. Here is the List Browsers article from the former Vectorlab site. For better understanding please use the comprehensive example at [[User:CBM-c-/Dialog with List Browser| Dialog with List Browser]].
 
By --[[User:CBM-c-|_c_]] 01:31, 31 December 2020 (EST),
previously Orso.B.Schmid, 2009-2018.
 
 
= List Browsers =
 
List Browsers allow for great layout, advanced data management, but also amazing layout features within the single cells. Is not difficult to load them with some text data and make them display a whatever list. Still the advanced settings of List Browsers are quite enigmatic. After years of trial and error, I attempt here to resume what I discovered. If you find an error, I'd be glad to be informed. I am a user and had no reference literature for this article which is based on pure experience, if you are a programmer you will probably find the terms employed not quite the right ones.
 
Since List Browsers are so complex, the best way to learn how to use them is to have some free code available for experiments. Free code for List Browsers can be counted on one hand and none of the snippets available tells you a single thing about Control Types, Edit Display Types, Item Display Types, Column Data Items and so on.
 
Use the example [[User:CBM-c-/Dialog with List Browser| Dialog with List Browser]] to experiment with the List Browser's options.


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




{| class="wikitable" style="margin: auto;"
{| class="wikitable" style="margin: auto;"
|-
|-
! [[User:CBM-c-/VS-List_Browsers| Introduction]]
! [[User:CBM-c-/VS-List_Browsers_part_1| Part 1: Creation]]
! List_Browsers_part_1
! [[User:CBM-c-/VS-List_Browsers_part_2| Part 2: Columns]]
! [[User:CBM-c-/VS-List_Browsers_part_2| List_Browsers_part_2]]
! [[User:CBM-c-/VS-List_Browsers_part_3| Part 3: Rows and Cells]]
! [[User:CBM-c-/VS-List_Browsers_part_4| Part 4: Events]]
|}
 
== Introduction ==
 
The display of List Browsers is determined by the right combination of four settings: Control Type, Display Type, Cell's Column Owner, Column Data Items.
 
This is all rather difficult, specially because it is not documented. It resembles a 4D-puzzle.
 
 
{| class="wikitable" style="margin: auto;"
|-
! colspan="3"| [[User:CBM-c-/VS-List_Browsers_part_2#Column_Data_Items| Column Data Items]]
! List Browser set up
 
|-
| colspan="3" style="text-align: center;"| Icons, Strings
| rowspan="4" |
* [[#Create_a_List_Browser|  Create a List Browser]]
* [[#Icon List|  Create a List of Icons]] (optional)
* [[User:CBM-c-/VS-List_Browsers_part_2#Columns|  Create columns]]
*: For each column:
*: [[User:CBM-c-/VS-List_Browsers_part_2#Control_Type|  Set Control Type]] (optional)
*: [[User:CBM-c-/VS-List_Browsers_part_2#Display_Type|  Set Display Type]] (optional)
*: [[User:CBM-c-/VS-List_Browsers_part_2#Column_Data_Items_List|  Create a List of Column Data Items]] (optional)
 
* [[User:CBM-c-/VS-List_Browsers_part_3#Rows_and_Cells|  Insert rows]]
*: For each row loop down all columns
*: and set for each cell:
** [[User:CBM-c-/VS-List_Browsers_part_2#Column_Owner_Type|  Column Owner Type]] (optional)
** cell values:
*** string and/or image, or
*** item from a [[User:CBM-c-/VS-List_Browsers_part_2#Column_Data_Items_List|  List of Column Data Items]] (optional)
 
|-
! colspan="2" | [[User:CBM-c-/VS-List_Browsers_part_2#Column|  Column]]
!  [[User:CBM-c-/VS-List_Browsers_part_3#Rows_and_Cells|  Cell]]
 
|-
! [[User:CBM-c-/VS-List_Browsers_part_2#Control_Type|  Control Type]]
display HOW
 
! [[User:CBM-c-/VS-List_Browsers_part_2#Display_Type|  Display Type]]
display WHICH DATA
 
! [[User:CBM-c-/VS-List_Browsers_part_2#Column_Owner_Type|  Column Owner Type]]
display WHAT
 
|-
|
# [[User:CBM-c-/VS-List_Browsers_part_2#Static|  Static]]
# [[User:CBM-c-/VS-List_Browsers_part_2#Radio|  Radio]]
# [[User:CBM-c-/VS-List_Browsers_part_2#Multi_State| Multi State]]
# [[User:CBM-c-/VS-List_Browsers_part_2#Single_Instance_Icon|  Single Instance Icon]]
# [[User:CBM-c-/VS-List_Browsers_part_2#Static_icon|  Static icon]]
# [[User:CBM-c-/VS-List_Browsers_part_2#Number| Number]]
# [[User:CBM-c-/VS-List_Browsers_part_2#Multiple_Icons|  Multiple Icons]]
 
|
# Image
# Text only
# Image and Text
 
|
:  0. [[User:CBM-c-/VS-List_Browsers_part_3#None|  None]]
# [[User:CBM-c-/VS-List_Browsers_part_3#Solid_rect|  Solid rect]]
# [[User:CBM-c-/VS-List_Browsers_part_3#Dual_solid_rect|  Dual solid rect]]
# [[User:CBM-c-/VS-List_Browsers_part_3#Pattern_and_Dual_Pattern|  Pattern rect]]
# [[User:CBM-c-/VS-List_Browsers_part_3#Pattern_and_Dual_Pattern|  Dual pattern rect]]
# [[User:CBM-c-/VS-List_Browsers_part_3#Gradients_and_Images|  Gradient or image]]
# [[User:CBM-c-/VS-List_Browsers_part_3#Blank|  Blank]]
# [[User:CBM-c-/VS-List_Browsers_part_3#Text|  Text]]
# [[User:CBM-c-/VS-List_Browsers_part_3#Dashed_line|  Dashed line]]
|}
|}
[[File:c_LB_NNAclasses.png| center]]
== Lists Validity Scope ==
List Browsers are more than tables of cells, they browse lists. You must imagine them like special containers with built-in lists of data which can be created and used on need. These lists have different validity scope.
; List of icons: available to the whole List Browser.
; Column Data Items: available to one column. Column Data Items will often use images from the List Browser's Image list, but they can also contain only strings.




== Create a List Browser ==
== Create a List Browser ==


List Browsers are called in a Layout Creation routine with [[VS:CreateLB]].
List Browsers are called in a Layout Creation routine with '''CreateLB'''.


<code lang="pas">
<code lang="pas">
CreateLB(dialogID: LONGINT; componentID: LONGINT;  
CreateLB(dialogID: LONGINT; listBrowserID: LONGINT;  
widthInCharacters: INTEGER; heightInCharacters: INTEGER);
widthInCharacters: INTEGER; heightInCharacters: INTEGER);
</code>
</code>
[[VS:CreateLB]] Creates an empty List Browser with no rows and no columns.


; '''widthInCharacters''', '''heightInCharacters''': is different between Mac and PC. Basically on Mac all dialog items with a scroll bar interpret the width excluding the bar. This will influence the width of dialog elements such as PullDown menus, List Browsers, Lists and such. These items won't align with Static Text, Edit fields and similar: the scroll bar will be outside alignment. You must correct the width programmatically.
; '''widthInCharacters''', '''heightInCharacters''': is different between Mac and PC. Basically on Mac all dialog items with a scroll bar interpret the width excluding the bar. This will influence the width of dialog elements such as PullDown menus, List Browsers, Lists and such. These items won't align with Static Text, Edit fields and similar: the scroll bar will be outside alignment. You must correct the width programmatically.
Line 37: Line 133:
dlog := CreateResizableLayout('List Browsers test', TRUE, 'Close', '', TRUE, FALSE);
dlog := CreateResizableLayout('List Browsers test', TRUE, 'Close', '', TRUE, FALSE);
{ ... }
{ ... }
CreateLB(dlog, cLB, cLBWidth, cLBHeight);
CreateLB(dlog, lb, lbWidth, lbHeight);
</code>
</code>


Line 45: Line 141:
Your List Browser after creation is just an empty container without columns, rows or any data. Before loading the List Browser it is important to understand what needs to be loaded once and if there are things that needs to be loaded repeatedly, after destroying data. Aside of images, which must be really loaded only once, all other List Browser elements can be loaded, destroyed, created or modified according to your needs. The typical script will set up a List Browser once in [[VS:Creating_a_Custom_Dialog_Box| SetupDialogC]] and manipulate repeatedly only rows data. Usually you will:
Your List Browser after creation is just an empty container without columns, rows or any data. Before loading the List Browser it is important to understand what needs to be loaded once and if there are things that needs to be loaded repeatedly, after destroying data. Aside of images, which must be really loaded only once, all other List Browser elements can be loaded, destroyed, created or modified according to your needs. The typical script will set up a List Browser once in [[VS:Creating_a_Custom_Dialog_Box| SetupDialogC]] and manipulate repeatedly only rows data. Usually you will:


* add Icons always only once
* add [[#Icon List| Icons]] always only once
* add Columns most times once
* add [[User:CBM-c-/VS-List_Browsers_part_2#Columns| Columns]] most times once
* add Column Data Items most times only once
* add [[User:CBM-c-/VS-List_Browsers_part_2#Column Data Items List| Column Data Items]] most times only once
* add/delete/modify Cells repeatedly
* add/delete/modify [[User:CBM-c-/VS-List_Browsers_part_3#Rows and Cells| Rows and Cells]] repeatedly


Then you'll organize your loading code as follows:
Then you'll organize your loading code as follows:


* needs loading once --> has a place in the SetupDialogC CASE item of your dialog driver routine
* needs loading once --> has a place in the [[VS:Creating_a_Custom_Dialog_Box| SetupDialogC]] CASE item of your dialog driver routine
* needs loading repeatedly --> resides in a subroutine with wider validity scope (including SetupDialogC for the first run).
* needs loading repeatedly --> resides in a subroutine with wider validity scope (including [[VS:Creating_a_Custom_Dialog_Box| SetupDialogC]] for the first run).




== Items and Sub-items (0-based) ==
=== Items and Sub-items, index (0-based) ===


At start the main difficulty in understanding List Browsers is caused by the naming of the various routine parameters. Everyone will struggle initially with "itemIndex" and "subItemIndex", sometimes also called (more clearly) "columnIndex". The official documentation uses names not consequently. Just some examples:
At start the main difficulty in understanding List Browsers is caused by the naming of the various routine parameters. Everyone will struggle initially with "itemIndex" and "subItemIndex", sometimes also called (more clearly) "columnIndex". The official documentation uses names not consequently. Just some examples:


; row index: itemIndex, nItemIndex
; column index: subItemIndex, nSubItemIndex, columnIndex


<code lang="pas">
GetLBItemInfo(dialogID: LONGINT; componentID: LONGINT; itemIndex: INTEGER; subItemIndex: INTEGER;
VAR itemString: STRING; VAR imageIndex: INTEGER): BOOLEAN;
GetLBItemData(nDialogID, nComponentID :LONGINT; nItemIndex, nSubItemIndex :INTEGER;
VAR nUserData :LONGINT);
InsertLBColumn( dialogID:LONGINT; componentID:LONGINT; columnIndex:INTEGER;
headerString:STRING; width:INTEGER):INTEGER;
</code>
;  row index: itemIndex, nItemIndex
; column index: subItemIndex, nSubItemIndex, columnIndex
If you see both parameters for row and for column you know that you'll target a cell (intersection of row and column).
If you see both parameters for row and for column you know that you'll target a cell (intersection of row and column).


Line 79: Line 164:


* [[#Icon List| Icons]]
* [[#Icon List| Icons]]
* [[#Column Data Items list| Column Data Items]]
* [[User:CBM-c-/VS-List_Browsers_part_2#Column Data Items List| Column Data Items]]
* [[#Columns| Columns]]
* [[User:CBM-c-/VS-List_Browsers_part_2#Columns| Columns]]
* [[#Rows and Cells| Rows and Cells]]
* [[User:CBM-c-/VS-List_Browsers_part_3#Rows and Cells| Rows and Cells]]


This implies that for setting the absence of an image -for example- you need to pass "-1". Take care to init your variables to -1. Mind the routine AddLBImage which on Mac might return "0" also if it failed to insert an image.
This implies that for setting the absence of an image -for example- you need to pass "-1". Take care to init your variables to -1. Mind the routine '''AddListBrowserImage''' which on Mac might return "0" also if it failed to insert an image.


Many mistakes in List Browsers are caused by unwanted 0-indexes in images or Column Data Items.
Many mistakes in List Browsers are caused by unwanted 0-indexes in images or Column Data Items.




==Icon List==
== Icon List ==
 
Very relevant for the layout of a List Browser is the list of icons (optional). Here you store small icons that will be available to the whole List Browser. The icons must be either loaded from external resource files or recycled from the built-in Vectorworks icons. They can be used directly from the singular cells and/or be used to build data in the List of Data Items of a column. An [[#Icon List| Icon List]] can be created using '''AddListBrowserImage'''.


Very relevant for the layout of a List Browser is the list of icons (optional). Here you store small icons that will be available to the whole List Browser. The icons must be either loaded from external resource files or recycled among the built-in Vectorworks icons. They can be used directly from the singular cells and/or be used to build data in the List of Data Items of a column. An Icon List can be created using [[VS:AddListBrowserImage]].  
There is a single routine allowing to load icon resources without pre-loading them in the [[#Icon List| Icon List]] first: '''SetLBImageIndexes''', which applies only to columns with control type Multiple Icons.  


There is a single routine allowing to load icon resources without pre-loading them in the Icon List first: [[VS:SetLBImageIndexes]], which applies only to columns with control type Multiple Icons.  
To my knowledge, once loaded the original indexes of the icon-resources are lost: for example it's not possible to fetch the original resource index of icon "2" in the '''Icon List''' and substitute it with something else. This is only possible on Mac using columns of type Multiple Icons when they are loaded with '''SetLBImageIndexes''', but I didn't try this with the new routine, only with its precursor: ''AddLBImage'' (obsolete).


To my knowledge, once loaded the original indexes of the icon-resources are lost: for example it's not possible to fetch the original resource index of icon "2" in the Icon List and substitute it with something else. This is only possible on Mac using columns of type Multiple Icons when they are loaded with [[VS:SetLBImageIndexes]], but I didn't try this with the new routine, only with its precursor: SetLBMultImageIndexes (obsolete).
It's also not possible to delete the image-list from the List Browser, once created. For this reason images must be loaded only once In [[VS:Creating_a_Custom_Dialog_Box| SetupDialogC]] and attention be paid that '''AddListBrowserImage''' doesn't land in any repetitive routine: this would add the same image over and over again, each time increasing the index count.


It's also not possible to delete the image-list from the List Browser, once created. For this reason images must be loaded only once In SetupDialogC and attention be paid that [[VS:AddListBrowserImage]] doesn't land in any repetitive routine: this would add the same image over and over again, each time increasing the index count.
The sequence defined by adding images is not relevant if you need the icons for singular cells or for a List of Data Items, but becomes very important if your icons need to be displayed in Radio columns, since this control follows the insertion order of the [[#Icon List| Icon List]] precisely.


The sequence defined by adding images is not relevant if you need the icons for singular cells or for a List of Data Items, but becomes very important if your icons need to be displayed in Radio columns, since this control follows the insertion order of the Icon List precisely.


<code lang="pas">
<code lang="pas">
AddListBrowserImage(dialogID: LONGINT; listBrowserID: LONGINT; imageSpecifier: DYNARRAY[] of CHAR): INTEGER;
AddListBrowserImage(dialogID: LONGINT; listBrowserID: LONGINT; imageSpecifier: DYNARRAY[] of CHAR): INTEGER;
</code>
</code>
[[VS:AddListBrowserImage]] Adds an image to the list of images that a list browser can use.


; imageSpecifier: the path to the image resource (since VW 2104), for example: 'Vectorworks/ResourceBrowser/WallStyle.png'.
; imageSpecifier: the path to the image resource (since VW 2014), for example: 'Vectorworks/ResourceBrowser/WallStyle.png'.
: I prefer to "borrow" icons from the application self, where there is a very large choice: loading resources from Vectorworks spares you the creation of your own resource file[s]. The application ships with a huge number of icons and you always find something that fits your needs.
: I prefer to use icons from the application self, where there is a very large choice: loading resources from Vectorworks spares you the creation of your own resource file[s]. The application ships with a huge number of icons and you always find something that fits your needs.


; result (0-based): the index of the newly inserted icon. This increases at each newly inserted icon. Once added, images cannot be deleted and stay with the List Browser until script ends. For this reason Images should be added to the List Browser only once. This is best done in the SetupDialogC section of the dialog driver.
; result (0-based): the index of the newly inserted icon. This increases at each newly inserted icon. Once added, images cannot be deleted and stay with the List Browser until script ends. For this reason Images should be added to the List Browser only once. This is best done in the [[VS:Creating_a_Custom_Dialog_Box| SetupDialogC]] section of the dialog driver.
: Since the index is 0-based you should remember later to use "-1" for telling cells not to use images. Whenever you see a routine allowing for an image index (for example [[VS:SetLBItemInfo]]) and you don't want an image to load, set the image index parameter to "-1". A typical mistake is to write "0", which will load the first image in the LB, if any loaded. If you didn't load images into your LB previously, you don't need to bother much.
: Since the index is 0-based you should remember later to use "-1" for telling cells not to use images. Whenever you see a routine allowing for an image index (for example [[VS:SetLBItemInfo]]) and you don't want an image to load, set the image index parameter to "-1". A typical mistake is to write "0", which will load the first image in the LB, if any loaded. If you didn't load images into your LB previously, you don't need to bother much.




=== Example: toggling only three images ===
=== Use custom icons ===


<div style="margin: 1em; border: dotted 1px #aaa; padding: 1em; background-color: #F2F2F2;">
* Create icons of size 16/16 px with a resolution of 72dpi.
<code lang="pas">
* Save them as .png file
{ add three images to a List Browser }
* Place them in the same folder where you have your plug-in .vsm file
gImgCnt := -1; { init }
gImgCnt := AddListBrowserImage(gD, cLB_Styles, 'Vectorworks/Standard Images/Visible'); { visible: black eye }
gImgCnt := AddListBrowserImage(gD, cLB_Styles, 'Vectorworks/Standard Images/Invisible'); { invisible: cross }
</code>


[[File:c_LB_toggleImgs.png| left| Toggle Images]]
See [[#Example: visibility toggle| Example: visibility toggle]] for a method to access them.


Since we know that the list starts at zero and the counter always increases by 1, we store the final index in the variable "gImgCnt". If something goes wrong, we have the needed "-1" value to declare the lack of images. To access them later we'll only need to subtract to this variable. You might prefer to access indexes in this fashion whenever your script uses only few images.
=== Use icons from Vectorworks.app ===
</div>


You can use all images shipped in VectorworksXX.app. There are also images stored in the SDK libraries provided by the various plug-ins:
* on Mac
** right-click on the application icon Vectorworks 20xx.app or any .vwlibrary file from the Plug-in Folder
** select '''Show Package Contents'''
** navigate to /Contents/Resources/xxx.vwr/Images
** use the file path name without @2x and suffix
* on Win (to do)


==Columns==


After creating an (optional) [[#Icon List| List of icons]] you can proceed to add columns to the List Browser. While creating each column, it is simple to set immediately its appearance and eventually some modifiers which affect -it goes without saying- the whole column and all cells there included. A column creates ready to display text which doesn't react on clicks. Any other display involves a resetting of [[#Control Type| Control Type]] and [[#Display Type| Display Type]].


Most of the times you create columns only at dialog setup and in a loop. If you do it only once -because you won't delete columns later- the loop needs a place in '''SetupDialogC''' and nowhere else. Nothing forbids you, though, to delete columns and redo them according to your script needs. In this case you'll have the column creation in a sub-routine callable on demand with a wider script scope. But is seldom.
=== Example: selection toggle ===


{| class="wikitable" style="margin: auto;"
The most frequent mistake in dealing with toggles, is to think that an icon list index is the same as a Column Data Item index. They are not the same list, so they might be the same only if the icon list is exactly identical with the Column Data Item list.
! Settings !! Modifiers !! Column set up
|-
|
* [[#Column Titles| Titles]]
* [[#Column Lines| Column Lines]]
* [[#Sorting| Column Sorting]]


|
Example:
* [[#Control Type| Control Type]]
* add 4 images to a list browser: pen, paint bucket, select and blank. The list sequence is 0, 1, 2, 3
* [[#Display Type| Item or Edit Display Type]]
* add 2 column data items to a column: select and blank. The index sequence is 0, 1, whereby img 0 and 1 correspond to 2 and 3 in the LB index.
* [[#Column Data Items| List of Column Data Items]]


|
<div style="margin: 1em; border: dotted 1px #aaa; padding: 1em; background-color: #F2F2F2;">
Insert columns using [[VS:InsertLBColumn]]. Set for each column:
* [[#Column Titles| title appearance]]
* if modifiers are needed, also set up:
** [[#Control Type| Control Type]] (optional)
** [[#Display Type| Item or Edit Display Type]] (optional)
** [[#Column Data Items| List of Column Data Items]] (optional)


Outside any loop set for the whole List Browser:
[[File:c_LB_toggleSel.png| right| Toggle Selection]]
* [[#Column Lines| Column Lines]] (optional)
* [[#Drag and Drop| Drag and Drop Column]] (optional)
* [[#Sorting| Sort Column]] column (optional)
|}


<code lang="pas">
<code lang="pas">
GetNumLBColumns( dialogID:LONGINT; componentID:LONGINT):INTEGER;
</code>


Count of columns present in a List Browser. You will use this call while adding or relating to columns. Remember to decrease the count of columns of -1, if you use it as column index reference, since -again- column indexes are 0-based
{ in the list browser setup, in SetupDialogC: }


<code lang="pas">
{ add blank and selection images to a List Browser and index them: }
InsertLBColumn( dialogID:LONGINT; componentID:LONGINT; columnIndex:INTEGER;  
penLBindex := AddListBrowserImage(dlog, LB, 'Vectorworks/Attributes/Pen.png'); { sets icon index for pen, not in usage, only for extra index }
headerString:STRING; width:INTEGER):INTEGER;
bucketLBindex := AddListBrowserImage(dlog, LB, 'Vectorworks/Attributes/PaintBucket.png'); { bucket, not in usage, only for extra index }
</code>
uncheckedLBindex := AddListBrowserImage(dlog, LB, 'Vectorworks/Standard Images/Blank.png'); { not selected, we use it later }
checkedLBindex := AddListBrowserImage(dlog, LB, 'Vectorworks/Standard Images/Checkmark.png'); { selected, we use it later }


Inserts a column ready to be filled with text cells. Call [[VS:InsertLBColumn]] for each column to be inserted, use the returned index for further column settings. Defaults upon creation are:
{ during column creation : }
{ make a cell toggle status on click }
temp_b := SetLBControlType(dlog, LB, col, 3); { kLBctrMultiState }
temp_b := SetLBItemDisplayType(dlog, LB, col, 1); { kLBdispImageOnly }


* [[#Control Type| Control Type]]: Static = 1
{ upon click on a cell in this column, the value will toggle between "offIndex" and "onIndex" }
* [[#Item Display| Item Display]]: Text Only = 2 (I lied you. Upon creation the Display type is "0", but... read the warning here)
offIndex := InsertLBColumnDataItem(dlog, LB, col, '-', uncheckedLBindex, -1, 0);
onIndex := InsertLBColumnDataItem(dlog, LB, col, 'v', checkedLBindex, -1, 0);


; result (0-based): index of the new column in the List Browser.
{ variant: text-only toggle: }
; columnIndex: at which position in the List Browser the column should be inserted.
{ temp_b := SetLBItemDisplayType(dlog, LB, col, 2); } { kLBdispTextOnly }
: ''BUG: passing "0" as insertion position the title will center after the first row. Moreover in VW 13 if the List Browser has icons loaded, an icon will unexpectedly appear in the title. For this reason is always wise to insert new columns only at the end using GetNumLBColumns.''
{ offIndex := InsertLBColumnDataItem(dlog, LB, col, '-', -1, -1, 0); }
; headerString: the column's title (string). The title aligns left by default. If a different alignment is needed it can be fixed later with [[VS:SetLBColumnHeaderJust]].
{ onIndex := InsertLBColumnDataItem(dlog, LB, col, 'v', -1, -1, 0); }
; width: the width of the column. Can be modified anytime using [[VS:SetLBColumnWidth]]. Don't pass a zero width.


<code lang="pas">
{ ... }
GetLBColumnWidth( dialogID:LONGINT; componentID:LONGINT; columnIndex:INTEGER;
VAR width:INTEGER):BOOLEAN;
SetLBColumnWidth( dialogID:LONGINT; componentID:LONGINT;
fromColumn:INTEGER; toColumn:INTEGER; width:INTEGER):BOOLEAN;
</code>


; fromColumn, toColumn: the range of columns where the width should apply. Mind that the title seems to create a large white space at the end. You should dimension columns rather large otherwise they won't display the whole title text. Under VW 14+ you can use [[VS:GetLBHeaderTextWidth]] to dimension precisely your column width.
{ while loading cell values: }
Often you'll create columns in a loop from string arrays or external files data. In this case you insert the columns with some default width and reset precisely only those columns that need to be different.
temp_b := SetLBItemUsingColumnDataItem(dlog, LB, row, col, onIndex); { set a cell to show as "selected" }
: ''BUG: Column widths "0" crash VW 13 (fixed by build 87094). You must programmatically avoid them and also make sure that your user is not in the position of resizing them to zero, if you wish to grant compatibility with VW 13.''
temp_b := SetLBItemUsingColumnDataItem(dlog, LB, row, col, offIndex); { set a cell to show as "not selected"  }
 
<code lang="pas">
GetLBHeaderTextWidth(className: STRING; allowForSortIcon: BOOLEAN): INTEGER ;
</code>
</code>
</div>


(VW14+) returns the column width needed to fit the column title without resizing. There is a parameter "allowForSortIcon". I didn't try this call yet.
=== Example: visibility toggle ===


If you need to see the standard access to an image toggle, please first look at the example above. This example is a bit more complex than the previous and uses relative indexes. You prefer this approach to save on the amount of variables needed.


=== Column Titles ===
<div style="margin: 1em; border: dotted 1px #aaa; padding: 1em; background-color: #F2F2F2;">
 
Frequently an array of string is a good way to create the titles in a loop. Other times data will be loaded from external files or from existing document objects. Whatever system you choose, you shall remember that column titles cannot be changed after creation. In order to change a column's title the only solution is to destroy the column and recreate it. This can be done with [[VS:DeleteLBColumn]].
 
<code lang="pas">
SetLBColumnImage(nDialogID, nComponentID :LONGINT;  
nColumnIndex, nImageIndex :INTEGER) :BOOLEAN;
</code>
 
; result: FALSE if the column index "nColumnIndex" points to a column that doesn't exists. Note that the routine doesn't return false if the icon index "nImageIndex" points to a missing icon.
; nImageIndex: Use an icon as column title. This replaces the text, you cannot have both text and icon. The image must available in the List Browser's Icon List.
 
<code lang="pas">
<code lang="pas">
GetLBColumnHeaderJust( dialogID:LONGINT; componentID:LONGINT; columnIndex:INTEGER;  
{ add three images to a List Browser and index them: }
VAR justification:INTEGER):BOOLEAN;
imgCnt := -1; { init }
imgVis := AddListBrowserImage(dlog, LB, 'Vectorworks/Standard Images/Visible');
SetLBColumnHeaderJust( dialogID:LONGINT; componentID:LONGINT; columnIndex:INTEGER;  
imgInvis := AddListBrowserImage(dlog, LB, 'Vectorworks/Standard Images/Invisible');
justification:INTEGER):BOOLEAN;
imgGray := AddListBrowserImage(dlog, LB, 'Vectorworks/Standard Images/Gray');
</code>


Modify the alignment of the column title. Use following constants:
{ Alternatively, store only the total count. Retrive them by offset to the count: }
: 1 = Left
imgCnt := -1; { init }
: 2 = Center
imgCnt := AddListBrowserImage(dlog, LB, 'Vectorworks/Standard Images/Visible');
: 3 = Right
imgCnt := AddListBrowserImage(dlog, LB, 'Vectorworks/Standard Images/Invisible');
imgCnt := AddListBrowserImage(dlog, LB, 'Vectorworks/Standard Images/Gray');


<code lang="pas">
{ Or use your own icons : }
GetLBColumnHeaderToolTip( dialogID:LONGINT; componentID:LONGINT; columnIndex:INTEGER;
{ fetch the file path to the .vsm file }
VAR toolTipPrimaryText:STRING; VAR toolTipSubText:STRING):BOOLEAN;
IF (GetPluginInfo(pioName, pioRecordHandle)) & FindFileInPluginFolder(Concat(pioName, '.vsm'), pluginPath) THEN
path2img := Concat(pluginPath, 'Imgs'); { path to a folder named 'Imgs' in your Plug-in folder }
{ ... }


SetLBColumnHeaderToolTip( dialogID:LONGINT; componentID:LONGINT; columnIndex:INTEGER;  
{ retrive your custom images during SetupDialogC }
toolTipPrimaryText:STRING; toolTipSubText:STRING):BOOLEAN;
imgCnt := -1; { init }
justification:INTEGER):BOOLEAN;
imgCnt := AddListBrowserImage(dlog, LB, Concat(path2img, '/Visible.png'));
imgCnt := AddListBrowserImage(dlog, LB, Concat(path2img, '/Invisible.png'));
imgCnt := AddListBrowserImage(dlog, LB, Concat(path2img, '/Gray.png'));  
</code>
</code>


Gets/sets hovering tips for the column headers. Setting tool tips is quite handy when the column width will certainly be too small and titles will be cropped: pass then titles as tool tip.
[[File:c_LB_toggleImgs.png| left| Toggle Images]]
 
; toolTipPrimaryText: text appearing on hovering over the column title.
; toolTipSubText: text appearing pressing the cmd/alt (Mac/Win) key while hovering.
: ''BUG: don't use GetLBColumnHeaderToolTip if you plan to use your script on VW 13. It crashes VW under Mac (fixed by VW 14, built 90067).''
 
 
=== Column Lines ===
 
Column lines are the gray vertical lines drawn between each column. They are optional. Columns with control type [[#Radio| Radio]] have an extra option for setting the sub-titles column lines.
 
<code lang="pas">
AreLBColumnLinesEnabled(dialogID: LONGINT; componentID: LONGINT): BOOLEAN;
</code>
 
Checks on/off status of column lines for a List Browser.
 
<code lang="pas">
EnableLBColumnLines(dialogID: LONGINT; componentID: LONGINT;
enableColumnLines:BOOLEAN);
</code>
 
Default: FALSE. Toggles the vertical column lines on/off. It affects a whole List Browser, so this call shall be kept outside repetitive routines. Usually it is called at the end of the List Browser setup routine. Don't confuse it with [[VS:EnableLBRadioColumnLines]].
 
<code lang="pas">
AreLBRadioColumnLinesEnabled(dialogID: LONGINT; componentID: LONGINT; columnIndex: INTEGER): BOOLEAN;
</code>
 
(only for control type [[#Radio| Radio]]) Checks on/off status of the sub-column lines for a chosen radio column. Note that this applies to a column, not to the whole List Browser as AreLBColumnLinesEnabled.
 
<code lang="pas">
EnableLBRadioColumnLines(dialogID: LONGINT; componentID: LONGINT; columnIndex: INTEGER;
enableRadioColumnLines: BOOLEAN);
</code>
 
Default: FALSE. (only for control type [[#Radio| Radio]]) Draws extra gray vertical lines for each sub-column in the chosen Radio column. For this to show you need:
 
* Column with control type [[#Radio| Radio]]
* [[#Column Data Items List| List of Column Data Items]]
This is applied on column index basis. Most of the times only a single Radio column is needed in a List Browser, so you'll choose to enable the radio vertical lines at the end of -and outside- the column creation loop (if any).
 
==Column Data Items List==


Since we know that the list starts at zero and the counter always increases by 1, we store the final index in the variable "imgCnt". If something goes wrong, we have the needed "-1" value to declare the lack of images. To access them later we'll only need to subtract to this variable. You might prefer to access indexes in this fashion whenever your script uses only few images.
</div>


==Rows and Cells==




{| class="wikitable" style="margin: auto;"
{| class="wikitable" style="margin: auto;"
|-
|-
! [[User:CBM-c-/VS-List_Browsers| Introduction]]
! [[User:CBM-c-/VS-List_Browsers_part_1| Part 1: Creation]]
! List_Browsers_part_1
! [[User:CBM-c-/VS-List_Browsers_part_2| Part 2: Columns]]
! [[User:CBM-c-/VS-List_Browsers_part_2| List_Browsers_part_2]]
! [[User:CBM-c-/VS-List_Browsers_part_3| Part 3: Rows and Cells]]
! [[User:CBM-c-/VS-List_Browsers_part_4| Part 4: Events]]
|}
|}

Latest revision as of 10:10, 31 January 2021


Some of you know me as Orso from the now defunct Vectorlab, I maintained it for many years. Here is the List Browsers article from the former Vectorlab site. For better understanding please use the comprehensive example at Dialog with List Browser.

By --_c_ 01:31, 31 December 2020 (EST), previously Orso.B.Schmid, 2009-2018.


List Browsers

List Browsers allow for great layout, advanced data management, but also amazing layout features within the single cells. Is not difficult to load them with some text data and make them display a whatever list. Still the advanced settings of List Browsers are quite enigmatic. After years of trial and error, I attempt here to resume what I discovered. If you find an error, I'd be glad to be informed. I am a user and had no reference literature for this article which is based on pure experience, if you are a programmer you will probably find the terms employed not quite the right ones.

Since List Browsers are so complex, the best way to learn how to use them is to have some free code available for experiments. Free code for List Browsers can be counted on one hand and none of the snippets available tells you a single thing about Control Types, Edit Display Types, Item Display Types, Column Data Items and so on.

Use the example Dialog with List Browser to experiment with the List Browser's options.


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

Introduction

The display of List Browsers is determined by the right combination of four settings: Control Type, Display Type, Cell's Column Owner, Column Data Items.

This is all rather difficult, specially because it is not documented. It resembles a 4D-puzzle.


Column Data Items List Browser set up
Icons, Strings
Column Cell
Control Type

display HOW

Display Type

display WHICH DATA

Column Owner Type

display WHAT

  1. Static
  2. Radio
  3. Multi State
  4. Single Instance Icon
  5. Static icon
  6. Number
  7. Multiple Icons
  1. Image
  2. Text only
  3. Image and Text
0. None
  1. Solid rect
  2. Dual solid rect
  3. Pattern rect
  4. Dual pattern rect
  5. Gradient or image
  6. Blank
  7. Text
  8. Dashed line


Lists Validity Scope

List Browsers are more than tables of cells, they browse lists. You must imagine them like special containers with built-in lists of data which can be created and used on need. These lists have different validity scope.

List of icons
available to the whole List Browser.
Column Data Items
available to one column. Column Data Items will often use images from the List Browser's Image list, but they can also contain only strings.


Create a List Browser

List Browsers are called in a Layout Creation routine with CreateLB.

CreateLB(dialogID: LONGINT; listBrowserID: LONGINT; 
	widthInCharacters: INTEGER; heightInCharacters: INTEGER);

VS:CreateLB Creates an empty List Browser with no rows and no columns.

widthInCharacters, heightInCharacters
is different between Mac and PC. Basically on Mac all dialog items with a scroll bar interpret the width excluding the bar. This will influence the width of dialog elements such as PullDown menus, List Browsers, Lists and such. These items won't align with Static Text, Edit fields and similar: the scroll bar will be outside alignment. You must correct the width programmatically.


List Browsers in resizable dialogs

List Browsers are special dialog items with a built-in binding to their parent container. If a dialog is resizable, they resize width and height automatically, without any Edge Binding. For this reason you'll prefer to leave List Browsers outside groups: they will fit beautifully to the dialog window without you to bother.

dlog := CreateResizableLayout('List Browsers test', TRUE, 'Close', '', TRUE, FALSE);
{ ... }
CreateLB(dlog, lb, lbWidth, lbHeight);


Load a List Browser

Your List Browser after creation is just an empty container without columns, rows or any data. Before loading the List Browser it is important to understand what needs to be loaded once and if there are things that needs to be loaded repeatedly, after destroying data. Aside of images, which must be really loaded only once, all other List Browser elements can be loaded, destroyed, created or modified according to your needs. The typical script will set up a List Browser once in SetupDialogC and manipulate repeatedly only rows data. Usually you will:

Then you'll organize your loading code as follows:

  • needs loading once --> has a place in the SetupDialogC CASE item of your dialog driver routine
  • needs loading repeatedly --> resides in a subroutine with wider validity scope (including SetupDialogC for the first run).


Items and Sub-items, index (0-based)

At start the main difficulty in understanding List Browsers is caused by the naming of the various routine parameters. Everyone will struggle initially with "itemIndex" and "subItemIndex", sometimes also called (more clearly) "columnIndex". The official documentation uses names not consequently. Just some examples:

row index
itemIndex, nItemIndex
column index
subItemIndex, nSubItemIndex, columnIndex

If you see both parameters for row and for column you know that you'll target a cell (intersection of row and column).

All indexes in List Browsers are 0-based:

This implies that for setting the absence of an image -for example- you need to pass "-1". Take care to init your variables to -1. Mind the routine AddListBrowserImage which on Mac might return "0" also if it failed to insert an image.

Many mistakes in List Browsers are caused by unwanted 0-indexes in images or Column Data Items.


Icon List

Very relevant for the layout of a List Browser is the list of icons (optional). Here you store small icons that will be available to the whole List Browser. The icons must be either loaded from external resource files or recycled from the built-in Vectorworks icons. They can be used directly from the singular cells and/or be used to build data in the List of Data Items of a column. An Icon List can be created using AddListBrowserImage.

There is a single routine allowing to load icon resources without pre-loading them in the Icon List first: SetLBImageIndexes, which applies only to columns with control type Multiple Icons.

To my knowledge, once loaded the original indexes of the icon-resources are lost: for example it's not possible to fetch the original resource index of icon "2" in the Icon List and substitute it with something else. This is only possible on Mac using columns of type Multiple Icons when they are loaded with SetLBImageIndexes, but I didn't try this with the new routine, only with its precursor: AddLBImage (obsolete).

It's also not possible to delete the image-list from the List Browser, once created. For this reason images must be loaded only once In SetupDialogC and attention be paid that AddListBrowserImage doesn't land in any repetitive routine: this would add the same image over and over again, each time increasing the index count.

The sequence defined by adding images is not relevant if you need the icons for singular cells or for a List of Data Items, but becomes very important if your icons need to be displayed in Radio columns, since this control follows the insertion order of the Icon List precisely.


AddListBrowserImage(dialogID: LONGINT; listBrowserID: LONGINT; imageSpecifier: DYNARRAY[] of CHAR): INTEGER;

VS:AddListBrowserImage Adds an image to the list of images that a list browser can use.

imageSpecifier
the path to the image resource (since VW 2014), for example: 'Vectorworks/ResourceBrowser/WallStyle.png'.
I prefer to use icons from the application self, where there is a very large choice: loading resources from Vectorworks spares you the creation of your own resource file[s]. The application ships with a huge number of icons and you always find something that fits your needs.
result (0-based)
the index of the newly inserted icon. This increases at each newly inserted icon. Once added, images cannot be deleted and stay with the List Browser until script ends. For this reason Images should be added to the List Browser only once. This is best done in the SetupDialogC section of the dialog driver.
Since the index is 0-based you should remember later to use "-1" for telling cells not to use images. Whenever you see a routine allowing for an image index (for example VS:SetLBItemInfo) and you don't want an image to load, set the image index parameter to "-1". A typical mistake is to write "0", which will load the first image in the LB, if any loaded. If you didn't load images into your LB previously, you don't need to bother much.


Use custom icons

  • Create icons of size 16/16 px with a resolution of 72dpi.
  • Save them as .png file
  • Place them in the same folder where you have your plug-in .vsm file

See Example: visibility toggle for a method to access them.

Use icons from Vectorworks.app

You can use all images shipped in VectorworksXX.app. There are also images stored in the SDK libraries provided by the various plug-ins:

  • on Mac
    • right-click on the application icon Vectorworks 20xx.app or any .vwlibrary file from the Plug-in Folder
    • select Show Package Contents
    • navigate to /Contents/Resources/xxx.vwr/Images
    • use the file path name without @2x and suffix
  • on Win (to do)


Example: selection toggle

The most frequent mistake in dealing with toggles, is to think that an icon list index is the same as a Column Data Item index. They are not the same list, so they might be the same only if the icon list is exactly identical with the Column Data Item list.

Example:

  • add 4 images to a list browser: pen, paint bucket, select and blank. The list sequence is 0, 1, 2, 3
  • add 2 column data items to a column: select and blank. The index sequence is 0, 1, whereby img 0 and 1 correspond to 2 and 3 in the LB index.
Toggle Selection
Toggle Selection

{ in the list browser setup, in SetupDialogC: }

{ add blank and selection images to a List Browser and index them: }
penLBindex := AddListBrowserImage(dlog, LB, 'Vectorworks/Attributes/Pen.png'); { sets icon index for pen, not in usage, only for extra index }
bucketLBindex := AddListBrowserImage(dlog, LB, 'Vectorworks/Attributes/PaintBucket.png'); { bucket, not in usage, only for extra index }
uncheckedLBindex := AddListBrowserImage(dlog, LB, 'Vectorworks/Standard Images/Blank.png'); { not selected, we use it later }
checkedLBindex := AddListBrowserImage(dlog, LB, 'Vectorworks/Standard Images/Checkmark.png'); { selected, we use it later }

{ during column creation : }
{ make a cell toggle status on click }
temp_b := SetLBControlType(dlog, LB, col, 3); { kLBctrMultiState }
temp_b := SetLBItemDisplayType(dlog, LB, col, 1); { kLBdispImageOnly }

{ upon click on a cell in this column, the value will toggle between "offIndex" and "onIndex" }
offIndex := InsertLBColumnDataItem(dlog, LB, col, '-', uncheckedLBindex, -1, 0);
onIndex := InsertLBColumnDataItem(dlog, LB, col, 'v', checkedLBindex, -1, 0);

{ variant: text-only toggle: }
{ temp_b := SetLBItemDisplayType(dlog, LB, col, 2); } { kLBdispTextOnly }
{ offIndex := InsertLBColumnDataItem(dlog, LB, col, '-', -1, -1, 0); }
{ onIndex := InsertLBColumnDataItem(dlog, LB, col, 'v', -1, -1, 0); }

{ ... }

{ while loading cell values: }
temp_b := SetLBItemUsingColumnDataItem(dlog, LB, row, col, onIndex); { set a cell to show as "selected"  }
temp_b := SetLBItemUsingColumnDataItem(dlog, LB, row, col, offIndex); { set a cell to show as "not selected"  }

Example: visibility toggle

If you need to see the standard access to an image toggle, please first look at the example above. This example is a bit more complex than the previous and uses relative indexes. You prefer this approach to save on the amount of variables needed.

{ add three images to a List Browser and index them: }
imgCnt := -1; { init }
imgVis := AddListBrowserImage(dlog, LB, 'Vectorworks/Standard Images/Visible');
imgInvis := AddListBrowserImage(dlog, LB, 'Vectorworks/Standard Images/Invisible');
imgGray := AddListBrowserImage(dlog, LB, 'Vectorworks/Standard Images/Gray');

{ Alternatively, store only the total count. Retrive them by offset to the count: }
imgCnt := -1; { init }
imgCnt := AddListBrowserImage(dlog, LB, 'Vectorworks/Standard Images/Visible');
imgCnt := AddListBrowserImage(dlog, LB, 'Vectorworks/Standard Images/Invisible');
imgCnt := AddListBrowserImage(dlog, LB, 'Vectorworks/Standard Images/Gray'); 

{ Or use your own icons : }
{ fetch the file path to the .vsm file }
IF (GetPluginInfo(pioName, pioRecordHandle)) & FindFileInPluginFolder(Concat(pioName, '.vsm'), pluginPath) THEN
	path2img := Concat(pluginPath, 'Imgs'); { path to a folder named 'Imgs' in your Plug-in folder }
	{ ... }

{ retrive your custom images during SetupDialogC }
imgCnt := -1; { init }
imgCnt := AddListBrowserImage(dlog, LB, Concat(path2img, '/Visible.png'));
imgCnt := AddListBrowserImage(dlog, LB, Concat(path2img, '/Invisible.png'));
imgCnt := AddListBrowserImage(dlog, LB, Concat(path2img, '/Gray.png')); 
Toggle Images
Toggle Images

Since we know that the list starts at zero and the counter always increases by 1, we store the final index in the variable "imgCnt". If something goes wrong, we have the needed "-1" value to declare the lack of images. To access them later we'll only need to subtract to this variable. You might prefer to access indexes in this fashion whenever your script uses only few images.


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