com.googlecode.blaisemath.graphics.core.Graphic Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of blaise-graphics Show documentation
Show all versions of blaise-graphics Show documentation
Scene graph and style library using Java2D graphics.
/**
* Graphic.java
* Created Jan 22, 2011
*/
package com.googlecode.blaisemath.graphics.core;
/*
* #%L
* BlaiseGraphics
* --
* Copyright (C) 2009 - 2019 Elisha Peterson
* --
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.collect.Lists;
import com.googlecode.blaisemath.style.AttributeSet;
import com.googlecode.blaisemath.style.StyleHints;
import com.googlecode.blaisemath.util.swing.ContextMenuInitializer;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import javax.annotation.Nullable;
import javax.swing.JPopupMenu;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.EventListenerList;
/**
*
* An object along with style and renderer information allowing it to be drawn
* on a graphics canvas.
*
*
* Key additional features are:
*
*
* - A parent (via get and set methods), which is a
* {@link GraphicComposite} and provides access to default styles of various
* types.
* - Visibility settings (via get and set methods). See {@link StyleHints}
* for the parameters.
* - Three methods based on a point on the canvas:
*
* - {@link #boundingBox()}, providing a box that encloses the graphic
* - {@link #contains(java.awt.geom.Point2D)}, testing whether the entry
* contains a point
* - {@link #getTooltip(java.awt.geom.Point2D)}, returning the tooltip for a
* point (or null)
*
*
*
*
* Implementations must provide the object to be rendered, as well as the
* render functionality, and they must implement their own drag functionality.
*
*
* @param type of graphics canvas to render to
*
* @author Elisha
*/
public abstract class Graphic implements ContextMenuInitializer> {
public static final String SELECTION_ENABLED = "selection-enabled";
public static final String TOOLTIP_ENABLED = "tooltip-enabled";
public static final String MOUSE_ENABLED = "mouse-enabled";
public static final String POPUP_ENABLED = "popupmenu-enabled";
/** Stores the parent of this entry */
protected GraphicComposite parent;
/** Modifiers that are applied to the style before drawing. */
protected AttributeSet styleHints = new AttributeSet();
/** Default text of tooltip */
protected String defaultTooltip = null;
/** Context initializers */
protected final List>> contextMenuInitializers = Lists.newArrayList();
/** Adds highlights to the graphic on mouseover. */
protected final HighlightOnMouseoverHandler highlighter = new HighlightOnMouseoverHandler();
/** Handles property listening */
protected final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
/** Stores event eventHandlers for the entry */
protected final EventListenerList eventHandlers = new EventListenerList();
/**
* Initialize graphic
*/
public Graphic() {
addMouseListener(highlighter);
styleHints.addChangeListener(new ChangeListener(){
@Override
public void stateChanged(ChangeEvent ce) {
fireGraphicChanged();
}
});
}
//
//
// COMPOSITION
//
/**
* Return parent of the entry
* @return parent, possibly null
*/
@Nullable
public GraphicComposite getParent() {
return parent;
}
/**
* Set parent of the entry
* @param p the new parent, possibly null
*/
@Nullable
public void setParent(@Nullable GraphicComposite p) {
this.parent = p;
}
/** Notify interested listeners of a change in the plottable. */
protected void fireGraphicChanged() {
if (parent != null) {
parent.graphicChanged(this);
}
}
//
//
//
// STYLE & RENDERING
//
/**
* Return style attributes of the graphic to be used for rendering.
* The result will have all style hints automatically applied. Any attributes
* of the parent style are inherited.
*
* @return style
*/
public final AttributeSet renderStyle() {
AttributeSet renderStyle = getStyle();
if (renderStyle == null) {
renderStyle = new AttributeSet();
}
AttributeSet renderHints = getStyleHints();
if (parent != null) {
AttributeSet parStyle = parent.getStyle();
if (parStyle != null && parStyle != renderStyle.getParent()) {
renderStyle = renderStyle.flatCopy().immutableWithParent(parStyle);
}
AttributeSet parStyleHints = parent.getStyleHints();
if (parStyleHints != null && renderHints.getParent() != parStyleHints) {
renderHints = renderHints.flatCopy().immutableWithParent(parStyleHints);
}
renderStyle = parent.getStyleContext().applyModifiers(renderStyle, renderHints);
}
return renderStyle;
}
/**
* Return style set of this graphic
* @return graphic style
*/
public abstract AttributeSet getStyle();
/**
* Return set of style hints for the graphic.
* @return style hints
*/
public AttributeSet getStyleHints() {
return styleHints;
}
/**
* Sets style hints of graphic
* @param hints new style hints
*/
public void setStyleHints(AttributeSet hints) {
this.styleHints = hints;
fireGraphicChanged();
}
/**
* Set status of a particular visibility hint.
* @param hint hint
* @param status status of hint
*/
public void setStyleHint(String hint, boolean status) {
styleHints.put(hint, status);
}
/**
* Draws the primitive on the specified graphics canvas, using current
* style.
* @param canvas graphics canvas
*/
public abstract void renderTo(G canvas);
//
//
//
// LOCATOR API
//
/**
* Method that provides the bounding box enclosing the graphic.
* @return bounding box
*/
public abstract Rectangle2D boundingBox();
/**
* Method used to determine whether the graphic receives mouse events
* and will be asked to provide a tooltip at the given point. The graphic's
* {@link MouseListener}s and {@link MouseMotionListener}s will have the
* opportunity to receive events if the graphic is the topmost element
* containing the event's point.
*
* @param point the window point
* @return true if the entry contains the point, else false
*/
public abstract boolean contains(Point2D point);
/**
* Checks to see if the graphic intersects the area within specified
* rectangle.
*
* @param box rectangle to check against
* @return true if it intersects, false otherwise
*/
public abstract boolean intersects(Rectangle2D box);
//
//
//
// CONTEXT MENU
//
/**
* Whether graphic supports context menu building
* @return true if yes
*/
public boolean isContextMenuEnabled() {
return styleHints.getBoolean(POPUP_ENABLED, false);
}
public void setContextMenuEnabled(boolean val) {
styleHints.put(POPUP_ENABLED, val);
}
public void clearContextMenuInitializers() {
contextMenuInitializers.clear();
setContextMenuEnabled(false);
}
public void addContextMenuInitializer(ContextMenuInitializer> init) {
if (!contextMenuInitializers.contains(init)) {
contextMenuInitializers.add(init);
setContextMenuEnabled(true);
}
}
public void removeContextMenuInitializer(ContextMenuInitializer> init) {
contextMenuInitializers.remove(init);
if (contextMenuInitializers.isEmpty()) {
setContextMenuEnabled(false);
}
}
@Override
public void initContextMenu(JPopupMenu menu, Graphic src, Point2D point, Object focus, Set selection) {
for (ContextMenuInitializer> cmi : contextMenuInitializers) {
cmi.initContextMenu(menu, src, point, focus, selection);
}
}
//
//
//
// SELECTION
//
/**
* Return true if graphic can be selected. If this flag is set to true, the
* locator API will be used to map selection gestures (e.g. click to select,
* or select graphics in box).
* @return selection flag
*/
public boolean isSelectionEnabled() {
return styleHints.getBoolean(SELECTION_ENABLED, false);
}
public void setSelectionEnabled(boolean val) {
styleHints.put(SELECTION_ENABLED, val);
}
public boolean isHighlightEnabled() {
return Arrays.asList(eventHandlers.getListenerList()).contains(highlighter);
}
public void setHighlightEnabled(boolean val) {
if (val != isHighlightEnabled()) {
if (val) {
addMouseListener(highlighter);
} else {
removeMouseListener(highlighter);
}
}
}
//
//
//
// TOOLTIP API
//
/**
* Return true if tips are enabled/supported
* @return true if yes
*/
public boolean isTooltipEnabled() {
return styleHints.getBoolean(TOOLTIP_ENABLED, true);
}
public final void setTooltipEnabled(boolean val) {
styleHints.put(TOOLTIP_ENABLED, val);
}
/**
* Return tooltip for the specified point
* @param p the point
* @return the tooltip at the specified location (may be null)
*/
public String getTooltip(Point2D p) {
return isTooltipEnabled() ? defaultTooltip : null;
}
/**
* Return the default tooltip for this object
* @return tip
*/
public String getDefaultTooltip() {
return defaultTooltip;
}
/**
* Sets the tooltip for this entry. Also updates the enabled tip flag to true.
* @param tooltip the tooltip
*/
public final void setDefaultTooltip(String tooltip) {
setTooltipEnabled(true);
this.defaultTooltip = tooltip;
}
//
//
//
// PROPERTY CHANGE LISTENING
//
public void addPropertyChangeListener(PropertyChangeListener pl) {
pcs.addPropertyChangeListener(pl);
}
public void addPropertyChangeListener(String string, PropertyChangeListener pl) {
pcs.addPropertyChangeListener(string, pl);
}
public void removePropertyChangeListener(PropertyChangeListener pl) {
pcs.removePropertyChangeListener(pl);
}
public void removePropertyChangeListener(String string, PropertyChangeListener pl) {
pcs.removePropertyChangeListener(string, pl);
}
//
//
//
// MOUSE HANDLING
//
/**
* Whether the object should receive mouse events.
* @return true if yes, false otherwise
*/
public boolean isMouseEnabled() {
return styleHints.getBoolean(MOUSE_ENABLED, true);
}
public void setMouseEnabled(boolean val) {
styleHints.put(MOUSE_ENABLED, val);
}
public void removeMouseListeners() {
for (MouseListener m : getMouseListeners()) {
eventHandlers.remove(MouseListener.class, m);
}
}
public void removeMouseMotionListeners() {
for (MouseMotionListener m : getMouseMotionListeners()) {
eventHandlers.remove(MouseMotionListener.class, m);
}
}
/**
* Adds a mouse listener to the graphic
* @param handler listener
*/
public final void addMouseListener(MouseListener handler) {
checkNotNull(handler);
eventHandlers.add(MouseListener.class, handler);
}
/**
* Removes a mouse listener from the graphic
* @param handler listener
*/
public void removeMouseListener(MouseListener handler) {
eventHandlers.remove(MouseListener.class, handler);
}
/**
* Return list of mouse listeners registered with the graphic
* @return listeners
*/
public MouseListener[] getMouseListeners() {
return eventHandlers.getListeners(MouseListener.class);
}
/**
* Adds a mouse motion listener to the graphic
* @param handler listener
*/
public void addMouseMotionListener(MouseMotionListener handler) {
checkNotNull(handler);
eventHandlers.add(MouseMotionListener.class, handler);
}
/**
* Removes a mouse motion listener from the graphic
* @param handler listener
*/
public void removeMouseMotionListener(MouseMotionListener handler) {
eventHandlers.remove(MouseMotionListener.class, handler);
}
/**
* Return list of mouse motion listeners registered with the graphic
* @return listeners
*/
public MouseMotionListener[] getMouseMotionListeners() {
return eventHandlers.getListeners(MouseMotionListener.class);
}
//
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy