001: package org.zilonis.tool.ui;
002:
003: import java.awt.AlphaComposite;
004: import java.awt.BorderLayout;
005: import java.awt.Color;
006: import java.awt.Composite;
007: import java.awt.Dimension;
008: import java.awt.Font;
009: import java.awt.FontMetrics;
010: import java.awt.Graphics;
011: import java.awt.Graphics2D;
012: import java.awt.GridBagConstraints;
013: import java.awt.GridBagLayout;
014: import java.awt.Insets;
015: import java.awt.Rectangle;
016: import java.awt.RenderingHints;
017: import java.awt.event.ActionEvent;
018: import java.awt.event.ActionListener;
019: import java.awt.event.MouseAdapter;
020: import java.awt.event.MouseEvent;
021: import java.awt.event.MouseListener;
022: import java.awt.event.MouseMotionAdapter;
023: import java.awt.font.FontRenderContext;
024: import java.awt.font.TextLayout;
025: import java.awt.geom.Rectangle2D;
026: import java.awt.image.BufferedImage;
027: import java.io.IOException;
028:
029: import javax.imageio.ImageIO;
030: import javax.swing.BorderFactory;
031: import javax.swing.Box;
032: import javax.swing.JButton;
033: import javax.swing.JPanel;
034: import javax.swing.SwingUtilities;
035:
036: import org.jdesktop.animation.timing.Animator;
037: import org.jdesktop.animation.timing.TimingTarget;
038: import org.jdesktop.fuse.InjectedResource;
039: import org.jdesktop.fuse.ResourceInjector;
040: import org.jdesktop.swingx.util.SwingWorker;
041: import org.zilonis.tool.ext.aerith.g2d.Reflection;
042: import org.zilonis.tool.ext.aerith.ui.BackgroundTitle;
043:
044: class LobbyPanel extends JPanel {
045: private JPanel buttonPanel;
046:
047: private float shadowOffsetX;
048: private float shadowOffsetY;
049:
050: private boolean mouseEnter = false;
051:
052: ////////////////////////////////////////////////////////////////////////////
053: // THEME SPECIFIC FIELDS
054: ////////////////////////////////////////////////////////////////////////////
055: @InjectedResource
056: private float shadowOpacity;
057: @InjectedResource
058: private Color shadowColor;
059: @InjectedResource
060: private int shadowDistance;
061: @InjectedResource
062: private int shadowDirection;
063: @InjectedResource
064: private Font categoryFont;
065: @InjectedResource
066: private Font categorySmallFont;
067: @InjectedResource
068: private float categorySmallOpacity;
069: @InjectedResource
070: private Color categoryColor;
071: @InjectedResource
072: private Color categoryHighlightColor;
073:
074: LobbyPanel() {
075: ResourceInjector.get().inject(this );
076:
077: setOpaque(false);
078: setLayout(new BorderLayout());
079:
080: computeShadow();
081:
082: buildPanel();
083: }
084:
085: private void buildPanel() {
086: setLayout(new BorderLayout());
087: setOpaque(false);
088: add(BorderLayout.NORTH, new BackgroundTitle("Select Option"));
089: buttonPanel = new JPanel();
090: buttonPanel.setOpaque(false);
091: buildButtonPanel();
092: add(BorderLayout.CENTER, buttonPanel);
093: add(BorderLayout.WEST, Box.createHorizontalStrut(60));
094: add(BorderLayout.EAST, Box.createHorizontalStrut(60));
095: }
096:
097: private void buildButtonPanel() {
098: buttonPanel.setLayout(new GridBagLayout());
099:
100: int counter = 0;
101: JButton button;
102: buttonPanel.add(button = createButton("View Scopes",
103: "Your Scopes Hierarchy",
104: "/resources/photos/task-view-photos.png"),
105: new GridBagConstraints(counter % 2, counter / 2, 1, 1,
106: 0.5, 0.5, GridBagConstraints.NORTHWEST,
107: GridBagConstraints.HORIZONTAL, new Insets(0, 0,
108: 0, (counter + 1) % 2 != 0 ? 30 : 0), 0,
109: 0));
110: button.addActionListener(new ActionListener() {
111: public void actionPerformed(ActionEvent e) {
112: TransitionManager.showScopes();
113: }
114: });
115: counter++;
116: buttonPanel.add(button = createButton("Rules Analysis",
117: "View the Rules Graph",
118: "/resources/photos/task-create-trip.png"),
119: new GridBagConstraints(counter % 2, counter / 2, 1, 1,
120: 0.5, 0.5, GridBagConstraints.NORTHWEST,
121: GridBagConstraints.HORIZONTAL, new Insets(0, 0,
122: 0, (counter + 1) % 2 != 0 ? 30 : 0), 0,
123: 0));
124: button.addActionListener(new ActionListener() {
125: public void actionPerformed(ActionEvent e) {
126: TransitionManager.showRules();
127: }
128: });
129: counter++;
130: buttonPanel.add(button = createButton("Facts wizard",
131: "Facts from Meta-data",
132: "/resources/photos/task-view-trip.png"),
133: new GridBagConstraints(counter % 2, counter / 2, 1, 1,
134: 0.5, 0.5, GridBagConstraints.NORTHWEST,
135: GridBagConstraints.HORIZONTAL, new Insets(0, 0,
136: 0, (counter + 1) % 2 != 0 ? 30 : 0), 0,
137: 0));
138: button.addActionListener(new ActionListener() {
139: public void actionPerformed(ActionEvent e) {
140: TransitionManager.showWMEs();
141: }
142: });
143: counter++;
144: buttonPanel.add(button = createButton("Zilonis Shell",
145: "Interact with the engine",
146: "/resources/photos/task-logout.png"),
147: new GridBagConstraints(counter % 2, counter / 2, 1, 1,
148: 0.5, 0.5, GridBagConstraints.NORTHWEST,
149: GridBagConstraints.HORIZONTAL, new Insets(0, 0,
150: 0, (counter + 1) % 2 != 0 ? 30 : 0), 0,
151: 0));
152: button.addActionListener(new ActionListener() {
153: public void actionPerformed(ActionEvent e) {
154: TransitionManager.showShell();
155: }
156: });
157:
158: }
159:
160: private void computeShadow() {
161: double rads = Math.toRadians(shadowDirection);
162: shadowOffsetX = (float) Math.cos(rads) * shadowDistance;
163: shadowOffsetY = (float) Math.sin(rads) * shadowDistance;
164: }
165:
166: private JButton createButton(String name, String description,
167: String image) {
168: return new TaskButton(name, description, image);
169: }
170:
171: void setTasks() {
172: buttonPanel.removeAll();
173: }
174:
175: private class TaskButton extends JButton {
176: private Dimension componentDimension = new Dimension(0, 0);
177: private BufferedImage image;
178: private Rectangle clickable;
179:
180: private float ghostValue = 0.0f;
181: private float newFraction = 0.0f;
182:
183: private int distance_r;
184: private int distance_g;
185: private int distance_b;
186:
187: private int color_r;
188: private int color_g;
189: private int color_b;
190:
191: private final String name;
192: private final String description;
193: private final String imageName;
194:
195: private TaskButton(String name, String description,
196: String imageName) {
197: this .name = name;
198: this .description = description;
199: this .imageName = imageName;
200:
201: setFocusable(false);
202:
203: setBorder(BorderFactory.createEmptyBorder(6, 6, 6, 6));
204:
205: setOpaque(false);
206: setContentAreaFilled(false);
207: setFocusPainted(false);
208: setBorderPainted(false);
209:
210: new ImageFetcher().execute();
211:
212: color_r = categoryColor.getRed();
213: color_g = categoryColor.getGreen();
214: color_b = categoryColor.getBlue();
215:
216: addMouseListener(new MouseClickHandler());
217: addMouseMotionListener(new GhostHandler());
218: HiglightHandler higlightHandler = new HiglightHandler();
219: addMouseListener(higlightHandler);
220: addMouseMotionListener(higlightHandler);
221: }
222:
223: @Override
224: protected void fireActionPerformed(ActionEvent e) {
225: // consume action performed events here
226: // see MouseClickHandler instead
227: }
228:
229: private class ImageFetcher extends SwingWorker {
230: @Override
231: protected Object doInBackground() throws Exception {
232: getImage();
233: return image;
234: }
235:
236: @Override
237: protected void done() {
238: componentDimension = computeDimension();
239: revalidate();
240: }
241: }
242:
243: private void getImage() {
244: try {
245: this .image = ImageIO.read(getClass().getResource(
246: imageName));
247: } catch (IOException e) {
248: e.printStackTrace();
249: }
250: BufferedImage mask = Reflection.createGradientMask(image
251: .getWidth(), image.getHeight());
252: this .image = Reflection.createReflectedPicture(image, mask);
253: }
254:
255: private Dimension computeDimension() {
256: Insets insets = getInsets();
257:
258: FontMetrics metrics = getFontMetrics(categoryFont);
259: Rectangle2D bounds = metrics
260: .getMaxCharBounds(getGraphics());
261: int height = (int) bounds.getHeight()
262: + metrics.getLeading();
263: int nameWidth = SwingUtilities.computeStringWidth(metrics,
264: name);
265:
266: metrics = getFontMetrics(categorySmallFont);
267: bounds = metrics.getMaxCharBounds(getGraphics());
268: height += bounds.getHeight();
269: int descWidth = SwingUtilities.computeStringWidth(metrics,
270: description == null ? "" : description);
271:
272: int width = Math.max(nameWidth, descWidth);
273: width += image.getWidth() + 10;
274:
275: clickable = new Rectangle(insets.left, insets.top /*+ 4*/,
276: width /*+ insets.left + insets.right*/, height /*+ insets.top + insets.bottom*/);
277: HyperlinkHandler.add(this , clickable);
278:
279: height = Math.max(height, image.getHeight());
280: height += 4;
281:
282: return new Dimension(width + insets.left + insets.right,
283: height + insets.top + insets.bottom);
284: }
285:
286: @Override
287: public Dimension getMinimumSize() {
288: return getPreferredSize();
289: }
290:
291: @Override
292: public Dimension getPreferredSize() {
293: return componentDimension;
294: }
295:
296: @Override
297: protected void paintComponent(Graphics g) {
298: if (!isVisible()) {
299: return;
300: }
301:
302: Graphics2D g2 = (Graphics2D) g;
303: setupGraphics(g2);
304:
305: float y = paintText(g2);
306: paintImage(g2, y);
307: }
308:
309: private void paintImage(Graphics2D g2, float y) {
310: Insets insets = getInsets();
311:
312: if (ghostValue > 0.0f) {
313: int newWidth = (int) (image.getWidth() * (1.0 + ghostValue / 2.0));
314: int newHeight = (int) (image.getHeight() * (1.0 + ghostValue / 2.0));
315:
316: Composite composite = g2.getComposite();
317: g2.setComposite(AlphaComposite.getInstance(
318: AlphaComposite.SRC_OVER,
319: 0.7f * (1.0f - ghostValue)));
320: g2.drawImage(image, insets.left
321: + (image.getWidth() - newWidth) / 2, 4
322: + (int) (y - newHeight / (5.0 / 3.0))
323: - (image.getWidth() - newWidth) / 2, newWidth,
324: newHeight, null);
325: g2.setComposite(composite);
326: }
327:
328: g2.drawImage(image, null, insets.left, 4 + (int) (y - image
329: .getHeight()
330: / (5.0 / 3.0)));
331: }
332:
333: private float paintText(Graphics2D g2) {
334: g2.setFont(categoryFont);
335:
336: Insets insets = getInsets();
337:
338: FontRenderContext context = g2.getFontRenderContext();
339: TextLayout layout = new TextLayout(name, categoryFont,
340: context);
341:
342: float x = image.getWidth() + 10.0f;
343: x += insets.left;
344: float y = 4.0f + layout.getAscent() - layout.getDescent();
345: y += insets.top;
346:
347: g2.setColor(shadowColor);
348: Composite composite = g2.getComposite();
349: g2.setComposite(AlphaComposite.getInstance(
350: AlphaComposite.SRC_OVER, shadowOpacity));
351: layout.draw(g2, shadowOffsetX + x, shadowOffsetY + y);
352: g2.setComposite(composite);
353:
354: g2.setColor(new Color(color_r, color_g, color_b));
355: layout.draw(g2, x, y);
356: y += layout.getDescent();
357:
358: layout = new TextLayout(description == null ? " "
359: : description, categorySmallFont, context);
360: y += layout.getAscent();
361: composite = g2.getComposite();
362: g2.setComposite(AlphaComposite.getInstance(
363: AlphaComposite.SRC_OVER, categorySmallOpacity));
364: layout.draw(g2, x, y);
365: g2.setComposite(composite);
366:
367: return y;
368: }
369:
370: private void setupGraphics(Graphics2D g2) {
371: g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
372: RenderingHints.VALUE_ANTIALIAS_ON);
373: g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
374: RenderingHints.VALUE_INTERPOLATION_BILINEAR);
375: }
376:
377: private final class GhostHandler extends MouseMotionAdapter {
378: private Animator timer;
379:
380: @Override
381: public void mouseMoved(MouseEvent e) {
382: if (!clickable.contains(e.getPoint()) || mouseEnter) {
383: return;
384: }
385:
386: if (timer != null && timer.isRunning()) {
387: return;
388: }
389:
390: distance_r = categoryHighlightColor.getRed()
391: - categoryColor.getRed();
392: distance_g = categoryHighlightColor.getGreen()
393: - categoryColor.getGreen();
394: distance_b = categoryHighlightColor.getBlue()
395: - categoryColor.getBlue();
396:
397: timer = new Animator(450, new AnimateGhost());
398: timer.start();
399: }
400: }
401:
402: private final class MouseClickHandler extends MouseAdapter {
403: @Override
404: public void mouseClicked(MouseEvent e) {
405: if (clickable.contains(e.getPoint())) {
406: for (ActionListener l : getActionListeners()) {
407: l.actionPerformed(new ActionEvent(
408: TaskButton.this , 462, ""));
409: }
410: }
411: }
412: }
413:
414: private final class AnimateGhost implements TimingTarget {
415: public void timingEvent(float fraction) {
416: ghostValue = fraction;
417: repaint();
418: }
419:
420: public void repeat() {
421:
422: }
423:
424: public void begin() {
425: ghostValue = 0.0f;
426: }
427:
428: public void end() {
429: ghostValue = 0.0f;
430: repaint();
431: }
432: }
433:
434: private final class HiglightHandler extends MouseMotionAdapter
435: implements MouseListener {
436: private Animator timer;
437:
438: @Override
439: public void mouseMoved(MouseEvent e) {
440: if (clickable.contains(e.getPoint())) {
441: if (!mouseEnter) {
442: mouseEnter = true;
443: if (timer != null && timer.isRunning()) {
444: timer.stop();
445: }
446: timer = new Animator(450, new AnimateHighlight(
447: true));
448: timer.start();
449: }
450: } else if (mouseEnter) {
451: mouseEnter = false;
452: if (timer != null && timer.isRunning()) {
453: timer.stop();
454: }
455: timer = new Animator(450, new AnimateHighlight(
456: false));
457: timer.start();
458: }
459: }
460:
461: public void mouseClicked(MouseEvent e) {
462: }
463:
464: public void mousePressed(MouseEvent e) {
465: }
466:
467: public void mouseReleased(MouseEvent e) {
468: }
469:
470: public void mouseEntered(MouseEvent e) {
471: mouseEnter = false;
472: }
473:
474: public void mouseExited(MouseEvent e) {
475: }
476: }
477:
478: private final class AnimateHighlight implements TimingTarget {
479: private boolean forward;
480: private float oldValue;
481:
482: AnimateHighlight(boolean forward) {
483: this .forward = forward;
484: oldValue = newFraction;
485: }
486:
487: public void repeat() {
488:
489: }
490:
491: public void timingEvent(float fraction) {
492: newFraction = oldValue + fraction
493: * (forward ? 1.0f : -1.0f);
494:
495: if (newFraction > 1.0f) {
496: newFraction = 1.0f;
497: } else if (newFraction < 0.0f) {
498: newFraction = 0.0f;
499: }
500:
501: color_r = (int) (categoryColor.getRed() + distance_r
502: * newFraction);
503: color_g = (int) (categoryColor.getGreen() + distance_g
504: * newFraction);
505: color_b = (int) (categoryColor.getBlue() + distance_b
506: * newFraction);
507:
508: repaint();
509: }
510:
511: public void begin() {
512: }
513:
514: public void end() {
515: }
516: }
517: }
518: }
|