View Javadoc

1   /*
2   
3       dsh-piccolo-identify  Piccolo2D nodes for identifiable beans.
4       Copyright (c) 2007-2013 held jointly by the individual authors.
5   
6       This library is free software; you can redistribute it and/or modify it
7       under the terms of the GNU Lesser General Public License as published
8       by the Free Software Foundation; either version 3 of the License, or (at
9       your option) any later version.
10  
11      This library is distributed in the hope that it will be useful, but WITHOUT
12      ANY WARRANTY; with out even the implied warranty of MERCHANTABILITY or
13      FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
14      License for more details.
15  
16      You should have received a copy of the GNU Lesser General Public License
17      along with this library;  if not, write to the Free Software Foundation,
18      Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA.
19  
20      > http://www.fsf.org/licensing/licenses/lgpl.html
21      > http://www.opensource.org/licenses/lgpl-license.php
22  
23  */
24  package org.dishevelled.piccolo.identify;
25  
26  import java.awt.Color;
27  import java.awt.Shape;
28  
29  import java.awt.geom.Point2D;
30  import java.awt.geom.RoundRectangle2D;
31  
32  import java.beans.PropertyChangeEvent;
33  import java.beans.PropertyChangeListener;
34  
35  import javax.swing.UIManager;
36  
37  import org.piccolo2d.nodes.PPath;
38  
39  import org.piccolo2d.util.PBounds;
40  
41  import org.piccolo2d.extras.nodes.PShadow;
42  
43  import org.dishevelled.iconbundle.IconSize;
44  import org.dishevelled.iconbundle.IconState;
45  
46  /**
47   * Nautilus-style id node.
48   *
49   * @author  Michael Heuer
50   * @version $Revision$ $Date$
51   */
52  public final class NautilusIdNode
53      extends AbstractIdNode
54  {
55      /** Text selection node. */
56      private PPath textSelection;
57  
58      /** Text shadow node. */
59      private PShadow textShadow;
60  
61      /** Icon text gap. */
62      private final double iconTextGap = DEFAULT_ICON_TEXT_GAP;
63  
64      /** Text shadow blur radius, <code>4</code>. */
65      private static final int BLUR_RADIUS = 4;
66  
67      /** Text shadow offset, <code>0.5d</code> */
68      private static final double TEXT_SHADOW_OFFSET = 0.5d;
69  
70      /** Default icon text gap. */
71      private static final double DEFAULT_ICON_TEXT_GAP = 2.0d;
72  
73  
74      /**
75       * Create a new nautilus-style id node.
76       */
77      public NautilusIdNode()
78      {
79          this(null);
80      }
81  
82      /**
83       * Create a new nautilus-style id node with the specified value.
84       *
85       * @param value value for this id node
86       */
87      public NautilusIdNode(final Object value)
88      {
89          super(value);
90          createNodes();
91          resetStateMachine();
92      }
93  
94      /**
95       * Create a new nautilus-style id node with the specified value and icon size.
96       *
97       * @param value value for this id node
98       * @param iconSize icon size for this id node, must not be null
99       */
100     public NautilusIdNode(final Object value, final IconSize iconSize)
101     {
102         super(value);
103         setIconSize(iconSize);
104         createNodes();
105         resetStateMachine();
106     }
107 
108 
109     /**
110      * Create nodes.
111      */
112     private void createNodes()
113     {
114         textSelection = new PPath.Double();
115         textShadow = new PShadow(getNameTextNode().toImage(), Color.BLACK, BLUR_RADIUS);
116         addChild(textShadow);
117         addChild(textSelection);
118         addChild(getIconBundleImageNode());
119         addChild(getNameTextNode());
120 
121         // update text shadow on text node property changes
122         PropertyChangeListener listener = new PropertyChangeListener()
123             {
124                 @Override
125                 public void propertyChange(final PropertyChangeEvent event)
126                 {
127                     updateTextShadow();
128                 }
129             };
130         getNameTextNode().addPropertyChangeListener("font", listener);
131         getNameTextNode().addPropertyChangeListener("text", listener);
132     }
133 
134     /**
135      * Normal state.
136      */
137     private void normal()
138     {
139         setIconState(IconState.NORMAL);
140         getNameTextNode().setTextPaint(Color.BLACK);
141         textSelection.setVisible(false);
142         textShadow.setVisible(false);
143     }
144 
145     /**
146      * Reverse normal state.
147      */
148     private void reverseNormal()
149     {
150         setIconState(IconState.NORMAL);
151         getNameTextNode().setTextPaint(Color.WHITE);
152         textSelection.setVisible(false);
153         textShadow.setVisible(true);
154     }
155 
156     /**
157      * Mouseover state.
158      */
159     private void mouseover()
160     {
161         setIconState(IconState.MOUSEOVER);
162         getNameTextNode().setTextPaint(Color.BLACK);
163         textSelection.setVisible(false);
164         textShadow.setVisible(false);
165     }
166 
167     /**
168      * Reverse mouseover state.
169      */
170     private void reverseMouseover()
171     {
172         setIconState(IconState.MOUSEOVER);
173         getNameTextNode().setTextPaint(Color.WHITE);
174         textSelection.setVisible(false);
175         textShadow.setVisible(true);
176     }
177 
178     /**
179      * Selected state.
180      */
181     private void selected()
182     {
183         setIconState(IconState.SELECTED);
184         getNameTextNode().setTextPaint(Color.WHITE);
185         textSelection.setPaint(UIManager.getColor("List.selectionBackground"));
186         textSelection.setStrokePaint(UIManager.getColor("List.selectionBackground"));
187         textSelection.setVisible(true);
188         textShadow.setVisible(false);
189     }
190 
191     /**
192      * Selected mouseover state.
193      */
194     private void selectedMouseover()
195     {
196         setIconState(IconState.SELECTED_MOUSEOVER);
197         getNameTextNode().setTextPaint(Color.WHITE);
198         textSelection.setPaint(UIManager.getColor("List.selectionBackground"));
199         textSelection.setStrokePaint(UIManager.getColor("List.selectionBackground"));
200         textSelection.setVisible(true);
201         textShadow.setVisible(false);
202     }
203 
204     /**
205      * Reverse selected state.
206      */
207     private void reverseSelected()
208     {
209         selected();
210     }
211 
212     /**
213      * Reverse selected mouseover state.
214      */
215     private void reverseSelectedMouseover()
216     {
217         selectedMouseover();
218     }
219 
220     /**
221      * Dragging state.
222      */
223     private void dragging()
224     {
225         setIconState(IconState.NORMAL);
226         getNameTextNode().setTextPaint(Color.WHITE);
227         textSelection.setPaint(UIManager.getColor("List.selectionBackground"));
228         textSelection.setStrokePaint(UIManager.getColor("List.selectionBackground"));
229         textSelection.setVisible(true);
230         textShadow.setVisible(false);
231     }
232 
233     /**
234      * Reverse dragging state.
235      */
236     private void reverseDragging()
237     {
238         setIconState(IconState.NORMAL);
239         getNameTextNode().setTextPaint(Color.WHITE);
240         textSelection.setPaint(UIManager.getColor("List.selectionBackground"));
241         textSelection.setStrokePaint(UIManager.getColor("List.selectionBackground"));
242         textSelection.setVisible(true);
243         textShadow.setVisible(false);
244     }
245 
246     /**
247      * Update text shadow.
248      */
249     private void updateTextShadow()
250     {
251         removeChild(textShadow);
252         boolean visible = textShadow.getVisible();
253         textShadow = new PShadow(getNameTextNode().toImage(), Color.BLACK, BLUR_RADIUS);
254         textShadow.setVisible(visible);
255         addChild(0, textShadow);
256     }
257 
258     @Override
259     protected void layoutChildren()
260     {
261         PBounds iconBounds = getIconBundleImageNode().getBoundsReference();
262         Point2D iconCenter = iconBounds.getCenter2D();
263         getIconBundleImageNode().setOffset(-iconCenter.getX(), -iconCenter.getY());
264 
265         PBounds textBounds = getNameTextNode().getBoundsReference();
266         Point2D textCenter = textBounds.getCenter2D();
267 
268         double textSelectionWidthMargin = 4.0d;
269         double textSelectionHeightMargin = 1.0d;
270 
271         Shape textSelectionRect = new RoundRectangle2D.Double(0.0d, 0.0d,
272                                                               textBounds.getWidth() + 2.0d * textSelectionWidthMargin, textBounds.getHeight() + 2.0d * textSelectionHeightMargin,
273                                                               6.0d, 6.0d);
274         textSelection.reset();
275         textSelection.append(textSelectionRect, false);
276         PBounds textSelectionBounds = textSelection.getBoundsReference();
277         Point2D textSelectionCenter = textSelectionBounds.getCenter2D();
278         textSelection.setOffset(-textSelectionCenter.getX(), iconCenter.getY() + iconTextGap - textSelectionHeightMargin);
279         getNameTextNode().setOffset(-textCenter.getX(), iconCenter.getY() + iconTextGap);
280         textShadow.setOffset(-textCenter.getX() - (2 * BLUR_RADIUS) + TEXT_SHADOW_OFFSET,
281                              iconCenter.getY() + iconTextGap + textSelectionHeightMargin - (2 * BLUR_RADIUS) + TEXT_SHADOW_OFFSET);
282     }
283 }