/*
* Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package sun.awt.X11;
import java.awt.*;
import java.awt.event.*;
import java.awt.peer.*;
import java.lang.reflect.*;
import sun.awt.SunToolkit;
class XScrollPanePeer extends XComponentPeer implements ScrollPanePeer, XScrollbarClient {
public final static int MARGIN = 1;
public final static int SCROLLBAR;
public final static int SPACE = 2;
public final static int SCROLLBAR_INSET = 2;
public final static int VERTICAL = 1 << 0;
public final static int HORIZONTAL = 1 << 1;
private static Method m_setValue;
static {
m_setValue = SunToolkit.getMethod(ScrollPaneAdjustable.class, "setTypedValue", new Class[] {Integer.TYPE, Integer.TYPE});
SCROLLBAR = XToolkit.getUIDefaults().getInt("ScrollBar.defaultWidth");
}
XVerticalScrollbar vsb;
XHorizontalScrollbar hsb;
XWindow clip;
int active=VERTICAL;
int hsbSpace;
int vsbSpace;
static class XScrollPaneContentWindow extends XWindow {
XScrollPaneContentWindow(ScrollPane target, long parentWindow) {
super(target, parentWindow);
}
public String getWMName() {
return "ScrollPane content";
}
}
XScrollPanePeer(ScrollPane target) {
super(target);
// Create the clip window. The field "clip" must be null when
// we call winCreate, or the parent of clip will be set to itself!
clip = null;
XWindow c = new XScrollPaneContentWindow(target,window);
clip = c;
vsb = new XVerticalScrollbar(this);
hsb = new XHorizontalScrollbar(this);
if (target.getScrollbarDisplayPolicy() == ScrollPane.SCROLLBARS_ALWAYS) {
vsbSpace = hsbSpace = SCROLLBAR;
} else {
vsbSpace = hsbSpace = 0;
}
int unitIncrement = 1;
Adjustable vAdjustable = target.getVAdjustable();
if (vAdjustable != null){
unitIncrement = vAdjustable.getUnitIncrement();
}
int h = height-hsbSpace;
vsb.setValues(0, h, 0, h, unitIncrement, Math.max(1, (int)(h * 0.90)));
vsb.setSize(vsbSpace-SCROLLBAR_INSET, h);
unitIncrement = 1;
Adjustable hAdjustable = target.getHAdjustable();
if (hAdjustable != null){
unitIncrement = hAdjustable.getUnitIncrement();
}
int w = width - vsbSpace;
hsb.setValues(0, w, 0, w, unitIncrement, Math.max(1, (int)(w * 0.90)));
hsb.setSize(w, hsbSpace-SCROLLBAR_INSET);
setViewportSize();
clip.xSetVisible(true);
}
public long getContentWindow()
{
return (clip == null) ? window : clip.getWindow();
}
public void setBounds(int x, int y, int w, int h, int op) {
super.setBounds(x, y, w, h, op);
if (clip == null) return;
setScrollbarSpace();
setViewportSize();
repaint();
}
public Insets getInsets() {
return new Insets(MARGIN, MARGIN, MARGIN+hsbSpace, MARGIN+vsbSpace);
}
public int getHScrollbarHeight() {
return SCROLLBAR;
}
public int getVScrollbarWidth() {
return SCROLLBAR;
}
public void childResized(int w, int h) {
if (setScrollbarSpace()) {
setViewportSize();
}
repaint();
}
Dimension getChildSize() {
ScrollPane sp = (ScrollPane)target;
if (sp.countComponents() > 0) {
Component c = sp.getComponent(0);
return c.size();
} else {
return new Dimension(0, 0);
}
}
boolean setScrollbarSpace() {
ScrollPane sp = (ScrollPane)target;
boolean changed = false;
int sbDisplayPolicy = sp.getScrollbarDisplayPolicy();
if (sbDisplayPolicy == ScrollPane.SCROLLBARS_NEVER) {
return changed;
}
Dimension cSize = getChildSize();
if (sbDisplayPolicy == ScrollPane.SCROLLBARS_AS_NEEDED) {
int oldHsbSpace = hsbSpace;
int oldVsbSpace = vsbSpace;
hsbSpace = (cSize.width <= (width - 2*MARGIN) ? 0 : SCROLLBAR);
vsbSpace = (cSize.height <= (height - 2*MARGIN) ? 0 : SCROLLBAR);
if (hsbSpace == 0 && vsbSpace != 0) {
hsbSpace = (cSize.width <= (width - SCROLLBAR - 2*MARGIN) ? 0 : SCROLLBAR);
}
if (vsbSpace == 0 && hsbSpace != 0) {
vsbSpace = (cSize.height <= (height - SCROLLBAR - 2*MARGIN) ? 0 : SCROLLBAR);
}
if (oldHsbSpace != hsbSpace || oldVsbSpace != vsbSpace) {
changed = true;
}
}
if (vsbSpace > 0) {
int vis = height - (2*MARGIN) - hsbSpace;
int max = Math.max(cSize.height, vis);
vsb.setValues(vsb.getValue(), vis, 0, max);
vsb.setBlockIncrement((int)(vsb.getVisibleAmount() * .90));
vsb.setSize(vsbSpace-SCROLLBAR_INSET, height-hsbSpace);
// Adjustable vadj = sp.getVAdjustable();
// vadj.setVisibleAmount(vsb.vis);
// vadj.setMaximum(vsb.max);
// vadj.setBlockIncrement(vsb.page);
}
if (hsbSpace > 0) {
int vis = width - (2*MARGIN) - vsbSpace;
int max = Math.max(cSize.width, vis);
hsb.setValues(hsb.getValue(), vis, 0, max);
hsb.setBlockIncrement((int)(hsb.getVisibleAmount() * .90));
hsb.setSize(width-vsbSpace, hsbSpace-SCROLLBAR_INSET);
// Adjustable hadj = sp.getHAdjustable();
// hadj.setVisibleAmount(hsb.vis);
// hadj.setMaximum(hsb.max);
// hadj.setBlockIncrement(hsb.page);
}
// Check to see if we hid either of the scrollbars but left
// ourselves scrolled off of the top and/or right of the pane.
// If we did, we need to scroll to the top and/or right of of
// the pane to make it visible.
//
// Reminder: see if there is a better place to put this code.
boolean must_scroll = false;
// Get the point at which the ScrollPane is currently located
// if number of components > 0
Point p = new Point(0, 0);
if (((ScrollPane)target).getComponentCount() > 0){
p = ((ScrollPane)target).getComponent(0).location();
if ((vsbSpace == 0) && (p.y < 0)) {
p.y = 0;
must_scroll = true;
}
if ((hsbSpace == 0) && (p.x < 0)) {
p.x = 0;
must_scroll = true;
}
}
if (must_scroll)
scroll(x, y, VERTICAL | HORIZONTAL);
return changed;
}
void setViewportSize() {
clip.xSetBounds(MARGIN, MARGIN,
width - (2*MARGIN) - vsbSpace,
height - (2*MARGIN) - hsbSpace);
}
public void setUnitIncrement(Adjustable adj, int u) {
if (adj.getOrientation() == Adjustable.VERTICAL) {
vsb.setUnitIncrement(u);
} else {
// HORIZONTAL
hsb.setUnitIncrement(u);
}
}
public void setValue(Adjustable adj, int v) {
if (adj.getOrientation() == Adjustable.VERTICAL) {
scroll(-1, v, VERTICAL);
} else {
// HORIZONTAL
scroll(v, -1, HORIZONTAL);
}
}
public void setScrollPosition(int x, int y) {
scroll(x, y, VERTICAL | HORIZONTAL);
}
void scroll(int x, int y, int flag) {
scroll(x, y, flag, AdjustmentEvent.TRACK);
}
/**
* Scroll the contents to position x, y
*/
void scroll(int x, int y, int flag, int type) {
checkSecurity();
ScrollPane sp = (ScrollPane)target;
Component c = getScrollChild();
if (c == null) {
return;
}
int sx, sy;
Color colors[] = getGUIcolors();
if (sp.getScrollbarDisplayPolicy() == ScrollPane.SCROLLBARS_NEVER) {
sx = -x;
sy = -y;
} else {
Point p = c.location();
sx = p.x;
sy = p.y;
if ((flag & HORIZONTAL) != 0) {
hsb.setValue(Math.min(x, hsb.getMaximum()-hsb.getVisibleAmount()));
ScrollPaneAdjustable hadj = (ScrollPaneAdjustable)sp.getHAdjustable();
setAdjustableValue(hadj, hsb.getValue(), type);
sx = -(hsb.getValue());
Graphics g = getGraphics();
try {
paintHorScrollbar(g, colors, true);
} finally {
g.dispose();
}
}
if ((flag & VERTICAL) != 0) {
vsb.setValue(Math.min(y, vsb.getMaximum() - vsb.getVisibleAmount()));
ScrollPaneAdjustable vadj = (ScrollPaneAdjustable)sp.getVAdjustable();
setAdjustableValue(vadj, vsb.getValue(), type);
sy = -(vsb.getValue());
Graphics g = getGraphics();
try {
paintVerScrollbar(g, colors, true);
} finally {
g.dispose();
}
}
}
c.move(sx, sy);
}
void setAdjustableValue(ScrollPaneAdjustable adj, int value, int type) {
try {
m_setValue.invoke(adj, new Object[] {Integer.valueOf(value), Integer.valueOf(type)});
} catch (IllegalAccessException iae) {
adj.setValue(value);
} catch (IllegalArgumentException iae2) {
adj.setValue(value);
} catch (InvocationTargetException ite) {
adj.setValue(value);
ite.getCause().printStackTrace();
}
}
public void paint(Graphics g) {
paintComponent(g);
}
void paintScrollBars(Graphics g, Color[] colors) {
if (vsbSpace > 0) {
paintVerScrollbar(g, colors, true);
// paint the whole scrollbar
}
if (hsbSpace > 0) {
paintHorScrollbar(g, colors, true);
// paint the whole scrollbar
}
}
void repaintScrollBars() {
Graphics g = getGraphics();
Color colors[] = getGUIcolors();
if (g != null) {
paintScrollBars(g,colors);
}
g.dispose();
}
public void repaintScrollbarRequest(XScrollbar sb) {
Graphics g = getGraphics();
Color colors[] = getGUIcolors();
if (g != null) {
if (sb == vsb) {
paintVerScrollbar(g,colors,true);
}
else if (sb == hsb) {
paintHorScrollbar(g,colors,true);
}
}
}
/**
* Paint the scrollpane.
*/
public void paintComponent(Graphics g) {
Color colors[] = getGUIcolors();
g.setColor(colors[BACKGROUND_COLOR]);
int h = height - hsbSpace;
int w = width - vsbSpace;
g.fillRect(0, 0, w, h);
// paint rectangular region between scrollbars
g.fillRect(w, h, vsbSpace, hsbSpace);
if (MARGIN > 0) {
draw3DRect(g, colors, 0, 0, w - 1, h - 1, false);
}
paintScrollBars(g,colors);
}
public void handleEvent(java.awt.AWTEvent e) {
super.handleEvent(e);
int id = e.getID();
switch(id) {
case PaintEvent.PAINT:
case PaintEvent.UPDATE:
repaintScrollBars();
break;
}
}
/**
* Paint the horizontal scrollbar to the screen
*
* @param g the graphics context to draw into
* @param colors the colors used to draw the scrollbar
* @param paintAll paint the whole scrollbar if true, just the thumb if false
*/
void paintHorScrollbar(Graphics g, Color colors[], boolean paintAll) {
if (hsbSpace <= 0) {
return;
}
Graphics ng = g.create();
g.setColor(colors[BACKGROUND_COLOR]);
// SCROLLBAR is the height of scrollbar area
// but the actual scrollbar is SCROLLBAR-SPACE high;
// the rest must be filled with background color
int w = width - vsbSpace - (2*MARGIN);
g.fillRect(MARGIN, height-SCROLLBAR, w, SPACE);
g.fillRect(0, height-SCROLLBAR, MARGIN, SCROLLBAR);
g.fillRect(MARGIN + w, height-SCROLLBAR, MARGIN, SCROLLBAR);
try {
ng.translate(MARGIN, height - (SCROLLBAR - SPACE));
hsb.paint(ng, colors, paintAll);
}
finally {
ng.dispose();
}
}
/**
* Paint the vertical scrollbar to the screen
*
* @param g the graphics context to draw into
* @param colors the colors used to draw the scrollbar
* @param paintAll paint the whole scrollbar if true, just the thumb if false
*/
void paintVerScrollbar(Graphics g, Color colors[], boolean paintAll) {
if (vsbSpace <= 0) {
return;
}
Graphics ng = g.create();
g.setColor(colors[BACKGROUND_COLOR]);
// SCROLLBAR is the width of scrollbar area
// but the actual scrollbar is SCROLLBAR-SPACE wide;
// the rest must be filled with background color
int h = height - hsbSpace - (2*MARGIN);
g.fillRect(width-SCROLLBAR, MARGIN, SPACE, h);
g.fillRect(width-SCROLLBAR, 0, SCROLLBAR, MARGIN);
g.fillRect(width-SCROLLBAR, MARGIN+h, SCROLLBAR, MARGIN);
try {
ng.translate(width - (SCROLLBAR - SPACE), MARGIN);
vsb.paint(ng, colors, paintAll);
}
finally {
ng.dispose();
}
}
/**
*
* @see java.awt.event.MouseEvent
* MouseEvent.MOUSE_CLICKED
* MouseEvent.MOUSE_PRESSED
* MouseEvent.MOUSE_RELEASED
* MouseEvent.MOUSE_MOVED
* MouseEvent.MOUSE_ENTERED
* MouseEvent.MOUSE_EXITED
* MouseEvent.MOUSE_DRAGGED
*/
public void handleJavaMouseEvent( MouseEvent mouseEvent ) {
super.handleJavaMouseEvent(mouseEvent);
int modifiers = mouseEvent.getModifiers();
int id = mouseEvent.getID();
int x = mouseEvent.getX();
int y = mouseEvent.getY();
// super.handleMouseEvent(mouseEvent);
if ((modifiers & InputEvent.BUTTON1_MASK) == 0) {
return;
}
switch (id) {
case MouseEvent.MOUSE_PRESSED:
if (inVerticalScrollbar(x,y )) {
active = VERTICAL;
int h = height - hsbSpace - (2*MARGIN);
vsb.handleMouseEvent(id,modifiers,x - (width - SCROLLBAR + SPACE),y-MARGIN);
} else if (inHorizontalScrollbar(x, y) ) {
active = HORIZONTAL;
int w = width - 2*MARGIN - vsbSpace;
hsb.handleMouseEvent(id,modifiers,x-MARGIN,y-(height - SCROLLBAR + SPACE));
}
break;
// On mouse up, pass the event through to the scrollbar to stop
// scrolling. The x & y passed do not matter.
case MouseEvent.MOUSE_RELEASED:
// winReleaseCursorFocus();
if (active == VERTICAL) {
vsb.handleMouseEvent(id,modifiers,x,y);
} else if (active == HORIZONTAL) {
hsb.handleMouseEvent(id,modifiers,x,y);
}
break;
case MouseEvent.MOUSE_DRAGGED:
if ((active == VERTICAL)) {
int h = height - 2*MARGIN - hsbSpace;
vsb.handleMouseEvent(id,modifiers,x-(width - SCROLLBAR + SPACE),y-MARGIN);
} else if ((active == HORIZONTAL)) {
int w = width - 2*MARGIN - vsbSpace;
hsb.handleMouseEvent(id,modifiers,x-MARGIN,y-(height - SCROLLBAR + SPACE));
}
break;
}
}
/**
* return value from the scrollbar
*/
public void notifyValue(XScrollbar obj, int type, int v, boolean isAdjusting) {
if (obj == vsb) {
scroll(-1, v, VERTICAL, type);
} else if ((XHorizontalScrollbar)obj == hsb) {
scroll(v, -1, HORIZONTAL, type);
}
}
/**
* return true if the x and y position is in the verticalscrollbar
*/
boolean inVerticalScrollbar(int x, int y) {
if (vsbSpace <= 0) {
return false;
}
int h = height - MARGIN - hsbSpace;
return (x >= width - (SCROLLBAR - SPACE)) && (x < width) && (y >= MARGIN) && (y < h);
}
/**
* return true if the x and y position is in the horizontal scrollbar
*/
boolean inHorizontalScrollbar(int x, int y) {
if (hsbSpace <= 0) {
return false;
}
int w = width - MARGIN - vsbSpace;
return (x >= MARGIN) && (x < w) && (y >= height - (SCROLLBAR - SPACE)) && (y < height);
}
private Component getScrollChild() {
ScrollPane sp = (ScrollPane)target;
Component child = null;
try {
child = sp.getComponent(0);
} catch (ArrayIndexOutOfBoundsException e) {
// do nothing. in this case we return null
}
return child;
}
int vval;
int hval;
int vmax;
int hmax;
/*
* Print the native component by rendering the Motif look ourselves.
* ToDo(aim): needs to query native motif for more accurate size and
* color information.
*/
public void print(Graphics g) {
ScrollPane sp = (ScrollPane)target;
Dimension d = sp.size();
Color bg = sp.getBackground();
Color fg = sp.getForeground();
Point p = sp.getScrollPosition();
Component c = getScrollChild();
Dimension cd;
if (c != null) {
cd = c.size();
} else {
cd = new Dimension(0, 0);
}
int sbDisplay = sp.getScrollbarDisplayPolicy();
int vvis, hvis, vmin, hmin, vmax, hmax, vval, hval;
switch (sbDisplay) {
case ScrollPane.SCROLLBARS_NEVER:
hsbSpace = vsbSpace = 0;
break;
case ScrollPane.SCROLLBARS_ALWAYS:
hsbSpace = vsbSpace = SCROLLBAR;
break;
case ScrollPane.SCROLLBARS_AS_NEEDED:
hsbSpace = (cd.width <= (d.width - 2*MARGIN)? 0 : SCROLLBAR);
vsbSpace = (cd.height <= (d.height - 2*MARGIN)? 0 : SCROLLBAR);
if (hsbSpace == 0 && vsbSpace != 0) {
hsbSpace = (cd.width <= (d.width - SCROLLBAR - 2*MARGIN)? 0 : SCROLLBAR);
}
if (vsbSpace == 0 && hsbSpace != 0) {
vsbSpace = (cd.height <= (d.height - SCROLLBAR - 2*MARGIN)? 0 : SCROLLBAR);
}
}
vvis = hvis = vmin = hmin = vmax = hmax = vval = hval = 0;
if (vsbSpace > 0) {
vmin = 0;
vvis = d.height - (2*MARGIN) - hsbSpace;
vmax = Math.max(cd.height - vvis, 0);
vval = p.y;
}
if (hsbSpace > 0) {
hmin = 0;
hvis = d.width - (2*MARGIN) - vsbSpace;
hmax = Math.max(cd.width - hvis, 0);
hval = p.x;
}
// need to be careful to add the margins back in here because
// we're drawing the margin border, after all!
int w = d.width - vsbSpace;
int h = d.height - hsbSpace;
g.setColor(bg);
g.fillRect(0, 0, d.width, d.height);
if (hsbSpace > 0) {
int sbw = d.width - vsbSpace;
g.fillRect(1, d.height - SCROLLBAR - 3, sbw - 1, SCROLLBAR - 3);
Graphics ng = g.create();
try {
ng.translate(0, d.height - (SCROLLBAR - 2));
drawScrollbar(ng, bg, SCROLLBAR - 2, sbw,
hmin, hmax, hval, hvis, true);
} finally {
ng.dispose();
}
}
if (vsbSpace > 0) {
int sbh = d.height - hsbSpace;
g.fillRect(d.width - SCROLLBAR - 3, 1, SCROLLBAR - 3, sbh - 1);
Graphics ng = g.create();
try {
ng.translate(d.width - (SCROLLBAR - 2), 0);
drawScrollbar(ng, bg, SCROLLBAR - 2, sbh,
vmin, vmax, vval, vvis, false);
} finally {
ng.dispose();
}
}
draw3DRect(g, bg, 0, 0, w - 1, h - 1, false);
target.print(g);
sp.printComponents(g);
}
}