View Javadoc

1   /***
2    * Redistribution  and use  in source  and binary  forms, with  or without
3    * modification, are permitted provided  that the following conditions are
4    * met :
5    *
6    * . Redistributions  of  source  code  must  retain  the  above copyright
7    *   notice, this list of conditions and the following disclaimer.
8    *
9    * . Redistributions in  binary form  must reproduce  the above  copyright
10   *   notice, this list of conditions  and the following disclaimer in  the
11   *   documentation and/or other materials provided with the distribution.
12   *
13   * . The name of the author may not be used to endorse or promote products
14   *   derived from this software without specific prior written permission.
15   *
16   * THIS SOFTWARE IS  PROVIDED BY THE  AUTHOR ``AS IS''  AND ANY EXPRESS  OR
17   * IMPLIED  WARRANTIES,  INCLUDING,  BUT   NOT  LIMITED  TO,  THE   IMPLIED
18   * WARRANTIES OF MERCHANTABILITY AND  FITNESS FOR A PARTICULAR  PURPOSE ARE
19   * DISCLAIMED.  IN NO  EVENT SHALL  THE AUTHOR  BE LIABLE  FOR ANY  DIRECT,
20   * INDIRECT,  INCIDENTAL,  SPECIAL,  EXEMPLARY,  OR  CONSEQUENTIAL  DAMAGES
21   * (INCLUDING,  BUT  NOT LIMITED  TO,  PROCUREMENT OF  SUBSTITUTE  GOODS OR
22   * SERVICES;  LOSS  OF USE,  DATA,  OR PROFITS;  OR  BUSINESS INTERRUPTION)
23   * HOWEVER CAUSED  AND ON  ANY THEORY  OF LIABILITY,  WHETHER IN  CONTRACT,
24   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25   * ANY  WAY  OUT OF  THE  USE OF  THIS  SOFTWARE, EVEN  IF  ADVISED OF  THE
26   * POSSIBILITY OF SUCH DAMAGE.
27   *
28   * $Id$
29   */
30  
31  package palmed.ui;
32  
33  import java.util.Enumeration;
34  import java.util.Vector;
35  import javax.microedition.lcdui.Graphics;
36  import javax.microedition.lcdui.Item;
37  
38  /***
39   * This class implements a custom toolbar.
40   *
41   * @author Mathieu Champlon
42   * @version $Revision$ $Date$
43   */
44  public final class Toolbar implements IToolbar, IComponent
45  {
46      /***
47       * The height of the top border.
48       */
49      private static final int TOP_BORDER_HEIGHT = 2;
50      /***
51       * The height of the bottom border.
52       */
53      private static final int BOTTOM_BORDER_HEIGHT = 1;
54      /***
55       * The height of a button row.
56       */
57      private static final int ROW_HEIGHT = 26;
58      /***
59       * The ordinate of the middle point in the first row.
60       */
61      private static final int MIDDLE_OF_FIRST_ROW = (TOP_BORDER_HEIGHT + BOTTOM_BORDER_HEIGHT + ROW_HEIGHT) / 2;
62      /***
63       * The height of the shrinked toolbar.
64       */
65      private static final int SHRINKED_HEIGHT = 17;
66      /***
67       * The border color.
68       */
69      private static final int BORDER_COLOR = 0xFFFFFF;
70      /***
71       * The background color.
72       */
73      private static final int BACKGROUND_COLOR = 0xADAAAD;
74      /***
75       * The button hover color.
76       */
77      private static final int BUTTON_HOVER_COLOR = 0x3165CE;
78      /***
79       * The color of the shrink/expand buttons.
80       */
81      private static final int SHRINK_EXPAND_BUTTONS_COLOR = 0x000000;
82      /***
83       * The width of the shrink/expand area.
84       */
85      private static final int SHRINK_EXPAND_AREA_WIDTH = 8;
86      /***
87       * The shift from the middle of the row for the shrink/expand buttons.
88       */
89      private static final int SHRINK_EXPAND_BUTTONS_SHIFT = 4;
90      /***
91       * The size of each facet of the shrink/expand buttons.
92       */
93      private static final int SHRINK_EXPAND_BUTTONS_SIZE = 3;
94      /***
95       * The command listener.
96       */
97      private final ICommandListener listener_;
98      /***
99       * The layout manager.
100      */
101     private final ILayoutManager manager_;
102     /***
103      * The buttons.
104      */
105     private final Vector buttons_;
106     /***
107      * The width of the toolbar.
108      */
109     private int width_;
110     /***
111      * The number of pages displayed.
112      */
113     private int pages_;
114     /***
115      * The total number of pages for displaying all buttons.
116      */
117     private int maxPages_;
118 
119     /***
120      * Create a toolbar.
121      *
122      * @param listener the command listener
123      * @param manager the layout manager
124      */
125     public Toolbar( final ICommandListener listener, final ILayoutManager manager )
126     {
127         if( listener == null )
128             throw new IllegalArgumentException( "parameter 'listener' is null" );
129         if( manager == null )
130             throw new IllegalArgumentException( "parameter 'manager' is null" );
131         listener_ = listener;
132         manager_ = manager;
133         buttons_ = new Vector();
134         width_ = 0;
135         pages_ = 1;
136         maxPages_ = 1;
137     }
138 
139     private int getPages()
140     {
141         if( pages_ > maxPages_ )
142             return maxPages_;
143         return pages_;
144     }
145 
146     /***
147      * {@inheritDoc}
148      */
149     public void paint( final Graphics g )
150     {
151         paintBackground( g );
152         if( getPages() != 0 )
153         {
154             paintBorder( g );
155             paintButtons( g );
156             paintShrinkButton( g );
157         }
158         if( getPages() != maxPages_ )
159             paintExpandButton( g );
160     }
161 
162     private void paintBorder( final Graphics g )
163     {
164         g.setColor( BORDER_COLOR );
165         g.setStrokeStyle( Graphics.SOLID );
166         g.drawLine( 0, 0, width_, 0 );
167     }
168 
169     private void paintBackground( final Graphics g )
170     {
171         g.setColor( BACKGROUND_COLOR );
172         g.fillRect( 0, 0, width_, getHeight() );
173     }
174 
175     private void paintButtons( final Graphics g )
176     {
177         g.setColor( BUTTON_HOVER_COLOR );
178         int start = 0;
179         int page = 0;
180         final Enumeration buttons = buttons_.elements();
181         while( buttons.hasMoreElements() )
182         {
183             final Button button = (Button)buttons.nextElement();
184             paintButton( g, start, pageToPixel( page ), button );
185             start += button.getWidth();
186             if( start >= width_ - SHRINK_EXPAND_AREA_WIDTH )
187             {
188                 ++page;
189                 start = 0;
190             }
191         }
192     }
193 
194     private void paintButton( final Graphics g, final int x, final int y, final Button button )
195     {
196         g.translate( x, y );
197         button.paint( g );
198         g.translate( -x, -y );
199     }
200 
201     private void paintShrinkButton( final Graphics g )
202     {
203         g.setColor( SHRINK_EXPAND_BUTTONS_COLOR );
204         final int x = width_ - SHRINK_EXPAND_AREA_WIDTH;
205         final int y = MIDDLE_OF_FIRST_ROW + SHRINK_EXPAND_BUTTONS_SHIFT;
206         g.fillTriangle( x, y, x + 2 * SHRINK_EXPAND_BUTTONS_SIZE, y, x + SHRINK_EXPAND_BUTTONS_SIZE, y
207                 + SHRINK_EXPAND_BUTTONS_SIZE );
208     }
209 
210     private void paintExpandButton( final Graphics g )
211     {
212         g.setColor( SHRINK_EXPAND_BUTTONS_COLOR );
213         final int x = width_ - SHRINK_EXPAND_AREA_WIDTH;
214         final int y = MIDDLE_OF_FIRST_ROW - SHRINK_EXPAND_BUTTONS_SHIFT;
215         g.fillTriangle( x, y, x + 2 * SHRINK_EXPAND_BUTTONS_SIZE, y, x + SHRINK_EXPAND_BUTTONS_SIZE, y
216                 - SHRINK_EXPAND_BUTTONS_SIZE );
217     }
218 
219     /***
220      * {@inheritDoc}
221      */
222     public void resize( final int width, final int height )
223     {
224         width_ = width;
225         final int maxPages = computeMaxPages();
226         if( maxPages_ != maxPages )
227             manager_.refresh();
228         maxPages_ = maxPages;
229     }
230 
231     private int computeMaxPages()
232     {
233         int start = 0;
234         int maxPages = 1;
235         final Enumeration buttons = buttons_.elements();
236         while( buttons.hasMoreElements() )
237         {
238             final Button button = (Button)buttons.nextElement();
239             start += button.getWidth();
240             if( start >= width_ - SHRINK_EXPAND_AREA_WIDTH )
241             {
242                 ++maxPages;
243                 start = 0;
244             }
245         }
246         return maxPages;
247     }
248 
249     /***
250      * {@inheritDoc}
251      */
252     public boolean click( final int x, final int y )
253     {
254         if( pixelToPage( y ) == 0 && x >= width_ - SHRINK_EXPAND_AREA_WIDTH )
255         {
256             if( getPages() == 0 || (getPages() != maxPages_ && y < MIDDLE_OF_FIRST_ROW) )
257                 expand();
258             else
259                 shrink();
260         }
261         else
262             clickButton( x, y );
263         return true;
264     }
265 
266     private void clickButton( final int x, final int y )
267     {
268         int start = 0;
269         int page = 0;
270         final Enumeration buttons = buttons_.elements();
271         while( buttons.hasMoreElements() )
272         {
273             final Button button = (Button)buttons.nextElement();
274             if( x >= start && x < start + button.getWidth() && page == pixelToPage( y ) )
275                 button.enter();
276             start += button.getWidth();
277             if( start >= width_ - SHRINK_EXPAND_AREA_WIDTH )
278             {
279                 ++page;
280                 start = 0;
281             }
282         }
283     }
284 
285     private int pageToPixel( final int page )
286     {
287         return TOP_BORDER_HEIGHT + ROW_HEIGHT * page;
288     }
289 
290     private int pixelToPage( final int y )
291     {
292         return (y - TOP_BORDER_HEIGHT) / ROW_HEIGHT;
293     }
294 
295     private void shrink()
296     {
297         pages_ = Math.max( 0, getPages() - 1 );
298         manager_.refresh();
299     }
300 
301     private void expand()
302     {
303         pages_ = Math.min( maxPages_, getPages() + 1 );
304         manager_.refresh();
305     }
306 
307     /***
308      * {@inheritDoc}
309      */
310     public void drag( final int x, final int y )
311     {
312         final Enumeration buttons = buttons_.elements();
313         while( buttons.hasMoreElements() )
314             ((Button)buttons.nextElement()).leave();
315         if( y >= 0 && x < width_ - SHRINK_EXPAND_AREA_WIDTH )
316             click( x, y );
317     }
318 
319     /***
320      * {@inheritDoc}
321      */
322     public void unclick( final int x, final int y )
323     {
324         final Enumeration buttons = buttons_.elements();
325         while( buttons.hasMoreElements() )
326             ((Button)buttons.nextElement()).trigger();
327     }
328 
329     /***
330      * {@inheritDoc}
331      */
332     public void add( final ICommand command, final String image )
333     {
334         buttons_.addElement( new Button( command, listener_, image ) );
335     }
336 
337     /***
338      * {@inheritDoc}
339      */
340     public int getLayout()
341     {
342         if( getPages() > 0 )
343             return Item.LAYOUT_EXPAND;
344         return Item.LAYOUT_DEFAULT;
345     }
346 
347     /***
348      * {@inheritDoc}
349      */
350     public int getWidth()
351     {
352         if( getPages() > 0 )
353             return width_;
354         return SHRINK_EXPAND_AREA_WIDTH;
355     }
356 
357     /***
358      * {@inheritDoc}
359      */
360     public int getHeight()
361     {
362         if( getPages() > 0 )
363             return ROW_HEIGHT * getPages() + TOP_BORDER_HEIGHT + BOTTOM_BORDER_HEIGHT;
364         return SHRINKED_HEIGHT;
365     }
366 }