/*******************************************************************************
* Copyright (c) 2016 Alex Shapiro - github.com/shpralex
* This program and the accompanying materials
* are made available under the terms of the The MIT License (MIT)
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*******************************************************************************/
package com.sproutlife.panel.gamepanel;
import java.awt.*;
import java.awt.event.*;
import java.util.Vector;
import java.util.concurrent.TimeUnit;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import com.sproutlife.panel.PanelController;
@SuppressWarnings("serial")
public class ScrollPanel extends JPanel {
private static final int SCROLL_UNIT_INCREMENT = 10;
private static final int SCROLL_BLOCK_INCREMENT_SUBTRACT_FROM_EXTENT = 10;
private static final int MIN_SCROLL_BLOCK_INCREMENT = 10;
private PanelController panelController;
private Vector<ViewportResizedListener> viewportResizedListeners;
private Vector<ViewportMovedListener> viewportMovedListeners;
private BoundedRangeModel hScrollModel;
private BoundedRangeModel vScrollModel;
private JScrollBar hScrollBar;
private JScrollBar vScrollBar;
private JPanel innerPanel;
private boolean isUpdating = false;
/*
private Vector<ShapeRenderer> frontShapes;
private Vector<ShapeRenderer> backShapes;
*/
public ScrollPanel(PanelController panelController) {
this.panelController = panelController;
viewportResizedListeners = new Vector<ViewportResizedListener>();
viewportMovedListeners = new Vector<ViewportMovedListener>();
vScrollModel = new DefaultBoundedRangeModel();
hScrollModel = new DefaultBoundedRangeModel();
//frontShapes = new Vector<ShapeRenderer>();
//backShapes = new Vector<ShapeRenderer>();
buildPanel();
createListeners();
}
private void buildPanel() {
GridBagLayout layout = new GridBagLayout();
GridBagConstraints layoutCons = new GridBagConstraints();
setLayout(layout);
innerPanel = new JPanel() {
public void paint(Graphics g) {
boolean locked = false;
try {
boolean success=false;
while(!success) {
locked = panelController.getInteractionLock().readLock().tryLock(100, TimeUnit.MILLISECONDS);
if (locked) {
success=true;
super.paint(g);
Graphics2D g2 = (Graphics2D)g;
//original commented out - gc.getInteractionLock().readLock().lock();
//paintBackShapes(g2);
panelController.getImageManager().paint(g2);
//paintFrontShapes(g2);
}
else {
try {
/*
for ( StackTraceElement[] steA : Thread.getAllStackTraces().values() ) {
for ( StackTraceElement ste : steA ) {
System.out.println(ste.toString());
}
}
*/
} catch ( Exception ex ) {// Catch exception if any
System.err.println("Error: " + ex.getMessage());
}
//System.out.println("Paint lock failed");
}
}
}
catch(Exception ex) {
ex.printStackTrace();
}
finally {
if (locked) {
panelController.getInteractionLock().readLock().unlock();
}
}
}
};
layoutCons.gridx = 0;
layoutCons.gridy = 0;
layoutCons.gridwidth = 100;
layoutCons.gridheight = 100;
layoutCons.fill = GridBagConstraints.BOTH;
layoutCons.insets = new Insets(1,1,0,0);
layoutCons.anchor = GridBagConstraints.NORTH;
layoutCons.weightx = 120.0;
layoutCons.weighty = 120.0;
layout.setConstraints(innerPanel, layoutCons);
add(innerPanel);
vScrollBar = new JScrollBar(JScrollBar.VERTICAL);
vScrollBar.setModel(vScrollModel);
layoutCons.gridx = 100;
layoutCons.gridy = 0;
layoutCons.gridwidth = GridBagConstraints.REMAINDER;
layoutCons.gridheight = 100;
layoutCons.fill = GridBagConstraints.VERTICAL;
layoutCons.insets = new Insets(1,0,0,1);
layoutCons.anchor = GridBagConstraints.NORTH;
layoutCons.weightx = 0.0;
layoutCons.weighty = 120.0;
layout.setConstraints(vScrollBar, layoutCons);
add(vScrollBar);
hScrollBar = new JScrollBar(JScrollBar.HORIZONTAL);
hScrollBar.setModel(hScrollModel);
layoutCons.gridx = 0;
layoutCons.gridy = 100;
layoutCons.gridwidth = 100;
layoutCons.gridheight = GridBagConstraints.REMAINDER;
layoutCons.fill = GridBagConstraints.HORIZONTAL;
layoutCons.insets = new Insets(0,1,1,0);
layoutCons.anchor = GridBagConstraints.NORTH;
layoutCons.weightx = 120.0;
layoutCons.weighty = 0.0;
layout.setConstraints(hScrollBar, layoutCons);
add(hScrollBar);
JPanel cornerPanel = new JPanel();
//cornerPanel.setBorder(new LineBorder(Color.black));
layoutCons.gridx = 100;
layoutCons.gridy = 100;
layoutCons.gridwidth = GridBagConstraints.REMAINDER;
layoutCons.gridheight = GridBagConstraints.REMAINDER;
layoutCons.fill = GridBagConstraints.BOTH;
layoutCons.insets = new Insets(0,0,1,1);
layoutCons.anchor = GridBagConstraints.NORTH;
layoutCons.weightx = 0.0;
layoutCons.weighty = 0.0;
layout.setConstraints(cornerPanel, layoutCons);
add(cornerPanel);
}
public Dimension getViewportSize() {
return new Dimension(innerPanel.getWidth(),innerPanel.getHeight());
}
public void addMouseListener(MouseListener ml) {
innerPanel.addMouseListener(ml);
}
public void addMouseMotionListener(MouseMotionListener mml) {
innerPanel.addMouseMotionListener(mml);
}
public void addMouseWheelListener(MouseWheelListener mwl) {
innerPanel.addMouseWheelListener(mwl);
}
public void removeMouseListener(MouseListener ml) {
innerPanel.removeMouseListener(ml);
}
public void removeMouseMotionListener(MouseMotionListener mml) {
innerPanel.removeMouseMotionListener(mml);
}
public void removeMouseWheelListener(MouseWheelListener mwl) {
innerPanel.removeMouseWheelListener(mwl);
}
public void enableMouseListeners() {
addMouseListener(panelController.getInteractionHandler());
addMouseMotionListener(panelController.getInteractionHandler());
addMouseWheelListener(panelController.getInteractionHandler());
}
public void disableMouseListeners() {
removeMouseListener(panelController.getInteractionHandler());
removeMouseMotionListener(panelController.getInteractionHandler());
removeMouseWheelListener(panelController.getInteractionHandler());
}
/*
public void addBackShape(ShapeRenderer shape) {
backShapes.add(shape);
}
public void removeBackShape(ShapeRenderer shape) {
backShapes.remove(shape);
}
public void addFrontShape(ShapeRenderer shape) {
frontShapes.add(shape);
}
public void removeFrontShape(ShapeRenderer shape) {
frontShapes.remove(shape);
}
private void paintBackShapes(Graphics2D g2) {
paintShapes(backShapes, g2);
}
private void paintFrontShapes(Graphics2D g2) {
paintShapes(frontShapes, g2);
}
private void paintShapes(Vector<ShapeRenderer> shapes, Graphics2D g2) {
for ( ShapeRenderer shape : shapes ) {
shape.paint(g2);
}
}
*/
protected void update(final int minX, final int maxX, final int xValue, final int xExtent,
final int minY, final int maxY, final int yValue, final int yExtent) {
Runnable updater = new Runnable() {
public void run() {
isUpdating = true;
hScrollModel.setRangeProperties(xValue, xExtent, minX, maxX, false);
vScrollModel.setRangeProperties(yValue, yExtent, minY, maxY, false);
hScrollBar.setBlockIncrement(Math.max(MIN_SCROLL_BLOCK_INCREMENT, xExtent-SCROLL_BLOCK_INCREMENT_SUBTRACT_FROM_EXTENT));
vScrollBar.setBlockIncrement(Math.max(MIN_SCROLL_BLOCK_INCREMENT, yExtent-SCROLL_BLOCK_INCREMENT_SUBTRACT_FROM_EXTENT));
hScrollBar.setUnitIncrement(SCROLL_UNIT_INCREMENT);
vScrollBar.setUnitIncrement(SCROLL_UNIT_INCREMENT);
isUpdating = false;
}
};
SwingUtilities.invokeLater(updater);
}
protected void update(final int xValue, final int yValue) {
Runnable updater = new Runnable() {
public void run() {
isUpdating = true;
hScrollModel.setValue(xValue);
vScrollModel.setValue(yValue);
isUpdating = false;
}
};
SwingUtilities.invokeLater(updater);
}
private void createListeners() {
innerPanel.addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent e) {
fireViewportResized(innerPanel.getWidth(), innerPanel.getHeight());
}
});
ChangeListener changeListener = new ChangeListener() {
public void stateChanged(ChangeEvent ce) {
if ( !isUpdating ) {
fireViewportMoved(hScrollModel.getValue(),vScrollModel.getValue());
}
}
};
vScrollModel.addChangeListener(changeListener);
hScrollModel.addChangeListener(changeListener);
}
private synchronized void fireViewportResized(int viewportWidth, int viewportHeight) {
for ( ViewportResizedListener gvrl : viewportResizedListeners ) {
gvrl.viewportResized(viewportWidth, viewportHeight);
}
}
public synchronized void addViewportResizedListener(ViewportResizedListener gvrl) {
viewportResizedListeners.add(gvrl);
}
public void removeViewportResizedListener(ViewportResizedListener gvrl) {
viewportResizedListeners.remove(gvrl);
}
public interface ViewportResizedListener {
public void viewportResized(int viewportWidth, int viewportHeight);
}
private void fireViewportMoved(int viewportX, int viewportY) {
for ( ViewportMovedListener gvml : viewportMovedListeners ) {
gvml.viewportMoved(viewportX, viewportY);
}
}
public void addViewportMovedListener(ViewportMovedListener gvml) {
viewportMovedListeners.add(gvml);
}
public void removeViewportMovedListener(ViewportMovedListener gvml) {
viewportMovedListeners.remove(gvml);
}
public interface ViewportMovedListener {
public void viewportMoved(int viewportX, int viewportY);
}
/*
public static class DecoratedShape implements ShapeRenderer {
private Shape shape;
private Color color;
private Stroke stroke;
public void paint( Graphics2D g2 ) {
g2.setColor(color);
g2.setStroke(stroke);
g2.draw(shape);
}
public DecoratedShape(Shape shape, Color color, Stroke stroke) {
this.shape = shape;
this.color = color;
this.stroke = stroke;
}
public Shape getShape() { return shape; }
public Color getColor() { return color; }
public Stroke getStroke() { return stroke; }
}
*/
}