VTV was always string in complex owner-draw rich content scenarios
However for simple scenarios it frequently was rather complex beast.
Now migrating a legacy app to a new Delphi/VTV i found a windows, consisting of VDT and having half of default paint method verbatim copied into OnMeasureItem event just to keep track of all the possible elements like checkboxes, etc.
It was a simplistic tree: no columns (-1), no pictures - just default text and checkboxes.
It did not more worked for a newer VTV, so i tried to reimplement it based on SVN VirtualStringTree
...and also making the form resizable at last!
So i want to review few features of VTV design, that seem to me related to being able to easily implement multiline items.
As far as i can see, multiline support boils down to
1) answering "Which Height is required to fit the given text into given width"
2) rendering the text wit htrespect to both width and height
It looks like for both points state is less than ideal
* One problem is that main column (or NoColumn mode) may contain a number of elements beside the "content".
* Another one is that vertical scrollbar may (or may not) affect an available width.
* And the 3rd one is the conflict of responsibilities (maybe that is my error, but since i could not find the clarification in neither chm nor pdf nor comments in sources, then i also see it somewhat a lack.
* Then i feel like OnMeasureXXXX events are somewhat too picky. It should ask for minimum values, not for final values IMHO.
Now i'll try to put more details in this.
======== Scroll bars =========
1. Usual mode for Windows apps is to only show them when required. That means that at any given time the scrollbar may or may not be present.
Then how should developer know about it ?
One possible answer would be "he does not need to, scrollbars are subtracted from clientwidth/clientheight/clientrect already). Like it is claimed to be done on VCL TCustomForm level. However that does not seem to happen in VTV (judging by its sources, which compares RangeX/RangeY with Client*** without extra checks for scrollbars)
Then i make a proposal to add a porperties, so that it would be clear whether scrollbars are visible this very moment and if they are - how much do they subtract from effectively visible area of a control.
Proposal is:
type
TVirtualStringTree = class(VirtualTrees.TVirtualStringTree)
protected
FScrollBarsBands: TSize;
procedure DoShowScrollbar(Bar: Integer; Show: Boolean); override;
public
property ScrollBarVisibleWidth: integer read FScrollBarsBands.cx;
property ScrollBarVisibleHeight: integer read FScrollBarsBands.cx;
end;
procedure TVirtualStringTree.DoShowScrollbar(Bar: Integer; Show: Boolean);
var _H, _V: boolean;
begin
inherited;
_H := Bar in [SB_HORZ, SB_BOTH];
_V := Bar in [SB_VERT, SB_BOTH];
if Show then begin
if _H then FScrollBarsBands.cx := GetSystemMetrics(SM_CXHSCROLL);
if _V then FScrollBarsBands.cy := GetSystemMetrics(SM_CXVSCROLL);
end else begin
if _H then FScrollBarsBands.cx := 0;
if _V then FScrollBarsBands.cy := 0;
end;
end;
PS. yes, One can directly compare RangeX with ClientWidth, then double-check this against ScrollOptions but that is "leaking implementation" and so it is both tedious, counter-intuitive and problematic for future compatibility.
2. I also did not tested if items re-measuring can be auto-triggered by VTV resizing without maualyl plumbing this into OnResize event. Probably not.
=========== VTV-managef elements plus Events andrResponsibilities ==========
VDT has OnMeasureItem event
VST adds OnMeasureTextWidth/Height events
Correlation between those stays unclear to me.
VST Demo (d:\DelphiProjects\Libs\VTW\trunk\Demos\Advanced\MultilineDemo.pas) uses base OnMeasureItem event and ignore more specific new OnMeasureItem events.
Also it suggests to use VST.ComputeNodeHeight method which i have problems working with (actually it seems to imply that in NoColumn mode there is no tree but a flat list with no indents).
Well, okay, i can use TCanvas.TextHeight and all that, but i then need to know the actual Width, available to the node.
And i don't want to copy half of WM_PAINT handler into my app - that would be fragile and too complex.
I just want to know which gaps would VTV take for scrollbars or checkboxes or state images or tree lines or margins or cell margins or indentation or... or whatever, now and in future.
So, there seems to be that GetDisplayRect(Node, -1, true, false, true); method...
But it is that complex that it probably just could not be fast (when i only need TRect.Left and nothing else!).
Worse: attempt to use it in OnMeasureTextHight handler immediately leads to stack overflow. This IMHO is the clearest way that GetdisplatRect is a heavy non-ubiquitous function, alas.
This problem IMHO manifests itself in VTV sources - just grepping for "FCheckImages.Width" text shows a dozen of places where the same left offset calculations are copy-pasted time and again, instead of being unified in some service function (or into PVirtualNode^ field).
Or maybe there is some reason that the code should actually be copy-pasted instead of keeping it in a single place of responsibility?
Side note: BTW, why is GetNodeIndent a memory-jumping loop, instead of just one more feld in PVirtualNode ? Doesn't it impact speed and CPU cache ?
SideNode 2: it seems that OnMeasureTextHight and OnMeasuretextWidth are always called in pair, then why they are separate events ? doesn't it only complicate things?
I think OnMeasureItem or OnMeasureTextHeight methods should include Width parameter or Left and Right boundaries.
But if it seems hard due to compatibiltiy issues, then VTV could implement function like LeftOffset(Node,Column).
PS. And ScrollBarEffectiveWidth as described above.
=== dimensions: minimal or final =====
Now about minimums.
NodeHeight := vst.ComputeNodeHeight(TargetCanvas, Node, -1);
Okay ? Not, if you're running display with 120 DPI fonts instead of old Windows habit of 96DPi.
The checkboxes would just be clipped!
NodeHeight := vst.ComputeNodeHeight(TargetCanvas, Node, -1);
NodeHeight := Max( vst.CheckImages.Height + 2, NodeHeight);
That works better... but it is against leaking implementation details. And yet not enough (what if [+] marks or other pictures would be even taller than those checkboxes?)
So again it looks like either a NodeMinimalHeight function is needed or a special extra parameter into event handler, specifying whether the height should be reduced or kept, if custom height is less than a default one.
Run it in Delphi XE2 on Win7 / 120DPI fonts and play wit hthe form's width.
Vertical scrollbar tends to appear way too late.
Text strings are "dancing", their vertical alignment is continualyl switchign middle to top and back
Some strings are word wrappedand some are not.
...somewhat a weird behaviour for the task seems to be conceptually clear and concise.