/* * This file is part or JMathLib * * Check it out at http://www.jmathlib.de * * Author: * (c) 2008-2009 */ package jmathlib.core.graphics; import jmathlib.core.interpreter.ErrorLogger; import jmathlib.core.graphics.properties.*; import jmathlib.core.graphics.axes.*; import java.awt.*; import java.awt.event.*; import java.awt.print.*; /** created and holds the axes of a plot, there can be multiple axes in one plot*/ public class FigureObject extends GraphicalObject implements WindowListener, Printable, ActionListener, PropertyListener { private class FigurePanel extends Panel { FigurePanel() { super(); } public void update(Graphics g) { ErrorLogger.debugLine("FigureOb: update"); paint(g); } public void add(AxesObject ax) { super.add(ax.getComponent()); } public void add(AxesObject ax, int index) { super.add(ax.getComponent(), index); } } /**The number of this figure*/ private int figureNo = 0; /** number of tiles in horizontal direction*/ private int gridX = 1; /** number of tiles in vertical direction*/ private int gridY = 1; /**An array of the axes*/ private AxesObject[][] figureElements = new AxesObject[gridY][gridX]; /**The current axes where all plot commands will be directed to */ private int currentAxes = 1; /**A pointer to the graphics manager*/ private GraphicsManager gM; // size of frame; private int dyFrame = 500; private int dxFrame = 500; /*Holds all elements of a figure. The panel is organized as a grid*/ private Frame fig = new Frame(); private FigurePanel p = new FigurePanel(); // the menu bar MenuBar mbar = new MenuBar(); // properties public DoubleVectorProperty AlphamapP = new DoubleVectorProperty(this, "Alphamap", new double[0], -1); public BooleanProperty BeingDeletedP = new BooleanProperty(this, "BeingDeleted", false); public FunctionalHandleProperty CloseRequestFcnP = new FunctionalHandleProperty(this, "CloseRequestFcn", ""); public ColorProperty ColorP = new ColorProperty(this, "Color", Color.lightGray); public ColormapProperty ColormapP = new ColormapProperty(this, "Colormap"); public FunctionalHandleProperty CreateFcnP = new FunctionalHandleProperty(this, "CreateFcn", ""); // public CurrentAxesP public StringProperty CurrentCharacterP = new StringProperty(this, "CurrentCharacter", ""); // public CurrentObjectP // public CurrentPointP public FunctionalHandleProperty DeleteFcnP = new FunctionalHandleProperty(this, "DeleteFcn", ""); public BooleanProperty DockControlsP = new BooleanProperty(this, "DockControls", true); public BooleanProperty DoubleBufferP = new BooleanProperty(this, "DoubleBuffer", true); public StringProperty FileNameP = new StringProperty(this, "FileName", ""); public ColormapProperty FixedColorsP = new ColormapProperty(this, "FixedColors"); public BooleanProperty IntegerHandleP = new BooleanProperty(this, "IntegerHandle", true); public BooleanProperty InvertHardcopyP = new BooleanProperty(this, "InvertHardcopy", true); public FunctionalHandleProperty KeyPressFcnP = new FunctionalHandleProperty(this, "KeyPressFcn", ""); public FunctionalHandleProperty KeyReleaseFcnP = new FunctionalHandleProperty(this, "KeyReleaseFcn", ""); public RadioProperty MenuBarP = new RadioProperty(this, "MenuBar", new String[] {"none", "figure"}, "figure"); public DoubleProperty MinColormapP = new DoubleProperty(this, "MinColormap", 1.0); public StringProperty NameP = new StringProperty(this, "Name", ""); public RadioProperty NextPlotP = new RadioProperty(this, "NextPlot", new String[] {"next", "add", "replace", "replacechildren"}, "add"); public BooleanProperty NumberTitleP = new BooleanProperty(this, "NumberTitle", true); public RadioProperty PaperOrientationP = new RadioProperty(this, "PaperOrientation", new String[] {"portrait", "landscape"}, "portrait"); public DoubleVectorProperty PaperPositionP = new DoubleVectorProperty(this, "PaperPosition", new double[0], -1); public RadioProperty PaperPositionModeP = new RadioProperty(this, "PaperPositionMode", new String[] {"auto", "manual"}, "manual"); public DoubleVectorProperty PaperSizeP = new DoubleVectorProperty(this, "PaperSize", new double[2], -1); public StringProperty PaperTypeP = new StringProperty(this, "PaperType", ""); public RadioProperty PaperUnitsP = new RadioProperty(this, "PaperUnits", new String[] {"normalized", "inches", "centimeters", "points"}, "inches"); public RadioProperty PointerP = new RadioProperty(this, "Pointer", new String[] {"crosshair", "arrow", "watch", "topl", "topr", "botl", "botr", "circle", "cross", "fleur", "left", "right", "top", "bottom", "fullcrosshair", "ibeam", "custom"}, "arrow"); public DoubleVectorProperty PointerShapeCDataP = new DoubleVectorProperty(this, "PointerShapeCData", new double[16], -1); public DoubleVectorProperty PointerShapeHotSpotP = new DoubleVectorProperty(this, "PointerShapeHotSpot", new double[2], -1); public DoubleVectorProperty PositionP = new DoubleVectorProperty(this, "Position", new double[4], 4); public RadioProperty RendererP = new RadioProperty(this, "Renderer", new String[] {"painters", "zbuffer", "OpenGL"}, "painters"); public RadioProperty RendererModeP = new RadioProperty(this, "RendererMode", new String[] {"auto", "manual"}, "auto"); public BooleanProperty ResizeP = new BooleanProperty(this, "Resize", true); public FunctionalHandleProperty ResizeFcnP = new FunctionalHandleProperty(this, "ResizeFcn", ""); public RadioProperty SelectionTypeP = new RadioProperty(this, "SelectionType", new String[] {"normal", "extend", "alt", "open"}, "normal"); public BooleanProperty ShareColorsP = new BooleanProperty(this, "ShareColors", true); public RadioProperty ToolBarP = new RadioProperty(this, "ToolBar", new String[] {"none", "auto", "figure"}, "auto"); // public UIContextMenuP public UnitsProperty UnitsP = new UnitsProperty(this, "Units", "pixels"); public FunctionalHandleProperty WindowButtonDownFcnP = new FunctionalHandleProperty(this, "WindowButtonDownFcn", ""); public FunctionalHandleProperty WindowButtonMotionFcnP = new FunctionalHandleProperty(this, "WindowButtonMotionFcn", ""); public FunctionalHandleProperty WindowButtonUpFcnP = new FunctionalHandleProperty(this, "WindowButtonUpFcn", ""); public FunctionalHandleProperty WindowScrollWheelFcnP = new FunctionalHandleProperty(this, "WindowScrollWheelFcn", ""); public RadioProperty WindowStyleP = new RadioProperty(this, "WindowStyle", new String[] {"normal", "modal", "docked"}, "normal"); // WVisual public RadioProperty WVisualModeP = new RadioProperty(this, "WVisualMode", new String[] {"auto", "manual"}, "manual"); // XDisplay // XVisual public RadioProperty VisualModeP = new RadioProperty(this, "VisualMode", new String[] {"auto", "manual"}, "manual"); public FigureObject() { // set type to "axes" TypeP = new TypeProperty(this, "figure"); MenuBarP.addPropertyListener(this); NameP.addPropertyListener(this); } public FigureObject(int _figureNo) { this(); // set type to "axes" TypeP = new TypeProperty(this, "figure"); figureNo = _figureNo; // setup window frame fig.setSize(dxFrame, dyFrame); fig.setTitle("Figure No."+figureNo); fig.setBackground( ColorP.getColor() ); fig.addWindowListener(this); // create initial axes object figureElements[0][0] = new AxesObject(); // setup internal layout p.setLayout(new GridLayout(gridY, gridX)); p.add(figureElements[0][0]); fig.add(p); fig.setResizable(ResizeP.isSet()); // other initialization initMenuBar(); fig.setVisible(true); } /** * set up menue for figure window * */ private void initMenuBar() { Menu fileMenu = new Menu("File"); fileMenu.add(new MenuItem("New Figure", new MenuShortcut(KeyEvent.VK_N, false))); fileMenu.add(new MenuItem("Close", new MenuShortcut(KeyEvent.VK_W, false))); fileMenu.add("Close All"); fileMenu.addSeparator(); fileMenu.add(new MenuItem("Print...", new MenuShortcut(KeyEvent.VK_P, false))); fileMenu.addActionListener(this); mbar.add(fileMenu); Menu editMenu = new Menu("Edit"); mbar.add(editMenu); Menu viewMenu = new Menu("View"); mbar.add(viewMenu); Menu insertMenu = new Menu("Insert"); mbar.add(insertMenu); Menu toolsMenu = new Menu("Tools"); mbar.add(toolsMenu); Menu helpMenu = new Menu("Help"); helpMenu.add("Check for Updates"); helpMenu.add("About JMathLib"); mbar.add(helpMenu); fig.setMenuBar(mbar); } //public void addAxes(AxesObject _axes) //{ //figureElements.addElement(_axes); //currentAxes = figureElements.indexOf(_axes); //ErrorLogger.debugLine("FigureObject: addElement: "+currentAxes); //} public AxesObject getCurrentAxes() { // numbering starts with 1 (top left) increases to the right // 1 | 2 | 3 | 4 // 5 | 6 | 7 | 8 int y = (int)(currentAxes / gridX); if (y*gridX == currentAxes) y--; int x = (int)(currentAxes - y*gridX) - 1; if (figureElements[y][x] == null) figureElements[y][x] = new AxesObject(); return figureElements[y][x]; } public PolarAxesObject getCurrentPolarAxes() { ErrorLogger.debugLine("FigureObject: getcurrentpolaraxes"); // numbering starts with 1 (top left) increases to the right // 1 | 2 | 3 | 4 // 5 | 6 | 7 | 8 int y = (int)(currentAxes / gridX); if (y*gridX == currentAxes) y--; int x = (int)(currentAxes - y*gridX) - 1; if (figureElements[y][x] instanceof PolarAxesObject) return (PolarAxesObject)figureElements[y][x]; else if (figureElements[y][x] == null) figureElements[y][x] = new PolarAxesObject(); else figureElements[y][x] = new PolarAxesObject(); p.remove(currentAxes-1); p.add(figureElements[y][x], currentAxes-1); p.validate(); return (PolarAxesObject)figureElements[y][x]; } public void convertCurrentAxesTo3DAxes() { //ErrorLogger.debugLine("FigureObject: convertCurrentAxesTo3DAxes"); if (getCurrentAxes() instanceof Axes3DObject) return; // somehow remove following 4 lines int y = (int)(currentAxes / gridX); if (y*gridX == currentAxes) y--; int x = (int)(currentAxes - y*gridX) - 1; figureElements[y][x]= new Axes3DObject(); p.remove(currentAxes-1); p.add(figureElements[y][x], currentAxes-1); p.validate(); } public int getFigureNumber() { return figureNo; } /**devide the current figure into n*m tiles*/ public void setSubPlot(int _gridY, int _gridX, int _currentAxes) { // numberring starts with 1 (top left) increases to the right // 1 | 2 | 3 | 4 // 5 | 6 | 7 | 8 (example of setSubPlot(2,4,x)) //ErrorLogger.debugLine("Figure:setSubPlot: "); if (_currentAxes<= _gridY*_gridX) currentAxes = _currentAxes; else currentAxes = 1; // check if only currentAxes is changed if ((gridY==_gridY) && (gridX==_gridX)) return; // gridY and/or gridX is changed => make new layout gridY = _gridY; gridX = _gridX; p.removeAll(); p.setLayout(new GridLayout(gridY,gridX)); figureElements = new AxesObject[gridY][gridX]; for (int y=0; y<figureElements.length; y++) { for (int x=0; x<figureElements[y].length; x++) { //ErrorLogger.debugLine("FigureObject: subplot : "+y+" "+x); //if (figureElements[y][x]!=null) figureElements[y][x] = new AxesObject(); p.add(figureElements[y][x]); } } p.validate(); } /** * */ public void clearFigure() { p.removeAll(); p.setLayout(new GridLayout(1,1)); for (int y=0; y<figureElements.length; y++) { for (int x=0; x<figureElements[y].length; x++) { //ErrorLogger.debugLine("FigureObject: subplot : "+y+" "+x); //if (figureElements[y][x]!=null) figureElements[y][x] = null; } } p.validate(); p.repaint(); } /** * method for printing the graphics window to an external printer */ public int print(Graphics g, PageFormat pf, int page) throws PrinterException { //ErrorLogger.debugLine("FigureObject: print : page="+page ); // get printable area int yPos = (int)pf.getImageableY(); int xPos = (int)pf.getImageableX(); int yMax = (int)pf.getImageableHeight(); int xMax = (int)pf.getImageableWidth(); //ErrorLogger.debugLine("FigureObject: xPos="+xPos+" yPos="+yPos); //ErrorLogger.debugLine("FigureObject: xMax="+xMax+" yMax="+yMax); double rPage = (double)yMax/(double)xMax; double rFig = (double)fig.getSize().height/(double)fig.getSize().width; if (rPage > rFig) { yMax = (int)(rFig*xMax); yPos += ((int)pf.getImageableHeight()-yMax)/2; } else { xMax = (int)(yMax/rFig); xPos += ((int)pf.getImageableWidth()-xMax)/2; } // draw black rectangle around printing area g.setColor(Color.black); g.drawRect(xPos, yPos, xMax, yMax); //this.setBackground(Color.lightGray); // create a new panel and group all elements which need to be printed // -> is is done in order to get the correct size of the elements FigurePanel pP = new FigurePanel(); pP.setLayout(new GridLayout(gridY, gridX)); for (int y=0; y<figureElements.length; y++) { for (int x=0; x<figureElements[y].length; x++) { //ErrorLogger.debugLine("FigureObject: print : "+y+" "+x); pP.add(figureElements[y][x]); } } // needed? pP.setSize(xMax,yMax); //pP.setBounds(xPos,yPos,xMax,yMax); // move origin of graphical context to left top corner // of the visible page layout g.translate(xPos, yPos); int xTransSum=0; int yTransSum=0; int xTrans=0; int yTrans=0; // print axes on the printer-page for (int y=0; y<figureElements.length; y++) { yTrans=0; for (int x=0; x<figureElements[y].length; x++) { //ErrorLogger.debugLine("FigureObject: print-method : "+y+" "+x); //ErrorLogger.debugLine("figure:size x="+figureElements[y][x].getSize().width+" y="+figureElements[y][x].getSize().height); figureElements[y][x].getComponent().setSize(xMax, yMax); xTrans = figureElements[y][x].getSize().width; yTrans = Math.max(yTrans, figureElements[y][x].getSize().height); figureElements[y][x].setBackBuffer(false); figureElements[y][x].paint(g); figureElements[y][x].setBackBuffer(true); // move origin to next figure element g.translate(xTrans, 0); xTransSum += xTrans; } // move origin back to left side and // move origin down one row g.translate(-xTransSum, 0); g.translate(0, yTrans); // remember moving down yTransSum += yTrans; } // go back to origin "top left" g.translate(0, -yTransSum); // copy figure elements back to original panel on the screen for (int y=0; y<figureElements.length; y++) { for (int x=0; x<figureElements[y].length; x++) { //ErrorLogger.debugLine("FigureObject: copy back : "+y+" "+x); //if (figureElements[y][x]!=null) p.add(figureElements[y][x]); } } // return one valid page (page-no. 0) if (page==0) return PAGE_EXISTS; else return NO_SUCH_PAGE; } public void close() { close(true); } public void close(boolean notify) { if (notify) gM.removeFigure(figureNo); fig.dispose(); } public void windowClosing(WindowEvent e) { //ErrorLogger.debugLine("FigureObject: windowClosing: "+figureNo); this.close(); } public void windowActivated(WindowEvent e){} public void windowDeactivated(WindowEvent e){} public void windowClosed(WindowEvent e){} public void windowIconified(WindowEvent e){} public void windowDeiconified(WindowEvent e){} public void windowOpened(WindowEvent e){} public void setGraphicsManager(GraphicsManager _gM) { gM = _gM; } public void actionPerformed(ActionEvent ev) { String cmd = ev.getActionCommand(); if (cmd.equals("Close")) gM.closeFigure(figureNo); else if (cmd.equals("New Figure")) gM.createNewFigure(); else if (cmd.equals("Close All")) gM.closeAll(); else if (cmd.equals("Print...")) doPrint(); } private void doPrint() { PrinterJob job = PrinterJob.getPrinterJob(); job.setPrintable(this); if (job.printDialog()) { try { job.print(); } catch (PrinterException e) { } } } public void repaint() { //super.repaint(); } public void propertyChanged(Property p) { ErrorLogger.debugLine("FigureObject property changed: "+ p.getName()); // xxx if (p==DockControlsP) { if (DockControlsP.isSet()) { } else { } } // xxx if (p==DoubleBufferP) { if (DoubleBufferP.isSet()) { } else { } } // display/remove menu bar if (p == MenuBarP) { if (MenuBarP.is("none")) fig.setMenuBar(null); else fig.setMenuBar(mbar); } // change name of this figure if (p == NameP) { if (NameP.getString().equals("")) fig.setTitle("Figure No."+figureNo); else fig.setTitle("Figure No."+figureNo+": "+NameP.getString()); } parent.repaint(); } }