/** * 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 org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Layout; import org.eclipse.swt.widgets.Scrollable; import com.codeaffine.eclipse.swt.layout.LayoutWrapper; import com.codeaffine.eclipse.swt.util.OperationWithRedrawSuspension; class LayoutActor extends LayoutWrapper { private final OperationWithRedrawSuspension operationWithRedrawSuspension; private final ScrollableControl<? extends Scrollable> scrollable; private final Composite adapter; LayoutActor( Layout layout, ScrollableControl<? extends Scrollable> scrollable, Composite adapter ) { this( layout, scrollable, adapter, new OperationWithRedrawSuspension() ); } LayoutActor( Layout layout, ScrollableControl<? extends Scrollable> scrollable, Composite adapter, OperationWithRedrawSuspension operationWithRedrawSuspension ) { super( layout ); this.operationWithRedrawSuspension = operationWithRedrawSuspension; this.scrollable = scrollable; this.adapter = adapter; } @Override public Point computeSize( Composite composite, int wHint, int hHint, boolean flushCache ) { return super.computeSize( composite, wHint, hHint, flushCache ); } @Override public void layout( Composite composite, boolean flushCache ) { operationWithRedrawSuspension.execute( composite, () -> { super.layout( composite, flushCache ); updateAdapterBounds( computeAdapterBounds() ); } ); } private Rectangle computeAdapterBounds() { Rectangle scrollableBounds = scrollable.getBounds(); Rectangle adapterBounds = adapter.getBounds(); int x = scrollableBounds.x - adapterBounds.x; int y = scrollableBounds.y - adapterBounds.y; return new Rectangle( x, y, scrollableBounds.width, scrollableBounds.height ); } private void updateAdapterBounds( Rectangle bounds ) { adapter.setBounds( bounds ); // Note [fappel]: This passage isn't covered with unit tests, since I wasn't able to reproduce the layout // issue in a test scenario. However, since this workaround seems to avoid the location computation // problems with StyledTextAdapters when lazy loading parts with TextViewers I leave it as // it is for now. if( !adapter.getBounds().equals( bounds ) ) { adapter.setBounds( bounds ); } } }