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.edit.scrollbar;
32  
33  import java.util.TimerTask;
34  import javax.microedition.lcdui.Graphics;
35  
36  /***
37   * This class captures common behaviours of scrollbars.
38   *
39   * @author Mathieu Champlon
40   * @version $Revision$ $Date$
41   */
42  public final class Scrollbar implements IScrollbar
43  {
44      /***
45       * The background color.
46       */
47      private static final int BACKGROUND_COLOR = 0xADAAAD;
48      /***
49       * The foreground color.
50       */
51      private static final int FOREGROUND_COLOR = 0x000000;
52      /***
53       * The size of the arrows in pixels.
54       */
55      private static final int ARROW_SIZE = 8;
56      /***
57       * The width of the scrollbar in pixels.
58       */
59      private static final int WIDTH = 2 * ARROW_SIZE + 1;
60      /***
61       * The space taken by arrows in pixels.
62       */
63      private static final int ARROW_SPACING = ARROW_SIZE + 2;
64      /***
65       * The width of the body and cursor in pixels.
66       */
67      private static final int BODY_WIDTH = WIDTH / 3;
68      /***
69       * The minimum cursor size allowed in pixels.
70       */
71      private static final int CURSOR_MINIMUM_SIZE = 20;
72      /***
73       * The values defining the cursor size and position.
74       */
75      private int max_, visible_, value_;
76      /***
77       * The size of the scrollbar in pixels.
78       */
79      private int size_;
80      /***
81       * Position in pixels from where a drag event occurs.
82       */
83      private int dragFrom_;
84      /***
85       * Value of the slidebar from which a drag event occurs.
86       */
87      private int dragFromValue_;
88      /***
89       * The scrolling timer.
90       */
91      private final RepeatableTimer timer_;
92      /***
93       * The viewport.
94       */
95      private final IScrollable viewport_;
96      /***
97       * The drawer.
98       */
99      private final IDrawer drawer_;
100 
101     /***
102      * Create a scrollbar.
103      *
104      * @param viewport the viewport to register
105      * @param drawer the scrollbar drawer
106      */
107     public Scrollbar( final IScrollable viewport, final IDrawer drawer )
108     {
109         if( viewport == null )
110             throw new IllegalArgumentException( "parameter 'viewport' is null" );
111         if( drawer == null )
112             throw new IllegalArgumentException( "parameter 'drawer' is null" );
113         viewport_ = viewport;
114         drawer_ = drawer;
115         size_ = 0;
116         dragFrom_ = -1;
117         timer_ = new RepeatableTimer();
118     }
119 
120     /***
121      * Paint the scrollbar.
122      *
123      * @param g the graphics
124      */
125     public void paint( final Graphics g )
126     {
127         g.setColor( BACKGROUND_COLOR );
128         paintBackground( g );
129         g.setColor( FOREGROUND_COLOR );
130         paintArrows( g );
131         paintBody( g );
132         paintCursor( g );
133     }
134 
135     private void paintBackground( final Graphics g )
136     {
137         g.setStrokeStyle( Graphics.SOLID );
138         drawer_.drawBackground( g, size_, WIDTH );
139     }
140 
141     private void paintArrows( final Graphics g )
142     {
143         drawer_.drawArrow( g, WIDTH - 1, ARROW_SIZE, 0 );
144         drawer_.drawArrow( g, WIDTH - 1, size_ - ARROW_SIZE - 1, size_ - 1 );
145     }
146 
147     private void paintBody( final Graphics g )
148     {
149         drawer_.drawBody( g, BODY_WIDTH, WIDTH - BODY_WIDTH - 1, ARROW_SPACING, size_ - ARROW_SPACING - 1 );
150     }
151 
152     private void paintCursor( final Graphics g )
153     {
154         final int size = computeCursorSize();
155         final int position = computeCursorPosition( size );
156         drawer_.drawCursor( g, BODY_WIDTH, WIDTH - 2 * BODY_WIDTH, position, size );
157     }
158 
159     private int getBodySize()
160     {
161         return size_ - 2 * ARROW_SPACING;
162     }
163 
164     private int computeCursorPosition( final int size )
165     {
166         if( visible_ < max_ )
167             return ARROW_SPACING + value_ * (getBodySize() - size) / (max_ - visible_);
168         return ARROW_SPACING;
169     }
170 
171     private int computeCursorSize()
172     {
173         if( visible_ < max_ )
174             return Math.max( CURSOR_MINIMUM_SIZE, getBodySize() * visible_ / max_ );
175         return getBodySize();
176     }
177 
178     /***
179      * Scroll the cursor to the given value.
180      *
181      * @param value the new value
182      */
183     public void scroll( final int value )
184     {
185         value_ = value;
186     }
187 
188     /***
189      * {@inheritDoc}
190      */
191     public void update( final int visible, final int max )
192     {
193         visible_ = visible;
194         max_ = max;
195     }
196 
197     /***
198      * Resize the scrollbar.
199      *
200      * @param size the new size in pixels
201      */
202     public void resize( final int size )
203     {
204         size_ = size;
205     }
206 
207     /***
208      * Handle a click event.
209      *
210      * @param offset the click offset
211      */
212     public void click( final int offset )
213     {
214         dragFrom_ = -1;
215         final int size = computeCursorSize();
216         final int position = computeCursorPosition( size );
217         click( offset, position, size );
218         if( dragFrom_ == -1 ) // FIXME review this
219         {
220             timer_.start( new TimerTask()
221             {
222                 public void run()
223                 {
224                     click( offset, position, size );
225                 }
226             } );
227         }
228     }
229 
230     private void click( final int offset, final int position, final int size )
231     {
232         if( offset < position )
233         {
234             if( offset > ARROW_SPACING )
235                 viewport_.scroll( -visible_ );
236             else
237                 viewport_.scroll( -1 );
238         }
239         else if( offset > position + size )
240         {
241             if( offset < size_ - ARROW_SPACING )
242                 viewport_.scroll( visible_ );
243             else
244                 viewport_.scroll( 1 );
245         }
246         else
247         {
248             dragFrom_ = offset;
249             dragFromValue_ = value_;
250         }
251     }
252 
253     /***
254      * Handle an unclick event.
255      */
256     public void unclick()
257     {
258         timer_.stop();
259     }
260 
261     /***
262      * Handle a drag event.
263      *
264      * @param offset the offset to drag to
265      */
266     public void drag( final int offset )
267     {
268         if( dragFrom_ != -1 ) // FIXME review this
269         {
270             final int size = getBodySize();
271             final int steps = (offset - dragFrom_) * max_ / size + dragFromValue_ - value_;
272             viewport_.scroll( steps );
273         }
274     }
275 
276     /***
277      * Retrieve the width.
278      *
279      * @return the width in pixels
280      */
281     public int getWidth()
282     {
283         return WIDTH;
284     }
285 
286     /***
287      * Retrieve the size.
288      *
289      * @return the size in pixels
290      */
291     public int getSize()
292     {
293         return size_;
294     }
295 }