/* Part of the GUI library for Processing http://www.lagers.org.uk/g4p/index.html http://sourceforge.net/projects/g4p/files/?source=navbar Copyright (c) 2012 Peter Lager 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; either version 2.1 of the License, or (at your option) any later version. 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package automenta.vivisect.gui; import automenta.vivisect.swing.PCanvas; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedList; import java.util.List; import processing.core.PApplet; import processing.core.PConstants; import processing.core.PMatrix; import processing.core.PMatrix3D; import processing.event.KeyEvent; import processing.event.MouseEvent; import static processing.event.MouseEvent.PRESS; /** * DO NOT ATTEMPT TO USE THIS CLASS <br> * * Although this class and many of its methods are declared public this is to * make them available through Reflection and means that they should only be * used inside the library code. <br> * * This class is used to remember information about a particular applet (i.e. * window) and is responsible for forwarding events passed to it from * Processing. <br> * * It remembers the original transformation matrix to simplify working with 3D * renderers and libraries such as PeasyCam. * * @author Peter Lager * */ public class GWindowInfo implements PConstants, GConstants, GConstantsInternal { public PCanvas app; public boolean app_g_3d; public PMatrix orgMatrix; public List<GControl> windowControls = new ArrayList<GControl>(); // These next two lists are for controls that are to be added or remove since these // actions must be performed outside the draw cycle to avoid concurrent modification // exceptions when changing windowControls public List<GControl> toRemove = new LinkedList<GControl>(); public List<GControl> toAdd = new LinkedList<GControl>(); // Set this to true if papplet is a GWinApplet objects i.e. part of a // Gwindow object //boolean isGWindow; /** * Create an applet info object * * @param papplet */ public GWindowInfo(PApplet papplet) { app = (PCanvas)papplet; // Is this applet part of a GWindow object //isGWindow = (app instanceof GWinApplet); app_g_3d = app.g.is3D(); if (app.g.is3D()) { orgMatrix = papplet.getMatrix((PMatrix3D) null); } // else // orgMatrix = papplet.getMatrix((PMatrix2D)null); /* * The WinInfo object is responsible for capturing events from Processing * and passing them onto the GWindow objects and the controls. */ app.registerMethod("draw", this); app.registerMethod("mouseEvent", this); app.registerMethod("keyEvent", this); app.registerMethod("pre", this); app.registerMethod("post", this); } /** * The draw method registered with Processing */ public void draw() { app.pushMatrix(); if (app_g_3d) { app.hint(PConstants.DISABLE_DEPTH_TEST); // Load the identity matrix. app.resetMatrix(); // Apply the original Processing transformation matrix. app.applyMatrix(orgMatrix); } int numControls = windowControls.size(); for (int i = 0; i < numControls; i++) { final GControl control = windowControls.get(i); if ((control.registeredMethods & DRAW_METHOD) == DRAW_METHOD) { control.draw(); } } if (app_g_3d) { app.hint(PConstants.ENABLE_DEPTH_TEST); } app.popMatrix(); } /** * The mouse method registered with Processing * * @param event */ public void mouseEvent(MouseEvent event) { /*if (isGWindow) { ((GWinApplet) app).mouseEvent(event); }*/ for (GControl control : windowControls) { //handle auto-zoom if ((event.getAction() == PRESS) && (event.getButton() == PConstants.RIGHT)) { if (control.isOver(event.getX(), event.getY())) { app.setZoom( control.getCX(), control.getCY(), control.getWidth(),control.getHeight()); break; } } if ((control.registeredMethods & MOUSE_METHOD) == MOUSE_METHOD) { control.mouseEvent(event); } } } /** * The key method registered with Processing */ public void keyEvent(KeyEvent event) { /*if (isGWindow) { ((GWinApplet) app).keyEvent(event); }*/ for (GControl control : windowControls) { if ((control.registeredMethods & KEY_METHOD) == KEY_METHOD) { control.keyEvent(event); } } } /** * The pre method registered with Processing */ public void pre() { // System.out.println(app); if (GControl.controlToTakeFocus != null && GControl.controlToTakeFocus.getPApplet() == app) { GControl.controlToTakeFocus.setFocus(true); GControl.controlToTakeFocus = null; } /*if (isGWindow) { ((GWinApplet) app).pre(); }*/ for (GControl control : windowControls) { if ((control.registeredMethods & PRE_METHOD) == PRE_METHOD) { control.pre(); } } } /** * The post method registered with Processing */ public void post() { if (GUI.cursorChangeEnabled) { if (GControl.cursorIsOver != null) //&& GControl.cursorIsOver.getPApplet() == app) { app.cursor(GControl.cursorIsOver.cursorOver); } else { app.cursor(GUI.mouseOff); } } /*if (isGWindow) { ((GWinApplet) app).post(); }*/ for (GControl control : windowControls) { if ((control.registeredMethods & POST_METHOD) == POST_METHOD) { control.post(); } } // ===================================================================================================== // ===================================================================================================== // This is where components are removed or added to the window to avoid concurrent access violations // ===================================================================================================== // ===================================================================================================== synchronized (this) { // Dispose of any unwanted controls if (!toRemove.isEmpty()) { for (GControl control : toRemove) { // If the control has focus then lose it if (GControl.focusIsWith == control) { control.loseFocus(null); } // Clear control resources control.buffer = null; if (control.parent != null) { control.parent.children.remove(control); control.parent = null; } if (control.children != null) { control.children.clear(); } control.palette = null; control.jpalette = null; control.eventHandlerObject = null; control.eventHandlerMethod = null; control.winApp = null; windowControls.remove(control); System.gc(); } toRemove.clear(); } if (!toAdd.isEmpty()) { for (GControl control : toAdd) { windowControls.add(control); } toAdd.clear(); Collections.sort(windowControls, GUI.zorder); } } } /** * Dispose of this WIndow. <br> * First unregister for event handling then clear list of controls for this * window. */ void dispose() { app.noLoop(); app.unregisterMethod("draw", this); app.unregisterMethod("pre", this); app.unregisterMethod("post", this); app.unregisterMethod("mouseEvent", this); app.unregisterMethod("keyEvent", this); windowControls.clear(); } /** * If a control is to be added to this window then add the control to the * toAdd list. The control will actually be added during the post() method * * @param control */ synchronized void addControl(GControl control) { // Make sure we avoid duplicates if (!windowControls.contains(control) && !toAdd.contains(control)) { toAdd.add(control); } } /** * If a control is to be removed to this window then add the control to the * toAdd list. The control will actually be added during the post() method * * @param control */ synchronized void removeControl(GControl control) { // Make sure we avoid duplicates if (windowControls.contains(control) && !toRemove.contains(control)) { toRemove.add(control); } } void setColorScheme(int cs) { for (GControl control : windowControls) { control.setLocalColorScheme(cs); } } void setAlpha(int alpha) { for (GControl control : windowControls) { control.setAlpha(alpha); } } }