Created
November 13, 2018 22:08
-
-
Save mcwhitaker/2db1158627e8bbe981dd765ccccb1478 to your computer and use it in GitHub Desktop.
variations bubble properties
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Copyright 2001-2011, Trustees of Indiana University | |
* All rights reserved. | |
* | |
* Redistribution and use in source and binary forms, with or without | |
* modification, are permitted provided that the following conditions are met: | |
* | |
* Redistributions of source code must retain the above copyright notice, | |
* this list of conditions and the following disclaimer. | |
* | |
* Redistributions in binary form must reproduce the above copyright notice, | |
* this list of conditions and the following disclaimer in the documentation | |
* and/or other materials provided with the distribution. | |
* | |
* Neither the name of Indiana University nor the names of its | |
* contributors may be used to endorse or promote products derived from this | |
* software without specific prior written permission. | |
* | |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | |
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
* POSSIBILITY OF SUCH DAMAGE. | |
* | |
* $Id: Bubble.java 822 2011-04-04 13:46:18Z cjcolvar $ | |
*/ | |
package edu.indiana.dml.ui.timeliner; | |
import javax.swing.*; | |
import java.awt.*; | |
import java.awt.geom.*; | |
/** | |
* Bubble class | |
* This class represents a bubble object. A bubble can be drawn, selected, and | |
* have its color changed. Bubbles are created in connection with a timeline object. | |
* Bubbles may be drawn in various ways: rounded or square or drawn in outline form. | |
* | |
* @author Brent Yorgason | |
*/ | |
public class Bubble extends JComponent { | |
// private variables | |
private Color color = new Color(166, 202, 240); // default color is light blue | |
private Color bwColor = new Color (255, 255, 255); // white | |
private Color shadeColor; | |
private Graphics g; | |
private Graphics2D g2d; | |
private int arcTop; | |
private int arcHeight; | |
private int squareTop; | |
private int squareHeight; | |
private int selectStrokeWidth = 2; | |
private Arc2D.Double arc; | |
private Rectangle2D.Double square; | |
private Point labelPoint; | |
private int labelFontSize; | |
protected int basicFontSize = 12; | |
private String unicodeFont = "Arial Unicode MS"; | |
private boolean selected; | |
private boolean blackAndWhite; | |
protected String duration = ""; | |
// protected variables | |
protected int start; | |
protected int end; | |
protected int base; | |
protected int width; | |
protected int height; | |
protected int top; | |
protected int type; | |
protected int level = 1; | |
protected String label = ""; | |
protected String annotation = ""; | |
protected boolean levelWasUserAdjusted = false; | |
protected boolean hasCustomColor = false; | |
/** | |
* default constructor | |
*/ | |
public Bubble() { | |
selected = false; | |
blackAndWhite = false; | |
} | |
/** | |
* alternate constructor that accepts a bubble as a parameter in order to copy its properties | |
*/ | |
public Bubble(Bubble bubble) { | |
color = bubble.getColor(); | |
height = bubble.getHeight(); | |
type = bubble.getType(); | |
selected = false; | |
blackAndWhite = false; | |
} | |
/** | |
* getBubble: returns a copy of the bubble object | |
*/ | |
public Bubble getBubble() { | |
return this; | |
} | |
/** | |
* contains: returns true if the bubble contains the given point | |
*/ | |
public boolean contains(Point p) { | |
if (type == 0) { // round bubbles | |
if (arc != null && arc.contains((Point2D)p)) { | |
return true; | |
} | |
} | |
else if (type == 1) { // square bubbles | |
if (square != null && square.contains((Point2D)p)) { | |
return true; | |
} | |
} | |
return false; | |
} | |
/** | |
* intersects: returns true if the bubble intersects with the given rect | |
*/ | |
protected boolean intersects(Rectangle rect) { | |
double x = rect.getX(); | |
double y = rect.getY(); | |
double w = rect.getWidth(); | |
double h = rect.getHeight(); | |
if (type == 0) { // round bubbles | |
if (arc.intersects(x, y, w, h)) { | |
return true; | |
} | |
else if (x < arc.x && y < arcTop && (x + w) > (arc.x + arc.width) && (y + h) > base) { // arc is within rect | |
return true; | |
} | |
} | |
else if (type == 1) { // square bubbles | |
if (square.intersects(x, y, w, h)) { | |
return true; | |
} | |
} | |
return false; | |
} | |
/** | |
* drawBubble: given the graphics, bubble start point, base, end point, and height, | |
* draws a bubble on the timeline | |
*/ | |
protected void drawBubble(Graphics2D graphics, int bubStart, int bubBase, int bubEnd, int bubHeight, int bubType, boolean bw) { | |
// load passed parameters | |
start = bubStart; | |
base = bubBase; | |
end = bubEnd; | |
width = bubEnd - bubStart; | |
if (bubType == 0) { // formula for setting the height of round bubbles--dependent on user settings and level | |
height = (int)((double)bubHeight + ((level - 1) * (double)(bubHeight * .7))); | |
} | |
else if (bubType == 1) { // formula for setting the height of square bubbles | |
height = bubHeight + ((level - 1) * bubHeight); | |
} | |
top = base - height; | |
g2d = graphics; | |
g2d.setColor(color); | |
arcHeight = height * 2; | |
arcTop = base - height; | |
type = bubType; | |
blackAndWhite = bw; | |
int sideAdjust = 2; // tweak value | |
// set up the bubble label font size, using a formula dependent on the bubble height | |
labelFontSize = basicFontSize - ((30 - bubHeight) / 4); | |
// impose a limit of font size 14 in level 1 and 18 in level 2 | |
if (level == 1 && labelFontSize > 14) { | |
labelFontSize = 14; | |
} | |
else if (level == 2 && labelFontSize > 18) { | |
labelFontSize = 18; | |
} | |
// set up label font and calculate label size and position | |
Font labelFont = new Font(unicodeFont, 0, labelFontSize); | |
g2d.setFont(labelFont); | |
FontMetrics labelMetrics = g2d.getFontMetrics(); | |
int labelWidth = labelMetrics.stringWidth(label); | |
int labelHeight = labelMetrics.getHeight(); | |
int durationWidth = labelMetrics.stringWidth(duration); | |
int labelX = start + (width / 2) - (labelWidth / 2); | |
int labelY = base - height + labelHeight + (bubHeight / 10); | |
int durationX = start + (width / 2) - (durationWidth / 2); | |
// create shapes | |
arc = new Arc2D.Double(start + 1, top, width - 2, arcHeight, 0, 180, 1); | |
square = new Rectangle2D.Double(start + sideAdjust, top, width - (sideAdjust * 2), height); | |
// set up shading color | |
if (selected) { | |
if (!blackAndWhite) { | |
if (color.getRed() + color.getGreen() + color.getBlue() > 250) { // darken | |
shadeColor = color.darker(); | |
} | |
else { | |
shadeColor = color.brighter(); | |
} | |
} | |
else { | |
shadeColor = Color.lightGray; | |
} | |
} | |
// now draw the bubble | |
if (type == 0) { // round bubbles | |
if (selected) { // this bubble is currently selected | |
// shade the bubble | |
g2d.setColor(shadeColor); | |
g2d.fill(arc); | |
// draw the outline selection indicator | |
g2d.setColor(Color.black); | |
g2d.setStroke(new BasicStroke(selectStrokeWidth)); | |
if (level==1) { | |
g2d.drawArc(start, top, width - 1, arcHeight, 0, 180); | |
} | |
else { | |
g2d.drawArc(start, top, width, arcHeight, 0, 180); | |
} | |
g2d.setStroke(new BasicStroke(1)); | |
} | |
else { // the bubble is not selected | |
if (blackAndWhite) { // just draw an outline | |
g2d.setColor(Color.black); | |
g2d.setStroke(new BasicStroke(1)); | |
g2d.drawArc(start, top - 1, width, arcHeight + 1, 0, 180); | |
g2d.setColor(bwColor); | |
g2d.fill(arc); | |
} | |
else { | |
g2d.setColor(color); | |
g2d.fill(arc); | |
} | |
} | |
} | |
else if (type == 1) { // square bubbles | |
if (selected) { // this bubble is currently selected | |
// shade the bubble | |
g2d.setColor(shadeColor); | |
g2d.fill(square); | |
// draw the outline selection indicator | |
g2d.setColor(Color.black); | |
g2d.setStroke(new BasicStroke(selectStrokeWidth)); | |
g2d.drawRect(start + sideAdjust - 2, top + 1, width - (sideAdjust * 2) + 3, height); | |
g2d.setStroke(new BasicStroke(1)); | |
} | |
else { // the bubble is not selected | |
if (blackAndWhite) { // just draw an outline | |
g2d.setColor(Color.black); | |
g2d.setStroke(new BasicStroke(1)); | |
g2d.drawRect(start + sideAdjust - 1, top - 1, width - (sideAdjust * 2) + 1, height + 1); | |
g2d.setColor(bwColor); | |
g2d.fill(square); | |
} | |
else { | |
g2d.setColor(color); | |
g2d.fill(square); | |
} | |
} | |
} | |
// draw the label | |
g2d.setColor(Color.black); | |
if (this.contains(new Point(labelX - 1, labelY - 1)) && labelY > 0 && labelX > 0 && label.length() > 0) { | |
if (duration != "") { | |
g2d.drawString(label, labelX, labelY); | |
g2d.drawString(duration, durationX, labelY + 14); | |
} | |
g2d.drawString(label, labelX, labelY); | |
} | |
else if (duration == "") { // shorten the label if not all of it will fit in the displayed bubble | |
for (int displayLength = label.length() - 1; displayLength > 0; displayLength--) { | |
String displayLabel = label.substring(0, displayLength); | |
labelWidth = labelMetrics.stringWidth(displayLabel); | |
labelX = start + (width / 2) - (labelWidth / 2); | |
labelY = base - height + labelHeight + (bubHeight / 10); | |
if (this.contains(new Point(labelX - 1, labelY - 1)) && labelY > 0 && labelX > 0 && displayLabel.length() > 0) { | |
g2d.drawString(displayLabel, labelX, labelY); | |
break; | |
} | |
} | |
} | |
} | |
/** | |
* select: marks the bubble as selected | |
*/ | |
protected void select() { | |
selected = true; | |
} | |
/** | |
* deselect: marks the bubble as not selected | |
*/ | |
protected void deselect() { | |
selected = false; | |
} | |
/** | |
* isSelected: returns true if the bubble is selected | |
*/ | |
public boolean isSelected() { | |
return selected; | |
} | |
/** | |
* toString: returns a little information about the bubble | |
*/ | |
public String toString() { | |
if (start > 0) { | |
return (new String("bubble start = " + (start - 50)) + " level = " + level); | |
} | |
else { | |
return (new String("root bubble, level = " + level)); | |
} | |
} | |
/** | |
* getAnnotation: returns the bubble annotation | |
*/ | |
public String getAnnotation() { | |
return annotation; | |
} | |
/** | |
* getArc: returns the arc object | |
*/ | |
protected Arc2D getArc() { | |
return arc; | |
} | |
/** | |
* getBlackAndWhite: returns whether bubble is black and white | |
*/ | |
public boolean getBlackAndWhite() { | |
return blackAndWhite; | |
} | |
/** | |
* getColor: returns bubble color | |
*/ | |
public Color getColor() { | |
return color; | |
} | |
/** | |
* getEnd: returns bubble's end point (pixels) | |
*/ | |
public int getEnd() { | |
return end; | |
} | |
/** | |
* getFontSize: gets the font size for the bubble label | |
*/ | |
protected int getFontSize() { | |
return labelFontSize; | |
} | |
/** | |
* getHeight: returns bubble height in pixels | |
*/ | |
public int getHeight() { | |
return height; | |
} | |
/** | |
* getLabel: returns bubble label | |
*/ | |
public String getLabel() { | |
return label; | |
} | |
/** | |
* getLevel: returns level of bubble | |
*/ | |
public int getLevel() { | |
return level; | |
} | |
/** | |
* getStart: returns bubble start point (in pixels) | |
*/ | |
public int getStart() { | |
return start; | |
} | |
/** | |
* getType: returns bubble type (round or square) | |
*/ | |
public int getType() { | |
return type; | |
} | |
/** | |
* setAnnotation: sets the annotation for the bubble | |
*/ | |
protected void setAnnotation(String annot) { | |
annotation = annot; | |
} | |
/** | |
* setColor: sets bubble color | |
*/ | |
public void setColor(Color c) { | |
color = c; | |
} | |
/** | |
* setEnd: sets bubble end point (in pixels) | |
*/ | |
protected void setEnd(int e) { | |
end = e; | |
} | |
/** | |
* setLabel: sets bubble label | |
*/ | |
protected void setLabel(String labelText) { | |
label = labelText; | |
} | |
/** | |
* setLevel: sets bubble level | |
*/ | |
protected void setLevel(int lev) { | |
level = lev; | |
} | |
/** | |
* setStart: sets bubble start point (in pixels) | |
*/ | |
protected void setStart(int s) { | |
start = s; | |
} | |
/** | |
* toElement: creates and returns an XML element representing the bubble | |
*/ | |
public org.w3c.dom.Element toElement(org.w3c.dom.Document doc, Timeline timeline) throws Exception{ | |
// bubble element | |
org.w3c.dom.Element bubbleElement = doc.createElement("Bubble"); | |
// color attribute | |
// if (hasCustomColor) { // all colors now saved, not just custom ones, in order to maintain compatibility with version 2.0 | |
bubbleElement.setAttribute("color", String.valueOf(color.getRed()) + "," | |
+ String.valueOf(color.getGreen()) + "," | |
+ String.valueOf(color.getBlue())); | |
// } | |
// level attribute | |
bubbleElement.setAttribute("level", String.valueOf(this.level)); | |
// label attribute | |
if (label.length() > 0) { | |
bubbleElement.setAttribute("label", label); | |
} | |
// time attribute | |
if (start == 0) { | |
bubbleElement.setAttribute("time", "0:00.0"); | |
} | |
else { | |
int tpoint = timeline.getTimepointAt(new Point(start, base)); | |
String time = timeline.getTimepoint(tpoint).getTime(); | |
if (time == "0") { | |
time = "0:00.0"; | |
} | |
bubbleElement.setAttribute("time", time); | |
} | |
// levelSetByUser element | |
if (this.levelWasUserAdjusted) { | |
bubbleElement.setAttribute("levelSetByUser", "true"); | |
} | |
// annotation element | |
if (annotation.length() > 0) { | |
org.w3c.dom.Element annotationElement = doc.createElement("Annotation"); | |
annotationElement.appendChild(doc.createTextNode(annotation)); | |
bubbleElement.appendChild(annotationElement); | |
} | |
return bubbleElement; | |
} | |
/** | |
* toElementHTML: creates and returns an XML element representing the bubble in HTML display format | |
*/ | |
public org.w3c.dom.Element toElementHTML(org.w3c.dom.Document doc, Timeline timeline, int bubbleNum) throws Exception{ | |
// bubble element | |
org.w3c.dom.Element bubbleElement = doc.createElement("Bubble"); | |
Timepoint t = null; | |
// label attribute | |
if (label.length() > 0) { | |
bubbleElement.setAttribute("label", label); | |
} | |
// time attribute | |
int tpoint = timeline.getTimepointAt(new Point(start, base)); | |
t = timeline.getTimepoint(tpoint); | |
if (start == 0) { | |
bubbleElement.setAttribute("time", null); | |
bubbleElement.setAttribute("timelabel", null); | |
} | |
else { | |
String time = t.getTime(); | |
if (time == "0") { | |
time = "0:00.0"; | |
} | |
bubbleElement.setAttribute("time", time); | |
bubbleElement.setAttribute("timelabel", t.getLabel()); | |
} | |
// annotation element | |
if (annotation.length() > 0) { | |
org.w3c.dom.Element annotationElement = doc.createElement("Annotation"); | |
annotationElement.appendChild(doc.createTextNode(annotation)); | |
bubbleElement.appendChild(annotationElement); | |
} | |
// now add any markers contained in the bubble, if it is a base bubble | |
if ((timeline.getBubbleNode(bubbleNum).isLeaf())) { | |
int beginOffset = timeline.getSortedPointList()[tpoint]; | |
int endOffset = timeline.getSortedPointList()[tpoint+1]; | |
for (int i = 0; i < timeline.getNumMarkers(); i++) { | |
int markOffset = timeline.getMarkerList()[i]; | |
if (markOffset >= beginOffset && markOffset <= endOffset) { | |
Marker m = timeline.getMarker(i); | |
org.w3c.dom.Element markerAnnotationElement = doc.createElement("MarkerAnnotation"); | |
markerAnnotationElement.setAttribute("label", m.getLabel()); | |
markerAnnotationElement.setAttribute("time", m.getTime()); | |
if (m.getAnnotation().length() > 0) { | |
org.w3c.dom.Element annElement = doc.createElement("Ann"); | |
annElement.appendChild(doc.createTextNode(m.getAnnotation())); | |
markerAnnotationElement.appendChild(annElement); | |
} | |
bubbleElement.appendChild(markerAnnotationElement); | |
} | |
} | |
} | |
return bubbleElement; | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment