//
// GDCanvas.java
// Java Graphics Device
//
// Created by Simon Urbanek on Thu Aug 05 2004.
// Copyright (c) 2004-2016 Simon Urbanek. All rights reserved.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation;
// version 2.1 of the License.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
package org.rosuda.javaGD;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.InputEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.lang.reflect.Method;
import java.util.Vector;
public class GDCanvas extends Canvas implements GDContainer, MouseListener {
Vector l;
boolean listChanged;
public static boolean forceAntiAliasing=true;
GDState gs;
Refresher r;
Dimension lastSize;
public int devNr=-1;
public GDCanvas(double w, double h, int canvasColor) {
this((int)w, (int)h, canvasColor);
}
public GDCanvas(int w, int h, int canvasColor) {
l=new Vector();
gs=new GDState();
gs.f=new Font(null,0,12);
setSize(w,h);
lastSize=getSize();
setBackground(new Color((canvasColor & 255), ((canvasColor>>8) & 255), ((canvasColor>>16) & 255)));
addMouseListener(this);
(r=new Refresher(this)).start();
}
public GDState getGState() { return gs; }
public void setDeviceNumber(int dn) { devNr=dn; }
public int getDeviceNumber() { return devNr; }
public void closeDisplay() {}
public synchronized void cleanup() {
r.active=false;
r.interrupt();
reset();
r=null;
l=null;
}
public void syncDisplay(boolean finish) {
repaint();
}
public void initRefresh() {
//System.out.println("resize requested");
try { // for now we use no cache - just pure reflection API for: Rengine.getMainEngine().eval("...")
Class c=Class.forName("org.rosuda.JRI.Rengine");
if (c==null)
System.out.println(">> can't find Rengine, automatic resizing disabled. [c=null]");
else {
Method m=c.getMethod("getMainEngine",null);
Object o=m.invoke(null,null);
if (o!=null) {
Class[] par=new Class[1];
par[0]=Class.forName("java.lang.String");
m=c.getMethod("eval",par);
Object[] pars=new Object[1];
pars[0]="try(.Call(\"javaGDresize\", "+devNr+"L)), PACKAGE= \"rj.gd\", silent= TRUE)";
m.invoke(o, pars);
}
}
} catch (Exception e) {
System.out.println(">> can't find Rengine, automatic resizing disabled. [x:"+e.getMessage()+"]");
}
}
public synchronized void add(GDObject o) {
l.add(o);
listChanged=true;
}
public synchronized void reset() {
l.removeAllElements();
listChanged=true;
}
LocatorSync lsCallback=null;
public synchronized boolean prepareLocator(LocatorSync ls) {
if (lsCallback!=null && lsCallback!=ls) // make sure we cause no deadlock
lsCallback.triggerAction(null);
lsCallback=ls;
return true;
}
// MouseListener for the Locator support
public void mouseClicked(MouseEvent e) {
if (lsCallback!=null) {
double[] pos = null;
if ((e.getModifiers()&InputEvent.BUTTON1_MASK)>0 && (e.getModifiers()&(InputEvent.BUTTON2_MASK|InputEvent.BUTTON3_MASK))==0) { // B1 = return position
pos = new double[2];
pos[0] = (double)e.getX();
pos[1] = (double)e.getY();
}
// pure security measure to make sure the trigger doesn't mess with the locator sync object
LocatorSync ls=lsCallback;
lsCallback=null; // reset the callback - we'll get a new one if necessary
ls.triggerAction(pos);
}
}
public void mousePressed(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public synchronized Vector getGDOList() { return l; }
long lastUpdate;
long lastUpdateFinished;
boolean updatePending=false;
public void update(Graphics g) {
if (System.currentTimeMillis()-lastUpdate<200) {
updatePending=true;
if (System.currentTimeMillis()-lastUpdateFinished>700) {
g.setColor(Color.white);
g.fillRect(0,0,250,25);
g.setColor(Color.blue);
g.drawString("Building plot... ("+l.size()+" objects)",10,10);
lastUpdateFinished=System.currentTimeMillis();
}
lastUpdate=System.currentTimeMillis();
return;
}
updatePending=false;
super.update(g);
lastUpdateFinished=lastUpdate=System.currentTimeMillis();
}
class Refresher extends Thread {
GDCanvas c;
boolean active;
public Refresher(GDCanvas c) {
this.c=c;
}
public void run() {
active=true;
while (active) {
try {
Thread.sleep(300);
} catch (Exception e) {}
if (!active) break;
if (c.updatePending && (System.currentTimeMillis()-lastUpdate>200)) {
c.repaint();
}
}
c=null;
}
}
public synchronized void paint(Graphics g) {
updatePending=false;
Dimension d=getSize();
if (!d.equals(lastSize)) {
initRefresh();
lastSize=d;
return;
}
if (forceAntiAliasing) {
Graphics2D g2=(Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
}
int i=0, j=l.size();
g.setFont(gs.f);
g.setClip(0,0,d.width,d.height); // reset clipping rect
while (i<j) {
GDObject o=(GDObject) l.elementAt(i++);
o.paint(this, gs, g);
}
lastUpdate=System.currentTimeMillis();
}
}