diff --git a/extras/src/main/java/edu/umd/cs/piccolox/PApplet.java b/extras/src/main/java/edu/umd/cs/piccolox/PApplet.java index a15a496..69efc97 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/PApplet.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/PApplet.java @@ -41,13 +41,15 @@ * @author Jesse Grosjean */ public class PApplet extends JApplet { - - /** - * - */ + /** Used to allow versioned binary streams for serializations. */ private static final long serialVersionUID = 1L; + + /** Canvas being displayed by this applet. */ private PCanvas canvas; + /** + * Initializes the applet with a canvas and no background. + */ public void init() { setBackground(null); @@ -70,19 +72,26 @@ }); } + /** + * Returns the canvas this PApplet is displaying. + * + * @return canvas this applet is displaying + */ public PCanvas getCanvas() { return canvas; } + /** + * Provides an extension point for subclasses so that they can control + * what's on the canvas by default. + * + * @return a built canvas + */ public PCanvas createCanvas() { return new PCanvas(); } - // **************************************************************** - // Initialize - // **************************************************************** - - /** + /** * This method will be called before the initialize() method and will be * called on the thread that is constructing this object. */ @@ -90,7 +99,7 @@ } /** - * Subclasses should override this method and add their Piccolo + * Subclasses should override this method and add their Piccolo2d * initialization code there. This method will be called on the swing event * dispatch thread. Note that the constructors of PFrame subclasses may not * be complete when this method is called. If you need to initailize some diff --git a/extras/src/main/java/edu/umd/cs/piccolox/PFrame.java b/extras/src/main/java/edu/umd/cs/piccolox/PFrame.java index f2379bd..472c9f0 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/PFrame.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/PFrame.java @@ -56,20 +56,47 @@ * @author Jesse Grosjean */ public class PFrame extends JFrame { - + /** Used to allow versioned binary streams for serializations. */ private static final long serialVersionUID = 1L; + + /** Canvas being displayed on this PFrame. */ private PCanvas canvas; + + /** The graphics device onto which the PFrame is being displayed. */ private final GraphicsDevice graphicsDevice; + + /** Listener that listens for escape key. */ private EventListener escapeFullScreenModeListener; + /** + * Creates a PFrame with no title, not full screen, and with the default + * canvas. + */ public PFrame() { this("", false, null); } + /** + * Creates a PFrame with the given title and with the default canvas. + * + * @param title title to display at the top of the frame + * @param fullScreenMode whether to display a full screen frame or not + * @param canvas to embed in the frame + */ public PFrame(final String title, final boolean fullScreenMode, final PCanvas aCanvas) { this(title, GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(), fullScreenMode, aCanvas); } + /** + * Creates a PFrame with the given title and with the default canvas being + * displayed on the provided device. + * + * @param title title to display at the top of the frame + * @param aDevice device onto which PFrame is to be displayed + * @param fullScreenMode whether to display a full screen frame or not + * @param canvas to embed in the frame, may be null. If so, it'll create a + * default PCanvas + */ public PFrame(final String title, final GraphicsDevice aDevice, final boolean fullScreenMode, final PCanvas aCanvas) { super(title, aDevice.getDefaultConfiguration()); @@ -111,52 +138,79 @@ }); } + /** + * Returns the canvas being displayed on this frame. + * + * @return canvas being displayed on this frame + */ public PCanvas getCanvas() { return canvas; } + /** + * Returns the default frame bounds. + * + * @return default frame bounds + */ public Rectangle getDefaultFrameBounds() { return new Rectangle(100, 100, 400, 400); } - // **************************************************************** - // Full Screen Display Mode - // **************************************************************** - + /** + * Returns whether the frame is currently in full screen mode. + * + * @return whether the frame is currently in full screen mode + */ public boolean isFullScreenMode() { return graphicsDevice.getFullScreenWindow() != null; } + /** + * Switches full screen state. + * + * @param fullScreenMode whether to place the frame in full screen mode or + * not. + */ public void setFullScreenMode(final boolean fullScreenMode) { - if (fullScreenMode) { - addEscapeFullScreenModeListener(); - - if (isDisplayable()) { - dispose(); + if (fullScreenMode != isFullScreenMode()) { + if (fullScreenMode) { + switchToFullScreenMode(); } - - setUndecorated(true); - setResizable(false); - graphicsDevice.setFullScreenWindow(this); - - if (graphicsDevice.isDisplayChangeSupported()) { - chooseBestDisplayMode(graphicsDevice); + else { + switchToWindowedMode(); } - validate(); } - else { - removeEscapeFullScreenModeListener(); + } - if (isDisplayable()) { - dispose(); - } + private void switchToFullScreenMode() { + addEscapeFullScreenModeListener(); - setUndecorated(false); - setResizable(true); - graphicsDevice.setFullScreenWindow(null); - validate(); - setVisible(true); + if (isDisplayable()) { + dispose(); } + + setUndecorated(true); + setResizable(false); + graphicsDevice.setFullScreenWindow(this); + + if (graphicsDevice.isDisplayChangeSupported()) { + chooseBestDisplayMode(graphicsDevice); + } + validate(); + } + + private void switchToWindowedMode() { + removeEscapeFullScreenModeListener(); + + if (isDisplayable()) { + dispose(); + } + + setUndecorated(false); + setResizable(true); + graphicsDevice.setFullScreenWindow(null); + validate(); + setVisible(true); } protected void chooseBestDisplayMode(final GraphicsDevice device) { diff --git a/extras/src/main/java/edu/umd/cs/piccolox/event/PSelectionEventHandler.java b/extras/src/main/java/edu/umd/cs/piccolox/event/PSelectionEventHandler.java index 0f720dd..be90724 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/event/PSelectionEventHandler.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/event/PSelectionEventHandler.java @@ -63,33 +63,48 @@ * @author Ben Bederson */ public class PSelectionEventHandler extends PDragSequenceEventHandler { - + /** + * Notification name that identifies a change in the selection. Used with + * PNotificationCenter. + */ public static final String SELECTION_CHANGED_NOTIFICATION = "SELECTION_CHANGED_NOTIFICATION"; - final static int DASH_WIDTH = 5; - final static int NUM_STROKES = 10; + /** The default dash width when displaying selection rectangle. */ + static final int DASH_WIDTH = 5; - // The current selection + static final int NUM_STROKES = 10; + + /** The current selection. */ private HashMap selection = null; - // List of nodes whose children can be selected + /** List of nodes whose children can be selected. */ private List selectableParents = null; + private PPath marquee = null; - // Node that marquee is added to as a child + /** Node that marquee is added to as a child. */ private PNode marqueeParent = null; + private Point2D presspt = null; private Point2D canvasPressPt = null; private float strokeNum = 0; private Stroke[] strokes = null; - // Used within drag handler temporarily + + /** Used within drag handler temporarily. */ private HashMap allItems = null; - // Used within drag handler temporarily + + /** Used within drag handler temporarily */ private ArrayList unselectList = null; private HashMap marqueeMap = null; - // Node pressed on (or null if none) + + /** Node pressed on (or null if none). */ private PNode pressNode = null; - // True if DELETE key should delete selection + + /** True if DELETE key should delete selection. */ private boolean deleteKeyActive = true; + + /** Paint applied when drawing the marquee. */ private Paint marqueePaint; + + /** How transparent the marquee should be. */ private float marqueePaintTransparency = 1.0f; /** @@ -134,10 +149,11 @@ marqueeMap = new HashMap(); } - // ///////////////////////////////////////////////////// - // Public static methods for manipulating the selection - // ///////////////////////////////////////////////////// - + /** + * Marks all items as selected. + * + * @param items collection of items to be selected + */ public void select(final Collection items) { boolean changes = false; final Iterator itemIt = items.iterator(); @@ -150,10 +166,21 @@ } } + /** + * Marks all keys as selected. + * + * @param items map where keys are to be selected + */ public void select(final Map items) { select(items.keySet()); } + /** + * Select the passed node if not already selected. + * + * @param node node to be selected + * @return true if node was not already selected + */ private boolean internalSelect(final PNode node) { if (isSelected(node)) { return false; @@ -164,20 +191,38 @@ return true; } + /** + * Dispatches a selection changed notification to the PNodificationCenter. + */ private void postSelectionChanged() { PNotificationCenter.defaultCenter().postNotification(SELECTION_CHANGED_NOTIFICATION, this); } + /** + * Selected the provided node if not already selected. + * + * @param node node to be selected + */ public void select(final PNode node) { if (internalSelect(node)) { postSelectionChanged(); } } + /** + * Adds bound handles to the provided node. + * + * @param node node to be decorated + */ public void decorateSelectedNode(final PNode node) { PBoundsHandle.addBoundsHandlesTo(node); } + /** + * Removes all nodes provided from the selection. + * + * @param items items to remove form the selection + */ public void unselect(final Collection items) { boolean changes = false; final Iterator itemIt = items.iterator(); @@ -190,6 +235,13 @@ } } + /** + * Removes provided selection node if not already selected. + * + * @param node node to remove from selection + * + * @return true on success + */ private boolean internalUnselect(final PNode node) { if (!isSelected(node)) { return false; @@ -200,16 +252,29 @@ return true; } + /** + * Removes node from selection. + * + * @param node node to be removed from selection + */ public void unselect(final PNode node) { if (internalUnselect(node)) { postSelectionChanged(); } } + /** + * Removes bounds handles from node. + * + * @param node to have handles removed from + */ public void undecorateSelectedNode(final PNode node) { PBoundsHandle.removeBoundsHandlesFrom(node); } + /** + * Empties the selection. + */ public void unselectAll() { // Because unselect() removes from selection, we need to // take a copy of it first so it isn't changed while we're iterating @@ -217,6 +282,12 @@ unselect(sel); } + /** + * Returns true is provided node is selected. + * + * @param node - node to be tested + * @return true if succeeded + */ public boolean isSelected(final PNode node) { if (node != null && selection.containsKey(node)) { return true; @@ -228,6 +299,8 @@ /** * Returns a copy of the currently selected nodes. + * + * @return copy of selection */ public Collection getSelection() { final ArrayList sel = new ArrayList(selection.keySet()); @@ -237,14 +310,19 @@ /** * Gets a reference to the currently selected nodes. You should not modify * or store this collection. + * + * @return direct reference to selection */ public Collection getSelectionReference() { return Collections.unmodifiableCollection(selection.keySet()); } /** - * Determine if the specified node is selectable (i.e., if it is a child of - * the one the list of selectable parents. + * Determine if the specified node can be selected (i.e., if it is a child + * of the one the list of nodes that can be selected). + * + * @param node node being tested + * @return true if node can be selected */ protected boolean isSelectable(final PNode node) { boolean selectable = false; @@ -270,28 +348,52 @@ return selectable; } - // //////////////////////////////////////////////////// - // Methods for modifying the set of selectable parents - // //////////////////////////////////////////////////// - + /** + * Flags the node provided as a selectable parent. This makes it possible to + * select its children. + * + * @param node to flag as selectable + */ public void addSelectableParent(final PNode node) { selectableParents.add(node); } + /** + * Removes the node provided from the set of selectable parents. This makes + * its impossible to select its children. + * + * @param node to remove from selectable parents + */ public void removeSelectableParent(final PNode node) { selectableParents.remove(node); } + /** + * Sets the node provided as the *only* selectable parent. + * + * @param node node to become the 1 and only selectable parent + */ public void setSelectableParent(final PNode node) { selectableParents.clear(); selectableParents.add(node); } + /** + * Sets the collection of selectable parents as the only parents that are + * selectable. + * + * @param c nodes to become selectable parents. + */ public void setSelectableParents(final Collection c) { selectableParents.clear(); selectableParents.addAll(c); } + /** + * Returns all selectable parents. + * + * @return selectable parents + */ public Collection getSelectableParents() { return new ArrayList(selectableParents); } @@ -300,7 +402,7 @@ // The overridden methods from PDragSequenceEventHandler // ////////////////////////////////////////////////////// - protected void startDrag(final PInputEvent e) { + protected void startDrag(final PInputEvent e) { super.startDrag(e); initializeSelection(e); @@ -358,14 +460,31 @@ // Additional methods // ////////////////////////// + /** + * Used to test whether the event is one that changes the selection. + * + * @param pie The event under test + * @return true if event changes the selection + */ public boolean isOptionSelection(final PInputEvent pie) { return pie.isShiftDown(); } + /** + * Tests the input event to see if it is selecting a new node. + * + * @param pie event under test + * @return true if there is no current selection + */ protected boolean isMarqueeSelection(final PInputEvent pie) { return pressNode == null; } + /** + * Starts a selection based on the provided event. + * + * @param pie event used to populate the selection + */ protected void initializeSelection(final PInputEvent pie) { canvasPressPt = pie.getCanvasPosition(); presspt = pie.getPosition(); diff --git a/extras/src/main/java/edu/umd/cs/piccolox/nodes/PStyledText.java b/extras/src/main/java/edu/umd/cs/piccolox/nodes/PStyledText.java index 007dd13..a76e39e 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/nodes/PStyledText.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/nodes/PStyledText.java @@ -62,24 +62,34 @@ */ public class PStyledText extends PNode { - /** - * - */ private static final long serialVersionUID = 1L; + protected static FontRenderContext SWING_FRC = new FontRenderContext(null, true, false); + + /** Used while painting underlines. */ protected static Line2D paintLine = new Line2D.Double(); + /** + * Underlying document used to handle the complexities involved with + * arbitrary text and formatting. + */ protected Document document; + + /** String contents of the document. */ protected transient ArrayList stringContents; + + /** Tracks the information about line metrics within the document. */ protected transient LineInfo[] lines; + /** Whether this node is currently being edited. */ protected boolean editing; + protected Insets insets = new Insets(0, 0, 0, 0); protected boolean constrainHeightToTextHeight = true; protected boolean constrainWidthToTextWidth = true; /** - * Constructor for PStyledText. + * Constructs an empty PStyledText element. */ public PStyledText() { super(); @@ -136,6 +146,9 @@ syncWithDocument(); } + /** + * Ensures that the current display matches the styling of the underlying document as closely as possible. + */ public void syncWithDocument() { // First get the actual text and stick it in an Attributed String stringContents = new ArrayList(); @@ -233,6 +246,14 @@ recomputeLayout(); } + /** + * Returns the first leaf encountered by drilling into the document for the given position. + * + * @param pos position under which we're trying to find a leaf + * @param rootElement top most element in the document tree + * + * @return Leaf element that corresponds to the position provided in the document + */ private Element drillDownFromRoot(final int pos, final Element rootElement) { Element curElement; // Before each pass, start at the root @@ -300,7 +321,7 @@ if (font == null) { font = style.getFont(rootElement.getAttributes()); } - } + } } else { font = style.getFont(rootElement.getAttributes()); @@ -505,16 +526,7 @@ // Small assumption here that there is one root element - can fix // for more general support later final Element rootElement = document.getDefaultRootElement(); - - // The current element will be used as a temp variable while searching - // for the leaf element at the current position - Element curElement = rootElement; - - // Now we descend the hierarchy until we get to a leaf - while (!curElement.isLeaf()) { - curElement = curElement.getElement(curElement.getElementIndex(0)); - } - + final Element curElement = drillDownFromRoot(0, rootElement); final StyleContext context = StyleContext.getDefaultStyleContext(); final Font font = context.getFont(curElement.getAttributes()); @@ -590,21 +602,27 @@ } /** - * Set whether this text is editing + * Set whether this text is editing. + * + * @param editing value to set editing flag */ public void setEditing(final boolean editing) { this.editing = editing; } /** - * Is this document editing + * Whether node is currently in editing state. + * + * @return true if node is currently editing */ public boolean isEditing() { return editing; } /** - * Set the insets of the text + * Set the insets of the text. + * + * @param insets desired insets */ public void setInsets(final Insets insets) { if (insets != null) { @@ -618,17 +636,19 @@ } /** - * Get the insets of the text + * Get the insets of the text. + * + * @return current text insets */ public Insets getInsets() { return (Insets) insets.clone(); } /** - * Add a call to recompute the layout after each bounds change + * Add a call to recompute the layout after each bounds change. */ - public boolean setBounds(final double x, final double y, final double w, final double h) { - if (document == null || !super.setBounds(x, y, w, h)) { + public boolean setBounds(final double x, final double y, final double width, final double height) { + if (document == null || !super.setBounds(x, y, width, height)) { return false; } @@ -637,7 +657,7 @@ } /** - * Simple class to represent an range within the document + * Simple class to represent an range within the document. */ protected static class RunInfo { public int startIndex; @@ -661,7 +681,7 @@ } /** - * Class to represent an integer run and the font in that run + * Class to represent an integer run and the font in that run. */ protected static class MetricsRunInfo extends RunInfo { public FontMetrics metrics; @@ -672,7 +692,7 @@ } /** - * The info for rendering a and computing the bounds of a line + * The info for rendering and computing the bounds of a line. */ protected static class LineInfo { public List segments; @@ -684,7 +704,7 @@ segments = new ArrayList(); } } - + protected static class SegmentInfo { public TextLayout layout; public Font font;