create changelog entry
[debian/openrocket] / android-libraries / ActionBarSherlock / src / com / actionbarsherlock / internal / widget / IcsLinearLayout.java
1 package com.actionbarsherlock.internal.widget;
2
3 import android.content.Context;
4 import android.content.res.TypedArray;
5 import android.graphics.Canvas;
6 import android.graphics.drawable.Drawable;
7 import android.util.AttributeSet;
8 import android.view.View;
9 import com.actionbarsherlock.internal.nineoldandroids.widget.NineLinearLayout;
10
11 /**
12  * A simple extension of a regular linear layout that supports the divider API
13  * of Android 4.0+. The dividers are added adjacent to the children by changing
14  * their layout params. If you need to rely on the margins which fall in the
15  * same orientation as the layout you should wrap the child in a simple
16  * {@link android.widget.FrameLayout} so it can receive the margin.
17  */
18 public class IcsLinearLayout extends NineLinearLayout {
19     private static final int[] LinearLayout = new int[] {
20         /* 0 */ android.R.attr.divider,
21         /* 1 */ android.R.attr.showDividers,
22         /* 2 */ android.R.attr.dividerPadding,
23     };
24     private static final int LinearLayout_divider = 0;
25     private static final int LinearLayout_showDividers = 1;
26     private static final int LinearLayout_dividerPadding = 2;
27
28     /**
29      * Don't show any dividers.
30      */
31     public static final int SHOW_DIVIDER_NONE = 0;
32     /**
33      * Show a divider at the beginning of the group.
34      */
35     public static final int SHOW_DIVIDER_BEGINNING = 1;
36     /**
37      * Show dividers between each item in the group.
38      */
39     public static final int SHOW_DIVIDER_MIDDLE = 2;
40     /**
41      * Show a divider at the end of the group.
42      */
43     public static final int SHOW_DIVIDER_END = 4;
44
45
46     private Drawable mDivider;
47     private int mDividerWidth;
48     private int mDividerHeight;
49     private int mShowDividers;
50     private int mDividerPadding;
51
52
53     public IcsLinearLayout(Context context, AttributeSet attrs) {
54         super(context, attrs);
55
56         TypedArray a = context.obtainStyledAttributes(attrs, /*com.android.internal.R.styleable.*/LinearLayout);
57
58         setDividerDrawable(a.getDrawable(/*com.android.internal.R.styleable.*/LinearLayout_divider));
59         mShowDividers = a.getInt(/*com.android.internal.R.styleable.*/LinearLayout_showDividers, SHOW_DIVIDER_NONE);
60         mDividerPadding = a.getDimensionPixelSize(/*com.android.internal.R.styleable.*/LinearLayout_dividerPadding, 0);
61
62         a.recycle();
63     }
64
65     /**
66      * Set how dividers should be shown between items in this layout
67      *
68      * @param showDividers One or more of {@link #SHOW_DIVIDER_BEGINNING},
69      *                     {@link #SHOW_DIVIDER_MIDDLE}, or {@link #SHOW_DIVIDER_END},
70      *                     or {@link #SHOW_DIVIDER_NONE} to show no dividers.
71      */
72     public void setShowDividers(int showDividers) {
73         if (showDividers != mShowDividers) {
74             requestLayout();
75             invalidate(); //XXX This is required if you are toggling a divider off
76         }
77         mShowDividers = showDividers;
78     }
79
80     /**
81      * @return A flag set indicating how dividers should be shown around items.
82      * @see #setShowDividers(int)
83      */
84     public int getShowDividers() {
85         return mShowDividers;
86     }
87
88     /**
89      * Set a drawable to be used as a divider between items.
90      * @param divider Drawable that will divide each item.
91      * @see #setShowDividers(int)
92      */
93     public void setDividerDrawable(Drawable divider) {
94         if (divider == mDivider) {
95             return;
96         }
97         mDivider = divider;
98         if (divider != null) {
99             mDividerWidth = divider.getIntrinsicWidth();
100             mDividerHeight = divider.getIntrinsicHeight();
101         } else {
102             mDividerWidth = 0;
103             mDividerHeight = 0;
104         }
105         setWillNotDraw(divider == null);
106         requestLayout();
107     }
108
109     /**
110      * Set padding displayed on both ends of dividers.
111      *
112      * @param padding Padding value in pixels that will be applied to each end
113      *
114      * @see #setShowDividers(int)
115      * @see #setDividerDrawable(Drawable)
116      * @see #getDividerPadding()
117      */
118     public void setDividerPadding(int padding) {
119         mDividerPadding = padding;
120     }
121
122     /**
123      * Get the padding size used to inset dividers in pixels
124      *
125      * @see #setShowDividers(int)
126      * @see #setDividerDrawable(Drawable)
127      * @see #setDividerPadding(int)
128      */
129     public int getDividerPadding() {
130         return mDividerPadding;
131     }
132
133     /**
134      * Get the width of the current divider drawable.
135      *
136      * @hide Used internally by framework.
137      */
138     public int getDividerWidth() {
139         return mDividerWidth;
140     }
141
142     @Override
143     protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) {
144         final int index = indexOfChild(child);
145         final int orientation = getOrientation();
146         final LayoutParams params = (LayoutParams) child.getLayoutParams();
147         if (hasDividerBeforeChildAt(index)) {
148             if (orientation == VERTICAL) {
149                 //Account for the divider by pushing everything up
150                 params.topMargin = mDividerHeight;
151             } else {
152                 //Account for the divider by pushing everything left
153                 params.leftMargin = mDividerWidth;
154             }
155         }
156
157         final int count = getChildCount();
158         if (index == count - 1) {
159             if (hasDividerBeforeChildAt(count)) {
160                 if (orientation == VERTICAL) {
161                     params.bottomMargin = mDividerHeight;
162                 } else {
163                     params.rightMargin = mDividerWidth;
164                 }
165             }
166         }
167         super.measureChildWithMargins(child, parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed);
168     }
169
170     @Override
171     protected void onDraw(Canvas canvas) {
172         if (mDivider != null) {
173             if (getOrientation() == VERTICAL) {
174                 drawDividersVertical(canvas);
175             } else {
176                 drawDividersHorizontal(canvas);
177             }
178         }
179         super.onDraw(canvas);
180     }
181
182     void drawDividersVertical(Canvas canvas) {
183         final int count = getChildCount();
184         for (int i = 0; i < count; i++) {
185             final View child = getChildAt(i);
186
187             if (child != null && child.getVisibility() != GONE) {
188                 if (hasDividerBeforeChildAt(i)) {
189                     final LayoutParams lp = (LayoutParams) child.getLayoutParams();
190                     final int top = child.getTop() - lp.topMargin/* - mDividerHeight*/;
191                     drawHorizontalDivider(canvas, top);
192                 }
193             }
194         }
195
196         if (hasDividerBeforeChildAt(count)) {
197             final View child = getChildAt(count - 1);
198             int bottom = 0;
199             if (child == null) {
200                 bottom = getHeight() - getPaddingBottom() - mDividerHeight;
201             } else {
202                 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
203                 bottom = child.getBottom()/* + lp.bottomMargin*/;
204             }
205             drawHorizontalDivider(canvas, bottom);
206         }
207     }
208
209     void drawDividersHorizontal(Canvas canvas) {
210         final int count = getChildCount();
211         for (int i = 0; i < count; i++) {
212             final View child = getChildAt(i);
213
214             if (child != null && child.getVisibility() != GONE) {
215                 if (hasDividerBeforeChildAt(i)) {
216                     final LayoutParams lp = (LayoutParams) child.getLayoutParams();
217                     final int left = child.getLeft() - lp.leftMargin/* - mDividerWidth*/;
218                     drawVerticalDivider(canvas, left);
219                 }
220             }
221         }
222
223         if (hasDividerBeforeChildAt(count)) {
224             final View child = getChildAt(count - 1);
225             int right = 0;
226             if (child == null) {
227                 right = getWidth() - getPaddingRight() - mDividerWidth;
228             } else {
229                 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
230                 right = child.getRight()/* + lp.rightMargin*/;
231             }
232             drawVerticalDivider(canvas, right);
233         }
234     }
235
236     void drawHorizontalDivider(Canvas canvas, int top) {
237         mDivider.setBounds(getPaddingLeft() + mDividerPadding, top,
238                 getWidth() - getPaddingRight() - mDividerPadding, top + mDividerHeight);
239         mDivider.draw(canvas);
240     }
241
242     void drawVerticalDivider(Canvas canvas, int left) {
243         mDivider.setBounds(left, getPaddingTop() + mDividerPadding,
244                 left + mDividerWidth, getHeight() - getPaddingBottom() - mDividerPadding);
245         mDivider.draw(canvas);
246     }
247
248     /**
249      * Determines where to position dividers between children.
250      *
251      * @param childIndex Index of child to check for preceding divider
252      * @return true if there should be a divider before the child at childIndex
253      * @hide Pending API consideration. Currently only used internally by the system.
254      */
255     protected boolean hasDividerBeforeChildAt(int childIndex) {
256         if (childIndex == 0) {
257             return (mShowDividers & SHOW_DIVIDER_BEGINNING) != 0;
258         } else if (childIndex == getChildCount()) {
259             return (mShowDividers & SHOW_DIVIDER_END) != 0;
260         } else if ((mShowDividers & SHOW_DIVIDER_MIDDLE) != 0) {
261             boolean hasVisibleViewBefore = false;
262             for (int i = childIndex - 1; i >= 0; i--) {
263                 if (getChildAt(i).getVisibility() != GONE) {
264                     hasVisibleViewBefore = true;
265                     break;
266                 }
267             }
268             return hasVisibleViewBefore;
269         }
270         return false;
271     }
272 }