/******************************************************************************* * CogTool Copyright Notice and Distribution Terms * CogTool 1.3, Copyright (c) 2005-2013 Carnegie Mellon University * This software is distributed under the terms of the FSF Lesser * Gnu Public License (see LGPL.txt). * * CogTool 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. * * CogTool 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 CogTool; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * CogTool makes use of several third-party components, with the * following notices: * * Eclipse SWT version 3.448 * Eclipse GEF Draw2D version 3.2.1 * * Unless otherwise indicated, all Content made available by the Eclipse * Foundation is provided to you under the terms and conditions of the Eclipse * Public License Version 1.0 ("EPL"). A copy of the EPL is provided with this * Content and is also available at http://www.eclipse.org/legal/epl-v10.html. * * CLISP version 2.38 * * Copyright (c) Sam Steingold, Bruno Haible 2001-2006 * This software is distributed under the terms of the FSF Gnu Public License. * See COPYRIGHT file in clisp installation folder for more information. * * ACT-R 6.0 * * Copyright (c) 1998-2007 Dan Bothell, Mike Byrne, Christian Lebiere & * John R Anderson. * This software is distributed under the terms of the FSF Lesser * Gnu Public License (see LGPL.txt). * * Apache Jakarta Commons-Lang 2.1 * * This product contains software developed by the Apache Software Foundation * (http://www.apache.org/) * * jopt-simple version 1.0 * * Copyright (c) 2004-2013 Paul R. Holser, Jr. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * Mozilla XULRunner 1.9.0.5 * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/. * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the * License for the specific language governing rights and limitations * under the License. * * The J2SE(TM) Java Runtime Environment version 5.0 * * Copyright 2009 Sun Microsystems, Inc., 4150 * Network Circle, Santa Clara, California 95054, U.S.A. All * rights reserved. U.S. * See the LICENSE file in the jre folder for more information. ******************************************************************************/ package edu.cmu.cs.hcii.cogtool.view; import org.eclipse.draw2d.Figure; import org.eclipse.draw2d.IFigure; import org.eclipse.draw2d.RectangleFigure; import org.eclipse.draw2d.ScalableFigure; import org.eclipse.draw2d.geometry.Dimension; import org.eclipse.draw2d.geometry.Point; import org.eclipse.draw2d.geometry.Rectangle; import org.eclipse.swt.events.ControlAdapter; import org.eclipse.swt.events.ControlEvent; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Cursor; import org.eclipse.swt.widgets.Composite; import edu.cmu.cs.hcii.cogtool.util.IFlatDraw2DMouseListener; import edu.cmu.cs.hcii.cogtool.util.IFlatDraw2DMouseMotionListener; import edu.cmu.cs.hcii.cogtool.util.Zoomable; /** * This class is responsible for drawing a default VIEW of a draw2d window * and a set of properties. Unlike the Standard Drawing Editor, this editor * also adds an interaction layer which can be used to receive clicks and * event messages. * * @author alexeiser * */ public class InteractionDrawingEditor extends StandardDrawingEditor implements InteractionFigure.IEnterExitListener { /** * The contents of the draw2d space */ protected CogToolScalableFigure contents; /** * An interaction layer which receives all clicks and events. * Any listeners on events should be attached to this object. */ protected InteractionFigure interactionLayer; /** * A background figure for providing color or texture to the background * of the draw2d space. */ protected RectangleFigure backgroundColorFigure; /** * A specific color object to be used for the background color. */ protected Color backgroundColor; /** * A mouse listener object. Handles click, up/down events. */ protected IFlatDraw2DMouseListener mouseClickState; /** * A mouse MOTION listener for mouse move/drag events. */ protected IFlatDraw2DMouseMotionListener mouseMotionState; /** * Call the more specialized constructor with a WHITE background color. * * @param child * @param motionL * @param clickL * @param window * @param propertiesPaneSize * @param propertiesPaneLoc * @param paletteSize * @param editorCursor */ public InteractionDrawingEditor(CogToolScalableFigure child, IFlatDraw2DMouseMotionListener motionL, IFlatDraw2DMouseListener clickL, Composite window, Zoomable zoom, int propertiesPaneSize, int propertiesPaneLoc, int paletteSize, Cursor editorCursor) { this(child, motionL, clickL, zoom, window, propertiesPaneSize, propertiesPaneLoc, paletteSize, editorCursor, null); } /** * Create the Interaction drawing editor. * Requires the needed motion listeners, the parent window as well as the * height and location of the properties panel. * * It also takes a background color which is used to color the window. * * A cursor is also provided to handle rollovers. * * NOTE: color will be disposed by this class; * DO NOT Dispose of it yourself. * * @param child * @param motionL * @param clickL * @param window * @param propertiesPaneSize * @param propertiesPaneLoc * @param paletteSize * @param editorCursor */ public InteractionDrawingEditor(CogToolScalableFigure child, IFlatDraw2DMouseMotionListener motionL, IFlatDraw2DMouseListener clickL, Zoomable zoom, Composite window, int propertiesPaneSize, int propertiesPaneLoc, int paletteSize, Cursor editorCursor, Color bgColor) { // Call the parent StandardDrawingEditor super(window, propertiesPaneSize, propertiesPaneLoc, paletteSize, zoom, 0); // Store the interaction layer, which is created with the motion and // click listeners as well as the editing cursor. interactionLayer = new InteractionFigure(this, motionL, clickL, editorCursor); backgroundColor = bgColor; backgroundColorFigure = new RectangleFigure(); backgroundColorFigure.setBackgroundColor(backgroundColor); mouseClickState = clickL; mouseMotionState = motionL; setContents(child); // set default editors size editorComposite.setBounds(getContentSize()); // Set the contents of the LightweightSystem to the interaction layer. // The scaled interaction layer will be the TOPMOST parent of all // draw2d objects. // Also calls resize the scroll area to handle the current object size. getLWS().setContents(interactionLayer); // Specify a control adapter to handle resize events. super.addEditorControlListener(new ControlAdapter() { @Override public void controlResized(ControlEvent e) { // On resize, get the new area, and resize the internal // contents org.eclipse.swt.graphics.Rectangle r = editorComposite.getClientArea(); // Specify true to shrink the minimum area of the // window; this is to allow for the window to reclaim // space that is no longer needed. resizeContents(r.width, r.height, true); // set scroll increments to something larger than one setScrollIncrements(); } }); } public void observeEnter() { if (capturingEvents) { stopForwardingCanvasEvents(); } } public void observeExit() { if (capturingEvents) { forwardCanvasEvents(); } } @Override protected void forwardCapturedEvent(int eventType, int button, int x, int y, int state) { switch (eventType) { case MOUSE_DOWN: { mouseClickState.mousePressed(interactionLayer, button, x, y, state); break; } case MOUSE_UP: { mouseClickState.mouseReleased(interactionLayer, button, x, y, state); break; } case MOUSE_MOVE: { mouseMotionState.mouseMoved(interactionLayer, x, y, state); break; } case MOUSE_DRAG: { mouseMotionState.mouseDragged(interactionLayer, button, x, y, state); break; } case MOUSE_DOUBLECLICK: { mouseClickState.mouseDoubleClicked(interactionLayer, button, x, y, state); break; } } } /** * Return the interactionFigure on request. * @return */ public InteractionFigure getInteractionFigure() { return interactionLayer; } /** * Return the scalable section of the drawing editor. This is the * design/frame portion. * @return */ public CogToolScalableFigure getContents() { return contents; } /** * Return the figure used to colourize the background on demand. * @return */ public Figure getBackgroundColorFigure() { return backgroundColorFigure; } @Override public org.eclipse.swt.graphics.Rectangle getContentSize() { Rectangle viewSize = contents.getChildrenUtilizedAreaScaled(); // We need the TOTAL size starting from 0,0. Not just the actual size. viewSize.width += viewSize.x; viewSize.height += viewSize.y; // use 0,0 as origin return new org.eclipse.swt.graphics.Rectangle(0, 0, viewSize.width, viewSize.height); } public void resizeContents(int width, int height, boolean resizeMin) { // Get the size of the view in unscaled coordinates Rectangle viewSize = contents.getChildrenUtilizedAreaScaled(); // We need the TOTAL size starting from 0,0. Not just the actual size. int viewUIWidth = viewSize.width + viewSize.x; int viewUIHeight = viewSize.height + viewSize.y; // If the area grows, then we want to use the LARGER area if (viewUIWidth > width) { width = viewUIWidth; } if (viewUIHeight > height) { height = viewUIHeight; } Dimension prefSize = new Dimension(width, height); contents.setPreferredSize(prefSize); contents.setSize(width, height); interactionLayer.setPreferredSize(prefSize); interactionLayer.setSize(width, height); backgroundColorFigure.setPreferredSize(prefSize); backgroundColorFigure.setSize(width, height); if (resizeMin) { setMinVisibleArea(width, height, false); // Check to see if the area was enlarged if so grow to match int editorWidth = editorComposite.getSize().x; int editorHeight = editorComposite.getSize().y; if (editorWidth > width) { width = editorWidth; } if (editorHeight > height) { height = editorHeight; } contents.setSize(width, height); interactionLayer.setSize(width, height); backgroundColorFigure.setSize(width, height); } } /** * Update the visible contents * Maintains the Zoom * * @param figure */ public void setContents(CogToolScalableFigure figure) { // TODO: remove old listener, add new listener // get previous ZOOM double zoom = getZoomSetting(); contents = figure; // Place the current frame in the top corner // TODO: do we need any more "accurate" X,Y position? // Set the position BEFORE adding it, to prevent flashes where the // position changes contents.setLocation(new Point(0, 0)); // Scaling is controlled in the DesignEditorFrame interactionLayer.removeAll(); interactionLayer.add(backgroundColorFigure); interactionLayer.add(contents); setZoomSetting(zoom); resizeScrollArea(); } public double computeZoomToFit() { // Put the origin of the scrollable region back to 0,0 scrollComposite.setOrigin(0, 0); // Ensures that both width and height will fit in available space org.eclipse.swt.graphics.Rectangle visibleBounds = getVisibleBounds(); // Need to get the UNSCALEd version of currentFrame Rectangle neededBounds = contents.getChildrenUtilizedAreaUnscaled(); double scalingToFit = 1.0; // Need a fudge factor for some reason. double neededWidth = neededBounds.width + 5.0; double neededHeight = neededBounds.height + 5.0; if (neededBounds.x > 0) { neededWidth += neededBounds.x; } if (neededBounds.y > 0) { neededHeight += neededBounds.y; } // Check to see if the height would fit if we resize the width. // If it doesn't fit then resize by height. if ((neededWidth != 0.0) && (neededHeight != 0.0)) { if (((visibleBounds.width) / neededWidth) * neededHeight < visibleBounds.height) { scalingToFit = (visibleBounds.width) / neededWidth; } else { scalingToFit = (visibleBounds.height) / neededHeight; } } return scalingToFit; } public double getZoomSetting() { if (contents != null) { return contents.getScale(); } return 1.0; // Default to 1.0 } @Override public void setZoomSetting(double zoom) { // Update the view zoom setting super.setZoomSetting(zoom); if (contents.getScale() != zoom) { contents.setScale(zoom); resizeScrollArea(); } } public void resizeScrollArea() { if (contents != null) { // Provide 0,0 as the size, since we want to size it to the contents resizeContents(0, 0, true); } } public void addInteractionFigure(IFigure figure) { interactionLayer.add(figure); } public void addInteractionFigure(IFigure figure, int index) { interactionLayer.add(figure, index); } public void addScaledInteractionFigure(ScalableFigure f, int atDepth) { // Scale the given figure f.setScale(contents.getScale()); addInteractionFigure(f, atDepth); } public void removeInteractionFigure(IFigure figure) { if (figure != null) { interactionLayer.remove(figure); } } /** * Quick pass through to repaint the contents. */ public void repaint() { interactionLayer.repaint(); } @Override public void dispose() { super.dispose(); if (backgroundColor != null) { backgroundColor.dispose(); } } }