/**
* Copyright (c) 2014 - 2017 Frank Appel
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Frank Appel - initial API and implementation
*/
package com.codeaffine.eclipse.swt.widget.scrollable.context;
import static java.lang.Integer.valueOf;
import static java.lang.Math.max;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Scrollable;
class SizeComputer {
static final String WIDTH_OFFSET_ON_VISIBLE_HORIZONTAL_BAR = AdaptionContext.class.getName() + "#widthAdjustment:";
static final String PREFERRED_SIZE = AdaptionContext.class.getName() + "# preferredSize";
static final Point EMPTY_BUFFER_SIZE = new Point( 0, 0 );
private final ScrollableControl<? extends Scrollable> scrollable;
private final PreferredSizeProvider preferredSizeProvider;
private final Composite adapter;
SizeComputer( ScrollableControl<? extends Scrollable> scrollable, Composite adapter ) {
this.preferredSizeProvider = new PreferredSizeProvider( scrollable );
this.scrollable = scrollable;
this.adapter = adapter;
}
Point getPreferredSize() {
Point preferredSize = getPreferredSizeInternal();
return new Point( preferredSize.x + getPreferredWidthAdjustmentForVisibleHorizontalBar(), preferredSize.y );
}
void updatePreferredSize() {
Point preferredSize = preferredSizeProvider.getSize();
if( scrollable.isInstanceof( ScrolledComposite.class ) ) {
preferredSizeForScrolledComposite( preferredSize );
} else if( preferredSize.x - scrollable.getVerticalBarSize().x == scrollable.getSize().x ) {
scrollable.setData( PREFERRED_SIZE, scrollable.getSize() );
} else if( isVirtualAndOwnerDrawn() ) {
bestPreferredSizeGuessForVirtualAndOwnerDrawnScrollables( preferredSize );
} else { // check possible improvement on non owner drawn scrollables: #28
bestPreferredlSizeGuessForOwnerDrawnScrollables( preferredSize );
}
}
void adjustPreferredWidthIfHorizontalBarIsVisible() {
if( scrollable.isHorizontalBarVisible() && scrollable.isChildOf( adapter.getParent() ) ) {
updatePreferredSize();
scrollable.setData( getWidthOffsetKey(), valueOf( getPreferredSizeInternal().x ) );
}
}
private boolean isVirtualAndOwnerDrawn() {
return scrollable.isOwnerDrawn() && scrollable.hasStyle( SWT.VIRTUAL );
}
private Point getPreferredSizeInternal() {
if( getBufferedPreferredSize().equals( EMPTY_BUFFER_SIZE ) ) {
updatePreferredSize();
}
return getBufferedPreferredSize();
}
private Point getBufferedPreferredSize() {
Point result = ( Point )scrollable.getData( PREFERRED_SIZE );
return result == null ? EMPTY_BUFFER_SIZE: result;
}
private int getPreferredWidthAdjustmentForVisibleHorizontalBar() {
Integer result = ( Integer )scrollable.getData( getWidthOffsetKey() );
return result != null ? result.intValue() : 0;
}
private String getWidthOffsetKey() {
return WIDTH_OFFSET_ON_VISIBLE_HORIZONTAL_BAR + getPreferredSizeInternal();
}
private void preferredSizeForScrolledComposite( Point preferredSize ) {
scrollable.setData( PREFERRED_SIZE, preferredSize );
Control content = ( ( ScrolledComposite )scrollable.getControl() ).getContent();
if( content != null ) {
scrollable.setData( PREFERRED_SIZE, content.getSize() );
}
}
private void bestPreferredSizeGuessForVirtualAndOwnerDrawnScrollables( Point computed ) {
int parentWidth = adapter.getClientArea().width;
int width = max( getBufferedPreferredSize().x, parentWidth );
scrollable.setData( PREFERRED_SIZE, new Point( width, computed.y ) );
// Ugly side effect, might lead to flickering - better options?
scrollable.setHorizontalBarVisible( false );
}
private void bestPreferredlSizeGuessForOwnerDrawnScrollables( Point computed ) {
int parentWidth = adapter.getClientArea().width;
int maximum = scrollable.getHorizontalBarMaximum();
int width = max( getBufferedPreferredSize().x, max( parentWidth, maximum ) );
scrollable.setData( PREFERRED_SIZE, new Point( width, computed.y ) );
}
}