blob: 6d1fb55dcb128632f2f622f7753b0c9519850af5 [file] [log] [blame]
Winson Chung321e9ee2010-08-09 13:37:56 -07001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.launcher2;
18
19import android.content.Context;
Winson Chung321e9ee2010-08-09 13:37:56 -070020import android.util.AttributeSet;
Winson Chung321e9ee2010-08-09 13:37:56 -070021import android.view.MotionEvent;
22import android.view.View;
23import android.view.ViewDebug;
24import android.view.ViewGroup;
25
26/**
27 * An abstraction of the original CellLayout which supports laying out items
28 * which span multiple cells into a grid-like layout. Also supports dimming
29 * to give a preview of its contents.
30 */
Michael Jurka8245a862011-02-01 17:53:59 -080031public class PagedViewCellLayout extends ViewGroup implements Page {
Winson Chung321e9ee2010-08-09 13:37:56 -070032 static final String TAG = "PagedViewCellLayout";
33
Winson Chung321e9ee2010-08-09 13:37:56 -070034 private int mCellCountX;
35 private int mCellCountY;
36 private int mCellWidth;
37 private int mCellHeight;
Winson Chungdf4b83d2010-10-20 17:49:27 -070038 private int mWidthGap;
39 private int mHeightGap;
Winson Chung321e9ee2010-08-09 13:37:56 -070040 private static int sDefaultCellDimensions = 96;
Michael Jurka8245a862011-02-01 17:53:59 -080041 protected PagedViewCellLayoutChildren mChildren;
42 private PagedViewCellLayoutChildren mHolographicChildren;
Winson Chung321e9ee2010-08-09 13:37:56 -070043
Winson Chung321e9ee2010-08-09 13:37:56 -070044 public PagedViewCellLayout(Context context) {
45 this(context, null);
46 }
47
48 public PagedViewCellLayout(Context context, AttributeSet attrs) {
49 this(context, attrs, 0);
50 }
51
52 public PagedViewCellLayout(Context context, AttributeSet attrs, int defStyle) {
53 super(context, attrs, defStyle);
54
Winson Chung321e9ee2010-08-09 13:37:56 -070055 setAlwaysDrawnWithCacheEnabled(false);
56
57 // setup default cell parameters
58 mCellWidth = mCellHeight = sDefaultCellDimensions;
59 mCellCountX = LauncherModel.getCellCountX();
60 mCellCountY = LauncherModel.getCellCountY();
Winson Chungdf4b83d2010-10-20 17:49:27 -070061 mWidthGap = mHeightGap = -1;
Winson Chung321e9ee2010-08-09 13:37:56 -070062
Michael Jurka8245a862011-02-01 17:53:59 -080063 mChildren = new PagedViewCellLayoutChildren(context);
64 mChildren.setCellDimensions(mCellWidth, mCellHeight);
65 mChildren.setGap(mWidthGap, mHeightGap);
66
67 addView(mChildren);
68 mHolographicChildren = new PagedViewCellLayoutChildren(context);
69 mHolographicChildren.setAlpha(0f);
70 mHolographicChildren.setCellDimensions(mCellWidth, mCellHeight);
71 mHolographicChildren.setGap(mWidthGap, mHeightGap);
72
73 addView(mHolographicChildren);
Winson Chungb3347bb2010-08-19 14:51:28 -070074 }
Winson Chung321e9ee2010-08-09 13:37:56 -070075
Winson Chungb3347bb2010-08-19 14:51:28 -070076 @Override
77 public void setAlpha(float alpha) {
Michael Jurka8245a862011-02-01 17:53:59 -080078 mChildren.setAlpha(alpha);
79 mHolographicChildren.setAlpha(1.0f - alpha);
Winson Chung321e9ee2010-08-09 13:37:56 -070080 }
81
82 @Override
83 public void cancelLongPress() {
84 super.cancelLongPress();
85
86 // Cancel long press for all children
87 final int count = getChildCount();
88 for (int i = 0; i < count; i++) {
89 final View child = getChildAt(i);
90 child.cancelLongPress();
91 }
92 }
93
94 public boolean addViewToCellLayout(View child, int index, int childId,
95 PagedViewCellLayout.LayoutParams params) {
96 final PagedViewCellLayout.LayoutParams lp = params;
97
98 // Generate an id for each view, this assumes we have at most 256x256 cells
99 // per workspace screen
100 if (lp.cellX >= 0 && lp.cellX <= (mCellCountX - 1) &&
101 lp.cellY >= 0 && (lp.cellY <= mCellCountY - 1)) {
102 // If the horizontal or vertical span is set to -1, it is taken to
103 // mean that it spans the extent of the CellLayout
104 if (lp.cellHSpan < 0) lp.cellHSpan = mCellCountX;
105 if (lp.cellVSpan < 0) lp.cellVSpan = mCellCountY;
106
107 child.setId(childId);
Michael Jurka8245a862011-02-01 17:53:59 -0800108 mChildren.addView(child, index, lp);
Winson Chung321e9ee2010-08-09 13:37:56 -0700109
Michael Jurka8245a862011-02-01 17:53:59 -0800110 if (child instanceof PagedViewIcon) {
111 PagedViewIcon pagedViewIcon = (PagedViewIcon) child;
112 mHolographicChildren.addView(pagedViewIcon.getHolographicOutlineView(), index, lp);
113 }
Winson Chung321e9ee2010-08-09 13:37:56 -0700114 return true;
115 }
116 return false;
117 }
118
119 @Override
Michael Jurka8245a862011-02-01 17:53:59 -0800120 public void removeAllViewsOnPage() {
121 mChildren.removeAllViews();
122 mHolographicChildren.removeAllViews();
Winson Chung321e9ee2010-08-09 13:37:56 -0700123 }
124
125 @Override
Michael Jurka8245a862011-02-01 17:53:59 -0800126 public void removeViewOnPageAt(int index) {
127 mChildren.removeViewAt(index);
128 mHolographicChildren.removeViewAt(index);
129 }
130
131 @Override
132 public int getPageChildCount() {
133 return mChildren.getChildCount();
134 }
135
136 @Override
137 public View getChildOnPageAt(int i) {
138 return mChildren.getChildAt(i);
139 }
140
141 @Override
142 public int indexOfChildOnPage(View v) {
143 return mChildren.indexOfChild(v);
144 }
145
Winson Chung321e9ee2010-08-09 13:37:56 -0700146 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
147 // TODO: currently ignoring padding
148
149 int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
150 int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
151
152 int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
153 int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
154
155 if (widthSpecMode == MeasureSpec.UNSPECIFIED || heightSpecMode == MeasureSpec.UNSPECIFIED) {
156 throw new RuntimeException("CellLayout cannot have UNSPECIFIED dimensions");
157 }
158
159 final int cellWidth = mCellWidth;
160 final int cellHeight = mCellHeight;
161
162 int numWidthGaps = mCellCountX - 1;
163 int numHeightGaps = mCellCountY - 1;
164
165 int vSpaceLeft = heightSpecSize - mPaddingTop
166 - mPaddingBottom - (cellHeight * mCellCountY);
167 int heightGap = vSpaceLeft / numHeightGaps;
168
169 int hSpaceLeft = widthSpecSize - mPaddingLeft
170 - mPaddingRight - (cellWidth * mCellCountX);
171 int widthGap = hSpaceLeft / numWidthGaps;
172
173 // center it around the min gaps
174 int minGap = Math.min(widthGap, heightGap);
Winson Chung321e9ee2010-08-09 13:37:56 -0700175 /*
176 if (minGap < heightGap) {
177 // vertical space has shrunken, so change padding accordingly
178 paddingTop += ((heightGap - minGap) * (mCellCountY - 1)) / 2;
179 } else if (minGap < widthGap) {
180 // horizontal space has shrunken, so change padding accordingly
181 paddingLeft += ((widthGap - minGap) * (mCellCountX - 1)) / 2;
182 }
183 */
Winson Chungdf4b83d2010-10-20 17:49:27 -0700184 if (mWidthGap > -1 && mHeightGap > -1) {
185 widthGap = mWidthGap;
186 heightGap = mHeightGap;
187 } else {
188 widthGap = heightGap = minGap;
189 }
Winson Chung321e9ee2010-08-09 13:37:56 -0700190
191 int newWidth = mPaddingLeft + mPaddingRight + (mCellCountX * cellWidth) +
Winson Chungdf4b83d2010-10-20 17:49:27 -0700192 ((mCellCountX - 1) * widthGap);
Winson Chung321e9ee2010-08-09 13:37:56 -0700193 int newHeight = mPaddingTop + mPaddingBottom + (mCellCountY * cellHeight) +
Winson Chungdf4b83d2010-10-20 17:49:27 -0700194 ((mCellCountY - 1) * heightGap);
Winson Chung321e9ee2010-08-09 13:37:56 -0700195
196 final int count = getChildCount();
197 for (int i = 0; i < count; i++) {
198 View child = getChildAt(i);
Michael Jurka8245a862011-02-01 17:53:59 -0800199 int childWidthMeasureSpec =
200 MeasureSpec.makeMeasureSpec(newWidth, MeasureSpec.EXACTLY);
201 int childheightMeasureSpec =
202 MeasureSpec.makeMeasureSpec(newHeight, MeasureSpec.EXACTLY);
Winson Chung321e9ee2010-08-09 13:37:56 -0700203 child.measure(childWidthMeasureSpec, childheightMeasureSpec);
204 }
205
206 setMeasuredDimension(newWidth, newHeight);
207 }
208
209 @Override
210 protected void onLayout(boolean changed, int l, int t, int r, int b) {
211 int count = getChildCount();
Winson Chung321e9ee2010-08-09 13:37:56 -0700212 for (int i = 0; i < count; i++) {
213 View child = getChildAt(i);
Michael Jurka8245a862011-02-01 17:53:59 -0800214 child.layout(0, 0, r - l, b - t);
Winson Chung321e9ee2010-08-09 13:37:56 -0700215 }
216 }
217
218 @Override
Winson Chung321e9ee2010-08-09 13:37:56 -0700219 public boolean onTouchEvent(MotionEvent event) {
220 return super.onTouchEvent(event) || true;
221 }
222
Winson Chung80baf5a2010-08-09 16:03:15 -0700223 public void enableCenteredContent(boolean enabled) {
Michael Jurka8245a862011-02-01 17:53:59 -0800224 mChildren.enableCenteredContent(enabled);
225 mHolographicChildren.enableCenteredContent(enabled);
Winson Chung80baf5a2010-08-09 16:03:15 -0700226 }
227
Winson Chung321e9ee2010-08-09 13:37:56 -0700228 @Override
229 protected void setChildrenDrawingCacheEnabled(boolean enabled) {
Michael Jurka8245a862011-02-01 17:53:59 -0800230 mChildren.setChildrenDrawingCacheEnabled(enabled);
231 mHolographicChildren.setChildrenDrawingCacheEnabled(enabled);
Winson Chung321e9ee2010-08-09 13:37:56 -0700232 }
233
234 public void setCellCount(int xCount, int yCount) {
235 mCellCountX = xCount;
236 mCellCountY = yCount;
237 requestLayout();
238 }
239
Winson Chungdf4b83d2010-10-20 17:49:27 -0700240 public void setGap(int widthGap, int heightGap) {
241 mWidthGap = widthGap;
242 mHeightGap = heightGap;
Michael Jurka8245a862011-02-01 17:53:59 -0800243 mChildren.setGap(widthGap, heightGap);
244 mHolographicChildren.setGap(widthGap, heightGap);
Winson Chungdf4b83d2010-10-20 17:49:27 -0700245 }
246
Winson Chunge3193b92010-09-10 11:44:42 -0700247 public void setCellDimensions(int width, int height) {
248 mCellWidth = width;
249 mCellHeight = height;
Michael Jurka8245a862011-02-01 17:53:59 -0800250 mChildren.setCellDimensions(width, height);
251 mHolographicChildren.setCellDimensions(width, height);
Winson Chunge3193b92010-09-10 11:44:42 -0700252 }
253
254 public int getDefaultCellDimensions() {
255 return sDefaultCellDimensions;
256 }
257
Winson Chung80baf5a2010-08-09 16:03:15 -0700258 public int[] getCellCountForDimensions(int width, int height) {
259 // Always assume we're working with the smallest span to make sure we
260 // reserve enough space in both orientations
261 int smallerSize = Math.min(mCellWidth, mCellHeight);
262
263 // Always round up to next largest cell
264 int spanX = (width + smallerSize) / smallerSize;
265 int spanY = (height + smallerSize) / smallerSize;
266
267 return new int[] { spanX, spanY };
268 }
269
Winson Chung321e9ee2010-08-09 13:37:56 -0700270 /**
271 * Start dragging the specified child
272 *
273 * @param child The child that is being dragged
274 */
275 void onDragChild(View child) {
276 PagedViewCellLayout.LayoutParams lp = (PagedViewCellLayout.LayoutParams) child.getLayoutParams();
277 lp.isDragging = true;
278 }
279
Winson Chunge3193b92010-09-10 11:44:42 -0700280 /**
281 * Estimates the number of cells that the specified width would take up.
282 */
Winson Chung80baf5a2010-08-09 16:03:15 -0700283 public int estimateCellHSpan(int width) {
Winson Chunge3193b92010-09-10 11:44:42 -0700284 // TODO: we need to take widthGap into effect
Winson Chung80baf5a2010-08-09 16:03:15 -0700285 return (width + mCellWidth) / mCellWidth;
286 }
Winson Chunge3193b92010-09-10 11:44:42 -0700287
288 /**
289 * Estimates the number of cells that the specified height would take up.
290 */
Winson Chung80baf5a2010-08-09 16:03:15 -0700291 public int estimateCellVSpan(int height) {
Winson Chunge3193b92010-09-10 11:44:42 -0700292 // TODO: we need to take heightGap into effect
Winson Chung80baf5a2010-08-09 16:03:15 -0700293 return (height + mCellHeight) / mCellHeight;
294 }
Winson Chunge3193b92010-09-10 11:44:42 -0700295
296 /**
297 * Estimates the width that the number of vSpan cells will take up.
298 */
299 public int estimateCellWidth(int hSpan) {
300 // TODO: we need to take widthGap into effect
301 return hSpan * mCellWidth;
302 }
303
304 /**
305 * Estimates the height that the number of vSpan cells will take up.
306 */
307 public int estimateCellHeight(int vSpan) {
308 // TODO: we need to take heightGap into effect
309 return vSpan * mCellHeight;
Winson Chung80baf5a2010-08-09 16:03:15 -0700310 }
311
Winson Chung321e9ee2010-08-09 13:37:56 -0700312 @Override
313 public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
314 return new PagedViewCellLayout.LayoutParams(getContext(), attrs);
315 }
316
317 @Override
318 protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
319 return p instanceof PagedViewCellLayout.LayoutParams;
320 }
321
322 @Override
323 protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
324 return new PagedViewCellLayout.LayoutParams(p);
325 }
326
327 public static class LayoutParams extends ViewGroup.MarginLayoutParams {
328 /**
329 * Horizontal location of the item in the grid.
330 */
331 @ViewDebug.ExportedProperty
332 public int cellX;
333
334 /**
335 * Vertical location of the item in the grid.
336 */
337 @ViewDebug.ExportedProperty
338 public int cellY;
339
340 /**
341 * Number of cells spanned horizontally by the item.
342 */
343 @ViewDebug.ExportedProperty
344 public int cellHSpan;
345
346 /**
347 * Number of cells spanned vertically by the item.
348 */
349 @ViewDebug.ExportedProperty
350 public int cellVSpan;
351
352 /**
353 * Is this item currently being dragged
354 */
355 public boolean isDragging;
356
Winson Chung80baf5a2010-08-09 16:03:15 -0700357 // a data object that you can bind to this layout params
358 private Object mTag;
359
Winson Chung321e9ee2010-08-09 13:37:56 -0700360 // X coordinate of the view in the layout.
361 @ViewDebug.ExportedProperty
362 int x;
363 // Y coordinate of the view in the layout.
364 @ViewDebug.ExportedProperty
365 int y;
366
Winson Chung80baf5a2010-08-09 16:03:15 -0700367 public LayoutParams() {
368 super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
369 cellHSpan = 1;
370 cellVSpan = 1;
371 }
372
Winson Chung321e9ee2010-08-09 13:37:56 -0700373 public LayoutParams(Context c, AttributeSet attrs) {
374 super(c, attrs);
375 cellHSpan = 1;
376 cellVSpan = 1;
377 }
378
379 public LayoutParams(ViewGroup.LayoutParams source) {
380 super(source);
381 cellHSpan = 1;
382 cellVSpan = 1;
383 }
384
385 public LayoutParams(LayoutParams source) {
386 super(source);
387 this.cellX = source.cellX;
388 this.cellY = source.cellY;
389 this.cellHSpan = source.cellHSpan;
390 this.cellVSpan = source.cellVSpan;
391 }
392
393 public LayoutParams(int cellX, int cellY, int cellHSpan, int cellVSpan) {
394 super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
395 this.cellX = cellX;
396 this.cellY = cellY;
397 this.cellHSpan = cellHSpan;
398 this.cellVSpan = cellVSpan;
399 }
400
401 public void setup(int cellWidth, int cellHeight, int widthGap, int heightGap,
402 int hStartPadding, int vStartPadding) {
403
404 final int myCellHSpan = cellHSpan;
405 final int myCellVSpan = cellVSpan;
406 final int myCellX = cellX;
407 final int myCellY = cellY;
408
409 width = myCellHSpan * cellWidth + ((myCellHSpan - 1) * widthGap) -
410 leftMargin - rightMargin;
411 height = myCellVSpan * cellHeight + ((myCellVSpan - 1) * heightGap) -
412 topMargin - bottomMargin;
413
414 x = hStartPadding + myCellX * (cellWidth + widthGap) + leftMargin;
415 y = vStartPadding + myCellY * (cellHeight + heightGap) + topMargin;
416 }
417
Winson Chung80baf5a2010-08-09 16:03:15 -0700418 public Object getTag() {
419 return mTag;
420 }
421
422 public void setTag(Object tag) {
423 mTag = tag;
424 }
425
Winson Chung321e9ee2010-08-09 13:37:56 -0700426 public String toString() {
Winson Chung80baf5a2010-08-09 16:03:15 -0700427 return "(" + this.cellX + ", " + this.cellY + ", " +
428 this.cellHSpan + ", " + this.cellVSpan + ")";
Winson Chung321e9ee2010-08-09 13:37:56 -0700429 }
430 }
431}
Michael Jurka8245a862011-02-01 17:53:59 -0800432
433interface Page {
434 public int getPageChildCount();
435 public View getChildOnPageAt(int i);
436 public void removeAllViewsOnPage();
437 public void removeViewOnPageAt(int i);
438 public int indexOfChildOnPage(View v);
439}