eXept Software AG Logo

Smalltalk/X Webserver

Documentation of class 'ListView':

Home

Documentation
www.exept.de
Everywhere
for:
[back]

Class: ListView


Inheritance:

   Object
   |
   +--GraphicsMedium
      |
      +--DisplaySurface
         |
         +--SimpleView
            |
            +--View
               |
               +--ListView
                  |
                  +--SelectionInListView
                  |
                  +--TextView

Package:
stx:libwidg
Category:
Views-Text
Version:
rev: 1.528 date: 2024/04/09 12:19:08
user: stefan
file: ListView.st directory: libwidg
module: stx stc-classLibrary: libwidg

Description:


a View for (string-)lists.

This class can only passively display collections of strings,
text or display objects which behave line-like (i.e. all have constant height).

Selections, editing, cursors etc. must be implemented in subclasses.
(see SelectionInListView, TextView etc.)

This code currently handles only fixed-height fonts correctly -
it should be rewritten in some places to not compute the position/height from
the view's font height, but by accumulating line heights...

It can only scroll by full lines vertically (i.e. setting firstLineShown to ~~ 1)
which should be changed to have this behavior optionally for smooth scroll.

The text is internally kept in the 'list' instance variable, and is supposed to consist
of a collection (Ordered-, String- or VirtualCollection) of line entries.
Typically, individual entries are either strings/text or nil (for empty lines).
However, ANY object which supports the displayOn: and widthIn: protocol can be
used - see MultipleColumnListEntry as an example.
Therefore, ListView (and all subclasses) are prepared to handle non-string entries
(especially: attributed Text and labelAndIcon-like entities).

The internal version of the text has tabulators expanded to blanks.
ListView is not prepared to deal with them.
When text is exchanged with an external medium (i.e. reading/writing files),
these are expanded/compressed assuming a tab-setting of 8.
This is done independent of the user's tab setting, which is used ONLY for positioning,
while the text is edited.
Thus, even if the tab setting is multiple of 4's, tabs are
written in multiples of 8 when the text is saved.
Since this is the default on all ascii terminals and printers,
this assures that the text looks correctly indented when finally printed.

Notice:
-------
ListView is one of the OLDEST widget classes in the system and definitely requires a major rewrite:

Due to historic reasons (ListView implemented scrolling before the general
scrolling code in View was added), this one does scrolling different from all other
views. The general scrolling code (in View) uses the transformation for transparent scrolling
using the viewOrigin (transparent means, that the code does not need to know - it simply draws
as if all of the text was visible).

Here in ListView, the transformation is not used, instead it is done again, and different,
by keeping the firstLineShown (i.e. vertical offset) and leftOffset (horizontal offset).
Even worse: the firstLineShown is a line-index, the most annoying consequence of this is that
scrolling is done by lines here, whereas it is done in pixels in the View class.
Thus, be very careful, when changing things (better: don't touch it ;-).
Also, the viewOrigin variable is only valid for the x coordinate. The viewOrigin's y is always 0 !

Also, all controller functionality is completely performed by the listView
(and subclasses) itself. It is still possible, to define and set a specialized
controller, though. I.e. if you like to change the input behavior, define
a corresponding controller class and intersect the keyXXX/buttonXXX messages
there.

This may be totally rewritten ... so don't depend on the internals; especially the scrolling
code will be totally removed here and the inherited functionality be used in the next version.

Also Notice:
------------
because ListView was written at a time when most of the graphics was done via remote connections
(X-window network protocol), it is highly tuned to avoid redraw operations. Thus, it can be used
happily over a slow Wide area LAN (say: 64kBit connection).
In that, it performed *much* better than other widgets, especialy Java and Qt, some of which are
hardly usable via the network.
It may be questionable whether this is still a requirement these days, where network connections
are usually pretty fast.
However, the author insists on this to remain as it is, because we do have customers
and applications which rely on relatively good remote display performance!
Future underlying graphics may well become network dependent in the future, for example, when
the display connection is implemented as an RPC into a web browser...

Also Notice (Virtual line collections):
------------
ListView shall be configurable to avoid accesses to its underlying list if required.
Currently, it can be customized to disable lineWidth computation, tab expansion and scanning for
non-string entries.
All of which is required when huge texts which are not in memory are to be displayed
(for example: a virtual array of 10million text lines).
Please be careful to not reintroduce such code when adding features
(as happened in the past). ListView shall always be configurable to only access
a minimum subset of the line collection (i.e. only the currently visible page),
by customizing the tab-expansion, line-end and widthOfContents behavior.
In that case, the max lineWidth (which is used by the h-scroller computation) should be
adapted dynamically.

[Instance variables:]

  list                <aCollection>           the text strings, a collection of lines.
                                              Nils may be used for empty lines.

  firstLineShown      <Number>                the index of the 1st visible line (1 ..)
  leftOffset          <Number>                left offset for horizontal scroll

  nFullLinesShown     <Number>                the number of unclipped lines in visible area
                                              (internal; updated on size changes)
  nLinesShown         <Number>                the number of lines in visible area, incl. partial
                                              (internal; updated on size changes)

  fgColor             <Color>                 color to draw characters
  bgColor             <Color>                 the background

  showPartialLines    <Boolean>               allow last line to be partial displayed
  leftMargin          <Number>                margin at left in pixels
  topMargin           <Number>                margin at top in pixels
  textStartLeft       <Number>                margin + leftMargin (internal)
  textStartTop        <Number>                margin + topMargin (internal)
  innerWidth          <Number>                width - margins (internal)
  tabPositions        <aCollection>           tab stops (cols)
  fontHeight          <Number>                font height in pixels (internal)
  fontAscent          <Number>                font ascent in pixels (internal)
  fontIsFixed         <Boolean>               true if it's a fixed font (internal)
  fontWidth           <Number>                width of space (internal)
  lineSpacing         <Number>                pixels between lines
  lastSearchPattern   <String>                last pattern for searching
                                              (kept to provide a default for next search)
  lastSearchIgnoredCase   <Boolean>           last search ignored case
                                              (kept to provide a default for next search)
  wordCheck           <Block>                 rule used for check for word boundaries in word select
                                              The default rule is to return true for alphaNumeric characters.
                                              (can be changed to allow for underscore and other
                                               characters to be treated as alphaCharacters)

  autoScrollBlock     <Block>                 block installed as timeoutBlock when doing an
                                              autoScroll (internal)
  autoScrollDeltaT                            computed scroll time delta in seconds (internal)

  includesNonStrings                          cached flag if any non-strings are in list
  widthOfWidestLine                           cached width of widest line
  listMsg                                     if view has a model and listMsg is non-nil,
                                              this is sent to the model to acquired a new contents
                                              whenever a change of the aspect  (aspectMsg) occurs.

  viewOrigin                                  the current origin

  backgroundAlreadyClearedColor               internal; speedup by avoiding
                                              multiple fills when drawing
                                              internal lines

  scrollWhenUpdating
                            <Symbol>        defines how the view is scrolled if the
                                            model changes its value by some outside activity
                                            (i.e. not by user input).
                                            Can be one of:
                                                #keep / nil     -> stay unchanged
                                                #endOfText      -> scroll to the end
                                                #beginOfText    -> scroll to the top
                                            The default is #beginOfText (i.e. scroll to top).

[StyleSheet parameters:]

  textForegroundColor                         defaults to Black
  textBackgroundColor                         defaults to White
  textFont                                    defaults to defaultFont
  textTabPositions                            defaults to #(1 9 17 25 ...)

copyright

COPYRIGHT (c) 1989 by Claus Gittinger All Rights Reserved This software is furnished under a license and may be used only in accordance with the terms of that license and with the inclusion of the above copyright notice. This software may not be provided or otherwise made available to, or used by, any other person. No title to or ownership of the software is hereby transferred.

Class protocol:

accessing private classes
o  searchSpec

defaults
o  defaultTabPositions
return an array containing the styleSheet's default tab positions

o  defaultTabPositions: aVector
set the array containing the styleSheet's tab positions

Usage example(s):

     ListView defaultTabPositions:(ListView tab4Positions)

o  tab4Positions
return an array containing tab positions for 4-col tabs

o  tab8Positions
return an array containing tab positions for 8-col tabs

o  updateStyleCache
extract values from the styleSheet and cache them in class variables

o  userDefaultTabPositions
return an array containing the user's default tab positions

o  userDefaultTabPositions: aVector
set the array containing the user's tab positions

Usage example(s):

     self userDefaultTabPositions:(self tab4Positions)

o  userDefaultTabPositions: aVectorWithNewTabPostitions setInAllViews: aBoolean
set the array containing the user's tab positions

Usage example(s):

     self userDefaultTabPositions:(self tab4Positions) setInAllViews:true
     self userDefaultTabPositions:(self tab8Positions) setInAllViews:true


Instance protocol:

accessing
o  innerHeight
return the number of pixels visible of the contents
- redefined since ListView adds another margin to start the text
somewhat to indented from the 3D border.

accessing-behavior
o  checkLineEndConventionWhenUpdating
return the line-end convention check when updating behavior.
If true (the default), the first line of the list given is checked for having a
cr-lf line end (which is a DOS convention), and the lineEndCRLF flag is set dynamically.
If false, the lineEndCRLF remains as specified by the user.
You may want to disable this flag if it is very expensive to generate a line
(although, only the very first line is checked, anyway)

o  checkLineEndConventionWhenUpdating: aBoolean
define the line-end convention check when updating behavior.
If true (the default), the first line of the list given is checked for having a
cr-lf line end (which is a DOS convention), and the lineEndCRLF flag is set dynamically.
If false, the lineEndCRLF remains as specified by the user.
You may want to disable this flag if it is very expensive to generate a line
(although, only the very first line is checked, anyway)

o  checkedLinesForWidthOfContentsComputation
return how many and which lines to consider in the widthOfContents computation,
which is needed by the scrollBar interface.

If nil (the default), all lines are processed and the width of the longest line is taken.
If positive, that number of lines is checked near the start of the text,
if negative, from the end of the text.
If 0, the width is dynamically readjusted, as lines are drawn.

You may want to change this to 1 if it is guaranteed that all lines are of the same width,
or -1, if all are shorter than the last line.
(useful, for example, when it is very expensive to generate all lines, and a huge number
of same-width lines is generated through a virtual array)

o  checkedLinesForWidthOfContentsComputation: aNumberOrNil
set how many and which lines to consider in the widthOfContents computation,
which is needed by the scrollBar interface.

If nil (the default), all lines are processed and the width of the longest line is taken.
If positive, that number of lines is checked near the start of the text,
if negative, from the end of the text.
If 0, the width is dynamically re adjusted, as lines are drawn.

You may want to change this to 1 if it is guaranteed that all linesa are of the same width,
or -1, if all are shorter than the last line.
(useful, for example, when it is very expensive to generate all lines, and a huge number
of same-width lines is generated through a virtual array)

o  compareModelWhenUpdating
return the compare when updating behavior.

If true (the default), the list of lines as given due to a model update
is processed and compared against the currently shown text.
If they are the same, no action is taken.

This behavior is ok in 99.99% of all applications.
However, you may turn this off iff:
- it is very expensive to process the list (for example, because the list
is defined by a virtual array, which computes the lines dynamically, on
the fly).
One use where this flag should be turned off is in the hex-memory display,
which is able to simulate texts with millions of lines, but they are actually
simulated by generating the presented lines dynamically, as they are displayed.

o  compareModelWhenUpdating: aBoolean
define the compare when updating behavior.
If true (the default), the list of lines as given due to a model update
is processed and compared against the currently shown text.
If they are the same, no action is taken.
This behavior is ok in 99.99% of all applications.
However, you may turn this off iff:
- it is very expensive to process the list (for example, because the list
is defined by a virtual array, which computes the lines dynamically, on
the fly).
One use where this flag should be turned off is in the hex-memory display,
which is able to simulate texts with millions of lines, but they are actually
simulated by generating the presented lines dynamically, as they are displayed.

o  expandTabsWhenUpdating
return the tab expansion behavior.
If true (the default), the list of lines as given via #list: or
due to a model update is processed and lines are replaced by lines with
tabs expanded.
This behavior is ok in 99.99% of all applications.
However, you may turn this off iff:
- you are certain, that no tabs are in the passed in list
- it is very expensive to process the list (for example, because the list
is defined by a virtual array, which computes the lines dynamically, on the fly).
One use where this flag should be turned off is in the hex-memory display,
which is able to simulate texts with millions of lines, but they are actually
simulated by generating the presented lines dynamically, as they are displayed.
Notice, that to totally prevent scanning og the whole text, you may have to turn off
other flags, such as checkineEndConventionWhenUpdating

o  expandTabsWhenUpdating: aBoolean
define the tab expansion behavior.
If true (the default), the list of lines as given via #list: or
due to a model update is processed and lines are replaced by lines with
tabs expanded.
This behavior is ok in 99.99% of all applications.
However, you may turn this off iff:
- you are certain, that no tabs are in the passed in list
- it is very expensive to process the list (for example, because the list
is defined by a virtual array, which computes the lines dynamically, on the fly).
One use where this flag should be turned off is in the hex-memory display,
which is able to simulate texts with millions of lines, but they are actually
simulated by generating the presented lines dynamically, as they are displayed.
Notice, that to totally prevent scanning og the whole text, you may have to turn off
other flags, such as checkineEndConventionWhenUpdating

o  isReadOnly
return true, if the text is readonly.

o  lineEndCRLF
answer true, if CRLF is used for the line end.
This is true for DOS/Windows files.
Otherwise 'Character cr' is the line end (which is LF in unix)

o  readOnly: aBoolean
for protocol compatibility with editTextViews,
but actually ignored

o  scrollWhenUpdating
return the scroll behavior, when I get a new text
(via the model or the #contents/#list)
Possible returnValues are:
#keep / nil -> no change
#endOfText -> scroll to the end
#beginOfText -> scroll to the top
The default is #keep.
This may be useful for fields which get new values assigned from
the program (i.e. not from the user)

o  scrollWhenUpdating: aSymbolOrNil
define how to scroll, when I get a new text
(via the model or the #contents/#list)
Allowed arguments are:
#keep / nil -> no change
#endOfText -> scroll to the end
#beginOfText -> scroll to the top
The default is #keep.
This may be useful for fields which get new values assigned from
the program (i.e. not from the user)

o  wordCheckBlock: aBlock
set the word-check block - this block is called with a character argument,
when the end/beginning of a word is searched.
It should return true, if the character belongs to the word.
The default block is set in #initialize, and returns true for alphanumeric
(national) characters.
Applications may change it to include underlines, dollars or other characters.
(a C/C++ editor would include underlines ...)
This is used eg. when double clicking on a word or when pressing CTRL-w.

accessing-channels
o  listHolder

o  listHolder: aListHolder

accessing-contents
o  add: aString
add a line and redisplay

o  add: aString beforeIndex: index
add a line and redisplay

o  addAll: aCollectionOfLines beforeIndex: index
add a bunch of lines and redisplay

o  at: lineNr
retrieve a line's item;
return nil if beyond end-of-text.
this allows textViews to be used like collections in some places.
Notice: for text lists, this returns strings (same as listAt:);
for non-text lists, the item is returned.

o  at: index put: aString
change a line and redisplay

o  characterAtCharacterPosition: charPos
return the character at a 1-based character position.
Return a space character if nothing is there
(i.e. beyond the end of the line or below the last line)

o  characterAtLine: lineNr col: colNr
return the character at physical line/col.
The lineNr and colNr arguments start at 1, for the top-left character.
Return a space character if nothing is there
(i.e. beyond the end of the line or below the last line)

o  contents
return the contents as a string or text (if there is emphasis),
terminated by the line end character (sequence)

o  contents: aStringOrStringCollection
set the contents (either a String or a Collection of strings)
also scroll to top. See #setContents:, which does not scroll.
If the argument is a string, it is converted
to a collection of line-strings here.

o  contentsAsStringCollection
return the contents as a string or text (if there is emphasis),
terminated by the line end character (sequence)

o  contentsAsStringCollectionWithoutEmphasis
return the contents as a collection of string (without emphasis),
terminated by the line end character (sequence)

o  contentsWithoutEmphasis
return the contents as a real string (without emphasis),
terminated by the line end character (sequence)

o  flushCachedWidthOfWidestLine
call this ,if the underlying contents changes without me getting to know
(i.e. if the line is a dynamically generated one,
such as a hexDump inside a virtual array)

o  from: from to: to do: aBlock
evaluate aBlock on some of my lines

o  grow: n
grow our list

o  lineAtY: y
return the lineNr for a given y-(view-)coordinate

o  list
return the contents as a collection of strings.
This returns the view's internal list - modifying it may confuse
the listView.

o  list: aCollection
set the contents (a collection of strings or list entries)
and scroll as specified in scrollWhenUpdating (default:top-left).
See also #setList:, which does not scroll.
Tabs are expanded (to spaces).
The passed list is scanned for nonStrings
(remembered to optimize later redraws).

o  list: aCollection expandTabs: expand
set the contents (a collection of strings)
and scroll as specified in scrollWhenUpdating (default:top-left).
If expand is true, tabs are expanded (to spaces).
The passed list is scanned for nonStrings (remembered to optimize
later redraws).

o  list: aCollection expandTabs: expand scanForNonStrings: scan
set the contents (a collection of strings)
and scroll as specified in scrollWhenUpdating (default:top-left).
If expand is true, tabs are expanded (to spaces).
If scan is true, scan the passed list for nonStrings; otherwise,
assume that it does contain non-strings
(remembered to optimize later redraws).

o  list: aCollection expandTabs: expand scanForNonStrings: scan includesNonStrings: nonStringsIfNoScan
set the contents (a collection of strings)
and scroll as specified in scrollWhenUpdating (default:top-left).
If expand is true, tabs are expanded (to spaces).
If scan is true, scan the passed list for nonStrings;
otherwise, take the information from the nonStrings arg.
(the nonStrings information is remembered to optimize later redraws & height computations).

o  list: aCollection expandTabs: expand scanForNonStrings: scan includesNonStrings: nonStringsIfNoScan redraw: doRedraw
set the contents (a collection of strings)
and scroll as specified in scrollWhenUpdating (default:top-left).
If expand is true, tabs are expanded (to spaces).
If scan is true, scan the passed list for nonStrings;
otherwise, take the information from the nonStrings arg.
(the nonStrings information is remembered to optimize later redraws & height computations).

o  listAt: lineNr
given a lineNumber, return the corresponding string
This is used for accessing; i.e. for non-string entries, this
returns the corresponding string.
Use #at: to get to the real item (if it is not a string)

o  removeFromIndex: startLineNr toIndex: endLineNr
delete some lines

o  removeIndex: lineNr
delete a line, redraw the view.
Returns the receiver

o  removeIndexWithoutRedraw: lineNr
delete a line, given its lineNr - no redraw;
return true, if something was really deleted (so sender knows,
if a redraw is needed)

o  replaceFrom: startLineNr to: endLineNr with: aCollection startingAt: replStartIndex
replace some lines

o  setContents: something
set the contents (either a string or a Collection of strings)
don't change position (i.e. do not scroll).
This can be used to update a self-changing list
(for example: a file list being shown, without disturbing user too much).
Compare with #contents:, which scrolls to top.

o  setList: aCollection
set the contents (a collection of strings);
do not change position (i.e. do not scroll).
This can be used to update a self-changing list
(for example: a file list being shown, without disturbing user too much)

o  setList: aCollection expandTabs: expandTabs
set the contents (a collection of strings);
do not change position (i.e. do not scroll).
This can be used to update a self-changing list
(for example: a file list being shown, without disturbing the user too much)

o  setList: aCollection expandTabs: expandTabs redraw: doRedraw
set the contents (a collection of strings);
do not change position (i.e. do not scroll).
This can be used to update a self-changing list
(for example: a file list being shown, without disturbing the user too much)

o  setList: aCollection expandTabs: expandTabs scanForNonStrings: scan includesNonStrings: nonStringsIfNoScan redraw: doRedraw
set the contents (a collection of strings);
do not change position (i.e. do not scroll).
This can be used to update a self-changing list
(for example: a file list being shown, without disturbing the user too much).
TODO: this stinks: most of the code is the same as in #list:expandTabs:...
needs a refactoring

Usage example(s):

"/                    self setList:newText expandTabs:expandTabsWhenUpdating

o  setWidthOfContents: nPixels
can be set to prevent scanning the while text
(eg. if the contents is in the list is expensive to compute)

o  size
return the size (i.e. number of lines)
this allows textViews to be used like collections in some places.

o  stringAtLine: lineNr from: col1 to: col2
return the substring starting at physical line/col1, up-to and
including col2.
The lineNr and colNr arguments start at 1, for the top-left character.
Fills the string with space characters at the right.
(i.e. beyond the end of the line or below the last line)

o  textFromCharacterPosition: charPos1 to: charPos2
return some text as a collection of (line-)strings.

o  textFromLine: startLine col: startCol toLine: endLine col: endCol
return some text as a collection of (line-)strings.

o  withoutRedrawAt: index put: aString
change a line without redisplay and WITHOUT any sizeChange notifications.
Somewhat dangerous, since scrollBars will not be informed about contents-changes.
Use only if multiple lines are to be changed, and a sizeChanged is invoked by some other
means at the end.

accessing-look
o  backgroundColor
return the background color

o  backgroundColor: aColor
set the background color of the contents

o  font: aFont
set the font for all shown text.
Redraws everything.
CAVEAT: with the addition of Text objects,
this method is going to be obsoleted by a textStyle
method, which allows specific control over
normalFont/boldFont/italicFont parameters.

o  fontHeight: pixels
set the line height - that's the number of pixels,
by which lines are vertically separated (from top to top of next line).

o  foregroundColor
return the foreground color

o  foregroundColor: aColor
set the foreground color

o  foregroundColor: color1 backgroundColor: color2
set both foreground and background colors

o  innerHorizontalMargin
return the margin between the left border and the 1st col

o  innerVerticalMargin
return the margin between the top border and the 1st line

o  leftMargin
return the margin to left of 1st col

o  leftMargin: aNumber
set the margin between the left border and the 1st col

o  level: aNumber
set the 3D level - caught here to update text-position variables
(which avoids many computations later)

o  lineSpacing
get the lineSpacing - that's an additional number of pixels,
by which lines are vertically separated.

o  lineSpacing: pixels
set the lineSpacing - that's an additional number of pixels,
by which lines are vertically separated.

o  partialLines: aBoolean
allow/disallow display of a last partial line

o  topMargin: aNumber
set the margin between the top border and the 1st line

o  viewBackground: aColor
(comment from inherited method)
set the viewBackground to something, a color, image or form.
If it's a color and we run on a color display, also set shadow and light
colors - this means, that a red view will get light-red and dark-red
edges.

accessing-mvc
o  addModelInterfaceTo: aDictionary
see comment in View>>modelInterface

o  listMessage
return the listMsg selector;
if non-nil, this is the message sent to the model (if any) to acquire
a new text upon change of the aspect.
This defaults to the aspect-selector.

o  listMessage: aSymbol
ST-80 compatibility: set the listMsg selector;
if non-nil, this will be sent to the model (if any) to acquire a
new text upon change of the aspect.
This defaults to the aspect-selector.

o  model: aModel
define the receiver's model, from which the text is
to be acquired via list- or aspect-messages, whenever its aspect
changes.

o  on: aModel aspect: aspectSymbol
ST-80 compatibility

o  on: aModel aspect: aspectSymbol change: changeSymbol
ST-80 compatibility

o  on: aModel aspect: aspectSymbol change: changeSymbol list: listSymbol menu: menuSymbol
ST-80 compatibility

o  on: aModel aspect: aspectSymbol change: changeSymbol menu: menuSymbol
ST-80 compatibility

o  on: aModel aspect: aspectSymbol list: listSymbol menu: menuSymbol
ST-80 compatibility

o  on: aModel aspect: aspectSymbol menu: menuSymbol
ST-80 compatibility

change & update
o  update: something with: aParameter from: changedObject
model changed (not more information)

drawing
o  drawLine: line inVisible: visLineNr with: fg and: bg
draw a given string at visible lines position in fg/bg

o  drawVisibleLine: visLineNr col: col with: fg and: bg
draw single character at col index of visible line in fg/bg

o  drawVisibleLine: visLineNr from: startCol to: endCol with: fg and: bg
draw part of a visible line in fg/bg

o  drawVisibleLine: visLineNr from: startCol with: fg and: bg
draw right part of a visible line from startCol to end of line in fg/bg

o  drawVisibleLine: visLineNr with: fg and: bg
draw a visible line in fg/bg

o  fillRectangleX: x y: y width: w height: h
fill rectangle; checks whether the rectangle already is filled with
the current paint (#redrawX:y:w:h).

o  invalidateLine: line
invalidate the area of a single line.
This arranges for that line to be redrawn asynchronously (later).
If multiple such invalidations arrive, those areas may be lumped
together for a block update.
The update takes place when the windowGroup process gets a chance to
process expose events.

drawing-basic
o  drawFromVisibleLine: startVisLineNr to: endVisLineNr with: fg and: bg
draw a visible line range in fg/bg

o  drawLine: line atX: x inVisible: visLineNr with: fg and: bg
draw a given string at visible lines position with
given x position in fg/bg. Clears the whole line before drawing the string.
This is a low level entry; not meant for public use.

o  drawLine: line fromX: x inVisible: visLineNr with: fg and: bg
draw a given string at visible lines position with
given x position in fg/bg. Clears partial line before drawing the string.
Low level entry; not meant for public use.

o  drawLine: lineStringArg inVisible: visLineNr col: col with: fg and: bg
draw single character at col index of visible line in fg/bg

o  drawLine: lineStringArg inVisible: visLineNr from: startCol to: endColOrNil with: fg and: bg
draw part of a visible line in fg/bg

o  drawLine: lineString inVisible: visLineNr from: startCol with: fg and: bg
draw right part of a visible line from startCol to end of line in fg/bg

event handling
o  contentsChanged
size of contents changed - move origin up if possible

o  keyPress: key x: x y: y
a key was pressed - handle page-keys here

o  keyboardZoom: largerBoolean
ALT+/- (was: CTRL+/-) zoom action

o  keyboardZoom: largerBoolean inAllViews: inAllViews
CTRL+/- zoom action

o  mapped
(comment from inherited method)
the view has been mapped (by some outside
action - i.e. window manager de-iconified me)

o  mouseWheelZoom: amount
CTRL-wheel action

o  redrawX: x y: y width: w height: h
a region must be redrawn

o  sizeChanged: how from: oldExtentOrNil
my view has changed the size (not the contents);
move origin if possible

o  unmap
(comment from inherited method)
unmap the view - the view stays created (but invisible),
and can be remapped again later.

initialization
o  create
I cache font parameters here - they are used so often ...

o  defaultControllerClass
(comment from inherited method)
Controller

o  fetchDeviceResources
fetch device colors, to avoid reallocation at redraw time

o  initStyle
setup viewStyle specifics

o  initialize
just any value ...

o  initializeWordCheckAction
the wordCheck is a predicate block which returns true if the given character
belongs to the (textual) word. Used with double click to select a word.
When editing code, typically characters which are part of an identifier
are part of a word (underline, dollar, but no other non-letters).
The standardWordCheck aks the current userPreferences for details.

o  realize
old: fetch models value on realize;

o  recreate
recreate after a snapin or a migration

private
o  absoluteLineToVisibleLine: absLineNr
given an absolute line (1..) return visible linenr or nil

** This is an obsolete interface - do not use it (it may vanish in future versions) **

o  checkForExistingLine: lineNr
check if a line for lineNr exists; if not, expand text

o  checkForExistingLine: lineNr sendChangeNotification: aBoolean
check if a line for lineNr exists; if not, expand text

o  colOfX: x inVisibleLine: visLineNr
given a visible lineNr and x-coordinate, return colNr

o  computeNumberOfLinesShown
recompute the number of visible lines

o  convertRTF: aList
this is a q&d RTF to poor-text converter which removes any rich stuff.
- a first shot 'til DocumentView is finished ...

** This is an obsolete interface - do not use it (it may vanish in future versions) **

o  enqueueDelayedContentsChangedNotification
because contentsChanged may be slow (recomputing width of widest line),
we delay its execution by pushing it onto the event queue.
This has the effect of allowing for multiple add-lines before recomputing,
much speeding up inserting into long lists

o  getFontParameters
get some info of the used font. They are cached since we use them often ..
The code below uses the font's average height parameters - these
are not OK for some oversized national characters (such as A-dieresis).
Therefore, this method should be redefined in views which will be used
with national characters (i.e. editTextViews).

o  getListFromModel
ask my model (if any) for the text via the listMsg.
If there is no listMessage, try aspect for backward compatibility.

o  getListFromModelScroll: aBoolean
ask my model (if any) for the text via the listMsg.
If there is no listMessage, try aspect for backward compatibility.
If aBoolean is false, scrolling is suppressed here

o  highlightLineSpacing
true if the spacing between lines is to be drawn with selected color,
false if it remains white.
false for selection in list views; true for edit/text views

o  line: line withoutEmphasis: emphasisToRemove

o  listAt: lineNr from: startCol
return right substring from startCol to end of a line

o  listAt: lineNr from: startCol to: endCol
return substring from startCol to endCol of a line

o  listAt: lineNr to: endCol
return left substring from start to endCol of a line

o  listLineIsVisible: listLineNr
return true, if a particular line is visible

o  listLineToVisibleLine: listLineNr
given a list line (1..) return visible linenr or nil

o  recomputeWidthOfWidestLineFor: aString

** This is an obsolete interface - do not use it (it may vanish in future versions) **

o  recomputeWidthOfWidestLineFor: newEntry old: oldEntry
a new line was added (oldEntry == nil) or replaced oldEntry.
Update the widthOfWidestLine cache or flush it, if we cannot easily
figure out the overall text width

o  suppressEmphasisInSelection
selection is shown with original emphasis

o  textChanged
ignored here

o  updateWidthOfWidestLineFor: aLine
when set to do this dynamically
(eg when checkedLinesForWidthOfContentsComputation == 0)

o  visibleAt: visibleLineNr
return what is visible at line (numbers start at 1).
This is used for redrawing; i.e. for non-string entries, this
returns the original.
visibleLineNr is a visible lineNr (i.e. not the absolute lineNr)

o  visibleLineOfY: y
given a y-coordinate, return the visible lineNr
- works for fix-height fonts only

o  visibleLineToAbsoluteLine: visibleLineNr
given a visible line (1..) return absolut linenr

o  visibleLineToListLine: visibleLineNr
given a visible line (1..) return linenr in list or nil
(this one returns nil if the given visibleLineNr is one of the
separators)

o  visibleStringFrom: aString

o  widthForScrollBetween: firstLine and: lastLine
return the width in pixels for a scroll between firstLine and lastLine.
- used to optimize scrolling, by limiting the scrolled area.
Subclasses with selections or other additional visible stuff should redefine
this method.

o  widthOfLineString: entry
return the width of an entry

o  widthOfWidestLineBetween: firstLine and: lastLine
return the width in pixels of the widest line in a range
- used to optimize scrolling, by limiting the scrolled area;
not for scrollbar or other width related stuff which should be exact.

o  withoutAnyColorEmphasis: line
'hello' asText colorizeAllWith:Color red.
('hello' asText colorizeAllWith:Color red) withoutForegroundColorEmphasis.
('hello' asText colorizeAllWith:Color red) withoutAnyColorEmphasis.

o  withoutBackgroundColorEmphasis: line

o  withoutColorEmphasis: line

o  withoutColorEmphasis: line ifFg: fg andBg: bg
remove lines color emphasis, to enforce color.

o  xOfCol: col inVisibleLine: visLineNr
given a visible line- and colNr, return the x-coordinate in view

o  yOfLine: lineNr
given a physical lineNr, return y-coordinate in view
- works for fix-height fonts only

o  yOfVisibleLine: visLineNr
given a visible lineNr, return y-coordinate in view
- works for fix-height fonts only

o  yVisibleToLineNr: yVisible

queries
o  characterPositionOfLine: lineNr col: colArg
given a line/col position, return the character index within the contents-string,
- used with compiler's error-positioning, which is based on character positions
of the contents-string.

o  colOfCharacterPosition: charPos
given a character index within the contents-string,
return the column number where the character is
- used to find line to hilight from Compilers error-position

o  computePreferredExtent
(comment from inherited method)
return my computed preferred extent - this is the minimum size I would like to have.
If there are any components, a rectangle enclosing them
is returned. Otherwise, the actual extent is returned.

o  currentLine
the current line (for relative gotos);
since listViews have no cursor, the first shown line is returned here.
Redefined in editTextView, to return the cursors line.

o  firstLineShown
return the index of the first (possibly partial) visible line

o  heightForLines: numberOfLines
return the height of the receiver, if numberOfLines are to be displayed

o  isLineFullyVisible: lineNr
is line fully visible?

o  isLineVisible: lineNr
is line visible?

o  lastLineShown
return the index of the last (possibly partial) visible line

o  leftIndentOfLine: lineNr
return the actual number of spaces at the left in line, lineNr.
returns 0 for empty lines.

o  lengthOfLongestLine
return the length (in characters) of the longest line

o  lengthOfLongestLineBetween: firstLine and: lastLine
return the length (in characters) of the longest line in a line-range

o  lineIsFullyVisible: lineNr
is line fully visible?

** This is an obsolete interface - do not use it (it may vanish in future versions) **

o  lineIsVisible: line
is line visible?

** This is an obsolete interface - do not use it (it may vanish in future versions) **

o  lineOfCharacterPosition: charPos
given a character index within the contents-string,
return the lineNumber where the character is
- used to find line to hilight from compiler's error-position

o  numberOfLines
return the number of lines the text has

o  preferredExtent
(comment from inherited method)
return my preferred extent - this is the minimum size I would like to have.
If the preferredExtent has been set already, that one is returned.
Otherwise, if there are any components, a rectangle enclosing them
is returned.
Otherwise, the actual extent is returned.

o  preferredExtentForContents
given the current contents, return my preferred extent.
Return at least 100 as height

o  preferredExtentForLines: numLines cols: numCols

o  supportsSyntaxElements
see CodeView2::TextView

o  widthOfLine: lineNr
return the width of a line in pixels

o  xOriginOfContents
return the horizontal origin of the contents in pixels
- used for scrollbar interface

o  yOriginOfContents
return the vertical origin of the contents in pixels
- used for scrollbar interface

queries-contents
o  heightOfContents
return the height of the contents in pixels
- used for scrollbar interface

o  widthOfContents
return the width of the contents in pixels
- used for scrollbar interface

redrawing
o  redraw
redraw complete view

o  redrawFromLine: lineNr
redraw starting at linrNr

o  redrawFromLine: startLine col: startCol toLine: endLine col: endCol

o  redrawFromLine: start to: end
redraw lines from start to end

o  redrawFromVisibleLine: startVisLineNr to: endVisLineNr
redraw a visible line range

o  redrawInverted
show contents in reverse colors

o  redrawLine: lineNr
redraw a list line

o  redrawLine: lineNr col: col
redraw a single character

o  redrawLine: lineNr from: startCol
redraw a list line from startCol to end of line

o  redrawLine: lineNr from: startCol to: endCol
redraw a list line from startCol to endCol

o  redrawVisibleLine: visLineNr
redraw a visible line

o  redrawVisibleLine: visLineNr col: col
redraw single character at col index of visible line

o  redrawVisibleLine: visLineNr from: startCol
redraw right part of a visible line from startCol to end of line

o  redrawVisibleLine: visLineNr from: startCol to: endCol
redraw part of a visible line

scrolling
o  gotoCharacterPosition: aCharacterPosition
position to line aLineNumber; this may be redefined
in subclasses (for example to move the cursor also)

o  gotoLine: aLineNumber
position to line aLineNumber; this may be redefined
in subclasses (for example to move the cursor also)

o  halfPageDown
scroll down half a page

o  halfPageUp
scroll up half a page

o  horizontalScrollStep
return the amount to scroll when stepping up/down.
Here, the scrolling unit is characters.

o  makeColVisible: aCol inLine: aLineNr
if column aCol is not visible, scroll horizontal to make it visible

o  makeLineVisible: aListLineNr
if aListLineNr is not visible, scroll to make it visible.
Numbering starts with 1 for the very first line of the text.

o  makeVisible: someString
if necessary, scroll to make the (first)
line containing someString visible.

o  mouseWheelScrollDown: units
here, we scroll in line-units

o  mouseWheelScrollUp: units

o  needScrollToMakeLine: aListLineNr
return true, if a scroll is needd to make a line visible.
Numbering starts with 1 for the very first line of the text.

o  needScrollToMakeLineVisible: aListLineNr
return true, if a scroll is needd to make a line visible.
Numbering starts with 1 for the very first line of the text.

o  pageDown
change origin to display the next page

o  pageUp
change origin to display the previous page

o  sceduleNextAutoScroll
care for a race in case any of autoScrollBlock/autoScrollDeltaT gets nilled in-between (via stopScrollSelect)

o  scrollDown
scroll down by one line;
this is called (among other) when the scrollbar's
scroll-step down button is pressed.

o  scrollDown: nPixels
change origin to scroll down some pixels
(towards the bottom of the text)
Redefined, as this view only allows scrolling in multiples of the line height

o  scrollDownLines: nLines
change origin to scroll down some lines
(towards the bottom of the text)

o  scrollHorizontalTo: aPixelOffset
change origin to make aPixelOffset be the left col

o  scrollLeft: nPixel
change origin to scroll left some cols

o  scrollRight: nPixel
change origin to scroll right some cols

o  scrollSelectDown
just a template - I do not know anything about selections

** This method must be redefined in concrete classes (subclassResponsibility) **

o  scrollSelectUp
just a template - I do not know anything about selections

** This method must be redefined in concrete classes (subclassResponsibility) **

o  scrollToBottom
change origin to show end of text

o  scrollToCol: aColNr
change origin to make aColNr be the left col

o  scrollToLeft
change origin to start (left) of text

o  scrollToLine: aLineNr
change origin to make aLineNr be the top line

o  scrollToPercent: percentOrigin
scroll to a position given in percent of total

o  scrollToTop
change origin to start of text

o  scrollUp
scroll up by one line;
this is called (among other) when the scrollbar's
scroll-step up button is pressed.

o  scrollUp: nPixels
change origin to scroll up some pixels
(towards the top of the text).
Redefined, as this view only allows scrolling in multiples of the line height

o  scrollUpLines: nLines
change origin to scroll up some lines
(towards the top of the text)

o  scrollVerticalToPercent: percent
scroll to a position given in percent of total

o  startAutoScrollDown: yDistance
setup for auto-scroll down (when button-press-moving below view)
- timeDelta for scroll is computed from distance.
Return true, to tell caller that scrolling is allowed (redefined in editField)

o  startAutoScrollHorizontal: xDistance scrollSelector: scrollSelector
setup for auto-scroll left/right (when button-press-moving to the right of the view)
- timeDelta for scroll is computed from distance

o  startAutoScrollLeft: xDistance
setup for auto-scroll up (when button-press-moving to the left of the view)
- timeDelta for scroll is computed from distance

o  startAutoScrollRight: xDistance
setup for auto-scroll down (when button-press-moving to the right of the view)
- timeDelta for scroll is computed from distance

o  startAutoScrollUp: yDistance
setup for auto-scroll up (when button-press-moving below view)
- timeDelta for scroll is computed from distance.
Return true, to tell caller that scrolling is allowed (redefined in editField)

o  startAutoScrollVertical: yDistance scrollSelector: scrollSelector
setup for auto-scroll up (when button-press-moving below view)
- timeDelta for scroll is computed from distance

o  stopAutoScroll
stop any auto-scroll

o  verticalScrollStep
return the amount to scroll when stepping up/down.
Here, the scrolling unit is lines.

o  viewOrigin
return the viewOrigin;
that's the coordinate of the contents which is shown topLeft in the view
(i.e. the origin of the visible part of the contents).

scrolling-basic
o  additionalMarginForHorizontalScroll
return the number of pixels by which we may scroll more than the actual
width of the document would allow.
This is redefined by editable textViews, to allo for the cursor
to be visible if it is positioned right behind the longest line of text.
The default returned here is the width of a blank (to beautify italic text)

o  scrollTo: anOrigin redraw: doRedraw
change origin to have newOrigin be visible at the top-left.
The argument defines the integer device coordinates of the new top-left
point.

searching
o  doSearchFrom: startLine col: startCol for: patternIn match: match regexMatch: regexMatch ignoreCase: ignCase fullWord: fullWord atBeginOfLineOnly: atBeginOfLineOnlyIn atEndOfLineOnly: atEndOfLineOnlyIn wrapAtEndOfText: wrapAtEndOfText matchesDo: matchCallback
this is end used if we must search across lines;
i.e. the searchpattern contains line-ends

o  doSearchLinewiseFrom: startLine col: startCol for: patternIn match: match regexMatch: regexMatch ignoreCase: ignCase fullWord: fullWord atBeginOfLineOnly: atBeginOfLineOnlyIn atEndOfLineOnly: atEndOfLineOnlyIn wrapAtEndOfText: wrapAtEndOfText matchesDo: matchAction
this is end used if we can search inside each individual line;
i.e. the searchpattern is either a non-pattern match,
or it does not contain $ (EOL) characters,
or it only contains a single EOL character at the end

o  findBeginOfWordAtLine: selectLine col: selectCol
return the col of first character of the word at given line/col.
If the character under the initial col is a space character, return
the first col of the blank-block.

o  findEndOfWordAtLine: selectLine col: selectCol
return the col of last character of the word at given line/col.
If the character under the initial col is a space character, return
the last col of the blank-block.
Return 0 if we should wrap to next line (for spaces)

o  searchBackwardFor: pattern ignoreCase: ignCase startingAtLine: startLine col: startCol ifFound: block1 ifAbsent: block2
search for a pattern, if found evaluate block1 with row/col as arguments, if not
found evaluate block2.
Sorry, but pattern is no regular expression pattern (yet)

o  searchBackwardFor: pattern startingAtLine: startLine col: startCol ifFound: block1 ifAbsent: block2
search for a pattern, if found evaluate block1 with row/col as arguments, if not
found evaluate block2.
Sorry, but pattern is no regular expression pattern (yet)

o  searchBackwardUsingSpec: searchSpec startingAtLine: startLine col: startCol ifFound: foundAction ifAbsent: notFoundAction
search for a pattern;
if found, evaluate foundAction with row/col as arguments,
if not found evaluate notFoundAction.
Sorry, but pattern is no regular expression pattern (yet).
Also, wraps are not done when searching backward.

o  searchForwardFor: pattern ignoreCase: ignCase match: match startingAtLine: startLine col: startCol ifFound: block1 ifAbsent: block2
search for a pattern, if found evaluate block1 with row/col as arguments, if not
found evaluate block2.

o  searchForwardFor: pattern ignoreCase: ignCase startingAtLine: startLine col: startCol ifFound: block1 ifAbsent: block2
search for a pattern, if found evaluate block1 with row/col as arguments, if not
found evaluate block2.

o  searchForwardFor: pattern startingAtLine: startLine col: startCol ifFound: block1 ifAbsent: block2
search for a pattern, if found evaluate block1 with row/col as arguments, if not
found evaluate block2.

o  searchForwardUsingSpec: searchSpec startingAtLine: startLine col: startCol ifFound: foundAction ifAbsent: notFoundAction
search for a pattern;
if found evaluate foundAction with row/col as arguments,
if not found evaluate notFoundAction.
If the block is a three-arg block, it gets the end-col (or nil, if not known)

o  standardWordCheck: char
the wordCheck is a predicate which returns true if the given character
belongs to the (textual) word. Used with double click to select a word.
When editing code, typically characters which are part of an identifier
are part of a word (underline, dollar, but no other non-letters).
The standardWordCheck aks the current userPreferences for details.

tabulators
o  expandTabs
go through whole text expanding tabs into spaces.
This is meant to be called for text being imported from a file.
Therefore, 8-col tabs are assumed - independent of any private tab setting.

o  nextTabAfter: colNr
return the next tab position after col

o  nextTabAfter: colNr in: tabPositions
return the next tab position after col.
The second arg, tabPositions is a collection of tabStops.

o  prevTabBefore: colNr
return the prev tab position before col

o  setTab4
set 4-spaces tab stops

o  setTab8
set 8-spaces tab stops

o  setTabPositions: aVector
set tab stops

o  withTabs: line
Assuming an 8-character tab,
compress multiple leading spaces to tabs, return a new line string
or the original line, if no tabs where created.
good idea, to make this one a primitive, since its called
many times when a big text is saved to a file.

o  withTabs: tabulatorTable expand: line
expand tabs into spaces, return a new line string,
or original line, if no tabs are included.
good idea, to make this one a primitive, since it is called
many times if a big text is read from a file.

o  withTabsExpanded: line
expand tabs into spaces, return a new line string,
or original line, if no tabs are included.
good idea, to make this one a primitive


Private classes:

    HighlightArea
    SearchSpec

Examples:


ListViews alone are rarely used - its mostly an abstract superclass for TextView, EditTextView and SelectionInListView. anyway, here are a few examples: basic simple setup:
    |top l|

    top := StandardSystemView new.
    top extent:100@200.

    l := ListView origin:0.0 @ 0.0 corner:1.0 @ 1.0 in:top.
    l list:#('one' 'two' 'three').

    top open
specifying textMargins (these have NOTHING to do with the viewInset):
    |top l|

    top := StandardSystemView new.
    top extent:100@200.

    l := ListView origin:0.0 @ 0.0 corner:1.0 @ 1.0 in:top.
    l list:#('one' 'two' 'three').
    l topMargin:10.
    l leftMargin:20.

    top open
globally set the fg/bg colors:
    |top l|

    top := StandardSystemView new.
    top extent:100@200.

    l := ListView origin:0.0 @ 0.0 corner:1.0 @ 1.0 in:top.
    l list:#('one' 'two' 'three').
    l foregroundColor:(Color white).
    l backgroundColor:(Color blue).

    top open
non-string (text) entries:
    |top list l|

    top := StandardSystemView new.
    top extent:100@200.

    l := ListView origin:0.0 @ 0.0 corner:1.0 @ 1.0 in:top.
    list := #('all' 'of' 'your' 'preferred' 'colors')
            with:#(red green blue 'orange' cyan)
            collect:[:s :clr |
                        Text string:s
                             emphasis:(Array with:#bold
                                             with:(#color->(Color name:clr))) ].
    l list:list.

    top open
generic non-string entries: (notice: ColoredListEntry is obsoleted by Text)
    |top list l|

    top := StandardSystemView new.
    top extent:100@200.

    l := ListView origin:0.0 @ 0.0 corner:1.0 @ 1.0 in:top.
    list := #('all' 'of' 'your' 'preferred' 'colors')
            with:#(red green blue 'orange' cyan)
            collect:[:s :clr | ColoredListEntry string:s color:(Color name:clr) ].
    l list:list.

    top open
using a model (default listMessage is aspectMessage):
    |top model l theModelsText|

    model := Plug new.
    model respondTo:#modelsAspect
               with:[ theModelsText ].

    top := StandardSystemView new.
    top extent:100@200.

    l := ListView origin:0.0 @ 0.0 corner:1.0 @ 1.0 in:top.
    l model:model.
    l aspect:#modelsAspect.

    top open.

    Delay waitForSeconds:3.
    theModelsText := #('foo' 'bar' 'baz').
    model changed:#modelsAspect.
using a model with different aspects for two listViews:
    |top model l1 l2 plainText|

    plainText := #('').

    model := Plug new.
    model respondTo:#modelsUppercaseText
               with:[ plainText asStringCollection
                          collect:[:l | l asUppercase]].
    model respondTo:#modelsLowercaseText
               with:[ plainText asStringCollection
                          collect:[:l | l asLowercase]].

    top := StandardSystemView extent:200@200.

    l1 := ListView origin:0.0 @ 0.0 corner:1.0 @ 0.5 in:top.
    l1 model:model.
    l1 aspect:#modelsAspect.
    l1 listMessage:#modelsUppercaseText.

    l2 := ListView origin:0.0 @ 0.5 corner:1.0 @ 1.0 in:top.
    l2 model:model.
    l2 aspect:#modelsAspect.
    l2 listMessage:#modelsLowercaseText.

    top open.

    Delay waitForSeconds:3.
    plainText := #('foo' 'bar' 'baz').
    model changed:#modelsAspect.
using a big list (100000 lines), wrapping in a ScrollableView:
    |bigList top lv|

    bigList := (1 to:100000) collect:[:lineNr | 'List line Nr. ' , lineNr printString].
    bigList at:10 put:('Some Text ' asText , 'with Bold part' allBold).
    bigList at:20 put:('Some Text ' asText , 'with Italic part' allItalic).

    top := StandardSystemView extent:200@200.

    lv := HVScrollableView for:ListView in:top.
    lv origin:0.0 @ 0.0 corner:1.0 @ 1.0.
    lv list:bigList expandTabs:false scanForNonStrings:false includesNonStrings:false.

    top open.
using a huge virtual list (1 mio simulated lines), wrapping in a ScrollableView:
    |virtualList top lv|

    virtualList := Plug new.
    virtualList inheritFrom:SequenceableCollection.
    virtualList respondTo:#size with:[ 1000000 ].
    virtualList respondTo:#at:  with:[:lineNr | 'List line Nr. ' , lineNr printString ].

    top := StandardSystemView extent:200@200.

    lv := ScrollableView for:ListView in:top.
    lv origin:0.0 @ 0.0 corner:1.0 @ 1.0.
    lv list:virtualList expandTabs:false scanForNonStrings:false includesNonStrings:false.

    top open.
using a huge virtual array (1 mio simulated lines), wrapping in a ScrollableView. To simulate an expensive computation, a delay is planted into the line generator; Startup and display of page full of lines should not take longer than the number of lines shown:
    |virtualList top lv|

    virtualList := VirtualArray new.
    virtualList
        setSize:1000000;
        generator:[:index | Transcript showCR:index.
                            Delay waitForSeconds:0.5.
                            '%1 -> %2' bindWith:index with:index squared].

    top := StandardSystemView extent:200@200.

    lv := ScrollableView for:ListView in:top.
    lv origin:0.0 @ 0.0 corner:1.0 @ 1.0.
    lv expandTabsWhenUpdating:false.
    lv checkLineEndConventionWhenUpdating:false.
    lv checkedLinesForWidthOfContentsComputation:-1.
    lv list:virtualList.

    top open.


ST/X 7.7.0.0; WebServer 1.702 at 20f6060372b9.unknown:8081; Sun, 22 Dec 2024 02:56:11 GMT