Bug 90232 - GridLayout unnecessarily accounts for scrollbars and borders in child control
Summary: GridLayout unnecessarily accounts for scrollbars and borders in child control
Status: RESOLVED DUPLICATE of bug 46112
Alias: None
Product: Platform
Classification: Eclipse Project
Component: SWT (show other bugs)
Version: 3.1   Edit
Hardware: PC Windows XP
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: Veronika Irvine CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2005-04-04 17:53 EDT by Randy Hudson CLA
Modified: 2005-05-11 17:02 EDT (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Randy Hudson CLA 2005-04-04 17:53:23 EDT
GridLayout is not following the computeSize API in that it should not be
subtracting the border or trim size from the control.  The API for computeSize
says that the width hint is the proprosed width for the control (not it's client
area). So the control should already subtract it's own border size within
computeSize.  It makes more sense to account for the border in the control, than
to have SWT layout in existence make this correction.

But more importantly, if the child is a Scrollable, GridLayout is calling
computeTrim on the scrollable, and removing the scrollbar width from the
available width. How does it know that the scrollbar will be displayed? You
don't know this, and in my case the scrollbar isn't displayed because that is
the whole point of asking the child how much space it wants, i.e. so that
scrollbar don't need to be displayed. In fact, the Scrollable may never display
its native scrollbars for any purpose, so removing that amount from the
available width is bogus.
Comment 1 Randy Hudson CLA 2005-04-04 18:08:55 EDT
correction: than to have *every* SWT layout in existence make this correction

BTW, this seems to be new 3.1 behavior
Comment 2 Veronika Irvine CLA 2005-04-05 16:05:26 EDT
The wHint and hHint in Control.computeSize actually do refer to the size of 
the content area (i.e. the clientArea).  The doc says:

"The <em>preferred size</em> of a control is the size that it would
best be displayed at. The width hint and height hint arguments
allow the caller to ask a control questions such as "Given a particular
width, how high does the control need to be to show all of the contents?"
To indicate that the caller does not wish to constrain a particular 
dimension, the constant <code>SWT.DEFAULT</code> is passed for the hint. "

If you call computeSize with some values other than SWT.DEFAULT, the trim is 
always added on to the value that is returned (computeTrim is called with the 
wHint and/or hHint).

For example, run the following code:

TabFolder folder = new TabFolder(shell, SWT.BORDER);
TabItem item = new TabItem(folder, SWT.NONE);
item.setText("hello");
System.out.println("computeSize (100, 100) = "+folder.computeSize(100, 100));

On Windows I get:

computeSize (100, 100) = Point {112, 130}

When GridLayout and FormLayout subtract off the trim from the widget it is 
because the next call to computeSize is going to add the trim back on and we 
do not want to account for the trim twice.

Steve and I have been discussing a new API for computeSize that would allow 
you to specify whether the trim should be added or not but this has never been 
finalized and released.
Comment 3 Veronika Irvine CLA 2005-04-05 16:09:19 EDT
I do agree tha calling computeTrim with (0, 0, 0, 0) does not allow the 
underlying control to determine whether or not scrollbars will be shown.  
However, it is currently the best we can do until we add new API for 
computeSize.  If we try to call computeTrim with values closer to the actual 
to the correct values, you end up dancing around the edge of where scrollbars 
are required and where they are not.
Comment 4 Randy Hudson CLA 2005-04-05 16:48:22 EDT
Exactly, "given a particular width".  But that's the inconsistency, you're 
actually going to give the control MORE width, and your example shows that.  112
 is not 100. That answer wouldn't even be useful if I am trying to determine 
the height needed for a paragraph that should be wrapped to width == 100.

calling computeSize(100, 100) for that type of info. is pointless since you 
could simply call computeTrim(0,0,100,100) and get the same result.

computeSize API becomes useful when you allow the control to grow in one or 
both directions.  So, if I say width is constrained, but height is not, why 
should the layout manager subtract the vertical scrollbar, when vertical 
dimension is unbounded meaning that a smart widget would hide the scrollbar.

Here is what we are trying to do. Calculate how much height is needed to 
display a wrapped paragraph, given the available width of the parent composite. 
Currently our paragraph is returning the wrong answer (because it received the 
wrong hint) which can result in an unneeded line of text at the bottom.

Snippets speak louder than words:
public static void main(String[] args) {
	Display d = Display.getDefault();
	final Shell shell = new Shell(d);
	shell.setLayout(new GridLayout());
	
	StyledText text = new StyledText(shell, SWT.MULTI | SWT.WRAP | 
SWT.H_SCROLL | SWT.READ_ONLY);
	text.setText("This is a  oijeoi aeif jaoiewjf oaiew jfoaiew" +
			"apijewpfk apoewkf paokwe pfokawpehfaowephf hawoiejf 
oaweijf paowkefp aoewkfpa " +
			"pawkfe paoewkf paowekf pawokefoaiwjefo iajewoifja 
oewijf poerk pgaokew faewfpokew f" +
			"f oaewkfp aewpofk apwejfoiuajweo foiwajef 
poawkefpawkje pfoakewpf aewpfkpaowke fpawf" +
			"gfpowaegpawepmulti-line label.");

	GridData data = new GridData(GridData.FILL_HORIZONTAL);
	data.widthHint = 170;
	data.heightHint = - 1;
	text.setLayoutData(data);
	data = new GridData(GridData.FILL_HORIZONTAL);
	data.widthHint = 170;
	data.heightHint = - 1;
//	label.setLayoutData(data);
	shell.open();
	shell.setSize(600,500);
	while (!shell.isDisposed())
		while (!d.readAndDispatch())
			d.sleep();
}
Comment 5 Veronika Irvine CLA 2005-04-06 13:56:10 EDT
I do not understand what your example is trying to show.  I have changed the 
example as shown below to demonstrate what I think you mean:

public static void main(String[] args) {
	String string = "This is a  oijeoi aeif jaoiewjf oaiew jfoaiew" +
			"apijewpfk apoewkf paokwe pfokawpehfaowephf hawoiejf 
oaweijf paowkefp aoewkfpa " +
			"pawkfe paoewkf paowekf pawokefoaiwjefo iajewoifja 
oewijf poerk pgaokew faewfpokew f" +
			"f oaewkfp aewpofk apwejfoiuajweo foiwajef 
poawkefpawkje pfoakewpf aewpfkpaowke fpawf" +
			"gfpowaegpawepmulti-line label.";
	Display display = new Display ();
	final Shell shell = new Shell(display);
	shell.setLayout(new GridLayout(3, false));
	
	StyledText text = new StyledText(shell, SWT.BORDER | SWT.MULTI | 
SWT.WRAP | SWT.H_SCROLL | SWT.READ_ONLY);
	text.setText(string);
	GridData data = new GridData(SWT.FILL, SWT.TOP, false, false);
	data.widthHint = 170;
	text.setLayoutData(data);
	System.out.println("Text = "+text.computeSize(170, -1));
	
	Label label = new Label(shell, SWT.BORDER | SWT.WRAP);
	label.setText(string);
	data = new GridData(SWT.FILL, SWT.TOP, false, false);
	data.widthHint = 170;
	label.setLayoutData(data);
	System.out.println("Label = "+label.computeSize(170, -1));
	
	shell.pack();
	shell.open();
	while (!shell.isDisposed ()) {
		if (!display.readAndDispatch ()) display.sleep ();
	}
	display.dispose ();
}

I think you are saying that the StyledText widget should have the same height 
as the Label widget but it does not.  

You have created a wrapping StyledText widget with a horizontal scrollbar.  
That is quite strange since the horizontal scrollbar will never be needed 
because the text wraps. A vertical scrollbar would make more sense.  I think 
if the StyledTextwidget is created with the style SWT.WRAP, then the 
SWT.H_SCROLL style should be ignored.  That is what the Text widget does.
Comment 6 Veronika Irvine CLA 2005-04-06 14:07:29 EDT
Fixed StyledText in HEAD to ignore H_SCROLL when WRAP is added.
Comment 7 Randy Hudson CLA 2005-04-06 15:07:35 EDT
I didn't realize I was showing horizontal instead of vertical. Using a vertical 
has some issues too, but not the same problem I have.

I thought I was using vertical, and that ST was hiding the vertical scrollbar, 
which is what my paragraph control does.
Comment 8 Randy Hudson CLA 2005-04-06 15:17:32 EDT
Try imagining a StyledText control using the V_SCROLL style, but when the 
scrollbar was disabled, it was hidden instead of sitting there disabled.  Once 
the hiding occurs, there is more width available, and the paragraph might 
require one fewer line to be displayed.  Meaning there is wasted space.

It is also possible to subclass Canvas, use the H_SCROLL or V_SCROLL style 
because you are forced to do so to receive mousewheel events, and never display 
the native scrollbars. So being an instanceof scrollable doesn't mean that 
gridlayout should subtract the trim width/height
Comment 9 Steve Northover CLA 2005-04-06 15:31:55 EDT
We should just close this as WONTFIX.  Even if Randy is right, we couldn't 
change the values that computeTrim() and computeSize() return without breaking 
the universe.  Veronika?
Comment 10 Veronika Irvine CLA 2005-04-06 16:14:22 EDT
I think we need to revisit the idea of having something like:

Control.computeSize(int wHint, int hHint, boolean changed, boolean addTrim).

Where addTrim is true if the trim should be added to the value of wHint and 
hHint.  If addTrim is false, wHint and hHint include the trim already.

This way, controls could implement a computeSize that knows about adding trim 
only if required and we can stop subtracting off the result of computeTrim 
before calling computeSize.
Comment 11 Randy Hudson CLA 2005-04-06 16:31:41 EDT
But there is no API currently to get the trim you need. My canvas is not going 
to display its vertical scrollbar if you give it the height it requested.

Why not just treat a Control as a black box, and not try to guess about how it 
works with respect to trim?
Comment 12 Veronika Irvine CLA 2005-04-06 17:16:25 EDT
The current implementations of Control.computeSize in SWT already go and add 
the trim to the wHint and hHint.  We can not change this because this would 
change the behaviour which has existed since the beginning of SWT.

Therefore, we must add new API to compute the size with the width hint and/or 
height hint already including the trim amount.

Please note that for many composites, adding the trim is really quite useful - 
take a TabFolder for example.  If you want to stick a table of a certain size 
in a TabFolder and you have no idea what the size of the tabs etc are then you 
want computeSize to add the trim on for you.  This is the case that 
computeSize was originally intended to solve.  However, now we have cases 
where we know the total width of a widget (including trim if required)and we 
want computeSize to just tell us the height.  We currently have no API to do 
this.
Comment 13 Randy Hudson CLA 2005-04-06 17:35:42 EDT
But, couldn't you just take the size of the table, and go to the tab folder and 
say computeTrim(tablebounds)?

Anyway, no existing behavior can change.  So, I guess our Canvas will simply 
have to add back in the trim width and height, and then just forget that it was 
ever subtracted.
Comment 14 Steve Northover CLA 2005-04-06 18:35:46 EDT
You canvas should do whatever the rest of the widgets in SWT do for now.
Comment 15 Veronika Irvine CLA 2005-04-11 10:18:00 EDT
Regarding comment #13 - this assumes you know how that TabFolder lays out its 
children.  In fact, it is not as simple as taking the size of the table since 
the computeSize(-1, -1) of TabFolder is based on the size of the largest child.
Comment 16 Randy Hudson CLA 2005-04-11 10:39:31 EDT
I'm no stranger to the layout problem. From my experience, it's best to treat 
the child as an unknown, and just pass the hints in. This avoids 2 things. 
First, you don't make the wrong assumptions about the child.  Second, you don't 
duplicate code in multiple layouts (i.e. Form and Grid) which belonged in the 
Control.

Creating a new method which subtracts the trim and calls the old method would 
solve my problem and remove the duplicate code from current SWT layouts. But I 
don't understand the need for the proposed isChanged or addTrim parameters.
Comment 17 Randy Hudson CLA 2005-05-11 15:57:41 EDT
references for "computeSize(int, int)" in a subset of Eclipse SDK show lots of
matches. References for "computeSize(int, int, boolean") show some more matches.

Most callers are not checking if the control is an instance of Scrollable, and
subtracting the trim width from the wHint.

Examples include:
PageBookLayout
PopupList
ScrolledCompositeLayout
EnhancedFillLayout
SashFormLayout

The simple fact that computeSize is on Control, while computeTrim is on
Scrollable, is a clear indicator that one should not have to subtract the trim,
as it requires an instanceof and cast.

Dupe of bug 46112?
Comment 18 Steve Northover CLA 2005-05-11 16:34:04 EDT
Not really, does every control have trim?  I agree that we could move the 
concept up and say that every control has trim but it can be zero.
Comment 19 Randy Hudson CLA 2005-05-11 16:45:27 EDT
(In reply to comment #18)
> Not really, does every control have trim?  I agree that we could move the 
> concept up and say that every control has trim but it can be zero.

What I am saying is that for me to call control.computeBounds(wHint), I must 
first do:
if (control instanceof Scrollable)
  wHint -= ((Scrollable)control).computeTrim(0,0,0,0).width;

which is ugly. My vote is to fix, or to deprecate and add new API, since many 
clients are misuing.

*** This bug has been marked as a duplicate of 46112 ***
Comment 20 Steve Northover CLA 2005-05-11 17:02:45 EDT
I agree.  The (ugly) pattern we are using is temporary code.  The real fix to 
happen after 3.1.