1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5 * in compliance with the License. You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software distributed under the License
10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11 * or implied. See the License for the specific language governing permissions and limitations under
12 * the License.
13 */
14
15package android.support.v17.leanback.widget;
16
17import static android.support.v7.widget.RecyclerView.HORIZONTAL;
18import static android.support.v7.widget.RecyclerView.VERTICAL;
19import static android.support.v17.leanback.widget.BaseGridView.ITEM_ALIGN_OFFSET_PERCENT_DISABLED;
20
21import android.graphics.Rect;
22import android.support.v17.leanback.widget.GridLayoutManager.LayoutParams;
23import android.view.View;
24import android.view.ViewGroup;
25
26/**
27 * Defines alignment position on two directions of an item view. Typically item
28 * view alignment is at the center of the view. The class allows defining
29 * alignment at left/right or fixed offset/percentage position; it also allows
30 * using descendant view by id match.
31 */
32class ItemAlignment {
33
34    final static class Axis {
35        private int mOrientation;
36        private int mOffset = 0;
37        private float mOffsetPercent = 50;
38        private int mViewId = 0;
39        private boolean mOffsetWithPadding = false;
40        private Rect mRect = new Rect();
41
42        Axis(int orientation) {
43            mOrientation = orientation;
44        }
45
46        public void setItemAlignmentOffset(int offset) {
47            mOffset = offset;
48        }
49
50        public int getItemAlignmentOffset() {
51            return mOffset;
52        }
53
54        public void setItemAlignmentOffsetWithPadding(boolean withPadding) {
55            mOffsetWithPadding = withPadding;
56        }
57
58        public boolean isItemAlignmentOffsetWithPadding() {
59            return mOffsetWithPadding;
60        }
61
62        public void setItemAlignmentOffsetPercent(float percent) {
63            if ( (percent < 0 || percent > 100) &&
64                    percent != ITEM_ALIGN_OFFSET_PERCENT_DISABLED) {
65                throw new IllegalArgumentException();
66            }
67            mOffsetPercent = percent;
68        }
69
70        public float getItemAlignmentOffsetPercent() {
71            return mOffsetPercent;
72        }
73
74        public void setItemAlignmentViewId(int viewId) {
75            mViewId = viewId;
76        }
77
78        public int getItemAlignmentViewId() {
79            return mViewId;
80        }
81
82        /**
83         * get alignment position relative to optical left/top of itemView.
84         */
85        public int getAlignmentPosition(View itemView) {
86            LayoutParams p = (LayoutParams) itemView.getLayoutParams();
87            View view = itemView;
88            if (mViewId != 0) {
89                view = itemView.findViewById(mViewId);
90                if (view == null) {
91                    view = itemView;
92                }
93            }
94            int alignPos;
95            if (mOrientation == HORIZONTAL) {
96                if (mOffset >= 0) {
97                    alignPos = mOffset;
98                    if (mOffsetWithPadding) {
99                        alignPos += view.getPaddingLeft();
100                    }
101                } else {
102                    alignPos = view == itemView ? p.getOpticalWidth(view) : view.getWidth()
103                            + mOffset;
104                    if (mOffsetWithPadding) {
105                        alignPos -= view.getPaddingRight();
106                    }
107                }
108                if (mOffsetPercent != ITEM_ALIGN_OFFSET_PERCENT_DISABLED) {
109                    alignPos += ((view == itemView ? p.getOpticalWidth(view) : view.getWidth())
110                            * mOffsetPercent) / 100f;
111                }
112                if (itemView != view) {
113                    mRect.left = alignPos;
114                    ((ViewGroup) itemView).offsetDescendantRectToMyCoords(view, mRect);
115                    alignPos = mRect.left - p.getOpticalLeftInset();
116                }
117            } else {
118                if (mOffset >= 0) {
119                    alignPos = mOffset;
120                    if (mOffsetWithPadding) {
121                        alignPos += view.getPaddingTop();
122                    }
123                } else {
124                    alignPos = view == itemView ? p.getOpticalHeight(view) : view.getHeight()
125                            + mOffset;
126                    if (mOffsetWithPadding) {
127                        alignPos += view.getPaddingBottom();
128                    }
129                }
130                if (mOffsetPercent != ITEM_ALIGN_OFFSET_PERCENT_DISABLED) {
131                    alignPos += ((view == itemView ? p.getOpticalHeight(view) : view.getHeight())
132                            * mOffsetPercent) / 100f;
133                }
134                if (itemView != view) {
135                    mRect.top = alignPos;
136                    ((ViewGroup) itemView).offsetDescendantRectToMyCoords(view, mRect);
137                    alignPos = mRect.top - p.getOpticalTopInset();
138                }
139            }
140            return alignPos;
141        }
142    }
143
144    private int mOrientation = HORIZONTAL;
145
146    final public Axis vertical = new Axis(VERTICAL);
147
148    final public Axis horizontal = new Axis(HORIZONTAL);
149
150    private Axis mMainAxis = horizontal;
151
152    private Axis mSecondAxis = vertical;
153
154    final public Axis mainAxis() {
155        return mMainAxis;
156    }
157
158    final public Axis secondAxis() {
159        return mSecondAxis;
160    }
161
162    final public void setOrientation(int orientation) {
163        mOrientation = orientation;
164        if (mOrientation == HORIZONTAL) {
165            mMainAxis = horizontal;
166            mSecondAxis = vertical;
167        } else {
168            mMainAxis = vertical;
169            mSecondAxis = horizontal;
170        }
171    }
172
173    final public int getOrientation() {
174        return mOrientation;
175    }
176
177
178}
179