/*******************************************************************************
* Copyright (c) 2007 Exadel, Inc. and Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is 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:
* Exadel, Inc. and Red Hat, Inc. - initial API and implementation
******************************************************************************/
package org.jboss.tools.common.model.ui.widgets;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Layout;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.ScrollBar;
/**
* @author AU
*/
public class ScrolledComposite extends Composite {
private Composite viewport;
private boolean fixedWidth;
private boolean fixedHeight;
private boolean inResize;
private boolean grabHSpace = Boolean.TRUE.booleanValue();
private boolean grabVSpace = Boolean.TRUE.booleanValue();
public ScrolledComposite(Composite parent, int style) {
super(parent, checkStyle(style));
setBackground(parent.getBackground());
ScrollBar hBar = getHorizontalBar ();
if (hBar != null) {
hBar.addListener (SWT.Selection, new Listener () {
public void handleEvent (Event e) {
hScroll();
}
});
} else {
this.fixedWidth = Boolean.TRUE.booleanValue();
}
ScrollBar vBar = getVerticalBar ();
vBar.setIncrement(10);
if (vBar != null) {
vBar.addListener (SWT.Selection, new Listener () {
public void handleEvent (Event e) {
vScroll();
}
});
} else {
this.fixedHeight = Boolean.TRUE.booleanValue();
}
addListener (SWT.Resize, new Listener () {
public void handleEvent (Event e) {
resize();
}
});
Label label = new Label(this, SWT.NONE);
label.setText("Test");
viewport = new Viewport(this, SWT.NONE);
}
private static int checkStyle (int style) {
int mask = SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER | SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT;
return style & mask;
}
private void vScroll() {
if (viewport == null) return;
Point location = viewport.getLocation ();
ScrollBar vBar = getVerticalBar ();
int vSelection = vBar.getSelection ();
viewport.setLocation (location.x, -vSelection);
}
private void hScroll() {
if (viewport == null) return;
Point location = viewport.getLocation ();
ScrollBar hBar = getHorizontalBar ();
int hSelection = hBar.getSelection ();
viewport.setLocation (-hSelection, location.y);
}
private void resize() {
if (inResize) return;
inResize = Boolean.TRUE.booleanValue();
layout();
inResize = Boolean.FALSE.booleanValue();
}
public Composite getViewport() {
return viewport;
}
public void setLayout(Layout layout) {
if (viewport!=null) viewport.setLayout(layout);
}
private int lock = 0;
public void layout(boolean changed) {
checkWidget();
if (viewport == null) return;
if(lock > 0) return; //EFWPE-617
++lock;
try {
doLayout();
} finally {
--lock;
}
}
private void doLayout() {
Point viewportSize = viewport.computeSize(SWT.DEFAULT, SWT.DEFAULT, Boolean.TRUE.booleanValue());
Point viewportLocation = viewport.getLocation();
Rectangle cr = new Rectangle(viewportLocation.x, viewportLocation.y, viewportSize.x, viewportSize.y);
Rectangle hr = getClientArea();
if (fixedWidth) {
cr.width = hr.width;
} else if (grabHSpace) {
cr.width = Math.max(cr.width, hr.width);
}
if (fixedHeight) {
cr.height = hr.height;
} else if (grabVSpace) {
cr.height = Math.max(cr.height, hr.height);
}
layoutHBar(cr, hr);
layoutVBar(cr, hr);
viewport.setBounds(cr);
}
private void layoutHBar(Rectangle cr, Rectangle hr) {
ScrollBar hBar = getHorizontalBar ();
if(hBar == null) return;
hBar.setMaximum (cr.width);
hBar.setThumb(Math.min (cr.width, hr.width));
int hs = hBar.getSelection ();
if (hs >= cr.width - hr.width) {
if (cr.width <= hr.width) {
hs = 0;
hBar.setSelection(0);
}
cr.x = -hs;
}
if(hBar.getThumb() >= hBar.getMaximum())
hBar.setVisible(false);
else
hBar.setVisible(true);
}
private void layoutVBar(Rectangle cr, Rectangle hr) {
ScrollBar vBar = getVerticalBar();
if(vBar == null) return;
vBar.setMaximum(cr.height);
vBar.setThumb(Math.min (cr.height, hr.height));
int vs = vBar.getSelection ();
if (vs >= cr.height - hr.height) {
if (cr.height <= hr.height) {
vs = 0;
vBar.setSelection(0);
}
cr.y = -vs;
}
if(vBar.getThumb() >= vBar.getMaximum())
vBar.setVisible(false);
else
vBar.setVisible(true);
}
public Point computeSize (int wHint, int hHint, boolean changed) {
checkWidget ();
if (viewport == null) {
return super.computeSize (wHint, hHint, changed);
}
if (wHint>16) wHint = wHint-16;
Point size = viewport.computeSize (wHint, hHint, changed);
Rectangle trim = computeTrim (0, 0, size.x, size.y);
//ModelUIPlugin.log("+++ computeSize="+trim);
return new Point (trim.width, trim.height);
}
public static void scrollToVisible(Control control, Rectangle r) {
int y = r == null ? 0 : r.y;
Rectangle pr = control.getBounds();
y += pr.y;
Composite parent = control.getParent();
while(parent != null && !(parent instanceof Viewport)) {
pr = parent.getBounds();
y += pr.y;
parent = parent.getParent();
}
if(parent == null) return;
Viewport v = (Viewport)parent;
pr = v.getBounds();
ScrolledComposite sc = (ScrolledComposite)v.getParent();
int availableH = sc.getBounds().height;
int viewportH = pr.height;
if(viewportH <= availableH) return;
ScrollBar bar = sc.getVerticalBar();
int dh = r == null ? 10 : r.height;
int up = dh + 2 - y;
int down = availableH - dh - 2 - dh - y;
if(up > down) {
up = (up + down) / 2 - 5;
down = up + 10;
}
int delta = 0;
if(pr.y > down) {
delta = down - pr.y;
} else if(pr.y < up) {
delta = up - pr.y;
}
int sDelta = (bar.getMaximum() - bar.getMinimum() - bar.getThumb()) * (-delta) / (viewportH - availableH);
bar.setSelection(bar.getSelection() + sDelta);
pr.y += delta;
v.setBounds(pr);
v.layout(true);
}
}