It looks like the plan to draw the entire tree initially, including
all hidden nodes, is doomed.  Don't worry, the last few days of work
will not go to waste.

The fatal problem is clear in retrospect: moving a large tree of
mostly-hidden nodes can take a very long time.  I discovered this by
happy accident.  test.leo contains the tree 'pythoscope & lib2to3'.
Imagine my surprise when I saw that moving this tree with the
"optimized" code took about half a second!

So it appears that the essential precondition for good *typical*
performance is to create tree nodes for only visible nodes (and the
first-level hidden nodes needed to set the plus/minus boxes properly).

This will make the initial redraw much faster again.  I was just
barely willing to tolerate the slow first draw, but now I see that was
unnecessary step backwards.

In effect, we are back to Ville's original suggestion, namely to
lazily create tree nodes.  I now have a much better sense of what that
means.

I discovered several other big problems yesterday:

1. In the "optimized" world, moving nodes on the screen involves some
tricky chicken-and-egg situations.  The optimized redraw code needs
position2item in order to find starting points for redrawing, but
position2item assumes that the entire tree has already been redrawn!

2. The code in Leo's core that called the redraw_after methods must be
extremely careful when switching the currently selected node.  The
typical pattern had to be:

    c.setCurrentPosition()  # Step 1: set c._currentPosition.
    c.redraw_after_insert() # Step 2: create new tree items.
    c.selectPosition()      # Step 3: select the new tree item.

This pattern shows that the underlying code is fragile.  Yes, I could
fold this into all the redraw_after methods, but the code would remain
fragile.

BTW, I lost work yesterday when the body text of nodes started moving
around.  This shows how dangerous it is to mess with the selection
process.  This lost data was money well spent.  It was a big incentive
to doing something better.

3. The optimized code requires that the redraw code *forget* nodes
when deleting parts of the tree.  Alas, deleting entries from the
dicts that associate items with vnodes and tnodes is much harder than
inserting entries.  It's not out of the question, but it would be good
to avoid this problem.

4. The optimized code would have required heroic efforts from Leo's
undo code.  This code is already too complex.

The way forward

I said at the beginning that the recent work will not go to waste.  I
mean that :-)  In particular, after seeing how well the doomed code
handled cursor movements, it would be unbearable to go back to the bad
old days where *every* tree operation caused a screen draw.

Here is my present plan. It can be modified easily, since I have not
started actual work.  Your comments and suggestions are welcome now.

1. The code will be based on the existing "non-clever" code.  That is,
only visible nodes will be created.

I see no good alternative to this.  Creating nodes for large-but-
mostly-hidden trees makes those trees much to "heavy".  Experience
shows that the performance penalty can be unacceptable.

2. Selecting an already-visible (tree) node should not change the tree
items.  This is the big payoff from the "clever" redraw code.

In particular, collapsing a node will not change any tree item.

3. (Controversial?) My present plan is to completely redraw the
(visible) tree whenever the tree changes.  But see point 4.

This is sound engineering.  We already know that it is fast enough,
and it is *by far* the simplest way.  It eliminates a lot of hard
problems, thereby eliminating many bugs before they are born.

4. Expanding a tree item will probably *not* count as changing the
tree.  That is, I hope that the revised code can create tree items as
necessary when they are first revealed, without actually redrawing the
entire tree.

This could be tricky.  Drawing the newly-revealed nodes is the easy
part. The hard part is to determine when an tree node must be expanded
as the result of a cursor movement.  This problem didn't exist with
the "non-clever" code: Leo's core simply calls c.redraw.

Conclusion

I think this plan will make everyone happy:

- Lazily creating tree nodes yields maximum possible performance.

- It will eliminate most flicker when moving around the tree.  There
will be (slight!) flicker when tree items are first revealed, but how
could that possibly be avoided?

- It will eliminate all the redraw optimizers.  This will squash
hundreds of bugs before they are born.  In particular, no heroism will
be demanded of Leo's undo code.  True, inserting, deleting and moving
nodes will result in a full redraw, but that is a price I am happy to
pay.

In short, this plan can deliver improved performance without requiring
heroism either in Leo's core or in the qt plugin.

Edward

P.S. The revised plan means that I no longer have any excuse for not
fixing bugs in the "non-clever" code :-) In particular, position2item
can fail in some cases.  It is urgent that I understand exactly why
that is happening.

EKR
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"leo-editor" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to 
[email protected]
For more options, visit this group at 
http://groups.google.com/group/leo-editor?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to