/*****************************************************************************
gui.Scroller
*****************************************************************************/
package gui;
import java.awt.*;
/** **************************************************************************
A `wrapper' panel for containing an awt.Component (of whatever design) which
can be scrolled. The Scroller provides a viewport onto the `scrolled' panel
and maintains optional scrollbars.
Note that due to limitations in the awt design (and limitations in time to find
workarounds) there are two notable problems with this Containter:
- It is rather jumpy, during scrolling (it doesn't seem possible, with the
documented interface, to double-buffer the display).
- If you add items to the scrolled panel, you have to invalidate() (and
then validate()) the Scroller. Otherwise, it doesn't know about the change
and will not recompute the viewport.
@author Bruce R. Miller (bruce.miller@nist.gov)
@author Contribution of the National Institute of Standards and Technology,
@author not subject to copyright.
*/
public class Scroller extends Panel implements LayoutManager {
/** Indicator to show scrollbars only when the scrolled component is
* too large.*/
public static final int IFNEEDED = 0;
/** Indicator to always show scrollbars. */
public static final int ALWAYS = 1;
/** Indicator to never show scrollbars. */
public static final int NEVER = 2;
int xscrolling = IFNEEDED, yscrolling = IFNEEDED;
int margin = 2;
Scrollbar xscroll,yscroll;
Panel clipper;
Component scrolled;
/** Create a Scroller panel using scrolled as the inner component to be
* scrolled, and placing scrollbars only if needed. */
public Scroller(Component scrolled) {
this(scrolled, IFNEEDED,IFNEEDED); }
/** Create a Scroller panel using scrolled as the inner component to be
* scrolled, and placing according to the given flags. */
public Scroller(Component scrolled, int xscrolling, int yscrolling) {
this.scrolled = scrolled;
setXScrolling(xscrolling);
setYScrolling(yscrolling);
GridBagLayout layout = new GridBagLayout();
GridBagConstraints c = new GridBagConstraints();
setLayout(layout);
c.fill = GridBagConstraints.BOTH;
c.anchor = GridBagConstraints.CENTER;
c.weightx = c.weighty = 1.0;
c.gridwidth = c.gridheight = GridBagConstraints.RELATIVE;
layout.setConstraints(add(clipper = new Panel()),c);
clipper.setLayout(this);
clipper.add(scrolled);
c.fill = GridBagConstraints.VERTICAL;
c.weightx = c.weighty = 0.0;
c.gridwidth = GridBagConstraints.REMAINDER;
add(yscroll = new Scrollbar(Scrollbar.VERTICAL, 0,1,0,1));
yscroll.setLineIncrement(1);
layout.setConstraints(yscroll,c);
c.fill = GridBagConstraints.HORIZONTAL;
c.gridwidth = GridBagConstraints.RELATIVE;
c.gridheight = GridBagConstraints.REMAINDER;
add(xscroll = new Scrollbar(Scrollbar.HORIZONTAL, 0,1,0,1));
xscroll.setLineIncrement(1);
layout.setConstraints(xscroll,c);
}
/** Set the parameter for when the X (horizontal) scrollbar should be
* shown.*/
public void setXScrolling(int xscrolling) {
if (this.xscrolling != xscrolling) {
this.xscrolling = xscrolling;
//invalidate();
}}
/** Set the parameter for when the Y (vertical) scrollbar should be shown.*/
public void setYScrolling(int yscrolling) {
if (this.yscrolling != yscrolling) {
this.yscrolling = yscrolling;
// invalidate();
}}
public boolean handleEvent(Event e) {
if ((e.target == xscroll) || (e.target == yscroll)) {
scrolled.move(-xscroll.getValue(),-yscroll.getValue());
return true; }
return super.handleEvent(e); }
public Insets insets() {
return new Insets(margin,margin,0,0); }
public void paint(Graphics g) {
Dimension S = size();
g.setColor(getBackground().darker());
g.fillRect(0,0,margin,S.height);
g.fillRect(0,0,S.width,margin); }
/**********************************************************************
Implementing Layout manager for use by clipping panel ONLY! */
public void addLayoutComponent(String name, Component comp) {}
public void layoutContainer(Container parent) {
if (parent != clipper)
throw new IllegalArgumentException("Using Scroller as layout manager");
Dimension s = clipper.size(), S = scrolled.preferredSize();
int w = s.width, h = s.height,
W = S.width, H = S.height;
//int maxX = Math.max(0,W-w), maxY = Math.max(0,H-h);
int maxX = W, maxY = H;
int x = (xscrolling == NEVER ? 0 : Math.max(-xscroll.getValue(),-maxX)),
y = (yscrolling == NEVER ? 0 : Math.max(-yscroll.getValue(),-maxY));
if ((w==0) || (h==0)) // Why this happens, no clue. (but it does!)
return;
scrolled.reshape(x,y,
(xscrolling == NEVER ? w : W),
(yscrolling == NEVER ? h : H));
if ((xscrolling == NEVER) || ((xscrolling == IFNEEDED) && (w >= W)))
xscroll.hide();
else {
xscroll.show();
xscroll.setValues(-x,w,0,maxX); }
if ((yscrolling == NEVER) || ((yscrolling == IFNEEDED) && (h >= H)))
yscroll.hide();
else {
yscroll.show();
yscroll.setValues(-y,h,0,maxY); }
if (isVisible())
repaint(); }
public Dimension minimumLayoutSize(Container parent) {
return scrolled.minimumSize(); }
public Dimension preferredLayoutSize(Container parent) {
return scrolled.preferredSize(); }
public void removeLayoutComponent(Component comp) {}
}