001: /* uDig - User Friendly Desktop Internet GIS client
002: * http://udig.refractions.net
003: * (C) 2004, Refractions Research Inc.
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation;
008: * version 2.1 of the License.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: */
015: package net.refractions.udig.tools.edit.animation;
016:
017: import java.awt.Color;
018: import java.awt.Rectangle;
019: import java.awt.geom.Rectangle2D;
020:
021: import net.refractions.udig.project.render.displayAdapter.IMapDisplay;
022: import net.refractions.udig.project.ui.IAnimation;
023: import net.refractions.udig.project.ui.commands.AbstractDrawCommand;
024: import net.refractions.udig.project.ui.render.displayAdapter.MapMouseEvent;
025: import net.refractions.udig.project.ui.render.displayAdapter.MapMouseListener;
026: import net.refractions.udig.project.ui.render.displayAdapter.MapMouseMotionListener;
027: import net.refractions.udig.project.ui.render.displayAdapter.MapMouseWheelEvent;
028: import net.refractions.udig.project.ui.render.displayAdapter.MapMouseWheelListener;
029: import net.refractions.udig.project.ui.render.displayAdapter.ViewportPane;
030: import net.refractions.udig.ui.graphics.ViewportGraphics;
031:
032: import org.eclipse.core.runtime.IProgressMonitor;
033:
034: /**
035: * Creates a semi transparent bubble (OSX like) that show a message to the user and disappears after
036: * a few seconds.
037: *
038: * @author Jesse
039: * @since 1.1.0
040: */
041: public class MessageBubble extends AbstractDrawCommand implements
042: IAnimation {
043:
044: private int x;
045: private int y;
046: private String[] message;
047: private short delay;
048: private Rectangle validArea;
049: private int verticalBorder = 5;
050: private int horizontalBorder = 5;
051: private int verticalCornerArc = 15;
052: private int horizontalCornerArc = 15;
053: private Color bubbleColor = new Color(0, 0, 0, 167);
054: private Color textColor = new Color(200, 200, 200, 167);
055:
056: /**
057: *
058: * @param x upperLeft of message
059: * @param y upperLeft of message
060: * @param message message to display
061: * @param delay the length of time to show the message
062: */
063: public MessageBubble(final int x, final int y,
064: final String message, short delay) {
065: this .x = x;
066: this .y = y;
067: processMessage(message);
068: this .delay = delay;
069: }
070:
071: private void processMessage(String message) {
072: this .message = message.split("[\n\r]"); //$NON-NLS-1$
073: for (String part : this .message) {
074: part.replaceAll("\t", " "); //$NON-NLS-1$//$NON-NLS-2$
075: }
076: }
077:
078: public short getFrameInterval() {
079: return delay;
080: }
081:
082: public boolean hasNext() {
083: return false;
084: }
085:
086: public void nextFrame() {
087: }
088:
089: public void run(IProgressMonitor monitor) throws Exception {
090:
091: display.addMouseListener(mouseListener);
092: display.addMouseWheelListener(wheelListener);
093:
094: Rectangle2D messageBounds = new Rectangle(0, 0);
095:
096: for (String part : message) {
097: Rectangle2D size = graphics.getStringBounds(part);
098: messageBounds = new Rectangle(
099: (int) (Math.max(size.getWidth(), messageBounds
100: .getWidth())),
101: (int) (size.getHeight() + messageBounds.getHeight()));
102: }
103:
104: if (x + messageBounds.getWidth() > display.getWidth()
105: + horizontalBorder) {
106: x = (int) (display.getWidth() - horizontalBorder - messageBounds
107: .getWidth());
108: }
109: if (y + messageBounds.getHeight() > display.getHeight()
110: + verticalBorder) {
111: y = (int) (display.getHeight() - verticalBorder - messageBounds
112: .getHeight());
113: }
114:
115: validArea = new Rectangle(x, y, (int) messageBounds.getWidth()
116: + horizontalBorder, (int) messageBounds.getHeight()
117: + verticalBorder);
118:
119: graphics.setColor(bubbleColor);
120: graphics.fillRoundRect(x, y, (int) messageBounds.getWidth()
121: + horizontalBorder, (int) messageBounds.getHeight()
122: + verticalBorder, horizontalCornerArc,
123: verticalCornerArc);
124:
125: // color for the message
126: graphics.setColor(textColor);
127: int height = graphics.getFontHeight();
128: int i = 0;
129: int verticalOffset = verticalBorder / 2;
130: int horizontalOffset = horizontalBorder / 2;
131: for (String part : message) {
132: graphics.drawString(part, x + horizontalOffset, y
133: + verticalOffset + (height * i),
134: ViewportGraphics.ALIGN_LEFT,
135: ViewportGraphics.ALIGN_BOTTOM);
136: i++;
137: }
138: }
139:
140: public Rectangle getValidArea() {
141: return validArea;
142: }
143:
144: /**
145: * Sets the space between the edge of the bubble and the text. Default = 10 pixels
146: *
147: * @param horizontalBorder border along the x-axis. In pixels.
148: */
149: public void setHorizontalBorder(int horizontalBorder) {
150: this .horizontalBorder = horizontalBorder;
151: }
152:
153: /**
154: * Sets the space between the edge of the bubble and the text. Default = 10 pixels
155: *
156: * @param verticalBorder border along the y-axis. In pixels.
157: */
158: public void setVerticalBorder(int verticalBorder) {
159: this .verticalBorder = verticalBorder;
160: }
161:
162: /**
163: * Sets the horizontal Arc of the bubble corners for the four edges. Default is 15 pixels.
164: *
165: * @param horizontalCornerArc the horizontal Arc of the bubble corners for the four edges in pixels.
166: */
167: public void setHorizontalCornerArc(int horizontalCornerArc) {
168: this .horizontalCornerArc = horizontalCornerArc;
169: }
170:
171: /**
172: * Sets the vertical Arc of the bubble corners for the four edges. Default is 15 pixels.
173: *
174: * @param verticalCornerArc the vertical Arc of the bubble corners for the four edges in pixels.
175: */
176: public void setVerticalCornerArc(int verticalCornerArc) {
177: this .verticalCornerArc = verticalCornerArc;
178: }
179:
180: /**
181: * Returns the color used to draw the Message Bubble
182: *
183: * @return the color used to draw the Message Bubble
184: */
185: public Color getBubbleColor() {
186: return bubbleColor;
187: }
188:
189: /**
190: * Sets the color used to draw the Message Bubble. Default is Color(0,0,0,167);
191: *
192: * @param bubbleColor the new color to use
193: */
194: public void setBubbleColor(Color bubbleColor) {
195: this .bubbleColor = bubbleColor;
196: }
197:
198: /**
199: * Returns the color used to draw the Message
200: *
201: * @return the color used to draw the Message
202: */
203: public Color getTextColor() {
204: return textColor;
205: }
206:
207: /**
208: * Sets the color used to draw the Message. Default is Color(200,200,200,167);
209: *
210: * @param bubbleColor the new color to use
211: */
212: public void setTextColor(Color textColor) {
213: this .textColor = textColor;
214: }
215:
216: @Override
217: public void setValid(boolean valid) {
218: super .setValid(valid);
219: display.removeMouseListener(mouseListener);
220: display.removeMouseWheelListener(wheelListener);
221: }
222:
223: private MapMouseListener mouseListener = new MapMouseListener() {
224:
225: public void mouseDoubleClicked(MapMouseEvent event) {
226: disable((ViewportPane) event.source, this );
227: }
228:
229: public void mouseEntered(MapMouseEvent event) {
230: disable((ViewportPane) event.source, this );
231: }
232:
233: public void mouseExited(MapMouseEvent event) {
234: disable((ViewportPane) event.source, this );
235: }
236:
237: public void mousePressed(MapMouseEvent event) {
238: disable((ViewportPane) event.source, this );
239: }
240:
241: public void mouseReleased(MapMouseEvent event) {
242: disable((ViewportPane) event.source, this );
243: }
244:
245: };
246:
247: private MapMouseWheelListener wheelListener = new MapMouseWheelListener() {
248:
249: public void mouseWheelMoved(MapMouseWheelEvent e) {
250: disable(display, this );
251: }
252:
253: };
254:
255: void disable(ViewportPane pane, Object listener) {
256: if (!isValid(pane)) {
257: if (listener instanceof MapMouseMotionListener)
258: pane
259: .removeMouseMotionListener((MapMouseMotionListener) listener);
260: else if (listener instanceof MapMouseListener) {
261: pane.removeMouseListener((MapMouseListener) listener);
262: } else if (listener instanceof MapMouseWheelListener) {
263: pane
264: .removeMouseWheelListener((MapMouseWheelListener) listener);
265: }
266:
267: return;
268: }
269:
270: setValid(false);
271: Rectangle bounds = getValidArea();
272: if (bounds == null) {
273: pane.repaint();
274: } else {
275: pane.repaint(bounds.x, bounds.y, bounds.width,
276: bounds.height);
277: }
278: }
279:
280: private boolean isValid(IMapDisplay source) {
281: if (!MessageBubble.this .isValid())
282: return false;
283: if (source != display)
284: return false;
285: return true;
286: }
287: }
|